Example #1
0
class ServiceProviderMetadataRegistry(object):
    def __init__(self):
        self._loaders = []
        for source_type, source_params in config.params.metadata.items():
            self._loaders.append({
                'local': ServiceProviderMetadataFileLoader,
                'remote': ServiceProviderMetadataHTTPLoader,
                'db': ServiceProviderMetadataDbLoader,
            }[source_type](source_params))
        self._validators = ValidatorGroup([
            XMLMetadataFormatValidator(),
            ServiceProviderMetadataXMLSchemaValidator(),
            SpidMetadataValidator(),
        ])

    def get(self, entity_id):
        entity_id = entity_id.strip()
        for loader in self._loaders:
            try:
                metadata = loader.get(entity_id)
                try:
                    self._validators.validate(metadata.xml)
                    return metadata
                except ValidationError as e:
                    raise DeserializationError(metadata.xml, e.details)
            except MetadataNotFoundError:
                continue

        raise MetadataNotFoundError(entity_id)

    def all(self):
        """Returns the list of entityIDs of all the known Service Providers"""
        return [i for l in self._loaders for i in l.all()]
Example #2
0
 def __init__(self):
     self._validators = ValidatorGroup([
         XMLMetadataFormatValidator(),
         ServiceProviderMetadataXMLSchemaValidator(),
         SpidMetadataValidator(),
     ])
     self._index_metadata()
Example #3
0
 def __init__(self):
     self._loaders = []
     for source_type, source_params in config.params.metadata.items():
         self._loaders.append({
             'local': ServiceProviderMetadataFileLoader,
             'remote': ServiceProviderMetadataHTTPLoader,
             'db': ServiceProviderMetadataDbLoader,
         }[source_type](source_params))
     self._validators = ValidatorGroup([
         XMLMetadataFormatValidator(),
         ServiceProviderMetadataXMLSchemaValidator(),
         SpidMetadataValidator(),
     ])
Example #4
0
def _get_deserializer(request, action, binding):
    validators = [
        XMLFormatValidator(),
        AuthnRequestXMLSchemaValidator(),
        SpidValidator(action, binding),
    ]
    validator_group = ValidatorGroup(validators)
    return HTTPRequestDeserializer(request, validator_group)
Example #5
0
 def test_successful_deserialization(self):
     validator = ValidatorGroup([SuccessValidator(), SuccessValidator()])
     request = FakeRequest('<xml></xml>')
     deserializer = HTTPRequestDeserializer(request,
                                            validator=validator,
                                            saml_class=FakeSAMLClass)
     deserialized = deserializer.deserialize()
     self.assertIsInstance(deserialized, FakeSAMLClass)
Example #6
0
def _get_loader(source_type, source_params):
    Loader = {
        'local': ServiceProviderMetadataFileLoader,
        'remote': ServiceProviderMetadataHTTPLoader,
    }[source_type]
    validator = ValidatorGroup([
        XMLMetadataFormatValidator(),
        ServiceProviderMetadataXMLSchemaValidator()
    ])
    return Loader(source_params, validator)
Example #7
0
 def test_blocking_validation_failure(self):
     xml = '<xml></xml>'
     blocking_validator = FailValidator(
         XMLFormatValidationError(['blocking error']))
     nonblocking_validator = FailValidator(
         XMLSchemaValidationError(['nonblocking error']))
     validator = ValidatorGroup([blocking_validator, nonblocking_validator])
     request = FakeRequest(xml)
     deserializer = HTTPRequestDeserializer(request,
                                            validator=validator,
                                            saml_class=FakeSAMLClass)
     with pytest.raises(DeserializationError) as excinfo:
         deserializer.deserialize()
     exc = excinfo.value
     self.assertEqual(len(exc.details), 1)
     self.assertEqual(exc.details[0], 'blocking error')
     self.assertEqual(exc.initial_data, xml)
