aboutsummaryrefslogtreecommitdiffstats
path: root/keystone-moon/keystone/federation/core.py
diff options
context:
space:
mode:
Diffstat (limited to 'keystone-moon/keystone/federation/core.py')
-rw-r--r--keystone-moon/keystone/federation/core.py611
1 files changed, 611 insertions, 0 deletions
diff --git a/keystone-moon/keystone/federation/core.py b/keystone-moon/keystone/federation/core.py
new file mode 100644
index 00000000..23028dfd
--- /dev/null
+++ b/keystone-moon/keystone/federation/core.py
@@ -0,0 +1,611 @@
+# 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.
+
+"""Main entry point into the Federation service."""
+
+import abc
+
+from oslo_config import cfg
+from oslo_log import versionutils
+import six
+
+from keystone.common import dependency
+from keystone.common import extension
+from keystone.common import manager
+from keystone import exception
+from keystone.federation import utils
+
+
+CONF = cfg.CONF
+EXTENSION_DATA = {
+ 'name': 'OpenStack Federation APIs',
+ 'namespace': 'http://docs.openstack.org/identity/api/ext/'
+ 'OS-FEDERATION/v1.0',
+ 'alias': 'OS-FEDERATION',
+ 'updated': '2013-12-17T12:00:0-00:00',
+ 'description': 'OpenStack Identity Providers Mechanism.',
+ 'links': [{
+ 'rel': 'describedby',
+ 'type': 'text/html',
+ 'href': 'http://specs.openstack.org/openstack/keystone-specs/api/v3/'
+ 'identity-api-v3-os-federation-ext.html',
+ }]}
+extension.register_admin_extension(EXTENSION_DATA['alias'], EXTENSION_DATA)
+extension.register_public_extension(EXTENSION_DATA['alias'], EXTENSION_DATA)
+
+
+@dependency.provider('federation_api')
+class Manager(manager.Manager):
+ """Default pivot point for the Federation backend.
+
+ See :mod:`keystone.common.manager.Manager` for more details on how this
+ dynamically calls the backend.
+
+ """
+
+ driver_namespace = 'keystone.federation'
+
+ def __init__(self):
+ super(Manager, self).__init__(CONF.federation.driver)
+
+ # Make sure it is a driver version we support, and if it is a legacy
+ # driver, then wrap it.
+ if isinstance(self.driver, FederationDriverV8):
+ self.driver = V9FederationWrapperForV8Driver(self.driver)
+ elif not isinstance(self.driver, FederationDriverV9):
+ raise exception.UnsupportedDriverVersion(
+ driver=CONF.federation.driver)
+
+ def get_enabled_service_providers(self):
+ """List enabled service providers for Service Catalog
+
+ Service Provider in a catalog contains three attributes: ``id``,
+ ``auth_url``, ``sp_url``, where:
+
+ - id is a unique, user defined identifier for service provider object
+ - auth_url is an authentication URL of remote Keystone
+ - sp_url a URL accessible at the remote service provider where SAML
+ assertion is transmitted.
+
+ :returns: list of dictionaries with enabled service providers
+ :rtype: list of dicts
+
+ """
+ def normalize(sp):
+ ref = {
+ 'auth_url': sp.auth_url,
+ 'id': sp.id,
+ 'sp_url': sp.sp_url
+ }
+ return ref
+
+ service_providers = self.driver.get_enabled_service_providers()
+ return [normalize(sp) for sp in service_providers]
+
+ def evaluate(self, idp_id, protocol_id, assertion_data):
+ mapping = self.get_mapping_from_idp_and_protocol(idp_id, protocol_id)
+ rules = mapping['rules']
+ rule_processor = utils.RuleProcessor(mapping['id'], rules)
+ mapped_properties = rule_processor.process(assertion_data)
+ return mapped_properties, mapping['id']
+
+
+# The FederationDriverBase class is the set of driver methods from earlier
+# drivers that we still support, that have not been removed or modified. This
+# class is then used to created the augmented V8 and V9 version abstract driver
+# classes, without having to duplicate a lot of abstract method signatures.
+# If you remove a method from V9, then move the abstract methods from this Base
+# class to the V8 class. Do not modify any of the method signatures in the Base
+# class - changes should only be made in the V8 and subsequent classes.
+
+@six.add_metaclass(abc.ABCMeta)
+class FederationDriverBase(object):
+
+ @abc.abstractmethod
+ def create_idp(self, idp_id, idp):
+ """Create an identity provider.
+
+ :param idp_id: ID of IdP object
+ :type idp_id: string
+ :param idp: idp object
+ :type idp: dict
+ :returns: idp ref
+ :rtype: dict
+
+ """
+ raise exception.NotImplemented() # pragma: no cover
+
+ @abc.abstractmethod
+ def delete_idp(self, idp_id):
+ """Delete an identity provider.
+
+ :param idp_id: ID of IdP object
+ :type idp_id: string
+ :raises keystone.exception.IdentityProviderNotFound: If the IdP
+ doesn't exist.
+
+ """
+ raise exception.NotImplemented() # pragma: no cover
+
+ @abc.abstractmethod
+ def get_idp(self, idp_id):
+ """Get an identity provider by ID.
+
+ :param idp_id: ID of IdP object
+ :type idp_id: string
+ :raises keystone.exception.IdentityProviderNotFound: If the IdP
+ doesn't exist.
+ :returns: idp ref
+ :rtype: dict
+
+ """
+ raise exception.NotImplemented() # pragma: no cover
+
+ @abc.abstractmethod
+ def get_idp_from_remote_id(self, remote_id):
+ """Get an identity provider by remote ID.
+
+ :param remote_id: ID of remote IdP
+ :type idp_id: string
+ :raises keystone.exception.IdentityProviderNotFound: If the IdP
+ doesn't exist.
+ :returns: idp ref
+ :rtype: dict
+
+ """
+ raise exception.NotImplemented() # pragma: no cover
+
+ @abc.abstractmethod
+ def update_idp(self, idp_id, idp):
+ """Update an identity provider by ID.
+
+ :param idp_id: ID of IdP object
+ :type idp_id: string
+ :param idp: idp object
+ :type idp: dict
+ :raises keystone.exception.IdentityProviderNotFound: If the IdP
+ doesn't exist.
+ :returns: idp ref
+ :rtype: dict
+
+ """
+ raise exception.NotImplemented() # pragma: no cover
+
+ @abc.abstractmethod
+ def create_protocol(self, idp_id, protocol_id, protocol):
+ """Add an IdP-Protocol configuration.
+
+ :param idp_id: ID of IdP object
+ :type idp_id: string
+ :param protocol_id: ID of protocol object
+ :type protocol_id: string
+ :param protocol: protocol object
+ :type protocol: dict
+ :raises keystone.exception.IdentityProviderNotFound: If the IdP
+ doesn't exist.
+ :returns: protocol ref
+ :rtype: dict
+
+ """
+ raise exception.NotImplemented() # pragma: no cover
+
+ @abc.abstractmethod
+ def update_protocol(self, idp_id, protocol_id, protocol):
+ """Change an IdP-Protocol configuration.
+
+ :param idp_id: ID of IdP object
+ :type idp_id: string
+ :param protocol_id: ID of protocol object
+ :type protocol_id: string
+ :param protocol: protocol object
+ :type protocol: dict
+ :raises keystone.exception.IdentityProviderNotFound: If the IdP
+ doesn't exist.
+ :raises keystone.exception.FederatedProtocolNotFound: If the federated
+ protocol cannot be found.
+ :returns: protocol ref
+ :rtype: dict
+
+ """
+ raise exception.NotImplemented() # pragma: no cover
+
+ @abc.abstractmethod
+ def get_protocol(self, idp_id, protocol_id):
+ """Get an IdP-Protocol configuration.
+
+ :param idp_id: ID of IdP object
+ :type idp_id: string
+ :param protocol_id: ID of protocol object
+ :type protocol_id: string
+ :raises keystone.exception.IdentityProviderNotFound: If the IdP
+ doesn't exist.
+ :raises keystone.exception.FederatedProtocolNotFound: If the federated
+ protocol cannot be found.
+ :returns: protocol ref
+ :rtype: dict
+
+ """
+ raise exception.NotImplemented() # pragma: no cover
+
+ @abc.abstractmethod
+ def list_protocols(self, idp_id):
+ """List an IdP's supported protocols.
+
+ :param idp_id: ID of IdP object
+ :type idp_id: string
+ :raises keystone.exception.IdentityProviderNotFound: If the IdP
+ doesn't exist.
+ :returns: list of protocol ref
+ :rtype: list of dict
+
+ """
+ raise exception.NotImplemented() # pragma: no cover
+
+ @abc.abstractmethod
+ def delete_protocol(self, idp_id, protocol_id):
+ """Delete an IdP-Protocol configuration.
+
+ :param idp_id: ID of IdP object
+ :type idp_id: string
+ :param protocol_id: ID of protocol object
+ :type protocol_id: string
+ :raises keystone.exception.IdentityProviderNotFound: If the IdP
+ doesn't exist.
+ :raises keystone.exception.FederatedProtocolNotFound: If the federated
+ protocol cannot be found.
+
+ """
+ raise exception.NotImplemented() # pragma: no cover
+
+ @abc.abstractmethod
+ def create_mapping(self, mapping_id, mapping):
+ """Create a mapping.
+
+ :param mapping_id: ID of mapping object
+ :type mapping_id: string
+ :param mapping: mapping ref with mapping name
+ :type mapping: dict
+ :returns: mapping ref
+ :rtype: dict
+
+ """
+ raise exception.NotImplemented() # pragma: no cover
+
+ @abc.abstractmethod
+ def delete_mapping(self, mapping_id):
+ """Delete a mapping.
+
+ :param mapping_id: id of mapping to delete
+ :type mapping_ref: string
+ :returns: None
+
+ """
+ raise exception.NotImplemented() # pragma: no cover
+
+ @abc.abstractmethod
+ def update_mapping(self, mapping_id, mapping_ref):
+ """Update a mapping.
+
+ :param mapping_id: id of mapping to update
+ :type mapping_id: string
+ :param mapping_ref: new mapping ref
+ :type mapping_ref: dict
+ :returns: mapping ref
+ :rtype: dict
+
+ """
+ raise exception.NotImplemented() # pragma: no cover
+
+ @abc.abstractmethod
+ def list_mappings(self):
+ """List all mappings.
+
+ :returns: list of mapping refs
+ :rtype: list of dicts
+
+ """
+ raise exception.NotImplemented() # pragma: no cover
+
+ @abc.abstractmethod
+ def get_mapping(self, mapping_id):
+ """Get a mapping, returns the mapping based on mapping_id.
+
+ :param mapping_id: id of mapping to get
+ :type mapping_ref: string
+ :raises keystone.exception.MappingNotFound: If the mapping cannot
+ be found.
+ :returns: mapping ref
+ :rtype: dict
+
+ """
+ raise exception.NotImplemented() # pragma: no cover
+
+ @abc.abstractmethod
+ def get_mapping_from_idp_and_protocol(self, idp_id, protocol_id):
+ """Get mapping based on idp_id and protocol_id.
+
+ :param idp_id: id of the identity provider
+ :type idp_id: string
+ :param protocol_id: id of the protocol
+ :type protocol_id: string
+ :raises keystone.exception.IdentityProviderNotFound: If the IdP
+ doesn't exist.
+ :raises keystone.exception.FederatedProtocolNotFound: If the federated
+ protocol cannot be found.
+ :returns: mapping ref
+ :rtype: dict
+
+ """
+ raise exception.NotImplemented() # pragma: no cover
+
+ @abc.abstractmethod
+ def create_sp(self, sp_id, sp):
+ """Create a service provider.
+
+ :param sp_id: id of the service provider
+ :type sp_id: string
+ :param sp: service prvider object
+ :type sp: dict
+
+ :returns: service provider ref
+ :rtype: dict
+
+ """
+ raise exception.NotImplemented() # pragma: no cover
+
+ @abc.abstractmethod
+ def delete_sp(self, sp_id):
+ """Delete a service provider.
+
+ :param sp_id: id of the service provider
+ :type sp_id: string
+
+ :raises keystone.exception.ServiceProviderNotFound: If the service
+ provider doesn't exist.
+
+ """
+ raise exception.NotImplemented() # pragma: no cover
+
+ @abc.abstractmethod
+ def get_sp(self, sp_id):
+ """Get a service provider.
+
+ :param sp_id: id of the service provider
+ :type sp_id: string
+ :returns: service provider ref
+ :rtype: dict
+
+ :raises keystone.exception.ServiceProviderNotFound: If the service
+ provider doesn't exist.
+
+ """
+ raise exception.NotImplemented() # pragma: no cover
+
+ @abc.abstractmethod
+ def update_sp(self, sp_id, sp):
+ """Update a service provider.
+
+ :param sp_id: id of the service provider
+ :type sp_id: string
+ :param sp: service prvider object
+ :type sp: dict
+
+ :returns: service provider ref
+ :rtype: dict
+
+ :raises keystone.exception.ServiceProviderNotFound: If the service
+ provider doesn't exist.
+
+ """
+ raise exception.NotImplemented() # pragma: no cover
+
+ def get_enabled_service_providers(self):
+ """List enabled service providers for Service Catalog
+
+ Service Provider in a catalog contains three attributes: ``id``,
+ ``auth_url``, ``sp_url``, where:
+
+ - id is a unique, user defined identifier for service provider object
+ - auth_url is an authentication URL of remote Keystone
+ - sp_url a URL accessible at the remote service provider where SAML
+ assertion is transmitted.
+
+ :returns: list of dictionaries with enabled service providers
+ :rtype: list of dicts
+
+ """
+ raise exception.NotImplemented() # pragma: no cover
+
+
+class FederationDriverV8(FederationDriverBase):
+ """Removed or redefined methods from V8.
+
+ Move the abstract methods of any methods removed or modified in later
+ versions of the driver from FederationDriverBase to here. We maintain this
+ so that legacy drivers, which will be a subclass of FederationDriverV8, can
+ still reference them.
+
+ """
+
+ @abc.abstractmethod
+ def list_idps(self):
+ """List all identity providers.
+
+ :returns: list of idp refs
+ :rtype: list of dicts
+
+ :raises keystone.exception.IdentityProviderNotFound: If the IdP
+ doesn't exist.
+
+ """
+ raise exception.NotImplemented() # pragma: no cover
+
+ @abc.abstractmethod
+ def list_sps(self):
+ """List all service providers.
+
+ :returns: List of service provider ref objects
+ :rtype: list of dicts
+
+ """
+ raise exception.NotImplemented() # pragma: no cover
+
+
+class FederationDriverV9(FederationDriverBase):
+ """New or redefined methods from V8.
+
+ Add any new V9 abstract methods (or those with modified signatures) to
+ this class.
+
+ """
+
+ @abc.abstractmethod
+ def list_idps(self, hints):
+ """List all identity providers.
+
+ :param hints: filter hints which the driver should
+ implement if at all possible.
+ :returns: list of idp refs
+ :rtype: list of dicts
+
+ :raises keystone.exception.IdentityProviderNotFound: If the IdP
+ doesn't exist.
+
+ """
+ raise exception.NotImplemented() # pragma: no cover
+
+ @abc.abstractmethod
+ def list_sps(self, hints):
+ """List all service providers.
+
+ :param hints: filter hints which the driver should
+ implement if at all possible.
+ :returns: List of service provider ref objects
+ :rtype: list of dicts
+
+ :raises keystone.exception.ServiceProviderNotFound: If the SP
+ doesn't exist.
+
+ """
+ raise exception.NotImplemented() # pragma: no cover
+
+
+class V9FederationWrapperForV8Driver(FederationDriverV9):
+ """Wrapper class to supported a V8 legacy driver.
+
+ In order to support legacy drivers without having to make the manager code
+ driver-version aware, we wrap legacy drivers so that they look like the
+ latest version. For the various changes made in a new driver, here are the
+ actions needed in this wrapper:
+
+ Method removed from new driver - remove the call-through method from this
+ class, since the manager will no longer be
+ calling it.
+ Method signature (or meaning) changed - wrap the old method in a new
+ signature here, and munge the input
+ and output parameters accordingly.
+ New method added to new driver - add a method to implement the new
+ functionality here if possible. If that is
+ not possible, then return NotImplemented,
+ since we do not guarantee to support new
+ functionality with legacy drivers.
+
+ """
+
+ @versionutils.deprecated(
+ as_of=versionutils.deprecated.MITAKA,
+ what='keystone.federation.FederationDriverV8',
+ in_favor_of='keystone.federation.FederationDriverV9',
+ remove_in=+2)
+ def __init__(self, wrapped_driver):
+ self.driver = wrapped_driver
+
+ def create_idp(self, idp_id, idp):
+ return self.driver.create_idp(idp_id, idp)
+
+ def delete_idp(self, idp_id):
+ self.driver.delete_idp(idp_id)
+
+ # NOTE(davechen): The hints is ignored here to support legacy drivers,
+ # but the filters in hints will be remain unsatisfied and V3Controller
+ # wrapper will apply these filters at the end. So that the result get
+ # returned for list IdP will still be filtered with the legacy drivers.
+ def list_idps(self, hints):
+ return self.driver.list_idps()
+
+ def get_idp(self, idp_id):
+ return self.driver.get_idp(idp_id)
+
+ def get_idp_from_remote_id(self, remote_id):
+ return self.driver.get_idp_from_remote_id(remote_id)
+
+ def update_idp(self, idp_id, idp):
+ return self.driver.update_idp(idp_id, idp)
+
+ def create_protocol(self, idp_id, protocol_id, protocol):
+ return self.driver.create_protocol(idp_id, protocol_id, protocol)
+
+ def update_protocol(self, idp_id, protocol_id, protocol):
+ return self.driver.update_protocol(idp_id, protocol_id, protocol)
+
+ def get_protocol(self, idp_id, protocol_id):
+ return self.driver.get_protocol(idp_id, protocol_id)
+
+ def list_protocols(self, idp_id):
+ return self.driver.list_protocols(idp_id)
+
+ def delete_protocol(self, idp_id, protocol_id):
+ self.driver.delete_protocol(idp_id, protocol_id)
+
+ def create_mapping(self, mapping_id, mapping):
+ return self.driver.create_mapping(mapping_id, mapping)
+
+ def delete_mapping(self, mapping_id):
+ self.driver.delete_mapping(mapping_id)
+
+ def update_mapping(self, mapping_id, mapping_ref):
+ return self.driver.update_mapping(mapping_id, mapping_ref)
+
+ def list_mappings(self):
+ return self.driver.list_mappings()
+
+ def get_mapping(self, mapping_id):
+ return self.driver.get_mapping(mapping_id)
+
+ def get_mapping_from_idp_and_protocol(self, idp_id, protocol_id):
+ return self.driver.get_mapping_from_idp_and_protocol(
+ idp_id, protocol_id)
+
+ def create_sp(self, sp_id, sp):
+ return self.driver.create_sp(sp_id, sp)
+
+ def delete_sp(self, sp_id):
+ self.driver.delete_sp(sp_id)
+
+ # NOTE(davechen): The hints is ignored here to support legacy drivers,
+ # but the filters in hints will be remain unsatisfied and V3Controller
+ # wrapper will apply these filters at the end. So that the result get
+ # returned for list SPs will still be filtered with the legacy drivers.
+ def list_sps(self, hints):
+ return self.driver.list_sps()
+
+ def get_sp(self, sp_id):
+ return self.driver.get_sp(sp_id)
+
+ def update_sp(self, sp_id, sp):
+ return self.driver.update_sp(sp_id, sp)
+
+ def get_enabled_service_providers(self):
+ return self.driver.get_enabled_service_providers()
+
+
+Driver = manager.create_legacy_driver(FederationDriverV8)