Ejemplo n.º 1
0
def test_flow():
    sp = Saml2Client(config_file="servera_conf")
    idp1 = Server(config_file="idp_conf_mdb")
    idp2 = Server(config_file="idp_conf_mdb")

    # clean out database
    idp1.ident.mdb.db.drop()

    # -- dummy request ---
    req_id, orig_req = sp.create_authn_request(idp1.config.entityid)

    # == Create an AuthnRequest response

    rinfo = idp1.response_args(orig_req, [BINDING_HTTP_POST])

    # name_id = idp1.ident.transient_nameid("id12", rinfo["sp_entity_id"])
    resp = idp1.create_authn_response(
        {
            "eduPersonEntitlement": "Short stop",
            "surName": "Jeter",
            "givenName": "Derek",
            "mail": "*****@*****.**",
            "title": "The man",
        },
        userid="jeter",
        authn=AUTHN,
        **rinfo
    )

    # What's stored away is the assertion
    a_info = idp2.session_db.get_assertion(resp.assertion.id)
    # Make sure what I got back from MongoDB is the same as I put in
    assert a_info["assertion"] == resp.assertion

    # By subject
    nid = resp.assertion.subject.name_id
    _assertion = idp2.session_db.get_assertions_by_subject(nid)
    assert len(_assertion) == 1
    assert _assertion[0] == resp.assertion

    nids = idp2.ident.find_nameid("jeter")
    assert len(nids) == 1
Ejemplo n.º 2
0
def test_flow():
    sp = Saml2Client(config_file="servera_conf")
    idp1 = Server(config_file="idp_conf_mdb")
    idp2 = Server(config_file="idp_conf_mdb")

    # clean out database
    idp1.ident.mdb.db.drop()

    # -- dummy request ---
    req_id, orig_req = sp.create_authn_request(idp1.config.entityid)

    # == Create an AuthnRequest response

    rinfo = idp1.response_args(orig_req, [BINDING_HTTP_POST])

    #name_id = idp1.ident.transient_nameid("id12", rinfo["sp_entity_id"])
    resp = idp1.create_authn_response(
        {
            "eduPersonEntitlement": "Short stop",
            "surName": "Jeter",
            "givenName": "Derek",
            "mail": "*****@*****.**",
            "title": "The man"
        },
        userid="jeter",
        authn=AUTHN,
        **rinfo)

    # What's stored away is the assertion
    a_info = idp2.session_db.get_assertion(resp.assertion.id)
    # Make sure what I got back from MongoDB is the same as I put in
    assert a_info["assertion"] == resp.assertion

    # By subject
    nid = resp.assertion.subject.name_id
    _assertion = idp2.session_db.get_assertions_by_subject(nid)
    assert len(_assertion) == 1
    assert _assertion[0] == resp.assertion

    nids = idp2.ident.find_nameid("jeter")
    assert len(nids) == 1
