Skip to content

Commit f1a7240

Browse files
authored
Merge pull request #167 from sdelements/fix/saml_bugs
Fix unsigned authentication request to POST endpoint
2 parents 2f80dbb + c27f208 commit f1a7240

File tree

4 files changed

+55
-1
lines changed

4 files changed

+55
-1
lines changed

djangosaml2/tests/conf.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919

2020

2121
def create_conf(sp_host='sp.example.com', idp_hosts=['idp.example.com'],
22-
metadata_file='remote_metadata.xml'):
22+
metadata_file='remote_metadata.xml', authn_requests_signed=True):
2323

2424
try:
2525
from saml2.sigver import get_xmlsec_binary
@@ -55,6 +55,7 @@ def create_conf(sp_host='sp.example.com', idp_hosts=['idp.example.com'],
5555
'optional_attributes': ['eduPersonAffiliation'],
5656
'idp': {}, # this is filled later
5757
'want_response_signed': False,
58+
'authn_requests_signed': authn_requests_signed,
5859
},
5960
},
6061

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?xml version="1.0"?>
2+
<md:EntitiesDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
3+
<md:EntityDescriptor entityID="https://idp.example.com/simplesaml/saml2/idp/metadata.php">
4+
<md:IDPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
5+
<md:KeyDescriptor use="signing">
6+
<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
7+
<ds:X509Data>
8+
<ds:X509Certificate>MIICgTCCAeoCCQCbOlrWDdX7FTANBgkqhkiG9w0BAQUFADCBhDELMAkGA1UEBhMCTk8xGDAWBgNVBAgTD0FuZHJlYXMgU29sYmVyZzEMMAoGA1UEBxMDRm9vMRAwDgYDVQQKEwdVTklORVRUMRgwFgYDVQQDEw9mZWlkZS5lcmxhbmcubm8xITAfBgkqhkiG9w0BCQEWEmFuZHJlYXNAdW5pbmV0dC5ubzAeFw0wNzA2MTUxMjAxMzVaFw0wNzA4MTQxMjAxMzVaMIGEMQswCQYDVQQGEwJOTzEYMBYGA1UECBMPQW5kcmVhcyBTb2xiZXJnMQwwCgYDVQQHEwNGb28xEDAOBgNVBAoTB1VOSU5FVFQxGDAWBgNVBAMTD2ZlaWRlLmVybGFuZy5ubzEhMB8GCSqGSIb3DQEJARYSYW5kcmVhc0B1bmluZXR0Lm5vMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDivbhR7P516x/S3BqKxupQe0LONoliupiBOesCO3SHbDrl3+q9IbfnfmE04rNuMcPsIxB161TdDpIesLCn7c8aPHISKOtPlAeTZSnb8QAu7aRjZq3+PbrP5uW3TcfCGPtKTytHOge/OlJbo078dVhXQ14d1EDwXJW1rRXuUt4C8QIDAQABMA0GCSqGSIb3DQEBBQUAA4GBACDVfp86HObqY+e8BUoWQ9+VMQx1ASDohBjwOsg2WykUqRXF+dLfcUH9dWR63CtZIKFDbStNomPnQz7nbK+onygwBspVEbnHuUihZq3ZUdmumQqCw4Uvs/1Uvq3orOo/WJVhTyvLgFVK2QarQ4/67OZfHd7R+POBXhophSMv1ZOo</ds:X509Certificate>
9+
</ds:X509Data>
10+
</ds:KeyInfo>
11+
</md:KeyDescriptor>
12+
<md:KeyDescriptor use="encryption">
13+
<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
14+
<ds:X509Data>
15+
<ds:X509Certificate>MIICgTCCAeoCCQCbOlrWDdX7FTANBgkqhkiG9w0BAQUFADCBhDELMAkGA1UEBhMCTk8xGDAWBgNVBAgTD0FuZHJlYXMgU29sYmVyZzEMMAoGA1UEBxMDRm9vMRAwDgYDVQQKEwdVTklORVRUMRgwFgYDVQQDEw9mZWlkZS5lcmxhbmcubm8xITAfBgkqhkiG9w0BCQEWEmFuZHJlYXNAdW5pbmV0dC5ubzAeFw0wNzA2MTUxMjAxMzVaFw0wNzA4MTQxMjAxMzVaMIGEMQswCQYDVQQGEwJOTzEYMBYGA1UECBMPQW5kcmVhcyBTb2xiZXJnMQwwCgYDVQQHEwNGb28xEDAOBgNVBAoTB1VOSU5FVFQxGDAWBgNVBAMTD2ZlaWRlLmVybGFuZy5ubzEhMB8GCSqGSIb3DQEJARYSYW5kcmVhc0B1bmluZXR0Lm5vMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDivbhR7P516x/S3BqKxupQe0LONoliupiBOesCO3SHbDrl3+q9IbfnfmE04rNuMcPsIxB161TdDpIesLCn7c8aPHISKOtPlAeTZSnb8QAu7aRjZq3+PbrP5uW3TcfCGPtKTytHOge/OlJbo078dVhXQ14d1EDwXJW1rRXuUt4C8QIDAQABMA0GCSqGSIb3DQEBBQUAA4GBACDVfp86HObqY+e8BUoWQ9+VMQx1ASDohBjwOsg2WykUqRXF+dLfcUH9dWR63CtZIKFDbStNomPnQz7nbK+onygwBspVEbnHuUihZq3ZUdmumQqCw4Uvs/1Uvq3orOo/WJVhTyvLgFVK2QarQ4/67OZfHd7R+POBXhophSMv1ZOo</ds:X509Certificate>
16+
</ds:X509Data>
17+
</ds:KeyInfo>
18+
</md:KeyDescriptor>
19+
<md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://idp.example.com/simplesaml/saml2/idp/SingleLogoutService.php"/>
20+
<md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</md:NameIDFormat>
21+
<md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://idp.example.com/simplesaml/saml2/idp/SSOService.php"/>
22+
</md:IDPSSODescriptor>
23+
<md:Organization>
24+
<md:OrganizationName xml:lang="en">Lorenzo's test IdP</md:OrganizationName>
25+
<md:OrganizationDisplayName xml:lang="en">idp.example.com IdP</md:OrganizationDisplayName>
26+
<md:OrganizationURL xml:lang="en">http://idp.example.com/</md:OrganizationURL>
27+
</md:Organization>
28+
<md:ContactPerson contactType="technical">
29+
<md:SurName>Administrator</md:SurName>
30+
<md:EmailAddress>[email protected]</md:EmailAddress>
31+
</md:ContactPerson>
32+
</md:EntityDescriptor>
33+
</md:EntitiesDescriptor>

