def build_token_values(token_data): token_expires_at = timeutils.parse_isotime(token_data['expires_at']) # Trim off the microseconds because the revocation event only has # expirations accurate to the second. token_expires_at = token_expires_at.replace(microsecond=0) token_values = { 'expires_at': timeutils.normalize_time(token_expires_at), 'issued_at': timeutils.normalize_time( timeutils.parse_isotime(token_data['issued_at']))} user = token_data.get('user') if user is not None: token_values['user_id'] = user['id'] token_values['identity_domain_id'] = user['domain']['id'] else: token_values['user_id'] = None token_values['identity_domain_id'] = None project = token_data.get('project', token_data.get('tenant')) if project is not None: token_values['project_id'] = project['id'] token_values['assignment_domain_id'] = project['domain']['id'] else: token_values['project_id'] = None domain = token_data.get('domain') if domain is not None: token_values['assignment_domain_id'] = domain['id'] else: token_values['assignment_domain_id'] = None role_list = [] roles = token_data.get('roles') if roles is not None: for role in roles: role_list.append(role['id']) token_values['roles'] = role_list trust = token_data.get('OS-TRUST:trust') if trust is None: token_values['trust_id'] = None token_values['trustor_id'] = None token_values['trustee_id'] = None else: token_values['trust_id'] = trust['id'] token_values['trustor_id'] = trust['trustor_user']['id'] token_values['trustee_id'] = trust['trustee_user']['id'] oauth1 = token_data.get('OS-OAUTH1') if oauth1 is None: token_values['consumer_id'] = None token_values['access_token_id'] = None else: token_values['consumer_id'] = oauth1['consumer_id'] token_values['access_token_id'] = oauth1['access_token_id'] return token_values
def test_token_expiry_maintained(self): foo_client = self.get_client(self.user_foo) orig_token = foo_client.service_catalog.catalog["token"] time.sleep(0.5) reauthenticated_token = foo_client.tokens.authenticate(token=foo_client.auth_token) self.assertCloseEnoughForGovernmentWork( timeutils.parse_isotime(orig_token["expires"]), timeutils.parse_isotime(reauthenticated_token.expires) )
def _add_to_revocation_list(self, data, lock): filtered_list = [] revoked_token_data = {} current_time = self._get_current_time() expires = data['expires'] if isinstance(expires, six.string_types): expires = timeutils.parse_isotime(expires) expires = timeutils.normalize_time(expires) if expires < current_time: LOG.warning(_('Token `%s` is expired, not adding to the ' 'revocation list.'), data['id']) return revoked_token_data['expires'] = timeutils.isotime(expires, subsecond=True) revoked_token_data['id'] = data['id'] token_list = self._get_key_or_default(self.revocation_key, default=[]) if not isinstance(token_list, list): # NOTE(morganfainberg): In the case that the revocation list is not # in a format we understand, reinitialize it. This is an attempt to # not allow the revocation list to be completely broken if # somehow the key is changed outside of keystone (e.g. memcache # that is shared by multiple applications). Logging occurs at error # level so that the cloud administrators have some awareness that # the revocation_list needed to be cleared out. In all, this should # be recoverable. Keystone cannot control external applications # from changing a key in some backends, however, it is possible to # gracefully handle and notify of this event. LOG.error(_('Reinitializing revocation list due to error ' 'in loading revocation list from backend. ' 'Expected `list` type got `%(type)s`. Old ' 'revocation list data: %(list)r'), {'type': type(token_list), 'list': token_list}) token_list = [] # NOTE(morganfainberg): on revocation, cleanup the expired entries, try # to keep the list of tokens revoked at the minimum. for token_data in token_list: try: expires_at = timeutils.normalize_time( timeutils.parse_isotime(token_data['expires'])) except ValueError: LOG.warning(_('Removing `%s` from revocation list due to ' 'invalid expires data in revocation list.'), token_data.get('id', 'INVALID_TOKEN_DATA')) continue if expires_at > current_time: filtered_list.append(token_data) filtered_list.append(revoked_token_data) self._set_key(self.revocation_key, filtered_list, lock)
def test_token_expiry_maintained(self): timeutils.set_time_override() foo_client = self.get_client(self.user_foo) orig_token = foo_client.service_catalog.catalog['token'] timeutils.advance_time_seconds(1) reauthenticated_token = foo_client.tokens.authenticate( token=foo_client.auth_token) self.assertCloseEnoughForGovernmentWork( timeutils.parse_isotime(orig_token['expires']), timeutils.parse_isotime(reauthenticated_token.expires))
def test_token_expiry_maintained(self, mock_utcnow): now = datetime.datetime.utcnow() mock_utcnow.return_value = now foo_client = self.get_client(self.user_foo) orig_token = foo_client.service_catalog.catalog['token'] mock_utcnow.return_value = now + datetime.timedelta(seconds=1) reauthenticated_token = foo_client.tokens.authenticate( token=foo_client.auth_token) self.assertCloseEnoughForGovernmentWork( timeutils.parse_isotime(orig_token['expires']), timeutils.parse_isotime(reauthenticated_token.expires))
def assertEqualTokens(self, a, b): def normalize(token): token['access']['token']['id'] = 'dummy' del token['access']['token']['expires'] del token['access']['token']['issued_at'] return token self.assertCloseEnoughForGovernmentWork( timeutils.parse_isotime(a['access']['token']['expires']), timeutils.parse_isotime(b['access']['token']['expires'])) self.assertCloseEnoughForGovernmentWork( timeutils.parse_isotime(a['access']['token']['issued_at']), timeutils.parse_isotime(b['access']['token']['issued_at'])) return self.assertDictEqual(normalize(a), normalize(b))
def authenticate(self, context, auth_info, auth_context): """Turn a signed request with an access key into a keystone token.""" if not self.oauth_api: raise exception.Unauthorized(_("%s not supported") % self.method) headers = context["headers"] oauth_headers = oauth.get_oauth_headers(headers) access_token_id = oauth_headers.get("oauth_token") if not access_token_id: raise exception.ValidationError(attribute="oauth_token", target="request") acc_token = self.oauth_api.get_access_token(access_token_id) expires_at = acc_token["expires_at"] if expires_at: now = timeutils.utcnow() expires = timeutils.normalize_time(timeutils.parse_isotime(expires_at)) if now > expires: raise exception.Unauthorized(_("Access token is expired")) url = controller.V3Controller.base_url(context, context["path"]) access_verifier = oauth.ResourceEndpoint( request_validator=validator.OAuthValidator(), token_generator=oauth.token_generator ) result, request = access_verifier.validate_protected_resource_request( url, http_method="POST", body=context["query_string"], headers=headers, realms=None ) if not result: msg = _("Could not validate the access token") raise exception.Unauthorized(msg) auth_context["user_id"] = acc_token["authorizing_user_id"] auth_context["access_token_id"] = access_token_id auth_context["project_id"] = acc_token["project_id"]
def issue_v2_token(self, token_ref, roles_ref=None, catalog_ref=None): token_data = self.v2_token_data_helper.format_token( token_ref, roles_ref, catalog_ref) token_id = self._get_token_id(token_data) token_data['access']['token']['id'] = token_id try: expiry = token_data['access']['token']['expires'] if isinstance(expiry, basestring): expiry = timeutils.normalize_time( timeutils.parse_isotime(expiry)) data = dict(key=token_id, id=token_id, expires=expiry, user=token_ref['user'], tenant=token_ref['tenant'], metadata=token_ref['metadata'], token_data=token_data, bind=token_ref.get('bind'), trust_id=token_ref['metadata'].get('trust_id'), token_version=token.provider.V2) self.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: self.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 issue_v2_token(self, token_ref, roles_ref=None, catalog_ref=None): token_data = self.v2_token_data_helper.format_token(token_ref, roles_ref, catalog_ref) token_id = self._get_token_id(token_data) token_data["access"]["token"]["id"] = token_id try: expiry = token_data["access"]["token"]["expires"] if isinstance(expiry, six.string_types): expiry = timeutils.normalize_time(timeutils.parse_isotime(expiry)) data = dict( key=token_id, id=token_id, expires=expiry, user=token_ref["user"], tenant=token_ref["tenant"], metadata=token_ref["metadata"], token_data=token_data, bind=token_ref.get("bind"), trust_id=token_ref["metadata"].get("trust_id"), token_version=token.provider.V2, ) self.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: self.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 _request_admin_token(self): """Retrieve new token as admin user from keystone. :return token id upon success :raises ServerError when unable to communicate with keystone """ params = { 'auth': { 'passwordCredentials': { 'username': self.admin_user, 'password': self.admin_password, }, 'tenantName': self.admin_tenant_name, } } response, data = self._json_request('POST', '/v2.0/tokens', body=params) try: token = data['access']['token']['id'] expiry = data['access']['token']['expires'] assert token assert expiry datetime_expiry = timeutils.parse_isotime(expiry) return (token, timeutils.normalize_time(datetime_expiry)) except (AssertionError, KeyError): LOG.warn("Unexpected response from keystone service: %s", data) raise ServiceError('invalid json response') except (ValueError): LOG.warn("Unable to parse expiration time from token: %s", data) raise ServiceError('invalid json response')
def _is_valid_token(self, token): """Verify the token is valid format and has not expired.""" current_time = timeutils.normalize_time(timeutils.utcnow()) try: # Get the data we need from the correct location (V2 and V3 tokens # differ in structure, Try V3 first, fall back to V2 second) token_data = token.get('token', token.get('access')) expires_at = token_data.get('expires_at', token_data.get('expires')) if not expires_at: expires_at = token_data['token']['expires'] expiry = timeutils.normalize_time( timeutils.parse_isotime(expires_at)) except Exception: LOG.exception(_('Unexpected error or malformed token determining ' 'token expiry: %s'), token) raise exception.TokenNotFound(_('Failed to validate token')) if current_time < expiry: self.check_revocation(token) # Token has not expired and has not been revoked. return None else: raise exception.TokenNotFound(_('Failed to validate token'))
def _is_valid_token(self, token): # Verify the token has not expired. current_time = timeutils.normalize_time(timeutils.utcnow()) try: # Get the data we need from the correct location (V2 and V3 tokens # differ in structure, Try V3 first, fall back to V2 second) token_data = token.get('token', token.get('access')) expires_at = token_data.get('expires_at', token_data.get('expires')) if not expires_at: expires_at = token_data['token']['expires'] expiry = timeutils.normalize_time( timeutils.parse_isotime(expires_at)) if current_time < expiry: # Token is has not expired and has not been revoked. return None except Exception: LOG.exception(_('Unexpected error or malformed token determining ' 'token expiry: %s') % token) # FIXME(morganfainberg): This error message needs to be updated to # reflect the token couldn't be found, but this change needs to wait # until Icehouse due to string freeze in Havana. This should be: # "Failed to find valid token" or something similar. raise exception.TokenNotFound(_('Failed to validate token'))
def build_token_values(token_data): token_values = { "expires_at": timeutils.normalize_time(timeutils.parse_isotime(token_data["expires_at"])), "issued_at": timeutils.normalize_time(timeutils.parse_isotime(token_data["issued_at"])), } user = token_data.get("user") if user is not None: token_values["user_id"] = user["id"] token_values["identity_domain_id"] = user["domain"]["id"] else: token_values["user_id"] = None token_values["identity_domain_id"] = None project = token_data.get("project", token_data.get("tenant")) if project is not None: token_values["project_id"] = project["id"] token_values["assignment_domain_id"] = project["domain"]["id"] else: token_values["project_id"] = None token_values["assignment_domain_id"] = None role_list = [] roles = token_data.get("roles") if roles is not None: for role in roles: role_list.append(role["id"]) token_values["roles"] = role_list trust = token_data.get("OS-TRUST:trust") if trust is None: token_values["trust_id"] = None token_values["trustor_id"] = None token_values["trustee_id"] = None else: token_values["trust_id"] = trust["id"] token_values["trustor_id"] = trust["trustor_user"]["id"] token_values["trustee_id"] = trust["trustee_user"]["id"] oauth1 = token_data.get("OS-OAUTH1") if oauth1 is None: token_values["consumer_id"] = None token_values["access_token_id"] = None else: token_values["consumer_id"] = oauth1["consumer_id"] token_values["access_token_id"] = oauth1["access_token_id"] return token_values
def create_trust(self, context, trust=None): """Create a new trust. The user creating the trust must be the trustor. """ # TODO(ayoung): instead of raising ValidationError on the first # problem, return a collection of all the problems. # Explicitly prevent a trust token from creating a new trust. auth_context = context.get('environment', {}).get('KEYSTONE_AUTH_CONTEXT', {}) if auth_context.get('is_delegated_auth'): raise exception.Forbidden( _('Cannot create a trust' ' with a token issued via delegation.')) if not trust: raise exception.ValidationError(attribute='trust', target='request') if trust.get('project_id') and not trust.get('roles'): raise exception.Forbidden( _('At least one role should be specified.')) try: user_id = self._get_user_id(context) _trustor_only(context, trust, user_id) #confirm that the trustee exists self.identity_api.get_user(trust['trustee_user_id']) all_roles = self.assignment_api.list_roles() clean_roles = self._clean_role_list(context, trust, all_roles) if trust.get('project_id'): user_role = self.assignment_api.get_roles_for_user_and_project( user_id, trust['project_id']) else: user_role = [] for trust_role in clean_roles: matching_roles = [x for x in user_role if x == trust_role['id']] if not matching_roles: raise exception.RoleNotFound(role_id=trust_role['id']) if trust.get('expires_at') is not None: if not trust['expires_at'].endswith('Z'): trust['expires_at'] += 'Z' try: trust['expires_at'] = (timeutils.parse_isotime (trust['expires_at'])) except ValueError: raise exception.ValidationTimeStampError() trust_id = uuid.uuid4().hex new_trust = self.trust_api.create_trust(trust_id, trust, clean_roles) self._fill_in_roles(context, new_trust, all_roles) return TrustV3.wrap_member(context, new_trust) except KeyError as e: raise exception.ValidationError(attribute=e.args[0], target='trust')
def _issue_v3_token(self, **kwargs): user_id = kwargs.get('user_id') method_names = kwargs.get('method_names') expires_at = kwargs.get('expires_at') project_id = kwargs.get('project_id') domain_id = kwargs.get('domain_id') auth_context = kwargs.get('auth_context') trust = kwargs.get('trust') metadata_ref = kwargs.get('metadata_ref') # for V2, trust is stashed in metadata_ref if (CONF.trust.enabled and not trust and metadata_ref and 'trust_id' in metadata_ref): trust = self.trust_api.get_trust(metadata_ref['trust_id']) token_data = self.v3_token_data_helper.get_token_data( user_id, method_names, auth_context.get('extras') if auth_context else None, domain_id=domain_id, project_id=project_id, expires=expires_at, trust=trust) token_id = self._get_token_id(token_data) try: expiry = token_data['token']['expires_at'] if isinstance(expiry, basestring): expiry = timeutils.normalize_time( timeutils.parse_isotime(expiry)) # FIXME(gyee): is there really a need to store roles in metadata? role_ids = [] metadata_ref = kwargs.get('metadata_ref', {}) if 'project' in token_data['token']: # project-scoped token, fill in the v2 token data # all we care are the role IDs role_ids = [r['id'] for r in token_data['token']['roles']] metadata_ref = {'roles': role_ids} if trust: metadata_ref.setdefault('trust_id', trust['id']) metadata_ref.setdefault('trustee_user_id', trust['trustee_user_id']) 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) self.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: self.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 create_token(context, auth_context, auth_info): token_data_helper = TokenDataHelper(context) (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 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(context, token_id, data) except Exception as e: # an identical token may have been created already. # if so, return the token_data as it is also identical try: token_api.get_token(context=context, token_id=token_id) except exception.TokenNotFound: raise e return (token_id, token_data)
def build_token_values_v2(access, default_domain_id): token_data = access['token'] token_expires_at = timeutils.parse_isotime(token_data['expires']) # Trim off the microseconds because the revocation event only has # expirations accurate to the second. token_expires_at = token_expires_at.replace(microsecond=0) token_values = { 'expires_at': timeutils.normalize_time(token_expires_at), 'issued_at': timeutils.normalize_time( timeutils.parse_isotime(token_data['issued_at']))} token_values['user_id'] = access.get('user', {}).get('id') project = token_data.get('tenant') if project is not None: token_values['project_id'] = project['id'] else: token_values['project_id'] = None token_values['identity_domain_id'] = default_domain_id token_values['assignment_domain_id'] = default_domain_id trust = token_data.get('trust') if trust is None: token_values['trust_id'] = None token_values['trustor_id'] = None token_values['trustee_id'] = None else: token_values['trust_id'] = trust['id'] token_values['trustor_id'] = trust['trustor_id'] token_values['trustee_id'] = trust['trustee_id'] token_values['consumer_id'] = None token_values['access_token_id'] = None role_list = [] # Roles are by ID in metadata and by name in the user section roles = access.get('metadata', {}).get('roles', []) for role in roles: role_list.append(role) token_values['roles'] = role_list return token_values
def assertEqualTokens(self, a, b): """Assert that two tokens are equal. Compare two tokens except for their ids. This also truncates the time in the comparison. """ def normalize(token): del token['expires'] del token['issued_at'] return token self.assertCloseEnoughForGovernmentWork( timeutils.parse_isotime(a['expires']), timeutils.parse_isotime(b['expires'])) self.assertCloseEnoughForGovernmentWork( timeutils.parse_isotime(a['issued_at']), timeutils.parse_isotime(b['issued_at'])) return self.assertDictEqual(normalize(a), normalize(b))
def authorize_request_token(self, context, request_token_id, roles): """An authenticated user is going to authorize a request token. As a security precaution, the requested roles must match those in the request token. Because this is in a CLI-only world at the moment, there is not another easy way to make sure the user knows which roles are being requested before authorizing. """ req_token = self.oauth_api.get_request_token(request_token_id) expires_at = req_token['expires_at'] if expires_at: now = timeutils.utcnow() expires = timeutils.normalize_time( timeutils.parse_isotime(expires_at)) if now > expires: raise exception.Unauthorized(_('Request token is expired')) # put the roles in a set for easy comparison authed_roles = set() for role in roles: authed_roles.add(role['id']) # verify the authorizing user has the roles user_token = self.token_api.get_token(context['token_id']) user_id = user_token['user'].get('id') project_id = req_token['requested_project_id'] user_roles = self.assignment_api.get_roles_for_user_and_project( user_id, project_id) cred_set = set(user_roles) if not cred_set.issuperset(authed_roles): msg = _('authorizing user does not have role required') raise exception.Unauthorized(message=msg) # create list of just the id's for the backend role_list = list(authed_roles) # verify the user has the project too req_project_id = req_token['requested_project_id'] user_projects = self.assignment_api.list_projects_for_user(user_id) found = False for user_project in user_projects: if user_project['id'] == req_project_id: found = True break if not found: msg = _("User is not a member of the requested project") raise exception.Unauthorized(message=msg) # finally authorize the token authed_token = self.oauth_api.authorize_request_token( request_token_id, user_id, role_list) to_return = {'token': {'oauth_verifier': authed_token['verifier']}} return to_return
def _parse_expiration_date(self, expiration_date): if expiration_date is None: return None if not expiration_date.endswith('Z'): expiration_date += 'Z' try: return timeutils.parse_isotime(expiration_date) except ValueError: raise exception.ValidationTimeStampError()
def assertReporteEventMatchesRecorded(self, event, sample, before_time): after_time = timeutils.utcnow() event_issued_before = timeutils.normalize_time( timeutils.parse_isotime(event['issued_before'])) self.assertTrue(before_time < event_issued_before, 'invalid event issued_before time; Too early') self.assertTrue(event_issued_before < after_time, 'invalid event issued_before time; too late') del (event['issued_before']) self.assertEqual(sample, event)
def authorize(self, context, request_token_id): """An authenticated user is going to authorize a request token. As a security precaution, the requested roles must match those in the request token. Because this is in a CLI-only world at the moment, there is not another easy way to make sure the user knows which roles are being requested before authorizing. """ req_token = self.oauth_api.get_request_token(request_token_id) expires_at = req_token['expires_at'] if expires_at: now = timeutils.utcnow() expires = timeutils.normalize_time( timeutils.parse_isotime(expires_at)) if now > expires: raise exception.Unauthorized(_('Request token is expired')) req_roles = req_token['requested_roles'] req_roles_list = jsonutils.loads(req_roles) req_set = set() for x in req_roles_list: req_set.add(x['id']) # verify the authorizing user has the roles user_token = self.token_api.get_token(context['token_id']) credentials = user_token['metadata'].copy() user_roles = credentials.get('roles') user_id = user_token['user'].get('id') cred_set = set(user_roles) if not cred_set.issuperset(req_set): msg = _('authorizing user does not have role required') raise exception.Unauthorized(message=msg) # verify the user has the project too req_project_id = req_token['requested_project_id'] user_projects = self.assignment_api.list_user_projects(user_id) found = False for user_project in user_projects: if user_project['id'] == req_project_id: found = True break if not found: msg = _("User is not a member of the requested project") raise exception.Unauthorized(message=msg) # finally authorize the token authed_token = self.oauth_api.authorize_request_token( request_token_id, user_id) to_return = {'token': {'oauth_verifier': authed_token['verifier']}} return to_return
def authorize_request_token(self, context, request_token_id, roles): """An authenticated user is going to authorize a request token. As a security precaution, the requested roles must match those in the request token. Because this is in a CLI-only world at the moment, there is not another easy way to make sure the user knows which roles are being requested before authorizing. """ auth_context = context.get("environment", {}).get("KEYSTONE_AUTH_CONTEXT", {}) if auth_context.get("is_delegated_auth"): raise exception.Forbidden(_("Cannot authorize a request token" " with a token issued via delegation.")) req_token = self.oauth_api.get_request_token(request_token_id) expires_at = req_token["expires_at"] if expires_at: now = timeutils.utcnow() expires = timeutils.normalize_time(timeutils.parse_isotime(expires_at)) if now > expires: raise exception.Unauthorized(_("Request token is expired")) # put the roles in a set for easy comparison authed_roles = set() for role in roles: authed_roles.add(role["id"]) # verify the authorizing user has the roles user_token = self.token_api.get_token(context["token_id"]) user_id = user_token["user"].get("id") project_id = req_token["requested_project_id"] user_roles = self.assignment_api.get_roles_for_user_and_project(user_id, project_id) cred_set = set(user_roles) if not cred_set.issuperset(authed_roles): msg = _("authorizing user does not have role required") raise exception.Unauthorized(message=msg) # create list of just the id's for the backend role_list = list(authed_roles) # verify the user has the project too req_project_id = req_token["requested_project_id"] user_projects = self.assignment_api.list_projects_for_user(user_id) for user_project in user_projects: if user_project["id"] == req_project_id: break else: msg = _("User is not a member of the requested project") raise exception.Unauthorized(message=msg) # finally authorize the token authed_token = self.oauth_api.authorize_request_token(request_token_id, user_id, role_list) to_return = {"token": {"oauth_verifier": authed_token["verifier"]}} return to_return
def assertEqualTokens(self, a, b): """Assert that two tokens are equal. Compare two tokens except for their ids. This also truncates the time in the comparison. """ def normalize(token): token["access"]["token"]["id"] = "dummy" del token["access"]["token"]["expires"] del token["access"]["token"]["issued_at"] return token self.assertCloseEnoughForGovernmentWork( timeutils.parse_isotime(a["access"]["token"]["expires"]), timeutils.parse_isotime(b["access"]["token"]["expires"]), ) self.assertCloseEnoughForGovernmentWork( timeutils.parse_isotime(a["access"]["token"]["issued_at"]), timeutils.parse_isotime(b["access"]["token"]["issued_at"]), ) return self.assertDictEqual(normalize(a), normalize(b))
def build_token_values_v2(access, default_domain_id): token_data = access["token"] token_values = { "expires_at": timeutils.normalize_time(timeutils.parse_isotime(token_data["expires"])), "issued_at": timeutils.normalize_time(timeutils.parse_isotime(token_data["issued_at"])), } token_values["user_id"] = access.get("user", {}).get("id") project = token_data.get("tenant") if project is not None: token_values["project_id"] = project["id"] else: token_values["project_id"] = None token_values["identity_domain_id"] = default_domain_id token_values["assignment_domain_id"] = default_domain_id trust = token_data.get("trust") if trust is None: token_values["trust_id"] = None token_values["trustor_id"] = None token_values["trustee_id"] = None else: token_values["trust_id"] = trust["id"] token_values["trustor_id"] = trust["trustor_id"] token_values["trustee_id"] = trust["trustee_id"] token_values["consumer_id"] = None token_values["access_token_id"] = None role_list = [] # Roles are by ID in metadata and by name in the user section roles = access.get("metadata", {}).get("roles", []) for role in roles: role_list.append(role) token_values["roles"] = role_list return token_values
def create_user(self, context, user): ref = self._assign_unique_id(self._normalize_dict(user)) user_id = user.get('id', None) if user_id is not None: ref['id'] = user_id expires = user.get('expires', None) if expires is not None: try: ref['expires'] = timeutils.parse_strtime(expires) except ValueError: ref['expires'] = timeutils.parse_isotime(expires) ref = self._normalize_domain_id(context, ref) ref = self.identity_api.create_user(context, ref['id'], ref) return UserV3.wrap_member(context, ref)
def _create_token(self, token_id, token_data): try: if isinstance(token_data['expires'], six.string_types): token_data['expires'] = timeutils.normalize_time( timeutils.parse_isotime(token_data['expires'])) self.token_api.create_token(token_id, token_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: self.token_api.get_token(token_id) except exception.TokenNotFound: six.reraise(*exc_info)
def create_trust(self, context, trust=None): """Create a new trust. The user creating the trust must be the trustor. """ # TODO(ayoung): instead of raising ValidationError on the first # problem, return a collection of all the problems. if not trust: raise exception.ValidationError(attribute='trust', target='request') try: user_id = self._get_user_id(context) _trustor_only(context, trust, user_id) #confirm that the trustee exists trustee_ref = self.identity_api.get_user(trust['trustee_user_id']) if not trustee_ref: raise exception.UserNotFound(user_id=trust['trustee_user_id']) all_roles = self.assignment_api.list_roles() clean_roles = self._clean_role_list(context, trust, all_roles) if trust.get('project_id'): user_role = self.assignment_api.get_roles_for_user_and_project( user_id, trust['project_id']) else: user_role = [] for trust_role in clean_roles: matching_roles = [x for x in user_role if x == trust_role['id']] if not matching_roles: raise exception.RoleNotFound(role_id=trust_role['id']) if trust.get('expires_at') is not None: if not trust['expires_at'].endswith('Z'): trust['expires_at'] += 'Z' try: trust['expires_at'] = (timeutils.parse_isotime (trust['expires_at'])) except ValueError: raise exception.ValidationTimeStampError() trust_id = uuid.uuid4().hex new_trust = self.trust_api.create_trust(trust_id, trust, clean_roles) self._fill_in_roles(context, new_trust, all_roles) return TrustV3.wrap_member(context, new_trust) except KeyError as e: raise exception.ValidationError(attribute=e.args[0], target='trust')
def assertReportedEventMatchesRecorded(self, event, sample, before_time): after_time = timeutils.utcnow() event_issued_before = timeutils.normalize_time( timeutils.parse_isotime(event['issued_before'])) self.assertTrue( before_time <= event_issued_before, 'invalid event issued_before time; %s is not later than %s.' % ( timeutils.isotime(event_issued_before, subsecond=True), timeutils.isotime(before_time, subsecond=True))) self.assertTrue( event_issued_before <= after_time, 'invalid event issued_before time; %s is not earlier than %s.' % ( timeutils.isotime(event_issued_before, subsecond=True), timeutils.isotime(after_time, subsecond=True))) del (event['issued_before']) self.assertEqual(sample, event)
def authenticate(self, context, auth_info, auth_context): """Turn a signed request with an access key into a keystone token.""" headers = context['headers'] oauth_headers = oauth.get_oauth_headers(headers) consumer_id = oauth_headers.get('oauth_consumer_key') access_token_id = oauth_headers.get('oauth_token') if not access_token_id: raise exception.ValidationError( attribute='oauth_token', target='request') acc_token = self.oauth_api.get_access_token(access_token_id) consumer = self.oauth_api.get_consumer_with_secret(consumer_id) expires_at = acc_token['expires_at'] if expires_at: now = timeutils.utcnow() expires = timeutils.normalize_time( timeutils.parse_isotime(expires_at)) if now > expires: raise exception.Unauthorized(_('Access token is expired')) consumer_obj = oauth1.Consumer(key=consumer['id'], secret=consumer['secret']) acc_token_obj = oauth1.Token(key=acc_token['id'], secret=acc_token['access_secret']) url = oauth.rebuild_url(context['path']) oauth_request = oauth1.Request.from_request( http_method='POST', http_url=url, headers=context['headers'], query_string=context['query_string']) oauth_server = oauth1.Server() oauth_server.add_signature_method(oauth1.SignatureMethod_HMAC_SHA1()) params = oauth_server.verify_request(oauth_request, consumer_obj, token=acc_token_obj) if params: msg = _('There should not be any non-oauth parameters') raise exception.Unauthorized(message=msg) auth_context['user_id'] = acc_token['authorizing_user_id'] auth_context['access_token_id'] = access_token_id auth_context['project_id'] = acc_token['project_id']
def build_token_values(token_data): token_expires_at = timeutils.parse_isotime(token_data['expires_at']) # Trim off the microseconds because the revocation event only has # expirations accurate to the second. token_expires_at = token_expires_at.replace(microsecond=0) token_values = { 'expires_at': timeutils.normalize_time(token_expires_at), 'issued_at': timeutils.normalize_time( timeutils.parse_isotime(token_data['issued_at'])) } user = token_data.get('user') if user is not None: token_values['user_id'] = user['id'] token_values['identity_domain_id'] = user['domain']['id'] else: token_values['user_id'] = None token_values['identity_domain_id'] = None project = token_data.get('project', token_data.get('tenant')) if project is not None: token_values['project_id'] = project['id'] token_values['assignment_domain_id'] = project['domain']['id'] else: token_values['project_id'] = None domain = token_data.get('domain') if domain is not None: token_values['assignment_domain_id'] = domain['id'] else: token_values['assignment_domain_id'] = None role_list = [] roles = token_data.get('roles') if roles is not None: for role in roles: role_list.append(role['id']) token_values['roles'] = role_list trust = token_data.get('OS-TRUST:trust') if trust is None: token_values['trust_id'] = None token_values['trustor_id'] = None token_values['trustee_id'] = None else: token_values['trust_id'] = trust['id'] token_values['trustor_id'] = trust['trustor_user']['id'] token_values['trustee_id'] = trust['trustee_user']['id'] oauth1 = token_data.get('OS-OAUTH1') if oauth1 is None: token_values['consumer_id'] = None token_values['access_token_id'] = None else: token_values['consumer_id'] = oauth1['consumer_id'] token_values['access_token_id'] = oauth1['access_token_id'] return token_values
def _authenticate_token(self, context, auth): """Try to authenticate using an already existing token. Returns auth_token_data, (user_ref, tenant_ref, metadata_ref) """ if 'token' not in auth: raise exception.ValidationError( attribute='token', target='auth') if "id" not in auth['token']: raise exception.ValidationError( attribute="id", target="token") old_token = auth['token']['id'] if len(old_token) > CONF.max_token_size: raise exception.ValidationSizeError(attribute='token', size=CONF.max_token_size) try: old_token_ref = self.token_api.get_token(context=context, token_id=old_token) except exception.NotFound as e: raise exception.Unauthorized(e) #A trust token cannot be used to get another token if 'trust' in old_token_ref: raise exception.Forbidden() if 'trust_id' in old_token_ref['metadata']: raise exception.Forbidden() user_ref = old_token_ref['user'] user_id = user_ref['id'] if not CONF.trust.enabled and 'trust_id' in auth: raise exception.Forbidden('Trusts are disabled.') elif CONF.trust.enabled and 'trust_id' in auth: trust_ref = self.trust_api.get_trust(context, auth['trust_id']) if trust_ref is None: raise exception.Forbidden() if user_id != trust_ref['trustee_user_id']: raise exception.Forbidden() if ('expires' in trust_ref) and (trust_ref['expires']): expiry = trust_ref['expires'] if expiry < timeutils.parse_isotime(timeutils.isotime()): raise exception.Forbidden()() user_id = trust_ref['trustor_user_id'] trustor_user_ref = (self.identity_api.get_user( context=context, user_id=trust_ref['trustor_user_id'])) if not trustor_user_ref['enabled']: raise exception.Forbidden()() trustee_user_ref = self.identity_api.get_user( context, trust_ref['trustee_user_id']) if not trustee_user_ref['enabled']: raise exception.Forbidden()() if trust_ref['impersonation'] == 'True': current_user_ref = trustor_user_ref else: current_user_ref = trustee_user_ref else: current_user_ref = self.identity_api.get_user(context=context, user_id=user_id) tenant_id = self._get_project_id_from_auth(context, auth) tenant_ref = self._get_project_ref(context, user_id, tenant_id) metadata_ref = self._get_metadata_ref(context, user_id, tenant_id) # TODO (henry-nash) If no tenant was specified, instead check # for a domain and find any related user/group roles self._append_roles(metadata_ref, self._get_group_metadata_ref( context, user_id, tenant_id)) expiry = old_token_ref['expires'] if CONF.trust.enabled and 'trust_id' in auth: trust_id = auth['trust_id'] trust_roles = [] for role in trust_ref['roles']: if not 'roles' in metadata_ref: raise exception.Forbidden()() if role['id'] in metadata_ref['roles']: trust_roles.append(role['id']) else: raise exception.Forbidden() if 'expiry' in trust_ref and trust_ref['expiry']: trust_expiry = timeutils.parse_isotime(trust_ref['expiry']) if trust_expiry < expiry: expiry = trust_expiry metadata_ref['roles'] = trust_roles metadata_ref['trustee_user_id'] = trust_ref['trustee_user_id'] metadata_ref['trust_id'] = trust_id return (current_user_ref, tenant_ref, metadata_ref, expiry)
def _update_user_list_with_cas(self, user_key, token_id): cas_retry = 0 max_cas_retry = CONF.memcache.max_compare_and_set_retry current_time = timeutils.normalize_time( timeutils.parse_isotime(timeutils.isotime())) self.client.reset_cas() while cas_retry <= max_cas_retry: # NOTE(morganfainberg): cas or "compare and set" is a function of # memcache. It will return false if the value has changed since the # last call to client.gets(). This is the memcache supported method # of avoiding race conditions on set(). Memcache is already atomic # on the back-end and serializes operations. # # cas_retry is for tracking our iterations before we give up (in # case memcache is down or something horrible happens we don't # iterate forever trying to compare and set the new value. cas_retry += 1 record = self.client.gets(user_key) filtered_list = [] if record is not None: token_list = jsonutils.loads('[%s]' % record) for token_i in token_list: ptk = self._prefix_token_id(token_i) token_ref = self.client.get(ptk) if not token_ref: # skip tokens that do not exist in memcache continue if 'expires' in token_ref: expires_at = timeutils.normalize_time( token_ref['expires']) if expires_at < current_time: # skip tokens that are expired. continue # Add the still valid token_id to the list. filtered_list.append(jsonutils.dumps(token_i)) # Add the new token_id to the list. filtered_list.append(token_id) # Use compare-and-set (cas) to set the new value for the # token-index-list for the user-key. Cas is used to prevent race # conditions from causing the loss of valid token ids from this # list. if self.client.cas(user_key, ','.join(filtered_list)): msg = _('Successful set of token-index-list for user-key ' '"%(user_key)s", #%(count)d records') LOG.debug(msg, { 'user_key': user_key, 'count': len(filtered_list) }) return filtered_list # The cas function will return true if it succeeded or false if it # failed for any reason, including memcache server being down, cas # id changed since gets() called (the data changed between when # this loop started and this point, etc. error_msg = _('Failed to set token-index-list for user-key ' '"%(user_key)s". Attempt %(cas_retry)d of ' '%(cas_retry_max)d') LOG.debug( error_msg, { 'user_key': user_key, 'cas_retry': cas_retry, 'cas_retry_max': max_cas_retry }) # Exceeded the maximum retry attempts. error_msg = _('Unable to add token user list') raise exception.UnexpectedError(error_msg)
def _authenticate_token(self, context, auth): """Try to authenticate using an already existing token. Returns auth_token_data, (user_ref, tenant_ref, metadata_ref) """ if 'token' not in auth: raise exception.ValidationError(attribute='token', target='auth') if "id" not in auth['token']: raise exception.ValidationError(attribute="id", target="token") old_token = auth['token']['id'] if len(old_token) > CONF.max_token_size: raise exception.ValidationSizeError(attribute='token', size=CONF.max_token_size) try: old_token_ref = self.token_api.get_token(old_token) except exception.NotFound as e: raise exception.Unauthorized(e) wsgi.validate_token_bind(context, old_token_ref) #A trust token cannot be used to get another token if 'trust' in old_token_ref: raise exception.Forbidden() if 'trust_id' in old_token_ref['metadata']: raise exception.Forbidden() user_ref = old_token_ref['user'] user_id = user_ref['id'] if not CONF.trust.enabled and 'trust_id' in auth: raise exception.Forbidden('Trusts are disabled.') elif CONF.trust.enabled and 'trust_id' in auth: trust_ref = self.trust_api.get_trust(auth['trust_id']) if trust_ref is None: raise exception.Forbidden() if user_id != trust_ref['trustee_user_id']: raise exception.Forbidden() if ('expires' in trust_ref) and (trust_ref['expires']): expiry = trust_ref['expires'] if expiry < timeutils.parse_isotime(timeutils.isotime()): raise exception.Forbidden()() user_id = trust_ref['trustor_user_id'] trustor_user_ref = self.identity_api.get_user( trust_ref['trustor_user_id']) if not trustor_user_ref['enabled']: raise exception.Forbidden()() trustee_user_ref = self.identity_api.get_user( trust_ref['trustee_user_id']) if not trustee_user_ref['enabled']: raise exception.Forbidden()() self.trust_api.consume_use(auth['trust_id']) if trust_ref['impersonation'] is True: current_user_ref = trustor_user_ref else: current_user_ref = trustee_user_ref else: current_user_ref = self.identity_api.get_user(user_id) metadata_ref = {} tenant_id = self._get_project_id_from_auth(auth) tenant_ref, metadata_ref['roles'] = self._get_project_roles_and_ref( user_id, tenant_id) expiry = old_token_ref['expires'] if CONF.trust.enabled and 'trust_id' in auth: trust_id = auth['trust_id'] trust_roles = [] for role in trust_ref['roles']: if 'roles' not in metadata_ref: raise exception.Forbidden()() if role['id'] in metadata_ref['roles']: trust_roles.append(role['id']) else: raise exception.Forbidden() if 'expiry' in trust_ref and trust_ref['expiry']: trust_expiry = timeutils.parse_isotime(trust_ref['expiry']) if trust_expiry < expiry: expiry = trust_expiry metadata_ref['roles'] = trust_roles metadata_ref['trustee_user_id'] = trust_ref['trustee_user_id'] metadata_ref['trust_id'] = trust_id bind = old_token_ref.get('bind') return (current_user_ref, tenant_ref, metadata_ref, expiry, bind)
def create_access_token(self, context): headers = context['headers'] oauth_headers = oauth1.get_oauth_headers(headers) consumer_id = oauth_headers.get('oauth_consumer_key') request_token_id = oauth_headers.get('oauth_token') oauth_verifier = oauth_headers.get('oauth_verifier') if not consumer_id: raise exception.ValidationError(attribute='oauth_consumer_key', target='request') if not request_token_id: raise exception.ValidationError(attribute='oauth_token', target='request') if not oauth_verifier: raise exception.ValidationError(attribute='oauth_verifier', target='request') req_token = self.oauth_api.get_request_token(request_token_id) expires_at = req_token['expires_at'] if expires_at: now = timeutils.utcnow() expires = timeutils.normalize_time( timeutils.parse_isotime(expires_at)) if now > expires: raise exception.Unauthorized(_('Request token is expired')) url = self.base_url(context, context['path']) access_verifier = oauth1.AccessTokenEndpoint( request_validator=validator.OAuthValidator(), token_generator=oauth1.token_generator) h, b, s = access_verifier.create_access_token_response( url, http_method='POST', body=context['query_string'], headers=headers) params = oauth1.extract_non_oauth_params(b) if len(params) != 0: msg = _('There should not be any non-oauth parameters') raise exception.Unauthorized(message=msg) if req_token['consumer_id'] != consumer_id: msg = _('provided consumer key does not match stored consumer key') raise exception.Unauthorized(message=msg) if req_token['verifier'] != oauth_verifier: msg = _('provided verifier does not match stored verifier') raise exception.Unauthorized(message=msg) if req_token['id'] != request_token_id: msg = _('provided request key does not match stored request key') raise exception.Unauthorized(message=msg) if not req_token.get('authorizing_user_id'): msg = _('Request Token does not have an authorizing user id') raise exception.Unauthorized(message=msg) access_token_duration = CONF.oauth1.access_token_duration token_ref = self.oauth_api.create_access_token(request_token_id, access_token_duration) result = ('oauth_token=%(key)s&oauth_token_secret=%(secret)s' % { 'key': token_ref['id'], 'secret': token_ref['access_secret'] }) if CONF.oauth1.access_token_duration: expiry_bit = '&oauth_expires_at=%s' % (token_ref['expires_at']) result += expiry_bit headers = [('Content-Type', 'application/x-www-urlformencoded')] response = wsgi.render_response(result, status=(201, 'Created'), headers=headers) return response
def authorize_request_token(self, context, request_token_id, roles): """An authenticated user is going to authorize a request token. As a security precaution, the requested roles must match those in the request token. Because this is in a CLI-only world at the moment, there is not another easy way to make sure the user knows which roles are being requested before authorizing. """ auth_context = context.get('environment', {}).get('KEYSTONE_AUTH_CONTEXT', {}) if auth_context.get('is_delegated_auth'): raise exception.Forbidden( _('Cannot authorize a request token' ' with a token issued via delegation.')) req_token = self.oauth_api.get_request_token(request_token_id) expires_at = req_token['expires_at'] if expires_at: now = timeutils.utcnow() expires = timeutils.normalize_time( timeutils.parse_isotime(expires_at)) if now > expires: raise exception.Unauthorized(_('Request token is expired')) # put the roles in a set for easy comparison authed_roles = set() for role in roles: authed_roles.add(role['id']) # verify the authorizing user has the roles user_token = self.token_api.get_token(context['token_id']) user_id = user_token['user'].get('id') project_id = req_token['requested_project_id'] user_roles = self.assignment_api.get_roles_for_user_and_project( user_id, project_id) cred_set = set(user_roles) if not cred_set.issuperset(authed_roles): msg = _('authorizing user does not have role required') raise exception.Unauthorized(message=msg) # create list of just the id's for the backend role_list = list(authed_roles) # verify the user has the project too req_project_id = req_token['requested_project_id'] user_projects = self.assignment_api.list_projects_for_user(user_id) for user_project in user_projects: if user_project['id'] == req_project_id: break else: msg = _("User is not a member of the requested project") raise exception.Unauthorized(message=msg) # finally authorize the token authed_token = self.oauth_api.authorize_request_token( request_token_id, user_id, role_list) to_return = {'token': {'oauth_verifier': authed_token['verifier']}} return to_return
def create_access_token(self, context): headers = context['headers'] oauth_headers = oauth1.get_oauth_headers(headers) consumer_id = oauth_headers.get('oauth_consumer_key') request_token_id = oauth_headers.get('oauth_token') oauth_verifier = oauth_headers.get('oauth_verifier') if not consumer_id: raise exception.ValidationError( attribute='oauth_consumer_key', target='request') if not request_token_id: raise exception.ValidationError( attribute='oauth_token', target='request') if not oauth_verifier: raise exception.ValidationError( attribute='oauth_verifier', target='request') consumer = self.oauth_api.get_consumer_with_secret(consumer_id) req_token = self.oauth_api.get_request_token( request_token_id) expires_at = req_token['expires_at'] if expires_at: now = timeutils.utcnow() expires = timeutils.normalize_time( timeutils.parse_isotime(expires_at)) if now > expires: raise exception.Unauthorized(_('Request token is expired')) consumer_obj = oauth1.Consumer(key=consumer['id'], secret=consumer['secret']) req_token_obj = oauth1.Token(key=req_token['id'], secret=req_token['request_secret']) req_token_obj.set_verifier(oauth_verifier) url = oauth1.rebuild_url(context['path']) oauth_request = oauth1.Request.from_request( http_method='POST', http_url=url, headers=context['headers'], query_string=context['query_string']) oauth_server = oauth1.Server() oauth_server.add_signature_method(oauth1.SignatureMethod_HMAC_SHA1()) params = oauth_server.verify_request(oauth_request, consumer_obj, token=req_token_obj) if len(params) != 0: msg = _('There should not be any non-oauth parameters') raise exception.Unauthorized(message=msg) if req_token['consumer_id'] != consumer_id: msg = _('provided consumer key does not match stored consumer key') raise exception.Unauthorized(message=msg) if req_token['verifier'] != oauth_verifier: msg = _('provided verifier does not match stored verifier') raise exception.Unauthorized(message=msg) if req_token['id'] != request_token_id: msg = _('provided request key does not match stored request key') raise exception.Unauthorized(message=msg) if not req_token.get('authorizing_user_id'): msg = _('Request Token does not have an authorizing user id') raise exception.Unauthorized(message=msg) access_token_duration = CONF.oauth1.access_token_duration token_ref = self.oauth_api.create_access_token(request_token_id, access_token_duration) result = ('oauth_token=%(key)s&oauth_token_secret=%(secret)s' % {'key': token_ref['id'], 'secret': token_ref['access_secret']}) if CONF.oauth1.access_token_duration: expiry_bit = '&oauth_expires_at=%s' % (token_ref['expires_at']) result += expiry_bit headers = [('Content-Type', 'application/x-www-urlformencoded')] response = wsgi.render_response(result, status=(201, 'Created'), headers=headers) return response
def issue_v3_token(self, user_id, method_names, expires_at=None, project_id=None, domain_id=None, auth_context=None, trust=None, metadata_ref=None, include_catalog=True): # for V2, trust is stashed in metadata_ref if (CONF.trust.enabled and not trust and metadata_ref and 'trust_id' in metadata_ref): trust = self.trust_api.get_trust(metadata_ref['trust_id']) access_token = None if 'oauth1' in method_names: if self.oauth_api: access_token_id = auth_context['access_token_id'] access_token = self.oauth_api.get_access_token(access_token_id) else: raise exception.Forbidden(_('Oauth is disabled.')) token_data = self.v3_token_data_helper.get_token_data( user_id, method_names, auth_context.get('extras') if auth_context else None, domain_id=domain_id, project_id=project_id, expires=expires_at, trust=trust, bind=auth_context.get('bind') if auth_context else None, include_catalog=include_catalog, access_token=access_token) token_id = self._get_token_id(token_data) try: expiry = token_data['token']['expires_at'] if isinstance(expiry, six.string_types): expiry = timeutils.normalize_time( timeutils.parse_isotime(expiry)) # FIXME(gyee): is there really a need to store roles in metadata? role_ids = [] if metadata_ref is None: metadata_ref = {} if 'project' in token_data['token']: # project-scoped token, fill in the v2 token data # all we care are the role IDs role_ids = [r['id'] for r in token_data['token']['roles']] metadata_ref = {'roles': role_ids} if trust: metadata_ref.setdefault('trust_id', trust['id']) metadata_ref.setdefault('trustee_user_id', trust['trustee_user_id']) 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_version=token.provider.V3) self.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: self.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 _issue_v3_token(self, **kwargs): user_id = kwargs.get('user_id') method_names = kwargs.get('method_names') expires_at = kwargs.get('expires_at') project_id = kwargs.get('project_id') domain_id = kwargs.get('domain_id') auth_context = kwargs.get('auth_context') trust = kwargs.get('trust') metadata_ref = kwargs.get('metadata_ref') include_catalog = kwargs.get('include_catalog') # for V2, trust is stashed in metadata_ref if (CONF.trust.enabled and not trust and metadata_ref and 'trust_id' in metadata_ref): trust = self.trust_api.get_trust(metadata_ref['trust_id']) token_data = self.v3_token_data_helper.get_token_data( user_id, method_names, auth_context.get('extras') if auth_context else None, domain_id=domain_id, project_id=project_id, expires=expires_at, trust=trust, bind=auth_context.get('bind') if auth_context else None, include_catalog=include_catalog) token_id = self._get_token_id(token_data) try: expiry = token_data['token']['expires_at'] if isinstance(expiry, basestring): expiry = timeutils.normalize_time( timeutils.parse_isotime(expiry)) # FIXME(gyee): is there really a need to store roles in metadata? role_ids = [] metadata_ref = kwargs.get('metadata_ref', {}) if 'project' in token_data['token']: # project-scoped token, fill in the v2 token data # all we care are the role IDs role_ids = [r['id'] for r in token_data['token']['roles']] metadata_ref = {'roles': role_ids} if trust: metadata_ref.setdefault('trust_id', trust['id']) metadata_ref.setdefault('trustee_user_id', trust['trustee_user_id']) 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) self.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: self.token_api.get_token(token_id) except exception.TokenNotFound: raise exc_info[0], exc_info[1], exc_info[2] return (token_id, token_data)