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()]
def __init__(self): self._validators = ValidatorGroup([ XMLMetadataFormatValidator(), ServiceProviderMetadataXMLSchemaValidator(), SpidMetadataValidator(), ]) self._index_metadata()
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_deserializer(request, action, binding): validators = [ XMLFormatValidator(), AuthnRequestXMLSchemaValidator(), SpidValidator(action, binding), ] validator_group = ValidatorGroup(validators) return HTTPRequestDeserializer(request, validator_group)
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)
def _get_loader(source_type, source_params): Loader = { 'local': ServiceProviderMetadataFileLoader, 'remote': ServiceProviderMetadataHTTPLoader, }[source_type] validator = ValidatorGroup([ XMLMetadataFormatValidator(), ServiceProviderMetadataXMLSchemaValidator() ]) return Loader(source_params, validator)
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)
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)
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)