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:
Michael Krotscheck 2015-02-06 14:17:37 -08:00
parent 29dca914aa
commit a6528afd71
4 changed files with 35 additions and 1 deletions

View File

@ -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

View File

@ -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.')

View File

@ -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:

View File

@ -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.