OAuth now validates client ID against a configured list.
This patch adds the valid_oauth_clients configuration option, a list of string ID's that limits what the client may use to identify itself. This is a breaking change for downstream consumers, as the domain on which storyboard is hosted will need to be added to this configuration option before logins will again be permitted. Change-Id: I411fdf67b56f5be0d151152471e5a00a75daa51e
This commit is contained in:
parent
29dca914aa
commit
a6528afd71
@ -60,6 +60,9 @@ lock_path = $state_path/lock
|
||||
# Time in seconds before an refresh_token expires
|
||||
# refresh_token_ttl = 604800
|
||||
|
||||
# A list of valid client id's that may connect to StoryBoard.
|
||||
# valid_oauth_clients = storyboard.openstack.org, localhost
|
||||
|
||||
[cron]
|
||||
# Storyboard's cron management configuration
|
||||
|
||||
|
@ -33,7 +33,12 @@ OAUTH_OPTS = [
|
||||
|
||||
cfg.IntOpt("refresh_token_ttl",
|
||||
default=60 * 60 * 24 * 7, # One week
|
||||
help="Time in seconds before an refresh_token expires")
|
||||
help="Time in seconds before an refresh_token expires"),
|
||||
|
||||
cfg.ListOpt("valid_oauth_clients",
|
||||
default=['storyboard.openstack.org', 'localhost'],
|
||||
help="A list of valid client id's that may connect to "
|
||||
"StoryBoard.")
|
||||
]
|
||||
|
||||
CONF.register_opts(OAUTH_OPTS, "oauth")
|
||||
@ -45,6 +50,7 @@ class ErrorMessages(object):
|
||||
NO_RESPONSE_TYPE = _('You did not provide a response_type.')
|
||||
INVALID_RESPONSE_TYPE = _('response_type must be \'code\'')
|
||||
NO_CLIENT_ID = _('You did not provide a client_id.')
|
||||
INVALID_CLIENT_ID = _('You did not provide a valid client_id.')
|
||||
NO_REDIRECT_URI = _('You did not provide a redirect_uri.')
|
||||
INVALID_REDIRECT_URI = _('You did not provide a valid redirect_uri.')
|
||||
|
||||
|
@ -25,6 +25,7 @@ from storyboard.common.exception import AccessDenied
|
||||
from storyboard.common.exception import InvalidClient
|
||||
from storyboard.common.exception import InvalidRequest
|
||||
from storyboard.common.exception import InvalidScope
|
||||
from storyboard.common.exception import UnauthorizedClient
|
||||
from storyboard.common.exception import UnsupportedResponseType
|
||||
|
||||
|
||||
@ -61,6 +62,9 @@ class OpenIdClient(object):
|
||||
if not client_id:
|
||||
raise InvalidClient(redirect_uri=redirect_uri,
|
||||
message=e_msg.NO_CLIENT_ID)
|
||||
if client_id not in CONF.oauth.valid_oauth_clients:
|
||||
raise UnauthorizedClient(redirect_uri=redirect_uri,
|
||||
message=e_msg.INVALID_CLIENT_ID)
|
||||
|
||||
# Sanity Check: scope
|
||||
if not scope:
|
||||
|
@ -195,6 +195,27 @@ class TestOAuthAuthorize(BaseOAuthTest):
|
||||
error='invalid_client',
|
||||
error_description=e_msg.NO_CLIENT_ID)
|
||||
|
||||
def test_authorize_invalid_client(self):
|
||||
"""Assert that an invalid client redirects back to the
|
||||
redirect_uri and provides the expected error response.
|
||||
"""
|
||||
invalid_params = self.valid_params.copy()
|
||||
invalid_params['client_id'] = 'invalid_client'
|
||||
|
||||
# Simple GET with invalid code parameters
|
||||
random_state = six.text_type(uuid.uuid4())
|
||||
response = self.get_json(path='/openid/authorize',
|
||||
expect_errors=True,
|
||||
state=random_state,
|
||||
**invalid_params)
|
||||
|
||||
# Validate the error response
|
||||
self.assertValidRedirect(response=response,
|
||||
expected_status_code=302,
|
||||
redirect_uri=invalid_params['redirect_uri'],
|
||||
error='unauthorized_client',
|
||||
error_description=e_msg.INVALID_CLIENT_ID)
|
||||
|
||||
def test_authorize_invalid_scope(self):
|
||||
"""Assert that an invalid scope redirects back to the
|
||||
redirect_uri and provides the expected error response.
|
||||
|
Loading…
x
Reference in New Issue
Block a user