Ejemplo n.º 3
0
class TestServer1():

    def setup_class(self):
        self.server = Server("idp_conf")

        conf = config.SPConfig()
        conf.load_file("server_conf")
        self.client = client.Saml2Client(conf)
        self.name_id = self.server.ident.transient_nameid(
            "urn:mace:example.com:saml:roland:sp", "id12")
        self.ava = {"givenName": ["Derek"], "sn": ["Jeter"],
               "mail": ["*****@*****.**"], "title": "The man"}

    def teardown_class(self):
        self.server.close()

    def verify_assertion(self, assertion):
        assert assertion
        assert assertion[0].attribute_statement

        ava = ava = get_ava(assertion[0])

        assert ava ==\
               {'mail': ['*****@*****.**'], 'givenName': ['Derek'],
                'sn': ['Jeter'], 'title': ['The man']}


    def verify_encrypted_assertion(self, assertion, decr_text):
        self.verify_assertion(assertion)
        assert assertion[0].signature is None

        assert 'EncryptedAssertion><encas1:Assertion xmlns:encas0="http://www.w3.org/2001/XMLSchema-instance" ' \
               'xmlns:encas1="urn:oasis:names:tc:SAML:2.0:assertion"' in decr_text

    def verify_advice_assertion(self, resp, decr_text):
        assert resp.assertion[0].signature is None

        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])
        self.verify_encrypted_assertion(assertion, decr_text)


    def test_issuer(self):
        issuer = self.server._issuer()
        assert isinstance(issuer, saml.Issuer)
        assert _eq(issuer.keyswv(), ["text", "format"])
        assert issuer.format == saml.NAMEID_FORMAT_ENTITY
        assert issuer.text == self.server.config.entityid

    def test_assertion(self):
        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(
                {
                    ("", "", "sn"): ("Jeter", ""),
                    ("", "", "givenName"): ("Derek", ""),
                }
            ),
            issuer=self.server._issuer(),
        )

        assert _eq(assertion.keyswv(), ['attribute_statement', 'issuer', 'id',
                                        'subject', 'issue_instant', 'version'])
        assert assertion.version == "2.0"
        assert assertion.issuer.text == "urn:mace:example.com:saml:roland:idp"
        #
        assert assertion.attribute_statement
        attribute_statement = assertion.attribute_statement
        assert len(attribute_statement.attribute) == 2
        attr0 = attribute_statement.attribute[0]
        attr1 = attribute_statement.attribute[1]
        if attr0.attribute_value[0].text == "Derek":
            assert attr0.friendly_name == "givenName"
            assert attr1.friendly_name == "sn"
            assert attr1.attribute_value[0].text == "Jeter"
        else:
            assert attr1.friendly_name == "givenName"
            assert attr1.attribute_value[0].text == "Derek"
            assert attr0.friendly_name == "sn"
            assert attr0.attribute_value[0].text == "Jeter"
        # 
        subject = assertion.subject
        assert _eq(subject.keyswv(), ["text", "name_id"])
        assert subject.text == "_aaa"
        assert subject.name_id.format == saml.NAMEID_FORMAT_TRANSIENT

    def test_response(self):
        response = sigver.response_factory(
            in_response_to="_012345",
            destination="https:#www.example.com",
            status=s_utils.success_status_factory(),
            assertion=s_utils.assertion_factory(
                subject=factory(saml.Subject, text="_aaa",
                                name_id=saml.NAMEID_FORMAT_TRANSIENT),
                attribute_statement=do_attribute_statement(
                    {
                        ("", "", "sn"): ("Jeter", ""),
                        ("", "", "givenName"): ("Derek", ""),
                    }
                ),
                issuer=self.server._issuer(),
            ),
            issuer=self.server._issuer(),
        )

        print(response.keyswv())
        assert _eq(response.keyswv(), ['destination', 'assertion', 'status',
                                       'in_response_to', 'issue_instant',
                                       'version', 'issuer', 'id'])
        assert response.version == "2.0"
        assert response.issuer.text == "urn:mace:example.com:saml:roland:idp"
        assert response.destination == "https:#www.example.com"
        assert response.in_response_to == "_012345"
        #
        status = response.status
        print(status)
        assert status.status_code.value == samlp.STATUS_SUCCESS

    def test_parse_faulty_request(self):
        req_id, authn_request = self.client.create_authn_request(
            destination="http://www.example.com", id="id1")

        # should raise an error because faulty spentityid
        binding = BINDING_HTTP_REDIRECT
        htargs = self.client.apply_binding(
            binding, "%s" % authn_request, "http://www.example.com", "abcd")
        _dict = parse_qs(htargs["headers"][0][1].split('?')[1])
        print(_dict)
        raises(OtherError, self.server.parse_authn_request,
               _dict["SAMLRequest"][0], binding)

    def test_parse_faulty_request_to_err_status(self):
        req_id, authn_request = self.client.create_authn_request(
            destination="http://www.example.com")

        binding = BINDING_HTTP_REDIRECT
        htargs = self.client.apply_binding(binding, "%s" % authn_request,
                                           "http://www.example.com", "abcd")
        _dict = parse_qs(htargs["headers"][0][1].split('?')[1])
        print(_dict)

        try:
            self.server.parse_authn_request(_dict["SAMLRequest"][0], binding)
            status = None
        except OtherError as oe:
            print(oe.args)
            status = s_utils.error_status_factory(oe)

        assert status
        print(status)
        assert _eq(status.keyswv(), ["status_code", "status_message"])
        assert status.status_message.text == 'Not destined for me!'
        status_code = status.status_code
        assert _eq(status_code.keyswv(), ["status_code", "value"])
        assert status_code.value == samlp.STATUS_RESPONDER
        assert status_code.status_code.value == samlp.STATUS_UNKNOWN_PRINCIPAL

    def test_parse_ok_request(self):
        req_id, authn_request = self.client.create_authn_request(
            message_id="id1", destination="http://*****:*****@nyy.mlb.com",
                "title": "The man"
            },
            "id12",  # in_response_to
            "http://*****:*****@nyy.mlb.com"], "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(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_signed_response_1(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,
        )

        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

        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_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_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_encrypted_signed_response_1(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=False,
            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

        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

        _, key_file = make_temp(cert_key_str, decode=False)

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

        resp = samlp.response_from_string(decr_text)

        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])

        self.verify_assertion(assertion)



        #PEFIM never signs assertions.
        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_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(cert_key_str, 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 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_2(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=True,
            encrypt_assertion_self_contained=True,
            pefim=True,
            encrypt_cert_advice=cert_str_advice,
        )

        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"])

        _, key_file = make_temp(cert_key_str_advice, decode=False)

        decr_text_2 = self.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 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_response_4(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,
            encrypted_advice_attributes=False,
        )

        sresponse = response_from_string(_resp)

        assert sresponse.signature is None

        decr_text = self.server.sec.decrypt(_resp, self.client.config.encryption_keypairs[1]["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_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,
            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.encryption_keypairs[1]["key_file"])

        resp = samlp.response_from_string(decr_text)

        self.verify_advice_assertion(resp, decr_text)

    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 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_response_8(self):
        try:
            _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,
                encrypt_cert_advice="whatever",
                encrypt_cert_assertion="whatever"
            )
            assert False, "Must throw an exception"
        except EncryptError as ex:
            pass
        except Exception as ex:
            assert False, "Wrong exception!"

        try:
            _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="whatever",
            )
            assert False, "Must throw an exception"
        except EncryptError as ex:
            pass
        except Exception as ex:
            assert False, "Wrong exception!"

        try:
            _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="whatever"
            )
            assert False, "Must throw an exception"
        except EncryptError as ex:
            pass
        except Exception as ex:
            assert False, "Wrong exception!"

        _server = Server("idp_conf_verify_cert")

        try:
            _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="whatever",
                encrypt_cert_assertion="whatever"
            )
            assert False, "Must throw an exception"
        except CertificateError as ex:
            pass
        except Exception as ex:
            assert False, "Wrong exception!"

        try:
            _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=False,
                encrypt_assertion_self_contained=True,
                pefim=True,
                encrypt_cert_advice="whatever",
            )
            assert False, "Must throw an exception"
        except CertificateError as ex:
            pass
        except Exception as ex:
            assert False, "Wrong exception!"

        try:
            _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,
                encrypted_advice_attributes=False,
                encrypt_cert_assertion="whatever"
            )
            assert False, "Must throw an exception"
        except CertificateError as ex:
            pass
        except Exception as ex:
            assert False, "Wrong exception!"

    def test_encrypted_response_9(self):
        _server = Server("idp_conf_sp_no_encrypt")

        _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,
        )

        self.verify_assertion(_resp.assertion.advice.assertion)

        _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=False,
            encrypt_assertion_self_contained=True,
            pefim=True
        )

        self.verify_assertion(_resp.assertion.advice.assertion)

        _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,
            encrypted_advice_attributes=False,
        )

        self.verify_assertion([_resp.assertion])


    def test_slo_http_post(self):
        soon = time_util.in_a_while(days=1)
        sinfo = {
            "name_id": nid,
            "issuer": "urn:mace:example.com:saml:roland:idp",
            "not_on_or_after": soon,
            "user": {
                "givenName": "Leo",
                "sn": "Laport",
            }
        }
        self.client.users.add_information_about_person(sinfo)

        req_id, logout_request = self.client.create_logout_request(
            destination="http://localhost:8088/slop", name_id=nid,
            issuer_entity_id="urn:mace:example.com:saml:roland:idp",
            reason="I'm tired of this")

        intermed = base64.b64encode(str(logout_request).encode('utf-8'))

        #saml_soap = make_soap_enveloped_saml_thingy(logout_request)
        request = self.server.parse_logout_request(intermed, BINDING_HTTP_POST)
        assert request

    def test_slo_soap(self):
        soon = time_util.in_a_while(days=1)
        sinfo = {
            "name_id": nid,
            "issuer": "urn:mace:example.com:saml:roland:idp",
            "not_on_or_after": soon,
            "user": {
                "givenName": "Leo",
                "sn": "Laport",
            }
        }

        sp = client.Saml2Client(config_file="server_conf")
        sp.users.add_information_about_person(sinfo)

        req_id, logout_request = sp.create_logout_request(
            name_id=nid, destination="http://localhost:8088/slo",
            issuer_entity_id="urn:mace:example.com:saml:roland:idp",
            reason="I'm tired of this")

        #_ = s_utils.deflate_and_base64_encode("%s" % (logout_request,))

        saml_soap = make_soap_enveloped_saml_thingy(logout_request)
        self.server.ident.close()

        with closing(Server("idp_soap_conf")) as idp:
            request = idp.parse_logout_request(saml_soap)
            idp.ident.close()
            assert request
