diff options
author | Morgan Fainberg <morgan.fainberg@gmail.com> | 2018-08-10 13:41:52 -0700 |
---|---|---|
committer | morgan fainberg <morgan.fainberg@gmail.com> | 2018-09-10 11:22:58 -0700 |
commit | 94f8f103abc6911144423c277fbd1a71d691aa99 (patch) | |
tree | 395775ed35d7777125fc11a0432e636ac193ab22 /keystone/federation | |
parent | 294ca38554bb229f66a772e7dba35a5b08a36b20 (diff) | |
download | keystone-94f8f103abc6911144423c277fbd1a71d691aa99.tar.gz |
Convert OS-FEDERATION to flask native dispatching
Convert OS-FEDERATION to flask native dispatching.
NOTE: Two changes occured that impact testing in this patch.
* The JSON Home test now uses assertDictEquals to make it
easier to debug json_home document errors
* It was by general good luck that the overloaded relation
'identity_providers' worked as expected. The relation was
used for both '/OS-FEDERATION/identity_providers' and
the Identity-Provider-Specific WebSSO path. The change
to the JSON Home document and the tests make the
Identity-Provider-Specific WebSSO path now a relation
of 'identity_providers_websso' to more closely align
with 'websso' relation for
'/auth/OS-FEDERATION/websso/{protocol_id}'. While
this constitutes a minor break in our contract (the
output of the json home document) it was required to
ensure consistency and functionality. The alternative
is to not represent '/OS-FEDERATION/identity_providers'
(list endpoint) in the JSON Home document at all, instead
represent only the WebSSO endpoint.
Change-Id: If746c14491322d4a5f88fa0cbb31105f6d38c240
Partial-Bug: #1776504
Diffstat (limited to 'keystone/federation')
-rw-r--r-- | keystone/federation/controllers.py | 326 | ||||
-rw-r--r-- | keystone/federation/routers.py | 178 |
2 files changed, 3 insertions, 501 deletions
diff --git a/keystone/federation/controllers.py b/keystone/federation/controllers.py index 86bb25928..96dce6d10 100644 --- a/keystone/federation/controllers.py +++ b/keystone/federation/controllers.py @@ -15,7 +15,6 @@ import string from oslo_log import log -from oslo_log import versionutils from six.moves import http_client from six.moves import urllib import webob @@ -49,217 +48,6 @@ class _ControllerBase(controller.V3Controller): return super(_ControllerBase, cls).base_url(context, path=path) -class IdentityProvider(_ControllerBase): - """Identity Provider representation.""" - - collection_name = 'identity_providers' - member_name = 'identity_provider' - - _public_parameters = frozenset(['id', 'enabled', 'description', - 'remote_ids', 'links', 'domain_id' - ]) - - @classmethod - def _add_related_links(cls, context, ref): - """Add URLs for entities related with Identity Provider. - - Add URLs pointing to: - - protocols tied to the Identity Provider - - """ - ref.setdefault('links', {}) - base_path = ref['links'].get('self') - if base_path is None: - base_path = '/'.join([IdentityProvider.base_url(context), - ref['id']]) - for name in ['protocols']: - ref['links'][name] = '/'.join([base_path, name]) - - @classmethod - def _add_self_referential_link(cls, context, ref): - id = ref['id'] - self_path = '/'.join([cls.base_url(context), id]) - ref.setdefault('links', {}) - ref['links']['self'] = self_path - - @classmethod - def wrap_member(cls, context, ref): - cls._add_self_referential_link(context, ref) - cls._add_related_links(context, ref) - ref = cls.filter_params(ref) - return {cls.member_name: ref} - - @controller.protected() - def create_identity_provider(self, request, idp_id, identity_provider): - validation.lazy_validate(schema.identity_provider_create, - identity_provider) - identity_provider = self._normalize_dict(identity_provider) - identity_provider.setdefault('enabled', False) - idp_ref = PROVIDERS.federation_api.create_idp( - idp_id, identity_provider - ) - response = IdentityProvider.wrap_member(request.context_dict, idp_ref) - return wsgi.render_response( - body=response, status=(http_client.CREATED, - http_client.responses[http_client.CREATED])) - - @controller.filterprotected('id', 'enabled') - def list_identity_providers(self, request, filters): - hints = self.build_driver_hints(request, filters) - ref = PROVIDERS.federation_api.list_idps(hints=hints) - ref = [self.filter_params(x) for x in ref] - return IdentityProvider.wrap_collection(request.context_dict, - ref, hints=hints) - - @controller.protected() - def get_identity_provider(self, request, idp_id): - ref = PROVIDERS.federation_api.get_idp(idp_id) - return IdentityProvider.wrap_member(request.context_dict, ref) - - @controller.protected() - def delete_identity_provider(self, request, idp_id): - PROVIDERS.federation_api.delete_idp(idp_id) - - @controller.protected() - def update_identity_provider(self, request, idp_id, identity_provider): - validation.lazy_validate(schema.identity_provider_update, - identity_provider) - identity_provider = self._normalize_dict(identity_provider) - idp_ref = PROVIDERS.federation_api.update_idp( - idp_id, identity_provider - ) - return IdentityProvider.wrap_member(request.context_dict, idp_ref) - - -class FederationProtocol(_ControllerBase): - """A federation protocol representation. - - See keystone.common.controller.V3Controller docstring for explanation - on _public_parameters class attributes. - - """ - - collection_name = 'protocols' - member_name = 'protocol' - - _public_parameters = frozenset(['id', 'mapping_id', 'links']) - - @classmethod - def _add_self_referential_link(cls, context, ref): - """Add 'links' entry to the response dictionary. - - Calls IdentityProvider.base_url() class method, as it constructs - proper URL along with the 'identity providers' part included. - - :param ref: response dictionary - - """ - ref.setdefault('links', {}) - base_path = ref['links'].get('identity_provider') - if base_path is None: - base_path = [IdentityProvider.base_url(context), ref['idp_id']] - base_path = '/'.join(base_path) - self_path = [base_path, 'protocols', ref['id']] - self_path = '/'.join(self_path) - ref['links']['self'] = self_path - - @classmethod - def _add_related_links(cls, context, ref): - """Add new entries to the 'links' subdictionary in the response. - - Adds 'identity_provider' key with URL pointing to related identity - provider as a value. - - :param ref: response dictionary - - """ - ref.setdefault('links', {}) - base_path = '/'.join([IdentityProvider.base_url(context), - ref['idp_id']]) - ref['links']['identity_provider'] = base_path - - @classmethod - def wrap_member(cls, context, ref): - cls._add_related_links(context, ref) - cls._add_self_referential_link(context, ref) - ref = cls.filter_params(ref) - return {cls.member_name: ref} - - @controller.protected() - def create_protocol(self, request, idp_id, protocol_id, protocol): - validation.lazy_validate(schema.protocol_create, protocol) - protocol = self._normalize_dict(protocol) - ref = PROVIDERS.federation_api.create_protocol( - idp_id, protocol_id, protocol) - response = FederationProtocol.wrap_member(request.context_dict, ref) - return wsgi.render_response( - body=response, status=(http_client.CREATED, - http_client.responses[http_client.CREATED])) - - @controller.protected() - def update_protocol(self, request, idp_id, protocol_id, protocol): - validation.lazy_validate(schema.protocol_update, protocol) - protocol = self._normalize_dict(protocol) - ref = PROVIDERS.federation_api.update_protocol(idp_id, protocol_id, - protocol) - return FederationProtocol.wrap_member(request.context_dict, ref) - - @controller.protected() - def get_protocol(self, request, idp_id, protocol_id): - ref = PROVIDERS.federation_api.get_protocol(idp_id, protocol_id) - return FederationProtocol.wrap_member(request.context_dict, ref) - - @controller.protected() - def list_protocols(self, request, idp_id): - protocols_ref = PROVIDERS.federation_api.list_protocols(idp_id) - protocols = list(protocols_ref) - return FederationProtocol.wrap_collection(request.context_dict, - protocols) - - @controller.protected() - def delete_protocol(self, request, idp_id, protocol_id): - PROVIDERS.federation_api.delete_protocol(idp_id, protocol_id) - - -class MappingController(_ControllerBase): - collection_name = 'mappings' - member_name = 'mapping' - - @controller.protected() - def create_mapping(self, request, mapping_id, mapping): - ref = self._normalize_dict(mapping) - utils.validate_mapping_structure(ref) - mapping_ref = PROVIDERS.federation_api.create_mapping(mapping_id, ref) - response = MappingController.wrap_member(request.context_dict, - mapping_ref) - return wsgi.render_response( - body=response, status=(http_client.CREATED, - http_client.responses[http_client.CREATED])) - - @controller.protected() - def list_mappings(self, request): - ref = PROVIDERS.federation_api.list_mappings() - return MappingController.wrap_collection(request.context_dict, ref) - - @controller.protected() - def get_mapping(self, request, mapping_id): - ref = PROVIDERS.federation_api.get_mapping(mapping_id) - return MappingController.wrap_member(request.context_dict, ref) - - @controller.protected() - def delete_mapping(self, request, mapping_id): - PROVIDERS.federation_api.delete_mapping(mapping_id) - - @controller.protected() - def update_mapping(self, request, mapping_id, mapping): - mapping = self._normalize_dict(mapping) - utils.validate_mapping_structure(mapping) - mapping_ref = PROVIDERS.federation_api.update_mapping( - mapping_id, mapping - ) - return MappingController.wrap_member(request.context_dict, mapping_ref) - - class Auth(auth_controllers.Auth): def _get_sso_origin_host(self, request): @@ -436,117 +224,3 @@ class Auth(auth_controllers.Auth): body=ecp_assertion.to_string(), status=(http_client.OK, http_client.responses[http_client.OK]), headers=headers) - - -class DomainV3(controller.V3Controller): - collection_name = 'domains' - member_name = 'domain' - - def __init__(self): - super(DomainV3, self).__init__() - self.get_member_from_driver = PROVIDERS.resource_api.get_domain - - @versionutils.deprecated( - as_of=versionutils.deprecated.JUNO, - in_favor_of='GET /v3/auth/domains/', - ) - @controller.protected() - def list_domains_for_user(self, request): - """List all domains available to an authenticated user. - - :param context: request context - :returns: list of accessible domains - - """ - controller = auth_controllers.Auth() - return controller.get_auth_domains(request) - - -class ProjectAssignmentV3(controller.V3Controller): - collection_name = 'projects' - member_name = 'project' - - def __init__(self): - super(ProjectAssignmentV3, self).__init__() - self.get_member_from_driver = PROVIDERS.resource_api.get_project - - @versionutils.deprecated( - as_of=versionutils.deprecated.JUNO, - in_favor_of='GET /v3/auth/projects/', - ) - @controller.protected() - def list_projects_for_user(self, request): - """List all projects available to an authenticated user. - - :param context: request context - :returns: list of accessible projects - - """ - controller = auth_controllers.Auth() - return controller.get_auth_projects(request) - - -class ServiceProvider(_ControllerBase): - """Service Provider representation.""" - - collection_name = 'service_providers' - member_name = 'service_provider' - - _public_parameters = frozenset(['auth_url', 'id', 'enabled', 'description', - 'links', 'relay_state_prefix', 'sp_url']) - - @controller.protected() - def create_service_provider(self, request, sp_id, service_provider): - validation.lazy_validate(schema.service_provider_create, - service_provider) - service_provider = self._normalize_dict(service_provider) - service_provider.setdefault('enabled', False) - service_provider.setdefault('relay_state_prefix', - CONF.saml.relay_state_prefix) - sp_ref = PROVIDERS.federation_api.create_sp(sp_id, service_provider) - response = ServiceProvider.wrap_member(request.context_dict, sp_ref) - return wsgi.render_response( - body=response, status=(http_client.CREATED, - http_client.responses[http_client.CREATED])) - - @controller.filterprotected('id', 'enabled') - def list_service_providers(self, request, filters): - hints = self.build_driver_hints(request, filters) - ref = PROVIDERS.federation_api.list_sps(hints=hints) - ref = [self.filter_params(x) for x in ref] - return ServiceProvider.wrap_collection(request.context_dict, - ref, hints=hints) - - @controller.protected() - def get_service_provider(self, request, sp_id): - ref = PROVIDERS.federation_api.get_sp(sp_id) - return ServiceProvider.wrap_member(request.context_dict, ref) - - @controller.protected() - def delete_service_provider(self, request, sp_id): - PROVIDERS.federation_api.delete_sp(sp_id) - - @controller.protected() - def update_service_provider(self, request, sp_id, service_provider): - validation.lazy_validate(schema.service_provider_update, - service_provider) - service_provider = self._normalize_dict(service_provider) - sp_ref = PROVIDERS.federation_api.update_sp(sp_id, service_provider) - return ServiceProvider.wrap_member(request.context_dict, sp_ref) - - -class SAMLMetadataV3(_ControllerBase): - member_name = 'metadata' - - def get_metadata(self, context): - metadata_path = CONF.saml.idp_metadata_path - try: - with open(metadata_path, 'r') as metadata_handler: - metadata = metadata_handler.read() - except IOError as e: - # Raise HTTP 500 in case Metadata file cannot be read. - raise exception.MetadataFileError(reason=e) - return wsgi.render_response( - body=metadata, status=(http_client.OK, - http_client.responses[http_client.OK]), - headers=[('Content-Type', 'text/xml')]) diff --git a/keystone/federation/routers.py b/keystone/federation/routers.py index 8b07f5376..9bfd11740 100644 --- a/keystone/federation/routers.py +++ b/keystone/federation/routers.py @@ -36,54 +36,6 @@ class Routers(wsgi.RoutersBase): The API looks like:: - PUT /OS-FEDERATION/identity_providers/{idp_id} - GET /OS-FEDERATION/identity_providers - HEAD /OS-FEDERATION/identity_providers - GET /OS-FEDERATION/identity_providers/{idp_id} - HEAD /OS-FEDERATION/identity_providers/{idp_id} - DELETE /OS-FEDERATION/identity_providers/{idp_id} - PATCH /OS-FEDERATION/identity_providers/{idp_id} - - PUT /OS-FEDERATION/identity_providers/ - {idp_id}/protocols/{protocol_id} - GET /OS-FEDERATION/identity_providers/ - {idp_id}/protocols - HEAD /OS-FEDERATION/identity_providers/ - {idp_id}/protocols - GET /OS-FEDERATION/identity_providers/ - {idp_id}/protocols/{protocol_id} - HEAD /OS-FEDERATION/identity_providers/ - {idp_id}/protocols/{protocol_id} - PATCH /OS-FEDERATION/identity_providers/ - {idp_id}/protocols/{protocol_id} - DELETE /OS-FEDERATION/identity_providers/ - {idp_id}/protocols/{protocol_id} - - PUT /OS-FEDERATION/mappings - GET /OS-FEDERATION/mappings - HEAD /OS-FEDERATION/mappings - PATCH /OS-FEDERATION/mappings/{mapping_id} - GET /OS-FEDERATION/mappings/{mapping_id} - HEAD /OS-FEDERATION/mappings/{mapping_id} - DELETE /OS-FEDERATION/mappings/{mapping_id} - - GET /OS-FEDERATION/projects - HEAD /OS-FEDERATION/projects - GET /OS-FEDERATION/domains - HEAD /OS-FEDERATION/domains - - PUT /OS-FEDERATION/service_providers/{sp_id} - GET /OS-FEDERATION/service_providers - HEAD /OS-FEDERATION/service_providers - GET /OS-FEDERATION/service_providers/{sp_id} - HEAD /OS-FEDERATION/service_providers/{sp_id} - DELETE /OS-FEDERATION/service_providers/{sp_id} - PATCH /OS-FEDERATION/service_providers/{sp_id} - - GET /OS-FEDERATION/identity_providers/{idp_id}/ - protocols/{protocol_id}/auth - POST /OS-FEDERATION/identity_providers/{idp_id}/ - protocols/{protocol_id}/auth GET /auth/OS-FEDERATION/identity_providers/ {idp_id}/protocols/{protocol_id}/websso ?origin=https%3A//horizon.example.com @@ -94,8 +46,6 @@ class Routers(wsgi.RoutersBase): POST /auth/OS-FEDERATION/saml2 POST /auth/OS-FEDERATION/saml2/ecp - GET /OS-FEDERATION/saml2/metadata - HEAD /OS-FEDERATION/saml2/metadata GET /auth/OS-FEDERATION/websso/{protocol_id} ?origin=https%3A//horizon.example.com @@ -105,133 +55,17 @@ class Routers(wsgi.RoutersBase): """ - _path_prefixes = ('auth', 'OS-FEDERATION') + _path_prefixes = ('auth',) def _construct_url(self, suffix): return "/OS-FEDERATION/%s" % suffix def append_v3_routers(self, mapper, routers): auth_controller = controllers.Auth() - idp_controller = controllers.IdentityProvider() - protocol_controller = controllers.FederationProtocol() - mapping_controller = controllers.MappingController() - project_controller = controllers.ProjectAssignmentV3() - domain_controller = controllers.DomainV3() - saml_metadata_controller = controllers.SAMLMetadataV3() - sp_controller = controllers.ServiceProvider() - - # Identity Provider CRUD operations - - self._add_resource( - mapper, idp_controller, - path=self._construct_url('identity_providers/{idp_id}'), - get_head_action='get_identity_provider', - put_action='create_identity_provider', - patch_action='update_identity_provider', - delete_action='delete_identity_provider', - rel=build_resource_relation(resource_name='identity_provider'), - path_vars={ - 'idp_id': IDP_ID_PARAMETER_RELATION, - }) - self._add_resource( - mapper, idp_controller, - path=self._construct_url('identity_providers'), - get_head_action='list_identity_providers', - rel=build_resource_relation(resource_name='identity_providers')) - - # Protocol CRUD operations - - self._add_resource( - mapper, protocol_controller, - path=self._construct_url('identity_providers/{idp_id}/protocols/' - '{protocol_id}'), - get_head_action='get_protocol', - put_action='create_protocol', - patch_action='update_protocol', - delete_action='delete_protocol', - rel=build_resource_relation( - resource_name='identity_provider_protocol'), - path_vars={ - 'idp_id': IDP_ID_PARAMETER_RELATION, - 'protocol_id': PROTOCOL_ID_PARAMETER_RELATION, - }) - self._add_resource( - mapper, protocol_controller, - path=self._construct_url('identity_providers/{idp_id}/protocols'), - get_head_action='list_protocols', - rel=build_resource_relation( - resource_name='identity_provider_protocols'), - path_vars={ - 'idp_id': IDP_ID_PARAMETER_RELATION, - }) - - # Mapping CRUD operations - - self._add_resource( - mapper, mapping_controller, - path=self._construct_url('mappings/{mapping_id}'), - get_head_action='get_mapping', - put_action='create_mapping', - patch_action='update_mapping', - delete_action='delete_mapping', - rel=build_resource_relation(resource_name='mapping'), - path_vars={ - 'mapping_id': build_parameter_relation( - parameter_name='mapping_id'), - }) - self._add_resource( - mapper, mapping_controller, - path=self._construct_url('mappings'), - get_head_action='list_mappings', - rel=build_resource_relation(resource_name='mappings')) - - # Service Providers CRUD operations - - self._add_resource( - mapper, sp_controller, - path=self._construct_url('service_providers/{sp_id}'), - get_head_action='get_service_provider', - put_action='create_service_provider', - patch_action='update_service_provider', - delete_action='delete_service_provider', - rel=build_resource_relation(resource_name='service_provider'), - path_vars={ - 'sp_id': SP_ID_PARAMETER_RELATION, - }) - - self._add_resource( - mapper, sp_controller, - path=self._construct_url('service_providers'), - get_head_action='list_service_providers', - rel=build_resource_relation(resource_name='service_providers')) - - self._add_resource( - mapper, domain_controller, - path=self._construct_url('domains'), - new_path='/auth/domains', - get_head_action='list_domains_for_user', - rel=build_resource_relation(resource_name='domains')) - self._add_resource( - mapper, project_controller, - path=self._construct_url('projects'), - new_path='/auth/projects', - get_head_action='list_projects_for_user', - rel=build_resource_relation(resource_name='projects')) # Auth operations self._add_resource( mapper, auth_controller, - path=self._construct_url('identity_providers/{idp_id}/' - 'protocols/{protocol_id}/auth'), - get_post_action='federated_authentication', - rel=build_resource_relation( - resource_name='identity_provider_protocol_auth'), - path_vars={ - 'idp_id': IDP_ID_PARAMETER_RELATION, - 'protocol_id': PROTOCOL_ID_PARAMETER_RELATION, - }) - self._add_resource( - mapper, auth_controller, path='/auth' + self._construct_url('saml2'), post_action='create_saml_assertion', rel=build_resource_relation(resource_name='saml2')) @@ -253,15 +87,9 @@ class Routers(wsgi.RoutersBase): path='/auth' + self._construct_url( 'identity_providers/{idp_id}/protocols/{protocol_id}/websso'), get_post_action='federated_idp_specific_sso_auth', - rel=build_resource_relation(resource_name='identity_providers'), + rel=build_resource_relation( + resource_name='identity_providers_websso'), path_vars={ 'idp_id': IDP_ID_PARAMETER_RELATION, 'protocol_id': PROTOCOL_ID_PARAMETER_RELATION, }) - - # Keystone-Identity-Provider metadata endpoint - self._add_resource( - mapper, saml_metadata_controller, - path=self._construct_url('saml2/metadata'), - get_head_action='get_metadata', - rel=build_resource_relation(resource_name='metadata')) |