diff options
Diffstat (limited to 'keystone/auth/token_factory.py')
-rw-r--r-- | keystone/auth/token_factory.py | 368 |
1 files changed, 0 insertions, 368 deletions
diff --git a/keystone/auth/token_factory.py b/keystone/auth/token_factory.py deleted file mode 100644 index 22bc8363..00000000 --- a/keystone/auth/token_factory.py +++ /dev/null @@ -1,368 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2013 OpenStack LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -"""Token Factory""" - -import json -import sys -import uuid -import webob - -from keystone import catalog -from keystone.common import cms -from keystone.common import environment -from keystone.common import logging -from keystone.common import utils -from keystone import config -from keystone import exception -from keystone import identity -from keystone.openstack.common import jsonutils -from keystone.openstack.common import timeutils -from keystone import token as token_module -from keystone import trust - - -CONF = config.CONF - -LOG = logging.getLogger(__name__) - - -class TokenDataHelper(object): - """Token data helper.""" - def __init__(self): - self.identity_api = identity.Manager() - self.catalog_api = catalog.Manager() - self.trust_api = trust.Manager() - - def _get_filtered_domain(self, domain_id): - domain_ref = self.identity_api.get_domain(domain_id) - return {'id': domain_ref['id'], 'name': domain_ref['name']} - - def _populate_scope(self, token_data, domain_id, project_id): - if 'domain' in token_data or 'project' in token_data: - return - - if domain_id: - token_data['domain'] = self._get_filtered_domain(domain_id) - if project_id: - project_ref = self.identity_api.get_project(project_id) - filtered_project = { - 'id': project_ref['id'], - 'name': project_ref['name']} - filtered_project['domain'] = self._get_filtered_domain( - project_ref['domain_id']) - token_data['project'] = filtered_project - - def _get_project_roles_for_user(self, user_id, project_id): - roles = self.identity_api.get_roles_for_user_and_project( - user_id, project_id) - roles_ref = [] - for role_id in roles: - role_ref = self.identity_api.get_role(role_id) - role_ref.setdefault('project_id', project_id) - roles_ref.append(role_ref) - # user have no project roles, therefore access denied - if len(roles_ref) == 0: - msg = _('User have no access to project') - LOG.debug(msg) - raise exception.Unauthorized(msg) - return roles_ref - - def _get_domain_roles_for_user(self, user_id, domain_id): - roles = self.identity_api.get_roles_for_user_and_domain( - user_id, domain_id) - roles_ref = [] - for role_id in roles: - role_ref = self.identity_api.get_role(role_id) - role_ref.setdefault('domain_id', domain_id) - roles_ref.append(role_ref) - # user have no domain roles, therefore access denied - if len(roles_ref) == 0: - msg = _('User have no access to domain') - LOG.debug(msg) - raise exception.Unauthorized(msg) - return roles_ref - - def _get_roles_for_user(self, user_id, domain_id, project_id): - roles = [] - if domain_id: - roles = self._get_domain_roles_for_user(user_id, domain_id) - if project_id: - roles = self._get_project_roles_for_user(user_id, project_id) - return roles - - def _populate_user(self, token_data, user_id, domain_id, project_id, - trust): - if 'user' in token_data: - return - - user_ref = self.identity_api.get_user(user_id) - if CONF.trust.enabled and trust: - trustor_user_ref = self.identity_api.get_user( - trust['trustor_user_id']) - if not trustor_user_ref['enabled']: - raise exception.Forbidden() - if trust['impersonation']: - user_ref = trustor_user_ref - token_data['OS-TRUST:trust'] = ( - { - 'id': trust['id'], - 'trustor_user': {'id': trust['trustor_user_id']}, - 'trustee_user': {'id': trust['trustee_user_id']}, - 'impersonation': trust['impersonation'] - }) - filtered_user = { - 'id': user_ref['id'], - 'name': user_ref['name'], - 'domain': self._get_filtered_domain(user_ref['domain_id'])} - token_data['user'] = filtered_user - - def _populate_roles(self, token_data, user_id, domain_id, project_id, - trust): - if 'roles' in token_data: - return - - if CONF.trust.enabled and trust: - token_user_id = trust['trustor_user_id'] - token_project_id = trust['project_id'] - #trusts do not support domains yet - token_domain_id = None - else: - token_user_id = user_id - token_project_id = project_id - token_domain_id = domain_id - - if token_domain_id or token_project_id: - roles = self._get_roles_for_user(token_user_id, - token_domain_id, - token_project_id) - filtered_roles = [] - if CONF.trust.enabled and trust: - for trust_role in trust['roles']: - match_roles = [x for x in roles - if x['id'] == trust_role['id']] - if match_roles: - filtered_roles.append(match_roles[0]) - else: - raise exception.Forbidden() - else: - for role in roles: - filtered_roles.append({'id': role['id'], - 'name': role['name']}) - token_data['roles'] = filtered_roles - - def _populate_service_catalog(self, token_data, user_id, - domain_id, project_id, trust): - if 'catalog' in token_data: - return - - if CONF.trust.enabled and trust: - user_id = trust['trustor_user_id'] - if project_id or domain_id: - try: - service_catalog = self.catalog_api.get_v3_catalog( - user_id, project_id) - # TODO(ayoung): KVS backend needs a sample implementation - except exception.NotImplemented: - service_catalog = {} - # TODO(gyee): v3 service catalog is not quite completed yet - # TODO(ayoung): Enforce Endpoints for trust - token_data['catalog'] = service_catalog - - def _populate_token(self, token_data, expires=None, trust=None): - if not expires: - expires = token_module.default_expire_time() - if not isinstance(expires, basestring): - expires = timeutils.isotime(expires, subsecond=True) - token_data['expires_at'] = expires - token_data['issued_at'] = timeutils.isotime(subsecond=True) - - def get_token_data(self, user_id, method_names, extras, - domain_id=None, project_id=None, expires=None, - trust=None, token=None): - token_data = {'methods': method_names, - 'extras': extras} - - # We've probably already written these to the token - for x in ('roles', 'user', 'catalog', 'project', 'domain'): - if token and x in token: - token_data[x] = token[x] - - if CONF.trust.enabled and trust: - if user_id != trust['trustee_user_id']: - raise exception.Forbidden() - - self._populate_scope(token_data, domain_id, project_id) - self._populate_user(token_data, user_id, domain_id, project_id, trust) - self._populate_roles(token_data, user_id, domain_id, project_id, trust) - self._populate_service_catalog(token_data, user_id, domain_id, - project_id, trust) - self._populate_token(token_data, expires, trust) - return {'token': token_data} - - -def recreate_token_data(token_data=None, expires=None, - user_ref=None, project_ref=None): - """Recreate token from an existing token. - - Repopulate the ephemeral data and return the new token data. - - """ - new_expires = expires - project_id = None - user_id = None - domain_id = None - methods = ['password', 'token'] - extras = {} - - # NOTE(termie): Let's get some things straight here, because this code - # is wrong but tested as such: - # token_data, if it exists, is going to look like: - # {'token': ... the actual token data + a superfluous extras field ...} - # this data is actually stored in the database in the 'extras' column and - # then deserialized and added to the token_ref, that already has the - # the 'expires', 'user_id', and 'id' columns from the db. - # the 'user' and 'tenant' fields are being added to the - # token_ref due to being deserialized from the 'extras' column - # - # So, how this all looks in the db: - # id = some_id - # user_id = some_user_id - # expires = some_expiration - # extras = {'user': {'id': some_used_id}, - # 'tenant': {'id': some_tenant_id}, - # 'token_data': 'token': {'domain': {'id': some_domain_id}, - # 'project': {'id': some_project_id}, - # 'domain': {'id': some_domain_id}, - # 'user': {'id': some_user_id}, - # 'roles': [{'id': some_role_id}, ...], - # 'catalog': ..., - # 'expires_at': some_expiry_time, - # 'issued_at': now(), - # 'methods': ['password', 'token'], - # 'extras': { ... empty? ...} - # - # TODO(termie): reduce stored token complexity, bug filed at: - # https://bugs.launchpad.net/keystone/+bug/1159990 - if token_data: - # peel the outer layer so its easier to operate - token = token_data['token'] - domain_id = (token['domain']['id'] if 'domain' in token - else None) - project_id = (token['project']['id'] if 'project' in token - else None) - if not new_expires: - # support Grizzly-3 to Grizzly-RC1 transition - # tokens issued in G3 has 'expires' instead of 'expires_at' - new_expires = token.get('expires_at', - token.get('expires')) - user_id = token['user']['id'] - methods = token['methods'] - extras = token['extras'] - else: - token = None - project_id = project_ref['id'] if project_ref else None - user_id = user_ref['id'] - token_data_helper = TokenDataHelper() - return token_data_helper.get_token_data(user_id, - methods, - extras, - domain_id, - project_id, - new_expires, - token=token) - - -def create_token(auth_context, auth_info): - token_data_helper = TokenDataHelper() - (domain_id, project_id, trust) = auth_info.get_scope() - method_names = list(set(auth_info.get_method_names() + - auth_context.get('method_names', []))) - token_data = token_data_helper.get_token_data( - auth_context['user_id'], - method_names, - auth_context['extras'], - domain_id, - project_id, - auth_context.get('expires_at', None), - trust) - - if CONF.signing.token_format == 'UUID': - token_id = uuid.uuid4().hex - elif CONF.signing.token_format == 'PKI': - try: - token_id = cms.cms_sign_token(json.dumps(token_data), - CONF.signing.certfile, - CONF.signing.keyfile) - except environment.subprocess.CalledProcessError: - raise exception.UnexpectedError(_( - 'Unable to sign token.')) - else: - raise exception.UnexpectedError(_( - 'Invalid value for token_format: %s.' - ' Allowed values are PKI or UUID.') % - CONF.signing.token_format) - token_api = token_module.Manager() - try: - expiry = token_data['token']['expires_at'] - if isinstance(expiry, basestring): - expiry = timeutils.normalize_time(timeutils.parse_isotime(expiry)) - role_ids = [] - if 'project' in token_data['token']: - # project-scoped token, fill in the v2 token data - # all we care are the role IDs - role_ids = [role['id'] for role in token_data['token']['roles']] - metadata_ref = {'roles': role_ids} - data = dict(key=token_id, - id=token_id, - expires=expiry, - user=token_data['token']['user'], - tenant=token_data['token'].get('project'), - metadata=metadata_ref, - token_data=token_data, - trust_id=trust['id'] if trust else None) - token_api.create_token(token_id, data) - except Exception: - exc_info = sys.exc_info() - # an identical token may have been created already. - # if so, return the token_data as it is also identical - try: - token_api.get_token(token_id) - except exception.TokenNotFound: - raise exc_info[0], exc_info[1], exc_info[2] - - return (token_id, token_data) - - -def render_token_data_response(token_id, token_data, created=False): - """Render token data HTTP response. - - Stash token ID into the X-Auth-Token header. - - """ - headers = [('X-Subject-Token', token_id)] - headers.append(('Vary', 'X-Auth-Token')) - headers.append(('Content-Type', 'application/json')) - - if created: - status = (201, 'Created') - else: - status = (200, 'OK') - - body = jsonutils.dumps(token_data, cls=utils.SmarterEncoder) - return webob.Response(body=body, - status='%s %s' % status, - headerlist=headers) |