Ejemplo n.º 4
0
class TestServer1():
    def setup_class(self):
        self.server = Server("idp_conf")

        conf = config.SPConfig()
        conf.load_file("server_conf")
        self.client = client.Saml2Client(conf)
        self.name_id = self.server.ident.transient_nameid(
            "urn:mace:example.com:saml:roland:sp", "id12")
        self.ava = {
            "givenName": ["Derek"],
            "surName": ["Jeter"],
            "mail": ["*****@*****.**"],
            "title": "The man"
        }

    def teardown_class(self):
        self.server.close()

    def verify_assertion(self, assertion):
        assert assertion
        assert assertion[0].attribute_statement

        ava = ava = get_ava(assertion[0])

        assert ava ==\
               {'mail': ['*****@*****.**'], 'givenname': ['Derek'], 'surname': ['Jeter'], 'title': ['The man']}

    def verify_encrypted_assertion(self, assertion, decr_text):
        self.verify_assertion(assertion)
        assert assertion[0].signature is None

        assert 'EncryptedAssertion><encas1:Assertion xmlns:encas0="http://www.w3.org/2001/XMLSchema-instance" ' \
               'xmlns:encas1="urn:oasis:names:tc:SAML:2.0:assertion"' in decr_text

    def verify_advice_assertion(self, resp, decr_text):
        assert resp.assertion[0].signature is None

        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])
        self.verify_encrypted_assertion(assertion, decr_text)

    def test_issuer(self):
        issuer = self.server._issuer()
        assert isinstance(issuer, saml.Issuer)
        assert _eq(issuer.keyswv(), ["text", "format"])
        assert issuer.format == saml.NAMEID_FORMAT_ENTITY
        assert issuer.text == self.server.config.entityid

    def test_assertion(self):
        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(),
        )

        assert _eq(assertion.keyswv(), [
            'attribute_statement', 'issuer', 'id', 'subject', 'issue_instant',
            'version'
        ])
        assert assertion.version == "2.0"
        assert assertion.issuer.text == "urn:mace:example.com:saml:roland:idp"
        #
        assert assertion.attribute_statement
        attribute_statement = assertion.attribute_statement
        assert len(attribute_statement.attribute) == 2
        attr0 = attribute_statement.attribute[0]
        attr1 = attribute_statement.attribute[1]
        if attr0.attribute_value[0].text == "Derek":
            assert attr0.friendly_name == "givenName"
            assert attr1.friendly_name == "surName"
            assert attr1.attribute_value[0].text == "Jeter"
        else:
            assert attr1.friendly_name == "givenName"
            assert attr1.attribute_value[0].text == "Derek"
            assert attr0.friendly_name == "surName"
            assert attr0.attribute_value[0].text == "Jeter"
        #
        subject = assertion.subject
        assert _eq(subject.keyswv(), ["text", "name_id"])
        assert subject.text == "_aaa"
        assert subject.name_id.format == saml.NAMEID_FORMAT_TRANSIENT

    def test_response(self):
        response = sigver.response_factory(
            in_response_to="_012345",
            destination="https:#www.example.com",
            status=s_utils.success_status_factory(),
            assertion=s_utils.assertion_factory(
                subject=factory(saml.Subject,
                                text="_aaa",
                                name_id=saml.NAMEID_FORMAT_TRANSIENT),
                attribute_statement=do_attribute_statement({
                    ("", "", "surName"): ("Jeter", ""),
                    ("", "", "givenName"): ("Derek", ""),
                }),
                issuer=self.server._issuer(),
            ),
            issuer=self.server._issuer(),
        )

        print(response.keyswv())
        assert _eq(response.keyswv(), [
            'destination', 'assertion', 'status', 'in_response_to',
            'issue_instant', 'version', 'issuer', 'id'
        ])
        assert response.version == "2.0"
        assert response.issuer.text == "urn:mace:example.com:saml:roland:idp"
        assert response.destination == "https:#www.example.com"
        assert response.in_response_to == "_012345"
        #
        status = response.status
        print(status)
        assert status.status_code.value == samlp.STATUS_SUCCESS

    def test_parse_faulty_request(self):
        req_id, authn_request = self.client.create_authn_request(
            destination="http://www.example.com", id="id1")

        # should raise an error because faulty spentityid
        binding = BINDING_HTTP_REDIRECT
        htargs = self.client.apply_binding(binding, "%s" % authn_request,
                                           "http://www.example.com", "abcd")
        _dict = parse_qs(htargs["headers"][0][1].split('?')[1])
        print(_dict)
        raises(OtherError, self.server.parse_authn_request,
               _dict["SAMLRequest"][0], binding)

    def test_parse_faulty_request_to_err_status(self):
        req_id, authn_request = self.client.create_authn_request(
            destination="http://www.example.com")

        binding = BINDING_HTTP_REDIRECT
        htargs = self.client.apply_binding(binding, "%s" % authn_request,
                                           "http://www.example.com", "abcd")
        _dict = parse_qs(htargs["headers"][0][1].split('?')[1])
        print(_dict)

        try:
            self.server.parse_authn_request(_dict["SAMLRequest"][0], binding)
            status = None
        except OtherError as oe:
            print(oe.args)
            status = s_utils.error_status_factory(oe)

        assert status
        print(status)
        assert _eq(status.keyswv(), ["status_code", "status_message"])
        assert status.status_message.text == 'Not destined for me!'
        status_code = status.status_code
        assert _eq(status_code.keyswv(), ["status_code", "value"])
        assert status_code.value == samlp.STATUS_RESPONDER
        assert status_code.status_code.value == samlp.STATUS_UNKNOWN_PRINCIPAL

    def test_parse_ok_request(self):
        req_id, authn_request = self.client.create_authn_request(
            message_id="id1", destination="http://*****:*****@nyy.mlb.com",
                "title": "The man"
            },
            "id12",  # in_response_to
            "http://*****:*****@nyy.mlb.com"],
            "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(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"
        }

        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_signed_response_1(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,
        )

        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

        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_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_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_encrypted_signed_response_1(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=False,
            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

        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

        _, 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)

        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])

        self.verify_assertion(assertion)

        #PEFIM never signs assertions.
        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_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 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_2(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=True,
            encrypt_assertion_self_contained=True,
            pefim=True,
            encrypt_cert_advice=cert_str_advice,
        )

        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"])

        _, key_file = make_temp(cert_key_str_advice, decode=False)

        decr_text_2 = self.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 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_response_4(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,
            encrypted_advice_attributes=False,
        )

        sresponse = response_from_string(_resp)

        assert sresponse.signature is None

        decr_text = self.server.sec.decrypt(
            _resp, self.client.config.encryption_keypairs[1]["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_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,
            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.encryption_keypairs[1]["key_file"])

        resp = samlp.response_from_string(decr_text)

        self.verify_advice_assertion(resp, decr_text)

    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 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_response_8(self):
        try:
            _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,
                encrypt_cert_advice="whatever",
                encrypt_cert_assertion="whatever")
            assert False, "Must throw an exception"
        except EncryptError as ex:
            pass
        except Exception as ex:
            assert False, "Wrong exception!"

        try:
            _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="whatever",
            )
            assert False, "Must throw an exception"
        except EncryptError as ex:
            pass
        except Exception as ex:
            assert False, "Wrong exception!"

        try:
            _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="whatever")
            assert False, "Must throw an exception"
        except EncryptError as ex:
            pass
        except Exception as ex:
            assert False, "Wrong exception!"

        _server = Server("idp_conf_verify_cert")

        try:
            _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="whatever",
                encrypt_cert_assertion="whatever")
            assert False, "Must throw an exception"
        except CertificateError as ex:
            pass
        except Exception as ex:
            assert False, "Wrong exception!"

        try:
            _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=False,
                encrypt_assertion_self_contained=True,
                pefim=True,
                encrypt_cert_advice="whatever",
            )
            assert False, "Must throw an exception"
        except CertificateError as ex:
            pass
        except Exception as ex:
            assert False, "Wrong exception!"

        try:
            _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,
                encrypted_advice_attributes=False,
                encrypt_cert_assertion="whatever")
            assert False, "Must throw an exception"
        except CertificateError as ex:
            pass
        except Exception as ex:
            assert False, "Wrong exception!"

    def test_encrypted_response_9(self):
        _server = Server("idp_conf_sp_no_encrypt")

        _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,
        )

        self.verify_assertion(_resp.assertion.advice.assertion)

        _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=False,
            encrypt_assertion_self_contained=True,
            pefim=True)

        self.verify_assertion(_resp.assertion.advice.assertion)

        _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,
            encrypted_advice_attributes=False,
        )

        self.verify_assertion([_resp.assertion])

    def test_slo_http_post(self):
        soon = time_util.in_a_while(days=1)
        sinfo = {
            "name_id": nid,
            "issuer": "urn:mace:example.com:saml:roland:idp",
            "not_on_or_after": soon,
            "user": {
                "givenName": "Leo",
                "surName": "Laport",
            }
        }
        self.client.users.add_information_about_person(sinfo)

        req_id, logout_request = self.client.create_logout_request(
            destination="http://localhost:8088/slop",
            name_id=nid,
            issuer_entity_id="urn:mace:example.com:saml:roland:idp",
            reason="I'm tired of this")

        intermed = base64.b64encode(str(logout_request).encode('utf-8'))

        #saml_soap = make_soap_enveloped_saml_thingy(logout_request)
        request = self.server.parse_logout_request(intermed, BINDING_HTTP_POST)
        assert request

    def test_slo_soap(self):
        soon = time_util.in_a_while(days=1)
        sinfo = {
            "name_id": nid,
            "issuer": "urn:mace:example.com:saml:roland:idp",
            "not_on_or_after": soon,
            "user": {
                "givenName": "Leo",
                "surName": "Laport",
            }
        }

        sp = client.Saml2Client(config_file="server_conf")
        sp.users.add_information_about_person(sinfo)

        req_id, logout_request = sp.create_logout_request(
            name_id=nid,
            destination="http://localhost:8088/slo",
            issuer_entity_id="urn:mace:example.com:saml:roland:idp",
            reason="I'm tired of this")

        #_ = s_utils.deflate_and_base64_encode("%s" % (logout_request,))

        saml_soap = make_soap_enveloped_saml_thingy(logout_request)
        self.server.ident.close()

        with closing(Server("idp_soap_conf")) as idp:
            request = idp.parse_logout_request(saml_soap)
            idp.ident.close()
            assert request
