Skip to content

Commit ff7a69f

Browse files
author
Hans Hörberg
committed
Fix, so if no encryption keys exists will the server not encrypt the message.
Extended the test suite with negative tests.
1 parent eb1f177 commit ff7a69f

File tree

8 files changed

+446
-13
lines changed

8 files changed

+446
-13
lines changed

src/saml2/config.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,8 @@
6767
"cert_handler_extra_class",
6868
"generate_cert_func",
6969
"generate_cert_info",
70-
"verify_encrypt_cert",
70+
"verify_encrypt_cert_advice",
71+
"verify_encrypt_cert_assertion",
7172
"tmp_cert_file",
7273
"tmp_key_file",
7374
"validate_certificate",
@@ -97,6 +98,8 @@
9798
"sign_assertion",
9899
"sign_response",
99100
"encrypt_assertion",
101+
"encrypted_advice_attributes",
102+
"encrypt_assertion_self_contained",
100103
"want_authn_requests_signed",
101104
"want_authn_requests_only_with_valid_cert",
102105
"provided_attributes",
@@ -219,7 +222,8 @@ def __init__(self, homedir="."):
219222
self.allow_unsolicited = False
220223
self.extension_schema = {}
221224
self.cert_handler_extra_class = None
222-
self.verify_encrypt_cert = None
225+
self.verify_encrypt_cert_advice = None
226+
self.verify_encrypt_cert_assertion = None
223227
self.generate_cert_func = None
224228
self.generate_cert_info = None
225229
self.tmp_cert_file = None

src/saml2/entity.py

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -502,14 +502,22 @@ def _add_info(self, msg, **kwargs):
502502
else:
503503
msg.extension_elements = extensions
504504

