def _get_token_id(self, token_data): try: token_id = cms.cms_sign_token(json.dumps(token_data), CONF.signing.certfile, CONF.signing.keyfile) return token_id except environment.subprocess.CalledProcessError: LOG.exception("Unable to sign token") raise exception.UnexpectedError(_("Unable to sign token."))
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 _get_token_id(self, token_data): try: token_id = cms.cms_sign_token(json.dumps(token_data), CONF.signing.certfile, CONF.signing.keyfile) return token_id except environment.subprocess.CalledProcessError: LOG.exception('Unable to sign token') raise exception.UnexpectedError(_('Unable to sign token.'))
def test_v3_pki_token_id(self): self.opt_in_group('signing', token_format='PKI') auth_data = self.build_authentication_request( user_id=self.user['id'], password=self.user['password']) resp = self.post('/auth/tokens', body=auth_data) token_data = resp.body token_id = resp.getheader('X-Subject-Token') self.assertIn('expires_at', token_data['token']) token_signed = cms.cms_sign_token(json.dumps(token_data), CONF.signing.certfile, CONF.signing.keyfile) self.assertEqual(token_signed, token_id)
def _get_token_id(self, token_data): try: # force conversion to a string as the keystone client cms code # produces unicode. This can be removed if the client returns # str() # TODO(ayoung): Make to a byte_str for Python3 token_json = jsonutils.dumps(token_data, cls=utils.PKIEncoder) token_id = str(cms.cms_sign_token(token_json, CONF.signing.certfile, CONF.signing.keyfile)) return token_id except environment.subprocess.CalledProcessError: LOG.exception(_LE('Unable to sign token')) raise exception.UnexpectedError(_( 'Unable to sign token.'))
def authenticate(self, context, auth=None): """Authenticate credentials and return a token. Accept auth as a dict that looks like:: { "auth":{ "passwordCredentials":{ "username":"******", "password":"******" }, "tenantName":"customer-x" } } In this case, tenant is optional, if not provided the token will be considered "unscoped" and can later be used to get a scoped token. Alternatively, this call accepts auth with only a token and tenant that will return a token that is scoped to that tenant. """ if auth is None: raise exception.ValidationError(attribute='auth', target='request body') auth_token_data = None if "token" in auth: # Try to authenticate using a token auth_info = self._authenticate_token(context, auth) else: # Try external authentication try: auth_info = self._authenticate_external(context, auth) except ExternalAuthNotApplicable: # Try local authentication auth_info = self._authenticate_local(context, auth) user_ref, tenant_ref, metadata_ref, expiry = auth_info core.validate_auth_info(self, context, user_ref, tenant_ref) trust_id = metadata_ref.get('trust_id') user_ref = self._filter_domain_id(user_ref) if tenant_ref: tenant_ref = self._filter_domain_id(tenant_ref) auth_token_data = self._get_auth_token_data(user_ref, tenant_ref, metadata_ref, expiry) if tenant_ref: catalog_ref = self.catalog_api.get_catalog( context=context, user_id=user_ref['id'], tenant_id=tenant_ref['id'], metadata=metadata_ref) else: catalog_ref = {} auth_token_data['id'] = 'placeholder' roles_ref = [] for role_id in metadata_ref.get('roles', []): role_ref = self.identity_api.get_role(context, role_id) roles_ref.append(dict(name=role_ref['name'])) token_data = Auth.format_token(auth_token_data, roles_ref) service_catalog = Auth.format_catalog(catalog_ref) token_data['access']['serviceCatalog'] = service_catalog 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) try: self.token_api.create_token( context, token_id, dict(key=token_id, id=token_id, expires=auth_token_data['expires'], user=user_ref, tenant=tenant_ref, metadata=metadata_ref, trust_id=trust_id)) except Exception as e: # 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(context=context, token_id=token_id) except exception.TokenNotFound: raise e token_data['access']['token']['id'] = token_id return token_data
def authenticate(self, context, auth=None): """Authenticate credentials and return a token. Accept auth as a dict that looks like:: { "auth":{ "passwordCredentials":{ "username":"******", "password":"******" }, "tenantName":"customer-x" } } In this case, tenant is optional, if not provided the token will be considered "unscoped" and can later be used to get a scoped token. Alternatively, this call accepts auth with only a token and tenant that will return a token that is scoped to that tenant. """ if auth is None: raise exception.ValidationError(attribute='auth', target='request body') auth_token_data = None if "token" in auth: # Try to authenticate using a token auth_info = self._authenticate_token( context, auth) else: # Try external authentication try: auth_info = self._authenticate_external( context, auth) except ExternalAuthNotApplicable: # Try local authentication auth_info = self._authenticate_local( context, auth) user_ref, tenant_ref, metadata_ref, expiry = auth_info user_ref = self._filter_domain_id(user_ref) if tenant_ref: tenant_ref = self._filter_domain_id(tenant_ref) auth_token_data = self._get_auth_token_data(user_ref, tenant_ref, metadata_ref, expiry) # If the user is disabled don't allow them to authenticate if not user_ref.get('enabled', True): msg = 'User is disabled: %s' % user_ref['id'] LOG.warning(msg) raise exception.Unauthorized(msg) # If the user's domain is disabled don't allow them to authenticate # TODO(dolph): remove this check after default-domain migration if user_ref.get('domain_id') is not None: user_domain_ref = self.identity_api.get_domain( context, user_ref['domain_id']) if user_domain_ref and not user_domain_ref.get('enabled', True): msg = 'Domain is disabled: %s' % user_domain_ref['id'] LOG.warning(msg) raise exception.Unauthorized(msg) if tenant_ref: # If the project is disabled don't allow them to authenticate if not tenant_ref.get('enabled', True): msg = 'Tenant is disabled: %s' % tenant_ref['id'] LOG.warning(msg) raise exception.Unauthorized(msg) # If the project's domain is disabled don't allow them to # authenticate # TODO(dolph): remove this check after default-domain migration if tenant_ref.get('domain_id') is not None: project_domain_ref = self.identity_api.get_domain( context, tenant_ref['domain_id']) if (project_domain_ref and not project_domain_ref.get('enabled', True)): msg = 'Domain is disabled: %s' % project_domain_ref['id'] LOG.warning(msg) raise exception.Unauthorized(msg) catalog_ref = self.catalog_api.get_catalog( context=context, user_id=user_ref['id'], tenant_id=tenant_ref['id'], metadata=metadata_ref) else: catalog_ref = {} auth_token_data['id'] = 'placeholder' roles_ref = [] for role_id in metadata_ref.get('roles', []): role_ref = self.identity_api.get_role(context, role_id) roles_ref.append(dict(name=role_ref['name'])) token_data = Auth.format_token(auth_token_data, roles_ref) service_catalog = Auth.format_catalog(catalog_ref) token_data['access']['serviceCatalog'] = service_catalog if CONF.signing.token_format == 'UUID': token_id = uuid.uuid4().hex elif CONF.signing.token_format == 'PKI': token_id = cms.cms_sign_token(json.dumps(token_data), CONF.signing.certfile, CONF.signing.keyfile) else: raise exception.UnexpectedError( 'Invalid value for token_format: %s.' ' Allowed values are PKI or UUID.' % CONF.signing.token_format) try: self.token_api.create_token( context, token_id, dict(key=token_id, id=token_id, expires=auth_token_data['expires'], user=user_ref, tenant=tenant_ref, metadata=metadata_ref)) except Exception as e: # 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(context=context, token_id=token_id) except exception.TokenNotFound: raise e token_data['access']['token']['id'] = token_id return token_data
def authenticate(self, context, auth=None): """Authenticate credentials and return a token. Accept auth as a dict that looks like:: { "auth":{ "passwordCredentials":{ "username":"******", "password":"******" }, "tenantName":"customer-x" } } In this case, tenant is optional, if not provided the token will be considered "unscoped" and can later be used to get a scoped token. Alternatively, this call accepts auth with only a token and tenant that will return a token that is scoped to that tenant. """ if auth is None: raise exception.ValidationError(attribute='auth', target='request body') auth_token_data = None if "token" in auth: # Try to authenticate using a token auth_info = self._authenticate_token( context, auth) else: # Try external authentication try: auth_info = self._authenticate_external( context, auth) except ExternalAuthNotApplicable: # Try local authentication auth_info = self._authenticate_local( context, auth) user_ref, tenant_ref, metadata_ref, expiry = auth_info core.validate_auth_info(self, context, user_ref, tenant_ref) trust_id = metadata_ref.get('trust_id') user_ref = self._filter_domain_id(user_ref) if tenant_ref: tenant_ref = self._filter_domain_id(tenant_ref) auth_token_data = self._get_auth_token_data(user_ref, tenant_ref, metadata_ref, expiry) if tenant_ref: catalog_ref = self.catalog_api.get_catalog( context=context, user_id=user_ref['id'], tenant_id=tenant_ref['id'], metadata=metadata_ref) else: catalog_ref = {} auth_token_data['id'] = 'placeholder' roles_ref = [] for role_id in metadata_ref.get('roles', []): role_ref = self.identity_api.get_role(context, role_id) roles_ref.append(dict(name=role_ref['name'])) token_data = Auth.format_token(auth_token_data, roles_ref) service_catalog = Auth.format_catalog(catalog_ref) token_data['access']['serviceCatalog'] = service_catalog 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) try: self.token_api.create_token( context, token_id, dict(key=token_id, id=token_id, expires=auth_token_data['expires'], user=user_ref, tenant=tenant_ref, metadata=metadata_ref, trust_id=trust_id)) except Exception as e: # 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(context=context, token_id=token_id) except exception.TokenNotFound: raise e token_data['access']['token']['id'] = token_id return token_data
def authenticate(self, context, auth=None): """Authenticate credentials and return a token. Accept auth as a dict that looks like:: { "auth":{ "passwordCredentials":{ "username":"******", "password":"******" }, "tenantName":"customer-x" } } In this case, tenant is optional, if not provided the token will be considered "unscoped" and can later be used to get a scoped token. Alternatively, this call accepts auth with only a token and tenant that will return a token that is scoped to that tenant. """ if 'passwordCredentials' in auth: user_id = auth['passwordCredentials'].get('userId', None) username = auth['passwordCredentials'].get('username', '') password = auth['passwordCredentials'].get('password', '') tenant_name = auth.get('tenantName', None) if username: try: user_ref = self.identity_api.get_user_by_name( context=context, user_name=username) user_id = user_ref['id'] except exception.UserNotFound: raise exception.Unauthorized() # more compat tenant_id = auth.get('tenantId', None) if tenant_name: try: tenant_ref = self.identity_api.get_tenant_by_name( context=context, tenant_name=tenant_name) tenant_id = tenant_ref['id'] except exception.TenantNotFound: raise exception.Unauthorized() try: auth_info = self.identity_api.authenticate(context=context, user_id=user_id, password=password, tenant_id=tenant_id) (user_ref, tenant_ref, metadata_ref) = auth_info # If the user is disabled don't allow them to authenticate if not user_ref.get('enabled', True): LOG.warning('User %s is disabled' % user_id) raise exception.Unauthorized() # If the tenant is disabled don't allow them to authenticate if tenant_ref and not tenant_ref.get('enabled', True): LOG.warning('Tenant %s is disabled' % tenant_id) raise exception.Unauthorized() except AssertionError as e: raise exception.Unauthorized(e.message) auth_token_data = dict(zip(['user', 'tenant', 'metadata'], auth_info)) expiry = self.token_api._get_default_expire_time(context=context) if tenant_ref: catalog_ref = self.catalog_api.get_catalog( context=context, user_id=user_ref['id'], tenant_id=tenant_ref['id'], metadata=metadata_ref) else: catalog_ref = {} elif 'token' in auth: old_token = auth['token'].get('id', None) tenant_name = auth.get('tenantName') try: old_token_ref = self.token_api.get_token(context=context, token_id=old_token) except exception.NotFound: raise exception.Unauthorized() user_ref = old_token_ref['user'] user_id = user_ref['id'] current_user_ref = self.identity_api.get_user(context=context, user_id=user_id) # If the user is disabled don't allow them to authenticate if not current_user_ref.get('enabled', True): LOG.warning('User %s is disabled' % user_id) raise exception.Unauthorized() if tenant_name: tenant_ref = self.identity_api.get_tenant_by_name( context=context, tenant_name=tenant_name) tenant_id = tenant_ref['id'] else: tenant_id = auth.get('tenantId', None) tenants = self.identity_api.get_tenants_for_user(context, user_id) if tenant_id: if not tenant_id in tenants: LOG.warning('User %s is authorized for tenant %s' % (user_id, tenant_id)) raise exception.Unauthorized() # if the old token is sufficient unpack and return it if (old_token_ref['tenant'] and tenant_id == old_token_ref['tenant']['id'] and len(old_token) > cms.UUID_TOKEN_LENGTH): json_data = cms.verify_token( old_token, config.CONF.signing.certfile, config.CONF.signing.ca_certs) return_data = json.loads(json_data) return_data['access']['token']['id'] = old_token return return_data expiry = old_token_ref['expires'] try: tenant_ref = self.identity_api.get_tenant(context=context, tenant_id=tenant_id) except exception.TenantNotFound: tenant_ref = None metadata_ref = {} catalog_ref = {} except exception.MetadataNotFound: metadata_ref = {} catalog_ref = {} # If the tenant is disabled don't allow them to authenticate if tenant_ref and not tenant_ref.get('enabled', True): LOG.warning('Tenant %s is disabled' % tenant_id) raise exception.Unauthorized() if tenant_ref: metadata_ref = self.identity_api.get_metadata( context=context, user_id=user_ref['id'], tenant_id=tenant_ref['id']) catalog_ref = self.catalog_api.get_catalog( context=context, user_id=user_ref['id'], tenant_id=tenant_ref['id'], metadata=metadata_ref) auth_token_data = dict(dict(user=current_user_ref, tenant=tenant_ref, metadata=metadata_ref)) auth_token_data['expires'] = expiry auth_token_data['id'] = 'placeholder' roles_ref = [] for role_id in metadata_ref.get('roles', []): role_ref = self.identity_api.get_role(context, role_id) roles_ref.append(dict(name=role_ref['name'])) token_data = self._format_token(auth_token_data, roles_ref) service_catalog = self._format_catalog(catalog_ref) token_data['access']['serviceCatalog'] = service_catalog if config.CONF.signing.token_format == "UUID": token_id = uuid.uuid4().hex elif config.CONF.signing.token_format == "PKI": token_id = cms.cms_sign_token(json.dumps(token_data), config.CONF.signing.certfile, config.CONF.signing.keyfile) else: raise exception.UnexpectedError( "Invalid value for token_format: %s." " Allowed values are PKI or UUID." % config.CONF.signing.token_format) try: self.token_api.create_token( context, token_id, dict(key=token_id, id=token_id, user=user_ref, tenant=tenant_ref, metadata=metadata_ref)) except Exception as e: # 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(context=context, token_id=token_id) except exception.TokenNotFound: raise e token_data['access']['token']['id'] = token_id return token_data
def authenticate(self, context, auth=None): """Authenticate credentials and return a token. Accept auth as a dict that looks like:: { "auth":{ "passwordCredentials":{ "username":"******", "password":"******" }, "tenantName":"customer-x" } } In this case, tenant is optional, if not provided the token will be considered "unscoped" and can later be used to get a scoped token. Alternatively, this call accepts auth with only a token and tenant that will return a token that is scoped to that tenant. """ if 'passwordCredentials' in auth: user_id = auth['passwordCredentials'].get('userId', None) username = auth['passwordCredentials'].get('username', '') password = auth['passwordCredentials'].get('password', '') tenant_name = auth.get('tenantName', None) if username: try: user_ref = self.identity_api.get_user_by_name( context=context, user_name=username) user_id = user_ref['id'] except exception.UserNotFound: raise exception.Unauthorized() # more compat tenant_id = auth.get('tenantId', None) if tenant_name: try: tenant_ref = self.identity_api.get_tenant_by_name( context=context, tenant_name=tenant_name) tenant_id = tenant_ref['id'] except exception.TenantNotFound: raise exception.Unauthorized() try: auth_info = self.identity_api.authenticate(context=context, user_id=user_id, password=password, tenant_id=tenant_id) (user_ref, tenant_ref, metadata_ref) = auth_info # If the user is disabled don't allow them to authenticate if not user_ref.get('enabled', True): LOG.warning('User %s is disabled' % user_id) raise exception.Unauthorized() # If the tenant is disabled don't allow them to authenticate if tenant_ref and not tenant_ref.get('enabled', True): LOG.warning('Tenant %s is disabled' % tenant_id) raise exception.Unauthorized() except AssertionError as e: raise exception.Unauthorized(e.message) auth_token_data = dict( zip(['user', 'tenant', 'metadata'], auth_info)) expiry = self.token_api._get_default_expire_time(context=context) if tenant_ref: catalog_ref = self.catalog_api.get_catalog( context=context, user_id=user_ref['id'], tenant_id=tenant_ref['id'], metadata=metadata_ref) else: catalog_ref = {} elif 'token' in auth: old_token = auth['token'].get('id', None) tenant_name = auth.get('tenantName') try: old_token_ref = self.token_api.get_token(context=context, token_id=old_token) except exception.NotFound: LOG.warning("Token not found: " + str(old_token)) raise exception.Unauthorized() user_ref = old_token_ref['user'] user_id = user_ref['id'] current_user_ref = self.identity_api.get_user(context=context, user_id=user_id) # If the user is disabled don't allow them to authenticate if not current_user_ref.get('enabled', True): LOG.warning('User %s is disabled' % user_id) raise exception.Unauthorized() if tenant_name: tenant_ref = self.identity_api.get_tenant_by_name( context=context, tenant_name=tenant_name) tenant_id = tenant_ref['id'] else: tenant_id = auth.get('tenantId', None) tenants = self.identity_api.get_tenants_for_user(context, user_id) if tenant_id: if not tenant_id in tenants: LOG.warning('User %s is authorized for tenant %s' % (user_id, tenant_id)) raise exception.Unauthorized() expiry = old_token_ref['expires'] try: tenant_ref = self.identity_api.get_tenant(context=context, tenant_id=tenant_id) except exception.TenantNotFound: tenant_ref = None metadata_ref = {} catalog_ref = {} except exception.MetadataNotFound: metadata_ref = {} catalog_ref = {} # If the tenant is disabled don't allow them to authenticate if tenant_ref and not tenant_ref.get('enabled', True): LOG.warning('Tenant %s is disabled' % tenant_id) raise exception.Unauthorized() if tenant_ref: metadata_ref = self.identity_api.get_metadata( context=context, user_id=user_ref['id'], tenant_id=tenant_ref['id']) catalog_ref = self.catalog_api.get_catalog( context=context, user_id=user_ref['id'], tenant_id=tenant_ref['id'], metadata=metadata_ref) auth_token_data = dict( dict(user=current_user_ref, tenant=tenant_ref, metadata=metadata_ref)) auth_token_data['expires'] = expiry auth_token_data['id'] = 'placeholder' roles_ref = [] for role_id in metadata_ref.get('roles', []): role_ref = self.identity_api.get_role(context, role_id) roles_ref.append(dict(name=role_ref['name'])) token_data = self._format_token(auth_token_data, roles_ref) service_catalog = self._format_catalog(catalog_ref) token_data['access']['serviceCatalog'] = service_catalog if config.CONF.signing.token_format == 'UUID': token_id = uuid.uuid4().hex elif config.CONF.signing.token_format == 'PKI': token_id = cms.cms_sign_token(json.dumps(token_data), config.CONF.signing.certfile, config.CONF.signing.keyfile) else: raise exception.UnexpectedError( 'Invalid value for token_format: %s.' ' Allowed values are PKI or UUID.' % config.CONF.signing.token_format) try: self.token_api.create_token( context, token_id, dict(key=token_id, id=token_id, user=user_ref, tenant=tenant_ref, metadata=metadata_ref)) except Exception as e: # 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(context=context, token_id=token_id) except exception.TokenNotFound: raise e token_data['access']['token']['id'] = token_id return token_data
def authenticate(self, context, auth=None): """Authenticate credentials and return a token. Accept auth as a dict that looks like:: { "auth":{ "passwordCredentials":{ "username":"******", "password":"******" }, "tenantName":"customer-x" } } In this case, tenant is optional, if not provided the token will be considered "unscoped" and can later be used to get a scoped token. Alternatively, this call accepts auth with only a token and tenant that will return a token that is scoped to that tenant. """ if not auth: raise exception.ValidationError(attribute='auth', target='request body') if auth is None: auth = {} remote_auth = False if 'REMOTE_USER' in context and not 'token' in auth: # authenticated external request remote_auth = True if 'passwordCredentials' not in auth: auth['passwordCredentials'] = {} auth['passwordCredentials']['username'] = context.get( 'REMOTE_USER', None) if 'passwordCredentials' in auth: user_id = auth['passwordCredentials'].get('userId', None) username = auth['passwordCredentials'].get('username', '') password = auth['passwordCredentials'].get('password', '') tenant_name = auth.get('tenantName', None) if not user_id and not username: raise exception.ValidationError( attribute='username or userId', target='passwordCredentials') tenant_ref = None user_ref = None metadata_ref = {} if username: try: user_ref = self.identity_api.get_user_by_name( context=context, user_name=username) user_id = user_ref['id'] except exception.UserNotFound: raise exception.Unauthorized() if not password and not remote_auth: raise exception.ValidationError( attribute='password', target='passwordCredentials') # more compat tenant_id = auth.get('tenantId', None) if tenant_name: try: tenant_ref = self.identity_api.get_tenant_by_name( context=context, tenant_name=tenant_name) tenant_id = tenant_ref['id'] except exception.TenantNotFound: raise exception.Unauthorized() try: if not remote_auth: # local identity authentication required auth_info = self.identity_api.authenticate( context=context, user_id=user_id, password=password, tenant_id=tenant_id) (user_ref, tenant_ref, metadata_ref) = auth_info else: # remote authentication already performed if not user_ref: user_ref = self.identity_api.get_user( self.identity_api, user_id) if tenant_id: if not tenant_ref: tenant_ref = self.identity_api.get_tenant( self.identity_api, tenant_id) metadata_ref = self.identity_api.get_metadata( self.identity_api, user_id, tenant_id) auth_info = (user_ref, tenant_ref, metadata_ref) # If the user is disabled don't allow them to authenticate if not user_ref.get('enabled', True): LOG.warning('User %s is disabled' % user_id) raise exception.Unauthorized() # If the tenant is disabled don't allow them to authenticate if tenant_ref and not tenant_ref.get('enabled', True): LOG.warning('Tenant %s is disabled' % tenant_id) raise exception.Unauthorized() except AssertionError as e: raise exception.Unauthorized(str(e)) auth_token_data = dict(zip(['user', 'tenant', 'metadata'], auth_info)) expiry = self.token_api._get_default_expire_time(context=context) if tenant_ref: catalog_ref = self.catalog_api.get_catalog( context=context, user_id=user_ref['id'], tenant_id=tenant_ref['id'], metadata=metadata_ref) else: catalog_ref = {} elif 'token' in auth: old_token = auth['token'].get('id', None) tenant_name = auth.get('tenantName') try: old_token_ref = self.token_api.get_token(context=context, token_id=old_token) except exception.NotFound: LOG.warning("Token not found: " + str(old_token)) raise exception.Unauthorized() user_ref = old_token_ref['user'] user_id = user_ref['id'] current_user_ref = self.identity_api.get_user(context=context, user_id=user_id) # If the user is disabled don't allow them to authenticate if not current_user_ref.get('enabled', True): LOG.warning('User %s is disabled' % user_id) raise exception.Unauthorized() if tenant_name: tenant_ref = self.identity_api.get_tenant_by_name( context=context, tenant_name=tenant_name) tenant_id = tenant_ref['id'] else: tenant_id = auth.get('tenantId', None) tenants = self.identity_api.get_tenants_for_user(context, user_id) if tenant_id: if not tenant_id in tenants: LOG.warning('User %s is unauthorized for tenant %s' % (user_id, tenant_id)) raise exception.Unauthorized() expiry = old_token_ref['expires'] try: tenant_ref = self.identity_api.get_tenant(context=context, tenant_id=tenant_id) except exception.TenantNotFound: tenant_ref = None metadata_ref = {} catalog_ref = {} except exception.MetadataNotFound: metadata_ref = {} catalog_ref = {} # If the tenant is disabled don't allow them to authenticate if tenant_ref and not tenant_ref.get('enabled', True): LOG.warning('Tenant %s is disabled' % tenant_id) raise exception.Unauthorized() if tenant_ref: metadata_ref = self.identity_api.get_metadata( context=context, user_id=user_ref['id'], tenant_id=tenant_ref['id']) catalog_ref = self.catalog_api.get_catalog( context=context, user_id=user_ref['id'], tenant_id=tenant_ref['id'], metadata=metadata_ref) auth_token_data = dict(dict(user=current_user_ref, tenant=tenant_ref, metadata=metadata_ref)) else: raise exception.ValidationError( attribute='passwordCredentials or token', target='auth') auth_token_data['expires'] = expiry auth_token_data['id'] = 'placeholder' roles_ref = [] for role_id in metadata_ref.get('roles', []): role_ref = self.identity_api.get_role(context, role_id) roles_ref.append(dict(name=role_ref['name'])) token_data = self._format_token(auth_token_data, roles_ref) service_catalog = self._format_catalog(catalog_ref) token_data['access']['serviceCatalog'] = service_catalog if config.CONF.signing.token_format == 'UUID': token_id = uuid.uuid4().hex elif config.CONF.signing.token_format == 'PKI': token_id = cms.cms_sign_token(json.dumps(token_data), config.CONF.signing.certfile, config.CONF.signing.keyfile) else: raise exception.UnexpectedError( 'Invalid value for token_format: %s.' ' Allowed values are PKI or UUID.' % config.CONF.signing.token_format) try: self.token_api.create_token( context, token_id, dict(key=token_id, id=token_id, user=user_ref, tenant=tenant_ref, metadata=metadata_ref)) except Exception as e: # 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(context=context, token_id=token_id) except exception.TokenNotFound: raise e token_data['access']['token']['id'] = token_id return token_data
def authenticate(self, context, auth=None): """Authenticate credentials and return a token. Accept auth as a dict that looks like:: { "auth":{ "passwordCredentials":{ "username":"******", "password":"******" }, "tenantName":"customer-x" } } In this case, tenant is optional, if not provided the token will be considered "unscoped" and can later be used to get a scoped token. Alternatively, this call accepts auth with only a token and tenant that will return a token that is scoped to that tenant. """ if "passwordCredentials" in auth: user_id = auth["passwordCredentials"].get("userId", None) username = auth["passwordCredentials"].get("username", "") password = auth["passwordCredentials"].get("password", "") tenant_name = auth.get("tenantName", None) if username: try: user_ref = self.identity_api.get_user_by_name(context=context, user_name=username) user_id = user_ref["id"] except exception.UserNotFound: raise exception.Unauthorized() # more compat tenant_id = auth.get("tenantId", None) if tenant_name: try: tenant_ref = self.identity_api.get_tenant_by_name(context=context, tenant_name=tenant_name) tenant_id = tenant_ref["id"] except exception.TenantNotFound: raise exception.Unauthorized() try: auth_info = self.identity_api.authenticate( context=context, user_id=user_id, password=password, tenant_id=tenant_id ) (user_ref, tenant_ref, metadata_ref) = auth_info # If the user is disabled don't allow them to authenticate if not user_ref.get("enabled", True): LOG.warning("User %s is disabled" % user_id) raise exception.Unauthorized() # If the tenant is disabled don't allow them to authenticate if tenant_ref and not tenant_ref.get("enabled", True): LOG.warning("Tenant %s is disabled" % tenant_id) raise exception.Unauthorized() except AssertionError as e: raise exception.Unauthorized(e.message) auth_token_data = dict(zip(["user", "tenant", "metadata"], auth_info)) expiry = self.token_api._get_default_expire_time(context=context) if tenant_ref: catalog_ref = self.catalog_api.get_catalog( context=context, user_id=user_ref["id"], tenant_id=tenant_ref["id"], metadata=metadata_ref ) else: catalog_ref = {} elif "token" in auth: old_token = auth["token"].get("id", None) tenant_name = auth.get("tenantName") try: old_token_ref = self.token_api.get_token(context=context, token_id=old_token) except exception.NotFound: LOG.warning("Token not found: " + str(old_token)) raise exception.Unauthorized() user_ref = old_token_ref["user"] user_id = user_ref["id"] current_user_ref = self.identity_api.get_user(context=context, user_id=user_id) # If the user is disabled don't allow them to authenticate if not current_user_ref.get("enabled", True): LOG.warning("User %s is disabled" % user_id) raise exception.Unauthorized() if tenant_name: tenant_ref = self.identity_api.get_tenant_by_name(context=context, tenant_name=tenant_name) tenant_id = tenant_ref["id"] else: tenant_id = auth.get("tenantId", None) tenants = self.identity_api.get_tenants_for_user(context, user_id) if tenant_id: if not tenant_id in tenants: LOG.warning("User %s is authorized for tenant %s" % (user_id, tenant_id)) raise exception.Unauthorized() expiry = old_token_ref["expires"] try: tenant_ref = self.identity_api.get_tenant(context=context, tenant_id=tenant_id) except exception.TenantNotFound: tenant_ref = None metadata_ref = {} catalog_ref = {} except exception.MetadataNotFound: metadata_ref = {} catalog_ref = {} # If the tenant is disabled don't allow them to authenticate if tenant_ref and not tenant_ref.get("enabled", True): LOG.warning("Tenant %s is disabled" % tenant_id) raise exception.Unauthorized() if tenant_ref: metadata_ref = self.identity_api.get_metadata( context=context, user_id=user_ref["id"], tenant_id=tenant_ref["id"] ) catalog_ref = self.catalog_api.get_catalog( context=context, user_id=user_ref["id"], tenant_id=tenant_ref["id"], metadata=metadata_ref ) auth_token_data = dict(dict(user=current_user_ref, tenant=tenant_ref, metadata=metadata_ref)) auth_token_data["expires"] = expiry auth_token_data["id"] = "placeholder" roles_ref = [] for role_id in metadata_ref.get("roles", []): role_ref = self.identity_api.get_role(context, role_id) roles_ref.append(dict(name=role_ref["name"])) token_data = self._format_token(auth_token_data, roles_ref) service_catalog = self._format_catalog(catalog_ref) token_data["access"]["serviceCatalog"] = service_catalog if config.CONF.signing.token_format == "UUID": token_id = uuid.uuid4().hex elif config.CONF.signing.token_format == "PKI": token_id = cms.cms_sign_token( json.dumps(token_data), config.CONF.signing.certfile, config.CONF.signing.keyfile ) else: raise exception.UnexpectedError( "Invalid value for token_format: %s." " Allowed values are PKI or UUID." % config.CONF.signing.token_format ) try: self.token_api.create_token( context, token_id, dict(key=token_id, id=token_id, user=user_ref, tenant=tenant_ref, metadata=metadata_ref), ) except Exception as e: # 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(context=context, token_id=token_id) except exception.TokenNotFound: raise e token_data["access"]["token"]["id"] = token_id return token_data