Ejemplo n.º 5
0
def login_process(request):
    """ View which processes the actual SAML request and returns a self-submitting form with the SAML response.
        The login_required decorator ensures the user authenticates first on the IdP using 'normal' ways.
    """
    # Construct server with config from settings dict
    conf = IdPConfig()
    conf.load(copy.deepcopy(settings.SAML_IDP_CONFIG))
    IDP = Server(config=conf)
    # Parse incoming request
    try:
        req_info = IDP.parse_authn_request(request.session['SAMLRequest'],
                                           BINDING_HTTP_POST)
    except Exception as excp:
        return HttpResponseBadRequest(excp)
    # TODO this is taken from example, but no idea how this works or whats it does. Check SAML2 specification?
    # Signed request for HTTP-REDIRECT
    if "SigAlg" in request.session and "Signature" in request.session:
        _certs = IDP.metadata.certs(req_info.message.issuer.text, "any",
                                    "signing")
        verified_ok = False
        for cert in _certs:
            # TODO implement
            #if verify_redirect_signature(_info, IDP.sec.sec_backend, cert):
            #    verified_ok = True
            #    break
            pass
        if not verified_ok:
            return HttpResponseBadRequest(
                "Message signature verification failure")

    binding_out, destination = IDP.pick_binding(
        service="assertion_consumer_service",
        entity_id=req_info.message.issuer.text)

    # Gather response arguments
    try:
        resp_args = IDP.response_args(req_info.message)
    except (UnknownPrincipal, UnsupportedBinding) as excp:
        return HttpResponseServerError(excp)

    try:
        sp_config = settings.SAML_IDP_SPCONFIG[resp_args['sp_entity_id']]
    except Exception:
        raise ImproperlyConfigured(
            "No config for SP %s defined in SAML_IDP_SPCONFIG" %
            resp_args['sp_entity_id'])

    # Create user-specified processor or fallback to all-access base processor
    processor_string = sp_config.get('processor', None)
    if processor_string is None:
        processor = BaseProcessor
    else:
        processor_class = import_string(processor_string)
        processor = processor_class()

    # Check if user has access to the service of this SP
    if not processor.has_access(request.user):
        raise PermissionDenied("You do not have access to this resource")

    # Create Identity dict (SP-specific)
    sp_mapping = sp_config.get('attribute_mapping', {'username': '******'})
    identity = processor.create_identity(request.user, sp_mapping)

    # TODO investigate how this works, because I don't get it. Specification?
    req_authn_context = req_info.message.requested_authn_context or PASSWORD
    AUTHN_BROKER = AuthnBroker()
    AUTHN_BROKER.add(authn_context_class_ref(req_authn_context), "")

    # Construct SamlResponse message
    try:
        authn_resp = IDP.create_authn_response(
            identity=identity,
            userid=request.user.username,
            name_id=NameID(format=resp_args['name_id_policy'].format,
                           sp_name_qualifier=destination,
                           text=request.user.username),
            authn=AUTHN_BROKER.get_authn_by_accr(req_authn_context),
            sign_response=IDP.config.getattr("sign_response", "idp") or False,
            sign_assertion=IDP.config.getattr("sign_assertion", "idp")
            or False,
            **resp_args)
    except Exception as excp:
        return HttpResponseServerError(excp)

    # Return as html with self-submitting form.
    http_args = IDP.apply_binding(binding=binding_out,
                                  msg_str="%s" % authn_resp,
                                  destination=destination,
                                  relay_state=request.session['RelayState'],
                                  response=True)

    logger.debug('http args are: %s' % http_args)

    if processor.enable_multifactor(request.user):
        # Store http_args in session for after multi factor is complete
        request.session['saml_data'] = http_args['data']
        logger.debug("Redirecting to process_multi_factor")
        return HttpResponseRedirect(reverse('saml_multi_factor'))
    else:
        logger.debug("Performing SAML redirect")
        return HttpResponse(http_args['data'])
Ejemplo n.º 6
0
def test_artifact_flow():
    #SP = 'urn:mace:example.com:saml:roland:sp'
    sp = Saml2Client(config_file="servera_conf")
    idp = Server(config_file="idp_all_conf")

    # original request

    binding, destination = sp.pick_binding("single_sign_on_service",
                                           entity_id=idp.config.entityid)
    relay_state = "RS0"
    req = sp.create_authn_request(destination, id="id1")

    artifact = sp.use_artifact(req, 1)

    binding, destination = sp.pick_binding("single_sign_on_service",
                                           [BINDING_HTTP_ARTIFACT],
                                           entity_id=idp.config.entityid)

    hinfo = sp.apply_binding(binding, "%s" % artifact, destination, relay_state)

    # ========== @IDP ============

    artifact2 = get_msg(hinfo, binding)

    assert artifact == artifact2

    # The IDP now wants to replace the artifact with the real request

    destination = idp.artifact2destination(artifact2, "spsso")

    msg = idp.create_artifact_resolve(artifact2, destination, sid())

    hinfo = idp.use_soap(msg, destination, None, False)

    # ======== @SP ==========

    msg = get_msg(hinfo, BINDING_SOAP)

    ar = sp.parse_artifact_resolve(msg)

    assert ar.artifact.text == artifact

    # The SP picks the request out of the repository with the artifact as the key
    oreq = sp.artifact[ar.artifact.text]
    # Should be the same as req above

    # Returns the information over the existing SOAP connection so
    # no transport information needed

    msg = sp.create_artifact_response(ar, ar.artifact.text)
    hinfo = sp.use_soap(msg, destination)

    # ========== @IDP ============

    msg = get_msg(hinfo, BINDING_SOAP)

    # The IDP untangles the request from the artifact resolve response
    spreq = idp.parse_artifact_resolve_response(msg)

    # should be the same as req above

    assert spreq.id == req.id

    # That was one way, the Request from the SP
    # ---------------------------------------------#
    # Now for the other, the response from the IDP

    name_id = idp.ident.transient_nameid(sp.config.entityid, "derek")

    resp_args = idp.response_args(spreq, [BINDING_HTTP_POST])

    response = idp.create_authn_response({"eduPersonEntitlement": "Short stop",
                                          "surName": "Jeter", "givenName": "Derek",
                                          "mail": "*****@*****.**",
                                          "title": "The man"},
                                         name_id=name_id,
                                         authn=AUTHN,
                                         **resp_args)

    print response

    # with the response in hand create an artifact

    artifact = idp.use_artifact(response, 1)

    binding, destination = sp.pick_binding("single_sign_on_service",
                                           [BINDING_HTTP_ARTIFACT],
                                           entity_id=idp.config.entityid)

    hinfo = sp.apply_binding(binding, "%s" % artifact, destination, relay_state,
                             response=True)

    # ========== SP =========

    artifact3 = get_msg(hinfo, binding)

    assert artifact == artifact3

    destination = sp.artifact2destination(artifact3, "idpsso")

    # Got an artifact want to replace it with the real message
    msg = sp.create_artifact_resolve(artifact3, destination, sid())

    print msg

    hinfo = sp.use_soap(msg, destination, None, False)

    # ======== IDP ==========

    msg = get_msg(hinfo, BINDING_SOAP)

    ar = idp.parse_artifact_resolve(msg)

    print ar

    assert ar.artifact.text == artifact3

    # The IDP retrieves the response from the database using the artifact as the key
    #oreq = idp.artifact[ar.artifact.text]

    binding, destination = idp.pick_binding("artifact_resolution_service",
                                            entity_id=sp.config.entityid)

    resp = idp.create_artifact_response(ar, ar.artifact.text)
    hinfo = idp.use_soap(resp, destination)

    # ========== SP ============

    msg = get_msg(hinfo, BINDING_SOAP)
    sp_resp = sp.parse_artifact_resolve_response(msg)

    assert sp_resp.id == response.id
