def delete_consumer(self, context, consumer_id): user_token_ref = utils.get_token_ref(context) payload = {'user_id': user_token_ref.user_id, 'consumer_id': consumer_id} _emit_user_oauth_consumer_token_invalidate(payload) initiator = notifications._get_request_audit_info(context) self.oauth_api.delete_consumer(consumer_id, initiator)
def assert_admin(self, context): """Ensure the user is an admin. :raises keystone.exception.Unauthorized: if a token could not be found/authorized, a user is invalid, or a tenant is invalid/not scoped. :raises keystone.exception.Forbidden: if the user is not an admin and does not have the admin role """ if not context['is_admin']: user_token_ref = utils.get_token_ref(context) validate_token_bind(context, user_token_ref) creds = copy.deepcopy(user_token_ref.metadata) try: creds['user_id'] = user_token_ref.user_id except exception.UnexpectedError: LOG.debug('Invalid user') raise exception.Unauthorized() if user_token_ref.project_scoped: creds['tenant_id'] = user_token_ref.project_id else: LOG.debug('Invalid tenant') raise exception.Unauthorized() creds['roles'] = user_token_ref.role_names # Accept either is_admin or the admin role self.policy_api.enforce(creds, 'admin_required', {})
def _get_domain_id_for_list_request(self, request): """Get the domain_id for a v3 list call. If we running with multiple domain drivers, then the caller must specify a domain_id either as a filter or as part of the token scope. """ if not CONF.identity.domain_specific_drivers_enabled: # We don't need to specify a domain ID in this case return domain_id = request.params.get('domain_id') if domain_id: return domain_id token_ref = utils.get_token_ref(request.context_dict) if token_ref.domain_scoped: return token_ref.domain_id elif token_ref.project_scoped: return token_ref.project_domain_id else: LOG.warning( _LW('No domain information specified as part of list request')) raise exception.Unauthorized()
def _get_domain_id_from_token(self, context): """Get the domain_id for a v3 create call. In the case of a v3 create entity call that does not specify a domain ID, the spec says that we should use the domain scoping from the token being used. """ token_ref = utils.get_token_ref(context) if token_ref.domain_scoped: return token_ref.domain_id else: # TODO(henry-nash): We should issue an exception here since if # a v3 call does not explicitly specify the domain_id in the # entity, it should be using a domain scoped token. However, # the current tempest heat tests issue a v3 call without this. # This is raised as bug #1283539. Once this is fixed, we # should remove the line below and replace it with an error. # # Ahead of actually changing the code to raise an exception, we # issue a deprecation warning. versionutils.report_deprecated_feature( LOG, _LW('Not specifying a domain during a create user, group or ' 'project call, and relying on falling back to the ' 'default domain, is deprecated as of Liberty and will be ' 'removed in the N release. Specify the domain explicitly ' 'or use a domain-scoped token')) return CONF.identity.default_domain_id
def authorize_request_token(self, request, 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. """ if request.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 = utils.get_token_ref(request.context_dict) user_id = user_token.user_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_ids = 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_ids) to_return = {'token': {'oauth_verifier': authed_token['verifier']}} return to_return
def delete_consumer(self, request, consumer_id): user_token_ref = utils.get_token_ref(request.context_dict) payload = {'user_id': user_token_ref.user_id, 'consumer_id': consumer_id} _emit_user_oauth_consumer_token_invalidate(payload) self.oauth_api.delete_consumer( consumer_id, initiator=request.audit_initiator )
def delete_consumer(self, request, consumer_id): user_token_ref = utils.get_token_ref(request.context_dict) payload = { 'user_id': user_token_ref.user_id, 'consumer_id': consumer_id } _emit_user_oauth_consumer_token_invalidate(payload) self.oauth_api.delete_consumer(consumer_id, initiator=request.audit_initiator)
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 = utils.get_token_ref(context) user_id = user_token.user_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_ids = 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_ids) to_return = {"token": {"oauth_verifier": authed_token["verifier"]}} return to_return
def _assert_identity(self, context, user_id): """Check that the provided token belongs to the user. :param context: standard context :param user_id: id of user :raises keystone.exception.Forbidden: when token is invalid """ token_ref = utils.get_token_ref(context) if token_ref.user_id != user_id: raise exception.Forbidden(_("Token belongs to another user"))
def _assert_identity(self, context, user_id): """Check that the provided token belongs to the user. :param context: standard context :param user_id: id of user :raises exception.Forbidden: when token is invalid """ token_ref = utils.get_token_ref(context) if token_ref.user_id != user_id: raise exception.Forbidden(_('Token belongs to another user'))
def _get_trust_id_for_request(self, context): """Get the trust_id for a call. Retrieve the trust_id from the token Returns None if token is not trust scoped """ if ('token_id' not in context or context.get('token_id') == CONF.admin_token): LOG.debug(('will not lookup trust as the request auth token is ' 'either absent or it is the system admin token')) return None token_ref = utils.get_token_ref(context) return token_ref.trust_id
def authorize_request_token(self, request, 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. """ if request.context.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 = utils.get_token_ref(request.context_dict) user_id = user_token.user_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_ids = list(authed_roles) # finally authorize the token authed_token = self.oauth_api.authorize_request_token( request_token_id, user_id, role_ids) to_return = {'token': {'oauth_verifier': authed_token['verifier']}} return to_return
def get_projects_for_token(self, context, **kw): """Get valid tenants for token based on token used to authenticate. Pulls the token from the context, validates it and gets the valid tenants for the user in the token. Doesn't care about token scopedness. """ token_ref = utils.get_token_ref(context) tenant_refs = self.assignment_api.list_projects_for_user(token_ref.user_id) tenant_refs = [ self.v3_to_v2_project(ref) for ref in tenant_refs if ref["domain_id"] == CONF.identity.default_domain_id ] params = {"limit": context["query_string"].get("limit"), "marker": context["query_string"].get("marker")} return self.format_project_list(tenant_refs, **params)
def get_projects_for_token(self, request, **kw): """Get valid tenants for token based on token used to authenticate. Pulls the token from the context, validates it and gets the valid tenants for the user in the token. Doesn't care about token scopedness. """ token_ref = utils.get_token_ref(request.context_dict) tenant_refs = (self.assignment_api.list_projects_for_user( token_ref.user_id)) tenant_refs = [ self.v3_to_v2_project(ref) for ref in tenant_refs if ref['domain_id'] == CONF.identity.default_domain_id ] params = { 'limit': request.params.get('limit'), 'marker': request.params.get('marker'), } return self.format_project_list(tenant_refs, **params)
def _get_domain_id_from_token(self, context): """Get the domain_id for a v3 create call. In the case of a v3 create entity call that does not specify a domain ID, the spec says that we should use the domain scoping from the token being used. """ token_ref = utils.get_token_ref(context) if token_ref.domain_scoped: return token_ref.domain_id else: # TODO(henry-nash): We should issue an exception here since if # a v3 call does not explicitly specify the domain_id in the # entity, it should be using a domain scoped token. However, # the current tempest heat tests issue a v3 call without this. # This is raised as bug #1283539. Once this is fixed, we # should remove the line below and replace it with an error. return CONF.identity.default_domain_id
def get_projects_for_token(self, request, **kw): """Get valid tenants for token based on token used to authenticate. Pulls the token from the context, validates it and gets the valid tenants for the user in the token. Doesn't care about token scopedness. """ token_ref = utils.get_token_ref(request.context_dict) tenant_refs = ( self.assignment_api.list_projects_for_user(token_ref.user_id)) tenant_refs = [self.v3_to_v2_project(ref) for ref in tenant_refs if ref['domain_id'] == CONF.identity.default_domain_id] params = { 'limit': request.params.get('limit'), 'marker': request.params.get('marker'), } return self.format_project_list(tenant_refs, **params)
def _get_domain_id_from_token(self, context): """Get the domain_id for a v3 create call. In the case of a v3 create entity call that does not specify a domain ID, the spec says that we should use the domain scoping from the token being used. """ try: token_ref = utils.get_token_ref(context) except exception.Unauthorized: if context.get('is_admin'): raise exception.ValidationError( _('You have tried to create a resource using the admin ' 'token. As this token is not within a domain you must ' 'explicitly include a domain for this resource to ' 'belong to.')) raise if token_ref.domain_scoped: return token_ref.domain_id else: # TODO(henry-nash): We should issue an exception here since if # a v3 call does not explicitly specify the domain_id in the # entity, it should be using a domain scoped token. However, # the current tempest heat tests issue a v3 call without this. # This is raised as bug #1283539. Once this is fixed, we # should remove the line below and replace it with an error. # # Ahead of actually changing the code to raise an exception, we # issue a deprecation warning. versionutils.report_deprecated_feature( LOG, _LW('Not specifying a domain during a create user, group or ' 'project call, and relying on falling back to the ' 'default domain, is deprecated as of Liberty. There is no ' 'plan to remove this compatibility, however, future API ' 'versions may remove this, so please specify the domain ' 'explicitly or use a domain-scoped token.')) return CONF.identity.default_domain_id
def _get_user_id(self, context): try: token_ref = utils.get_token_ref(context) except exception.Unauthorized: return None return token_ref.user_id