Merge "Convert role_inferences API to flask native dispatching"
This commit is contained in:
commit
210faf3344
|
@ -20,6 +20,7 @@ from keystone.api import os_revoke
|
|||
from keystone.api import os_simple_cert
|
||||
from keystone.api import regions
|
||||
from keystone.api import registered_limits
|
||||
from keystone.api import role_inferences
|
||||
from keystone.api import roles
|
||||
from keystone.api import services
|
||||
from keystone.api import trusts
|
||||
|
@ -35,6 +36,7 @@ __all__ = (
|
|||
'os_simple_cert',
|
||||
'regions',
|
||||
'registered_limits',
|
||||
'role_inferences',
|
||||
'roles',
|
||||
'services',
|
||||
'trusts',
|
||||
|
@ -51,6 +53,7 @@ __apis__ = (
|
|||
os_simple_cert,
|
||||
regions,
|
||||
registered_limits,
|
||||
role_inferences,
|
||||
roles,
|
||||
services,
|
||||
trusts,
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
# flake8: noqa
|
||||
|
||||
# NOTE(morgan): The keystone.api._shared module is explicitly for shared code
|
||||
# between the APIs that should not be duplicated. This occurs infrequently.
|
||||
# For the most part adding a new file or code to anything in this module is
|
||||
# incorrect. If you are unsure of what you are doing, do not add code here.
|
||||
|
||||
# WARNING: THIS FILE SHOULD CONTAIN NO CODE, it is explicitly ignored by
|
||||
# flake8 completely.
|
|
@ -0,0 +1,50 @@
|
|||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
# NOTE(morgan): This file does not implement any API-specific code. It simply
|
||||
# supplies shared functions between the "role_inferences" and "roles" (for
|
||||
# implied roles) APIs. In general, all code for an API should be isolated to
|
||||
# it's own keystone.api.XXX module and not in the _shared module.
|
||||
|
||||
from keystone.common import provider_api
|
||||
from keystone.server import flask as ks_flask
|
||||
|
||||
|
||||
PROVIDERS = provider_api.ProviderAPIs
|
||||
|
||||
|
||||
def build_prior_role_response_data(prior_role_id, prior_role_name):
|
||||
return {
|
||||
'id': prior_role_id,
|
||||
'links': {
|
||||
'self': ks_flask.base_url(path='/roles/%s' % prior_role_id)
|
||||
},
|
||||
'name': prior_role_name}
|
||||
|
||||
|
||||
def build_implied_role_response_data(implied_role):
|
||||
return {
|
||||
'id': implied_role['id'],
|
||||
'links': {
|
||||
'self': ks_flask.base_url(
|
||||
path='/roles/%s' % implied_role['id'])
|
||||
},
|
||||
'name': implied_role['name']}
|
||||
|
||||
|
||||
def role_inference_response(prior_role_id):
|
||||
prior_role = PROVIDERS.role_api.get_role(prior_role_id)
|
||||
response = {
|
||||
'role_inference': {
|
||||
'prior_role': build_prior_role_response_data(
|
||||
prior_role_id, prior_role['name'])}}
|
||||
return response
|
|
@ -0,0 +1,70 @@
|
|||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
# This file handles all flask-restful resources for /v3/role_inferences
|
||||
|
||||
import flask_restful
|
||||
|
||||
from keystone.api._shared import implied_roles as shared
|
||||
from keystone.common import provider_api
|
||||
from keystone.common import rbac_enforcer
|
||||
from keystone.server import flask as ks_flask
|
||||
|
||||
|
||||
ENFORCER = rbac_enforcer.RBACEnforcer
|
||||
PROVIDERS = provider_api.ProviderAPIs
|
||||
|
||||
|
||||
class RoleInferencesResource(flask_restful.Resource):
|
||||
def get(self):
|
||||
"""List role inference rules.
|
||||
|
||||
GET/HEAD /v3/role_inferences
|
||||
"""
|
||||
ENFORCER.enforce_call(action='identity:list_role_inference_rules')
|
||||
refs = PROVIDERS.role_api.list_role_inference_rules()
|
||||
role_dict = {role_ref['id']: role_ref
|
||||
for role_ref in PROVIDERS.role_api.list_roles()}
|
||||
|
||||
rules = dict()
|
||||
for ref in refs:
|
||||
implied_role_id = ref['implied_role_id']
|
||||
prior_role_id = ref['prior_role_id']
|
||||
implied = rules.get(prior_role_id, [])
|
||||
implied.append(
|
||||
shared.build_implied_role_response_data(
|
||||
role_dict[implied_role_id]))
|
||||
rules[prior_role_id] = implied
|
||||
|
||||
inferences = []
|
||||
for prior_id, implied, in rules.items():
|
||||
prior_response = shared.build_prior_role_response_data(
|
||||
prior_id, role_dict[prior_id]['name'])
|
||||
inferences.append({'prior_role': prior_response,
|
||||
'implies': implied})
|
||||
results = {'role_inferences': inferences}
|
||||
return results
|
||||
|
||||
|
||||
class RoleInferencesAPI(ks_flask.APIBase):
|
||||
_name = 'role_inferences'
|
||||
_import_name = __name__
|
||||
resources = []
|
||||
resource_mapping = [
|
||||
ks_flask.construct_resource_map(
|
||||
resource=RoleInferencesResource,
|
||||
url='/role_inferences',
|
||||
resource_kwargs={},
|
||||
rel='role_inferences')
|
||||
]
|
||||
|
||||
APIs = (RoleInferencesAPI,)
|
|
@ -16,6 +16,7 @@ import flask
|
|||
import flask_restful
|
||||
from six.moves import http_client
|
||||
|
||||
from keystone.api._shared import implied_roles as shared
|
||||
from keystone.assignment import schema
|
||||
from keystone.common import json_home
|
||||
from keystone.common import provider_api
|
||||
|
@ -191,34 +192,6 @@ def _build_enforcement_target_ref():
|
|||
return ref
|
||||
|
||||
|
||||
def _build_prior_role_response_data(prior_role_id, prior_role_name):
|
||||
return {
|
||||
'id': prior_role_id,
|
||||
'links': {
|
||||
'self': ks_flask.base_url(path='/roles/%s' % prior_role_id)
|
||||
},
|
||||
'name': prior_role_name}
|
||||
|
||||
|
||||
def _build_implied_role_response_data(implied_role):
|
||||
return {
|
||||
'id': implied_role['id'],
|
||||
'links': {
|
||||
'self': ks_flask.base_url(
|
||||
path='/roles/%s' % implied_role['id'])
|
||||
},
|
||||
'name': implied_role['name']}
|
||||
|
||||
|
||||
def _role_inference_response(prior_role_id):
|
||||
prior_role = PROVIDERS.role_api.get_role(prior_role_id)
|
||||
response = {
|
||||
'role_inference': {
|
||||
'prior_role': _build_prior_role_response_data(
|
||||
prior_role_id, prior_role['name'])}}
|
||||
return response
|
||||
|
||||
|
||||
class RoleImplicationListResource(flask_restful.Resource):
|
||||
def get(self, prior_role_id):
|
||||
"""List Implied Roles.
|
||||
|
@ -229,12 +202,12 @@ class RoleImplicationListResource(flask_restful.Resource):
|
|||
target_attr=_build_enforcement_target_ref())
|
||||
ref = PROVIDERS.role_api.list_implied_roles(prior_role_id)
|
||||
implied_ids = [r['implied_role_id'] for r in ref]
|
||||
response_json = _role_inference_response(prior_role_id)
|
||||
response_json = shared.role_inference_response(prior_role_id)
|
||||
response_json['role_inference']['implies'] = []
|
||||
for implied_id in implied_ids:
|
||||
implied_role = PROVIDERS.role_api.get_role(implied_id)
|
||||
response_json['role_inference']['implies'].append(
|
||||
_build_implied_role_response_data(implied_role))
|
||||
shared.build_implied_role_response_data(implied_role))
|
||||
response_json['links'] = {
|
||||
'self': ks_flask.base_url(
|
||||
path='/roles/%s/implies' % prior_role_id)}
|
||||
|
@ -274,9 +247,9 @@ class RoleImplicationResource(flask_restful.Resource):
|
|||
PROVIDERS.role_api.get_implied_role(
|
||||
prior_role_id, implied_role_id)
|
||||
implied_role_ref = PROVIDERS.role_api.get_role(implied_role_id)
|
||||
response_json = _role_inference_response(prior_role_id)
|
||||
response_json = shared.role_inference_response(prior_role_id)
|
||||
response_json['role_inference'][
|
||||
'implies'] = _build_implied_role_response_data(
|
||||
'implies'] = shared.build_implied_role_response_data(
|
||||
implied_role_ref)
|
||||
response_json['links'] = {
|
||||
'self': ks_flask.base_url(
|
||||
|
|
|
@ -50,66 +50,6 @@ class ProjectAssignmentV3(controller.V3Controller):
|
|||
hints=hints)
|
||||
|
||||
|
||||
class ImpliedRolesV3(controller.V3Controller):
|
||||
"""The V3 ImpliedRoles CRD APIs. There is no Update."""
|
||||
|
||||
def _check_implies_role(self, request, prep_info,
|
||||
prior_role_id, implied_role_id=None):
|
||||
ref = {}
|
||||
ref['prior_role'] = PROVIDERS.role_api.get_role(prior_role_id)
|
||||
if implied_role_id:
|
||||
ref['implied_role'] = PROVIDERS.role_api.get_role(implied_role_id)
|
||||
|
||||
self.check_protection(request, prep_info, ref)
|
||||
|
||||
def _prior_role_stanza(self, endpoint, prior_role_id, prior_role_name):
|
||||
return {
|
||||
"id": prior_role_id,
|
||||
"links": {
|
||||
"self": endpoint + "/v3/roles/" + prior_role_id
|
||||
},
|
||||
"name": prior_role_name
|
||||
}
|
||||
|
||||
def _implied_role_stanza(self, endpoint, implied_role):
|
||||
implied_id = implied_role['id']
|
||||
implied_response = {
|
||||
"id": implied_id,
|
||||
"links": {
|
||||
"self": endpoint + "/v3/roles/" + implied_id
|
||||
},
|
||||
"name": implied_role['name']
|
||||
}
|
||||
return implied_response
|
||||
|
||||
@controller.protected()
|
||||
def list_role_inference_rules(self, request):
|
||||
refs = PROVIDERS.role_api.list_role_inference_rules()
|
||||
role_dict = {role_ref['id']: role_ref
|
||||
for role_ref in PROVIDERS.role_api.list_roles()}
|
||||
|
||||
rules = dict()
|
||||
endpoint = super(controller.V3Controller, ImpliedRolesV3).base_url(
|
||||
request.context_dict, 'public')
|
||||
|
||||
for ref in refs:
|
||||
implied_role_id = ref['implied_role_id']
|
||||
prior_role_id = ref['prior_role_id']
|
||||
implied = rules.get(prior_role_id, [])
|
||||
implied.append(self._implied_role_stanza(
|
||||
endpoint, role_dict[implied_role_id]))
|
||||
rules[prior_role_id] = implied
|
||||
|
||||
inferences = []
|
||||
for prior_id, implied in rules.items():
|
||||
prior_response = self._prior_role_stanza(
|
||||
endpoint, prior_id, role_dict[prior_id]['name'])
|
||||
inferences.append({'prior_role': prior_response,
|
||||
'implies': implied})
|
||||
results = {'role_inferences': inferences}
|
||||
return results
|
||||
|
||||
|
||||
class GrantAssignmentV3(controller.V3Controller):
|
||||
"""The V3 Grant Assignment APIs."""
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@ class Public(wsgi.ComposableRouter):
|
|||
|
||||
class Routers(wsgi.RoutersBase):
|
||||
|
||||
_path_prefixes = ('users', 'role_inferences', 'projects',
|
||||
_path_prefixes = ('users', 'projects',
|
||||
'domains', 'system', 'role_assignments', 'OS-INHERIT')
|
||||
|
||||
def append_v3_routers(self, mapper, routers):
|
||||
|
@ -53,15 +53,6 @@ class Routers(wsgi.RoutersBase):
|
|||
'user_id': json_home.Parameters.USER_ID,
|
||||
})
|
||||
|
||||
implied_roles_controller = controllers.ImpliedRolesV3()
|
||||
self._add_resource(
|
||||
mapper, implied_roles_controller,
|
||||
path='/role_inferences',
|
||||
get_head_action='list_role_inference_rules',
|
||||
rel=json_home.build_v3_resource_relation('role_inferences'),
|
||||
path_vars={}
|
||||
)
|
||||
|
||||
grant_controller = controllers.GrantAssignmentV3()
|
||||
self._add_resource(
|
||||
mapper, grant_controller,
|
||||
|
|
|
@ -50,6 +50,7 @@ _MOVED_API_PREFIXES = frozenset(
|
|||
'limits',
|
||||
'regions',
|
||||
'registered_limits',
|
||||
'role_inferences',
|
||||
'roles',
|
||||
'services',
|
||||
]
|
||||
|
|
Loading…
Reference in New Issue