Ejemplo n.º 7
0
class SamlIDP(service.Service):
    def __init__(self, environ, start_response, conf, cache, incoming):
        """
        Constructor for the class.
        :param environ: WSGI environ
        :param start_response: WSGI start response function
        :param conf: The SAML configuration
        :param cache: Cache with active sessions
        """
        service.Service.__init__(self, environ, start_response)
        self.response_bindings = None
        self.idp = Server(config=conf, cache=cache)
        self.incoming = incoming

    def verify_request(self, query, binding):
        """ Parses and verifies the SAML Authentication Request

        :param query: The SAML authn request, transport encoded
        :param binding: Which binding the query came in over
        :returns: dictionary
        """

        if not query:
            logger.info("Missing QUERY")
            resp = Unauthorized('Unknown user')
            return {"response": resp(self.environ, self.start_response)}

        req_info = self.idp.parse_authn_request(query, binding)

        logger.info("parsed OK")
        _authn_req = req_info.message
        logger.debug("%s" % _authn_req)

        # Check that I know where to send the reply to.
        try:
            binding_out, destination = self.idp.pick_binding(
                "assertion_consumer_service",
                bindings=self.response_bindings,
                entity_id=_authn_req.issuer.text, request=_authn_req)
        except Exception as err:
            logger.error("Couldn't find receiver endpoint: %s" % err)
            raise

        logger.debug("Binding: %s, destination: %s" % (binding_out,
                                                       destination))

        resp_args = {}
        try:
            resp_args = self.idp.response_args(_authn_req)
            _resp = None
        except UnknownPrincipal as excp:
            _resp = self.idp.create_error_response(_authn_req.id,
                                                   destination, excp)
        except UnsupportedBinding as excp:
            _resp = self.idp.create_error_response(_authn_req.id,
                                                   destination, excp)

        req_args = {}
        for key in ["subject", "name_id_policy", "conditions",
                    "requested_authn_context", "scoping", "force_authn",
                    "is_passive"]:
            try:
                val = getattr(_authn_req, key)
            except AttributeError:
                pass
            else:
                if val is not None:
                    req_args[key] = val

        return {"resp_args": resp_args, "response": _resp,
                "authn_req": _authn_req, "req_args": req_args}

    def handle_authn_request(self, binding_in):
        """
        Deal with an authentication request

        :param binding_in: Which binding was used when receiving the query
        :return: A response if an error occurred or session information in a
            dictionary
        """

        _request = self.unpack(binding_in)
        _binding_in = service.INV_BINDING_MAP[binding_in]

        try:
            _dict = self.verify_request(_request["SAMLRequest"], _binding_in)
        except UnknownPrincipal as excp:
            logger.error("UnknownPrincipal: %s" % (excp,))
            resp = ServiceError("UnknownPrincipal: %s" % (excp,))
            return resp(self.environ, self.start_response)
        except UnsupportedBinding as excp:
            logger.error("UnsupportedBinding: %s" % (excp,))
            resp = ServiceError("UnsupportedBinding: %s" % (excp,))
            return resp(self.environ, self.start_response)

        _binding = _dict["resp_args"]["binding"]
        if _dict["response"]:  # An error response.
            http_args = self.idp.apply_binding(
                _binding, "%s" % _dict["response"],
                _dict["resp_args"]["destination"],
                _request["RelayState"], response=True)

            logger.debug("HTTPargs: %s" % http_args)
            return self.response(_binding, http_args)
        else:
            return self.incoming(_dict, self.environ, self.start_response,
                                 _request["RelayState"])

    def construct_authn_response(self, identity, name_id, authn, resp_args,
                                 relay_state, sign_response=True):
        """

        :param identity:
        :param name_id:
        :param authn:
        :param resp_args:
        :param relay_state:
        :param sign_response:
        :return:
        """

        _resp = self.idp.create_authn_response(identity, name_id=name_id,
                                               authn=authn,
                                               sign_response=sign_response,
                                               **resp_args)

        http_args = self.idp.apply_binding(
            resp_args["binding"], "%s" % _resp, resp_args["destination"],
            relay_state, response=True)

        logger.debug("HTTPargs: %s" % http_args)

        resp = None
        if http_args["data"]:
            resp = Response(http_args["data"], headers=http_args["headers"])
        else:
            for header in http_args["headers"]:
                if header[0] == "Location":
                    resp = Redirect(header[1])

        if not resp:
            resp = ServiceError("Don't know how to return response")

        return resp(self.environ, self.start_response)

    def register_endpoints(self):
        """
        Given the configuration, return a set of URL to function mappings.
        """

        url_map = []
        idp_endpoints = self.idp.config.getattr("endpoints", "idp")
        for endp, binding in idp_endpoints["single_sign_on_service"]:
            p = urlparse(endp)
            url_map.append(("^%s/(.*)$" % p.path[1:],
                            ("IDP", "handle_authn_request",
                             service.BINDING_MAP[binding])))
            url_map.append(("^%s$" % p.path[1:],
                            ("IDP", "handle_authn_request",
                             service.BINDING_MAP[binding])))

        return url_map
Ejemplo n.º 8
0
class SamlIDP(service.Service):
    def __init__(self, environ, start_response, conf, cache, incomming):
        """
        Constructor for the class.
        :param environ: WSGI environ
        :param start_response: WSGI start response function
        :param conf: The SAML configuration
        :param cache: Cache with active sessions
        """
        service.Service.__init__(self, environ, start_response)
        self.response_bindings = None
        self.idp = Server(config=conf, cache=cache)
        self.incomming = incomming

    def verify_request(self, query, binding):
        """ Parses and verifies the SAML Authentication Request

        :param query: The SAML authn request, transport encoded
        :param binding: Which binding the query came in over
        :returns: dictionary
        """

        if not query:
            logger.info("Missing QUERY")
            resp = Unauthorized('Unknown user')
            return {"response": resp(self.environ, self.start_response)}

        req_info = self.idp.parse_authn_request(query, binding)

        logger.info("parsed OK")
        _authn_req = req_info.message
        logger.debug("%s" % _authn_req)

        # Check that I know where to send the reply to
        try:
            binding_out, destination = self.idp.pick_binding(
                "assertion_consumer_service",
                bindings=self.response_bindings,
                entity_id=_authn_req.issuer.text,
                request=_authn_req)
        except Exception as err:
            logger.error("Couldn't find receiver endpoint: %s" % err)
            raise

        logger.debug("Binding: %s, destination: %s" %
                     (binding_out, destination))

        resp_args = {}
        try:
            resp_args = self.idp.response_args(_authn_req)
            _resp = None
        except UnknownPrincipal as excp:
            _resp = self.idp.create_error_response(_authn_req.id, destination,
                                                   excp)
        except UnsupportedBinding as excp:
            _resp = self.idp.create_error_response(_authn_req.id, destination,
                                                   excp)

        req_args = {}
        for key in [
                "subject", "name_id_policy", "conditions",
                "requested_authn_context", "scoping", "force_authn",
                "is_passive"
        ]:
            try:
                val = getattr(_authn_req, key)
            except AttributeError:
                pass
            else:
                req_args[key] = val

        return {
            "resp_args": resp_args,
            "response": _resp,
            "authn_req": _authn_req,
            "req_args": req_args
        }

    def handle_authn_request(self, binding_in):
        """
        Deal with an authentication request

        :param binding_in: Which binding was used when receiving the query
        :return: A response if an error occurred or session information in a
            dictionary
        """

        _request = self.unpack(binding_in)
        _binding_in = service.INV_BINDING_MAP[binding_in]

        try:
            _dict = self.verify_request(_request["SAMLRequest"], _binding_in)
        except UnknownPrincipal as excp:
            logger.error("UnknownPrincipal: %s" % (excp, ))
            resp = ServiceError("UnknownPrincipal: %s" % (excp, ))
            return resp(self.environ, self.start_response)
        except UnsupportedBinding as excp:
            logger.error("UnsupportedBinding: %s" % (excp, ))
            resp = ServiceError("UnsupportedBinding: %s" % (excp, ))
            return resp(self.environ, self.start_response)

        _binding = _dict["resp_args"]["binding"]
        if _dict["response"]:  # An error response
            http_args = self.idp.apply_binding(
                _binding,
                "%s" % _dict["response"],
                _dict["resp_args"]["destination"],
                _request["RelayState"],
                response=True)

            logger.debug("HTTPargs: %s" % http_args)
            return self.response(_binding, http_args)
        else:
            return self.incomming(_dict, self, self.environ,
                                  self.start_response, _request["RelayState"])

    def construct_authn_response(self,
                                 identity,
                                 name_id,
                                 authn,
                                 resp_args,
                                 relay_state,
                                 sign_response=True):
        """

        :param identity:
        :param name_id:
        :param authn:
        :param resp_args:
        :param relay_state:
        :param sign_response:
        :return:
        """

        _resp = self.idp.create_authn_response(identity,
                                               name_id=name_id,
                                               authn=authn,
                                               sign_response=sign_response,
                                               **resp_args)

        http_args = self.idp.apply_binding(resp_args["binding"],
                                           "%s" % _resp,
                                           resp_args["destination"],
                                           relay_state,
                                           response=True)

        logger.debug("HTTPargs: %s" % http_args)

        resp = None
        if http_args["data"]:
            resp = Response(http_args["data"], headers=http_args["headers"])
        else:
            for header in http_args["headers"]:
                if header[0] == "Location":
                    resp = Redirect(header[1])

        if not resp:
            resp = ServiceError("Don't know how to return response")

        return resp(self.environ, self.start_response)

    def register_endpoints(self):
        """
        Given the configuration, return a set of URL to function mappings.
        """

        url_map = []
        for endp, binding in self.idp.config.getattr(
                "endpoints", "idp")["single_sign_on_service"]:
            p = urlparse(endp)
            url_map.append(
                ("^%s/(.*)$" % p.path[1:], ("IDP", "handle_authn_request",
                                            service.BINDING_MAP[binding])))
            url_map.append(
                ("^%s$" % p.path[1:], ("IDP", "handle_authn_request",
                                       service.BINDING_MAP[binding])))

        return url_map
