def test_encrypted_signed_response_4(self): cert_str, cert_key_str = generate_cert() signed_resp = self.server.create_authn_response( self.ava, "id12", # in_response_to "http://lingon.catalogix.se:8087/", # consumer_url "urn:mace:example.com:saml:roland:sp", # sp_entity_id name_id=self.name_id, sign_response=True, sign_assertion=True, encrypt_assertion=True, encrypt_assertion_self_contained=True, pefim=True, encrypt_cert_advice=cert_str, ) sresponse = response_from_string(signed_resp) valid = self.server.sec.verify_signature(signed_resp, self.server.config.cert_file, node_name='urn:oasis:names:tc:SAML:2.0:protocol:Response', node_id=sresponse.id, id_attr="") assert valid decr_text = self.server.sec.decrypt(signed_resp, self.client.config.encryption_keypairs[1]["key_file"]) resp = samlp.response_from_string(decr_text) resp.assertion = extension_elements_to_elements(resp.encrypted_assertion[0].extension_elements, [saml, samlp]) valid = self.server.sec.verify_signature(decr_text, self.server.config.cert_file, node_name='urn:oasis:names:tc:SAML:2.0:assertion:Assertion', node_id=resp.assertion[0].id, id_attr="") assert valid _, key_file = make_temp(cert_key_str, decode=False) decr_text = self.server.sec.decrypt(decr_text, key_file) resp = samlp.response_from_string(decr_text) assertion = extension_elements_to_elements(resp.encrypted_assertion[0].extension_elements, [saml, samlp]) assertion = \ extension_elements_to_elements(assertion[0].advice.encrypted_assertion[0].extension_elements,[saml, samlp]) self.verify_assertion(assertion) #PEFIM never signs assertion in advice assert assertion[0].signature is None #valid = self.server.sec.verify_signature(decr_text, # self.server.config.cert_file, # node_name='urn:oasis:names:tc:SAML:2.0:assertion:Assertion', # node_id=assertion[0].id, # id_attr="") assert valid
def test_encrypted_response_1(self): cert_str_advice, cert_key_str_advice = generate_cert() _resp = self.server.create_authn_response( self.ava, "id12", # in_response_to "http://lingon.catalogix.se:8087/", # consumer_url "urn:mace:example.com:saml:roland:sp", # sp_entity_id name_id=self.name_id, sign_response=False, sign_assertion=False, encrypt_assertion=False, encrypt_assertion_self_contained=True, pefim=True, encrypt_cert_advice=cert_str_advice, ) _resp = "%s" % _resp sresponse = response_from_string(_resp) assert sresponse.signature is None _, key_file = make_temp(cert_key_str_advice, decode=False) decr_text = self.server.sec.decrypt(_resp, key_file) resp = samlp.response_from_string(decr_text) self.verify_advice_assertion(resp, decr_text)
def test_encrypted_response_7(self): _resp = self.server.create_authn_response( self.ava, "id12", # in_response_to "http://lingon.catalogix.se:8087/", # consumer_url "urn:mace:example.com:saml:roland:sp", # sp_entity_id name_id=self.name_id, sign_response=False, sign_assertion=False, encrypt_assertion=True, encrypt_assertion_self_contained=True, pefim=True ) sresponse = response_from_string(_resp) assert sresponse.signature is None decr_text_1 = self.server.sec.decrypt(_resp, self.client.config.encryption_keypairs[1]["key_file"]) decr_text_2 = self.server.sec.decrypt(decr_text_1, self.client.config.encryption_keypairs[1]["key_file"]) resp = samlp.response_from_string(decr_text_2) resp.assertion = extension_elements_to_elements(resp.encrypted_assertion[0].extension_elements, [saml, samlp]) self.verify_advice_assertion(resp, decr_text_2)
def test_encrypted_signed_response_2(self): cert_str, cert_key_str = generate_cert() signed_resp = self.server.create_authn_response( self.ava, "id12", # in_response_to "http://lingon.catalogix.se:8087/", # consumer_url "urn:mace:example.com:saml:roland:sp", # sp_entity_id name_id=self.name_id, sign_response=True, sign_assertion=False, encrypt_assertion=True, encrypt_assertion_self_contained=True, ) sresponse = response_from_string(signed_resp) valid = self.server.sec.verify_signature(signed_resp, self.server.config.cert_file, node_name='urn:oasis:names:tc:SAML:2.0:protocol:Response', node_id=sresponse.id, id_attr="") assert valid decr_text = self.server.sec.decrypt(signed_resp, self.client.config.key_file) resp = samlp.response_from_string(decr_text) resp.assertion = extension_elements_to_elements(resp.encrypted_assertion[0].extension_elements, [saml, samlp]) assert resp.assertion[0].signature == None self.verify_assertion(resp.assertion)
def test_encrypted_response_5(self): _resp = self.server.create_authn_response( self.ava, "id12", # in_response_to "http://lingon.catalogix.se:8087/", # consumer_url "urn:mace:example.com:saml:roland:sp", # sp_entity_id name_id=self.name_id, sign_response=False, sign_assertion=False, encrypt_assertion=False, encrypt_assertion_self_contained=True, #encrypted_advice_attributes=True, pefim=True ) _resp = "%s" % _resp sresponse = response_from_string(_resp) assert sresponse.signature is None decr_text = self.server.sec.decrypt(_resp, self.client.config.key_file) resp = samlp.response_from_string(decr_text) self.verify_advice_assertion(resp, decr_text)
def test_encrypted_response_3(self): cert_str_assertion, cert_key_str_assertion = generate_cert() _resp = self.server.create_authn_response( self.ava, "id12", # in_response_to "http://lingon.catalogix.se:8087/", # consumer_url "urn:mace:example.com:saml:roland:sp", # sp_entity_id name_id=self.name_id, sign_response=False, sign_assertion=False, encrypt_assertion=True, encrypt_assertion_self_contained=True, encrypted_advice_attributes=False, encrypt_cert_assertion=cert_str_assertion ) sresponse = response_from_string(_resp) assert sresponse.signature is None _, key_file = make_temp(cert_key_str_assertion, decode=False) decr_text = self.server.sec.decrypt(_resp, key_file) resp = samlp.response_from_string(decr_text) assert resp.encrypted_assertion[0].extension_elements assertion = extension_elements_to_elements(resp.encrypted_assertion[0].extension_elements, [saml, samlp]) self.verify_encrypted_assertion(assertion, decr_text)
def test_encrypted_signed_response_2(self): name_id = self.server.ident.transient_nameid( "urn:mace:example.com:saml:roland:sp", "id12") ava = {"givenName": ["Derek"], "surName": ["Jeter"], "mail": ["*****@*****.**"], "title": "The man"} cert_str, cert_key_str = generate_cert() signed_resp = self.server.create_authn_response( ava, "id12", # in_response_to "http://lingon.catalogix.se:8087/", # consumer_url "urn:mace:example.com:saml:roland:sp", # sp_entity_id name_id=name_id, sign_response=True, sign_assertion=True, encrypt_assertion=True, encrypt_assertion_self_contained=True, encrypt_cert=cert_str, ) sresponse = response_from_string(signed_resp) valid = self.server.sec.verify_signature(signed_resp, self.server.config.cert_file, node_name='urn:oasis:names:tc:SAML:2.0:protocol:Response', node_id=sresponse.id, id_attr="") assert valid _, key_file = make_temp("%s" % cert_key_str, decode=False) decr_text = self.server.sec.decrypt(signed_resp, key_file) resp = samlp.response_from_string(decr_text) assert resp.encrypted_assertion[0].extension_elements assertion = extension_elements_to_elements(resp.encrypted_assertion[0].extension_elements, [saml, samlp]) assert assertion assert assertion[0].attribute_statement ava = get_ava(assertion[0]) assert ava ==\ {'mail': ['*****@*****.**'], 'givenname': ['Derek'], 'surname': ['Jeter'], 'title': ['The man']} assert 'EncryptedAssertion><encas2:Assertion xmlns:encas0="http://www.w3.org/2000/09/xmldsig#" ' \ 'xmlns:encas1="http://www.w3.org/2001/XMLSchema-instance" ' \ 'xmlns:encas2="urn:oasis:names:tc:SAML:2.0:assertion"' in decr_text valid = self.server.sec.verify_signature(decr_text, self.server.config.cert_file, node_name='urn:oasis:names:tc:SAML:2.0:assertion:Assertion', node_id=assertion[0].id, id_attr="") assert valid
def parse_assertion(self, key_file=""): if self.context == "AuthnQuery": # can contain one or more assertions pass else: # This is a saml2int limitation try: assert len(self.response.assertion) == 1 or len(self.response.encrypted_assertion) == 1 except AssertionError: raise Exception("No assertion part") if self.response.encrypted_assertion: logger.debug("***Encrypted assertion/-s***") decr_text = self.sec.decrypt(self.xmlstr, key_file) resp = samlp.response_from_string(decr_text) res = self.decrypt_assertions(resp.encrypted_assertion, key_file) if self.response.assertion: self.response.assertion.extend(res) else: self.response.assertion = res self.response.encrypted_assertion = [] if self.response.assertion: logger.debug("***Unencrypted assertion***") for assertion in self.response.assertion: if not self._assertion(assertion): return False else: self.assertions.append(assertion) self.assertion = self.assertions[0] return True
def test_authn_response_0(self): ava = { "givenName": ["Derek"], "surName": ["Jeter"], "mail": ["*****@*****.**"]} resp_str = self.server.authn_response(ava, "id1", "http://*****:*****@example.com") response = samlp.response_from_string("\n".join(resp_str)) print response.keyswv() assert _eq(response.keyswv(),['status', 'destination', 'assertion', 'in_response_to', 'issue_instant', 'version', 'issuer', 'id']) print response.assertion[0].keyswv() assert len(response.assertion) == 1 assert _eq(response.assertion[0].keyswv(), ['authn_statement', 'attribute_statement', 'subject', 'issue_instant', 'version', 'issuer', 'conditions', 'id']) assertion = response.assertion[0] assert len(assertion.attribute_statement) == 1 astate = assertion.attribute_statement[0] print astate assert len(astate.attribute) == 3
def test_sign_response(self): response = factory(samlp.Response, assertion=self._assertion, id="22222", signature=sigver.pre_signature_part("22222", self.sec .my_cert)) to_sign = [(class_name(self._assertion), self._assertion.id), (class_name(response), response.id)] s_response = sigver.signed_instance_factory(response, self.sec, to_sign) assert s_response is not None print(s_response) response = response_from_string(s_response) sass = response.assertion[0] print(sass) assert _eq(sass.keyswv(), ['attribute_statement', 'issue_instant', 'version', 'signature', 'id']) assert sass.version == "2.0" assert sass.id == "11111" item = self.sec.check_signature(response, class_name(response), s_response) assert isinstance(item, samlp.Response) assert item.id == "22222"
def test_sign_verify_with_cert_from_instance(self): response = factory(samlp.Response, assertion=self._assertion, id="22222", signature=sigver.pre_signature_part("22222", self.sec .my_cert)) to_sign = [(class_name(self._assertion), self._assertion.id), (class_name(response), response.id)] s_response = sigver.signed_instance_factory(response, self.sec, to_sign) response2 = response_from_string(s_response) ci = "".join(sigver.cert_from_instance(response2)[0].split()) assert ci == self.sec.my_cert res = self.sec.verify_signature(s_response, node_name=class_name(samlp.Response())) assert res res = self.sec._check_signature(s_response, response2, class_name(response2), s_response) assert res == response2
def test_multiple_signatures_response(self): response = factory( samlp.Response, assertion=self._assertion, id="22222", signature=sigver.pre_signature_part("22222", self.sec.my_cert), ) # order is important, we can't validate if the signatures are made # in the reverse order to_sign = [(self._assertion, self._assertion.id, ""), (response, response.id, "")] s_response = self.sec.multiple_signatures("%s" % response, to_sign) assert s_response is not None response = response_from_string(s_response) item = self.sec.check_signature(response, class_name(response), s_response, must=True) assert item == response assert item.id == "22222" s_assertion = item.assertion[0] assert isinstance(s_assertion, saml.Assertion) # make sure the assertion was modified when we supposedly signed it assert s_assertion != self._assertion ci = "".join(sigver.cert_from_instance(s_assertion)[0].split()) assert ci == self.sec.my_cert res = self.sec.check_signature(s_assertion, class_name(s_assertion), s_response, must=True) assert res == s_assertion assert s_assertion.id == "11111" assert s_assertion.version == "2.0" assert _eq(s_assertion.keyswv(), ["attribute_statement", "issue_instant", "version", "signature", "id"])
def test_exception_sign_verify_with_cert_from_instance(self): assertion = factory(saml.Assertion, version="2.0", id="11100", issue_instant="2009-10-30T13:20:28Z", #signature= sigver.pre_signature_part("11100", # self.sec.my_cert), attribute_statement=do_attribute_statement({ ("", "", "surName"): ("Foo", ""), ("", "", "givenName"): ("Bar", ""), }) ) response = factory(samlp.Response, assertion=assertion, id="22222", signature=sigver.pre_signature_part("22222", self.sec .my_cert)) to_sign = [(class_name(response), response.id)] s_response = sigver.signed_instance_factory(response, self.sec, to_sign) response2 = response_from_string(s_response) # Change something that should make everything fail response2.id = "23456" raises(sigver.SignatureError, self.sec._check_signature, s_response, response2, class_name(response2))
def test_signed_response_2(self): signed_resp = self.server.create_authn_response( self.ava, "id12", # in_response_to "http://lingon.catalogix.se:8087/", # consumer_url "urn:mace:example.com:saml:roland:sp", # sp_entity_id name_id=self.name_id, sign_response=True, sign_assertion=True, sign_alg=ds.SIG_RSA_SHA256, digest_alg=ds.DIGEST_SHA256 ) sresponse = response_from_string(signed_resp) assert ds.SIG_RSA_SHA256 in str(sresponse), "Not correctly signed!" assert ds.DIGEST_SHA256 in str(sresponse), "Not correctly signed!" valid = self.server.sec.verify_signature(signed_resp, self.server.config.cert_file, node_name='urn:oasis:names:tc:SAML:2.0:protocol:Response', node_id=sresponse.id, id_attr="") assert valid assert ds.SIG_RSA_SHA256 in str(sresponse.assertion[0]), "Not correctly signed!" assert ds.DIGEST_SHA256 in str(sresponse.assertion[0]), "Not correctly signed!" valid = self.server.sec.verify_signature(signed_resp, self.server.config.cert_file, node_name='urn:oasis:names:tc:SAML:2.0:assertion:Assertion', node_id=sresponse.assertion[0].id, id_attr="") assert valid self.verify_assertion(sresponse.assertion)
def correctly_signed_response(self, decoded_xml, must=False, origdoc=None): """ Check if a instance is correctly signed, if we have metadata for the IdP that sent the info use that, if not use the key that are in the message if any. :param decoded_xml: The SAML message as a XML string :param must: Whether there must be a signature :return: None if the signature can not be verified otherwise an instance """ response = samlp.response_from_string(decoded_xml) if not response: raise TypeError("Not a Response") if response.signature: self._check_signature(decoded_xml, response, class_name(response), origdoc) if response.assertion: # Try to find the signing cert in the assertion for assertion in response.assertion: if not assertion.signature: logger.debug("unsigned") if must: raise SignatureError("Signature missing") continue else: logger.debug("signed") try: self._check_signature(decoded_xml, assertion, class_name(assertion), origdoc) except Exception, exc: logger.error("correctly_signed_response: %s" % exc) raise
def testAccessors(self): """Test for Response accessors""" self.response.id = "response id" self.response.in_response_to = "request id" self.response.version = saml2.VERSION self.response.issue_instant = "2007-09-14T01:05:02Z" self.response.destination = "http://www.example.com/Destination" self.response.consent = saml.CONSENT_UNSPECIFIED self.response.issuer = saml.Issuer() self.response.signature = ds.Signature() self.response.extensions = samlp.Extensions() self.response.status = samlp.Status() self.response.assertion.append(saml.Assertion()) self.response.encrypted_assertion.append(saml.EncryptedAssertion()) new_response = samlp.response_from_string(self.response.to_string()) assert new_response.id == "response id" assert new_response.in_response_to == "request id" assert new_response.version == saml2.VERSION assert new_response.issue_instant == "2007-09-14T01:05:02Z" assert new_response.destination == "http://www.example.com/Destination" assert new_response.consent == saml.CONSENT_UNSPECIFIED assert isinstance(new_response.issuer, saml.Issuer) assert isinstance(new_response.signature, ds.Signature) assert isinstance(new_response.extensions, samlp.Extensions) assert isinstance(new_response.status, samlp.Status) assert isinstance(new_response.assertion[0], saml.Assertion) assert isinstance(new_response.encrypted_assertion[0], saml.EncryptedAssertion)
def test_sign_response_2(self): assertion2 = factory( saml.Assertion, version= "2.0", id= "11122", issue_instant= "2009-10-30T13:20:28Z", signature= sigver.pre_signature_part("11122", self.sec.my_cert), attribute_statement=do_attribute_statement({ ("","","surName"): ("Fox",""), ("","","givenName") :("Bear",""), }) ) response = factory(samlp.Response, assertion=assertion2, id="22233", signature=sigver.pre_signature_part("22233", self.sec.my_cert)) to_sign = [(class_name(assertion2), assertion2.id), (class_name(response), response.id)] s_response = sigver.signed_instance_factory(response, self.sec, to_sign) assert s_response is not None response2 = response_from_string(s_response) sass = response2.assertion[0] assert _eq(sass.keyswv(), ['attribute_statement', 'issue_instant', 'version', 'signature', 'id']) assert sass.version == "2.0" assert sass.id == "11122" item = self.sec.check_signature(response2, class_name(response), s_response) assert isinstance(item, samlp.Response)
def test_authn_response_0(self): conf = config.SPConfig() conf.load_file("server_conf") self.client = client.Saml2Client(conf) ava = {"givenName": ["Derek"], "sn": ["Jeter"], "mail": ["*****@*****.**"], "title": "The man"} npolicy = samlp.NameIDPolicy(format=saml.NAMEID_FORMAT_TRANSIENT, allow_create="true") resp_str = "%s" % self.server.create_authn_response( ava, "id1", "http://*****:*****@example.com", authn=AUTHN) response = samlp.response_from_string(resp_str) print(response.keyswv()) assert _eq(response.keyswv(), ['status', 'destination', 'assertion', 'in_response_to', 'issue_instant', 'version', 'issuer', 'id']) print(response.assertion[0].keyswv()) assert len(response.assertion) == 1 assert _eq(response.assertion[0].keyswv(), ['attribute_statement', 'issue_instant', 'version', 'subject', 'conditions', 'id', 'issuer', 'authn_statement']) assertion = response.assertion[0] assert len(assertion.attribute_statement) == 1 astate = assertion.attribute_statement[0] print(astate) assert len(astate.attribute) == 4
def test_signed_response_3(self): signed_resp = self.server.create_authn_response( self.ava, "id12", # in_response_to "http://lingon.catalogix.se:8087/", # consumer_url "urn:mace:example.com:saml:roland:sp", # sp_entity_id name_id=self.name_id, sign_response=False, sign_assertion=True, ) sresponse = response_from_string(signed_resp) assert sresponse.signature == None valid = self.server.sec.verify_signature(signed_resp, self.server.config.cert_file, node_name='urn:oasis:names:tc:SAML:2.0:assertion:Assertion', node_id=sresponse.assertion[0].id, id_attr="") assert valid self.verify_assertion(sresponse.assertion)
def test_signed_response(self): name_id = self.server.ident.transient_nameid( "urn:mace:example.com:saml:roland:sp", "id12") ava = {"givenName": ["Derek"], "sn": ["Jeter"], "mail": ["*****@*****.**"], "title": "The man"} signed_resp = self.server.create_authn_response( ava, "id12", # in_response_to "http://lingon.catalogix.se:8087/", # consumer_url "urn:mace:example.com:saml:roland:sp", # sp_entity_id name_id=name_id, sign_assertion=True ) print(signed_resp) assert signed_resp sresponse = response_from_string(signed_resp) # It's the assertions that are signed not the response per se assert len(sresponse.assertion) == 1 assertion = sresponse.assertion[0] # Since the reponse is created dynamically I don't know the signature # value. Just that there should be one assert assertion.signature.signature_value.text != ""
def test_cert_from_instance_1(): xml_response = open(SIGNED).read() response = samlp.response_from_string(xml_response) assertion = response.assertion[0] certs = sigver.cert_from_instance(assertion) assert len(certs) == 1 print(certs[0]) assert certs[0] == CERT1
def test_encrypted_signed_response_2(self): cert_str, cert_key_str = generate_cert() signed_resp = self.server.create_authn_response( self.ava, "id12", # in_response_to "http://lingon.catalogix.se:8087/", # consumer_url "urn:mace:example.com:saml:roland:sp", # sp_entity_id name_id=self.name_id, sign_response=True, sign_assertion=False, encrypt_assertion=True, encrypt_assertion_self_contained=True, ) sresponse = response_from_string(signed_resp) valid = self.server.sec.verify_signature( signed_resp, self.server.config.cert_file, node_name='urn:oasis:names:tc:SAML:2.0:protocol:Response', node_id=sresponse.id, id_attr="") assert valid decr_text_old = copy.deepcopy("%s" % signed_resp) decr_text = self.server.sec.decrypt( signed_resp, self.client.config.encryption_keypairs[0]["key_file"]) assert decr_text == decr_text_old decr_text = self.server.sec.decrypt( signed_resp, self.client.config.encryption_keypairs[1]["key_file"]) assert decr_text != decr_text_old resp = samlp.response_from_string(decr_text) resp.assertion = extension_elements_to_elements( resp.encrypted_assertion[0].extension_elements, [saml, samlp]) assert resp.assertion[0].signature == None self.verify_assertion(resp.assertion)
def test_encrypted_signed_response_3(self): cert_str, cert_key_str = generate_cert() signed_resp = self.server.create_authn_response( self.ava, "id12", # in_response_to "http://lingon.catalogix.se:8087/", # consumer_url "urn:mace:example.com:saml:roland:sp", # sp_entity_id name_id=self.name_id, sign_response=True, sign_assertion=True, encrypt_assertion=True, encrypt_assertion_self_contained=False, encrypt_cert_assertion=cert_str, ) sresponse = response_from_string(signed_resp) valid = self.server.sec.verify_signature(signed_resp, self.server.config.cert_file, node_name='urn:oasis:names:tc:SAML:2.0:protocol:Response', node_id=sresponse.id, id_attr="") assert valid _, key_file = make_temp(str(cert_key_str).encode('ascii'), decode=False) decr_text = self.server.sec.decrypt(signed_resp, key_file) resp = samlp.response_from_string(decr_text) resp.assertion = extension_elements_to_elements(resp.encrypted_assertion[0].extension_elements, [saml, samlp]) valid = self.server.sec.verify_signature(decr_text, self.server.config.cert_file, node_name='urn:oasis:names:tc:SAML:2.0:assertion:Assertion', node_id=resp.assertion[0].id, id_attr="") assert valid self.verify_assertion(resp.assertion) assert 'xmlns:encas' not in decr_text
def get_metadata(self, xmlstr): response = samlp.response_from_string(xmlstr) issuer = response.issuer.text.replace('http://', 'https://') meta_url = issuer + '/metadata' xml_response = requests.get(meta_url, timeout=5) metadata = xml_response.text return self.manipulate_metadata(metadata, response)
def test_cert_from_instance_ssp(): xml_response = open(SIMPLE_SAML_PHP_RESPONSE).read() response = samlp.response_from_string(xml_response) assertion = response.assertion[0] certs = sigver.cert_from_instance(assertion) assert len(certs) == 1 assert certs[0] == CERT_SSP der = base64.b64decode(certs[0]) print str(decoder.decode(der)).replace('.',"\n.") assert decoder.decode(der)
def test_cert_from_instance_ssp(): xml_response = open(SIMPLE_SAML_PHP_RESPONSE).read() response = samlp.response_from_string(xml_response) assertion = response.assertion[0] certs = sigver.cert_from_instance(assertion) assert len(certs) == 1 assert certs[0] == CERT_SSP der = base64.b64decode(certs[0]) print(str(decoder.decode(der)).replace('.', "\n.")) assert decoder.decode(der)
def test_unsolicited_response(self): """ """ self.server = Server("idp_conf") conf = config.SPConfig() conf.load_file("server_conf") self.client = Saml2Client(conf) for subject in self.client.users.subjects(): self.client.users.remove_person(subject) IDP = "urn:mace:example.com:saml:roland:idp" ava = { "givenName": ["Derek"], "surname": ["Jeter"], "mail": ["*****@*****.**"] } resp_str = "\n".join( self.server.authn_response( identity=ava, in_response_to="id1", destination="http://lingon.catalogix.se:8087/", sp_entity_id="urn:mace:example.com:saml:roland:sp", name_id_policy=samlp.NameIDPolicy( format=saml.NAMEID_FORMAT_PERSISTENT), userid="*****@*****.**")) resp_str = base64.encodestring(resp_str) self.client.allow_unsolicited = True authn_response = self.client.response({"SAMLResponse": resp_str}, ()) assert authn_response is not None assert authn_response.issuer() == IDP assert authn_response.response.assertion[0].issuer.text == IDP session_info = authn_response.session_info() print session_info assert session_info["ava"] == { 'mail': ['*****@*****.**'], 'givenName': ['Derek'], 'sn': ['Jeter'] } assert session_info["issuer"] == IDP assert session_info["came_from"] == "" response = samlp.response_from_string(authn_response.xmlstr) assert response.destination == "http://lingon.catalogix.se:8087/" # One person in the cache assert len(self.client.users.subjects()) == 1
def test_encrypted_response_6(self): _server = Server("idp_conf_verify_cert") cert_str_advice, cert_key_str_advice = generate_cert() cert_str_assertion, cert_key_str_assertion = generate_cert() _resp = _server.create_authn_response( self.ava, "id12", # in_response_to "http://lingon.catalogix.se:8087/", # consumer_url "urn:mace:example.com:saml:roland:sp", # sp_entity_id name_id=self.name_id, sign_response=False, sign_assertion=False, encrypt_assertion=True, encrypt_assertion_self_contained=True, pefim=True, encrypt_cert_advice=cert_str_advice, encrypt_cert_assertion=cert_str_assertion) sresponse = response_from_string(_resp) assert sresponse.signature is None _, key_file = make_temp(cert_key_str_assertion, decode=False) decr_text_1 = _server.sec.decrypt(_resp, key_file) _, key_file = make_temp(cert_key_str_advice, decode=False) decr_text_2 = _server.sec.decrypt(decr_text_1, key_file) resp = samlp.response_from_string(decr_text_2) resp.assertion = extension_elements_to_elements( resp.encrypted_assertion[0].extension_elements, [saml, samlp]) self.verify_advice_assertion(resp, decr_text_2)
def parse_assertion(self, key_file="", decrypt=True): if self.context == "AuthnQuery": # can contain one or more assertions pass else: # This is a saml2int limitation try: assert len(self.response.assertion) == 1 or \ len(self.response.encrypted_assertion) == 1 except AssertionError: raise Exception("No assertion part") res = [] has_encrypted_assertions = self.response.encrypted_assertion if not has_encrypted_assertions and self.response.assertion: for tmp_assertion in self.response.assertion: if tmp_assertion.advice: if tmp_assertion.advice.encrypted_assertion: has_encrypted_assertions = True break if has_encrypted_assertions and decrypt: logger.debug("***Encrypted assertion/-s***") decr_text = self.sec.decrypt(self.xmlstr, key_file) resp = samlp.response_from_string(decr_text) res = self.decrypt_assertions(resp.encrypted_assertion, decr_text) if resp.assertion: for tmp_ass in resp.assertion: if tmp_ass.advice and tmp_ass.advice.encrypted_assertion: advice_res = self.decrypt_assertions(tmp_ass.advice.encrypted_assertion, decr_text) if tmp_ass.advice.assertion: tmp_ass.advice.assertion.extend(advice_res) else: tmp_ass.advice.assertion = advice_res tmp_ass.advice.encrypted_assertion = [] self.response.assertion = resp.assertion if self.response.assertion: self.response.assertion.extend(res) else: self.response.assertion = res self.xmlstr = decr_text self.response.encrypted_assertion = [] if self.response.assertion: logger.debug("***Unencrypted assertion***") for assertion in self.response.assertion: if not self._assertion(assertion, assertion in res): return False else: self.assertions.append(assertion) self.assertion = self.assertions[0] return True
def test_unsolicited_response(self): """ """ self.server = Server("idp_conf") conf = config.SPConfig() conf.load_file("server_conf") self.client = Saml2Client(conf) for subject in self.client.users.subjects(): self.client.users.remove_person(subject) IDP = "urn:mace:example.com:saml:roland:idp" ava = { "givenName": ["Derek"], "surName": ["Jeter"], "mail": ["*****@*****.**"]} resp_str = "%s" % self.server.create_authn_response( identity=ava, in_response_to="id1", destination="http://lingon.catalogix.se:8087/", sp_entity_id="urn:mace:example.com:saml:roland:sp", name_id_policy=samlp.NameIDPolicy( format=saml.NAMEID_FORMAT_PERSISTENT), userid="*****@*****.**") resp_str = base64.encodestring(resp_str) self.client.allow_unsolicited = True authn_response = self.client.authn_request_response( {"SAMLResponse":resp_str}, ()) assert authn_response is not None assert authn_response.issuer() == IDP assert authn_response.response.assertion[0].issuer.text == IDP session_info = authn_response.session_info() print session_info assert session_info["ava"] == {'mail': ['*****@*****.**'], 'givenName': ['Derek'], 'surName': ['Jeter']} assert session_info["issuer"] == IDP assert session_info["came_from"] == "" response = samlp.response_from_string(authn_response.xmlstr) assert response.destination == "http://lingon.catalogix.se:8087/" # One person in the cache assert len(self.client.users.subjects()) == 1
def create_authn_response(session_id, identity=dict(), sign=True): config = IdPConfig() config.load(idp_config) idp_server = Server(config=config) idp_server.ident = Identifier(auth.AuthDictCache(dict(), '_ident')) authn_response = str(idp_server.authn_response( identity=identity, in_response_to=session_id, destination='https://foo.example.com/sp/acs', sp_entity_id='https://foo.example.com/sp/metadata', name_id_policy=None, userid='Irrelevent', sign=sign, instance=True)) response = samlp.response_from_string(authn_response) return response.assertion[0].subject.name_id.text, authn_response
def __init__(self, authn_response='', issuer='', nameid_formats=['urn:oasis:names:tc:SAML:2.0:nameid-format:transient'], recipient='spidSaml2/acs/post', accepted_time_diff=60, in_response_to='', requester='', authn_context_class_ref='https://www.spid.gov.it/SpidL2', return_addrs = []): self.response = samlp.response_from_string(authn_response) self.nameid_formats = nameid_formats self.recipient = recipient self.accepted_time_diff = accepted_time_diff self.authn_context_class_ref = authn_context_class_ref self.in_response_to = in_response_to self.requester = requester self.return_addrs = return_addrs
def create_authn_response(session_id, identity=dict(), sign=True): config = IdPConfig() config.load(idp_config) idp_server = Server(config=config) idp_server.ident = Identifier(auth.AuthDictCache(dict(), '_ident')) authn_response = str( idp_server.authn_response( identity=identity, in_response_to=session_id, destination='https://foo.example.com/sp/acs', sp_entity_id='https://foo.example.com/sp/metadata', name_id_policy=None, userid='Irrelevent', sign=sign, instance=True)) response = samlp.response_from_string(authn_response) return response.assertion[0].subject.name_id.text, authn_response
def test_sign_response_2(self): assertion2 = factory( saml.Assertion, version="2.0", id="id-11122", issuer=saml.Issuer(text="the-issuer-2"), issue_instant="2009-10-30T13:20:28Z", signature=sigver.pre_signature_part("id-11122", self.sec .my_cert), attribute_statement=do_attribute_statement({ ("name:surName", "nameformat", "surName"): ("Fox", ""), ("name:givenName", "nameformat", "givenName"): ("Bear", ""), }) ) response = factory( samlp.Response, issuer=saml.Issuer(text="the-isser-2"), status=success_status_factory(), assertion=assertion2, version="2.0", issue_instant="2099-10-30T13:20:28Z", id="id-22233", signature=sigver.pre_signature_part("id-22233", self.sec.my_cert), ) to_sign = [(class_name(assertion2), assertion2.id), (class_name(response), response.id)] s_response = sigver.signed_instance_factory(response, self.sec, to_sign) assert s_response is not None response2 = response_from_string(s_response) sass = response2.assertion[0] ['signature', 'attribute_statement', 'version', 'id', 'issue_instant'] ['issuer', 'attribute_statement', 'issue_instant', 'version', 'signature', 'id'] assert _eq(sass.keyswv(), ['issuer', 'attribute_statement', 'issue_instant', 'version', 'signature', 'id']) assert sass.version == "2.0" assert sass.id == "id-11122" item = self.sec.check_signature(response2, class_name(response), s_response) assert isinstance(item, samlp.Response)
def _encrypted_assertion(self, xmlstr): if xmlstr.encrypted_data: assertion_str = self.sec.decrypt(xmlstr.encrypted_data.to_string()) assertion = saml.assertion_from_string(assertion_str) else: decrypt_xml = self.sec.decrypt(xmlstr) logger.debug("Decryption successfull") self.response = samlp.response_from_string(decrypt_xml) logger.debug("Parsed decrypted assertion successfull") enc = self.response.encrypted_assertion[0].extension_elements[0] assertion = extension_element_to_element( enc, saml.ELEMENT_FROM_STRING, namespace=saml.NAMESPACE) logger.debug("Decrypted Assertion: %s" % assertion) return self._assertion(assertion)
def _encrypted_assertion(self, xmlstr): if xmlstr.encrypted_data: assertion_str = self.sec.decrypt(xmlstr.encrypted_data) assertion = saml.assertion_from_string(assertion_str) else: decrypt_xml = self.sec.decrypt(xmlstr) logger.debug("Decryption successfull") self.response = samlp.response_from_string(decrypt_xml) logger.debug("Parsed decrypted assertion successfull") enc = self.response.encrypted_assertion[0].extension_elements[0] assertion = extension_element_to_element(enc, saml.ELEMENT_FROM_STRING, namespace=saml.NAMESPACE) logger.debug("Decrypted Assertion: %s" % assertion) return self._assertion(assertion)
def test_authn_response_0(self): self.server = Server("idp_conf") conf = config.SPConfig() conf.load_file("server_conf") self.client = client.Saml2Client(conf) ava = { "givenName": ["Derek"], "surName": ["Jeter"], "mail": ["*****@*****.**"], "title": "The man" } npolicy = samlp.NameIDPolicy(format=saml.NAMEID_FORMAT_TRANSIENT, allow_create="true") resp_str = "%s" % self.server.create_authn_response( ava, "id1", "http://*****:*****@example.com", authn=AUTHN) response = samlp.response_from_string(resp_str) print((response.keyswv())) assert _eq(response.keyswv(), [ 'status', 'destination', 'assertion', 'in_response_to', 'issue_instant', 'version', 'issuer', 'id' ]) print((response.assertion[0].keyswv())) assert len(response.assertion) == 1 assert _eq(response.assertion[0].keyswv(), [ 'attribute_statement', 'issue_instant', 'version', 'subject', 'conditions', 'id', 'issuer', 'authn_statement' ]) assertion = response.assertion[0] assert len(assertion.attribute_statement) == 1 astate = assertion.attribute_statement[0] print(astate) assert len(astate.attribute) == 4
def test_multiple_signatures_response(self): response = factory(samlp.Response, assertion=self._assertion, id="22222", signature=sigver.pre_signature_part( "22222", self.sec.my_cert)) # order is important, we can't validate if the signatures are made # in the reverse order to_sign = [(self._assertion, self._assertion.id, ''), (response, response.id, '')] s_response = self.sec.multiple_signatures("%s" % response, to_sign) assert s_response is not None response = response_from_string(s_response) item = self.sec.check_signature(response, class_name(response), s_response, must=True) assert item == response assert item.id == "22222" s_assertion = item.assertion[0] assert isinstance(s_assertion, saml.Assertion) # make sure the assertion was modified when we supposedly signed it assert s_assertion != self._assertion ci = "".join(sigver.cert_from_instance(s_assertion)[0].split()) assert ci == self.sec.my_cert res = self.sec.check_signature(s_assertion, class_name(s_assertion), s_response, must=True) assert res == s_assertion assert s_assertion.id == "11111" assert s_assertion.version == "2.0" assert _eq(s_assertion.keyswv(), [ 'attribute_statement', 'issue_instant', 'version', 'signature', 'id' ])
def test_signed_response_2(self): signed_resp = self.server.create_authn_response( self.ava, "id12", # in_response_to "http://lingon.catalogix.se:8087/", # consumer_url "urn:mace:example.com:saml:roland:sp", # sp_entity_id name_id=self.name_id, sign_response=True, sign_assertion=False, ) sresponse = response_from_string(signed_resp) valid = self.server.sec.verify_signature( signed_resp, self.server.config.cert_file, node_name='urn:oasis:names:tc:SAML:2.0:protocol:Response', node_id=sresponse.id, id_attr="") assert valid assert sresponse.assertion[0].signature == None
def test_signed_response(self): print(ds.DefaultSignature().get_digest_alg()) name_id = self.server.ident.transient_nameid( "urn:mace:example.com:saml:roland:sp", "id12") ava = {"givenName": ["Derek"], "surName": ["Jeter"], "mail": ["*****@*****.**"], "title": "The man"} signed_resp = self.server.create_authn_response( ava, "id12", # in_response_to "http://lingon.catalogix.se:8087/", # consumer_url "urn:mace:example.com:saml:roland:sp", # sp_entity_id name_id=name_id, sign_assertion=True ) print(signed_resp) assert signed_resp sresponse = response_from_string(signed_resp) assert ds.SIG_RSA_SHA1 in str(sresponse), "Not correctly signed!" assert ds.DIGEST_SHA1 in str(sresponse), "Not correctly signed!"
def __init__( self, authn_response="", issuer="", nameid_formats=( "urn:oasis:names:tc:SAML:2.0:nameid-format:transient", ), recipient="spidSaml2/acs/post", accepted_time_diff=1, in_response_to="", requester="", authn_context_class_ref="https://www.spid.gov.it/SpidL2", return_addrs=(), ): self.response = samlp.response_from_string(authn_response) self.nameid_formats = nameid_formats self.recipient = recipient self.accepted_time_diff = accepted_time_diff or 300 self.authn_context_class_ref = authn_context_class_ref self.in_response_to = in_response_to self.requester = requester self.return_addrs = return_addrs
def test_sign_response_2(self): assertion2 = factory(saml.Assertion, version="2.0", id="11122", issue_instant="2009-10-30T13:20:28Z", signature=sigver.pre_signature_part( "11122", self.sec.my_cert), attribute_statement=do_attribute_statement({ ("", "", "surName"): ("Räv", ""), ("", "", "givenName"): ("Björn", ""), })) response = factory(samlp.Response, assertion=assertion2, id="22233", signature=sigver.pre_signature_part( "22233", self.sec.my_cert)) to_sign = [(class_name(assertion2), assertion2.id), (class_name(response), response.id)] s_response = sigver.signed_instance_factory(response, self.sec, to_sign) assert s_response is not None response2 = response_from_string(s_response) sass = response2.assertion[0] assert _eq(sass.keyswv(), [ 'attribute_statement', 'issue_instant', 'version', 'signature', 'id' ]) assert sass.version == "2.0" assert sass.id == "11122" item = self.sec.check_signature(response2, class_name(response), s_response) assert isinstance(item, samlp.Response)
def test_signed_response(self): print(ds.DefaultSignature().get_digest_alg()) name_id = self.server.ident.transient_nameid( "urn:mace:example.com:saml:roland:sp", "id12") ava = {"givenName": ["Derek"], "surName": ["Jeter"], "mail": ["*****@*****.**"], "title": "The man"} signed_resp = self.server.create_authn_response( ava, "id12", # in_response_to "http://lingon.catalogix.se:8087/", # consumer_url "urn:mace:example.com:saml:roland:sp", # sp_entity_id name_id=name_id, sign_assertion=True ) print(signed_resp) assert signed_resp sresponse = response_from_string(signed_resp) assert ds.SIG_RSA_SHA512 in str(sresponse), "Not correctly signed!" assert ds.DIGEST_SHA512 in str(sresponse), "Not correctly signed!"
def test_exception_sign_verify_with_cert_from_instance(self): assertion = factory( saml.Assertion, version="2.0", id="id-11100", issuer=saml.Issuer(text="the-issuer-2"), issue_instant="2009-10-30T13:20:28Z", attribute_statement=do_attribute_statement({ ("name:surName", "nameformat", "surName"): ("Foo", ""), ("name:givenName", "nameformat", "givenName"): ("Bar", ""), }) ) response = factory( samlp.Response, issuer=saml.Issuer(text="the-isser"), status=success_status_factory(), assertion=assertion, version="2.0", issue_instant="2099-10-30T13:20:28Z", id="id-22222", signature=sigver.pre_signature_part( "id-22222", self.sec.my_cert ), ) to_sign = [(class_name(response), response.id)] s_response = sigver.signed_instance_factory(response, self.sec, to_sign) response2 = response_from_string(s_response) # Change something that should make everything fail response2.id = "id-23456" with raises(sigver.SignatureError): self.sec._check_signature(s_response, response2, class_name(response2))
def assertion_id_request_response(self, response): """ Verify that the response is OK """ resp = samlp.response_from_string(response) return resp
def authn_query_response(self, response): """ Verify that the response is OK """ resp = samlp.response_from_string(response) return resp
def _response(self, in_response_to, consumer_url=None, status=None, issuer=None, sign=False, to_sign=None, sp_entity_id=None, encrypt_assertion=False, encrypt_assertion_self_contained=False, encrypted_advice_attributes=False, encrypt_cert_advice=None, encrypt_cert_assertion=None,sign_assertion=None, pefim=False, **kwargs): """ Create a Response. Encryption: encrypt_assertion must be true for encryption to be performed. If encrypted_advice_attributes also is true, then will the function try to encrypt the assertion in the the advice element of the main assertion. Only one assertion element is allowed in the advice element, if multiple assertions exists in the advice element the main assertion will be encrypted instead, since it's no point to encrypt If encrypted_advice_attributes is false the main assertion will be encrypted. Since the same key :param in_response_to: The session identifier of the request :param consumer_url: The URL which should receive the response :param status: The status of the response :param issuer: The issuer of the response :param sign: Whether the response should be signed or not :param to_sign: If there are other parts to sign :param sp_entity_id: Entity ID for the calling service provider. :param encrypt_assertion: True if assertions should be encrypted. :param encrypt_assertion_self_contained: True if all encrypted assertions should have alla namespaces selfcontained. :param encrypted_advice_attributes: True if assertions in the advice element should be encrypted. :param encrypt_cert_advice: Certificate to be used for encryption of assertions in the advice element. :param encrypt_cert_assertion: Certificate to be used for encryption of assertions. :param sign_assertion: True if assertions should be signed. :param pefim: True if a response according to the PEFIM profile should be created. :param kwargs: Extra key word arguments :return: A Response instance """ if not status: status = success_status_factory() _issuer = self._issuer(issuer) response = response_factory(issuer=_issuer, in_response_to=in_response_to, status=status) if consumer_url: response.destination = consumer_url self._add_info(response, **kwargs) if not sign and to_sign and not encrypt_assertion: return signed_instance_factory(response, self.sec, to_sign) has_encrypt_cert = self.has_encrypt_cert_in_metadata(sp_entity_id) if not has_encrypt_cert and encrypt_cert_advice is None: encrypted_advice_attributes = False if not has_encrypt_cert and encrypt_cert_assertion is None: encrypt_assertion = False if encrypt_assertion or (encrypted_advice_attributes and response.assertion.advice is not None and len(response.assertion.advice.assertion) == 1): if sign: response.signature = pre_signature_part(response.id, self.sec.my_cert, 1) sign_class = [(class_name(response), response.id)] cbxs = CryptoBackendXmlSec1(self.config.xmlsec_binary) encrypt_advice = False if encrypted_advice_attributes and response.assertion.advice is not None \ and len(response.assertion.advice.assertion) > 0: _assertions = response.assertion if not isinstance(_assertions, list): _assertions = [_assertions] for _assertion in _assertions: _assertion.advice.encrypted_assertion = [] _assertion.advice.encrypted_assertion.append(EncryptedAssertion()) _advice_assertions = copy.deepcopy(_assertion.advice.assertion) _assertion.advice.assertion = [] if not isinstance(_advice_assertions, list): _advice_assertions = [_advice_assertions] for tmp_assertion in _advice_assertions: to_sign_advice = [] if sign_assertion and not pefim: tmp_assertion.signature = pre_signature_part(tmp_assertion.id, self.sec.my_cert, 1) to_sign_advice.append((class_name(tmp_assertion), tmp_assertion.id)) #tmp_assertion = response.assertion.advice.assertion[0] _assertion.advice.encrypted_assertion[0].add_extension_element(tmp_assertion) if encrypt_assertion_self_contained: advice_tag = response.assertion.advice._to_element_tree().tag assertion_tag = tmp_assertion._to_element_tree().tag response = \ response.get_xml_string_with_self_contained_assertion_within_advice_encrypted_assertion( assertion_tag, advice_tag) node_xpath = ''.join(["/*[local-name()=\"%s\"]" % v for v in ["Response", "Assertion", "Advice", "EncryptedAssertion", "Assertion"]]) if to_sign_advice: response = signed_instance_factory(response, self.sec, to_sign_advice) response = self._encrypt_assertion(encrypt_cert_advice, sp_entity_id, response, node_xpath=node_xpath) response = response_from_string(response) if encrypt_assertion: to_sign_assertion = [] if sign_assertion is not None and sign_assertion: _assertions = response.assertion if not isinstance(_assertions, list): _assertions = [_assertions] for _assertion in _assertions: _assertion.signature = pre_signature_part(_assertion.id, self.sec.my_cert, 1) to_sign_assertion.append((class_name(_assertion), _assertion.id)) if encrypt_assertion_self_contained: try: assertion_tag = response.assertion._to_element_tree().tag except: assertion_tag = response.assertion[0]._to_element_tree().tag response = pre_encrypt_assertion(response) response = response.get_xml_string_with_self_contained_assertion_within_encrypted_assertion( assertion_tag) if to_sign_assertion: response = signed_instance_factory(response, self.sec, to_sign_assertion) response = self._encrypt_assertion(encrypt_cert_assertion, sp_entity_id, response) else: if to_sign: response = signed_instance_factory(response, self.sec, to_sign) if sign: return signed_instance_factory(response, self.sec, sign_class) else: return response if sign: return self.sign(response, to_sign=to_sign) else: return response
def test_sign_then_encrypt_assertion(self): # Begin with the IdPs side _sec = self.server.sec assertion = s_utils.assertion_factory( subject=factory(saml.Subject, text="_aaa", name_id=factory( saml.NameID, format=saml.NAMEID_FORMAT_TRANSIENT)), attribute_statement=do_attribute_statement( { ("", "", "surName"): ("Jeter", ""), ("", "", "givenName"): ("Derek", ""), } ), issuer=self.server._issuer(), ) assertion.signature = sigver.pre_signature_part( assertion.id, _sec.my_cert, 1) sigass = _sec.sign_statement(assertion, class_name(assertion), key_file="pki/mykey.pem", node_id=assertion.id) # Create an Assertion instance from the signed assertion _ass = saml.assertion_from_string(sigass) response = sigver.response_factory( in_response_to="_012345", destination="https:#www.example.com", status=s_utils.success_status_factory(), issuer=self.server._issuer(), assertion=_ass ) enctext = _sec.crypto.encrypt_assertion(response, _sec.cert_file, pre_encryption_part()) seresp = samlp.response_from_string(enctext) # Now over to the client side _csec = self.client.sec if seresp.encrypted_assertion: decr_text = _csec.decrypt(enctext) seresp = samlp.response_from_string(decr_text) resp_ass = [] sign_cert_file = "pki/mycert.pem" for enc_ass in seresp.encrypted_assertion: assers = extension_elements_to_elements( enc_ass.extension_elements, [saml, samlp]) for ass in assers: if ass.signature: if not _csec.verify_signature("%s" % ass, sign_cert_file, node_name=class_name(ass)): continue resp_ass.append(ass) seresp.assertion = resp_ass seresp.encrypted_assertion = None #print _sresp assert seresp.assertion
def test_response(self): IDP = "urn:mace:example.com:saml:roland:idp" ava = {"givenName": ["Derek"], "surName": ["Jeter"], "mail": ["*****@*****.**"], "title": ["The man"]} nameid_policy = samlp.NameIDPolicy(allow_create="false", format=saml.NAMEID_FORMAT_PERSISTENT) resp = self.server.create_authn_response( identity=ava, in_response_to="id1", destination="http://lingon.catalogix.se:8087/", sp_entity_id="urn:mace:example.com:saml:roland:sp", name_id_policy=nameid_policy, userid="*****@*****.**", authn=AUTHN) resp_str = "%s" % resp resp_str = base64.encodestring(resp_str) authn_response = self.client.parse_authn_request_response( resp_str, BINDING_HTTP_POST, {"id1": "http://foo.example.com/service"}) assert authn_response is not None assert authn_response.issuer() == IDP assert authn_response.response.assertion[0].issuer.text == IDP session_info = authn_response.session_info() print session_info assert session_info["ava"] == {'mail': ['*****@*****.**'], 'givenName': ['Derek'], 'sn': ['Jeter'], 'title': ["The man"]} assert session_info["issuer"] == IDP assert session_info["came_from"] == "http://foo.example.com/service" response = samlp.response_from_string(authn_response.xmlstr) assert response.destination == "http://lingon.catalogix.se:8087/" # One person in the cache assert len(self.client.users.subjects()) == 1 subject_id = self.client.users.subjects()[0] print "||||", self.client.users.get_info_from(subject_id, IDP) # The information I have about the subject comes from one source assert self.client.users.issuers_of_info(subject_id) == [IDP] # --- authenticate another person ava = {"givenName": ["Alfonson"], "surName": ["Soriano"], "mail": ["*****@*****.**"], "title": ["outfielder"]} resp_str = "%s" % self.server.create_authn_response( identity=ava, in_response_to="id2", destination="http://lingon.catalogix.se:8087/", sp_entity_id="urn:mace:example.com:saml:roland:sp", name_id_policy=nameid_policy, userid="*****@*****.**", authn=AUTHN) resp_str = base64.encodestring(resp_str) self.client.parse_authn_request_response( resp_str, BINDING_HTTP_POST, {"id2": "http://foo.example.com/service"}) # Two persons in the cache assert len(self.client.users.subjects()) == 2 issuers = [self.client.users.issuers_of_info(s) for s in self.client.users.subjects()] # The information I have about the subjects comes from the same source print issuers assert issuers == [[IDP], [IDP]]
def test_encrypted_signed_response_4(self): cert_str, cert_key_str = generate_cert() signed_resp = self.server.create_authn_response( self.ava, "id12", # in_response_to "http://lingon.catalogix.se:8087/", # consumer_url "urn:mace:example.com:saml:roland:sp", # sp_entity_id name_id=self.name_id, sign_response=True, sign_assertion=True, encrypt_assertion=True, encrypt_assertion_self_contained=True, pefim=True, encrypt_cert_advice=cert_str, ) sresponse = response_from_string(signed_resp) valid = self.server.sec.verify_signature( signed_resp, self.server.config.cert_file, node_name='urn:oasis:names:tc:SAML:2.0:protocol:Response', node_id=sresponse.id, id_attr="") assert valid decr_text = self.server.sec.decrypt( signed_resp, self.client.config.encryption_keypairs[1]["key_file"]) resp = samlp.response_from_string(decr_text) resp.assertion = extension_elements_to_elements( resp.encrypted_assertion[0].extension_elements, [saml, samlp]) valid = self.server.sec.verify_signature( decr_text, self.server.config.cert_file, node_name='urn:oasis:names:tc:SAML:2.0:assertion:Assertion', node_id=resp.assertion[0].id, id_attr="") assert valid _, key_file = make_temp(cert_key_str, decode=False) decr_text = self.server.sec.decrypt(decr_text, key_file) resp = samlp.response_from_string(decr_text) assertion = extension_elements_to_elements( resp.encrypted_assertion[0].extension_elements, [saml, samlp]) assertion = \ extension_elements_to_elements(assertion[0].advice.encrypted_assertion[0].extension_elements,[saml, samlp]) self.verify_assertion(assertion) #PEFIM never signs assertion in advice assert assertion[0].signature is None #valid = self.server.sec.verify_signature(decr_text, # self.server.config.cert_file, # node_name='urn:oasis:names:tc:SAML:2.0:assertion:Assertion', # node_id=assertion[0].id, # id_attr="") assert valid
def parse_assertion(self, keys=None): """ Parse the assertions for a saml response. :param keys: A string representing a RSA key or a list of strings containing RSA keys. :return: True if the assertions are parsed otherwise False. """ if self.context == "AuthnQuery": # can contain one or more assertions pass else: # This is a saml2int limitation try: assert len(self.response.assertion) == 1 or \ len(self.response.encrypted_assertion) == 1 or \ self.assertion is not None except AssertionError: raise Exception("No assertion part") has_encrypted_assertions = self.find_encrypt_data(self.response) # # self.response.encrypted_assertion # if not has_encrypted_assertions and self.response.assertion: # for tmp_assertion in self.response.assertion: # if tmp_assertion.advice: # if tmp_assertion.advice.encrypted_assertion: # has_encrypted_assertions = True # break if self.response.assertion: logger.debug("***Unencrypted assertion***") for assertion in self.response.assertion: if not self._assertion(assertion, False): return False if has_encrypted_assertions: _enc_assertions = [] logger.debug("***Encrypted assertion/-s***") decr_text = "%s" % self.response resp = self.response decr_text_old = None while self.find_encrypt_data(resp) and decr_text_old != decr_text: decr_text_old = decr_text decr_text = self.sec.decrypt_keys(decr_text, keys) resp = samlp.response_from_string(decr_text) _enc_assertions = self.decrypt_assertions(resp.encrypted_assertion, decr_text) decr_text_old = None while (self.find_encrypt_data( resp) or self.find_encrypt_data_assertion_list( _enc_assertions)) and \ decr_text_old != decr_text: decr_text_old = decr_text decr_text = self.sec.decrypt_keys(decr_text, keys) resp = samlp.response_from_string(decr_text) _enc_assertions = self.decrypt_assertions( resp.encrypted_assertion, decr_text, verified=True) # _enc_assertions = self.decrypt_assertions( # resp.encrypted_assertion, decr_text, verified=True) all_assertions = _enc_assertions if resp.assertion: all_assertions = all_assertions + resp.assertion if len(all_assertions) > 0: for tmp_ass in all_assertions: if tmp_ass.advice and tmp_ass.advice.encrypted_assertion: advice_res = self.decrypt_assertions( tmp_ass.advice.encrypted_assertion, decr_text, tmp_ass.issuer) if tmp_ass.advice.assertion: tmp_ass.advice.assertion.extend(advice_res) else: tmp_ass.advice.assertion = advice_res if len(advice_res) > 0: tmp_ass.advice.encrypted_assertion = [] self.response.assertion = resp.assertion for assertion in _enc_assertions: if not self._assertion(assertion, True): return False else: self.assertions.append(assertion) self.xmlstr = decr_text if len(_enc_assertions) > 0: self.response.encrypted_assertion = [] if self.response.assertion: for assertion in self.response.assertion: self.assertions.append(assertion) if self.assertions and len(self.assertions) > 0: self.assertion = self.assertions[0] if self.context == "AuthnReq" or self.context == "AttrQuery": self.ava = self.get_identity() logger.debug("--- AVA: %s", self.ava) return True
def test_response(self): IDP = "urn:mace:example.com:saml:roland:idp" ava = { "givenName": ["Derek"], "surName": ["Jeter"], "mail": ["*****@*****.**"], "title": ["The man"] } nameid_policy = samlp.NameIDPolicy( allow_create="false", format=saml.NAMEID_FORMAT_PERSISTENT) resp = self.server.create_authn_response( identity=ava, in_response_to="id1", destination="http://lingon.catalogix.se:8087/", sp_entity_id="urn:mace:example.com:saml:roland:sp", name_id_policy=nameid_policy, userid="*****@*****.**", authn=AUTHN) resp_str = "%s" % resp resp_str = base64.encodestring(resp_str) authn_response = self.client.parse_authn_request_response( resp_str, BINDING_HTTP_POST, {"id1": "http://foo.example.com/service"}) assert authn_response is not None assert authn_response.issuer() == IDP assert authn_response.response.assertion[0].issuer.text == IDP session_info = authn_response.session_info() print session_info assert session_info["ava"] == { 'mail': ['*****@*****.**'], 'givenName': ['Derek'], 'sn': ['Jeter'], 'title': ["The man"] } assert session_info["issuer"] == IDP assert session_info["came_from"] == "http://foo.example.com/service" response = samlp.response_from_string(authn_response.xmlstr) assert response.destination == "http://lingon.catalogix.se:8087/" # One person in the cache assert len(self.client.users.subjects()) == 1 subject_id = self.client.users.subjects()[0] print "||||", self.client.users.get_info_from(subject_id, IDP) # The information I have about the subject comes from one source assert self.client.users.issuers_of_info(subject_id) == [IDP] # --- authenticate another person ava = { "givenName": ["Alfonson"], "surName": ["Soriano"], "mail": ["*****@*****.**"], "title": ["outfielder"] } resp_str = "%s" % self.server.create_authn_response( identity=ava, in_response_to="id2", destination="http://lingon.catalogix.se:8087/", sp_entity_id="urn:mace:example.com:saml:roland:sp", name_id_policy=nameid_policy, userid="*****@*****.**", authn=AUTHN) resp_str = base64.encodestring(resp_str) self.client.parse_authn_request_response( resp_str, BINDING_HTTP_POST, {"id2": "http://foo.example.com/service"}) # Two persons in the cache assert len(self.client.users.subjects()) == 2 issuers = [ self.client.users.issuers_of_info(s) for s in self.client.users.subjects() ] # The information I have about the subjects comes from the same source print issuers assert issuers == [[IDP], [IDP]]
def parse_assertion(self, keys=None): """ Parse the assertions for a saml response. :param keys: A string representing a RSA key or a list of strings containing RSA keys. :return: True if the assertions are parsed otherwise False. """ if self.context == "AuthnQuery": # can contain one or more assertions pass else: # This is a saml2int limitation try: assert ( len(self.response.assertion) == 1 or len(self.response.encrypted_assertion) == 1 or self.assertion is not None ) except AssertionError: raise Exception("No assertion part") if self.response.assertion: logger.debug("***Unencrypted assertion***") for assertion in self.response.assertion: if not self._assertion(assertion, False): return False if self.find_encrypt_data(self.response): logger.debug("***Encrypted assertion/-s***") _enc_assertions = [] resp = self.response decr_text = str(self.response) decr_text_old = None while self.find_encrypt_data(resp) and decr_text_old != decr_text: decr_text_old = decr_text try: decr_text = self.sec.decrypt_keys(decr_text, keys) except DecryptError as e: continue else: resp = samlp.response_from_string(decr_text) # check and prepare for comparison between str and unicode if type(decr_text_old) != type(decr_text): if isinstance(decr_text_old, six.binary_type): decr_text_old = decr_text_old.decode("utf-8") else: decr_text_old = decr_text_old.encode("utf-8") _enc_assertions = self.decrypt_assertions( resp.encrypted_assertion, decr_text ) decr_text_old = None while ( self.find_encrypt_data(resp) or self.find_encrypt_data_assertion_list(_enc_assertions) ) and decr_text_old != decr_text: decr_text_old = decr_text try: decr_text = self.sec.decrypt_keys(decr_text, keys) except DecryptError as e: continue else: resp = samlp.response_from_string(decr_text) _enc_assertions = self.decrypt_assertions( resp.encrypted_assertion, decr_text, verified=True ) # check and prepare for comparison between str and unicode if type(decr_text_old) != type(decr_text): if isinstance(decr_text_old, six.binary_type): decr_text_old = decr_text_old.decode("utf-8") else: decr_text_old = decr_text_old.encode("utf-8") all_assertions = _enc_assertions if resp.assertion: all_assertions = all_assertions + resp.assertion if len(all_assertions) > 0: for tmp_ass in all_assertions: if tmp_ass.advice and tmp_ass.advice.encrypted_assertion: advice_res = self.decrypt_assertions( tmp_ass.advice.encrypted_assertion, decr_text, tmp_ass.issuer) if tmp_ass.advice.assertion: tmp_ass.advice.assertion.extend(advice_res) else: tmp_ass.advice.assertion = advice_res if len(advice_res) > 0: tmp_ass.advice.encrypted_assertion = [] self.response.assertion = resp.assertion for assertion in _enc_assertions: if not self._assertion(assertion, True): return False else: self.assertions.append(assertion) self.xmlstr = decr_text if len(_enc_assertions) > 0: self.response.encrypted_assertion = [] if self.response.assertion: for assertion in self.response.assertion: self.assertions.append(assertion) if self.assertions and len(self.assertions) > 0: self.assertion = self.assertions[0] if self.context == "AuthnReq" or self.context == "AttrQuery": self.ava = self.get_identity() logger.debug("--- AVA: %s", self.ava) return True
def test_sign_then_encrypt_assertion(self): # Begin with the IdPs side _sec = self.server.sec assertion = s_utils.assertion_factory( subject=factory(saml.Subject, text="_aaa", name_id=factory( saml.NameID, format=saml.NAMEID_FORMAT_TRANSIENT)), attribute_statement=do_attribute_statement({ ("", "", "surName"): ("Jeter", ""), ("", "", "givenName"): ("Derek", ""), }), issuer=self.server._issuer(), ) assertion.signature = sigver.pre_signature_part( assertion.id, _sec.my_cert, 1) sigass = _sec.sign_statement(assertion, class_name(assertion), key_file=full_path("test.key"), node_id=assertion.id) # Create an Assertion instance from the signed assertion _ass = saml.assertion_from_string(sigass) response = sigver.response_factory( in_response_to="_012345", destination="https:#www.example.com", status=s_utils.success_status_factory(), issuer=self.server._issuer(), assertion=_ass) enctext = _sec.crypto.encrypt_assertion(response, _sec.cert_file, pre_encryption_part()) seresp = samlp.response_from_string(enctext) # Now over to the client side _csec = self.client.sec if seresp.encrypted_assertion: decr_text = _csec.decrypt(enctext) seresp = samlp.response_from_string(decr_text) resp_ass = [] sign_cert_file = full_path("test.pem") for enc_ass in seresp.encrypted_assertion: assers = extension_elements_to_elements( enc_ass.extension_elements, [saml, samlp]) for ass in assers: if ass.signature: if not _csec.verify_signature( "%s" % ass, sign_cert_file, node_name=class_name(ass)): continue resp_ass.append(ass) seresp.assertion = resp_ass seresp.encrypted_assertion = None #print _sresp assert seresp.assertion
def parse_assertion(self, keys=None): """ Parse the assertions for a saml response. :param keys: A string representing a RSA key or a list of strings containing RSA keys. :return: True if the assertions are parsed otherwise False. """ if self.context == "AuthnQuery": # can contain one or more assertions pass else: # This is a saml2int limitation try: assert len(self.response.assertion) == 1 or \ len(self.response.encrypted_assertion) == 1 except AssertionError: raise Exception("No assertion part") has_encrypted_assertions = self.find_encrypt_data(self.response) #self.response.encrypted_assertion #if not has_encrypted_assertions and self.response.assertion: # for tmp_assertion in self.response.assertion: # if tmp_assertion.advice: # if tmp_assertion.advice.encrypted_assertion: # has_encrypted_assertions = True # break if self.response.assertion: logger.debug("***Unencrypted assertion***") for assertion in self.response.assertion: if not self._assertion(assertion, False): return False if has_encrypted_assertions: _enc_assertions = [] logger.debug("***Encrypted assertion/-s***") decr_text = "%s" % self.response resp = self.response decr_text_old = None while self.find_encrypt_data(resp) and decr_text_old != decr_text: decr_text_old = decr_text decr_text = self.sec.decrypt_keys(decr_text, keys) resp = samlp.response_from_string(decr_text) _enc_assertions = self.decrypt_assertions(resp.encrypted_assertion, decr_text) decr_text_old = None while (self.find_encrypt_data(resp) or self.find_encrypt_data_assertion_list(_enc_assertions)) and \ decr_text_old != decr_text: decr_text_old = decr_text decr_text = self.sec.decrypt_keys(decr_text, keys) resp = samlp.response_from_string(decr_text) _enc_assertions = self.decrypt_assertions(resp.encrypted_assertion, decr_text, verified=True) #_enc_assertions = self.decrypt_assertions(resp.encrypted_assertion, decr_text, verified=True) all_assertions = _enc_assertions if resp.assertion: all_assertions = all_assertions + resp.assertion if len(all_assertions) > 0: for tmp_ass in all_assertions: if tmp_ass.advice and tmp_ass.advice.encrypted_assertion: advice_res = self.decrypt_assertions(tmp_ass.advice.encrypted_assertion, decr_text, tmp_ass.issuer) if tmp_ass.advice.assertion: tmp_ass.advice.assertion.extend(advice_res) else: tmp_ass.advice.assertion = advice_res if len(advice_res) > 0: tmp_ass.advice.encrypted_assertion = [] self.response.assertion = resp.assertion for assertion in _enc_assertions: if not self._assertion(assertion, True): return False else: self.assertions.append(assertion) self.xmlstr = decr_text if len(_enc_assertions) > 0: self.response.encrypted_assertion = [] if self.response.assertion: for assertion in self.response.assertion: self.assertions.append(assertion) if self.assertions and len(self.assertions) > 0: self.assertion = self.assertions[0] if self.context == "AuthnReq" or self.context == "AttrQuery": self.ava = self.get_identity() logger.debug("--- AVA: %s" % (self.ava,)) return True
def test_encrypted_signed_response_4(self): name_id = self.server.ident.transient_nameid( "urn:mace:example.com:saml:roland:sp", "id12") ava = { "givenName": ["Derek"], "surName": ["Jeter"], "mail": ["*****@*****.**"], "title": "The man" } cert_str, cert_key_str = generate_cert() signed_resp = self.server.create_authn_response( ava, "id12", # in_response_to "http://lingon.catalogix.se:8087/", # consumer_url "urn:mace:example.com:saml:roland:sp", # sp_entity_id name_id=name_id, sign_response=True, sign_assertion=True, encrypt_assertion=True, encrypted_advice_attributes=True, encrypt_cert=cert_str, ) sresponse = response_from_string(signed_resp) valid = self.server.sec.verify_signature( signed_resp, self.server.config.cert_file, node_name='urn:oasis:names:tc:SAML:2.0:protocol:Response', node_id=sresponse.id, id_attr="") assert valid _, key_file = make_temp("%s" % cert_key_str, decode=False) decr_text = self.server.sec.decrypt(signed_resp, key_file) resp = samlp.response_from_string(decr_text) valid = self.server.sec.verify_signature( decr_text, self.server.config.cert_file, node_name='urn:oasis:names:tc:SAML:2.0:assertion:Assertion', node_id=resp.assertion[0].id, id_attr="") assert valid assert resp.assertion[0].advice.encrypted_assertion[ 0].extension_elements assertion = extension_elements_to_elements( resp.assertion[0].advice.encrypted_assertion[0].extension_elements, [saml, samlp]) assert assertion assert assertion[0].attribute_statement ava = ava = get_ava(assertion[0]) assert ava ==\ {'mail': ['*****@*****.**'], 'givenname': ['Derek'], 'surname': ['Jeter'], 'title': ['The man']} #Should work, but I suspect that xmlsec manipulates the xml to much while encrypting that the signature #is no longer working. :( assert 'xmlns:encas' not in decr_text valid = self.server.sec.verify_signature( decr_text, self.server.config.cert_file, node_name='urn:oasis:names:tc:SAML:2.0:assertion:Assertion', node_id=assertion[0].id, id_attr="") assert valid
def test_encrypted_signed_response_2(self): name_id = self.server.ident.transient_nameid( "urn:mace:example.com:saml:roland:sp", "id12") ava = { "givenName": ["Derek"], "surName": ["Jeter"], "mail": ["*****@*****.**"], "title": "The man" } cert_str, cert_key_str = generate_cert() signed_resp = self.server.create_authn_response( ava, "id12", # in_response_to "http://lingon.catalogix.se:8087/", # consumer_url "urn:mace:example.com:saml:roland:sp", # sp_entity_id name_id=name_id, sign_response=True, sign_assertion=True, encrypt_assertion=True, encrypt_assertion_self_contained=True, encrypt_cert=cert_str, ) sresponse = response_from_string(signed_resp) valid = self.server.sec.verify_signature( signed_resp, self.server.config.cert_file, node_name='urn:oasis:names:tc:SAML:2.0:protocol:Response', node_id=sresponse.id, id_attr="") assert valid _, key_file = make_temp("%s" % cert_key_str, decode=False) decr_text = self.server.sec.decrypt(signed_resp, key_file) resp = samlp.response_from_string(decr_text) assert resp.encrypted_assertion[0].extension_elements assertion = extension_elements_to_elements( resp.encrypted_assertion[0].extension_elements, [saml, samlp]) assert assertion assert assertion[0].attribute_statement ava = get_ava(assertion[0]) assert ava ==\ {'mail': ['*****@*****.**'], 'givenname': ['Derek'], 'surname': ['Jeter'], 'title': ['The man']} assert 'EncryptedAssertion><encas2:Assertion xmlns:encas0="http://www.w3.org/2000/09/xmldsig#" ' \ 'xmlns:encas1="http://www.w3.org/2001/XMLSchema-instance" ' \ 'xmlns:encas2="urn:oasis:names:tc:SAML:2.0:assertion"' in decr_text valid = self.server.sec.verify_signature( decr_text, self.server.config.cert_file, node_name='urn:oasis:names:tc:SAML:2.0:assertion:Assertion', node_id=assertion[0].id, id_attr="") assert valid