Skip to content

Commit 4c14943

Browse files
committed
#112. Remove requirement on responsesRemove
1 parent 81e06ba commit 4c14943

File tree

9 files changed

+129
-11
lines changed

9 files changed

+129
-11
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,10 @@ In addition to the required settings data (idp, sp), there is extra information
347347
// this SP to be signed. [Metadata of the SP will offer this info]
348348
"wantAssertionsSigned": false,
349349

350+
// Indicates a requirement for the NameID element on the SAMLResponse
351+
// received by this SP to be present.
352+
"wantNameId": true,
353+
350354
// Indicates a requirement for the NameID received by
351355
// this SP to be encrypted.
352356
"wantNameIdEncrypted": false,

demo-bottle/saml/advanced_settings.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
"signMetadata": false,
88
"wantMessagesSigned": false,
99
"wantAssertionsSigned": false,
10+
"wantNameId" : true,
1011
"wantNameIdEncrypted": false,
1112
"signatureAlgorithm": "http://www.w3.org/2000/09/xmldsig#rsa-sha1"
1213
},

demo-django/saml/advanced_settings.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
"signMetadata": false,
88
"wantMessagesSigned": false,
99
"wantAssertionsSigned": false,
10+
"wantNameId" : true,
1011
"wantNameIdEncrypted": false,
1112
"signatureAlgorithm": "http://www.w3.org/2000/09/xmldsig#rsa-sha1"
1213
},

demo-flask/saml/advanced_settings.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
"signMetadata": false,
88
"wantMessagesSigned": false,
99
"wantAssertionsSigned": false,
10+
"wantNameId" : true,
1011
"wantNameIdEncrypted": false,
1112
"signatureAlgorithm": "http://www.w3.org/2000/09/xmldsig#rsa-sha1"
1213
},

src/onelogin/saml2/auth.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ def get_nameid(self):
206206
Returns the nameID.
207207
208208
:returns: NameID
209-
:rtype: string
209+
:rtype: string|None
210210
"""
211211
return self.__nameid
212212

@@ -222,7 +222,7 @@ def get_session_expiration(self):
222222
"""
223223
Returns the SessionNotOnOrAfter from the AuthnStatement.
224224
:returns: The SessionNotOnOrAfter of the assertion
225-
:rtype: DateTime|null
225+
:rtype: DateTime|None
226226
"""
227227
return self.__session_expiration
228228

src/onelogin/saml2/response.py

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,8 @@ def get_nameid_data(self):
276276
:rtype: dict
277277
"""
278278
nameid = None
279+
nameid_data = {}
280+
279281
encrypted_id_data_nodes = self.__query_assertion('/saml:Subject/saml:EncryptedID/xenc:EncryptedData')
280282
if encrypted_id_data_nodes:
281283
encrypted_data = encrypted_id_data_nodes[0]
@@ -286,24 +288,30 @@ def get_nameid_data(self):
286288
if nameid_nodes:
287289
nameid = nameid_nodes[0]
288290
if nameid is None:
289-
raise Exception('Not NameID found in the assertion of the Response')
291+
security = self.__settings.get_security_data()
290292

291-
nameid_data = {'Value': nameid.text}
292-
for attr in ['Format', 'SPNameQualifier', 'NameQualifier']:
293-
value = nameid.get(attr, None)
294-
if value:
295-
nameid_data[attr] = value
293+
if security.get('wantNameId', True):
294+
raise Exception('Not NameID found in the assertion of the Response')
295+
else:
296+
nameid_data = {'Value': nameid.text}
297+
for attr in ['Format', 'SPNameQualifier', 'NameQualifier']:
298+
value = nameid.get(attr, None)
299+
if value:
300+
nameid_data[attr] = value
296301
return nameid_data
297302

298303
def get_nameid(self):
299304
"""
300305
Gets the NameID provided by the SAML Response from the IdP
301306
302307
:returns: NameID (value)
303-
:rtype: string
308+
:rtype: string|None
304309
"""
310+
nameid_value = None
305311
nameid_data = self.get_nameid_data()
306-
return nameid_data['Value']
312+
if nameid_data and 'Value' in nameid_data.keys():
313+
nameid_value = nameid_data['Value']
314+
return nameid_value
307315