Ejemplo n.º 9
0
class SamlIDP(service.Service):
    def __init__(self, environ, start_response, conf, cache, incomming, tid1_to_tid2, tid2_to_tid1, 
                 encmsg_to_iv, tid_handler, force_persistant_nameid, force_no_userid_subject_cacheing, idp=None):
        """
        Constructor for the class.
        :param environ: WSGI environ
        :param start_response: WSGI start response function
        :param conf: The SAML configuration
        :param cache: Cache with active sessions
        """
        service.Service.__init__(self, environ, start_response)
        self.response_bindings = None
        if idp is None:
            self.idp = Server(config=conf, cache=cache)
        else:
            self.idp = idp
        self.incomming = incomming
        self.tid1_to_tid2 = tid1_to_tid2
        self.tid2_to_tid1 = tid2_to_tid1
        self.encmsg_to_iv = encmsg_to_iv
        self.tid_handler = tid_handler
        self.force_persistant_nameid = force_persistant_nameid
        self.force_no_userid_subject_cacheing = force_no_userid_subject_cacheing

    def verify_request(self, query, binding):
        """ Parses and verifies the SAML Authentication Request

        :param query: The SAML authn request, transport encoded
        :param binding: Which binding the query came in over
        :returns: dictionary
        """

        if not query:
            logger.info("Missing QUERY")
            resp = Unauthorized('Unknown user')
            return {"response": resp}

        req_info = self.idp.parse_authn_request(query, binding)
        encrypt_cert = encrypt_cert_from_item(req_info.message)

        logger.info("parsed OK")
        _authn_req = req_info.message
        logger.debug("%s" % _authn_req)

        # Check that I know where to send the reply to
        try:
            binding_out, destination = self.idp.pick_binding(
                "assertion_consumer_service",
                bindings=self.response_bindings,
                entity_id=_authn_req.issuer.text, request=_authn_req)
        except Exception as err:
            logger.error("Couldn't find receiver endpoint: %s" % err)
            raise

        logger.debug("Binding: %s, destination: %s" % (binding_out,
                                                       destination))

        resp_args = {}
        try:
            resp_args = self.idp.response_args(_authn_req)
            _resp = None
        except UnknownPrincipal as excp:
            _resp = self.idp.create_error_response(_authn_req.id,
                                                   destination, excp)
        except UnsupportedBinding as excp:
            _resp = self.idp.create_error_response(_authn_req.id,
                                                   destination, excp)

        req_args = {}
        for key in ["subject", "name_id_policy", "conditions",
                    "requested_authn_context", "scoping", "force_authn",
                    "is_passive"]:
            try:
                val = getattr(_authn_req, key)
            except AttributeError:
                pass
            else:
                if val is not None:
                    req_args[key] = val

        return {"resp_args": resp_args, "response": _resp,
                "authn_req": _authn_req, "req_args": req_args, "encrypt_cert": encrypt_cert}

    def handle_authn_request(self, binding_in):
        """
        Deal with an authentication request

        :param binding_in: Which binding was used when receiving the query
        :return: A response if an error occurred or session information in a
            dictionary
        """

        _request = self.unpack(binding_in)
        _binding_in = service.INV_BINDING_MAP[binding_in]

        try:
            _dict = self.verify_request(_request["SAMLRequest"], _binding_in)
        except UnknownPrincipal as excp:
            logger.error("UnknownPrincipal: %s" % (excp,))
            resp = ServiceError("UnknownPrincipal: %s" % (excp,))
            return resp
        except UnsupportedBinding as excp:
            logger.error("UnsupportedBinding: %s" % (excp,))
            resp = ServiceError("UnsupportedBinding: %s" % (excp,))
            return resp

        _binding = _dict["resp_args"]["binding"]
        if _dict["response"]:  # An error response
            http_args = self.idp.apply_binding(
                _binding, "%s" % _dict["response"],
                _dict["resp_args"]["destination"],
                _request["RelayState"], response=True)

            logger.debug("HTTPargs: %s" % http_args)
            return self.response(_binding, http_args)
        else:
            return self.incomming(_dict, self, self.environ,
                                  self.start_response, _request["RelayState"])

    def get_tid1_resp(self, org_resp):
        tid1 = org_resp.assertion.subject.name_id.text
        return tid1

    def get_sp_entityid(self, resp_args):
        sp_entityid = resp_args["destination"]
        return sp_entityid

    def get_tid2_enc(self, tid1, sp_entityid):
        iv = None
        if self.encmsg_to_iv is not None:
            iv = self.tid_handler.get_new_iv()
        tid2_enc = self.tid_handler.tid2_encrypt(tid1, sp_entityid, iv=iv)
        if self.encmsg_to_iv is not None:
            self.encmsg_to_iv[tid2_enc] = iv
        return tid2_enc

    def get_tid2_hash(self, tid1, sp_entityid):
        tid2_hash = self.tid_handler.tid2_hash(tid1, sp_entityid)
        return tid2_hash

    def handle_tid(self, tid1, tid2):
        if self.tid1_to_tid2 is not None:
            self.tid1_to_tid2[tid1] = tid2
        if self.tid2_to_tid1 is not None:
            self.tid2_to_tid1[tid2] = tid1

    def name_id_exists(self, userid, name_id_policy, sp_entity_id):
        try:
            snq = name_id_policy.sp_name_qualifier
        except AttributeError:
            snq = sp_entity_id

        if not snq:
            snq = sp_entity_id

        kwa = {"sp_name_qualifier": snq}

        try:
            kwa["format"] = name_id_policy.format
        except AttributeError:
            pass
        return self.idp.ident.find_nameid(userid, **kwa)

    def construct_authn_response(self, identity, userid, authn, resp_args,
                                 relay_state, name_id=None, sign_response=True, org_resp=None, org_xml_response=None):
        """

        :param identity:
        :param name_id:
        :param authn:
        :param resp_args:
        :param relay_state:
        :param sign_response:
        :return:
        """
        if self.force_persistant_nameid:
            if "name_id_policy" in resp_args:
                resp_args["name_id_policy"].format = NAMEID_FORMAT_PERSISTENT

        sp_entityid = self.get_sp_entityid(resp_args)
        tid1 = self.get_tid1_resp(org_resp)
        userid = self.tid_handler.uid_hash(tid1)

        if self.force_no_userid_subject_cacheing:
            self.idp.ident = IdentDB({})

        name_id_exist = False
        if self.name_id_exists(userid, resp_args["name_id_policy"], resp_args["sp_entity_id"]):
            name_id_exist = True

        if not name_id_exist:
            if identity is not None:
                identity["uid"] = userid
            if self.tid2_to_tid1 is None:
                tid2 = self.get_tid2_enc(tid1, sp_entityid)
            else:
                tid2 = self.get_tid2_hash(tid1, sp_entityid)
        else:
            tid2 = None

        _resp = self.idp.create_authn_response(identity, userid=userid, name_id=name_id,
                                               authn=authn,
                                               sign_response=False,
                                               **resp_args)

        if not name_id_exist:
            #Fix for name_id so sid2 is used instead.
            _resp.assertion.subject.name_id.text = tid2
            self.idp.ident.remove_local(userid)
            self.idp.ident.store(userid, _resp.assertion.subject.name_id)

        tid2 = _resp.assertion.subject.name_id.text
        if self.tid2_to_tid1 is not None:
            self.tid2_to_tid1[tid2] = tid1
            if self.tid1_to_tid2 is not None:
                self.tid1_to_tid2[tid1] = tid2

        advice = None
        for tmp_assertion in org_resp.response.assertion:
            if tmp_assertion.advice is not None:
                advice = tmp_assertion.advice
                break
        if advice is not None:
            _resp.assertion.advice = advice
        #_resp.assertion = []

        if sign_response:
            _class_sign = class_name(_resp)
            _resp.signature = pre_signature_part(_resp.id, self.idp.sec.my_cert, 1)
            _resp = self.idp.sec.sign_statement(_resp, _class_sign, node_id=_resp.id)
        http_args = self.idp.apply_binding(
            resp_args["binding"], "%s" % _resp, resp_args["destination"],
            relay_state, response=True)

        logger.debug("HTTPargs: %s" % http_args)

        resp = None
        if http_args["data"]:
            resp = Response(http_args["data"], headers=http_args["headers"])
        else:
            for header in http_args["headers"]:
                if header[0] == "Location":
                    resp = Redirect(header[1])

        if not resp:
            resp = ServiceError("Don't know how to return response")

        return resp

    def register_endpoints(self):
        """
        Given the configuration, return a set of URL to function mappings.
        """
        url_map = []
        for endp, binding in self.idp.config.getattr("endpoints", "idp")[
                "single_sign_on_service"]:
            p = urlparse(endp)
            url_map.append(("^%s/(.*)$" % p.path[1:],
                            ("IDP", "handle_authn_request",
                             service.BINDING_MAP[binding])))
            url_map.append(("^%s$" % p.path[1:],
                            ("IDP", "handle_authn_request",
                             service.BINDING_MAP[binding])))

        return url_map