Example #8
0
 def test_nonblocking_validation_failure(self):
     xml = '<xml></xml>'
     first_nonblocking_validator = FailValidator(
         XMLSchemaValidationError(['a nonblocking error']))
     second_nonblocking_validator = FailValidator(
         SPIDValidationError(['another nonblocking error']))
     validator = ValidatorGroup([
         first_nonblocking_validator,
         second_nonblocking_validator,
     ])
     request = FakeRequest(xml)
     deserializer = HTTPRequestDeserializer(request,
                                            validator=validator,
                                            saml_class=FakeSAMLClass)
     with pytest.raises(DeserializationError) as excinfo:
         deserializer.deserialize()
     exc = excinfo.value
     self.assertEqual(len(exc.details), 2)
     self.assertEqual(exc.details[0], 'a nonblocking error')
     self.assertEqual(exc.details[1], 'another nonblocking error')
     self.assertEqual(exc.initial_data, xml)
Example #9
0
class ServiceProviderMetadataRegistry:
    def __init__(self):
        self._validators = ValidatorGroup([
            XMLMetadataFormatValidator(),
            ServiceProviderMetadataXMLSchemaValidator(),
            SpidMetadataValidator(),
        ])
        self._index_metadata()

    def load(self, entity_id):
        """
        Loads the metadata of a Service Provider.

        Args:
            entity_id (str): Entity id of the SP (usually a URL or a URN).

        Returns:
            A ServiceProviderMetadata instance.

        Raises
            MetadataNotFoundError: If there is no metadata associated to
                the entity id.
            DeserializationError: If the metadata associated to the entity id
                is not valid.
        """
        entity_id = entity_id.strip()

        fresh_metadata = None

        metadata = self._metadata.get(entity_id, None)
        if not metadata:
            # Try to reload all sources to see if the unknown entity id was added there
            # somewhere.
            logger.debug(
                "Unknown entityId '{}`, reloading all the sources.".format(
                    entity_id))
            self._index_metadata()
        else:
            # We got an known entity id, try to load its metadata the previously known
            # location.
            try:
                fresh_metadata = metadata.loader.load(metadata.location)
                if fresh_metadata.entity_id != entity_id:
                    raise MetadataLoadError
            except MetadataLoadError as e:
                logger.debug(
                    ("{}\n"
                     "Cannot find entityId '{}` at its previous location '{}`"
                     "reloading all the sources").format(
                         e, entity_id, metadata.location))
                self._index_metadata()

        if not fresh_metadata:
            try:
                metadata = self._metadata[entity_id]
                fresh_metadata = metadata.loader.load(metadata.location)
            except (KeyError, MetadataLoadError):
                raise MetadataNotFoundError(entity_id)

            if metadata.entity_id != entity_id:
                raise MetadataNotFoundError(entity_id)
        try:
            self._validators.validate(fresh_metadata.xml)
        except ValidationError as e:
            raise DeserializationError(fresh_metadata.xml, e.details)

        return fresh_metadata

    def load_all(self):
        """
        Returns a dict containing all ServerProviderMetadata loaded,
        indexed by entityId.
        """
        self._index_metadata()

        return self._metadata

    def _index_metadata(self):
        """
        Populate self._metadata with the up to date information from all the
        configured SP metadata.
        """

        # dict of { entity_id: ServiceProviderMetadata }
        self._metadata = {}

        # Possible sources of metadata, ordered by preference
        # (ie. the first source will be preferred in case of duplicate
        # entity ids).
        SOURCE_TYPES = ['local', 'db', 'remote']

        for source_type in reversed(SOURCE_TYPES):
            if source_type not in config.params.metadata:
                continue

            source_params = config.params.metadata[source_type]

            loader = {
                'local': ServiceProviderMetadataFileLoader,
                'remote': ServiceProviderMetadataHTTPLoader,
                'db': ServiceProviderMetadataDbLoader,
            }[source_type](source_params)

            metadata = loader.load_all()
            for dup in set(metadata.keys()).intersection(set(self._metadata)):
                logger.info(
                    "Discarding duplicate entity_id `{}' from '{}`.".format(
                        dup, self._metadata[dup].location))

            self._metadata.update(metadata)