505+
def has_encrypt_cert_in_metadata(self, sp_entity_id):
506+
if sp_entity_id is not None:
507+
_certs = self.metadata.certs(sp_entity_id, "any", "encryption")
508+
if len(_certs) > 0:
509+
return True
510+
return False
511+
512+
505513
def _encrypt_assertion(self, encrypt_cert, sp_entity_id, response, node_xpath=None):
506514
_certs = []
507515
cbxs = CryptoBackendXmlSec1(self.config.xmlsec_binary)
508516
if encrypt_cert:
509517
_certs = []
510518
_certs.append(encrypt_cert)
511519
elif sp_entity_id is not None:
512-
_certs = self.metadata.certs(sp_entity_id, "any", "encrypt")
520+
_certs = self.metadata.certs(sp_entity_id, "any", "encryption")
513521
exception = None
514522
for _cert in _certs:
515523
try:
@@ -528,6 +536,7 @@ def _encrypt_assertion(self, encrypt_cert, sp_entity_id, response, node_xpath=No
528536
pass
529537
if exception:
530538
raise exception
539+
return response
531540

532541
def _response(self, in_response_to, consumer_url=None, status=None,
533542
issuer=None, sign=False, to_sign=None, sp_entity_id=None,
@@ -552,7 +561,6 @@ def _response(self, in_response_to, consumer_url=None, status=None,
552561
:return: A Response instance
553562
"""
554563

555-
556564
if not status:
557565
status = success_status_factory()
558566

@@ -570,8 +578,13 @@ def _response(self, in_response_to, consumer_url=None, status=None,
570578
if not sign and to_sign and not encrypt_assertion:
571579
return signed_instance_factory(response, self.sec, to_sign)
572580

573-
if encrypt_assertion or (encrypted_advice_attributes and response.assertion.advice is not None and
574-
len(response.assertion.advice.assertion) == 1):
581+
has_encrypt_cert = self.has_encrypt_cert_in_metadata(sp_entity_id)
582+
if not has_encrypt_cert and encrypt_cert_advice is None:
583+
encrypted_advice_attributes = False
584+
if not has_encrypt_cert and encrypt_cert_assertion is None:
585+
encrypt_assertion = False
586+
587+
if encrypt_assertion or (encrypted_advice_attributes and response.assertion.advice is not None and len(response.assertion.advice.assertion) == 1):
575588
if sign:
576589
response.signature = pre_signature_part(response.id,
577590
self.sec.my_cert, 1)

src/saml2/server.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -545,7 +545,6 @@ def create_authn_response(self, identity, in_response_to, destination,
545545
if not verify_encrypt_cert(encrypt_cert_advice):
546546
raise CertificateError("Invalid certificate for encryption!")
547547

548-
549548
if encrypt_assertion:
550549
verify_encrypt_cert = self.config.getattr("verify_encrypt_cert_assertion", "idp")
551550
if verify_encrypt_cert is not None:

tests/idp_conf_sp_no_encrypt.py

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
from saml2 import BINDING_SOAP
2+
from saml2 import BINDING_HTTP_REDIRECT
3+
from saml2 import BINDING_HTTP_POST
4+
from saml2.saml import NAMEID_FORMAT_PERSISTENT
5+
from saml2.saml import NAME_FORMAT_URI
6+
7+
from pathutils import full_path
8+
from pathutils import xmlsec_path
9+
10+
BASE = "http://localhost:8088"
11+
12+
CONFIG = {
13+
"entityid": "urn:mace:example.com:saml:roland:idp",
14+
"name": "Rolands IdP",
15+
"service": {
16+
"idp": {
17+
"endpoints": {
18+
"single_sign_on_service": [
19+
("%s/sso" % BASE, BINDING_HTTP_REDIRECT)],
20+
"single_logout_service": [
21+
("%s/slo" % BASE, BINDING_SOAP),
22+
("%s/slop" % BASE, BINDING_HTTP_POST)]
23+
},
24+
"policy": {
25+
"default": {
26+
"lifetime": {"minutes": 15},
27+
"attribute_restrictions": None, # means all I have
28+
"name_form": NAME_FORMAT_URI,
29+
},
30+
"urn:mace:example.com:saml:roland:sp": {
31+
"lifetime": {"minutes": 5},
32+
"nameid_format": NAMEID_FORMAT_PERSISTENT,
33+
# "attribute_restrictions":{
34+
# "givenName": None,
35+
# "surName": None,
36+
# }
37+
}
38+
},
39+
"subject_data": full_path("subject_data.db"),
40+
#"domain": "umu.se",
41+
#"name_qualifier": ""
42+
},
43+
},
44+
"debug": 1,
45+
"key_file": full_path("test.key"),
46+
"cert_file": full_path("test.pem"),
47+
"xmlsec_binary": xmlsec_path,
48+
"metadata": [{
49+
"class": "saml2.mdstore.MetaDataFile",
50+
"metadata": [(full_path("metadata_sp_1_no_encryption.xml"), ),
51+
(full_path("vo_metadata.xml"), )],
52+
}],
53+
"attribute_map_dir": full_path("attributemaps"),
54+
"organization": {
55+
"name": "Exempel AB",
56+
"display_name": [("Exempel AB", "se"), ("Example Co.", "en")],
57+
"url": "http://www.example.com/roland",
58+
},
59+
"contact_person": [
60+
{
61+
"given_name": "John",
62+
"sur_name": "Smith",
63+
"email_address": ["[email protected]"],
64+
"contact_type": "technical",
65+
},
66+
],
67+
}

tests/idp_conf_verify_cert.py

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
from saml2 import BINDING_SOAP
2+
from saml2 import BINDING_HTTP_REDIRECT
3+
from saml2 import BINDING_HTTP_POST
4+
from saml2.cert import OpenSSLWrapper
5+
from saml2.saml import NAMEID_FORMAT_PERSISTENT
6+
from saml2.saml import NAME_FORMAT_URI
7+
8+
from pathutils import full_path
9+
from pathutils import xmlsec_path
10+
11+
BASE = "http://localhost:8088"
12+
13+
def verify_encrypt_cert(cert_str):
14+
osw = OpenSSLWrapper()
15+
ca_cert_str = osw.read_str_from_file(full_path("root_cert/localhost.ca.crt"))
16+
valid, mess = osw.verify(ca_cert_str, cert_str)
17+
return valid
18+
19+
CONFIG = {
20+
"entityid": "urn:mace:example.com:saml:roland:idp",
21+
"name": "Rolands IdP",
22+
"service": {
23+
"idp": {
24+
"verify_encrypt_cert_advice": verify_encrypt_cert,
25+
"verify_encrypt_cert_assertion": verify_encrypt_cert,
26+
"endpoints": {
27+
"single_sign_on_service": [
28+
("%s/sso" % BASE, BINDING_HTTP_REDIRECT)],
29+
"single_logout_service": [
30+
("%s/slo" % BASE, BINDING_SOAP),
31+
("%s/slop" % BASE, BINDING_HTTP_POST)]
32+
},
33+
"policy": {
34+
"default": {
35+
"lifetime": {"minutes": 15},
36+
"attribute_restrictions": None, # means all I have
37+
"name_form": NAME_FORMAT_URI,
38+
},
39+
"urn:mace:example.com:saml:roland:sp": {
40+
"lifetime": {"minutes": 5},
41+
"nameid_format": NAMEID_FORMAT_PERSISTENT,
42+
# "attribute_restrictions":{
43+
# "givenName": None,
44+
# "surName": None,
45+
# }
46+
}
47+
},
48+
"subject_data": full_path("subject_data.db"),
49+
#"domain": "umu.se",
50+
#"name_qualifier": ""
51+
},
52+
},
53+
"debug": 1,
54+
"key_file": full_path("test.key"),
55+
"cert_file": full_path("test.pem"),
56+
"xmlsec_binary": xmlsec_path,
57+
"metadata": [{
58+
"class": "saml2.mdstore.MetaDataFile",
59+
"metadata": [(full_path("metadata_sp_1.xml"), ),
60+
(full_path("vo_metadata.xml"), )],
61+
}],
62+
"attribute_map_dir": full_path("attributemaps"),
63+
"organization": {
64+
"name": "Exempel AB",
65+
"display_name": [("Exempel AB", "se"), ("Example Co.", "en")],
66+
"url": "http://www.example.com/roland",
67+
},
68+
"contact_person": [
69+
{
70+
"given_name": "John",
71+
"sur_name": "Smith",
72+
"email_address": ["[email protected]"],
73+
"contact_type": "technical",
74+
},
75+
],
76+
}

tests/metadata_sp_1.xml

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,30 @@
55
<ns0:SPSSODescriptor AuthnRequestsSigned="false"
66
WantAssertionsSigned="true"
77
protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
8-
<ns0:KeyDescriptor>
8+
<ns0:KeyDescriptor use="signing">
9+
<ns1:KeyInfo>
10+
<ns1:X509Data>
11+
<ns1:X509Certificate>
12+
MIICsDCCAhmgAwIBAgIJAJrzqSSwmDY9MA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV
13+
BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX
14+
aWRnaXRzIFB0eSBMdGQwHhcNMDkxMDA2MTk0OTQxWhcNMDkxMTA1MTk0OTQxWjBF
15+
MQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50
16+
ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB
17+
gQDJg2cms7MqjniT8Fi/XkNHZNPbNVQyMUMXE9tXOdqwYCA1cc8vQdzkihscQMXy
18+
3iPw2cMggBu6gjMTOSOxECkuvX5ZCclKr8pXAJM5cY6gVOaVO2PdTZcvDBKGbiaN
19+
efiEw5hnoZomqZGp8wHNLAUkwtH9vjqqvxyS/vclc6k2ewIDAQABo4GnMIGkMB0G
20+
A1UdDgQWBBRePsKHKYJsiojE78ZWXccK9K4aJTB1BgNVHSMEbjBsgBRePsKHKYJs
21+
iojE78ZWXccK9K4aJaFJpEcwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUt
22+
U3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZIIJAJrzqSSw
23+
mDY9MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAJSrKOEzHO7TL5cy6
24+
h3qh+3+JAk8HbGBW+cbX6KBCAw/mzU8flK25vnWwXS3dv2FF3Aod0/S7AWNfKib5
25+
U/SA9nJaz/mWeF9S0farz9AQFc8/NSzAzaVq7YbM4F6f6N2FRl7GikdXRCed45j6
26+
mrPzGzk3ECbupFnqyREH3+ZPSdk=
27+
</ns1:X509Certificate>
28+
</ns1:X509Data>
29+
</ns1:KeyInfo>
30+
</ns0:KeyDescriptor>
31+
<ns0:KeyDescriptor use="encryption">
932
<ns1:KeyInfo>
1033
<ns1:X509Data>
1134
<ns1:X509Certificate>

tests/metadata_sp_1_no_encryption.xml

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
<?xml version='1.0' encoding='UTF-8'?>
2+
<ns0:EntitiesDescriptor xmlns:ns0="urn:oasis:names:tc:SAML:2.0:metadata"
3+
xmlns:ns1="http://www.w3.org/2000/09/xmldsig#">
4+
<ns0:EntityDescriptor entityID="urn:mace:example.com:saml:roland:sp">
5+
<ns0:SPSSODescriptor AuthnRequestsSigned="false"
6+
WantAssertionsSigned="true"
7+
protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
8+
<ns0:KeyDescriptor use="signing">
9+
<ns1:KeyInfo>
10+
<ns1:X509Data>
11+
<ns1:X509Certificate>
12+
MIICsDCCAhmgAwIBAgIJAJrzqSSwmDY9MA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV
13+
BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX
14+
aWRnaXRzIFB0eSBMdGQwHhcNMDkxMDA2MTk0OTQxWhcNMDkxMTA1MTk0OTQxWjBF
15+
MQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50
16+
ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB
17+
gQDJg2cms7MqjniT8Fi/XkNHZNPbNVQyMUMXE9tXOdqwYCA1cc8vQdzkihscQMXy
18+
3iPw2cMggBu6gjMTOSOxECkuvX5ZCclKr8pXAJM5cY6gVOaVO2PdTZcvDBKGbiaN
19+
efiEw5hnoZomqZGp8wHNLAUkwtH9vjqqvxyS/vclc6k2ewIDAQABo4GnMIGkMB0G
20+
A1UdDgQWBBRePsKHKYJsiojE78ZWXccK9K4aJTB1BgNVHSMEbjBsgBRePsKHKYJs
21+
iojE78ZWXccK9K4aJaFJpEcwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUt
22+
U3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZIIJAJrzqSSw
23+
mDY9MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAJSrKOEzHO7TL5cy6
24+
h3qh+3+JAk8HbGBW+cbX6KBCAw/mzU8flK25vnWwXS3dv2FF3Aod0/S7AWNfKib5
25+
U/SA9nJaz/mWeF9S0farz9AQFc8/NSzAzaVq7YbM4F6f6N2FRl7GikdXRCed45j6
26+
mrPzGzk3ECbupFnqyREH3+ZPSdk=
27+
</ns1:X509Certificate>
28+
</ns1:X509Data>
29+
</ns1:KeyInfo>
30+
</ns0:KeyDescriptor>
31+
<ns0:AssertionConsumerService
32+
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
33+
Location="http://lingon.catalogix.se:8087/" index="1"/>
34+
<ns0:AttributeConsumingService index="1">
35+
<ns0:ServiceName xml:lang="en">
36+
urn:mace:example.com:saml:roland:sp
37+
</ns0:ServiceName>
38+
<ns0:ServiceDescription xml:lang="en">My own SP
39+
</ns0:ServiceDescription>
40+
<ns0:RequestedAttribute FriendlyName="surName"
41+
Name="urn:oid:2.5.4.4"
42+
NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"
43+
isRequired="true"/>
44+
<ns0:RequestedAttribute FriendlyName="givenName"
45+
Name="urn:oid:2.5.4.42"
46+
NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"
47+
isRequired="true"/>
48+
<ns0:RequestedAttribute FriendlyName="mail"
49+
Name="urn:oid:0.9.2342.19200300.100.1.3"
50+
NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"
51+
isRequired="true"/>
52+
<ns0:RequestedAttribute FriendlyName="title"
53+
Name="urn:oid:2.5.4.12"
54+
NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri"
55+
isRequired="false"/>
56+
</ns0:AttributeConsumingService>
57+
</ns0:SPSSODescriptor>
58+
<ns0:Organization>
59+
<ns0:OrganizationName xml:lang="se">AB Exempel
60+
</ns0:OrganizationName>
61+
<ns0:OrganizationDisplayName xml:lang="se">AB Exempel
62+
</ns0:OrganizationDisplayName>
63+
<ns0:OrganizationURL xml:lang="en">http://www.example.org
64+
</ns0:OrganizationURL>
65+
</ns0:Organization>
66+
<ns0:ContactPerson contactType="technical">
67+
<ns0:GivenName>Roland</ns0:GivenName>
68+
<ns0:SurName>Hedberg</ns0:SurName>
69+
<ns0:EmailAddress>[email protected]</ns0:EmailAddress>
70+
<ns0:EmailAddress>[email protected]</ns0:EmailAddress>
71+
<ns0:TelephoneNumber>+46 70 100 0000</ns0:TelephoneNumber>
72+
</ns0:ContactPerson>
73+
</ns0:EntityDescriptor>
74+
</ns0:EntitiesDescriptor>

0 commit comments

Comments
 (0)