Ejemplo n.º 10
0
class TestServer1():
    def setup_class(self):
        self.server = Server("idp_conf")

        conf = config.SPConfig()
        conf.load_file("server_conf")
        self.client = client.Saml2Client(conf)

    def teardown_class(self):
        self.server.ident.close()

    def test_issuer(self):
        issuer = self.server._issuer()
        assert isinstance(issuer, saml.Issuer)
        assert _eq(issuer.keyswv(), ["text", "format"])
        assert issuer.format == saml.NAMEID_FORMAT_ENTITY
        assert issuer.text == self.server.config.entityid

    def test_assertion(self):
        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(),
        )

        assert _eq(assertion.keyswv(), ['attribute_statement', 'issuer', 'id',
                                        'subject', 'issue_instant', 'version'])
        assert assertion.version == "2.0"
        assert assertion.issuer.text == "urn:mace:example.com:saml:roland:idp"
        #
        assert assertion.attribute_statement
        attribute_statement = assertion.attribute_statement
        assert len(attribute_statement.attribute) == 2
        attr0 = attribute_statement.attribute[0]
        attr1 = attribute_statement.attribute[1]
        if attr0.attribute_value[0].text == "Derek":
            assert attr0.friendly_name == "givenName"
            assert attr1.friendly_name == "surName"
            assert attr1.attribute_value[0].text == "Jeter"
        else:
            assert attr1.friendly_name == "givenName"
            assert attr1.attribute_value[0].text == "Derek"
            assert attr0.friendly_name == "surName"
            assert attr0.attribute_value[0].text == "Jeter"
        # 
        subject = assertion.subject
        assert _eq(subject.keyswv(), ["text", "name_id"])
        assert subject.text == "_aaa"
        assert subject.name_id.format == saml.NAMEID_FORMAT_TRANSIENT

    def test_response(self):
        response = sigver.response_factory(
            in_response_to="_012345",
            destination="https:#www.example.com",
            status=s_utils.success_status_factory(),
            assertion=s_utils.assertion_factory(
                subject=factory(saml.Subject, text="_aaa",
                                name_id=saml.NAMEID_FORMAT_TRANSIENT),
                attribute_statement=do_attribute_statement(
                    {
                        ("", "", "surName"): ("Jeter", ""),
                        ("", "", "givenName"): ("Derek", ""),
                    }
                ),
                issuer=self.server._issuer(),
            ),
            issuer=self.server._issuer(),
        )

        print((response.keyswv()))
        assert _eq(response.keyswv(), ['destination', 'assertion', 'status',
                                       'in_response_to', 'issue_instant',
                                       'version', 'issuer', 'id'])
        assert response.version == "2.0"
        assert response.issuer.text == "urn:mace:example.com:saml:roland:idp"
        assert response.destination == "https:#www.example.com"
        assert response.in_response_to == "_012345"
        #
        status = response.status
        print(status)
        assert status.status_code.value == samlp.STATUS_SUCCESS

    def test_parse_faulty_request(self):
        req_id, authn_request = self.client.create_authn_request(
            destination="http://www.example.com", id="id1")

        # should raise an error because faulty spentityid
        binding = BINDING_HTTP_REDIRECT
        htargs = self.client.apply_binding(
            binding, "%s" % authn_request, "http://www.example.com", "abcd")
        _dict = parse_qs(htargs["headers"][0][1].split('?')[1])
        print(_dict)
        raises(OtherError, self.server.parse_authn_request,
               _dict["SAMLRequest"][0], binding)

    def test_parse_faulty_request_to_err_status(self):
        req_id, authn_request = self.client.create_authn_request(
            destination="http://www.example.com")

        binding = BINDING_HTTP_REDIRECT
        htargs = self.client.apply_binding(binding, "%s" % authn_request,
                                           "http://www.example.com", "abcd")
        _dict = parse_qs(htargs["headers"][0][1].split('?')[1])
        print(_dict)

        try:
            self.server.parse_authn_request(_dict["SAMLRequest"][0], binding)
            status = None
        except OtherError as oe:
            print((oe.args))
            status = s_utils.error_status_factory(oe)

        assert status
        print(status)
        assert _eq(status.keyswv(), ["status_code", "status_message"])
        assert status.status_message.text == 'Not destined for me!'
        status_code = status.status_code
        assert _eq(status_code.keyswv(), ["status_code", "value"])
        assert status_code.value == samlp.STATUS_RESPONDER
        assert status_code.status_code.value == samlp.STATUS_UNKNOWN_PRINCIPAL

    def test_parse_ok_request(self):
        req_id, authn_request = self.client.create_authn_request(
            message_id="id1", destination="http://*****:*****@nyy.mlb.com",
                "title": "The man"
            },
            "id12",                         # in_response_to
            "http://*****:*****@nyy.mlb.com"], "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(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"}

        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_slo_http_post(self):
        soon = time_util.in_a_while(days=1)
        sinfo = {
            "name_id": nid,
            "issuer": "urn:mace:example.com:saml:roland:idp",
            "not_on_or_after": soon,
            "user": {
                "givenName": "Leo",
                "surName": "Laport",
            }
        }
        self.client.users.add_information_about_person(sinfo)

        req_id, logout_request = self.client.create_logout_request(
            destination="http://localhost:8088/slop", name_id=nid,
            issuer_entity_id="urn:mace:example.com:saml:roland:idp",
            reason="I'm tired of this")

        _req = "%s" % logout_request
        intermed = base64.b64encode(_req.encode("utf8"))

        #saml_soap = make_soap_enveloped_saml_thingy(logout_request)
        request = self.server.parse_logout_request(intermed, BINDING_HTTP_POST)
        assert request

    def test_slo_soap(self):
        soon = time_util.in_a_while(days=1)
        sinfo = {
            "name_id": nid,
            "issuer": "urn:mace:example.com:saml:roland:idp",
            "not_on_or_after": soon,
            "user": {
                "givenName": "Leo",
                "surName": "Laport",
            }
        }

        sp = client.Saml2Client(config_file="server_conf")
        sp.users.add_information_about_person(sinfo)

        req_id, logout_request = sp.create_logout_request(
            name_id=nid, destination="http://localhost:8088/slo",
            issuer_entity_id="urn:mace:example.com:saml:roland:idp",
            reason="I'm tired of this")

        #_ = s_utils.deflate_and_base64_encode("%s" % (logout_request,))

        saml_soap = make_soap_enveloped_saml_thingy(logout_request)
        self.server.ident.close()
        idp = Server("idp_soap_conf")
        request = idp.parse_logout_request(saml_soap)
        idp.ident.close()
        assert request
