Skip to content

Commit 281d2e1

Browse files
author
Alex Bublichenko
committed
Gracefully handle invalid HOK assertions
1 parent 65af4be commit 281d2e1

File tree

3 files changed

+56
-10
lines changed

3 files changed

+56
-10
lines changed

src/saml2/response.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -726,7 +726,8 @@ def _holder_of_key_confirmed(self, data):
726726
return False
727727

728728
has_keyinfo = False
729-
for element in extension_elements_to_elements(data.key_info,
729+
key_info = data.key_info or ()
730+
for element in extension_elements_to_elements(key_info,
730731
[samlp, saml, xenc, ds]):
731732
if isinstance(element, ds.KeyInfo):
732733
has_keyinfo = True

tests/saml_hok_invalid.xml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?xml version='1.0' encoding='UTF-8'?>
2+
<!-- SAML response with invalid 'holder-of-key' SubjectConfirmation: missing KeyInfo element. -->
3+
<ns0:Response xmlns:ns0="urn:oasis:names:tc:SAML:2.0:protocol"
4+
xmlns:ns1="urn:oasis:names:tc:SAML:2.0:assertion"
5+
xmlns:ns2="http://www.w3.org/2000/09/xmldsig#"
6+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" Destination="https://sp:443/.auth/saml/login" ID="_df9a1eadc90519252694519504a13dfb8dd67a1bb4" InResponseTo="id-KHlas49TtW2VdC8WN" IssueInstant="2019-05-14T20:35:13Z" Version="2.0">
7+
<ns1:Issuer>https://idp:8443</ns1:Issuer>
8+
<ns0:Status>
9+
<ns0:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success" />
10+
</ns0:Status>
11+
<ns1:Assertion ID="_12d211a5015f71eba8f837d2aa8b95b28bbdc4599b" IssueInstant="2019-05-14T20:35:13Z" Version="2.0">
12+
<ns1:Issuer>https://idp:8443</ns1:Issuer>
13+
<ns1:Subject>
14+
<ns1:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent">57a0a35eefdb29ca8b4ab78d5a118117</ns1:NameID>
15+
<ns1:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:holder-of-key">
16+
<ns1:SubjectConfirmationData InResponseTo="id-KHlas49TtW2VdC8WN" NotOnOrAfter="2019-05-14T20:36:13Z" Recipient="https://sp:443/.auth/saml/login" />
17+
</ns1:SubjectConfirmation>
18+
</ns1:Subject>
19+
<ns1:AuthnStatement AuthnInstant="2019-05-14T20:35:13Z" SessionIndex="1">
20+
<ns1:AuthnContext>
21+
<ns1:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</ns1:AuthnContextClassRef>
22+
</ns1:AuthnContext>
23+
</ns1:AuthnStatement>
24+
<ns1:AttributeStatement>
25+
<ns1:Attribute Name="uid" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri">
26+
<ns1:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xsi:type="xs:string">testuser</ns1:AttributeValue>
27+
</ns1:Attribute>
28+
</ns1:AttributeStatement>
29+
</ns1:Assertion>
30+
</ns0:Response>

tests/test_93_hok.py

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,19 @@
11
#!/usr/bin/env python
22
# -*- coding: utf-8 -*-
3-
from saml2.response import authn_response
3+
from saml2.response import authn_response, VerificationError
44
from saml2.config import config_factory
55

66
from pathutils import dotname, full_path
77

8-
HOLDER_OF_KEY_RESPONSE_FILE = full_path("saml_hok.xml")
8+
HOLDER_OF_KEY_RESPONSE_FILE = full_path("saml_hok.xml")
9+
INVALID_HOLDER_OF_KEY_RESPONSE_FILE = full_path("saml_hok_invalid.xml")
910

1011

1112
class TestHolderOfKeyResponse:
12-
def test_hok_response_is_parsed(self):
13+
def test_valid_hok_response_is_parsed(self):
1314
"""Verifies that response with 'holder-of-key' subject confirmations is parsed successfully."""
14-
conf = config_factory("idp", dotname("server_conf"))
15-
resp = authn_response(conf, "https://sp:443/.auth/saml/login", asynchop=False, allow_unsolicited=True)
16-
with open(HOLDER_OF_KEY_RESPONSE_FILE, 'r') as fp:
17-
authn_response_xml = fp.read()
18-
resp.loads(authn_response_xml, False)
15+
resp = self._get_test_response(HOLDER_OF_KEY_RESPONSE_FILE)
1916
resp.do_not_verify = True
20-
2117
resp.parse_assertion()
2218

2319
assert resp.get_subject() is not None
@@ -56,6 +52,25 @@ def _expected_hok_certs(self):
5652
certs[index] = item
5753
return certs
5854

55+
def test_invalid_hok_response_fails_verification(self):
56+
"""Verifies that response with invalid 'holder-of-key' subject confirmations is parsed successfully."""
57+
resp = self._get_test_response(INVALID_HOLDER_OF_KEY_RESPONSE_FILE)
58+
resp.do_not_verify = True
59+
60+
try:
61+
resp.parse_assertion()
62+
assert False, "parse_assertion() did not fail as expected"
63+
except VerificationError as e:
64+
assert e is not None
65+
66+
def _get_test_response(self, path):
67+
conf = config_factory("idp", dotname("server_conf"))
68+
resp = authn_response(conf, "https://sp:443/.auth/saml/login", asynchop=False, allow_unsolicited=True)
69+
with open(path, 'r') as fp:
70+
authn_response_xml = fp.read()
71+
resp.loads(authn_response_xml, False)
72+
return resp
73+
5974

6075
if __name__ == "__main__":
6176
t = TestHolderOfKeyResponse()

0 commit comments

Comments
 (0)