Merge "Convert policy API to flask"

This commit is contained in:
Zuul 2018-09-01 06:35:00 +00:00 committed by Gerrit Code Review
commit 2448c3475b
8 changed files with 280 additions and 351 deletions

View File

@ -18,6 +18,7 @@ from keystone.api import os_ep_filter
from keystone.api import os_oauth1
from keystone.api import os_revoke
from keystone.api import os_simple_cert
from keystone.api import policy
from keystone.api import regions
from keystone.api import registered_limits
from keystone.api import role_assignments
@ -36,6 +37,7 @@ __all__ = (
'os_oauth1',
'os_revoke',
'os_simple_cert',
'policy',
'regions',
'registered_limits',
'role_assignments',
@ -55,6 +57,7 @@ __apis__ = (
os_oauth1,
os_revoke,
os_simple_cert,
policy,
regions,
registered_limits,
role_assignments,

276
keystone/api/policy.py Normal file
View File

@ -0,0 +1,276 @@
# 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 /policy
import flask_restful
from oslo_log import versionutils
from six.moves import http_client
from keystone.api._shared import json_home_relations
from keystone.common import json_home
from keystone.common import provider_api
from keystone.common import rbac_enforcer
from keystone.common import validation
from keystone.policy import schema
from keystone.server import flask as ks_flask
ENFORCER = rbac_enforcer.RBACEnforcer
PROVIDERS = provider_api.ProviderAPIs
_resource_rel_func = json_home_relations.os_endpoint_policy_resource_rel_func
class PolicyResource(ks_flask.ResourceBase):
collection_key = 'policies'
member_key = 'policy'
def get(self, policy_id=None):
if policy_id:
return self._get_policy(policy_id)
return self._list_policies()
@versionutils.deprecated(
as_of=versionutils.deprecated.QUEENS,
what='identity:get_policy of the v3 Policy APIs'
)
def _get_policy(self, policy_id):
ENFORCER.enforce_call(action='identity:get_policy')
ref = PROVIDERS.policy_api.get_policy(policy_id)
return self.wrap_member(ref)
@versionutils.deprecated(
as_of=versionutils.deprecated.QUEENS,
what='identity:list_policies of the v3 Policy APIs'
)
def _list_policies(self):
ENFORCER.enforce_call(action='identity:list_policies')
filters = ['type']
hints = self.build_driver_hints(filters)
refs = PROVIDERS.policy_api.list_policies(hints=hints)
return self.wrap_collection(refs, hints=hints)
@versionutils.deprecated(
as_of=versionutils.deprecated.QUEENS,
what='identity:create_policy of the v3 Policy APIs'
)
def post(self):
ENFORCER.enforce_call(action='identity:create_policy')
policy_body = self.request_body_json.get('policy', {})
validation.lazy_validate(schema.policy_create, policy_body)
policy = self._assign_unique_id(self._normalize_dict(policy_body))
ref = PROVIDERS.policy_api.create_policy(
policy['id'], policy, initiator=self.audit_initiator
)
return self.wrap_member(ref), http_client.CREATED
@versionutils.deprecated(
as_of=versionutils.deprecated.QUEENS,
what='identity:update_policy of the v3 Policy APIs'
)
def patch(self, policy_id):
ENFORCER.enforce_call(action='identity:update_policy')
policy_body = self.request_body_json.get('policy', {})
validation.lazy_validate(schema.policy_update, policy_body)
ref = PROVIDERS.policy_api.update_policy(
policy_id, policy_body, initiator=self.audit_initiator
)
return self.wrap_member(ref)
@versionutils.deprecated(
as_of=versionutils.deprecated.QUEENS,
what='identity:delete_policy of the v3 Policy APIs'
)
def delete(self, policy_id):
ENFORCER.enforce_call(action='identity:delete_policy')
res = PROVIDERS.policy_api.delete_policy(
policy_id, initiator=self.audit_initiator
)
return (res, http_client.NO_CONTENT)
class EndpointPolicyResource(flask_restful.Resource):
def get(self, policy_id):
ENFORCER.enforce_call(action='identity:list_endpoints_for_policy')
PROVIDERS.policy_api.get_policy(policy_id)
endpoints = PROVIDERS.endpoint_policy_api.list_endpoints_for_policy(
policy_id
)
self._remove_legacy_ids(endpoints)
return ks_flask.ResourceBase.wrap_collection(
endpoints, collection_name='endpoints'
)
def _remove_legacy_ids(self, endpoints):
for endpoint in endpoints:
endpoint.pop('legacy_endpoint_id', None)
class EndpointPolicyAssociations(flask_restful.Resource):
def get(self, policy_id, endpoint_id):
action = 'identity:check_policy_association_for_endpoint'
ENFORCER.enforce_call(action=action)
PROVIDERS.policy_api.get_policy(policy_id)
PROVIDERS.catalog_api.get_endpoint(endpoint_id)
PROVIDERS.endpoint_policy_api.check_policy_association(
policy_id, endpoint_id=endpoint_id
)
return None, http_client.NO_CONTENT
def put(self, policy_id, endpoint_id):
action = 'identity:create_policy_association_for_endpoint'
ENFORCER.enforce_call(action=action)
PROVIDERS.policy_api.get_policy(policy_id)
PROVIDERS.catalog_api.get_endpoint(endpoint_id)
PROVIDERS.endpoint_policy_api.create_policy_association(
policy_id, endpoint_id=endpoint_id
)
return None, http_client.NO_CONTENT
def delete(self, policy_id, endpoint_id):
action = 'identity:delete_policy_association_for_endpoint'
ENFORCER.enforce_call(action=action)
PROVIDERS.policy_api.get_policy(policy_id)
PROVIDERS.catalog_api.get_endpoint(endpoint_id)
PROVIDERS.endpoint_policy_api.delete_policy_association(
policy_id, endpoint_id=endpoint_id
)
return None, http_client.NO_CONTENT
class ServicePolicyAssociations(flask_restful.Resource):
def get(self, policy_id, service_id):
action = 'identity:check_policy_association_for_service'
ENFORCER.enforce_call(action=action)
PROVIDERS.policy_api.get_policy(policy_id)
PROVIDERS.catalog_api.get_service(service_id)
PROVIDERS.endpoint_policy_api.check_policy_association(
policy_id, service_id=service_id
)
return None, http_client.NO_CONTENT
def put(self, policy_id, service_id):
action = 'identity:create_policy_association_for_service'
ENFORCER.enforce_call(action=action)
PROVIDERS.policy_api.get_policy(policy_id)
PROVIDERS.catalog_api.get_service(service_id)
PROVIDERS.endpoint_policy_api.create_policy_association(
policy_id, service_id=service_id
)
return None, http_client.NO_CONTENT
def delete(self, policy_id, service_id):
action = 'identity:delete_policy_association_for_service'
ENFORCER.enforce_call(action=action)
PROVIDERS.policy_api.get_policy(policy_id)
PROVIDERS.catalog_api.get_service(service_id)
PROVIDERS.endpoint_policy_api.delete_policy_association(
policy_id, service_id=service_id
)
return None, http_client.NO_CONTENT
class ServiceRegionPolicyAssociations(flask_restful.Resource):
def get(self, policy_id, service_id, region_id):
action = 'identity:check_policy_association_for_region_and_service'
ENFORCER.enforce_call(action=action)
PROVIDERS.policy_api.get_policy(policy_id)
PROVIDERS.catalog_api.get_service(service_id)
PROVIDERS.catalog_api.get_region(region_id)
PROVIDERS.endpoint_policy_api.check_policy_association(
policy_id, service_id=service_id, region_id=region_id
)
return None, http_client.NO_CONTENT
def put(self, policy_id, service_id, region_id):
action = 'identity:create_policy_association_for_region_and_service'
ENFORCER.enforce_call(action=action)
PROVIDERS.policy_api.get_policy(policy_id)
PROVIDERS.catalog_api.get_service(service_id)
PROVIDERS.catalog_api.get_region(region_id)
PROVIDERS.endpoint_policy_api.create_policy_association(
policy_id, service_id=service_id, region_id=region_id
)
return None, http_client.NO_CONTENT
def delete(self, policy_id, service_id, region_id):
action = 'identity:delete_policy_association_for_region_and_service'
ENFORCER.enforce_call(action=action)
PROVIDERS.policy_api.get_policy(policy_id)
PROVIDERS.catalog_api.get_service(service_id)
PROVIDERS.catalog_api.get_region(region_id)
PROVIDERS.endpoint_policy_api.delete_policy_association(
policy_id, service_id=service_id, region_id=region_id
)
return None, http_client.NO_CONTENT
class PolicyAPI(ks_flask.APIBase):
_name = 'policy'
_import_name = __name__
resources = [PolicyResource]
resource_mapping = [
ks_flask.construct_resource_map(
resource=EndpointPolicyResource,
url='/policies/<string:policy_id>/OS-ENDPOINT-POLICY/endpoints',
resource_kwargs={},
rel='policy_endpoints',
path_vars={'policy_id': json_home.Parameters.POLICY_ID},
resource_relation_func=_resource_rel_func
),
ks_flask.construct_resource_map(
resource=EndpointPolicyAssociations,
url=('/policies/<string:policy_id>/OS-ENDPOINT-POLICY/'
'endpoints/<string:endpoint_id>'),
resource_kwargs={},
rel='endpoint_policy_association',
path_vars={
'policy_id': json_home.Parameters.POLICY_ID,
'endpoint_id': json_home.Parameters.ENDPOINT_ID
},
resource_relation_func=_resource_rel_func
),
ks_flask.construct_resource_map(
resource=ServicePolicyAssociations,
url=('/policies/<string:policy_id>/OS-ENDPOINT-POLICY/'
'services/<string:service_id>'),
resource_kwargs={},
rel='service_policy_association',
path_vars={
'policy_id': json_home.Parameters.POLICY_ID,
'service_id': json_home.Parameters.SERVICE_ID
},
resource_relation_func=_resource_rel_func
),
ks_flask.construct_resource_map(
resource=ServiceRegionPolicyAssociations,
url=('/policies/<string:policy_id>/OS-ENDPOINT-POLICY/'
'services/<string:service_id>/regions/<string:region_id>'),
resource_kwargs={},
rel='region_and_service_policy_association',
path_vars={
'policy_id': json_home.Parameters.POLICY_ID,
'service_id': json_home.Parameters.SERVICE_ID,
'region_id': json_home.Parameters.REGION_ID
},
resource_relation_func=_resource_rel_func
)
]
APIs = (PolicyAPI,)

View File

@ -1,160 +0,0 @@
# Copyright 2014 IBM Corp.
#
# 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.
from keystone.common import controller
from keystone.common import provider_api
from keystone import notifications
PROVIDERS = provider_api.ProviderAPIs
class EndpointPolicyV3Controller(controller.V3Controller):
collection_name = 'endpoints'
member_name = 'endpoint'
def __init__(self):
super(EndpointPolicyV3Controller, self).__init__()
notifications.register_event_callback(
'deleted', 'endpoint', self._on_endpoint_delete)
notifications.register_event_callback(
'deleted', 'service', self._on_service_delete)
notifications.register_event_callback(
'deleted', 'region', self._on_region_delete)
notifications.register_event_callback(
'deleted', 'policy', self._on_policy_delete)
def _on_endpoint_delete(self, service, resource_type, operation, payload):
PROVIDERS.endpoint_policy_api.delete_association_by_endpoint(
payload['resource_info'])
def _on_service_delete(self, service, resource_type, operation, payload):
PROVIDERS.endpoint_policy_api.delete_association_by_service(
payload['resource_info'])
def _on_region_delete(self, service, resource_type, operation, payload):
PROVIDERS.endpoint_policy_api.delete_association_by_region(
payload['resource_info'])
def _on_policy_delete(self, service, resource_type, operation, payload):
PROVIDERS.endpoint_policy_api.delete_association_by_policy(
payload['resource_info'])
@controller.protected()
def create_policy_association_for_endpoint(self, request,
policy_id, endpoint_id):
"""Create an association between a policy and an endpoint."""
PROVIDERS.policy_api.get_policy(policy_id)
PROVIDERS.catalog_api.get_endpoint(endpoint_id)
PROVIDERS.endpoint_policy_api.create_policy_association(
policy_id, endpoint_id=endpoint_id)
@controller.protected()
def check_policy_association_for_endpoint(self, request,
policy_id, endpoint_id):
"""Check an association between a policy and an endpoint."""
PROVIDERS.policy_api.get_policy(policy_id)
PROVIDERS.catalog_api.get_endpoint(endpoint_id)
PROVIDERS.endpoint_policy_api.check_policy_association(
policy_id, endpoint_id=endpoint_id)
@controller.protected()
def delete_policy_association_for_endpoint(self, request,
policy_id, endpoint_id):
"""Delete an association between a policy and an endpoint."""
PROVIDERS.policy_api.get_policy(policy_id)
PROVIDERS.catalog_api.get_endpoint(endpoint_id)
PROVIDERS.endpoint_policy_api.delete_policy_association(
policy_id, endpoint_id=endpoint_id)
@controller.protected()
def create_policy_association_for_service(self, request,
policy_id, service_id):
"""Create an association between a policy and a service."""
PROVIDERS.policy_api.get_policy(policy_id)
PROVIDERS.catalog_api.get_service(service_id)
PROVIDERS.endpoint_policy_api.create_policy_association(
policy_id, service_id=service_id)
@controller.protected()
def check_policy_association_for_service(self, request,
policy_id, service_id):
"""Check an association between a policy and a service."""
PROVIDERS.policy_api.get_policy(policy_id)
PROVIDERS.catalog_api.get_service(service_id)
PROVIDERS.endpoint_policy_api.check_policy_association(
policy_id, service_id=service_id)
@controller.protected()
def delete_policy_association_for_service(self, request,
policy_id, service_id):
"""Delete an association between a policy and a service."""
PROVIDERS.policy_api.get_policy(policy_id)
PROVIDERS.catalog_api.get_service(service_id)
PROVIDERS.endpoint_policy_api.delete_policy_association(
policy_id, service_id=service_id)
@controller.protected()
def create_policy_association_for_region_and_service(
self, request, policy_id, service_id, region_id):
"""Create an association between a policy and region+service."""
PROVIDERS.policy_api.get_policy(policy_id)
PROVIDERS.catalog_api.get_service(service_id)
PROVIDERS.catalog_api.get_region(region_id)
PROVIDERS.endpoint_policy_api.create_policy_association(
policy_id, service_id=service_id, region_id=region_id)
@controller.protected()
def check_policy_association_for_region_and_service(
self, request, policy_id, service_id, region_id):
"""Check an association between a policy and region+service."""
PROVIDERS.policy_api.get_policy(policy_id)
PROVIDERS.catalog_api.get_service(service_id)
PROVIDERS.catalog_api.get_region(region_id)
PROVIDERS.endpoint_policy_api.check_policy_association(
policy_id, service_id=service_id, region_id=region_id)
@controller.protected()
def delete_policy_association_for_region_and_service(
self, request, policy_id, service_id, region_id):
"""Delete an association between a policy and region+service."""
PROVIDERS.policy_api.get_policy(policy_id)
PROVIDERS.catalog_api.get_service(service_id)
PROVIDERS.catalog_api.get_region(region_id)
PROVIDERS.endpoint_policy_api.delete_policy_association(
policy_id, service_id=service_id, region_id=region_id)
# NOTE(henry-nash): As in the catalog controller, we must ensure that the
# legacy_endpoint_id does not escape.
@classmethod
def filter_endpoint(cls, ref):
if 'legacy_endpoint_id' in ref:
ref.pop('legacy_endpoint_id')
return ref
@classmethod
def wrap_member(cls, context, ref):
ref = cls.filter_endpoint(ref)
return super(EndpointPolicyV3Controller, cls).wrap_member(context, ref)
@controller.protected()
def list_endpoints_for_policy(self, request, policy_id):
"""List endpoints with the effective association to a policy."""
PROVIDERS.policy_api.get_policy(policy_id)
refs = PROVIDERS.endpoint_policy_api.list_endpoints_for_policy(
policy_id
)
return EndpointPolicyV3Controller.wrap_collection(request.context_dict,
refs)

View File

@ -1,81 +0,0 @@
# Copyright 2014 IBM Corp.
#
# 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.
import functools
from keystone.common import json_home
from keystone.common import wsgi
from keystone.endpoint_policy import controllers
build_resource_relation = functools.partial(
json_home.build_v3_extension_resource_relation,
extension_name='OS-ENDPOINT-POLICY', extension_version='1.0')
class Routers(wsgi.RoutersBase):
PATH_PREFIX = '/OS-ENDPOINT-POLICY'
_path_prefixes = ('OS-ENDPOINT-POLICY',)
def append_v3_routers(self, mapper, routers):
endpoint_policy_controller = controllers.EndpointPolicyV3Controller()
self._add_resource(
mapper, endpoint_policy_controller,
path='/policies/{policy_id}' + self.PATH_PREFIX + '/endpoints',
get_head_action='list_endpoints_for_policy',
rel=build_resource_relation(resource_name='policy_endpoints'),
path_vars={'policy_id': json_home.Parameters.POLICY_ID})
self._add_resource(
mapper, endpoint_policy_controller,
path=('/policies/{policy_id}' + self.PATH_PREFIX +
'/endpoints/{endpoint_id}'),
get_head_action='check_policy_association_for_endpoint',
put_action='create_policy_association_for_endpoint',
delete_action='delete_policy_association_for_endpoint',
rel=build_resource_relation(
resource_name='endpoint_policy_association'),
path_vars={
'policy_id': json_home.Parameters.POLICY_ID,
'endpoint_id': json_home.Parameters.ENDPOINT_ID,
})
self._add_resource(
mapper, endpoint_policy_controller,
path=('/policies/{policy_id}' + self.PATH_PREFIX +
'/services/{service_id}'),
get_head_action='check_policy_association_for_service',
put_action='create_policy_association_for_service',
delete_action='delete_policy_association_for_service',
rel=build_resource_relation(
resource_name='service_policy_association'),
path_vars={
'policy_id': json_home.Parameters.POLICY_ID,
'service_id': json_home.Parameters.SERVICE_ID,
})
self._add_resource(
mapper, endpoint_policy_controller,
path=('/policies/{policy_id}' + self.PATH_PREFIX +
'/services/{service_id}/regions/{region_id}'),
get_head_action='check_policy_association_for_region_and_service',
put_action='create_policy_association_for_region_and_service',
delete_action='delete_policy_association_for_region_and_service',
rel=build_resource_relation(
resource_name='region_and_service_policy_association'),
path_vars={
'policy_id': json_home.Parameters.POLICY_ID,
'service_id': json_home.Parameters.SERVICE_ID,
'region_id': json_home.Parameters.REGION_ID,
})

View File

@ -12,5 +12,4 @@
# License for the specific language governing permissions and limitations
# under the License.
from keystone.policy import controllers # noqa
from keystone.policy.core import * # noqa

View File

@ -1,79 +0,0 @@
# Copyright 2012 OpenStack Foundation
#
# 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.
from oslo_log import versionutils
import six
from keystone.common import controller
from keystone.common import provider_api
from keystone.common import validation
from keystone.policy import schema
PROVIDERS = provider_api.ProviderAPIs
def policy_deprecated(f):
@six.wraps(f)
def wrapper(*args, **kwargs):
deprecated = versionutils.deprecated(
what=f.__name__ + ' of the v3 Policy APIs',
as_of=versionutils.deprecated.QUEENS)
return deprecated(f)
return wrapper()
class PolicyV3(controller.V3Controller):
collection_name = 'policies'
member_name = 'policy'
@policy_deprecated
@controller.protected()
def create_policy(self, request, policy):
validation.lazy_validate(schema.policy_create, policy)
ref = self._assign_unique_id(self._normalize_dict(policy))
ref = PROVIDERS.policy_api.create_policy(
ref['id'], ref, initiator=request.audit_initiator
)
return PolicyV3.wrap_member(request.context_dict, ref)
@policy_deprecated
@controller.filterprotected('type')
def list_policies(self, request, filters):
hints = PolicyV3.build_driver_hints(request, filters)
refs = PROVIDERS.policy_api.list_policies(hints=hints)
return PolicyV3.wrap_collection(request.context_dict,
refs, hints=hints)
@policy_deprecated
@controller.protected()
def get_policy(self, request, policy_id):
ref = PROVIDERS.policy_api.get_policy(policy_id)
return PolicyV3.wrap_member(request.context_dict, ref)
@policy_deprecated
@controller.protected()
def update_policy(self, request, policy_id, policy):
validation.lazy_validate(schema.policy_update, policy)
ref = PROVIDERS.policy_api.update_policy(
policy_id, policy, initiator=request.audit_initiator
)
return PolicyV3.wrap_member(request.context_dict, ref)
@policy_deprecated
@controller.protected()
def delete_policy(self, request, policy_id):
return PROVIDERS.policy_api.delete_policy(
policy_id, initiator=request.audit_initiator
)

View File

@ -1,26 +0,0 @@
# Copyright 2012 OpenStack Foundation
#
# 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.
from keystone.common import router
from keystone.common import wsgi
from keystone.policy import controllers
class Routers(wsgi.RoutersBase):
_path_prefixes = ('policies',)
def append_v3_routers(self, mapper, routers):
policy_controller = controllers.PolicyV3()
routers.append(router.Router(policy_controller, 'policies', 'policy',
resource_descriptions=self.v3_resources))

View File

@ -30,11 +30,9 @@ from keystone.auth import routers as auth_routers
from keystone.common import wsgi as keystone_wsgi
from keystone.contrib.ec2 import routers as ec2_routers
from keystone.contrib.s3 import routers as s3_routers
from keystone.endpoint_policy import routers as endpoint_policy_routers
from keystone.federation import routers as federation_routers
from keystone.identity import routers as identity_routers
from keystone.oauth1 import routers as oauth1_routers
from keystone.policy import routers as policy_routers
from keystone.resource import routers as resource_routers
# TODO(morgan): _MOVED_API_PREFIXES to be removed when the legacy dispatch
@ -48,6 +46,7 @@ _MOVED_API_PREFIXES = frozenset(
'OS-SIMPLE-CERT',
'OS-TRUST',
'limits',
'policy',
'regions',
'registered_limits',
'role_assignments',
@ -65,11 +64,9 @@ ALL_API_ROUTERS = [auth_routers,
assignment_routers,
identity_routers,
app_cred_routers,
policy_routers,
resource_routers,
federation_routers,
oauth1_routers,
endpoint_policy_routers,
ec2_routers,
s3_routers]