diff options
Diffstat (limited to 'keystone/common/controller.py')
-rw-r--r-- | keystone/common/controller.py | 86 |
1 files changed, 58 insertions, 28 deletions
diff --git a/keystone/common/controller.py b/keystone/common/controller.py index 6377692e..f4f3c79d 100644 --- a/keystone/common/controller.py +++ b/keystone/common/controller.py @@ -1,3 +1,4 @@ +import collections import functools import uuid @@ -27,46 +28,78 @@ def _build_policy_check_credentials(self, action, context, kwargs): raise exception.Unauthorized() creds = {} - token_data = token_ref['token_data'] + if 'token_data' in token_ref: + #V3 Tokens + token_data = token_ref['token_data']['token'] + try: + creds['user_id'] = token_data['user']['id'] + except AttributeError: + LOG.warning(_('RBAC: Invalid user')) + raise exception.Unauthorized() + + if 'project' in token_data: + creds['project_id'] = token_data['project']['id'] + else: + LOG.debug(_('RBAC: Proceeding without project')) - try: - creds['user_id'] = token_data['user']['id'] - except AttributeError: - LOG.warning(_('RBAC: Invalid user')) - raise exception.Unauthorized() + if 'domain' in token_data: + creds['domain_id'] = token_data['domain']['id'] - if 'project' in token_data: - creds['project_id'] = token_data['project']['id'] + if 'roles' in token_data: + creds['roles'] = [] + for role in token_data['roles']: + creds['roles'].append(role['name']) else: - LOG.debug(_('RBAC: Proceeding without project')) + #v2 Tokens + creds = token_ref.get('metadata', {}).copy() + try: + creds['user_id'] = token_ref['user'].get('id') + except AttributeError: + LOG.warning(_('RBAC: Invalid user')) + raise exception.Unauthorized() + try: + creds['project_id'] = token_ref['tenant'].get('id') + except AttributeError: + LOG.debug(_('RBAC: Proceeding without tenant')) + # NOTE(vish): this is pretty inefficient + creds['roles'] = [self.identity_api.get_role(context, role)['name'] + for role in creds.get('roles', [])] + + return creds - if 'domain' in token_data: - creds['domain_id'] = token_data['domain']['id'] - if 'roles' in token_data: - creds['roles'] = [] - for role in token_data['roles']: - creds['roles'].append(role['name']) +def flatten(d, parent_key=''): + """Flatten a nested dictionary - return creds + Converts a dictionary with nested values to a single level flat + dictionary, with dotted notation for each key. + + """ + items = [] + for k, v in d.items(): + new_key = parent_key + '.' + k if parent_key else k + if isinstance(v, collections.MutableMapping): + items.extend(flatten(v, new_key).items()) + else: + items.append((new_key, v)) + return dict(items) def protected(f): """Wraps API calls with role based access controls (RBAC).""" - @functools.wraps(f) def wrapper(self, context, **kwargs): - if not context['is_admin']: + if 'is_admin' in context and context['is_admin']: + LOG.warning(_('RBAC: Bypassing authorization')) + else: action = 'identity:%s' % f.__name__ creds = _build_policy_check_credentials(self, action, context, kwargs) # Simply use the passed kwargs as the target dict, which # would typically include the prime key of a get/update/delete # call. - self.policy_api.enforce(context, creds, action, kwargs) + self.policy_api.enforce(context, creds, action, flatten(kwargs)) LOG.debug(_('RBAC: Authorization granted')) - else: - LOG.warning(_('RBAC: Bypassing authorization')) return f(self, context, **kwargs) return wrapper @@ -89,11 +122,6 @@ def filterprotected(*filters): # parameter) and would typically include the prime key # of a get/update/delete call # - # TODO(henry-nash) do we need to put the whole object - # in, which is part of kwargs? I kept this in as it was part - # of the previous implementation, but without a specific key - # reference in the target I don't see how it can be used. - # First any query filter parameters target = dict() if len(filters) > 0: @@ -109,7 +137,8 @@ def filterprotected(*filters): for key in kwargs: target[key] = kwargs[key] - self.policy_api.enforce(context, creds, action, target) + self.policy_api.enforce(context, creds, action, + flatten(target)) LOG.debug(_('RBAC: Authorization granted')) else: @@ -119,7 +148,8 @@ def filterprotected(*filters): return _filterprotected -@dependency.requires('identity_api', 'policy_api', 'token_api') +@dependency.requires('identity_api', 'policy_api', 'token_api', + 'trust_api', 'catalog_api') class V2Controller(wsgi.Application): """Base controller class for Identity API v2.""" |