def testIsValid(self): """ Tests the is_valid method of the OneLogin_Saml2_LogoutRequest """ request_data = { 'http_host': 'example.com', 'script_name': 'index.html' } request = self.file_contents(join(self.data_path, 'logout_requests', 'logout_request.xml')) settings = OneLogin_Saml2_Settings(self.loadSettingsJSON()) self.assertTrue(OneLogin_Saml2_Logout_Request.is_valid(settings, request, request_data)) settings.set_strict(True) self.assertFalse(OneLogin_Saml2_Logout_Request.is_valid(settings, request, request_data)) settings.set_strict(False) dom = parseString(request) self.assertTrue(OneLogin_Saml2_Logout_Request.is_valid(settings, dom, request_data)) settings.set_strict(True) self.assertFalse(OneLogin_Saml2_Logout_Request.is_valid(settings, dom, request_data)) current_url = OneLogin_Saml2_Utils.get_self_url_no_query(request_data) request_2 = request.replace('http://stuff.com/endpoints/endpoints/sls.php', current_url) self.assertTrue(OneLogin_Saml2_Logout_Request.is_valid(settings, request_2, request_data))
def testIsInvalidDestination(self): """ Tests the is_valid method of the OneLogin_Saml2_LogoutRequest Case Invalid Destination """ request_data = { 'http_host': 'example.com', 'script_name': 'index.html' } request = self.file_contents(join(self.data_path, 'logout_requests', 'logout_request.xml')) settings = OneLogin_Saml2_Settings(self.loadSettingsJSON()) self.assertTrue(OneLogin_Saml2_Logout_Request.is_valid(settings, request, request_data)) settings.set_strict(True) try: valid = OneLogin_Saml2_Logout_Request.is_valid(settings, request, request_data) self.assertFalse(valid) except Exception as e: self.assertIn('The LogoutRequest was received at', e.message) dom = parseString(request) dom.documentElement.setAttribute('Destination', None) self.assertTrue(OneLogin_Saml2_Logout_Request.is_valid(settings, dom.toxml(), request_data)) dom.documentElement.removeAttribute('Destination') self.assertTrue(OneLogin_Saml2_Logout_Request.is_valid(settings, dom.toxml(), request_data))
def testGetIDFromSAMLLogoutRequest(self): """ Tests the get_id method of the OneLogin_Saml2_LogoutRequest """ logout_request = self.file_contents(join(self.data_path, 'logout_requests', 'logout_request.xml')) id = OneLogin_Saml2_Logout_Request.get_id(logout_request) self.assertEqual('ONELOGIN_21584ccdfaca36a145ae990442dcd96bfe60151e', id) dom = parseString(logout_request) id2 = OneLogin_Saml2_Logout_Request.get_id(dom) self.assertEqual('ONELOGIN_21584ccdfaca36a145ae990442dcd96bfe60151e', id2)
def process_slo(self, keep_local_session=False, request_id=None, delete_session_cb=None): """ Process the SAML Logout Response / Logout Request sent by the IdP. :param keep_local_session: When false will destroy the local session, otherwise will destroy it :type keep_local_session: bool :param request_id: The ID of the LogoutRequest sent by this SP to the IdP :type request_id: string :returns: Redirection url """ self.__errors = [] if 'get_data' in self.__request_data and 'SAMLResponse' in self.__request_data['get_data']: logout_response = OneLogin_Saml2_Logout_Response(self.__settings, self.__request_data['get_data']['SAMLResponse']) if not logout_response.is_valid(self.__request_data, request_id): self.__errors.append('invalid_logout_response') elif logout_response.get_status() != OneLogin_Saml2_Constants.STATUS_SUCCESS: self.__errors.append('logout_not_success') elif not keep_local_session: OneLogin_Saml2_Utils.delete_local_session(delete_session_cb) elif 'get_data' in self.__request_data and 'SAMLRequest' in self.__request_data['get_data']: request = OneLogin_Saml2_Utils.decode_base64_and_inflate(self.__request_data['get_data']['SAMLRequest']) if not OneLogin_Saml2_Logout_Request.is_valid(self.__settings, request, self.__request_data): self.__errors.append('invalid_logout_request') else: if not keep_local_session: OneLogin_Saml2_Utils.delete_local_session(delete_session_cb) in_response_to = OneLogin_Saml2_Logout_Request.get_id(request) response_builder = OneLogin_Saml2_Logout_Response(self.__settings) response_builder.build(in_response_to) logout_response = response_builder.get_response() parameters = {'SAMLResponse': logout_response} if 'RelayState' in self.__request_data['get_data']: parameters['RelayState'] = self.__request_data['get_data']['RelayState'] security = self.__settings.get_security_data() if 'logoutResponseSigned' in security and security['logoutResponseSigned']: parameters['SigAlg'] = OneLogin_Saml2_Constants.RSA_SHA1 parameters['Signature'] = self.build_response_signature(logout_response, parameters.get('RelayState', None)) return self.redirect_to(self.get_slo_url(), parameters) else: self.__errors.append('invalid_binding') raise OneLogin_Saml2_Error( 'SAML LogoutRequest/LogoutResponse not found. Only supported HTTP_REDIRECT Binding', OneLogin_Saml2_Error.SAML_LOGOUTMESSAGE_NOT_FOUND )
def testIsInvalidXML(self): """ Tests the is_valid method of the OneLogin_Saml2_LogoutRequest Case Invalid XML """ request = '<xml>invalid</xml>' request_data = { 'http_host': 'example.com', 'script_name': 'index.html' } settings = OneLogin_Saml2_Settings(self.loadSettingsJSON()) self.assertTrue(OneLogin_Saml2_Logout_Request.is_valid(settings, request, request_data)) settings.set_strict(True) self.assertFalse(OneLogin_Saml2_Logout_Request.is_valid(settings, request, request_data))
def testGetSessionIndexes(self): """ Tests the get_session_indexes of the OneLogin_Saml2_LogoutRequest """ request = self.file_contents(join(self.data_path, 'logout_requests', 'logout_request.xml')) session_indexes = OneLogin_Saml2_Logout_Request.get_session_indexes(request) self.assertEqual(len(session_indexes), 0) dom = parseString(request) session_indexes_2 = OneLogin_Saml2_Logout_Request.get_session_indexes(dom) self.assertEqual(len(session_indexes_2), 0) request_2 = self.file_contents(join(self.data_path, 'logout_requests', 'logout_request_with_sessionindex.xml')) session_indexes_3 = OneLogin_Saml2_Logout_Request.get_session_indexes(request_2) self.assertEqual(['_ac72a76526cb6ca19f8438e73879a0e6c8ae5131'], session_indexes_3)
def testGetNameId(self): """ Tests the get_nameid of the OneLogin_Saml2_LogoutRequest """ request = self.file_contents(join(self.data_path, 'logout_requests', 'logout_request.xml')) name_id = OneLogin_Saml2_Logout_Request.get_nameid(request) self.assertEqual(name_id, 'ONELOGIN_1e442c129e1f822c8096086a1103c5ee2c7cae1c') request_2 = self.file_contents(join(self.data_path, 'logout_requests', 'logout_request_encrypted_nameid.xml')) self.assertRaisesRegexp(Exception, 'Key is required in order to decrypt the NameID', OneLogin_Saml2_Logout_Request.get_nameid, request_2) settings = OneLogin_Saml2_Settings(self.loadSettingsJSON()) key = settings.get_sp_key() name_id_3 = OneLogin_Saml2_Logout_Request.get_nameid(request_2, key) self.assertEqual('ONELOGIN_9c86c4542ab9d6fce07f2f7fd335287b9b3cdf69', name_id_3)
def testGetIssuer(self): """ Tests the get_issuer of the OneLogin_Saml2_LogoutRequest """ request = self.file_contents(join(self.data_path, 'logout_requests', 'logout_request.xml')) issuer = OneLogin_Saml2_Logout_Request.get_issuer(request) self.assertEqual('http://idp.example.com/', issuer) dom = parseString(request) issuer_2 = OneLogin_Saml2_Logout_Request.get_issuer(dom) self.assertEqual('http://idp.example.com/', issuer_2) issuer_node = dom.getElementsByTagName('saml:Issuer')[0] issuer_node.parentNode.removeChild(issuer_node) issuer_3 = OneLogin_Saml2_Logout_Request.get_issuer(dom) self.assertIsNone(issuer_3)
def testGetIDFromDeflatedSAMLLogoutRequest(self): """ Tests the get_id method of the OneLogin_Saml2_LogoutRequest """ deflated_logout_request = self.file_contents(join(self.data_path, 'logout_requests', 'logout_request_deflated.xml.base64')) logout_request = OneLogin_Saml2_Utils.decode_base64_and_inflate(deflated_logout_request) id = OneLogin_Saml2_Logout_Request.get_id(logout_request) self.assertEqual('ONELOGIN_21584ccdfaca36a145ae990442dcd96bfe60151e', id)
def testGetNameIdData(self): """ Tests the get_nameid_data method of the OneLogin_Saml2_LogoutRequest """ expected_name_id_data = { 'Value': 'ONELOGIN_1e442c129e1f822c8096086a1103c5ee2c7cae1c', 'Format': 'urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified', 'SPNameQualifier': 'http://idp.example.com/' } request = self.file_contents(join(self.data_path, 'logout_requests', 'logout_request.xml')) name_id_data = OneLogin_Saml2_Logout_Request.get_nameid_data(request) self.assertEqual(expected_name_id_data, name_id_data) dom = parseString(request) name_id_data_2 = OneLogin_Saml2_Logout_Request.get_nameid_data(dom) self.assertEqual(expected_name_id_data, name_id_data_2) request_2 = self.file_contents(join(self.data_path, 'logout_requests', 'logout_request_encrypted_nameid.xml')) try: OneLogin_Saml2_Logout_Request.get_nameid_data(request_2) self.assertTrue(False) except Exception as e: self.assertIn('Key is required in order to decrypt the NameID', e.message) settings = OneLogin_Saml2_Settings(self.loadSettingsJSON()) key = settings.get_sp_key() name_id_data_4 = OneLogin_Saml2_Logout_Request.get_nameid_data(request_2, key) expected_name_id_data = { 'Value': 'ONELOGIN_9c86c4542ab9d6fce07f2f7fd335287b9b3cdf69', 'Format': 'urn:oasis:names:tc:SAML:2.0:nameid-format:emailAddress', 'SPNameQualifier': 'https://pitbulk.no-ip.org/newonelogin/demo1/metadata.php' } self.assertEqual(expected_name_id_data, name_id_data_4) dom_2 = parseString(request_2) encrypted_id_nodes = dom_2.getElementsByTagName('saml:EncryptedID') encrypted_data = encrypted_id_nodes[0].firstChild.nextSibling encrypted_id_nodes[0].removeChild(encrypted_data) try: OneLogin_Saml2_Logout_Request.get_nameid_data(dom_2.toxml(), key) self.assertTre(False) except Exception as e: self.assertIn('Not NameID found in the Logout Request', e.message) inv_request = self.file_contents(join(self.data_path, 'logout_requests', 'invalids', 'no_nameId.xml')) try: OneLogin_Saml2_Logout_Request.get_nameid_data(inv_request) self.assertTre(False) except Exception as e: self.assertIn('Not NameID found in the Logout Request', e.message)
def testGetIssuer(self): """ Tests the get_issuer of the OneLogin_Saml2_LogoutRequest """ request = self.file_contents( join(self.data_path, 'logout_requests', 'logout_request.xml')) issuer = OneLogin_Saml2_Logout_Request.get_issuer(request) self.assertEqual('http://idp.example.com/', issuer) dom = parseString(request) issuer_2 = OneLogin_Saml2_Logout_Request.get_issuer(dom) self.assertEqual('http://idp.example.com/', issuer_2) issuer_node = dom.getElementsByTagName('saml:Issuer')[0] issuer_node.parentNode.removeChild(issuer_node) issuer_3 = OneLogin_Saml2_Logout_Request.get_issuer(dom) self.assertIsNone(issuer_3)
def testConstructorWithNameIdFormatOnSettings(self): """ Tests the OneLogin_Saml2_LogoutRequest Constructor. Case: Defines NameIDFormat from settings """ settings_info = self.loadSettingsJSON() name_id = 'ONELOGIN_1e442c129e1f822c8096086a1103c5ee2c7cae1c' name_id_format = 'urn:oasis:names:tc:SAML:2.0:nameid-format:transient' settings_info['sp']['NameIDFormat'] = name_id_format settings = OneLogin_Saml2_Settings(settings_info) logout_request = OneLogin_Saml2_Logout_Request(settings, name_id=name_id) logout_request_xml = OneLogin_Saml2_Utils.decode_base64_and_inflate( logout_request.get_request()) name_id_data = OneLogin_Saml2_Logout_Request.get_nameid_data( logout_request_xml) expected_name_id_data = {'Value': name_id, 'Format': name_id_format} self.assertEqual(expected_name_id_data, name_id_data)
def testConstructorWithoutNameIdFormat(self): """ Tests the OneLogin_Saml2_LogoutRequest Constructor. Case: Checks that NameIDFormat is not added """ settings_info = self.loadSettingsJSON() name_id = 'ONELOGIN_1e442c129e1f822c8096086a1103c5ee2c7cae1c' name_id_format = 'urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified' settings_info['sp']['NameIDFormat'] = name_id_format settings = OneLogin_Saml2_Settings(settings_info) logout_request = OneLogin_Saml2_Logout_Request(settings, name_id=name_id) logout_request_xml = OneLogin_Saml2_Utils.decode_base64_and_inflate( logout_request.get_request()) name_id_data = OneLogin_Saml2_Logout_Request.get_nameid_data( logout_request_xml) expected_name_id_data = {'Value': name_id} self.assertEqual(expected_name_id_data, name_id_data)
def logout(self, return_to=None, name_id=None, session_index=None, nq=None): """ Initiates the SLO process. :param return_to: Optional argument. The target URL the user should be redirected to after logout. :type return_to: string :param name_id: The NameID that will be set in the LogoutRequest. :type name_id: string :param session_index: SessionIndex that identifies the session of the user. :type session_index: string :param nq: IDP Name Qualifier :type: string :returns: Redirection url """ slo_url = self.get_slo_url() if slo_url is None: raise OneLogin_Saml2_Error( 'The IdP does not support Single Log Out', OneLogin_Saml2_Error.SAML_SINGLE_LOGOUT_NOT_SUPPORTED) if name_id is None and self.__nameid is not None: name_id = self.__nameid logout_request = OneLogin_Saml2_Logout_Request( self.__settings, name_id=name_id, session_index=session_index, nq=nq) self.__last_request_id = logout_request.id saml_request = logout_request.get_request() parameters = {'SAMLRequest': logout_request.get_request()} if return_to is not None: parameters['RelayState'] = return_to else: parameters[ 'RelayState'] = OneLogin_Saml2_Utils.get_self_url_no_query( self.__request_data) security = self.__settings.get_security_data() if security.get('logoutRequestSigned', False): parameters['SigAlg'] = security['signatureAlgorithm'] parameters['Signature'] = self.build_request_signature( saml_request, parameters['RelayState'], security['signatureAlgorithm']) return self.redirect_to(slo_url, parameters)
def testGetXML(self): """ Tests that we can get the logout request XML directly without going through intermediate steps """ request = self.file_contents(join(self.data_path, 'logout_requests', 'logout_request.xml')) settings = OneLogin_Saml2_Settings(self.loadSettingsJSON()) logout_request_generated = OneLogin_Saml2_Logout_Request(settings) expectedFragment = ( 'Destination="http://idp.example.com/SingleLogoutService.php">\n' ' <saml:Issuer>http://stuff.com/endpoints/metadata.php</saml:Issuer>\n' ' <saml:NameID SPNameQualifier="http://stuff.com/endpoints/metadata.php" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">http://idp.example.com/</saml:NameID>\n' ' \n</samlp:LogoutRequest>' ) self.assertIn(expectedFragment, logout_request_generated.get_xml()) logout_request_processed = OneLogin_Saml2_Logout_Request(settings, OneLogin_Saml2_Utils.b64encode(request)) self.assertEqual(request, logout_request_processed.get_xml())
def testGetNameIdData(self): """ Tests the get_nameid_data method of the OneLogin_Saml2_LogoutRequest """ expected_name_id_data = { 'Value': 'ONELOGIN_1e442c129e1f822c8096086a1103c5ee2c7cae1c', 'Format': 'urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified', 'SPNameQualifier': 'http://idp.example.com/' } request = self.file_contents(join(self.data_path, 'logout_requests', 'logout_request.xml')) name_id_data = OneLogin_Saml2_Logout_Request.get_nameid_data(request) self.assertEqual(expected_name_id_data, name_id_data) dom = parseString(request) name_id_data_2 = OneLogin_Saml2_Logout_Request.get_nameid_data(dom.toxml()) self.assertEqual(expected_name_id_data, name_id_data_2) request_2 = self.file_contents(join(self.data_path, 'logout_requests', 'logout_request_encrypted_nameid.xml')) with self.assertRaises(Exception) as context: OneLogin_Saml2_Logout_Request.get_nameid(request_2) exception = context.exception self.assertIn("Key is required in order to decrypt the NameID", str(exception)) settings = OneLogin_Saml2_Settings(self.loadSettingsJSON()) key = settings.get_sp_key() name_id_data_4 = OneLogin_Saml2_Logout_Request.get_nameid_data(request_2, key) expected_name_id_data = { 'Value': 'ONELOGIN_9c86c4542ab9d6fce07f2f7fd335287b9b3cdf69', 'Format': 'urn:oasis:names:tc:SAML:2.0:nameid-format:emailAddress', 'SPNameQualifier': 'https://pitbulk.no-ip.org/newonelogin/demo1/metadata.php' } self.assertEqual(expected_name_id_data, name_id_data_4) dom_2 = parseString(request_2) encrypted_id_nodes = dom_2.getElementsByTagName('saml:EncryptedID') encrypted_data = encrypted_id_nodes[0].firstChild.nextSibling encrypted_id_nodes[0].removeChild(encrypted_data) with self.assertRaises(Exception) as context: OneLogin_Saml2_Logout_Request.get_nameid(dom_2.toxml(), key) exception = context.exception self.assertIn("Not NameID found in the Logout Request", str(exception)) inv_request = self.file_contents(join(self.data_path, 'logout_requests', 'invalids', 'no_nameId.xml')) with self.assertRaises(Exception) as context: OneLogin_Saml2_Logout_Request.get_nameid(inv_request) exception = context.exception self.assertIn("Not NameID found in the Logout Request", str(exception))
def testGetNameId(self): """ Tests the get_nameid of the OneLogin_Saml2_LogoutRequest """ request = self.file_contents(join(self.data_path, 'logout_requests', 'logout_request.xml')) name_id = OneLogin_Saml2_Logout_Request.get_nameid(request) self.assertEqual(name_id, 'ONELOGIN_1e442c129e1f822c8096086a1103c5ee2c7cae1c') request_2 = self.file_contents(join(self.data_path, 'logout_requests', 'logout_request_encrypted_nameid.xml')) try: OneLogin_Saml2_Logout_Request.get_nameid(request_2) self.assertTrue(False) except Exception as e: self.assertIn('Key is required in order to decrypt the NameID', e.message) settings = OneLogin_Saml2_Settings(self.loadSettingsJSON()) key = settings.get_sp_key() name_id_3 = OneLogin_Saml2_Logout_Request.get_nameid(request_2, key) self.assertEqual('ONELOGIN_9c86c4542ab9d6fce07f2f7fd335287b9b3cdf69', name_id_3)
def testIsInvalidXML(self): """ Tests the is_valid method of the OneLogin_Saml2_LogoutRequest Case Invalid XML """ request = b64encode('<xml>invalid</xml>') request_data = { 'http_host': 'example.com', 'script_name': 'index.html', } settings = OneLogin_Saml2_Settings(self.loadSettingsJSON()) logout_request = OneLogin_Saml2_Logout_Request(settings, request) self.assertTrue(logout_request.is_valid(request_data)) settings.set_strict(True) logout_request2 = OneLogin_Saml2_Logout_Request(settings, request) self.assertFalse(logout_request2.is_valid(request_data))
def testIsInvalidIssuer(self): """ Tests the is_valid method of the OneLogin_Saml2_LogoutRequest Case Invalid Issuer """ request = self.file_contents(join(self.data_path, 'logout_requests', 'invalids', 'invalid_issuer.xml')) request_data = { 'http_host': 'example.com', 'script_name': 'index.html' } current_url = OneLogin_Saml2_Utils.get_self_url_no_query(request_data) request = request.replace('http://stuff.com/endpoints/endpoints/sls.php', current_url) settings = OneLogin_Saml2_Settings(self.loadSettingsJSON()) logout_request = OneLogin_Saml2_Logout_Request(settings, b64encode(request)) self.assertTrue(logout_request.is_valid(request_data)) settings.set_strict(True) logout_request2 = OneLogin_Saml2_Logout_Request(settings, b64encode(request)) self.assertFalse(logout_request2.is_valid(request_data)) self.assertIn('Invalid issuer in the Logout Request', logout_request2.get_error())
def process_slo(self, keep_local_session=False, request_id=None, delete_session_cb=None): """ Process the SAML Logout Response / Logout Request sent by the IdP. :param keep_local_session: When false will destroy the local session, otherwise will destroy it :type keep_local_session: bool :param request_id: The ID of the LogoutRequest sent by this SP to the IdP :type request_id: string :returns: Redirection url """ self.__errors = [] if 'get_data' in self.__request_data and 'SAMLResponse' in self.__request_data['get_data']: logout_response = OneLogin_Saml2_Logout_Response(self.__settings, self.__request_data['get_data']['SAMLResponse']) if not logout_response.is_valid(self.__request_data, request_id): self.__errors.append('invalid_logout_response') self.__error_reason = logout_response.get_error() elif logout_response.get_status() != OneLogin_Saml2_Constants.STATUS_SUCCESS: self.__errors.append('logout_not_success') elif not keep_local_session: OneLogin_Saml2_Utils.delete_local_session(delete_session_cb) elif 'get_data' in self.__request_data and 'SAMLRequest' in self.__request_data['get_data']: logout_request = OneLogin_Saml2_Logout_Request(self.__settings, self.__request_data['get_data']['SAMLRequest']) if not logout_request.is_valid(self.__request_data): self.__errors.append('invalid_logout_request') self.__error_reason = logout_request.get_error() else: if not keep_local_session: OneLogin_Saml2_Utils.delete_local_session(delete_session_cb) in_response_to = logout_request.id response_builder = OneLogin_Saml2_Logout_Response(self.__settings) response_builder.build(in_response_to) logout_response = response_builder.get_response() parameters = {'SAMLResponse': logout_response} if 'RelayState' in self.__request_data['get_data']: parameters['RelayState'] = self.__request_data['get_data']['RelayState'] security = self.__settings.get_security_data() if 'logoutResponseSigned' in security and security['logoutResponseSigned']: parameters['SigAlg'] = security['signatureAlgorithm'] parameters['Signature'] = self.build_response_signature(logout_response, parameters.get('RelayState', None), security['signatureAlgorithm']) return self.redirect_to(self.get_slo_url(), parameters) else: self.__errors.append('invalid_binding') raise OneLogin_Saml2_Error( 'SAML LogoutRequest/LogoutResponse not found. Only supported HTTP_REDIRECT Binding', OneLogin_Saml2_Error.SAML_LOGOUTMESSAGE_NOT_FOUND )
def testIsInvalidNotOnOrAfter(self): """ Tests the is_valid method of the OneLogin_Saml2_LogoutRequest Case Invalid NotOnOrAfter """ request_data = { 'http_host': 'example.com', 'script_name': 'index.html' } request = self.file_contents(join(self.data_path, 'logout_requests', 'invalids', 'not_after_failed.xml')) current_url = OneLogin_Saml2_Utils.get_self_url_no_query(request_data) request = request.replace('http://stuff.com/endpoints/endpoints/sls.php', current_url) settings = OneLogin_Saml2_Settings(self.loadSettingsJSON()) self.assertTrue(OneLogin_Saml2_Logout_Request.is_valid(settings, request, request_data)) settings.set_strict(True) try: valid = OneLogin_Saml2_Logout_Request.is_valid(settings, request, request_data) self.assertFalse(valid) except Exception as e: self.assertIn('Timing issues (please check your clock settings)', e.message)
def testGetIDFromDeflatedSAMLLogoutRequest(self): """ Tests the get_id method of the OneLogin_Saml2_LogoutRequest """ deflated_logout_request = self.file_contents( join(self.data_path, 'logout_requests', 'logout_request_deflated.xml.base64')) logout_request = OneLogin_Saml2_Utils.decode_base64_and_inflate( deflated_logout_request) id = OneLogin_Saml2_Logout_Request.get_id(logout_request) self.assertEqual('ONELOGIN_21584ccdfaca36a145ae990442dcd96bfe60151e', id)
def testIsInvalidNotOnOrAfter(self): """ Tests the is_valid method of the OneLogin_Saml2_LogoutRequest Case Invalid NotOnOrAfter """ request_data = { 'http_host': 'example.com', 'script_name': 'index.html' } request = self.file_contents(join(self.data_path, 'logout_requests', 'invalids', 'not_after_failed.xml')) current_url = OneLogin_Saml2_Utils.get_self_url_no_query(request_data) request = request.replace('http://stuff.com/endpoints/endpoints/sls.php', current_url) settings = OneLogin_Saml2_Settings(self.loadSettingsJSON()) logout_request = OneLogin_Saml2_Logout_Request(settings, b64encode(request)) self.assertTrue(logout_request.is_valid(request_data)) settings.set_strict(True) logout_request2 = OneLogin_Saml2_Logout_Request(settings, b64encode(request)) self.assertFalse(logout_request2.is_valid(request_data)) self.assertIn('Could not validate timestamp: expired. Check system clock.', logout_request2.get_error())
def testIsInValidWithCapitalization(self): """ Tests the is_valid method of the OneLogin_Saml2_LogoutRequest """ request_data = { 'http_host': 'example.com', 'script_name': 'INdex.html' } request = self.file_contents( join(self.data_path, 'logout_requests', 'logout_request.xml')) settings = OneLogin_Saml2_Settings(self.loadSettingsJSON()) logout_request = OneLogin_Saml2_Logout_Request(settings, b64encode(request)) self.assertTrue(logout_request.is_valid(request_data)) settings.set_strict(True) logout_request2 = OneLogin_Saml2_Logout_Request( settings, b64encode(request)) self.assertFalse(logout_request2.is_valid(request_data)) settings.set_strict(False) dom = parseString(request) logout_request3 = OneLogin_Saml2_Logout_Request( settings, b64encode(dom.toxml())) self.assertTrue(logout_request3.is_valid(request_data)) settings.set_strict(True) logout_request4 = OneLogin_Saml2_Logout_Request( settings, b64encode(dom.toxml())) self.assertFalse(logout_request4.is_valid(request_data)) current_url = OneLogin_Saml2_Utils.get_self_url_no_query(request_data) request = request.replace( 'http://stuff.com/endpoints/endpoints/sls.php', current_url.lower()) logout_request5 = OneLogin_Saml2_Logout_Request( settings, b64encode(request)) self.assertFalse(logout_request5.is_valid(request_data))
def testLogoutNameIDandSessionIndex(self): """ Tests the logout method of the OneLogin_Saml2_Auth class Case nameID and sessionIndex as parameters. """ settings_info = self.loadSettingsJSON() request_data = self.get_request() auth = OneLogin_Saml2_Auth(request_data, old_settings=settings_info) name_id = 'name_id_example' session_index = 'session_index_example' target_url = auth.logout(name_id=name_id, session_index=session_index) parsed_query = parse_qs(urlparse(target_url)[4]) slo_url = settings_info['idp']['singleLogoutService']['url'] self.assertIn(slo_url, target_url) self.assertIn('SAMLRequest', parsed_query) logout_request = OneLogin_Saml2_Utils.decode_base64_and_inflate(parsed_query['SAMLRequest'][0]) name_id_from_request = OneLogin_Saml2_Logout_Request.get_nameid(logout_request) sessions_index_in_request = OneLogin_Saml2_Logout_Request.get_session_indexes(logout_request) self.assertIn(session_index, sessions_index_in_request) self.assertEqual(name_id, name_id_from_request)
def testGetSessionIndexes(self): """ Tests the get_session_indexes of the OneLogin_Saml2_LogoutRequest """ request = self.file_contents( join(self.data_path, 'logout_requests', 'logout_request.xml')) session_indexes = OneLogin_Saml2_Logout_Request.get_session_indexes( request) self.assertEqual(len(session_indexes), 0) dom = parseString(request) session_indexes_2 = OneLogin_Saml2_Logout_Request.get_session_indexes( dom) self.assertEqual(len(session_indexes_2), 0) request_2 = self.file_contents( join(self.data_path, 'logout_requests', 'logout_request_with_sessionindex.xml')) session_indexes_3 = OneLogin_Saml2_Logout_Request.get_session_indexes( request_2) self.assertEqual(['_ac72a76526cb6ca19f8438e73879a0e6c8ae5131'], session_indexes_3)
def testIsValidRaisesExceptionWhenRaisesArgumentIsTrue(self): request = OneLogin_Saml2_Utils.deflate_and_base64_encode('<xml>invalid</xml>') request_data = { 'http_host': 'example.com', 'script_name': 'index.html' } settings = OneLogin_Saml2_Settings(self.loadSettingsJSON()) settings.set_strict(True) logout_request = OneLogin_Saml2_Logout_Request(settings, request) self.assertFalse(logout_request.is_valid(request_data)) with self.assertRaisesRegexp(OneLogin_Saml2_ValidationError, "Invalid SAML Logout Request. Not match the saml-schema-protocol-2.0.xsd"): logout_request.is_valid(request_data, raise_exceptions=True)
def testIsValidRaisesExceptionWhenRaisesArgumentIsTrue(self): request = OneLogin_Saml2_Utils.b64encode('<xml>invalid</xml>') request_data = { 'http_host': 'example.com', 'script_name': 'index.html', } settings = OneLogin_Saml2_Settings(self.loadSettingsJSON()) settings.set_strict(True) logout_request = OneLogin_Saml2_Logout_Request(settings, request) self.assertFalse(logout_request.is_valid(request_data)) with self.assertRaises(Exception): logout_request.is_valid(request_data, raise_exceptions=True)
def testCreateDeflatedSAMLLogoutRequestURLParameter(self): """ Tests the OneLogin_Saml2_LogoutRequest Constructor. The creation of a deflated SAML Logout Request """ settings = OneLogin_Saml2_Settings(self.loadSettingsJSON()) logout_request = OneLogin_Saml2_Logout_Request(settings) parameters = {'SAMLRequest': logout_request.get_request()} logout_url = OneLogin_Saml2_Utils.redirect('http://idp.example.com/SingleLogoutService.php', parameters, True) self.assertRegexpMatches(logout_url, '^http://idp\.example\.com\/SingleLogoutService\.php\?SAMLRequest=') url_parts = urlparse(logout_url) exploded = parse_qs(url_parts.query) payload = exploded['SAMLRequest'][0] inflated = OneLogin_Saml2_Utils.decode_base64_and_inflate(payload) self.assertRegexpMatches(inflated, '^<samlp:LogoutRequest')
def testConstructorWithoutNameIdFormat(self): """ Tests the OneLogin_Saml2_LogoutRequest Constructor. Case: Checks that NameIDFormat is not added """ settings_info = self.loadSettingsJSON() name_id = 'ONELOGIN_1e442c129e1f822c8096086a1103c5ee2c7cae1c' name_id_format = 'urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified' settings_info['sp']['NameIDFormat'] = name_id_format settings = OneLogin_Saml2_Settings(settings_info) logout_request = OneLogin_Saml2_Logout_Request(settings, name_id=name_id) logout_request_xml = OneLogin_Saml2_Utils.decode_base64_and_inflate(logout_request.get_request()) name_id_data = OneLogin_Saml2_Logout_Request.get_nameid_data(logout_request_xml) expected_name_id_data = { 'Value': name_id } self.assertEqual(expected_name_id_data, name_id_data)
def testConstructorWithNameIdFormatOnSettings(self): """ Tests the OneLogin_Saml2_LogoutRequest Constructor. Case: Defines NameIDFormat from settings """ settings_info = self.loadSettingsJSON() name_id = 'ONELOGIN_1e442c129e1f822c8096086a1103c5ee2c7cae1c' name_id_format = 'urn:oasis:names:tc:SAML:2.0:nameid-format:transient' settings_info['sp']['NameIDFormat'] = name_id_format settings = OneLogin_Saml2_Settings(settings_info) logout_request = OneLogin_Saml2_Logout_Request(settings, name_id=name_id) logout_request_xml = OneLogin_Saml2_Utils.decode_base64_and_inflate(logout_request.get_request()) name_id_data = OneLogin_Saml2_Logout_Request.get_nameid_data(logout_request_xml) expected_name_id_data = { 'Value': name_id, 'Format': name_id_format } self.assertEqual(expected_name_id_data, name_id_data)
def testConstructor(self): """ Tests the OneLogin_Saml2_LogoutRequest Constructor. """ settings_info = self.loadSettingsJSON() settings_info['security']['nameIdEncrypted'] = True settings = OneLogin_Saml2_Settings(settings_info) logout_request = OneLogin_Saml2_Logout_Request(settings) parameters = {'SAMLRequest': logout_request.get_request()} logout_url = OneLogin_Saml2_Utils.redirect('http://idp.example.com/SingleLogoutService.php', parameters, True) self.assertRegex(logout_url, '^http://idp\.example\.com\/SingleLogoutService\.php\?SAMLRequest=') url_parts = urlparse(logout_url) exploded = parse_qs(url_parts.query) payload = exploded['SAMLRequest'][0] inflated = compat.to_string(OneLogin_Saml2_Utils.decode_base64_and_inflate(payload)) self.assertRegex(inflated, '^<samlp:LogoutRequest')
def testIsValidSignUsingX509certMulti(self): """ Tests the is_valid method of the OneLogin_Saml2_LogoutRequest """ request_data = { 'http_host': 'example.com', 'script_name': 'index.html', 'get_data': { 'SAMLRequest': 'fZJNa+MwEIb/itHdiTz6sC0SQyEsBPoB27KHXoIsj7cGW3IlGfLzV7G7kN1DL2KYmeedmRcdgp7GWT26326JP/FzwRCz6zTaoNbKkSzeKqfDEJTVEwYVjXp9eHpUsKNq9i4640Zyh3xP6BDQx8FZkp1PR3KpqexAl72QmpUCS8SW01IiZz2TVVGD4X1VQYlAsl/oQyKPJAklPIQFzzZEbWNK0YLnlOVA3wqpQCoB7yQ7pWsGq+NKfcQ4q/0+xKXvd8ZNe7Td7AYbw10UxrCbP2aSPbv4Yl/8Qx/R3+SB5bTOoXiDQvFNvjnc7lXrIr75kh+6eYdXPc0jrkMO+/umjXhOtpxP2Q/nJx2/9+uWGbq8X1tV9NqGAW0kzaVvoe1AAJeCSWqYaUVRM2SilKKuqDTpFSlszdcK29RthVm9YriZebYdXpsLdhVAB7VJzif3haYMqqTVcl0JMBR4y+s2zak3sf/4v8l/vlHzBw==', 'RelayState': '_1037fbc88ec82ce8e770b2bed1119747bb812a07e6', 'SigAlg': 'http://www.w3.org/2000/09/xmldsig#rsa-sha1', 'Signature': 'Ouxo9BV6zmq4yrgamT9EbSKy/UmvSxGS8z26lIMgKOEP4LFR/N23RftdANmo4HafrzSfA0YTXwhKDqbOByS0j+Ql8OdQOes7vGioSjo5qq/Bi+5i6jXwQfphnfcHAQiJL4gYVIifkhhHRWpvYeiysF1Y9J02me0izwazFmoRXr4=' } } settings_info = self.loadSettingsJSON('settings8.json') settings_info['strict'] = False settings = OneLogin_Saml2_Settings(settings_info) logout_request = OneLogin_Saml2_Logout_Request(settings, request_data['get_data']['SAMLRequest']) self.assertTrue(logout_request.is_valid(request_data))
def testConstructorEncryptIdUsingX509certMulti(self): """ Tests the OneLogin_Saml2_LogoutRequest Constructor. Case: Able to generate encryptedID with MultiCert """ settings_info = self.loadSettingsJSON('settings8.json') settings_info['security']['nameIdEncrypted'] = True settings = OneLogin_Saml2_Settings(settings_info) logout_request = OneLogin_Saml2_Logout_Request(settings) parameters = {'SAMLRequest': logout_request.get_request()} logout_url = OneLogin_Saml2_Utils.redirect('http://idp.example.com/SingleLogoutService.php', parameters, True) self.assertRegexpMatches(logout_url, r'^http://idp\.example\.com\/SingleLogoutService\.php\?SAMLRequest=') url_parts = urlparse(logout_url) exploded = parse_qs(url_parts.query) payload = exploded['SAMLRequest'][0] inflated = OneLogin_Saml2_Utils.decode_base64_and_inflate(payload) self.assertRegexpMatches(inflated, '^<samlp:LogoutRequest') self.assertRegexpMatches(inflated, '<saml:EncryptedID>')
def testLogoutNameID(self): """ Tests the logout method of the OneLogin_Saml2_Auth class Case nameID loaded after process SAML Response """ request_data = self.get_request() message = self.file_contents(join(self.data_path, "responses", "valid_response.xml.base64")) del request_data["get_data"] request_data["post_data"] = {"SAMLResponse": message} auth = OneLogin_Saml2_Auth(request_data, old_settings=self.loadSettingsJSON()) auth.process_response() name_id_from_response = auth.get_nameid() target_url = auth.logout() parsed_query = parse_qs(urlparse(target_url)[4]) self.assertIn("SAMLRequest", parsed_query) logout_request = OneLogin_Saml2_Utils.decode_base64_and_inflate(parsed_query["SAMLRequest"][0]) name_id_from_request = OneLogin_Saml2_Logout_Request.get_nameid(logout_request) self.assertEqual(name_id_from_response, name_id_from_request)
def process_slo(self, keep_local_session=False, request_id=None, delete_session_cb=None): """ Process the SAML Logout Response / Logout Request sent by the IdP. :param keep_local_session: When false will destroy the local session, otherwise will destroy it :type keep_local_session: bool :param request_id: The ID of the LogoutRequest sent by this SP to the IdP :type request_id: string :returns: Redirection url """ self.__errors = [] self.__error_reason = None post_data = 'post_data' in self._SpidSaml2Auth__request_data and self._SpidSaml2Auth__request_data[ 'post_data'] get_data = 'get_data' in self._SpidSaml2Auth__request_data and self._SpidSaml2Auth__request_data[ 'get_data'] method = 'redirect' if post_data: get_data = post_data method = 'post' elif get_data and 'SAMLResponse' in get_data: logout_response = SpidSaml2LogoutResponse(self.__settings, get_data['SAMLResponse'], method) self._OneLogin_Saml2_Auth__last_response = logout_response.get_xml( ) if not self.validate_response_signature(get_data): self.__errors.append('invalid_logout_response_signature') self.__errors.append( 'Signature validation failed. Logout Response rejected') if not logout_response.is_valid(self.__request_data, request_id): self.__errors.append('invalid_logout_response') self.__error_reason = logout_response.get_error() elif logout_response.get_status( ) != OneLogin_Saml2_Constants.STATUS_SUCCESS: self.__errors.append('logout_not_success') else: self._OneLogin_Saml2_Auth__last_message_id = logout_response.id if not keep_local_session: OneLogin_Saml2_Utils.delete_local_session( delete_session_cb) elif get_data and 'SAMLRequest' in get_data: logout_request = OneLogin_Saml2_Logout_Request( self.__settings, get_data['SAMLRequest']) self._OneLogin_Saml2_Auth__last_request = logout_request.get_xml() if not self.validate_request_signature(get_data): self.__errors.append("invalid_logout_request_signature") self.__errors.append( 'Signature validation failed. Logout Request rejected') elif not logout_request.is_valid(self.__request_data): self.__errors.append('invalid_logout_request') self.__error_reason = logout_request.get_error() else: if not keep_local_session: OneLogin_Saml2_Utils.delete_local_session( delete_session_cb) in_response_to = logout_request.id self._OneLogin_Saml2_Auth__last_message_id = logout_request.id response_builder = OneLogin_Saml2_Logout_Response( self.__settings, method) response_builder.build(in_response_to) self._OneLogin_Saml2_Auth__last_response = response_builder.get_xml( ) logout_response = response_builder.get_response() parameters = {'SAMLResponse': logout_response} if 'RelayState' in self._OneLogin_Saml2_Auth__request_data[ 'get_data']: parameters['RelayState'] = self.__request_data['get_data'][ 'RelayState'] security = self._OneLogin_Saml2_Auth__settings.get_security_data( ) if security['logoutResponseSigned']: self.add_response_signature(parameters, security['signatureAlgorithm']) return self.redirect_to(self.get_slo_url(), parameters) else: self.__errors.append('invalid_binding') raise OneLogin_Saml2_Error( 'SAML LogoutRequest/LogoutResponse not found. Only supported HTTP_REDIRECT Binding', OneLogin_Saml2_Error.SAML_LOGOUTMESSAGE_NOT_FOUND)
def testGetNameIdData(self): """ Tests the get_nameid_data method of the OneLogin_Saml2_LogoutRequest """ expected_name_id_data = { 'Value': 'ONELOGIN_1e442c129e1f822c8096086a1103c5ee2c7cae1c', 'Format': 'urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified', 'SPNameQualifier': 'http://idp.example.com/' } request = self.file_contents(join(self.data_path, 'logout_requests', 'logout_request.xml')) name_id_data = OneLogin_Saml2_Logout_Request.get_nameid_data(request) self.assertEqual(expected_name_id_data, name_id_data) dom = parseString(request) name_id_data_2 = OneLogin_Saml2_Logout_Request.get_nameid_data(dom) self.assertEqual(expected_name_id_data, name_id_data_2) request_2 = self.file_contents(join(self.data_path, 'logout_requests', 'logout_request_encrypted_nameid.xml')) with self.assertRaisesRegexp(OneLogin_Saml2_Error, 'Key is required in order to decrypt the NameID'): OneLogin_Saml2_Logout_Request.get_nameid_data(request_2) settings = OneLogin_Saml2_Settings(self.loadSettingsJSON()) key = settings.get_sp_key() name_id_data_4 = OneLogin_Saml2_Logout_Request.get_nameid_data(request_2, key) expected_name_id_data = { 'Value': 'ONELOGIN_9c86c4542ab9d6fce07f2f7fd335287b9b3cdf69', 'Format': 'urn:oasis:names:tc:SAML:2.0:nameid-format:emailAddress', 'SPNameQualifier': 'https://pitbulk.no-ip.org/newonelogin/demo1/metadata.php' } self.assertEqual(expected_name_id_data, name_id_data_4) dom_2 = parseString(request_2) encrypted_id_nodes = dom_2.getElementsByTagName('saml:EncryptedID') encrypted_data = encrypted_id_nodes[0].firstChild.nextSibling encrypted_id_nodes[0].removeChild(encrypted_data) with self.assertRaisesRegexp(OneLogin_Saml2_ValidationError, 'NameID not found in the Logout Request'): OneLogin_Saml2_Logout_Request.get_nameid_data(dom_2.toxml(), key) idp_data = settings.get_idp_data() sp_data = settings.get_sp_data() expected_name_id_data = { 'Format': 'urn:oasis:names:tc:SAML:2.0:nameid-format:emailAddress', 'NameQualifier': idp_data['entityId'], 'SPNameQualifier': sp_data['entityId'], 'Value': 'ONELOGIN_9c86c4542ab9d6fce07f2f7fd335287b9b3cdf69' } inv_request = self.file_contents(join(self.data_path, 'logout_requests', 'invalids', 'no_nameId.xml')) with self.assertRaisesRegexp(OneLogin_Saml2_ValidationError, 'NameID not found in the Logout Request'): OneLogin_Saml2_Logout_Request.get_nameid_data(inv_request) logout_request = OneLogin_Saml2_Logout_Request(settings, None, expected_name_id_data['Value'], None, idp_data['entityId'], expected_name_id_data['Format']) dom = parseString(logout_request.get_xml()) name_id_data_3 = OneLogin_Saml2_Logout_Request.get_nameid_data(dom) self.assertEqual(expected_name_id_data, name_id_data_3) expected_name_id_data = { 'Format': 'urn:oasis:names:tc:SAML:2.0:nameid-format:emailAddress', 'Value': 'ONELOGIN_9c86c4542ab9d6fce07f2f7fd335287b9b3cdf69' } logout_request = OneLogin_Saml2_Logout_Request(settings, None, expected_name_id_data['Value'], None, None, expected_name_id_data['Format']) dom = parseString(logout_request.get_xml()) name_id_data_4 = OneLogin_Saml2_Logout_Request.get_nameid_data(dom) self.assertEqual(expected_name_id_data, name_id_data_4) expected_name_id_data = { 'Format': 'urn:oasis:names:tc:SAML:2.0:nameid-format:entity', 'Value': 'http://idp.example.com/' } logout_request = OneLogin_Saml2_Logout_Request(settings) dom = parseString(logout_request.get_xml()) name_id_data_5 = OneLogin_Saml2_Logout_Request.get_nameid_data(dom) self.assertEqual(expected_name_id_data, name_id_data_5)
def testIsValidSign(self): """ Tests the is_valid method of the OneLogin_Saml2_LogoutRequest """ request_data = { 'http_host': 'example.com', 'script_name': 'index.html', 'get_data': { 'SAMLRequest': 'lVLBitswEP0Vo7tjeWzJtki8LIRCYLvbNksPewmyPc6K2pJqyXQ/v1LSQlroQi/DMJr33rwZbZ2cJysezNms/gt+X9H55G2etBOXlx1ZFy2MdMoJLWd0wvfieP/xQcCGCrsYb3ozkRvI+wjpHC5eGU2Sw35HTg3lA8hqZFwWFcMKsStpxbEsxoLXeQN9OdY1VAgk+YqLC8gdCUQB7tyKB+281D6UaF6mtEiBPudcABcMXkiyD26Ulv6CevXeOpFlVvlunb5ttEmV3ZjlnGn8YTRO5qx0NuBs8kzpAd829tXeucmR5NH4J/203I8el6gFRUqbFPJnyEV51Wq30by4TLW0/9ZyarYTxt4sBsjUYLMZvRykl1Fxm90SXVkfwx4P++T4KSafVzmpUcVJ/sfSrQZJPphllv79W8WKGtLx0ir8IrVTqD1pT2MH3QAMSs4KTvui71jeFFiwirOmprwPkYW063+5uRq4urHiiC4e8hCX3J5wqAEGaPpw9XB5JmkBdeDqSlkz6CmUXdl0Qae5kv2F/1384wu3PwE=', 'RelayState': '_1037fbc88ec82ce8e770b2bed1119747bb812a07e6', 'SigAlg': 'http://www.w3.org/2000/09/xmldsig#rsa-sha1', 'Signature': 'XCwCyI5cs7WhiJlB5ktSlWxSBxv+6q2xT3c8L7dLV6NQG9LHWhN7gf8qNsahSXfCzA0Ey9dp5BQ0EdRvAk2DIzKmJY6e3hvAIEp1zglHNjzkgcQmZCcrkK9Czi2Y1WkjOwR/WgUTUWsGJAVqVvlRZuS3zk3nxMrLH6f7toyvuJc=' } } settings = OneLogin_Saml2_Settings(self.loadSettingsJSON()) current_url = OneLogin_Saml2_Utils.get_self_url_no_query(request_data) request = OneLogin_Saml2_Utils.decode_base64_and_inflate( request_data['get_data']['SAMLRequest']) settings.set_strict(False) logout_request = OneLogin_Saml2_Logout_Request(settings, b64encode(request)) self.assertTrue(logout_request.is_valid(request_data)) relayState = request_data['get_data']['RelayState'] del request_data['get_data']['RelayState'] self.assertFalse(logout_request.is_valid(request_data)) request_data['get_data']['RelayState'] = relayState settings.set_strict(True) logout_request2 = OneLogin_Saml2_Logout_Request( settings, b64encode(request)) self.assertFalse(logout_request2.is_valid(request_data)) self.assertIn('The LogoutRequest was received at', logout_request2.get_error()) settings.set_strict(False) old_signature = request_data['get_data']['Signature'] request_data['get_data'][ 'Signature'] = 'vfWbbc47PkP3ejx4bjKsRX7lo9Ml1WRoE5J5owF/0mnyKHfSY6XbhO1wwjBV5vWdrUVX+xp6slHyAf4YoAsXFS0qhan6txDiZY4Oec6yE+l10iZbzvie06I4GPak4QrQ4gAyXOSzwCrRmJu4gnpeUxZ6IqKtdrKfAYRAcVf3333=' logout_request3 = OneLogin_Saml2_Logout_Request( settings, b64encode(request)) self.assertFalse(logout_request3.is_valid(request_data)) self.assertIn('Signature validation failed. Logout Request rejected', logout_request3.get_error()) request_data['get_data']['Signature'] = old_signature old_signature_algorithm = request_data['get_data']['SigAlg'] del request_data['get_data']['SigAlg'] self.assertTrue(logout_request3.is_valid(request_data)) request_data['get_data'][ 'RelayState'] = 'http://example.com/relaystate' self.assertFalse(logout_request3.is_valid(request_data)) self.assertIn('Signature validation failed. Logout Request rejected', logout_request3.get_error()) settings.set_strict(True) request_2 = request.replace( 'https://pitbulk.no-ip.org/newonelogin/demo1/index.php?sls', current_url) request_2 = request_2.replace( 'https://pitbulk.no-ip.org/simplesaml/saml2/idp/metadata.php', 'http://idp.example.com/') request_data['get_data'][ 'SAMLRequest'] = OneLogin_Saml2_Utils.deflate_and_base64_encode( request_2) logout_request4 = OneLogin_Saml2_Logout_Request( settings, b64encode(request_2)) self.assertFalse(logout_request4.is_valid(request_data)) self.assertIn('Signature validation failed. Logout Request rejected', logout_request4.get_error()) settings.set_strict(False) logout_request5 = OneLogin_Saml2_Logout_Request( settings, b64encode(request_2)) self.assertFalse(logout_request5.is_valid(request_data)) self.assertIn('Signature validation failed. Logout Request rejected', logout_request5.get_error()) request_data['get_data'][ 'SigAlg'] = 'http://www.w3.org/2000/09/xmldsig#dsa-sha1' self.assertFalse(logout_request5.is_valid(request_data)) self.assertIn('Signature validation failed. Logout Request rejected', logout_request5.get_error()) settings_info = self.loadSettingsJSON() settings_info['strict'] = True settings_info['security']['wantMessagesSigned'] = True settings = OneLogin_Saml2_Settings(settings_info) request_data['get_data']['SigAlg'] = old_signature_algorithm old_signature = request_data['get_data']['Signature'] del request_data['get_data']['Signature'] logout_request6 = OneLogin_Saml2_Logout_Request( settings, b64encode(request_2)) self.assertFalse(logout_request6.is_valid(request_data)) self.assertIn( 'The Message of the Logout Request is not signed and the SP require it', logout_request6.get_error()) request_data['get_data']['Signature'] = old_signature settings_info['idp'][ 'certFingerprint'] = 'afe71c28ef740bc87425be13a2263d37971da1f9' del settings_info['idp']['x509cert'] settings_2 = OneLogin_Saml2_Settings(settings_info) logout_request7 = OneLogin_Saml2_Logout_Request( settings_2, b64encode(request_2)) self.assertFalse(logout_request7.is_valid(request_data)) self.assertEqual( 'In order to validate the sign on the Logout Request, the x509cert of the IdP is required', logout_request7.get_error())
def testIsValidSign(self): """ Tests the is_valid method of the OneLogin_Saml2_LogoutRequest """ request_data = { 'http_host': 'example.com', 'script_name': 'index.html', 'SAMLRequest': 'lVLBitswEP0Vo7tjeWzJtki8LIRCYLvbNksPewmyPc6K2pJqyXQ/v1LSQlroQi/DMJr33rwZbZ2cJysezNms/gt+X9H55G2etBOXlx1ZFy2MdMoJLWd0wvfieP/xQcCGCrsYb3ozkRvI+wjpHC5eGU2Sw35HTg3lA8hqZFwWFcMKsStpxbEsxoLXeQN9OdY1VAgk+YqLC8gdCUQB7tyKB+281D6UaF6mtEiBPudcABcMXkiyD26Ulv6CevXeOpFlVvlunb5ttEmV3ZjlnGn8YTRO5qx0NuBs8kzpAd829tXeucmR5NH4J/203I8el6gFRUqbFPJnyEV51Wq30by4TLW0/9ZyarYTxt4sBsjUYLMZvRykl1Fxm90SXVkfwx4P++T4KSafVzmpUcVJ/sfSrQZJPphllv79W8WKGtLx0ir8IrVTqD1pT2MH3QAMSs4KTvui71jeFFiwirOmprwPkYW063+5uRq4urHiiC4e8hCX3J5wqAEGaPpw9XB5JmkBdeDqSlkz6CmUXdl0Qae5kv2F/1384wu3PwE=', 'RelayState': '_1037fbc88ec82ce8e770b2bed1119747bb812a07e6', 'SigAlg': 'http://www.w3.org/2000/09/xmldsig#rsa-sha1', 'Signature': 'XCwCyI5cs7WhiJlB5ktSlWxSBxv+6q2xT3c8L7dLV6NQG9LHWhN7gf8qNsahSXfCzA0Ey9dp5BQ0EdRvAk2DIzKmJY6e3hvAIEp1zglHNjzkgcQmZCcrkK9Czi2Y1WkjOwR/WgUTUWsGJAVqVvlRZuS3zk3nxMrLH6f7toyvuJc=' } settings = OneLogin_Saml2_Settings(self.loadSettingsJSON()) current_url = OneLogin_Saml2_Utils.get_self_url_no_query(request_data) request = OneLogin_Saml2_Utils.decode_base64_and_inflate(request_data['SAMLRequest']) settings.set_strict(False) self.assertTrue(OneLogin_Saml2_Logout_Request.is_valid(settings, request, request_data)) relayState = request_data['RelayState'] del request_data['RelayState'] self.assertFalse(OneLogin_Saml2_Logout_Request.is_valid(settings, request, request_data)) request_data['RelayState'] = relayState settings.set_strict(True) try: valid = OneLogin_Saml2_Logout_Request.is_valid(settings, request, request_data) self.assertFalse(valid) except Exception as e: self.assertIn('The LogoutRequest was received at', e.message) settings.set_strict(False) old_signature = request_data['Signature'] request_data['Signature'] = 'vfWbbc47PkP3ejx4bjKsRX7lo9Ml1WRoE5J5owF/0mnyKHfSY6XbhO1wwjBV5vWdrUVX+xp6slHyAf4YoAsXFS0qhan6txDiZY4Oec6yE+l10iZbzvie06I4GPak4QrQ4gAyXOSzwCrRmJu4gnpeUxZ6IqKtdrKfAYRAcVf3333=' try: valid = OneLogin_Saml2_Logout_Request.is_valid(settings, request, request_data) self.assertFalse(valid) except Exception as e: self.assertIn('Signature validation failed. Logout Request rejected', e.message) request_data['Signature'] = old_signature old_signature_algorithm = request_data['SigAlg'] del request_data['SigAlg'] self.assertTrue(OneLogin_Saml2_Logout_Request.is_valid(settings, request, request_data)) request_data['RelayState'] = 'http://example.com/relaystate' try: valid = OneLogin_Saml2_Logout_Request.is_valid(settings, request, request_data) self.assertFalse(valid) except Exception as e: self.assertIn('Signature validation failed. Logout Request rejected', e.message) settings.set_strict(True) request_2 = request.replace('https://pitbulk.no-ip.org/newonelogin/demo1/index.php?sls', current_url) request_2 = request_2.replace('https://pitbulk.no-ip.org/simplesaml/saml2/idp/metadata.php', 'http://idp.example.com/') request_data['SAMLRequest'] = OneLogin_Saml2_Utils.deflate_and_base64_encode(request_2) try: valid = OneLogin_Saml2_Logout_Request.is_valid(settings, request_2, request_data) self.assertFalse(valid) except Exception as e: self.assertIn('Signature validation failed. Logout Request rejected', e.message) settings.set_strict(False) try: valid = OneLogin_Saml2_Logout_Request.is_valid(settings, request_2, request_data) self.assertFalse(valid) except Exception as e: self.assertIn('Signature validation failed. Logout Request rejected', e.message) request_data['SigAlg'] = 'http://www.w3.org/2000/09/xmldsig#dsa-sha1' try: valid = OneLogin_Saml2_Logout_Request.is_valid(settings, request_2, request_data) self.assertFalse(valid) except Exception as e: self.assertIn('Invalid signAlg in the recieved Logout Request', e.message) settings_info = self.loadSettingsJSON() settings_info['strict'] = True settings_info['security']['wantMessagesSigned'] = True settings = OneLogin_Saml2_Settings(settings_info) request_data['SigAlg'] = old_signature_algorithm old_signature = request_data['Signature'] del request_data['Signature'] try: valid = OneLogin_Saml2_Logout_Request.is_valid(settings, request_2, request_data) self.assertFalse(valid) except Exception as e: self.assertIn('The Message of the Logout Request is not signed and the SP require it', e.message) request_data['Signature'] = old_signature settings_info['idp']['certFingerprint'] = 'afe71c28ef740bc87425be13a2263d37971da1f9' del settings_info['idp']['x509cert'] settings_2 = OneLogin_Saml2_Settings(settings_info) try: valid = OneLogin_Saml2_Logout_Request.is_valid(settings_2, request_2, request_data) self.assertFalse(valid) except Exception as e: self.assertIn('In order to validate the sign on the Logout Request, the x509cert of the IdP is required', e.message)