Wrap v3 API with RBAC (bug 1023943)
Change-Id: Ie77be83054ea88bb0860260e1750196ac5ded650
This commit is contained in:
parent
715a17b71d
commit
84cd8ff7f3
@ -1,3 +1,57 @@
|
||||
{
|
||||
"admin_required": [["role:admin"], ["is_admin:1"]]
|
||||
"admin_required": [["role:admin"], ["is_admin:1"]],
|
||||
|
||||
"identity:get_service": [["rule:admin_required"]],
|
||||
"identity:list_services": [["rule:admin_required"]],
|
||||
"identity:create_service": [["rule:admin_required"]],
|
||||
"identity:update_service": [["rule:admin_required"]],
|
||||
"identity:delete_service": [["rule:admin_required"]],
|
||||
|
||||
"identity:get_endpoint": [["rule:admin_required"]],
|
||||
"identity:list_endpoints": [["rule:admin_required"]],
|
||||
"identity:create_endpoint": [["rule:admin_required"]],
|
||||
"identity:update_endpoint": [["rule:admin_required"]],
|
||||
"identity:delete_endpoint": [["rule:admin_required"]],
|
||||
|
||||
"identity:get_domain": [["rule:admin_required"]],
|
||||
"identity:list_domains": [["rule:admin_required"]],
|
||||
"identity:create_domain": [["rule:admin_required"]],
|
||||
"identity:update_domain": [["rule:admin_required"]],
|
||||
"identity:delete_domain": [["rule:admin_required"]],
|
||||
|
||||
"identity:get_project": [["rule:admin_required"]],
|
||||
"identity:list_projects": [["rule:admin_required"]],
|
||||
"identity:list_user_projects": [["rule:admin_required"], ["user_id:%(user_id)s"]],
|
||||
"identity:create_project": [["rule:admin_required"]],
|
||||
"identity:update_project": [["rule:admin_required"]],
|
||||
"identity:delete_project": [["rule:admin_required"]],
|
||||
|
||||
"identity:get_user": [["rule:admin_required"]],
|
||||
"identity:list_users": [["rule:admin_required"]],
|
||||
"identity:create_user": [["rule:admin_required"]],
|
||||
"identity:update_user": [["rule:admin_required"]],
|
||||
"identity:delete_user": [["rule:admin_required"]],
|
||||
|
||||
"identity:get_credential": [["rule:admin_required"]],
|
||||
"identity:list_credentials": [["rule:admin_required"]],
|
||||
"identity:create_credential": [["rule:admin_required"]],
|
||||
"identity:update_credential": [["rule:admin_required"]],
|
||||
"identity:delete_credential": [["rule:admin_required"]],
|
||||
|
||||
"identity:get_role": [["rule:admin_required"]],
|
||||
"identity:list_roles": [["rule:admin_required"]],
|
||||
"identity:create_role": [["rule:admin_required"]],
|
||||
"identity:update_roles": [["rule:admin_required"]],
|
||||
"identity:delete_roles": [["rule:admin_required"]],
|
||||
|
||||
"identity:check_grant": [["rule:admin_required"]],
|
||||
"identity:list_grants": [["rule:admin_required"]],
|
||||
"identity:create_grant": [["rule:admin_required"]],
|
||||
"identity:revoke_grant": [["rule:admin_required"]],
|
||||
|
||||
"identity:get_policy": [["rule:admin_required"]],
|
||||
"identity:list_policies": [["rule:admin_required"]],
|
||||
"identity:create_policy": [["rule:admin_required"]],
|
||||
"identity:update_policy": [["rule:admin_required"]],
|
||||
"identity:delete_policy": [["rule:admin_required"]]
|
||||
}
|
||||
|
@ -278,46 +278,40 @@ class EndpointController(wsgi.Application):
|
||||
|
||||
|
||||
class ServiceControllerV3(controller.V3Controller):
|
||||
@controller.protected
|
||||
def create_service(self, context, service):
|
||||
self.assert_admin(context)
|
||||
|
||||
ref = self._assign_unique_id(self._normalize_dict(service))
|
||||
self._require_attribute(ref, 'type')
|
||||
|
||||
ref = self.catalog_api.create_service(context, ref['id'], ref)
|
||||
return {'service': ref}
|
||||
|
||||
@controller.protected
|
||||
def list_services(self, context):
|
||||
self.assert_admin(context)
|
||||
|
||||
refs = self.catalog_api.list_services(context)
|
||||
refs = self._filter_by_attribute(context, refs, 'type')
|
||||
return {'services': self._paginate(context, refs)}
|
||||
|
||||
@controller.protected
|
||||
def get_service(self, context, service_id):
|
||||
self.assert_admin(context)
|
||||
|
||||
ref = self.catalog_api.get_service(context, service_id)
|
||||
return {'service': ref}
|
||||
|
||||
@controller.protected
|
||||
def update_service(self, context, service_id, service):
|
||||
self.assert_admin(context)
|
||||
|
||||
self._require_matching_id(service_id, service)
|
||||
|
||||
ref = self.catalog_api.update_service(context, service_id, service)
|
||||
return {'service': ref}
|
||||
|
||||
@controller.protected
|
||||
def delete_service(self, context, service_id):
|
||||
self.assert_admin(context)
|
||||
|
||||
return self.catalog_api.delete_service(context, service_id)
|
||||
|
||||
|
||||
class EndpointControllerV3(controller.V3Controller):
|
||||
@controller.protected
|
||||
def create_endpoint(self, context, endpoint):
|
||||
self.assert_admin(context)
|
||||
|
||||
ref = self._assign_unique_id(self._normalize_dict(endpoint))
|
||||
self._require_attribute(ref, 'service_id')
|
||||
self._require_attribute(ref, 'interface')
|
||||
@ -326,23 +320,20 @@ class EndpointControllerV3(controller.V3Controller):
|
||||
ref = self.catalog_api.create_endpoint(context, ref['id'], ref)
|
||||
return {'endpoint': ref}
|
||||
|
||||
@controller.protected
|
||||
def list_endpoints(self, context):
|
||||
self.assert_admin(context)
|
||||
|
||||
refs = self.catalog_api.list_endpoints(context)
|
||||
refs = self._filter_by_attribute(context, refs, 'service_id')
|
||||
refs = self._filter_by_attribute(context, refs, 'interface')
|
||||
return {'endpoints': self._paginate(context, refs)}
|
||||
|
||||
@controller.protected
|
||||
def get_endpoint(self, context, endpoint_id):
|
||||
self.assert_admin(context)
|
||||
|
||||
ref = self.catalog_api.get_endpoint(context, endpoint_id)
|
||||
return {'endpoint': ref}
|
||||
|
||||
@controller.protected
|
||||
def update_endpoint(self, context, endpoint_id, endpoint):
|
||||
self.assert_admin(context)
|
||||
|
||||
self._require_matching_id(endpoint_id, endpoint)
|
||||
|
||||
if 'service_id' in endpoint:
|
||||
@ -351,6 +342,6 @@ class EndpointControllerV3(controller.V3Controller):
|
||||
ref = self.catalog_api.update_endpoint(context, endpoint_id, endpoint)
|
||||
return {'endpoint': ref}
|
||||
|
||||
@controller.protected
|
||||
def delete_endpoint(self, context, endpoint_id):
|
||||
self.assert_admin(context)
|
||||
return self.catalog_api.delete_endpoint(context, endpoint_id)
|
||||
|
@ -1,9 +1,60 @@
|
||||
import uuid
|
||||
import functools
|
||||
|
||||
from keystone.common import logging
|
||||
from keystone.common import wsgi
|
||||
from keystone import exception
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def protected(f):
|
||||
"""Wraps API calls with role based access controls (RBAC)."""
|
||||
|
||||
@functools.wraps(f)
|
||||
def wrapper(self, context, **kwargs):
|
||||
if not context['is_admin']:
|
||||
action = 'identity:%s' % f.__name__
|
||||
|
||||
LOG.debug('RBAC: Authorizing %s(%s)' % (
|
||||
action,
|
||||
', '.join(['%s=%s' % (k, kwargs[k]) for k in kwargs])))
|
||||
|
||||
try:
|
||||
token_ref = self.token_api.get_token(
|
||||
context=context, token_id=context['token_id'])
|
||||
except exception.TokenNotFound:
|
||||
LOG.warning('RBAC: Invalid token')
|
||||
raise exception.Unauthorized()
|
||||
|
||||
creds = token_ref['metadata'].copy()
|
||||
|
||||
try:
|
||||
creds['user_id'] = token_ref['user'].get('id')
|
||||
except AttributeError:
|
||||
LOG.warning('RBAC: Invalid user')
|
||||
raise exception.Unauthorized()
|
||||
|
||||
try:
|
||||
creds['tenant_id'] = token_ref['tenant'].get('id')
|
||||
except AttributeError:
|
||||
LOG.debug('RBAC: Proceeding without tenant')
|
||||
|
||||
# NOTE(vish): this is pretty inefficient
|
||||
creds['roles'] = [self.identity_api.get_role(context, role)['name']
|
||||
for role in creds.get('roles', [])]
|
||||
|
||||
self.policy_api.enforce(context, creds, action, kwargs)
|
||||
|
||||
LOG.debug('RBAC: Authorization granted')
|
||||
else:
|
||||
LOG.warning('RBAC: Bypassing authorization')
|
||||
|
||||
return f(self, context, **kwargs)
|
||||
return wrapper
|
||||
|
||||
|
||||
class V3Controller(wsgi.Application):
|
||||
"""Base controller class for Identity API v3."""
|
||||
|
||||
|
@ -859,134 +859,116 @@ class RoleController(wsgi.Application):
|
||||
|
||||
|
||||
class DomainControllerV3(controller.V3Controller):
|
||||
@controller.protected
|
||||
def create_domain(self, context, domain):
|
||||
self.assert_admin(context)
|
||||
|
||||
ref = self._assign_unique_id(self._normalize_dict(domain))
|
||||
ref = self.identity_api.create_domain(context, ref['id'], ref)
|
||||
return {'domain': ref}
|
||||
|
||||
@controller.protected
|
||||
def list_domains(self, context):
|
||||
self.assert_admin(context)
|
||||
|
||||
refs = self.identity_api.list_domains(context)
|
||||
return {'domains': self._paginate(context, refs)}
|
||||
|
||||
@controller.protected
|
||||
def get_domain(self, context, domain_id):
|
||||
self.assert_admin(context)
|
||||
|
||||
ref = self.identity_api.get_domain(context, domain_id)
|
||||
return {'domain': ref}
|
||||
|
||||
@controller.protected
|
||||
def update_domain(self, context, domain_id, domain):
|
||||
self.assert_admin(context)
|
||||
|
||||
self._require_matching_id(domain_id, domain)
|
||||
|
||||
ref = self.identity_api.update_domain(context, domain_id, domain)
|
||||
return {'domain': ref}
|
||||
|
||||
@controller.protected
|
||||
def delete_domain(self, context, domain_id):
|
||||
self.assert_admin(context)
|
||||
return self.identity_api.delete_domain(context, domain_id)
|
||||
|
||||
|
||||
class ProjectControllerV3(controller.V3Controller):
|
||||
@controller.protected
|
||||
def create_project(self, context, project):
|
||||
self.assert_admin(context)
|
||||
|
||||
ref = self._assign_unique_id(self._normalize_dict(project))
|
||||
ref = self.identity_api.create_project(context, ref['id'], ref)
|
||||
return {'project': ref}
|
||||
|
||||
@controller.protected
|
||||
def list_projects(self, context):
|
||||
self.assert_admin(context)
|
||||
|
||||
refs = self.identity_api.list_projects(context)
|
||||
return {'projects': self._paginate(context, refs)}
|
||||
|
||||
@controller.protected
|
||||
def list_user_projects(self, context, user_id):
|
||||
# FIXME(dolph): this should also be callable by user_id themselves
|
||||
self.assert_admin(context)
|
||||
|
||||
refs = self.identity_api.list_user_projects(context, user_id)
|
||||
return {'projects': self._paginate(context, refs)}
|
||||
|
||||
@controller.protected
|
||||
def get_project(self, context, project_id):
|
||||
self.assert_admin(context)
|
||||
|
||||
ref = self.identity_api.get_project(context, project_id)
|
||||
return {'project': ref}
|
||||
|
||||
@controller.protected
|
||||
def update_project(self, context, project_id, project):
|
||||
self.assert_admin(context)
|
||||
|
||||
self._require_matching_id(project_id, project)
|
||||
|
||||
ref = self.identity_api.update_project(context, project_id, project)
|
||||
return {'project': ref}
|
||||
|
||||
@controller.protected
|
||||
def delete_project(self, context, project_id):
|
||||
self.assert_admin(context)
|
||||
return self.identity_api.delete_project(context, project_id)
|
||||
|
||||
|
||||
class UserControllerV3(controller.V3Controller):
|
||||
@controller.protected
|
||||
def create_user(self, context, user):
|
||||
self.assert_admin(context)
|
||||
|
||||
ref = self._assign_unique_id(self._normalize_dict(user))
|
||||
ref = self.identity_api.create_user(context, ref['id'], ref)
|
||||
return {'user': ref}
|
||||
|
||||
@controller.protected
|
||||
def list_users(self, context):
|
||||
self.assert_admin(context)
|
||||
|
||||
refs = self.identity_api.list_users(context)
|
||||
return {'users': self._paginate(context, refs)}
|
||||
|
||||
@controller.protected
|
||||
def get_user(self, context, user_id):
|
||||
self.assert_admin(context)
|
||||
|
||||
ref = self.identity_api.get_user(context, user_id)
|
||||
return {'user': ref}
|
||||
|
||||
@controller.protected
|
||||
def update_user(self, context, user_id, user):
|
||||
self.assert_admin(context)
|
||||
|
||||
self._require_matching_id(user_id, user)
|
||||
|
||||
ref = self.identity_api.update_user(context, user_id, user)
|
||||
return {'user': ref}
|
||||
|
||||
@controller.protected
|
||||
def delete_user(self, context, user_id):
|
||||
self.assert_admin(context)
|
||||
return self.identity_api.delete_user(context, user_id)
|
||||
|
||||
|
||||
class CredentialControllerV3(controller.V3Controller):
|
||||
@controller.protected
|
||||
def create_credential(self, context, credential):
|
||||
self.assert_admin(context)
|
||||
|
||||
ref = self._assign_unique_id(self._normalize_dict(credential))
|
||||
ref = self.identity_api.create_credential(context, ref['id'], ref)
|
||||
return {'credential': ref}
|
||||
|
||||
@controller.protected
|
||||
def list_credentials(self, context):
|
||||
self.assert_admin(context)
|
||||
|
||||
refs = self.identity_api.list_credentials(context)
|
||||
return {'credentials': self._paginate(context, refs)}
|
||||
|
||||
@controller.protected
|
||||
def get_credential(self, context, credential_id):
|
||||
self.assert_admin(context)
|
||||
|
||||
ref = self.identity_api.get_credential(context, credential_id)
|
||||
return {'credential': ref}
|
||||
|
||||
@controller.protected
|
||||
def update_credential(self, context, credential_id, credential):
|
||||
self.assert_admin(context)
|
||||
|
||||
self._require_matching_id(credential_id, credential)
|
||||
|
||||
ref = self.identity_api.update_credential(
|
||||
@ -995,41 +977,37 @@ class CredentialControllerV3(controller.V3Controller):
|
||||
credential)
|
||||
return {'credential': ref}
|
||||
|
||||
@controller.protected
|
||||
def delete_credential(self, context, credential_id):
|
||||
self.assert_admin(context)
|
||||
return self.identity_api.delete_credential(context, credential_id)
|
||||
|
||||
|
||||
class RoleControllerV3(controller.V3Controller):
|
||||
@controller.protected
|
||||
def create_role(self, context, role):
|
||||
self.assert_admin(context)
|
||||
|
||||
ref = self._assign_unique_id(self._normalize_dict(role))
|
||||
ref = self.identity_api.create_role(context, ref['id'], ref)
|
||||
return {'role': ref}
|
||||
|
||||
@controller.protected
|
||||
def list_roles(self, context):
|
||||
self.assert_admin(context)
|
||||
|
||||
refs = self.identity_api.list_roles(context)
|
||||
return {'roles': self._paginate(context, refs)}
|
||||
|
||||
@controller.protected
|
||||
def get_role(self, context, role_id):
|
||||
self.assert_admin(context)
|
||||
|
||||
ref = self.identity_api.get_role(context, role_id)
|
||||
return {'role': ref}
|
||||
|
||||
@controller.protected
|
||||
def update_role(self, context, role_id, role):
|
||||
self.assert_admin(context)
|
||||
|
||||
self._require_matching_id(role_id, role)
|
||||
|
||||
ref = self.identity_api.update_role(context, role_id, role)
|
||||
return {'role': ref}
|
||||
|
||||
@controller.protected
|
||||
def delete_role(self, context, role_id):
|
||||
self.assert_admin(context)
|
||||
return self.identity_api.delete_role(context, role_id)
|
||||
|
||||
def _require_domain_or_project(self, domain_id, project_id):
|
||||
@ -1037,41 +1015,37 @@ class RoleControllerV3(controller.V3Controller):
|
||||
msg = 'Specify a domain or project, not both'
|
||||
raise exception.ValidationError(msg)
|
||||
|
||||
@controller.protected
|
||||
def create_grant(self, context, role_id, user_id, domain_id=None,
|
||||
project_id=None):
|
||||
"""Grants a role to a user on either a domain or project."""
|
||||
self.assert_admin(context)
|
||||
|
||||
self._require_domain_or_project(domain_id, project_id)
|
||||
|
||||
return self.identity_api.create_grant(
|
||||
context, role_id, user_id, domain_id, project_id)
|
||||
|
||||
@controller.protected
|
||||
def list_grants(self, context, user_id, domain_id=None,
|
||||
project_id=None):
|
||||
"""Lists roles granted to a user on either a domain or project."""
|
||||
self.assert_admin(context)
|
||||
|
||||
self._require_domain_or_project(domain_id, project_id)
|
||||
|
||||
return self.identity_api.list_grants(
|
||||
context, user_id, domain_id, project_id)
|
||||
|
||||
@controller.protected
|
||||
def check_grant(self, context, role_id, user_id, domain_id=None,
|
||||
project_id=None):
|
||||
"""Checks if a role has been granted on either a domain or project."""
|
||||
self.assert_admin(context)
|
||||
|
||||
self._require_domain_or_project(domain_id, project_id)
|
||||
|
||||
self.identity_api.get_grant(
|
||||
context, role_id, user_id, domain_id, project_id)
|
||||
|
||||
@controller.protected
|
||||
def revoke_grant(self, context, role_id, user_id, domain_id=None,
|
||||
project_id=None):
|
||||
"""Revokes a role from a user on either a domain or project."""
|
||||
self.assert_admin(context)
|
||||
|
||||
self._require_domain_or_project(domain_id, project_id)
|
||||
|
||||
self.identity_api.delete_grant(
|
||||
|
@ -105,9 +105,8 @@ class Driver(object):
|
||||
|
||||
|
||||
class PolicyControllerV3(controller.V3Controller):
|
||||
@controller.protected
|
||||
def create_policy(self, context, policy):
|
||||
self.assert_admin(context)
|
||||
|
||||
ref = self._assign_unique_id(self._normalize_dict(policy))
|
||||
self._require_attribute(ref, 'blob')
|
||||
self._require_attribute(ref, 'type')
|
||||
@ -115,22 +114,22 @@ class PolicyControllerV3(controller.V3Controller):
|
||||
ref = self.policy_api.create_policy(context, ref['id'], ref)
|
||||
return {'policy': ref}
|
||||
|
||||
@controller.protected
|
||||
def list_policies(self, context):
|
||||
self.assert_admin(context)
|
||||
refs = self.policy_api.list_policies(context)
|
||||
refs = self._filter_by_attribute(context, refs, 'type')
|
||||
return {'policies': self._paginate(context, refs)}
|
||||
|
||||
@controller.protected
|
||||
def get_policy(self, context, policy_id):
|
||||
self.assert_admin(context)
|
||||
ref = self.policy_api.get_policy(context, policy_id)
|
||||
return {'policy': ref}
|
||||
|
||||
@controller.protected
|
||||
def update_policy(self, context, policy_id, policy):
|
||||
self.assert_admin(context)
|
||||
ref = self.policy_api.update_policy(context, policy_id, policy)
|
||||
return {'policy': ref}
|
||||
|
||||
@controller.protected
|
||||
def delete_policy(self, context, policy_id):
|
||||
self.assert_admin(context)
|
||||
return self.policy_api.delete_policy(context, policy_id)
|
||||
|
Loading…
Reference in New Issue
Block a user