Skip to content

Commit 1d031a4

Browse files
committed
Partial commit.
Improved signing and added more testcases.
1 parent 2949fba commit 1d031a4

File tree

3 files changed

+88
-88
lines changed

3 files changed

+88
-88
lines changed

src/saml2/entity.py

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -579,6 +579,12 @@ def _response(self, in_response_to, consumer_url=None, status=None,
579579
encrypt_advice = False
580580
if encrypted_advice_attributes and response.assertion.advice is not None \
581581
and len(response.assertion.advice.assertion) == 1:
582+
to_sign_advice = []
583+
if sign_assertion is not None and sign_assertion:
584+
if response.assertion.advice and response.assertion.advice.assertion:
585+
for tmp_assertion in response.assertion.advice.assertion:
586+
tmp_assertion.signature = pre_signature_part(tmp_assertion.id, self.sec.my_cert, 1)
587+
to_sign_advice.append((class_name(tmp_assertion), tmp_assertion.id))
582588
tmp_assertion = response.assertion.advice.assertion[0]
583589
response.assertion.advice.encrypted_assertion = []
584590
response.assertion.advice.encrypted_assertion.append(EncryptedAssertion())
@@ -587,12 +593,6 @@ def _response(self, in_response_to, consumer_url=None, status=None,
587593
else:
588594
response.assertion.advice.encrypted_assertion[0].add_extension_element(tmp_assertion)
589595
response.assertion.advice.assertion = []
590-
to_sign_advice = []
591-
if sign_assertion is not None and sign_assertion:
592-
if response.assertion.advice and response.assertion.advice.assertion:
593-
for tmp_assertion in response.assertion.advice.assertion:
594-
tmp_assertion.signature = pre_signature_part(tmp_assertion.id, self.sec.my_cert, 1)
595-
to_sign_advice.append((class_name(tmp_assertion), tmp_assertion.id))
596596
if encrypt_assertion_self_contained:
597597
advice_tag = response.assertion.advice._to_element_tree().tag
598598
assertion_tag = tmp_assertion._to_element_tree().tag
@@ -608,6 +608,14 @@ def _response(self, in_response_to, consumer_url=None, status=None,
608608
if encrypt_assertion:
609609
response = response_from_string(response)
610610
if encrypt_assertion:
611+
to_sign_assertion = []
612+
if sign_assertion is not None and sign_assertion:
613+
_assertions = response.assertion
614+
if not isinstance(response.assertion, list):
615+
_assertions = [response.assertion]
616+
for _assertion in _assertions:
617+
_assertion.signature = pre_signature_part(_assertion.id, self.sec.my_cert, 1)
618+
to_sign_assertion.append((class_name(_assertion), _assertion.id))
611619
if encrypt_assertion_self_contained:
612620
try:
613621
assertion_tag = response.assertion._to_element_tree().tag
@@ -618,13 +626,12 @@ def _response(self, in_response_to, consumer_url=None, status=None,
618626
assertion_tag)
619627
else:
620628
response = pre_encrypt_assertion(response)
621-
to_sign_assertion = []
622-
if sign_assertion is not None and sign_assertion:
623-
response.assertion.signature = pre_signature_part(response.assertion.id, self.sec.my_cert, 1)
624-
to_sign_assertion.append((class_name(response.assertion), response.assertion.id))
625629
if to_sign_assertion:
626630
response = signed_instance_factory(response, self.sec, to_sign_assertion)
627631
response = self._encrypt_assertion(encrypt_cert_assertion, sp_entity_id, response)
632+
else:
633+
if to_sign:
634+
response = signed_instance_factory(response, self.sec, to_sign)
628635
if sign:
629636
return signed_instance_factory(response, self.sec, sign_class)
630637
else:

src/saml2/server.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -380,12 +380,12 @@ def _authn_response(self, in_response_to, consumer_url,
380380
assertion.signature = pre_signature_part(assertion.id, self.sec.my_cert, 1)
381381
to_sign.append((class_name(assertion), assertion.id))
382382

383-
if not encrypted_advice_attributes:
384-
if sign_assertion:
385-
if assertion.advice and assertion.advice.assertion:
386-
for tmp_assertion in assertion.advice.assertion:
387-
tmp_assertion.signature = pre_signature_part(tmp_assertion.id, self.sec.my_cert, 1)
388-
to_sign.append((class_name(tmp_assertion), tmp_assertion.id))
383+
#if not encrypted_advice_attributes:
384+
# if sign_assertion:
385+
# if assertion.advice and assertion.advice.assertion:
386+
# for tmp_assertion in assertion.advice.assertion:
387+
# tmp_assertion.signature = pre_signature_part(tmp_assertion.id, self.sec.my_cert, 1)
388+
# to_sign.append((class_name(tmp_assertion), tmp_assertion.id))
389389

390390
# Store which assertion that has been sent to which SP about which
391391
# subject.

tests/test_50_server.py

Lines changed: 65 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -498,8 +498,32 @@ def test_signed_response_2(self):
498498

499499
assert sresponse.assertion[0].signature == None
500500

501+
def test_signed_response_3(self):
501502

502503

504+
signed_resp = self.server.create_authn_response(
505+
self.ava,
506+
"id12", # in_response_to
507+
"http://lingon.catalogix.se:8087/", # consumer_url
508+
"urn:mace:example.com:saml:roland:sp", # sp_entity_id
509+
name_id=self.name_id,
510+
sign_response=False,
511+
sign_assertion=True,
512+
)
513+
514+
sresponse = response_from_string(signed_resp)
515+
516+
assert sresponse.signature == None
517+
518+
valid = self.server.sec.verify_signature(signed_resp,
519+
self.server.config.cert_file,
520+
node_name='urn:oasis:names:tc:SAML:2.0:assertion:Assertion',
521+
node_id=sresponse.assertion[0].id,
522+
id_attr="")
523+
assert valid
524+
525+
self.verify_assertion(sresponse.assertion)
526+
503527
def test_encrypted_signed_response_1(self):
504528

505529
cert_str, cert_key_str = generate_cert()
@@ -512,10 +536,10 @@ def test_encrypted_signed_response_1(self):
512536
name_id=self.name_id,
513537
sign_response=True,
514538
sign_assertion=True,
515-
encrypt_assertion=True,
539+
encrypt_assertion=False,
516540
encrypt_assertion_self_contained=True,
517541
encrypted_advice_attributes=True,
518-
encrypt_cert=cert_str,
542+
encrypt_cert_advice=cert_str,
519543
)
520544

521545
sresponse = response_from_string(signed_resp)
@@ -527,34 +551,26 @@ def test_encrypted_signed_response_1(self):
527551
id_attr="")
528552
assert valid
529553

554+
valid = self.server.sec.verify_signature(signed_resp,
555+
self.server.config.cert_file,
556+
node_name='urn:oasis:names:tc:SAML:2.0:assertion:Assertion',
557+
node_id=sresponse.assertion[0].id,
558+
id_attr="")
559+
560+
assert valid
561+
530562
_, key_file = make_temp("%s" % cert_key_str, decode=False)
531563

532564
decr_text = self.server.sec.decrypt(signed_resp, key_file)
533565

534566
resp = samlp.response_from_string(decr_text)
535567

536-
valid = self.server.sec.verify_signature(decr_text,
537-
self.server.config.cert_file,
538-
node_name='urn:oasis:names:tc:SAML:2.0:assertion:Assertion',
539-
node_id=resp.assertion[0].id,
540-
id_attr="")
541-
assert valid
542-
543568
assert resp.assertion[0].advice.encrypted_assertion[0].extension_elements
544569

545570
assertion = extension_elements_to_elements(resp.assertion[0].advice.encrypted_assertion[0].extension_elements,
546571
[saml, samlp])
547-
assert assertion
548-
assert assertion[0].attribute_statement
549572

550-
ava = ava = get_ava(assertion[0])
551-
552-
assert ava ==\
553-
{'mail': ['[email protected]'], 'givenname': ['Derek'], 'surname': ['Jeter'], 'title': ['The man']}
554-
555-
assert 'EncryptedAssertion><encas2:Assertion xmlns:encas0="http://www.w3.org/2000/09/xmldsig#" ' \
556-
'xmlns:encas1="http://www.w3.org/2001/XMLSchema-instance" ' \
557-
'xmlns:encas2="urn:oasis:names:tc:SAML:2.0:assertion"' in decr_text
573+
self.verify_assertion(assertion)
558574

559575
valid = self.server.sec.verify_signature(decr_text,
560576
self.server.config.cert_file,
@@ -573,7 +589,7 @@ def test_encrypted_signed_response_2(self):
573589
"urn:mace:example.com:saml:roland:sp", # sp_entity_id
574590
name_id=self.name_id,
575591
sign_response=True,
576-
sign_assertion=True,
592+
sign_assertion=False,
577593
encrypt_assertion=True,
578594
encrypt_assertion_self_contained=True,
579595
encrypt_cert=cert_str,
@@ -588,33 +604,16 @@ def test_encrypted_signed_response_2(self):
588604
id_attr="")
589605
assert valid
590606

591-
_, key_file = make_temp("%s" % cert_key_str, decode=False)
592-
593-
decr_text = self.server.sec.decrypt(signed_resp, key_file)
607+
decr_text = self.server.sec.decrypt(signed_resp, self.client.config.key_file)
594608

595609
resp = samlp.response_from_string(decr_text)
596610

597-
assert resp.encrypted_assertion[0].extension_elements
598-
599-
assertion = extension_elements_to_elements(resp.encrypted_assertion[0].extension_elements, [saml, samlp])
600-
assert assertion
601-
assert assertion[0].attribute_statement
611+
resp.assertion = extension_elements_to_elements(resp.encrypted_assertion[0].extension_elements, [saml, samlp])
602612

603-
ava = get_ava(assertion[0])
613+
assert resp.assertion[0].signature == None
604614

605-
assert ava ==\
606-
{'mail': ['[email protected]'], 'givenname': ['Derek'], 'surname': ['Jeter'], 'title': ['The man']}
607-
608-
assert 'EncryptedAssertion><encas2:Assertion xmlns:encas0="http://www.w3.org/2000/09/xmldsig#" ' \
609-
'xmlns:encas1="http://www.w3.org/2001/XMLSchema-instance" ' \
610-
'xmlns:encas2="urn:oasis:names:tc:SAML:2.0:assertion"' in decr_text
615+
self.verify_assertion(resp.assertion)
611616

612-
valid = self.server.sec.verify_signature(decr_text,
613-
self.server.config.cert_file,
614-
node_name='urn:oasis:names:tc:SAML:2.0:assertion:Assertion',
615-
node_id=assertion[0].id,
616-
id_attr="")
617-
assert valid
618617

619618
def test_encrypted_signed_response_3(self):
620619
cert_str, cert_key_str = generate_cert()
@@ -628,7 +627,8 @@ def test_encrypted_signed_response_3(self):
628627
sign_response=True,
629628
sign_assertion=True,
630629
encrypt_assertion=True,
631-
encrypt_cert=cert_str,
630+
encrypt_assertion_self_contained=False,
631+
encrypt_cert_assertion=cert_str,
632632
)
633633

634634
sresponse = response_from_string(signed_resp)
@@ -646,27 +646,24 @@ def test_encrypted_signed_response_3(self):
646646

647647
resp = samlp.response_from_string(decr_text)
648648

649-
assert resp.encrypted_assertion[0].extension_elements
650-
651-
assertion = extension_elements_to_elements(resp.encrypted_assertion[0].extension_elements, [saml, samlp])
652-
assert assertion
653-
assert assertion[0].attribute_statement
654-
655-
ava = get_ava(assertion[0])
656-
657-
assert ava ==\
658-
{'mail': ['[email protected]'], 'givenname': ['Derek'], 'surname': ['Jeter'], 'title': ['The man']}
649+
resp.assertion = extension_elements_to_elements(resp.encrypted_assertion[0].extension_elements, [saml, samlp])
659650

660-
assert 'xmlns:encas' not in decr_text
661651

662652
valid = self.server.sec.verify_signature(decr_text,
663653
self.server.config.cert_file,
664654
node_name='urn:oasis:names:tc:SAML:2.0:assertion:Assertion',
665-
node_id=assertion[0].id,
655+
node_id=resp.assertion[0].id,
666656
id_attr="")
657+
667658
assert valid
668659

660+
self.verify_assertion(resp.assertion)
661+
662+
assert 'xmlns:encas' not in decr_text
663+
664+
669665
def test_encrypted_signed_response_4(self):
666+
670667
cert_str, cert_key_str = generate_cert()
671668

672669
signed_resp = self.server.create_authn_response(
@@ -678,8 +675,9 @@ def test_encrypted_signed_response_4(self):
678675
sign_response=True,
679676
sign_assertion=True,
680677
encrypt_assertion=True,
678+
encrypt_assertion_self_contained=True,
681679
encrypted_advice_attributes=True,
682-
encrypt_cert=cert_str,
680+
encrypt_cert_advice=cert_str,
683681
)
684682

685683
sresponse = response_from_string(signed_resp)
@@ -691,35 +689,30 @@ def test_encrypted_signed_response_4(self):
691689
id_attr="")
692690
assert valid
693691