djangosaml2/tests/utils.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
from html.parser import HTMLParser
2+
3+
4+
class SAMLPostFormParser(HTMLParser):
5+
"""
6+
Parses the SAML Post binding form page for the SAMLRequest value.
7+
"""
8+
9+
saml_request_value = None
10+
11+
def handle_starttag(self, tag, attrs):
12+
attrs_dict = dict(attrs)
13+
14+
if tag != "input" or attrs_dict.get("name") != "SAMLRequest":
15+
return
16+
self.saml_request_value = attrs_dict.get("value")

djangosaml2/views.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
)
4545
from saml2.mdstore import SourceNotFound
4646
from saml2.sigver import MissingKey
47+
from saml2.samlp import AuthnRequest
4748
from saml2.validate import ResponseLifetimeExceed, ToEarly
4849
from saml2.xmldsig import ( # support for SHA1 is required by spec
4950
SIG_RSA_SHA1, SIG_RSA_SHA256)
@@ -228,6 +229,9 @@ def login(request,
228229
binding=binding,
229230
**kwargs)
230231
try:
232+
if isinstance(request_xml, AuthnRequest):
233+
# request_xml will be an instance of AuthnRequest if the message is not signed
234+
request_xml = str(request_xml)
231235
saml_request = base64.b64encode(bytes(request_xml, 'UTF-8')).decode('utf-8')
232236

233237
http_response = render(request, post_binding_form_template, {

0 commit comments

Comments
 (0)