def test_get_service_provider_returns_correct_value(self): # Arrange service_provider_metadata = fixtures.CORRECT_XML_WITH_ONE_SP metadata_parser = SAMLMetadataParser() metadata_parser.parse = MagicMock(side_effect=metadata_parser.parse) configuration_storage = ConfigurationStorage( self._saml_integration_association) configuration_storage.load = MagicMock( side_effect=configuration_storage.load) saml_configuration_factory = SAMLConfigurationFactory(metadata_parser) with saml_configuration_factory.create( configuration_storage, self._db, SAMLConfiguration) as configuration: configuration.service_provider_xml_metadata = service_provider_metadata # Act service_provider = configuration.get_service_provider(self._db) # Assert assert True == isinstance(service_provider, SAMLServiceProviderMetadata) assert fixtures.SP_ENTITY_ID == service_provider.entity_id configuration_storage.load.assert_has_calls([ call(self._db, SAMLConfiguration.service_provider_xml_metadata.key), call(self._db, SAMLConfiguration.service_provider_private_key.key), ]) metadata_parser.parse.assert_called_once_with( service_provider_metadata)
def test_parse_does_not_raise_exception_when_xml_metadata_does_not_have_display_names( self, ): # Arrange metadata_parser = SAMLMetadataParser() # Act parsing_results = metadata_parser.parse( fixtures.CORRECT_XML_WITH_ONE_IDP_METADATA_WITHOUT_DISPLAY_NAMES) # Assert assert 1 == len(parsing_results) [parsing_result] = parsing_results assert True == isinstance(parsing_result, SAMLMetadataParsingResult) assert True == isinstance(parsing_result.provider, SAMLIdentityProviderMetadata) assert True == isinstance(parsing_result.xml_node, onelogin.saml2.xmlparser.RestrictedElement) assert (SAMLIdentityProviderMetadata( entity_id=fixtures.IDP_1_ENTITY_ID, ui_info=SAMLUIInfo(), organization=SAMLOrganization(), name_id_format=fixtures.NAME_ID_FORMAT_1, sso_service=SAMLService(fixtures.IDP_1_SSO_URL, fixtures.IDP_1_SSO_BINDING), want_authn_requests_signed=False, signing_certificates=[ fixtures.strip_certificate(fixtures.SIGNING_CERTIFICATE) ], encryption_certificates=[ fixtures.strip_certificate(fixtures.ENCRYPTION_CERTIFICATE) ], ) == parsing_result.provider)
def test_parse_raises_exception_when_xml_metadata_has_incorrect_format( self): # Arrange metadata_parser = SAMLMetadataParser() # Act with pytest.raises(SAMLMetadataParsingError): metadata_parser.parse(fixtures.INCORRECT_XML)
def test_parse_raises_exception_when_sp_metadata_does_not_contain_acs_service( self): # Arrange metadata_parser = SAMLMetadataParser() # Act with pytest.raises(SAMLMetadataParsingError): metadata_parser.parse( fixtures.INCORRECT_XML_WITH_ONE_SP_METADATA_WITHOUT_ACS_SERVICE )
def test_parse_raises_exception_when_idp_metadata_contains_sso_service_with_wrong_binding( self, ): # Arrange metadata_parser = SAMLMetadataParser() # Act with pytest.raises(SAMLMetadataParsingError): metadata_parser.parse( fixtures. INCORRECT_XML_WITH_ONE_IDP_METADATA_WITH_SSO_SERVICE_WITH_WRONG_BINDING )
def test_get_identity_providers_returns_non_federated_idps(self): # Arrange identity_providers_metadata = fixtures.CORRECT_XML_WITH_MULTIPLE_IDPS metadata_parser = SAMLMetadataParser() metadata_parser.parse = MagicMock(side_effect=metadata_parser.parse) configuration_storage = ConfigurationStorage( self._saml_integration_association) configuration_storage.load = MagicMock( side_effect=configuration_storage.load) saml_configuration_factory = SAMLConfigurationFactory(metadata_parser) with saml_configuration_factory.create( configuration_storage, self._db, SAMLConfiguration) as configuration: configuration.non_federated_identity_provider_xml_metadata = ( identity_providers_metadata) # Act identity_providers = configuration.get_identity_providers(self._db) # Assert assert 2 == len(identity_providers) assert True == isinstance(identity_providers[0], SAMLIdentityProviderMetadata) assert fixtures.IDP_1_ENTITY_ID == identity_providers[0].entity_id assert True == isinstance(identity_providers[1], SAMLIdentityProviderMetadata) assert fixtures.IDP_2_ENTITY_ID == identity_providers[1].entity_id configuration_storage.load.assert_has_calls([ call( self._db, SAMLConfiguration. non_federated_identity_provider_xml_metadata.key, ), call( self._db, SAMLConfiguration.federated_identity_provider_entity_ids. key, ), ]) metadata_parser.parse.assert_called_once_with( identity_providers_metadata)
def __init__(self, library, integration, analytics=None): """Initializes a new instance of SAMLAuthenticationProvider class :param library: Patrons authenticated through this provider are associated with this Library. Don't store this object! It's associated with a scoped database session. Just pull normal Python objects out of it. :type library: Library :param integration: The ExternalIntegration that configures this AuthenticationProvider. Don't store this object! It's associated with a scoped database session. Just pull normal Python objects out of it. :type integration: ExternalIntegration """ super(BaseSAMLAuthenticationProvider, self).__init__(library, integration, analytics) self._logger = logging.getLogger(__name__) self._configuration_storage = ConfigurationStorage(self) self._configuration_factory = SAMLConfigurationFactory( SAMLMetadataParser()) self._authentication_manager_factory = SAMLAuthenticationManagerFactory( ) db = Session.object_session(library) with self.get_configuration(db) as configuration: self._patron_id_use_name_id = ConfigurationMetadata.to_bool( configuration.patron_id_use_name_id) self._patron_id_attributes = configuration.patron_id_attributes self._patron_id_regular_expression = ( configuration.patron_id_regular_expression)
def validator_factory(): metadata_parser = SAMLMetadataParser() parser = DSLParser() visitor = DSLEvaluationVisitor() evaluator = DSLEvaluator(parser, visitor) subject_filter = SAMLSubjectFilter(evaluator) return SAMLSettingsValidator(metadata_parser, subject_filter)
def test_validate( self, _, sp_xml_metadata, idp_xml_metadata, patron_id_regular_expression, expected_validation_result, ): """Ensure that SAMLSettingsValidator correctly validates the input data. :param sp_xml_metadata: SP SAML metadata :type sp_xml_metadata: str :param idp_xml_metadata: IdP SAML metadata :type idp_xml_metadata: str :param patron_id_regular_expression: Regular expression used to extract a unique patron ID from SAML attributes :type patron_id_regular_expression: str :param expected_validation_result: Expected result: ProblemDetail object if validation must fail, None otherwise :type expected_validation_result: Optional[ProblemDetail] """ # Arrange submitted_form_data = MultiDict() if sp_xml_metadata is not None: submitted_form_data.add( SAMLConfiguration.service_provider_xml_metadata.key, sp_xml_metadata) if idp_xml_metadata is not None: submitted_form_data.add( SAMLConfiguration.non_federated_identity_provider_xml_metadata. key, idp_xml_metadata, ) if patron_id_regular_expression is not None: submitted_form_data.add( SAMLConfiguration.patron_id_regular_expression.key, patron_id_regular_expression, ) submitted_form = {"form": submitted_form_data} metadata_parser = SAMLMetadataParser() parser = DSLParser() visitor = DSLEvaluationVisitor() evaluator = DSLEvaluator(parser, visitor) subject_filter = SAMLSubjectFilter(evaluator) validator = SAMLSettingsValidator(metadata_parser, subject_filter) # Act settings = list(SAMLWebSSOAuthenticationProvider.SETTINGS) result = validator.validate(settings, submitted_form) # Assert if isinstance(result, ProblemDetail): assert expected_validation_result.response == result.response else: assert expected_validation_result == result
def setup_method(self, _db=None, set_up_circulation_manager=True): super(TestSAMLWebSSOAuthenticationProvider, self).setup_method() metadata_parser = SAMLMetadataParser() self._external_integration_association = create_autospec( spec=HasExternalIntegration) self._external_integration_association.external_integration = MagicMock( return_value=self._integration) self._configuration_storage = ConfigurationStorage( self._external_integration_association) self._configuration_factory = SAMLConfigurationFactory(metadata_parser)
def test_load(self): # Arrange federation_type = incommon.FEDERATION_TYPE federation_idp_metadata_service_url = incommon.IDP_METADATA_SERVICE_URL xml_metadata = fixtures.CORRECT_XML_WITH_MULTIPLE_IDPS metadata_loader = create_autospec(spec=SAMLMetadataLoader) metadata_validator = create_autospec( spec=SAMLFederatedMetadataValidator) metadata_parser = SAMLMetadataParser() idp_loader = SAMLFederatedIdentityProviderLoader( metadata_loader, metadata_validator, metadata_parser) saml_federation = SAMLFederation(federation_type, federation_idp_metadata_service_url) metadata_loader.load_idp_metadata = MagicMock( return_value=xml_metadata) metadata_parser.parse = MagicMock(side_effect=metadata_parser.parse) # Act idps = idp_loader.load(saml_federation) # Assert assert 2 == len(idps) assert fixtures.IDP_1_ENTITY_ID == idps[0].entity_id assert fixtures.IDP_1_UI_INFO_EN_DISPLAY_NAME == idps[0].display_name assert saml_federation == idps[0].federation assert fixtures.IDP_2_ENTITY_ID == idps[1].entity_id assert fixtures.IDP_2_UI_INFO_EN_DISPLAY_NAME == idps[1].display_name assert saml_federation == idps[1].federation metadata_loader.load_idp_metadata.assert_called_once_with( federation_idp_metadata_service_url) metadata_parser.parse.assert_called_once_with(xml_metadata)
def __init__(self, circulation_manager, authenticator): """Initializes a new instance of SAMLController class :param circulation_manager: Circulation Manager :type circulation_manager: CirculationManager :param authenticator: Authenticator object used to route requests to the appropriate LibraryAuthenticator :type authenticator: Authenticator """ self._circulation_manager = circulation_manager self._authenticator = authenticator self._logger = logging.getLogger(__name__) self._configuration_factory = SAMLConfigurationFactory( SAMLMetadataParser())
def test_parse_correctly_parses_one_idp_metadata(self): # Arrange metadata_parser = SAMLMetadataParser() # Act parsing_results = metadata_parser.parse( fixtures.CORRECT_XML_WITH_IDP_1) # Assert assert 1 == len(parsing_results) [parsing_result] = parsing_results assert True == isinstance(parsing_result, SAMLMetadataParsingResult) assert True == isinstance(parsing_result.provider, SAMLIdentityProviderMetadata) assert True == isinstance(parsing_result.xml_node, onelogin.saml2.xmlparser.RestrictedElement) assert (SAMLIdentityProviderMetadata( entity_id=fixtures.IDP_1_ENTITY_ID, ui_info=SAMLUIInfo( [ SAMLLocalizedMetadataItem( fixtures.IDP_1_UI_INFO_EN_DISPLAY_NAME, "en"), SAMLLocalizedMetadataItem( fixtures.IDP_1_UI_INFO_ES_DISPLAY_NAME, "es"), ], [ SAMLLocalizedMetadataItem( fixtures.IDP_1_UI_INFO_DESCRIPTION, "en") ], [ SAMLLocalizedMetadataItem( fixtures.IDP_1_UI_INFO_INFORMATION_URL, "en") ], [ SAMLLocalizedMetadataItem( fixtures.IDP_1_UI_INFO_PRIVACY_STATEMENT_URL, "en") ], [ SAMLLocalizedMetadataItem(fixtures.IDP_1_UI_INFO_LOGO_URL, "en") ], ), organization=SAMLOrganization( [ SAMLLocalizedMetadataItem( fixtures.IDP_1_ORGANIZATION_EN_ORGANIZATION_NAME, "en"), SAMLLocalizedMetadataItem( fixtures.IDP_1_ORGANIZATION_ES_ORGANIZATION_NAME, "es"), ], [ SAMLLocalizedMetadataItem( fixtures. IDP_1_ORGANIZATION_EN_ORGANIZATION_DISPLAY_NAME, "en", ), SAMLLocalizedMetadataItem( fixtures. IDP_1_ORGANIZATION_ES_ORGANIZATION_DISPLAY_NAME, "es", ), ], [ SAMLLocalizedMetadataItem( fixtures.IDP_1_ORGANIZATION_EN_ORGANIZATION_URL, "en"), SAMLLocalizedMetadataItem( fixtures.IDP_1_ORGANIZATION_ES_ORGANIZATION_URL, "es"), ], ), name_id_format=fixtures.NAME_ID_FORMAT_1, sso_service=SAMLService(fixtures.IDP_1_SSO_URL, fixtures.IDP_1_SSO_BINDING), want_authn_requests_signed=False, signing_certificates=[ fixtures.strip_certificate(fixtures.SIGNING_CERTIFICATE) ], encryption_certificates=[ fixtures.strip_certificate(fixtures.ENCRYPTION_CERTIFICATE) ], ) == parsing_result.provider)
def test_parse_correctly_parses_one_sp_metadata(self): # Arrange metadata_parser = SAMLMetadataParser() # Act parsing_results = metadata_parser.parse( fixtures.CORRECT_XML_WITH_ONE_SP) # Assert assert 1 == len(parsing_results) [parsing_result] = parsing_results assert True == isinstance(parsing_result, SAMLMetadataParsingResult) assert True == isinstance(parsing_result.provider, SAMLServiceProviderMetadata) assert True == isinstance(parsing_result.xml_node, onelogin.saml2.xmlparser.RestrictedElement) assert (SAMLServiceProviderMetadata( entity_id=fixtures.SP_ENTITY_ID, ui_info=SAMLUIInfo( [ SAMLLocalizedMetadataItem( fixtures.SP_UI_INFO_EN_DISPLAY_NAME, "en"), SAMLLocalizedMetadataItem( fixtures.SP_UI_INFO_ES_DISPLAY_NAME, "es"), ], [ SAMLLocalizedMetadataItem(fixtures.SP_UI_INFO_DESCRIPTION, "en") ], [ SAMLLocalizedMetadataItem( fixtures.SP_UI_INFO_INFORMATION_URL, "en") ], [ SAMLLocalizedMetadataItem( fixtures.SP_UI_INFO_PRIVACY_STATEMENT_URL, "en") ], [SAMLLocalizedMetadataItem(fixtures.SP_UI_INFO_LOGO_URL)], ), organization=SAMLOrganization( [ SAMLLocalizedMetadataItem( fixtures.SP_ORGANIZATION_EN_ORGANIZATION_NAME, "en"), SAMLLocalizedMetadataItem( fixtures.SP_ORGANIZATION_ES_ORGANIZATION_NAME, "es"), ], [ SAMLLocalizedMetadataItem( fixtures.SP_ORGANIZATION_EN_ORGANIZATION_DISPLAY_NAME, "en"), SAMLLocalizedMetadataItem( fixtures.SP_ORGANIZATION_ES_ORGANIZATION_DISPLAY_NAME, "es"), ], [ SAMLLocalizedMetadataItem( fixtures.SP_ORGANIZATION_EN_ORGANIZATION_URL, "en"), SAMLLocalizedMetadataItem( fixtures.SP_ORGANIZATION_ES_ORGANIZATION_URL, "es"), ], ), name_id_format=SAMLNameIDFormat.UNSPECIFIED.value, acs_service=SAMLService(fixtures.SP_ACS_URL, fixtures.SP_ACS_BINDING), authn_requests_signed=False, want_assertions_signed=False, certificate=fixtures.strip_certificate( fixtures.SIGNING_CERTIFICATE), ) == parsing_result.provider)
def test_get_identity_providers_returns_both_non_federated_and_federated_idps( self): # Arrange non_federated_identity_providers_metadata = ( fixtures.CORRECT_XML_WITH_MULTIPLE_IDPS) federated_identity_provider_entity_ids = json.dumps( [fixtures.IDP_1_ENTITY_ID, fixtures.IDP_2_ENTITY_ID]) metadata_parser = SAMLMetadataParser() metadata_parser.parse = MagicMock(side_effect=metadata_parser.parse) configuration_storage = ConfigurationStorage( self._saml_integration_association) configuration_storage.load = MagicMock( side_effect=configuration_storage.load) saml_configuration_factory = SAMLConfigurationFactory(metadata_parser) federation = SAMLFederation("Test federation", "http://localhost") federated_idp_1 = SAMLFederatedIdentityProvider( federation, fixtures.IDP_1_ENTITY_ID, fixtures.IDP_1_UI_INFO_EN_DISPLAY_NAME, fixtures.CORRECT_XML_WITH_IDP_1, ) federated_idp_2 = SAMLFederatedIdentityProvider( federation, fixtures.IDP_2_ENTITY_ID, fixtures.IDP_2_UI_INFO_EN_DISPLAY_NAME, fixtures.CORRECT_XML_WITH_IDP_2, ) self._db.add_all([federation, federated_idp_1, federated_idp_2]) with saml_configuration_factory.create( configuration_storage, self._db, SAMLConfiguration) as configuration: configuration.non_federated_identity_provider_xml_metadata = ( non_federated_identity_providers_metadata) configuration.federated_identity_provider_entity_ids = ( federated_identity_provider_entity_ids) # Act identity_providers = configuration.get_identity_providers(self._db) # Assert assert 4 == len(identity_providers) assert True == isinstance(identity_providers[0], SAMLIdentityProviderMetadata) assert fixtures.IDP_1_ENTITY_ID == identity_providers[0].entity_id assert True == isinstance(identity_providers[1], SAMLIdentityProviderMetadata) assert fixtures.IDP_2_ENTITY_ID == identity_providers[1].entity_id assert True == isinstance(identity_providers[2], SAMLIdentityProviderMetadata) assert fixtures.IDP_1_ENTITY_ID == identity_providers[2].entity_id assert True == isinstance(identity_providers[3], SAMLIdentityProviderMetadata) assert fixtures.IDP_2_ENTITY_ID == identity_providers[3].entity_id configuration_storage.load.assert_has_calls([ call( self._db, SAMLConfiguration. non_federated_identity_provider_xml_metadata.key, ), call( self._db, SAMLConfiguration.federated_identity_provider_entity_ids. key, ), ]) metadata_parser.parse.assert_has_calls([ call(non_federated_identity_providers_metadata), call(federated_idp_1.xml_metadata), call(federated_idp_2.xml_metadata), ])