694-
_, key_file = make_temp("%s" % cert_key_str, decode=False)
695-
696-
decr_text = self.server.sec.decrypt(signed_resp, key_file)
692+
decr_text = self.server.sec.decrypt(signed_resp, self.client.config.key_file)
697693

698694
resp = samlp.response_from_string(decr_text)
699695

696+
resp.assertion = extension_elements_to_elements(resp.encrypted_assertion[0].extension_elements, [saml, samlp])
697+
700698
valid = self.server.sec.verify_signature(decr_text,
701699
self.server.config.cert_file,
702700
node_name='urn:oasis:names:tc:SAML:2.0:assertion:Assertion',
703701
node_id=resp.assertion[0].id,
704702
id_attr="")
705-
assert valid
706-
707-
assert resp.assertion[0].advice.encrypted_assertion[0].extension_elements
708703

709-
assertion = extension_elements_to_elements(resp.assertion[0].advice.encrypted_assertion[0].extension_elements,
710-
[saml, samlp])
711-
assert assertion
712-
assert assertion[0].attribute_statement
704+
assert valid
713705

714-
ava = ava = get_ava(assertion[0])
706+
_, key_file = make_temp("%s" % cert_key_str, decode=False)
715707

716-
assert ava ==\
717-
{'mail': ['[email protected]'], 'givenname': ['Derek'], 'surname': ['Jeter'], 'title': ['The man']}
708+
decr_text = self.server.sec.decrypt(decr_text, key_file)
718709

719-
#Should work, but I suspect that xmlsec manipulates the xml to much while encrypting that the signature
720-
#is no longer working. :(
710+
resp = samlp.response_from_string(decr_text)
721711

722-
assert 'xmlns:encas' not in decr_text
712+
assertion = extension_elements_to_elements(resp.encrypted_assertion[0].extension_elements, [saml, samlp])
713+
assertion = \
714+
extension_elements_to_elements(assertion[0].advice.encrypted_assertion[0].extension_elements,[saml, samlp])
715+
self.verify_assertion(assertion)
723716

724717
valid = self.server.sec.verify_signature(decr_text,
725718
self.server.config.cert_file,
@@ -1079,4 +1072,4 @@ def test_1(self):
10791072
if __name__ == "__main__":
10801073
ts = TestServer1()
10811074
ts.setup_class()
1082-
ts.test_signed_response_1()
1075+
ts.test_encrypted_signed_response_4()

0 commit comments

Comments
 (0)