308316
def get_session_not_on_or_after(self):
309317
"""

src/onelogin/saml2/settings.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,10 @@ def __add_default_values(self):
293293
if 'wantAssertionsSigned' not in self.__security.keys():
294294
self.__security['wantAssertionsSigned'] = False
295295

296+
# NameID element expected
297+
if 'wantNameId' not in self.__security.keys():
298+
self.__security['wantNameId'] = True
299+
296300
# Encrypt expected
297301
if 'wantAssertionsEncrypted' not in self.__security.keys():
298302
self.__security['wantAssertionsEncrypted'] = False

tests/src/OneLogin/saml2_tests/response_test.py

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,9 @@ def testReturnNameId(self):
6464
"""
6565
Tests the get_nameid method of the OneLogin_Saml2_Response
6666
"""
67-
settings = OneLogin_Saml2_Settings(self.loadSettingsJSON())
67+
json_settings = self.loadSettingsJSON()
68+
69+
settings = OneLogin_Saml2_Settings(json_settings)
6870
xml = self.file_contents(join(self.data_path, 'responses', 'response1.xml.base64'))
6971
response = OneLogin_Saml2_Response(settings, xml)
7072
self.assertEqual('support@onelogin.com', response.get_nameid())
@@ -85,10 +87,39 @@ def testReturnNameId(self):
8587
except Exception as e:
8688
self.assertIn('Not NameID found in the assertion of the Response', e.message)
8789

90+
json_settings['security']['wantNameId'] = True
91+
settings = OneLogin_Saml2_Settings(json_settings)
92+
93+
response_5 = OneLogin_Saml2_Response(settings, xml_4)
94+
try:
95+
response_5.get_nameid()
96+
self.assertTrue(False)
97+
except Exception as e:
98+
self.assertIn('Not NameID found in the assertion of the Response', e.message)
99+
100+
json_settings['security']['wantNameId'] = False
101+
settings = OneLogin_Saml2_Settings(json_settings)
102+
103+
response_6 = OneLogin_Saml2_Response(settings, xml_4)
104+
nameid_6 = response_6.get_nameid()
105+
self.assertIsNone(nameid_6)
106+
107+
del json_settings['security']['wantNameId']
108+
settings = OneLogin_Saml2_Settings(json_settings)
109+
110+
response_7 = OneLogin_Saml2_Response(settings, xml_4)
111+
try:
112+
response_7.get_nameid()
113+
self.assertTrue(False)
114+
except Exception as e:
115+
self.assertIn('Not NameID found in the assertion of the Response', e.message)
116+
88117
def testGetNameIdData(self):
89118
"""
90119
Tests the get_nameid_data method of the OneLogin_Saml2_Response
91120
"""
121+
json_settings = self.loadSettingsJSON()
122+
92123
settings = OneLogin_Saml2_Settings(self.loadSettingsJSON())
93124
xml = self.file_contents(join(self.data_path, 'responses', 'response1.xml.base64'))
94125
response = OneLogin_Saml2_Response(settings, xml)
@@ -127,6 +158,33 @@ def testGetNameIdData(self):
127158
except Exception as e:
128159
self.assertIn('Not NameID found in the assertion of the Response', e.message)
129160

161+
json_settings['security']['wantNameId'] = True
162+
settings = OneLogin_Saml2_Settings(json_settings)
163+
164+
response_5 = OneLogin_Saml2_Response(settings, xml_4)
165+
try:
166+
response_5.get_nameid_data()
167+
self.assertTrue(False)
168+
except Exception as e:
169+
self.assertIn('Not NameID found in the assertion of the Response', e.message)
170+
171+
json_settings['security']['wantNameId'] = False
172+
settings = OneLogin_Saml2_Settings(json_settings)
173+
174+
response_6 = OneLogin_Saml2_Response(settings, xml_4)
175+
nameid_data_6 = response_6.get_nameid_data()
176+
self.assertEqual({}, nameid_data_6)
177+
178+
del json_settings['security']['wantNameId']
179+
settings = OneLogin_Saml2_Settings(json_settings)
180+
181+
response_7 = OneLogin_Saml2_Response(settings, xml_4)
182+
try:
183+
response_7.get_nameid_data()
184+
self.assertTrue(False)
185+
except Exception as e:
186+
self.assertIn('Not NameID found in the assertion of the Response', e.message)
187+
130188
def testCheckStatus(self):
131189
"""
132190
Tests the check_status method of the OneLogin_Saml2_Response

tests/src/OneLogin/saml2_tests/settings_test.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -621,8 +621,49 @@ def testGetSecurityData(self):
621621
self.assertIn('signMetadata', security)
622622
self.assertIn('wantMessagesSigned', security)
623623
self.assertIn('wantAssertionsSigned', security)
624+
self.assertIn('requestedAuthnContext', security)
625+
self.assertIn('wantNameId', security)
624626
self.assertIn('wantNameIdEncrypted', security)
625627

628+
def testGetDefaultSecurityValues(self):
629+
"""
630+
Tests default values of Security advanced sesettings
631+
"""
632+
settings_json = self.loadSettingsJSON()
633+
del settings_json['security']
634+
settings = OneLogin_Saml2_Settings(settings_json)
635+
security = settings.get_security_data()
636+
637+
self.assertIn('nameIdEncrypted', security)
638+
self.assertFalse(security.get('nameIdEncrypted'))
639+
640+
self.assertIn('authnRequestsSigned', security)
641+
self.assertFalse(security.get('authnRequestsSigned'))
642+
643+
self.assertIn('logoutRequestSigned', security)
644+
self.assertFalse(security.get('logoutRequestSigned'))
645+
646+
self.assertIn('logoutResponseSigned', security)
647+
self.assertFalse(security.get('logoutResponseSigned'))
648+
649+
self.assertIn('signMetadata', security)
650+
self.assertFalse(security.get('signMetadata'))
651+
652+
self.assertIn('wantMessagesSigned', security)
653+
self.assertFalse(security.get('wantMessagesSigned'))
654+
655+
self.assertIn('wantAssertionsSigned', security)
656+
self.assertFalse(security.get('wantAssertionsSigned'))
657+
658+
self.assertIn('requestedAuthnContext', security)
659+
self.assertTrue(security.get('requestedAuthnContext'))
660+
661+
self.assertIn('wantNameId', security)
662+
self.assertTrue(security.get('wantNameId'))
663+
664+
self.assertIn('wantNameIdEncrypted', security)
665+
self.assertFalse(security.get('wantNameIdEncrypted'))
666+
626667
def testGetContacts(self):
627668
"""
628669
Tests the getContacts method of the OneLogin_Saml2_Settings

0 commit comments

Comments
 (0)