Ejemplo n.º 11
0
class TestServer1():
    def setup_class(self):
        self.server = Server("idp_conf")

        conf = config.SPConfig()
        conf.load_file("server_conf")
        self.client = client.Saml2Client(conf)

    def teardown_class(self):
        self.server.ident.close()

    def test_issuer(self):
        issuer = self.server._issuer()
        assert isinstance(issuer, saml.Issuer)
        assert _eq(issuer.keyswv(), ["text", "format"])
        assert issuer.format == saml.NAMEID_FORMAT_ENTITY
        assert issuer.text == self.server.config.entityid

    def test_assertion(self):
        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(),
        )

        assert _eq(assertion.keyswv(), [
            'attribute_statement', 'issuer', 'id', 'subject', 'issue_instant',
            'version'
        ])
        assert assertion.version == "2.0"
        assert assertion.issuer.text == "urn:mace:example.com:saml:roland:idp"
        #
        assert assertion.attribute_statement
        attribute_statement = assertion.attribute_statement
        assert len(attribute_statement.attribute) == 2
        attr0 = attribute_statement.attribute[0]
        attr1 = attribute_statement.attribute[1]
        if attr0.attribute_value[0].text == "Derek":
            assert attr0.friendly_name == "givenName"
            assert attr1.friendly_name == "surName"
            assert attr1.attribute_value[0].text == "Jeter"
        else:
            assert attr1.friendly_name == "givenName"
            assert attr1.attribute_value[0].text == "Derek"
            assert attr0.friendly_name == "surName"
            assert attr0.attribute_value[0].text == "Jeter"
        #
        subject = assertion.subject
        assert _eq(subject.keyswv(), ["text", "name_id"])
        assert subject.text == "_aaa"
        assert subject.name_id.format == saml.NAMEID_FORMAT_TRANSIENT

    def test_response(self):
        response = sigver.response_factory(
            in_response_to="_012345",
            destination="https:#www.example.com",
            status=s_utils.success_status_factory(),
            assertion=s_utils.assertion_factory(
                subject=factory(saml.Subject,
                                text="_aaa",
                                name_id=saml.NAMEID_FORMAT_TRANSIENT),
                attribute_statement=do_attribute_statement({
                    ("", "", "surName"): ("Jeter", ""),
                    ("", "", "givenName"): ("Derek", ""),
                }),
                issuer=self.server._issuer(),
            ),
            issuer=self.server._issuer(),
        )

        print((response.keyswv()))
        assert _eq(response.keyswv(), [
            'destination', 'assertion', 'status', 'in_response_to',
            'issue_instant', 'version', 'issuer', 'id'
        ])
        assert response.version == "2.0"
        assert response.issuer.text == "urn:mace:example.com:saml:roland:idp"
        assert response.destination == "https:#www.example.com"
        assert response.in_response_to == "_012345"
        #
        status = response.status
        print(status)
        assert status.status_code.value == samlp.STATUS_SUCCESS

    def test_parse_faulty_request(self):
        req_id, authn_request = self.client.create_authn_request(
            destination="http://www.example.com", id="id1")

        # should raise an error because faulty spentityid
        binding = BINDING_HTTP_REDIRECT
        htargs = self.client.apply_binding(binding, "%s" % authn_request,
                                           "http://www.example.com", "abcd")
        _dict = parse_qs(htargs["headers"][0][1].split('?')[1])
        print(_dict)
        raises(OtherError, self.server.parse_authn_request,
               _dict["SAMLRequest"][0], binding)

    def test_parse_faulty_request_to_err_status(self):
        req_id, authn_request = self.client.create_authn_request(
            destination="http://www.example.com")

        binding = BINDING_HTTP_REDIRECT
        htargs = self.client.apply_binding(binding, "%s" % authn_request,
                                           "http://www.example.com", "abcd")
        _dict = parse_qs(htargs["headers"][0][1].split('?')[1])
        print(_dict)

        try:
            self.server.parse_authn_request(_dict["SAMLRequest"][0], binding)
            status = None
        except OtherError as oe:
            print((oe.args))
            status = s_utils.error_status_factory(oe)

        assert status
        print(status)
        assert _eq(status.keyswv(), ["status_code", "status_message"])
        assert status.status_message.text == 'Not destined for me!'
        status_code = status.status_code
        assert _eq(status_code.keyswv(), ["status_code", "value"])
        assert status_code.value == samlp.STATUS_RESPONDER
        assert status_code.status_code.value == samlp.STATUS_UNKNOWN_PRINCIPAL

    def test_parse_ok_request(self):
        req_id, authn_request = self.client.create_authn_request(
            message_id="id1", destination="http://*****:*****@nyy.mlb.com",
                "title": "The man"
            },
            "id12",  # in_response_to
            "http://*****:*****@nyy.mlb.com"],
            "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(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"
        }

        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_slo_http_post(self):
        soon = time_util.in_a_while(days=1)
        sinfo = {
            "name_id": nid,
            "issuer": "urn:mace:example.com:saml:roland:idp",
            "not_on_or_after": soon,
            "user": {
                "givenName": "Leo",
                "surName": "Laport",
            }
        }
        self.client.users.add_information_about_person(sinfo)

        req_id, logout_request = self.client.create_logout_request(
            destination="http://localhost:8088/slop",
            name_id=nid,
            issuer_entity_id="urn:mace:example.com:saml:roland:idp",
            reason="I'm tired of this")

        _req = "%s" % logout_request
        intermed = base64.b64encode(_req.encode("utf8"))

        #saml_soap = make_soap_enveloped_saml_thingy(logout_request)
        request = self.server.parse_logout_request(intermed, BINDING_HTTP_POST)
        assert request

    def test_slo_soap(self):
        soon = time_util.in_a_while(days=1)
        sinfo = {
            "name_id": nid,
            "issuer": "urn:mace:example.com:saml:roland:idp",
            "not_on_or_after": soon,
            "user": {
                "givenName": "Leo",
                "surName": "Laport",
            }
        }

        sp = client.Saml2Client(config_file="server_conf")
        sp.users.add_information_about_person(sinfo)

        req_id, logout_request = sp.create_logout_request(
            name_id=nid,
            destination="http://localhost:8088/slo",
            issuer_entity_id="urn:mace:example.com:saml:roland:idp",
            reason="I'm tired of this")

        #_ = s_utils.deflate_and_base64_encode("%s" % (logout_request,))

        saml_soap = make_soap_enveloped_saml_thingy(logout_request)
        self.server.ident.close()
        idp = Server("idp_soap_conf")
        request = idp.parse_logout_request(saml_soap)
        idp.ident.close()
        assert request