Skip to content

Commit 919a288

Browse files
committed
Do not send NameID with no TextContent
Fix to the SAMLFrontend so that it will not create and return to the SP a SAML <NameID> that has no TextContent, since that is not valid SAML.
1 parent ce7cfe7 commit 919a288

File tree

2 files changed

+41
-9
lines changed

2 files changed

+41
-9
lines changed

src/satosa/frontends/saml2.py

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -308,15 +308,24 @@ def _handle_authn_response(self, context, internal_response, idp):
308308
ava.pop(k, None)
309309

310310
nameid_value = internal_response.subject_id
311-
nameid_format = subject_type_to_saml_nameid_format(
312-
internal_response.subject_type
313-
)
314-
name_id = NameID(
315-
text=nameid_value,
316-
format=nameid_format,
317-
sp_name_qualifier=None,
318-
name_qualifier=None,
319-
)
311+
312+
# If the backend did not receive a SAML <NameID> and so
313+
# name_id is set to None then do not create a NameID instance.
314+
# Instead pass None as the name name_id to the IdP server
315+
# instance and it will use its configured policy to construct
316+
# a <NameID>, with the default to create a transient <NameID>.
317+
if nameid_value is None:
318+
name_id = None
319+
else:
320+
nameid_format = subject_type_to_saml_nameid_format(
321+
internal_response.subject_type
322+
)
323+
name_id = NameID(
324+
text=nameid_value,
325+
format=nameid_format,
326+
sp_name_qualifier=None,
327+
name_qualifier=None,
328+
)
320329

321330
dbgmsg = "returning attributes %s" % json.dumps(ava)
322331
satosa_logging(logger, logging.DEBUG, dbgmsg, context.state)

tests/satosa/frontends/test_saml2.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,11 +190,34 @@ def test_handle_authn_response_without_relay_state(self, context, idp_conf, sp_c
190190
fakesp = FakeSP(SPConfig().load(sp_conf, metadata_construction=False))
191191
resp = fakesp.parse_authn_request_response(resp_dict["SAMLResponse"][0],
192192
BINDING_HTTP_REDIRECT)
193+
193194
for key in resp.ava:
194195
assert USERS["testuser1"][key] == resp.ava[key]
195196

196197
assert samlfrontend.name not in context.state
197198

199+
def test_handle_authn_response_without_name_id(
200+
self, context, idp_conf, sp_conf, internal_response):
201+
samlfrontend = self.setup_for_authn_req(
202+
context, idp_conf, sp_conf, relay_state=None)
203+
_, internal_req = samlfrontend.handle_authn_request(
204+
context, BINDING_HTTP_REDIRECT)
205+
206+
# Make sure we are testing the equivalent of a <Response> with no
207+
# <NameID> in the <Subject>.
208+
assert internal_response.subject_type is None
209+
assert internal_response.subject_id is None
210+
211+
resp = samlfrontend.handle_authn_response(context, internal_response)
212+
resp_dict = parse_qs(urlparse(resp.message).query)
213+
214+
fakesp = FakeSP(SPConfig().load(sp_conf, metadata_construction=False))
215+
resp = fakesp.parse_authn_request_response(
216+
resp_dict["SAMLResponse"][0], BINDING_HTTP_REDIRECT)
217+
218+
# The <NameID> must not have an empty TextContent.
219+
assert resp.name_id.text is not None
220+
198221
def test_get_filter_attributes_with_sp_requested_attributes_without_friendlyname(self, idp_conf):
199222
sp_metadata_str = """<?xml version="1.0"?>
200223
<md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" entityID="http://sp.example.com">

0 commit comments

Comments
 (0)