From 265d019451adac073ca8f470c757a05e9b447867 Mon Sep 17 00:00:00 2001 From: Sixto Martin Date: Thu, 19 Oct 2017 12:10:39 +0200 Subject: [PATCH] Fix issue with LogoutRequest rejected by ADFS due NameID with unspecified format instead no format attribute --- src/onelogin/saml2/logout_request.py | 12 ++-- src/onelogin/saml2/utils.py | 5 +- .../saml2_tests/logout_request_test.py | 57 +++++++++++++++---- tests/src/OneLogin/saml2_tests/utils_test.py | 11 ++++ 4 files changed, 66 insertions(+), 19 deletions(-) diff --git a/src/onelogin/saml2/logout_request.py b/src/onelogin/saml2/logout_request.py index 6e6a1903..2efd8aa8 100644 --- a/src/onelogin/saml2/logout_request.py +++ b/src/onelogin/saml2/logout_request.py @@ -76,15 +76,13 @@ def __init__(self, settings, request=None, name_id=None, session_index=None, nq= cert = idp_data['x509cert'] if name_id is not None: - if name_id_format is not None: - nameIdFormat = name_id_format - else: - nameIdFormat = sp_data['NameIDFormat'] + if not name_id_format and sp_data['NameIDFormat'] != OneLogin_Saml2_Constants.NAMEID_UNSPECIFIED: + name_id_format = sp_data['NameIDFormat'] else: - nameIdFormat = OneLogin_Saml2_Constants.NAMEID_ENTITY + name_id_format = OneLogin_Saml2_Constants.NAMEID_ENTITY spNameQualifier = None - if nameIdFormat == OneLogin_Saml2_Constants.NAMEID_ENTITY: + if name_id_format == OneLogin_Saml2_Constants.NAMEID_ENTITY: name_id = idp_data['entityId'] nq = None elif nq is not None: @@ -94,7 +92,7 @@ def __init__(self, settings, request=None, name_id=None, session_index=None, nq= name_id_obj = OneLogin_Saml2_Utils.generate_name_id( name_id, spNameQualifier, - nameIdFormat, + name_id_format, cert, False, nq diff --git a/src/onelogin/saml2/utils.py b/src/onelogin/saml2/utils.py index 19f1511a..51e5db18 100644 --- a/src/onelogin/saml2/utils.py +++ b/src/onelogin/saml2/utils.py @@ -612,7 +612,7 @@ def format_finger_print(fingerprint): return formated_fingerprint.lower() @staticmethod - def generate_name_id(value, sp_nq, sp_format, cert=None, debug=False, nq=None): + def generate_name_id(value, sp_nq, sp_format=None, cert=None, debug=False, nq=None): """ Generates a nameID. @@ -646,7 +646,8 @@ def generate_name_id(value, sp_nq, sp_format, cert=None, debug=False, nq=None): name_id.setAttribute('SPNameQualifier', sp_nq) if nq is not None: name_id.setAttribute('NameQualifier', nq) - name_id.setAttribute('Format', sp_format) + if sp_format is not None: + name_id.setAttribute('Format', sp_format) name_id.appendChild(doc.createTextNode(value)) name_id_container.appendChild(name_id) diff --git a/tests/src/OneLogin/saml2_tests/logout_request_test.py b/tests/src/OneLogin/saml2_tests/logout_request_test.py index d1eab57e..6d78d1bc 100644 --- a/tests/src/OneLogin/saml2_tests/logout_request_test.py +++ b/tests/src/OneLogin/saml2_tests/logout_request_test.py @@ -55,15 +55,12 @@ def testConstructor(self): inflated = OneLogin_Saml2_Utils.decode_base64_and_inflate(payload) self.assertRegexpMatches(inflated, '^') - def testCreateDeflatedSAMLLogoutRequestURLParameter(self): + def testConstructorWithNameIdFormatOnSettings(self): """ Tests the OneLogin_Saml2_LogoutRequest Constructor. - The creation of a deflated SAML Logout Request + Case: Defines NameIDFormat from settings """ - settings = OneLogin_Saml2_Settings(self.loadSettingsJSON()) + 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 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()} @@ -92,6 +128,7 @@ def testCreateDeflatedSAMLLogoutRequestURLParameter(self): payload = exploded['SAMLRequest'][0] inflated = OneLogin_Saml2_Utils.decode_base64_and_inflate(payload) self.assertRegexpMatches(inflated, '^') def testGetIDFromSAMLLogoutRequest(self): """ diff --git a/tests/src/OneLogin/saml2_tests/utils_test.py b/tests/src/OneLogin/saml2_tests/utils_test.py index cbc36d66..f1f2aeb6 100644 --- a/tests/src/OneLogin/saml2_tests/utils_test.py +++ b/tests/src/OneLogin/saml2_tests/utils_test.py @@ -607,6 +607,17 @@ def testGenerateNameIdWithSPNameQualifier(self): expected_name_id_enc = '' self.assertIn(expected_name_id_enc, name_id_enc) + def testGenerateNameIdWithoutFormat(self): + """ + Tests the generateNameId method of the OneLogin_Saml2_Utils + """ + name_id_value = 'ONELOGIN_ce998811003f4e60f8b07a311dc641621379cfde' + name_id_format = None + + name_id = OneLogin_Saml2_Utils.generate_name_id(name_id_value, None, name_id_format) + expected_name_id = 'ONELOGIN_ce998811003f4e60f8b07a311dc641621379cfde' + self.assertEqual(name_id, expected_name_id) + def testGenerateNameIdWithoutSPNameQualifier(self): """ Tests the generateNameId method of the OneLogin_Saml2_Utils