예제 #1
0
    def _response(self,
                  in_response_to,
                  consumer_url=None,
                  status=None,
                  issuer=None,
                  sign=False,
                  to_sign=None,
                  encrypt_assertion=False,
                  encrypt_cert=None,
                  **kwargs):
        """ Create a Response.

        :param in_response_to: The session identifier of the request
        :param consumer_url: The URL which should receive the response
        :param status: The status of the response
        :param issuer: The issuer of the response
        :param sign: Whether the response should be signed or not
        :param to_sign: If there are other parts to sign
        :param kwargs: Extra key word arguments
        :return: A Response instance
        """

        if not status:
            status = success_status_factory()

        _issuer = self._issuer(issuer)

        response = response_factory(issuer=_issuer,
                                    in_response_to=in_response_to,
                                    status=status)

        if consumer_url:
            response.destination = consumer_url

        self._add_info(response, **kwargs)

        if not sign and to_sign and not encrypt_assertion:
            return signed_instance_factory(response, self.sec, to_sign)

        if encrypt_assertion:
            sign_class = [(class_name(response), response.id)]
            if sign:
                response.signature = pre_signature_part(
                    response.id, self.sec.my_cert, 1)
            cbxs = CryptoBackendXmlSec1(self.config.xmlsec_binary)
            _, cert_file = make_temp("%s" % encrypt_cert, decode=False)
            response = cbxs.encrypt_assertion(response, cert_file,
                                              pre_encryption_part())
            #template(response.assertion.id))
            if sign:
                return signed_instance_factory(response, self.sec, sign_class)
            else:
                return response

        if sign:
            return self.sign(response, to_sign=to_sign)
        else:
            return response
예제 #2
0
파일: entity.py 프로젝트: 18600597055/hue
    def _response(self, in_response_to, consumer_url=None, status=None,
                  issuer=None, sign=False, to_sign=None,
                  encrypt_assertion=False, encrypt_cert=None, **kwargs):
        """ Create a Response.

        :param in_response_to: The session identifier of the request
        :param consumer_url: The URL which should receive the response
        :param status: The status of the response
        :param issuer: The issuer of the response
        :param sign: Whether the response should be signed or not
        :param to_sign: If there are other parts to sign
        :param kwargs: Extra key word arguments
        :return: A Response instance
        """

        if not status:
            status = success_status_factory()

        _issuer = self._issuer(issuer)

        response = response_factory(issuer=_issuer,
                                    in_response_to=in_response_to,
                                    status=status)

        if consumer_url:
            response.destination = consumer_url

        self._add_info(response, **kwargs)

        if not sign and to_sign and not encrypt_assertion:
            return signed_instance_factory(response, self.sec, to_sign)

        if encrypt_assertion:
            if sign:
                response.signature = pre_signature_part(response.id,
                                                        self.sec.my_cert, 1)
            cbxs = CryptoBackendXmlSec1(self.config.xmlsec_binary)
            _, cert_file = make_temp("%s" % encrypt_cert, decode=False)
            response = cbxs.encrypt_assertion(response, cert_file,
                                              pre_encryption_part())
                                              # template(response.assertion.id))
            if sign:
                if to_sign:
                    signed_instance_factory(response, self.sec, to_sign)
                else:
                    # default is to sign the whole response if anything
                    sign_class = [(class_name(response), response.id)]
                    return signed_instance_factory(response, self.sec,
                                                   sign_class)
            else:
                return response

        if sign:
            return self.sign(response, to_sign=to_sign)
        else:
            return response
예제 #3
0
    def do_authz_decision_query(self, entityid, assertion=None, sign=False):

        authz_decision_query = self.authz_decision_query(entityid, assertion)

        for destination in self.config.authz_services(entityid):
            to_sign = []
            if sign:
                authz_decision_query.signature = pre_signature_part(
                    authz_decision_query.id, self.sec.my_cert, 1)
                to_sign.append((class_name(authz_decision_query),
                                authz_decision_query.id))

                authz_decision_query = signed_instance_factory(
                    authz_decision_query, self.sec, to_sign)

            response = send_using_soap(authz_decision_query,
                                       destination,
                                       self.config.key_file,
                                       self.config.cert_file,
                                       ca_certs=self.config.ca_certs)
            if response:
                logger.info("Verifying response")
                response = self.authz_decision_query_response(response)

            if response:
                #not_done.remove(entity_id)
                logger.info("OK response from %s" % destination)
                return response
            else:
                logger.info("NOT OK response from %s" % destination)

        return None
예제 #4
0
    def test_exception_sign_verify_with_cert_from_instance(self):
        assertion = factory(
            saml.Assertion,
            version="2.0",
            id="id-11100",
            issuer=saml.Issuer(text="the-issuer"),
            issue_instant="2009-10-30T13:20:28Z",
            attribute_statement=do_attribute_statement({
                ("name:surName", "nameformat", "surName"): ("Föö", ""),
                ("name:givenName", "nameformat", "givenName"): ("Bär", ""),
            })
        )

        response = factory(
            samlp.Response,
            issuer=saml.Issuer(text="the-isser"),
            status=success_status_factory(),
            assertion=assertion,
            version="2.0",
            issue_instant="2099-10-30T13:20:28Z",
            id="id-22222",
            signature=sigver.pre_signature_part(
                "id-22222", self.sec.my_cert
            ),
        )

        to_sign = [(class_name(response), response.id)]

        s_response = sigver.signed_instance_factory(response, self.sec, to_sign)

        response2 = response_from_string(s_response)
        # Change something that should make everything fail
        response2.id = "id-23456"
        with raises(sigver.SignatureError):
            self.sec._check_signature(s_response, response2, class_name(response2))
예제 #5
0
    def test_exception_sign_verify_with_cert_from_instance(self):
        assertion = factory(saml.Assertion,
                            version="2.0",
                            id="11100",
                            issue_instant="2009-10-30T13:20:28Z",
                            #signature= sigver.pre_signature_part("11100",
                            # self.sec.my_cert),
                            attribute_statement=do_attribute_statement({
                                ("", "", "surName"): ("Foo", ""),
                                ("", "", "givenName"): ("Bar", ""),
                            })
        )

        response = factory(samlp.Response,
                           assertion=assertion,
                           id="22222",
                           signature=sigver.pre_signature_part("22222",
                                                               self.sec
                                                               .my_cert))

        to_sign = [(class_name(response), response.id)]

        s_response = sigver.signed_instance_factory(response, self.sec, to_sign)

        response2 = response_from_string(s_response)
        # Change something that should make everything fail
        response2.id = "23456"
        raises(sigver.SignatureError, self.sec._check_signature,
               s_response, response2, class_name(response2))
예제 #6
0
    def test_sign_verify_with_cert_from_instance(self):
        response = factory(samlp.Response,
                           assertion=self._assertion,
                           id="22222",
                           signature=sigver.pre_signature_part("22222",
                                                               self.sec
                                                               .my_cert))

        to_sign = [(class_name(self._assertion), self._assertion.id),
                   (class_name(response), response.id)]

        s_response = sigver.signed_instance_factory(response, self.sec, to_sign)

        response2 = response_from_string(s_response)

        ci = "".join(sigver.cert_from_instance(response2)[0].split())

        assert ci == self.sec.my_cert

        res = self.sec.verify_signature(s_response,
                                        node_name=class_name(samlp.Response()))

        assert res

        res = self.sec._check_signature(s_response, response2,
                                        class_name(response2), s_response)
        assert res == response2
예제 #7
0
파일: client.py 프로젝트: natebeacham/saml2
    def do_authz_decision_query(self, entityid, assertion=None, log=None, sign=False):

        authz_decision_query = self.authz_decision_query(entityid, assertion)

        for destination in self.config.authz_services(entityid):
            to_sign = []
            if sign:
                authz_decision_query.signature = pre_signature_part(authz_decision_query.id, self.sec.my_cert, 1)
                to_sign.append((class_name(authz_decision_query), authz_decision_query.id))

                authz_decision_query = signed_instance_factory(authz_decision_query, self.sec, to_sign)

            response = send_using_soap(
                authz_decision_query,
                destination,
                self.config.key_file,
                self.config.cert_file,
                log=log,
                ca_certs=self.config.ca_certs,
            )
            if response:
                if log:
                    log.info("Verifying response")
                response = self.authz_decision_query_response(response, log)

            if response:
                # not_done.remove(entity_id)
                if log:
                    log.info("OK response from %s" % destination)
                return response
            else:
                if log:
                    log.info("NOT OK response from %s" % destination)

        return None
예제 #8
0
    def test_sign_verify_assertion_with_cert_from_instance(self):
        assertion = factory(saml.Assertion,
                            version="2.0",
                            id="11100",
                            issue_instant="2009-10-30T13:20:28Z",
                            signature=sigver.pre_signature_part("11100",
                                                                self.sec
                                                                .my_cert),
                            attribute_statement=do_attribute_statement({
                                ("", "", "surName"): ("Fox", ""),
                                ("", "", "givenName"): ("Bear", ""),
                            })
        )

        to_sign = [(class_name(assertion), assertion.id)]
        s_assertion = sigver.signed_instance_factory(assertion, self.sec,
                                                     to_sign)
        print(s_assertion)
        ass = assertion_from_string(s_assertion)
        ci = "".join(sigver.cert_from_instance(ass)[0].split())
        assert ci == self.sec.my_cert

        res = self.sec.verify_signature(s_assertion,
                                        node_name=class_name(ass))
        assert res

        res = self.sec._check_signature(s_assertion, ass, class_name(ass))

        assert res
예제 #9
0
    def test_sign_response_2(self):
        assertion2 = factory( saml.Assertion,
            version= "2.0",
            id= "11122",
            issue_instant= "2009-10-30T13:20:28Z",
            signature= sigver.pre_signature_part("11122", self.sec.my_cert),
            attribute_statement=do_attribute_statement({
                    ("","","surName"): ("Fox",""),
                    ("","","givenName") :("Bear",""),
                })
            )
        response = factory(samlp.Response,
                assertion=assertion2,
                id="22233",
                signature=sigver.pre_signature_part("22233", self.sec.my_cert))

        to_sign = [(class_name(assertion2), assertion2.id),
                    (class_name(response), response.id)]

        s_response = sigver.signed_instance_factory(response, self.sec, to_sign)

        assert s_response is not None
        response2 = response_from_string(s_response)

        sass = response2.assertion[0]
        assert _eq(sass.keyswv(), ['attribute_statement', 'issue_instant',
                                'version', 'signature', 'id'])
        assert sass.version == "2.0"
        assert sass.id == "11122"

        item = self.sec.check_signature(response2, class_name(response),
                                        s_response)

        assert isinstance(item, samlp.Response)
예제 #10
0
파일: server.py 프로젝트: wibed/pysaml2
    def create_assertion_id_request_response(self,
                                             assertion_id,
                                             sign=None,
                                             sign_alg=None,
                                             digest_alg=None,
                                             **kwargs):
        try:
            (assertion, to_sign) = self.session_db.get_assertion(assertion_id)
        except KeyError:
            raise Unknown

        if to_sign:
            if assertion.signature is None:
                # XXX self.signing_algorithm self.digest_algorithm defined by entity
                # XXX this should be handled through entity.py
                # XXX sig/digest-allowed should be configurable
                sign_alg = sign_alg or self.signing_algorithm
                digest_alg = digest_alg or self.digest_algorithm

                assertion.signature = pre_signature_part(
                    assertion.id,
                    self.sec.my_cert,
                    1,
                    sign_alg=sign_alg,
                    digest_alg=digest_alg,
                )
            return signed_instance_factory(assertion, self.sec, to_sign)
        else:
            return assertion
예제 #11
0
    def test_sign_response(self):
        response = factory(samlp.Response,
                           assertion=self._assertion,
                           id="22222",
                           signature=sigver.pre_signature_part("22222",
                                                               self.sec
                                                               .my_cert))

        to_sign = [(class_name(self._assertion), self._assertion.id),
                   (class_name(response), response.id)]
        s_response = sigver.signed_instance_factory(response, self.sec, to_sign)

        assert s_response is not None
        print(s_response)
        response = response_from_string(s_response)
        sass = response.assertion[0]

        print(sass)
        assert _eq(sass.keyswv(), ['attribute_statement', 'issue_instant',
                                   'version', 'signature', 'id'])
        assert sass.version == "2.0"
        assert sass.id == "11111"

        item = self.sec.check_signature(response, class_name(response),
                                        s_response)
        assert isinstance(item, samlp.Response)
        assert item.id == "22222"
예제 #12
0
    def test_sign_verify_with_cert_from_instance(self):
        response = factory(
            samlp.Response,
            issuer=saml.Issuer(text="the-isser"),
            status=success_status_factory(),
            assertion=self._assertion,
            version="2.0",
            issue_instant="2099-10-30T13:20:28Z",
            id="id-22222",
            signature=sigver.pre_signature_part(
                "id-22222", self.sec.my_cert
            ),
        )

        to_sign = [(class_name(self._assertion), self._assertion.id),
                   (class_name(response), response.id)]

        s_response = sigver.signed_instance_factory(response, self.sec, to_sign)

        response2 = response_from_string(s_response)

        ci = "".join(sigver.cert_from_instance(response2)[0].split())

        assert ci == self.sec.my_cert

        res = self.sec.verify_signature(s_response,
                                        node_name=class_name(samlp.Response()))

        assert res

        res = self.sec._check_signature(s_response, response2,
                                        class_name(response2), s_response)
        assert res == response2
예제 #13
0
파일: entity.py 프로젝트: gbel/pysaml2
    def _response(self, in_response_to, consumer_url=None, status=None,
                  issuer=None, sign=False, to_sign=None, **kwargs):
        """ Create a Response.

        :param in_response_to: The session identifier of the request
        :param consumer_url: The URL which should receive the response
        :param status: The status of the response
        :param issuer: The issuer of the response
        :param sign: Whether the response should be signed or not
        :param to_sign: If there are other parts to sign
        :param kwargs: Extra key word arguments
        :return: A Response instance
        """

        if not status:
            status = success_status_factory()

        _issuer = self._issuer(issuer)

        response = response_factory(issuer=_issuer,
                                    in_response_to=in_response_to,
                                    status=status)

        if consumer_url:
            response.destination = consumer_url

        self._add_info(response, **kwargs)

        if sign:
            return self.sign(response, to_sign=to_sign)
        elif to_sign:
            return signed_instance_factory(response, self.sec, to_sign)
        else:
            return response
예제 #14
0
파일: server.py 프로젝트: Lefford/pysaml2
    def create_assertion_id_request_response(self, assertion_id, sign=False,
                                             sign_alg=None,
                                             digest_alg=None, **kwargs):
        """

        :param assertion_id:
        :param sign:
        :return:
        """

        try:
            (assertion, to_sign) = self.session_db.get_assertion(assertion_id)
        except KeyError:
            raise Unknown

        if to_sign:
            if assertion.signature is None:
                assertion.signature = pre_signature_part(assertion.id,
                                                         self.sec.my_cert, 1,
                                                         sign_alg=sign_alg,
                                                         digest_alg=digest_alg)

            return signed_instance_factory(assertion, self.sec, to_sign)
        else:
            return assertion
예제 #15
0
    def test_sign_response_2(self):
        assertion2 = factory( saml.Assertion,
            version= "2.0",
            id= "11122",
            issue_instant= "2009-10-30T13:20:28Z",
            signature= sigver.pre_signature_part("11122", self.sec.my_cert),
            attribute_statement=do_attribute_statement({
                    ("","","surName"): ("Fox",""),
                    ("","","givenName") :("Bear",""),
                })
            )
        response = factory(samlp.Response,
                assertion=assertion2,
                id="22233",
                signature=sigver.pre_signature_part("22233", self.sec.my_cert))

        to_sign = [(class_name(assertion2), assertion2.id),
                    (class_name(response), response.id)]

        s_response = sigver.signed_instance_factory(response, self.sec, to_sign)

        assert s_response is not None
        response2 = response_from_string(s_response)

        sass = response2.assertion[0]
        assert _eq(sass.keyswv(), ['attribute_statement', 'issue_instant',
                                'version', 'signature', 'id'])
        assert sass.version == "2.0"
        assert sass.id == "11122"

        item = self.sec.check_signature(response2, class_name(response),
                                        s_response)

        assert isinstance(item, samlp.Response)
예제 #16
0
    def create_assertion_id_request_response(self, assertion_id, sign=False,
                                             sign_alg=None,
                                             digest_alg=None, **kwargs):
        """

        :param assertion_id:
        :param sign:
        :return:
        """

        try:
            (assertion, to_sign) = self.session_db.get_assertion(assertion_id)
        except KeyError:
            raise Unknown

        if to_sign:
            if assertion.signature is None:
                assertion.signature = pre_signature_part(assertion.id,
                                                         self.sec.my_cert, 1,
                                                         sign_alg=sign_alg,
                                                         digest_alg=digest_alg)

            return signed_instance_factory(assertion, self.sec, to_sign)
        else:
            return assertion
예제 #17
0
파일: entity.py 프로젝트: sigmunau/pysaml2
    def _response(self, in_response_to, consumer_url=None, status=None,
                  issuer=None, sign=False, to_sign=None, **kwargs):
        """ Create a Response.

        :param in_response_to: The session identifier of the request
        :param consumer_url: The URL which should receive the response
        :param status: The status of the response
        :param issuer: The issuer of the response
        :param sign: Whether the response should be signed or not
        :param to_sign: If there are other parts to sign
        :param kwargs: Extra key word arguments
        :return: A Response instance
        """

        if not status:
            status = success_status_factory()

        _issuer = self._issuer(issuer)

        response = response_factory(issuer=_issuer,
                                    in_response_to=in_response_to,
                                    status=status)

        if consumer_url:
            response.destination = consumer_url

        self._add_info(response, **kwargs)

        if sign:
            self.sign(response, to_sign=to_sign)
        elif to_sign:
            return signed_instance_factory(response, self.sec, to_sign)
        else:
            return response
예제 #18
0
    def slo(self, request):
        """
        generate a SAML2 logout request; reset session; return IDP URL
        """
        session = request.SESSION
        session.set(self.session_auth_key, False)
        del session[self.session_user_properties]

        config = self._saml2_config()
        scl = Saml2Client(config)
        samluid = session.get(self.session_samluid_key, "")
        entityid = config.metadata.keys()[0]
        sp_url = self.saml2_sp_url
        actual_url = request.get("ACTUAL_URL", "")
        if not actual_url.startswith(sp_url):
            # the request was made from within a context we cannot handle
            return None
        session.set(self.session_storedurl_key, request.URL1)
        # we cannot simply call global_logout on the client since it doesn't know about our user...
        srvs = scl.metadata.single_logout_service(entityid, BINDING_HTTP_REDIRECT, "idpsso")
        destination = destinations(srvs)[0]
        samlrequest = scl.create_logout_request(destination, entityid, name_id=saml.NameID(text=samluid))
        samlrequest.session_index = samlp.SessionIndex(session.get(self.session_samlsessionindex_key))
        to_sign = []
        samlrequest = signed_instance_factory(samlrequest, scl.sec, to_sign)
        logger.info("SSO logout request: %s" % samlrequest.to_string())
        session_id = samlrequest.id
        rstate = scl._relay_state(session_id)
        msg = http_redirect_message(samlrequest, destination, rstate)
        headers = dict(msg["headers"])
        location = headers["Location"]
        logger.info("attempting to post: {loc}".format(loc=headers["Location"]))
        return location
예제 #19
0
    def test_sign_verify(self):
        response = factory(
            samlp.Response,
            issuer=saml.Issuer(text="the-isser"),
            status=success_status_factory(),
            assertion=self._assertion,
            version="2.0",
            issue_instant="2099-10-30T13:20:28Z",
            id="id-22233",
            signature=sigver.pre_signature_part(
                "id-22233", self.sec.my_cert
            ),
        )

        to_sign = [(class_name(self._assertion), self._assertion.id),
                   (class_name(response), response.id)]

        s_response = sigver.signed_instance_factory(response, self.sec,
                                                    to_sign)

        print(s_response)
        res = self.sec.verify_signature(s_response,
                                        node_name=class_name(samlp.Response()))

        print(res)
        assert res
예제 #20
0
    def test_sign_response(self):
        response = factory(
            samlp.Response,
            issuer=saml.Issuer(text="the-isser"),
            status=success_status_factory(),
            assertion=self._assertion,
            version="2.0",
            issue_instant="2099-10-30T13:20:28Z",
            id="id-22222",
            signature=sigver.pre_signature_part(
                "id-22222", self.sec.my_cert
            ),
        )

        to_sign = [(class_name(self._assertion), self._assertion.id),
                   (class_name(response), response.id)]
        s_response = sigver.signed_instance_factory(response, self.sec, to_sign)

        assert s_response is not None
        print(s_response)
        response = response_from_string(s_response)
        sass = response.assertion[0]

        print(sass)
        assert _eq(sass.keyswv(), ['issuer', 'attribute_statement', 'issue_instant',
                                   'version', 'signature', 'id'])
        assert sass.version == "2.0"
        assert sass.id == "id-11111"

        item = self.sec.check_signature(response, class_name(response), s_response)
        assert isinstance(item, samlp.Response)
        assert item.id == "id-22222"
예제 #21
0
파일: entity.py 프로젝트: caustin/pysaml2
    def sign(self, msg, mid=None, to_sign=None):
        if msg.signature is None:
            msg.signature = pre_signature_part(msg.id, self.sec.my_cert, 1)

        if mid is None:
            mid = msg.id

        try:
            to_sign.append([(class_name(msg), mid)])
        except AttributeError:
            to_sign = [(class_name(msg), mid)]

        logger.info("REQUEST: %s" % msg)

        return signed_instance_factory(msg, self.sec, to_sign)
예제 #22
0
    def test_sign_verify(self):
        response = factory(
            samlp.Response, assertion=self._assertion, id="22233",
            signature=sigver.pre_signature_part("22233", self.sec.my_cert))

        to_sign = [(class_name(self._assertion), self._assertion.id),
                   (class_name(response), response.id)]

        s_response = sigver.signed_instance_factory(response, self.sec, to_sign)

        print(s_response)
        res = self.sec.verify_signature(s_response,
                                        node_name=class_name(samlp.Response()))

        print(res)
        assert res
예제 #23
0
    def _message(self,
                 request_cls,
                 destination=None,
                 id=0,
                 consent=None,
                 extensions=None,
                 sign=False,
                 **kwargs):
        """
        Some parameters appear in all requests so simplify by doing
        it in one place

        :param request_cls: The specific request type
        :param destination: The recipient
        :param id: A message identifier
        :param consent: Whether the principal have given her consent
        :param extensions: Possible extensions
        :param kwargs: Key word arguments specific to one request type
        :return: An instance of the request_cls
        """
        if not id:
            id = sid(self.seed)

        req = request_cls(id=id,
                          version=VERSION,
                          issue_instant=instant(),
                          issuer=self._issuer(),
                          **kwargs)

        if destination:
            req.destination = destination

        if consent:
            req.consent = consent

        if extensions:
            req.extensions = extensions

        if sign:
            req.signature = pre_signature_part(req.id, self.sec.my_cert, 1)
            to_sign = [(class_name(req), req.id)]
        else:
            to_sign = []

        logger.info("REQUEST: %s" % req)

        return signed_instance_factory(req, self.sec, to_sign)
예제 #24
0
    def test_sign_verify(self):        
        response = factory(samlp.Response,
                assertion=self._assertion,
                id="22233",
                signature=sigver.pre_signature_part("22233", self.sec.my_cert))

        to_sign = [(class_name(self._assertion), self._assertion.id),
                    (class_name(response), response.id)]

        s_response = sigver.signed_instance_factory(response, self.sec, to_sign)

        print s_response
        res = self.sec.verify_signature("%s" % s_response, 
                                    node_name=class_name(samlp.Response()))

        print res        
        assert res
예제 #25
0
파일: entity.py 프로젝트: gbel/pysaml2
    def sign(self, msg, mid=None, to_sign=None, sign_prepare=False):
        if msg.signature is None:
            msg.signature = pre_signature_part(msg.id, self.sec.my_cert, 1)

        if sign_prepare:
            return msg

        if mid is None:
            mid = msg.id

        try:
            to_sign += [(class_name(msg), mid)]
        except (AttributeError, TypeError):
            to_sign = [(class_name(msg), mid)]

        logger.info("REQUEST: %s" % msg)
        return signed_instance_factory(msg, self.sec, to_sign)
예제 #26
0
파일: entity.py 프로젝트: sigmunau/pysaml2
    def sign(self, msg, mid=None, to_sign=None, sign_prepare=False):
        if msg.signature is None:
            msg.signature = pre_signature_part(msg.id, self.sec.my_cert, 1)

        if sign_prepare:
            return msg

        if mid is None:
            mid = msg.id

        try:
            to_sign.append([(class_name(msg), mid)])
        except AttributeError:
            to_sign = [(class_name(msg), mid)]

        logger.info("REQUEST: %s" % msg)
        return signed_instance_factory(msg, self.sec, to_sign)
예제 #27
0
    def create_logout_response(self, request, binding, status=None,
                               sign=False, issuer=None):
        """ Create a LogoutResponse. What is returned depends on which binding
        is used.
        
        :param request: The request this is a response to
        :param binding: Which binding the request came in over
        :param status: The return status of the response operation
        :param issuer: The issuer of the message
        :return: A logout message.
        """
        mid = sid()

        if not status:
            status = success_status_factory()

        # response and packaging differs depending on binding
        response = ""
        if binding in [BINDING_SOAP, BINDING_HTTP_POST]:
            response = logoutresponse_factory(sign=sign, id = mid,
                                              in_response_to = request.id,
                                              status = status)
        elif binding == BINDING_HTTP_REDIRECT:
            sp_entity_id = request.issuer.text.strip()
            srvs = self.metadata.single_logout_service(sp_entity_id, "spsso")
            if not srvs:
                raise Exception("Nowhere to send the response")

            destination = destinations(srvs)[0]

            _issuer = self.issuer(issuer)
            response = logoutresponse_factory(sign=sign, id = mid,
                                              in_response_to = request.id,
                                              status = status,
                                              issuer = _issuer,
                                              destination = destination,
                                              sp_entity_id = sp_entity_id,
                                              instant=instant())
        if sign:
            to_sign = [(class_name(response), mid)]
            response = signed_instance_factory(response, self.sec, to_sign)

        logger.info("Response: %s" % (response,))

        return response
예제 #28
0
    def test_sign_response_2(self):
        assertion2 = factory(
            saml.Assertion,
            version="2.0",
            id="id-11122",
            issuer=saml.Issuer(text="the-issuer-2"),
            issue_instant="2009-10-30T13:20:28Z",
            signature=sigver.pre_signature_part("id-11122", self.sec .my_cert),
            attribute_statement=do_attribute_statement({
                ("name:surName", "nameformat", "surName"): ("Räv", ""),
                ("name:givenName", "nameformat", "givenName"): ("Björn", ""),
            })
        )
        response = factory(
            samlp.Response,
            issuer=saml.Issuer(text="the-isser"),
            status=success_status_factory(),
            assertion=assertion2,
            version="2.0",
            issue_instant="2099-10-30T13:20:28Z",
            id="id-22233",
            signature=sigver.pre_signature_part("id-22233", self.sec.my_cert),
        )

        to_sign = [(class_name(assertion2), assertion2.id),
                   (class_name(response), response.id)]

        s_response = sigver.signed_instance_factory(response, self.sec, to_sign)

        assert s_response is not None
        response2 = response_from_string(s_response)

        sass = response2.assertion[0]
        assert _eq(sass.keyswv(), ['issuer', 'attribute_statement', 'issue_instant',
                                   'version', 'signature', 'id'])
        assert sass.version == "2.0"
        assert sass.id == "id-11122"

        item = self.sec.check_signature(response2, class_name(response),
                                        s_response)

        assert isinstance(item, samlp.Response)
예제 #29
0
    def sign(self, msg, mid=None, to_sign=None, sign_prepare=False,
             sign_alg=None, digest_alg=None):
        if msg.signature is None:
            msg.signature = pre_signature_part(msg.id, self.sec.my_cert, 1,
                                               sign_alg=sign_alg,
                                               digest_alg=digest_alg)

        if sign_prepare:
            return msg

        if mid is None:
            mid = msg.id

        try:
            to_sign += [(class_name(msg), mid)]
        except (AttributeError, TypeError):
            to_sign = [(class_name(msg), mid)]

        logger.info("REQUEST: %s", msg)
        return signed_instance_factory(msg, self.sec, to_sign)
예제 #30
0
    def _response(self, in_response_to, consumer_url=None, status=None,
                  issuer=None, sign=False, to_sign=None,
                  **kwargs):
        """ Create a Response that adhers to the ??? profile.
        
        :param in_response_to: The session identifier of the request
        :param consumer_url: The URL which should receive the response
        :param status: The status of the response
        :param issuer: The issuer of the response
        :param sign: Whether the response should be signed or not
        :param to_sign: What other parts to sign
        :param kwargs: Extra key word arguments
        :return: A Response instance
        """

        if not status: 
            status = success_status_factory()

        _issuer = self.issuer(issuer)

        response = response_factory(
            issuer=_issuer,
            in_response_to = in_response_to,
            status = status,
            )

        if consumer_url:
            response.destination = consumer_url

        for key, val in kwargs.items():
            setattr(response, key, val)

        if sign:
            try:
                to_sign.append((class_name(response), response.id))
            except AttributeError:
                to_sign = [(class_name(response), response.id)]


        return signed_instance_factory(response, self.sec, to_sign)
예제 #31
0
    def _message(self, request_cls, destination=None, id=0,
                 consent=None, extensions=None, sign=False, **kwargs):
        """
        Some parameters appear in all requests so simplify by doing
        it in one place

        :param request_cls: The specific request type
        :param destination: The recipient
        :param id: A message identifier
        :param consent: Whether the principal have given her consent
        :param extensions: Possible extensions
        :param kwargs: Key word arguments specific to one request type
        :return: An instance of the request_cls
        """
        if not id:
            id = sid(self.seed)

        req = request_cls(id=id, version=VERSION, issue_instant=instant(),
                          issuer=self._issuer(), **kwargs)

        if destination:
            req.destination = destination

        if consent:
            req.consent = consent

        if extensions:
            req.extensions = extensions

        if sign:
            req.signature = pre_signature_part(req.id, self.sec.my_cert, 1)
            to_sign = [(class_name(req), req.id)]
        else:
            to_sign = []

        logger.info("REQUEST: %s" % req)

        return signed_instance_factory(req, self.sec, to_sign)
예제 #32
0
    def slo(self, request):
        """
        generate a SAML2 logout request; reset session; return IDP URL
        """
        session = request.SESSION
        session.set(self.session_auth_key, False)
        del session[self.session_user_properties]

        config = self._saml2_config()
        scl = Saml2Client(config)
        samluid = session.get(self.session_samluid_key, '')
        entityid = config.metadata.keys()[0]
        sp_url = self.saml2_sp_url
        actual_url = request.get("ACTUAL_URL", '')
        if not actual_url.startswith(sp_url):
            # the request was made from within a context we cannot handle
            return None
        session.set(self.session_storedurl_key, request.URL1)
        # we cannot simply call global_logout on the client since it doesn't know about our user...
        srvs = scl.metadata.single_logout_service(entityid,
                                                  BINDING_HTTP_REDIRECT,
                                                  "idpsso")
        destination = destinations(srvs)[0]
        samlrequest = scl.create_logout_request(
            destination, entityid, name_id=saml.NameID(text=samluid))
        samlrequest.session_index = samlp.SessionIndex(
            session.get(self.session_samlsessionindex_key))
        to_sign = []
        samlrequest = signed_instance_factory(samlrequest, scl.sec, to_sign)
        logger.info('SSO logout request: %s' % samlrequest.to_string())
        session_id = samlrequest.id
        rstate = scl._relay_state(session_id)
        msg = http_redirect_message(samlrequest, destination, rstate)
        headers = dict(msg['headers'])
        location = headers['Location']
        logger.info(
            'attempting to post: {loc}'.format(loc=headers['Location']))
        return location
예제 #33
0
    def send_idp_response(self, req, resp):
        """
        :param req: The expected request
        :param resp: The response type to be used
        :return: A response
        """
        # make sure I got the request I expected
        assert isinstance(self.saml_request.message, req._class)

        try:
            self.test_sequence(req.tests["post"])
        except KeyError:
            pass

        # Pick information from the request that should be in the response
        args = self.instance.response_args(self.saml_request.message,
                                           [resp._binding])
        _mods = list(resp.__mro__[:])
        _mods.reverse()
        for m in _mods:
            try:
                args.update(self.json_config["args"][m.__name__])
            except KeyError:
                pass

        args.update(resp._response_args)

        for param in ["identity", "userid"]:
            if param in self.json_config:
                args[param] = self.json_config[param]

        if resp == ErrorResponse:
            func = getattr(self.instance, "create_error_response")
        else:
            _op = camel2underscore.sub(r'_\1', req._class.c_tag).lower()
            func = getattr(self.instance, "create_%s_response" % _op)

        sign = []
        for styp in ["sign_assertion", "sign_response"]:
            if styp in args:
                del args[styp]
                sign.append(styp)

        response = func(**args)
        response = resp(self).pre_processing(response)
        # and now for signing
        if sign:
            to_sign = []
            # Order is important, first assertion and then response if both
            if "sign_assertion" in sign:
                to_sign = [(class_name(response.assertion),
                            response.assertion.id)]
                response.assertion.signature = pre_signature_part(
                    response.assertion.id, self.instance.sec.my_cert, 1)
            if "sign_response" in sign:
                to_sign = [(class_name(response), response.id)]
                response.signature = pre_signature_part(
                    response.id, self.instance.sec.my_cert, 1)

            response = signed_instance_factory(response, self.instance.sec,
                                               to_sign)

        info = self.instance.apply_binding(resp._binding, response,
                                           args["destination"],
                                           self.relay_state, "SAMLResponse",
                                           resp._sign)

        if resp._binding == BINDING_HTTP_REDIRECT:
            url = None
            for param, value in info["headers"]:
                if param == "Location":
                    url = value
                    break
            self.last_response = self.instance.send(url)
        elif resp._binding == BINDING_HTTP_POST:
            resp = base64.b64encode("%s" % response)
            info["data"] = urllib.urlencode({
                "SAMLResponse": resp,
                "RelayState": self.relay_state
            })
            info["method"] = "POST"
            info["headers"] = {
                'Content-type': 'application/x-www-form-urlencoded'
            }
            self.last_response = self.instance.send(**info)

        self._log_response(self.last_response)
예제 #34
0
파일: server.py 프로젝트: howow/pysaml2
    def logout_response(self, request, bindings, status=None, sign=False, issuer=None):
        """ Create a LogoutResponse. What is returned depends on which binding
        is used.
        
        :param request: The request this is a response to
        :param bindings: Which bindings that can be used to send the response
        :param status: The return status of the response operation
        :param issuer: The issuer of the message
        :return: A 3-tuple consisting of HTTP return code, HTTP headers and 
            possibly a message.
        """
        sp_entity_id = request.issuer.text.strip()

        binding = None
        destinations = []
        for binding in bindings:
            destinations = self.conf.single_logout_services(sp_entity_id, binding)
            if destinations:
                break

        if not destinations:
            if self.log:
                self.log.error("Not way to return a response !!!")
            return ("412 Precondition Failed", [("Content-type", "text/html")], ["No return way defined"])

        # Pick the first
        destination = destinations[0]

        if self.log:
            self.log.info("Logout Destination: %s, binding: %s" % (destination, binding))
        if not status:
            status = success_status_factory()

        mid = sid()
        rcode = "200 OK"

        # response and packaging differs depending on binding

        if binding == BINDING_SOAP:
            response = logoutresponse_factory(sign=sign, id=mid, in_response_to=request.id, status=status)
            if sign:
                to_sign = [(class_name(response), mid)]
                response = signed_instance_factory(response, self.sec, to_sign)

            (headers, message) = http_soap_message(response)
        else:
            _issuer = self.issuer(issuer)
            response = logoutresponse_factory(
                sign=sign,
                id=mid,
                in_response_to=request.id,
                status=status,
                issuer=_issuer,
                destination=destination,
                sp_entity_id=sp_entity_id,
                instant=instant(),
            )
            if sign:
                to_sign = [(class_name(response), mid)]
                response = signed_instance_factory(response, self.sec, to_sign)

            if self.log:
                self.log.info("Response: %s" % (response,))
            if binding == BINDING_HTTP_REDIRECT:
                (headers, message) = http_redirect_message(response, destination, typ="SAMLResponse")
                rcode = "302 Found"
            else:
                (headers, message) = http_post_message(response, destination, typ="SAMLResponse")

        return rcode, headers, message
예제 #35
0
파일: base.py 프로젝트: jchysk/pysaml2
    def send_idp_response(self, req_flow, resp_flow):
        """
        :param req_flow: The flow to check the request
        :param resp_flow: The flow to prepare the response
        :return: The SP's HTTP response on receiving the SAML response
        """

        # Pick information from the request that should be in the response
        args = self.instance.response_args(self.saml_request.message,
                                           [resp_flow._binding])
        _mods = list(resp_flow.__mro__[:])
        _mods.reverse()
        for m in _mods:
            try:
                args.update(self.json_config["args"][m.__name__])
            except KeyError:
                pass

        args.update(resp_flow._response_args)

        for param in ["identity", "userid"]:
            if param in self.json_config:
                args[param] = self.json_config[param]

        if resp_flow == ErrorResponse:
            func = getattr(self.instance, "create_error_response")
        else:
            _op = camel2underscore.sub(r'_\1', req_flow._class.c_tag).lower()
            func = getattr(self.instance, "create_%s_response" % _op)

        # get from config which parts shall be signed
        sign = []
        for styp in ["sign_assertion", "sign_response"]:
            if styp in args:
                try:
                    if args[styp].lower() == "always":
                        sign.append(styp)
                    del args[styp]
                except (AttributeError, TypeError):
                    raise AssertionError('config parameters "sign_assertion", '
                                         '"sign_response" must be of type string')

        response = func(**args)
        response = resp_flow(self).pre_processing(response)
        # and now for signing
        if sign:
            to_sign = []
            try:
                _digest_alg=args["sign_digest_alg"]
            except KeyError:
                _digest_alg=None
            try:
                _sign_alg=args["sign_signature_alg"]
            except KeyError:
                _sign_alg=None
            # Order is important, first assertion and then response if both
            if "sign_assertion" in sign:
                to_sign = [(class_name(response.assertion),
                            response.assertion.id)]
                response.assertion.signature = pre_signature_part(
                    response.assertion.id, self.instance.sec.my_cert, 1,
                    digest_alg=_digest_alg, sign_alg=_sign_alg)
            if "sign_response" in sign:
                to_sign = [(class_name(response), response.id)]
                response.signature = pre_signature_part(
                    response.id, self.instance.sec.my_cert, 1,
                    digest_alg=_digest_alg, sign_alg=_sign_alg)

            response = signed_instance_factory(response, self.instance.sec,
                                               to_sign)

        info = self.instance.apply_binding(resp_flow._binding, response,
                                           args["destination"],
                                           self.relay_state,
                                           "SAMLResponse", resp_flow._sign)

        if resp_flow._binding == BINDING_HTTP_REDIRECT:
            url = None
            for param, value in info["headers"]:
                if param == "Location":
                    url = value
                    break
            self.last_response = self.instance.send(url)
        elif resp_flow._binding == BINDING_HTTP_POST:
            resp_flow = base64.b64encode("%s" % response)
            info["data"] = urllib.urlencode({"SAMLResponse": resp_flow,
                                             "RelayState": self.relay_state})
            info["method"] = "POST"
            info["headers"] = {
                'Content-type': 'application/x-www-form-urlencoded'}
            self.last_response = self.instance.send(**info)
            try:
                self.last_content = self.last_response.content
            except AttributeError:
                self.last_content = None

        self._log_response(self.last_response)
예제 #36
0
    def send_idp_response(self, req_flow, resp_flow):
        """
        :param req_flow: The flow to check the request
        :param resp_flow: The flow to prepare the response
        :return: The SP's HTTP response on receiving the SAML response
        """

        # Pick information from the request that should be in the response
        args = self.instance.response_args(self.saml_request.message,
                                           [resp_flow._binding])
        _mods = list(resp_flow.__mro__[:])
        _mods.reverse()
        for m in _mods:
            try:
                args.update(self.json_config["args"][m.__name__])
            except KeyError:
                pass

        args.update(resp_flow._response_args)

        for param in ["identity", "userid"]:
            if param in self.json_config:
                args[param] = self.json_config[param]

        if resp_flow == ErrorResponse:
            func = getattr(self.instance, "create_error_response")
        else:
            _op = camel2underscore.sub(r'_\1', req_flow._class.c_tag).lower()
            func = getattr(self.instance, "create_%s_response" % _op)

        # get from config which parts shall be signed
        sign = []
        for styp in ["sign_assertion", "sign_response"]:
            if styp in args:
                try:
                    if args[styp].lower() == "always":
                        sign.append(styp)
                    del args[styp]
                except (AttributeError, TypeError):
                    raise AssertionError('config parameters "sign_assertion", '
                                         '"sign_response" must be of type string')

        response = func(**args)
        response = resp_flow(self).pre_processing(response)
        # and now for signing
        if sign:
            to_sign = []
            try:
                _digest_alg=args["sign_digest_alg"]
            except KeyError:
                _digest_alg=None
            try:
                _sign_alg=args["sign_signature_alg"]
            except KeyError:
                _sign_alg=None
            # Order is important, first assertion and then response if both
            if "sign_assertion" in sign:
                to_sign = [(class_name(response.assertion),
                            response.assertion.id)]
                response.assertion.signature = pre_signature_part(
                    response.assertion.id, self.instance.sec.my_cert, 1,
                    digest_alg=_digest_alg, sign_alg=_sign_alg)
            if "sign_response" in sign:
                to_sign = [(class_name(response), response.id)]
                response.signature = pre_signature_part(
                    response.id, self.instance.sec.my_cert, 1,
                    digest_alg=_digest_alg, sign_alg=_sign_alg)

            response = signed_instance_factory(response, self.instance.sec,
                                               to_sign)

        info = self.instance.apply_binding(resp_flow._binding, response,
                                           args["destination"],
                                           self.relay_state,
                                           "SAMLResponse", resp_flow._sign)

        if resp_flow._binding == BINDING_HTTP_REDIRECT:
            url = None
            for param, value in info["headers"]:
                if param == "Location":
                    url = value
                    break
            self.last_response = self.instance.send(url)
        elif resp_flow._binding == BINDING_HTTP_POST:
            resp_flow = base64.b64encode("%s" % response)
            info["data"] = urllib.urlencode({"SAMLResponse": resp_flow,
                                             "RelayState": self.relay_state})
            info["method"] = "POST"
            info["headers"] = {
                'Content-type': 'application/x-www-form-urlencoded'}
            self.last_response = self.instance.send(**info)
            try:
                self.last_content = self.last_response.content
            except AttributeError:
                self.last_content = None

        self._log_response(self.last_response)
예제 #37
0
    def _response(self, in_response_to, consumer_url=None, status=None,
                  issuer=None, sign=False, to_sign=None, sp_entity_id=None,
                  encrypt_assertion=False, encrypt_assertion_self_contained=False, encrypted_advice_attributes=False,
                  encrypt_cert_advice=None, encrypt_cert_assertion=None,sign_assertion=None, pefim=False, **kwargs):
        """ Create a Response.
            Encryption:
                encrypt_assertion must be true for encryption to be performed. If encrypted_advice_attributes also is
                true, then will the function try to encrypt the assertion in the the advice element of the main
                assertion. Only one assertion element is allowed in the advice element, if multiple assertions exists
                in the advice element the main assertion will be encrypted instead, since it's no point to encrypt
                If encrypted_advice_attributes is
                false the main assertion will be encrypted. Since the same key

        :param in_response_to: The session identifier of the request
        :param consumer_url: The URL which should receive the response
        :param status: The status of the response
        :param issuer: The issuer of the response
        :param sign: Whether the response should be signed or not
        :param to_sign: If there are other parts to sign
        :param sp_entity_id: Entity ID for the calling service provider.
        :param encrypt_assertion: True if assertions should be encrypted.
        :param encrypt_assertion_self_contained: True if all encrypted assertions should have alla namespaces
        selfcontained.
        :param encrypted_advice_attributes: True if assertions in the advice element should be encrypted.
        :param encrypt_cert_advice: Certificate to be used for encryption of assertions in the advice element.
        :param encrypt_cert_assertion: Certificate to be used for encryption of assertions.
        :param sign_assertion: True if assertions should be signed.
        :param pefim: True if a response according to the PEFIM profile should be created.
        :param kwargs: Extra key word arguments
        :return: A Response instance
        """

        if not status:
            status = success_status_factory()

        _issuer = self._issuer(issuer)

        response = response_factory(issuer=_issuer,
                                    in_response_to=in_response_to,
                                    status=status)

        if consumer_url:
            response.destination = consumer_url

        self._add_info(response, **kwargs)

        if not sign and to_sign and not encrypt_assertion:
            return signed_instance_factory(response, self.sec, to_sign)

        has_encrypt_cert = self.has_encrypt_cert_in_metadata(sp_entity_id)
        if not has_encrypt_cert and encrypt_cert_advice is None:
            encrypted_advice_attributes = False
        if not has_encrypt_cert and encrypt_cert_assertion is None:
            encrypt_assertion = False

        if encrypt_assertion or (encrypted_advice_attributes and response.assertion.advice is not None and
                                         len(response.assertion.advice.assertion) == 1):
            if sign:
                response.signature = pre_signature_part(response.id,
                                                        self.sec.my_cert, 1)
                sign_class = [(class_name(response), response.id)]
            cbxs = CryptoBackendXmlSec1(self.config.xmlsec_binary)
            encrypt_advice = False
            if encrypted_advice_attributes and response.assertion.advice is not None \
                    and len(response.assertion.advice.assertion) > 0:
                _assertions = response.assertion
                if not isinstance(_assertions, list):
                    _assertions = [_assertions]
                for _assertion in _assertions:
                    _assertion.advice.encrypted_assertion = []
                    _assertion.advice.encrypted_assertion.append(EncryptedAssertion())
                    _advice_assertions = copy.deepcopy(_assertion.advice.assertion)
                    _assertion.advice.assertion = []
                    if not isinstance(_advice_assertions, list):
                        _advice_assertions = [_advice_assertions]
                    for tmp_assertion in _advice_assertions:
                        to_sign_advice = []
                        if sign_assertion and not pefim:
                            tmp_assertion.signature = pre_signature_part(tmp_assertion.id, self.sec.my_cert, 1)
                            to_sign_advice.append((class_name(tmp_assertion), tmp_assertion.id))
                        #tmp_assertion = response.assertion.advice.assertion[0]
                        _assertion.advice.encrypted_assertion[0].add_extension_element(tmp_assertion)

                        if encrypt_assertion_self_contained:
                            advice_tag = response.assertion.advice._to_element_tree().tag
                            assertion_tag = tmp_assertion._to_element_tree().tag
                            response = \
                                response.get_xml_string_with_self_contained_assertion_within_advice_encrypted_assertion(
                                    assertion_tag, advice_tag)
                        node_xpath = ''.join(["/*[local-name()=\"%s\"]" % v for v in
                                              ["Response", "Assertion", "Advice", "EncryptedAssertion", "Assertion"]])

                        if to_sign_advice:
                            response = signed_instance_factory(response, self.sec, to_sign_advice)
                        response = self._encrypt_assertion(encrypt_cert_advice, sp_entity_id, response, node_xpath=node_xpath)
                        response = response_from_string(response)

            if encrypt_assertion:
                to_sign_assertion = []
                if sign_assertion is not None and sign_assertion:
                    _assertions = response.assertion
                    if not isinstance(_assertions, list):
                        _assertions = [_assertions]
                    for _assertion in _assertions:
                        _assertion.signature = pre_signature_part(_assertion.id, self.sec.my_cert, 1)
                        to_sign_assertion.append((class_name(_assertion), _assertion.id))
                if encrypt_assertion_self_contained:
                    try:
                        assertion_tag = response.assertion._to_element_tree().tag
                    except:
                        assertion_tag = response.assertion[0]._to_element_tree().tag
                    response = pre_encrypt_assertion(response)
                    response = response.get_xml_string_with_self_contained_assertion_within_encrypted_assertion(
                        assertion_tag)

                if to_sign_assertion:
                    response = signed_instance_factory(response, self.sec, to_sign_assertion)
                response = self._encrypt_assertion(encrypt_cert_assertion, sp_entity_id, response)
            else:
                if to_sign:
                    response = signed_instance_factory(response, self.sec, to_sign)
            if sign:
                return signed_instance_factory(response, self.sec, sign_class)
            else:
                return response

        if sign:
            return self.sign(response, to_sign=to_sign)
        else:
            return response
예제 #38
0
    def _logout(self,
                subject_id,
                entity_ids,
                reason,
                expire,
                sign=None,
                return_to="/"):

        # check time
        if not not_on_or_after(expire):  # I've run out of time
            # Do the local logout anyway
            self.local_logout(subject_id)
            return 0, "504 Gateway Timeout", [], []

        # for all where I can use the SOAP binding, do those first
        not_done = entity_ids[:]
        response = False

        for entity_id in entity_ids:
            response = False

            for binding in [
                    BINDING_SOAP, BINDING_HTTP_POST, BINDING_HTTP_REDIRECT
            ]:
                destinations = self.config.single_logout_services(
                    entity_id, binding)
                if not destinations:
                    continue

                destination = destinations[0]

                logger.info("destination to provider: %s" % destination)
                request = self.construct_logout_request(
                    subject_id, destination, entity_id, reason, expire)

                to_sign = []
                #if sign and binding != BINDING_HTTP_REDIRECT:

                if sign is None:
                    sign = self.logout_requests_signed_default

                if sign:
                    request.signature = pre_signature_part(
                        request.id, self.sec.my_cert, 1)
                    to_sign = [(class_name(request), request.id)]

                logger.info("REQUEST: %s" % request)

                request = signed_instance_factory(request, self.sec, to_sign)

                if binding == BINDING_SOAP:
                    response = send_using_soap(request,
                                               destination,
                                               self.config.key_file,
                                               self.config.cert_file,
                                               ca_certs=self.config.ca_certs)
                    if response:
                        logger.info("Verifying response")
                        response = self.logout_response(response)

                    if response:
                        not_done.remove(entity_id)
                        logger.info("OK response from %s" % destination)
                    else:
                        logger.info("NOT OK response from %s" % destination)

                else:
                    session_id = request.id
                    rstate = self._relay_state(session_id)

                    self.state[session_id] = {
                        "entity_id": entity_id,
                        "operation": "SLO",
                        "entity_ids": entity_ids,
                        "subject_id": subject_id,
                        "reason": reason,
                        "not_on_of_after": expire,
                        "sign": sign,
                        "return_to": return_to
                    }

                    if binding == BINDING_HTTP_POST:
                        (head,
                         body) = http_post_message(request, destination,
                                                   rstate)
                        code = "200 OK"
                    else:
                        (head,
                         body) = http_redirect_message(request, destination,
                                                       rstate)
                        code = "302 Found"

                    return session_id, code, head, body

        if not_done:
            # upstream should try later
            raise LogoutError("%s" % (entity_ids, ))

        return 0, "", [], response
예제 #39
0
파일: base.py 프로젝트: HaToHo/saml2test
    def send_idp_response(self, req, resp):
        """
        :param req: The expected request
        :param resp: The response type to be used
        :return: A response
        """
        # make sure I got the request I expected
        assert isinstance(self.saml_request.message, req._class)

        try:
            self.test_sequence(req.tests["post"])
        except KeyError:
            pass

        # Pick information from the request that should be in the response
        args = self.instance.response_args(self.saml_request.message,
                                           [resp._binding])
        _mods = list(resp.__mro__[:])
        _mods.reverse()
        for m in _mods:
            try:
                args.update(self.json_config["args"][m.__name__])
            except KeyError:
                pass

        args.update(resp._response_args)

        for param in ["identity", "userid"]:
            if param in self.json_config:
                args[param] = self.json_config[param]

        if resp == ErrorResponse:
            func = getattr(self.instance, "create_error_response")
        else:
            _op = camel2underscore.sub(r'_\1', req._class.c_tag).lower()
            func = getattr(self.instance, "create_%s_response" % _op)

        sign = []
        for styp in ["sign_assertion", "sign_response"]:
            if styp in args:
                del args[styp]
                sign.append(styp)

        response = func(**args)
        response = resp(self).pre_processing(response)
        # and now for signing
        if sign:
            to_sign = []
            # Order is important, first assertion and then response if both
            if "sign_assertion" in sign:
                to_sign = [(class_name(response.assertion),
                            response.assertion.id)]
                response.assertion.signature = pre_signature_part(
                    response.assertion.id, self.instance.sec.my_cert, 1)
            if "sign_response" in sign:
                to_sign = [(class_name(response), response.id)]
                response.signature = pre_signature_part(
                    response.id, self.instance.sec.my_cert, 1)

            response = signed_instance_factory(response, self.instance.sec,
                                               to_sign)

        info = self.instance.apply_binding(resp._binding, response,
                                           args["destination"],
                                           self.relay_state,
                                           "SAMLResponse", resp._sign)

        if resp._binding == BINDING_HTTP_REDIRECT:
            url = None
            for param, value in info["headers"]:
                if param == "Location":
                    url = value
                    break
            self.last_response = self.instance.send(url)
        elif resp._binding == BINDING_HTTP_POST:
            resp = base64.b64encode("%s" % response)
            info["data"] = urllib.urlencode({"SAMLResponse": resp,
                                             "RelayState": self.relay_state})
            info["method"] = "POST"
            info["headers"] = {
                'Content-type': 'application/x-www-form-urlencoded'}
            self.last_response = self.instance.send(**info)

        self._log_response(self.last_response)
예제 #40
0
파일: client.py 프로젝트: natebeacham/saml2
    def authn_request(
        self,
        query_id,
        destination,
        service_url,
        spentityid,
        my_name="",
        vorg="",
        scoping=None,
        log=None,
        sign=None,
        binding=saml2.BINDING_HTTP_POST,
        nameid_format=saml.NAMEID_FORMAT_TRANSIENT,
    ):
        """ Creates an authentication request.
        
        :param query_id: The identifier for this request
        :param destination: Where the request should be sent.
        :param service_url: Where the reply should be sent.
        :param spentityid: The entity identifier for this service.
        :param my_name: The name of this service.
        :param vorg: The vitual organization the service belongs to.
        :param scoping: The scope of the request
        :param log: A service to which logs should be written
        :param sign: Whether the request should be signed or not.
        :param binding: The protocol to use for the Response !!
        :return: <samlp:AuthnRequest> instance
        """
        request = samlp.AuthnRequest(
            id=query_id,
            version=VERSION,
            issue_instant=instant(),
            assertion_consumer_service_url=service_url,
            protocol_binding=binding,
        )

        if destination:
            request.destination = destination
        if my_name:
            request.provider_name = my_name
        if scoping:
            request.scoping = scoping

        # Profile stuff, should be configurable
        if nameid_format == saml.NAMEID_FORMAT_TRANSIENT:
            name_id_policy = samlp.NameIDPolicy(allow_create="true", format=nameid_format)
        else:
            name_id_policy = samlp.NameIDPolicy(format=nameid_format)

        if vorg:
            try:
                name_id_policy.sp_name_qualifier = vorg
                name_id_policy.format = saml.NAMEID_FORMAT_PERSISTENT
            except KeyError:
                pass

        if sign is None:
            sign = self.authn_requests_signed_default

        if sign:
            request.signature = pre_signature_part(request.id, self.sec.my_cert, 1)
            to_sign = [(class_name(request), request.id)]
        else:
            to_sign = []

        request.name_id_policy = name_id_policy
        request.issuer = self.issuer(spentityid)

        if log is None:
            log = self.logger

        if log:
            log.info("REQUEST: %s" % request)

        return signed_instance_factory(request, self.sec, to_sign)
예제 #41
0
파일: client.py 프로젝트: natebeacham/saml2
    def _logout(self, subject_id, entity_ids, reason, expire, sign=None, log=None, return_to="/"):

        # check time
        if not not_on_or_after(expire):  # I've run out of time
            # Do the local logout anyway
            self.local_logout(subject_id)
            return 0, "504 Gateway Timeout", [], []

        # for all where I can use the SOAP binding, do those first
        not_done = entity_ids[:]
        response = False
        if log is None:
            log = self.logger

        for entity_id in entity_ids:
            response = False

            for binding in [BINDING_SOAP, BINDING_HTTP_POST, BINDING_HTTP_REDIRECT]:
                destinations = self.config.single_logout_services(entity_id, binding)
                if not destinations:
                    continue

                destination = destinations[0]

                if log:
                    log.info("destination to provider: %s" % destination)
                request = self.construct_logout_request(subject_id, destination, entity_id, reason, expire)

                to_sign = []
                # if sign and binding != BINDING_HTTP_REDIRECT:

                if sign is None:
                    sign = self.logout_requests_signed_default

                if sign:
                    request.signature = pre_signature_part(request.id, self.sec.my_cert, 1)
                    to_sign = [(class_name(request), request.id)]

                if log:
                    log.info("REQUEST: %s" % request)

                request = signed_instance_factory(request, self.sec, to_sign)

                if binding == BINDING_SOAP:
                    response = send_using_soap(
                        request,
                        destination,
                        self.config.key_file,
                        self.config.cert_file,
                        log=log,
                        ca_certs=self.config.ca_certs,
                    )
                    if response:
                        if log:
                            log.info("Verifying response")
                        response = self.logout_response(response, log)

                    if response:
                        not_done.remove(entity_id)
                        if log:
                            log.info("OK response from %s" % destination)
                    else:
                        if log:
                            log.info("NOT OK response from %s" % destination)

                else:
                    session_id = request.id
                    rstate = self._relay_state(session_id)

                    self.state[session_id] = {
                        "entity_id": entity_id,
                        "operation": "SLO",
                        "entity_ids": entity_ids,
                        "subject_id": subject_id,
                        "reason": reason,
                        "not_on_of_after": expire,
                        "sign": sign,
                        "return_to": return_to,
                    }

                    if binding == BINDING_HTTP_POST:
                        (head, body) = http_post_message(request, destination, rstate)
                        code = "200 OK"
                    else:
                        (head, body) = http_redirect_message(request, destination, rstate)
                        code = "302 Found"

                    return session_id, code, head, body

        if not_done:
            # upstream should try later
            raise LogoutError("%s" % (entity_ids,))

        return 0, "", [], response
예제 #42
0
파일: entity.py 프로젝트: Itxaka/pysaml2
    def _response(self, in_response_to, consumer_url=None, status=None,
                  issuer=None, sign=False, to_sign=None,
                  encrypt_assertion=False, encrypt_assertion_self_contained=False, encrypted_advice_attributes=False,
                  encrypt_cert=None, **kwargs):
        """ Create a Response.
            Encryption:
                encrypt_assertion must be true for encryption to be performed. If encrypted_advice_attributes also is
                true, then will the function try to encrypt the assertion in the the advice element of the main
                assertion. Only one assertion element is allowed in the advice element, if multiple assertions exists
                in the advice element the main assertion will be encrypted instead, since it's no point to encrypt
                If encrypted_advice_attributes is
                false the main assertion will be encrypted. Since the same key

        :param in_response_to: The session identifier of the request
        :param consumer_url: The URL which should receive the response
        :param status: The status of the response
        :param issuer: The issuer of the response
        :param sign: Whether the response should be signed or not
        :param to_sign: If there are other parts to sign
        :param kwargs: Extra key word arguments
        :return: A Response instance
        """

        if not status:
            status = success_status_factory()

        _issuer = self._issuer(issuer)

        response = response_factory(issuer=_issuer,
                                    in_response_to=in_response_to,
                                    status=status)

        if consumer_url:
            response.destination = consumer_url

        self._add_info(response, **kwargs)

        if not sign and to_sign and not encrypt_assertion:
            return signed_instance_factory(response, self.sec, to_sign)

        if encrypt_assertion:
            node_xpath = None
            if sign:
                response.signature = pre_signature_part(response.id,
                                                        self.sec.my_cert, 1)
                sign_class = [(class_name(response), response.id)]
            cbxs = CryptoBackendXmlSec1(self.config.xmlsec_binary)
            if encrypted_advice_attributes and response.assertion.advice is not None \
                    and len(response.assertion.advice.assertion) == 1:
                tmp_assertion = response.assertion.advice.assertion[0]
                response.assertion.advice.encrypted_assertion = []
                response.assertion.advice.encrypted_assertion.append(EncryptedAssertion())
                if isinstance(tmp_assertion, list):
                    response.assertion.advice.encrypted_assertion[0].add_extension_elements(tmp_assertion)
                else:
                    response.assertion.advice.encrypted_assertion[0].add_extension_element(tmp_assertion)
                response.assertion.advice.assertion = []
                if encrypt_assertion_self_contained:
                    advice_tag = response.assertion.advice._to_element_tree().tag
                    assertion_tag = tmp_assertion._to_element_tree().tag
                    response = response.get_xml_string_with_self_contained_assertion_within_advice_encrypted_assertion(
                        assertion_tag, advice_tag)
                node_xpath = ''.join(["/*[local-name()=\"%s\"]" % v for v in
                                      ["Response", "Assertion", "Advice", "EncryptedAssertion", "Assertion"]])
            elif encrypt_assertion_self_contained:
                assertion_tag = response.assertion._to_element_tree().tag
                response = pre_encrypt_assertion(response)
                response = response.get_xml_string_with_self_contained_assertion_within_encrypted_assertion(
                    assertion_tag)
            else:
                response = pre_encrypt_assertion(response)
            if to_sign:
                response = signed_instance_factory(response, self.sec, to_sign)
            _, cert_file = make_temp("%s" % encrypt_cert, decode=False)
            response = cbxs.encrypt_assertion(response, cert_file,
                                              pre_encryption_part(), node_xpath=node_xpath)
                                              # template(response.assertion.id))
            if sign:
                return signed_instance_factory(response, self.sec, sign_class)
            else:
                return response

        if sign:
            return self.sign(response, to_sign=to_sign)
        else:
            return response
예제 #43
0
    def _response(self,
                  in_response_to,
                  consumer_url=None,
                  status=None,
                  issuer=None,
                  sign=False,
                  to_sign=None,
                  encrypt_assertion=False,
                  encrypt_assertion_self_contained=False,
                  encrypted_advice_attributes=False,
                  encrypt_cert=None,
                  **kwargs):
        """ Create a Response.
            Encryption:
                encrypt_assertion must be true for encryption to be performed. If encrypted_advice_attributes also is
                true, then will the function try to encrypt the assertion in the the advice element of the main
                assertion. Only one assertion element is allowed in the advice element, if multiple assertions exists
                in the advice element the main assertion will be encrypted instead, since it's no point to encrypt
                If encrypted_advice_attributes is
                false the main assertion will be encrypted. Since the same key

        :param in_response_to: The session identifier of the request
        :param consumer_url: The URL which should receive the response
        :param status: The status of the response
        :param issuer: The issuer of the response
        :param sign: Whether the response should be signed or not
        :param to_sign: If there are other parts to sign
        :param kwargs: Extra key word arguments
        :return: A Response instance
        """

        if not status:
            status = success_status_factory()

        _issuer = self._issuer(issuer)

        response = response_factory(issuer=_issuer,
                                    in_response_to=in_response_to,
                                    status=status)

        if consumer_url:
            response.destination = consumer_url

        self._add_info(response, **kwargs)

        if not sign and to_sign and not encrypt_assertion:
            return signed_instance_factory(response, self.sec, to_sign)

        if encrypt_assertion:
            node_xpath = None
            if sign:
                response.signature = pre_signature_part(
                    response.id, self.sec.my_cert, 1)
                sign_class = [(class_name(response), response.id)]
            cbxs = CryptoBackendXmlSec1(self.config.xmlsec_binary)
            if encrypted_advice_attributes and response.assertion.advice is not None \
                    and len(response.assertion.advice.assertion) == 1:
                tmp_assertion = response.assertion.advice.assertion[0]
                response.assertion.advice.encrypted_assertion = []
                response.assertion.advice.encrypted_assertion.append(
                    EncryptedAssertion())
                if isinstance(tmp_assertion, list):
                    response.assertion.advice.encrypted_assertion[
                        0].add_extension_elements(tmp_assertion)
                else:
                    response.assertion.advice.encrypted_assertion[
                        0].add_extension_element(tmp_assertion)
                response.assertion.advice.assertion = []
                if encrypt_assertion_self_contained:
                    advice_tag = response.assertion.advice._to_element_tree(
                    ).tag
                    assertion_tag = tmp_assertion._to_element_tree().tag
                    response = response.get_xml_string_with_self_contained_assertion_within_advice_encrypted_assertion(
                        assertion_tag, advice_tag)
                node_xpath = ''.join([
                    "/*[local-name()=\"%s\"]" % v for v in [
                        "Response", "Assertion", "Advice",
                        "EncryptedAssertion", "Assertion"
                    ]
                ])
            elif encrypt_assertion_self_contained:
                assertion_tag = response.assertion._to_element_tree().tag
                response = pre_encrypt_assertion(response)
                response = response.get_xml_string_with_self_contained_assertion_within_encrypted_assertion(
                    assertion_tag)
            else:
                response = pre_encrypt_assertion(response)
            if to_sign:
                response = signed_instance_factory(response, self.sec, to_sign)
            _, cert_file = make_temp("%s" % encrypt_cert, decode=False)
            response = cbxs.encrypt_assertion(response,
                                              cert_file,
                                              pre_encryption_part(),
                                              node_xpath=node_xpath)
            # template(response.assertion.id))
            if sign:
                return signed_instance_factory(response, self.sec, sign_class)
            else:
                return response

        if sign:
            return self.sign(response, to_sign=to_sign)
        else:
            return response
예제 #44
0
    def logout_response(self, request, bindings, status=None, sign=False,
                        issuer=None):
        """ Create a LogoutResponse. What is returned depends on which binding
        is used.
        
        :param request: The request this is a response to
        :param bindings: Which bindings that can be used to send the response
        :param status: The return status of the response operation
        :param issuer: The issuer of the message
        :return: A 3-tuple consisting of HTTP return code, HTTP headers and 
            possibly a message.
        """
        sp_entity_id = request.issuer.text.strip()
        
        binding = None
        destinations = []
        for binding in bindings:
            destinations = self.conf.single_logout_services(sp_entity_id,
                                                           binding)
            if destinations:
                break
                

        if not destinations:
            logger.error("Not way to return a response !!!")
            return ("412 Precondition Failed",
                    [("Content-type", "text/html")],
                    ["No return way defined"])
        
        # Pick the first
        destination = destinations[0]

        logger.info("Logout Destination: %s, binding: %s" % (destination,
                                                                    binding))
        if not status: 
            status = success_status_factory()

        mid = sid()
        rcode = "200 OK"
        
        # response and packaging differs depending on binding
        
        if binding == BINDING_SOAP:
            response = logoutresponse_factory(
                                sign=sign,
                                id = mid,
                                in_response_to = request.id,
                                status = status,
                                )
            if sign:
                to_sign = [(class_name(response), mid)]
                response = signed_instance_factory(response, self.sec, to_sign)
                
            (headers, message) = http_soap_message(response)
        else:
            _issuer = self.issuer(issuer)
            response = logoutresponse_factory(
                                sign=sign,
                                id = mid,
                                in_response_to = request.id,
                                status = status,
                                issuer = _issuer,
                                destination = destination,
                                sp_entity_id = sp_entity_id,
                                instant=instant(),
                                )
            if sign:
                to_sign = [(class_name(response), mid)]
                response = signed_instance_factory(response, self.sec, to_sign)

            logger.info("Response: %s" % (response,))
            if binding == BINDING_HTTP_REDIRECT:
                (headers, message) = http_redirect_message(response, 
                                                            destination, 
                                                            typ="SAMLResponse")
                rcode = "302 Found"
            else:
                (headers, message) = http_post_message(response, destination,
                                                        typ="SAMLResponse")
                
        return rcode, headers, message
예제 #45
0
    def authn_request(self,
                      query_id,
                      destination,
                      service_url,
                      spentityid,
                      my_name="",
                      vorg="",
                      scoping=None,
                      log=None,
                      sign=None,
                      binding=BINDING_HTTP_POST,
                      nameid_format=saml.NAMEID_FORMAT_TRANSIENT,
                      **kwargs):
        """ Creates an authentication request.
        
        :param query_id: The identifier for this request
        :param destination: Where the request should be sent.
        :param service_url: Where the reply should be sent.
        :param spentityid: The entity identifier for this service.
        :param my_name: The name of this service.
        :param vorg: The vitual organization the service belongs to.
        :param scoping: The scope of the request
        :param log: A service to which logs should be written
        :param sign: Whether the request should be signed or not.
        :param binding: The protocol to use for the Response !!
        :return: <samlp:AuthnRequest> instance

        added: we want additional kw arguments, namely is_passive
        """
        request = samlp.AuthnRequest(
            id=query_id,
            version=VERSION,
            issue_instant=instant(),
            assertion_consumer_service_url=service_url,
            protocol_binding=binding,
            **kwargs)

        if destination:
            request.destination = destination
        if my_name:
            request.provider_name = my_name
        if scoping:
            request.scoping = scoping

        # Profile stuff, should be configurable
        if nameid_format == saml.NAMEID_FORMAT_TRANSIENT:
            name_id_policy = samlp.NameIDPolicy(allow_create="true",
                                                format=nameid_format)
        else:
            name_id_policy = samlp.NameIDPolicy(format=nameid_format)

        if vorg:
            try:
                name_id_policy.sp_name_qualifier = vorg
                name_id_policy.format = saml.NAMEID_FORMAT_PERSISTENT
            except KeyError:
                pass

        if sign is None:
            sign = self.authn_requests_signed

        if sign:
            request.signature = pre_signature_part(request.id,
                                                   self.sec.my_cert, 1)
            to_sign = [(class_name(request), request.id)]
        else:
            to_sign = []

        request.name_id_policy = name_id_policy
        request.issuer = self._issuer(spentityid)

        logger.info("REQUEST: %s" % request)

        return signed_instance_factory(request, self.sec, to_sign)
예제 #46
0
파일: client.py 프로젝트: GSA/pysaml2
    def do_logout(self, subject_id, entity_ids, reason, expire, sign=None):
        """

        :param subject_id: Identifier of the Subject
        :param entity_ids: List of entity ids for the IdPs that have provided
            information concerning the subject
        :param reason: The reason for doing the logout
        :param expire: Try to logout before this time.
        :param sign: Whether to sign the request or not
        :return:
        """
        # check time
        if not not_on_or_after(expire): # I've run out of time
            # Do the local logout anyway
            self.local_logout(subject_id)
            return 0, "504 Gateway Timeout", [], []
            
        # for all where I can use the SOAP binding, do those first
        not_done = entity_ids[:]
        responses = {}

        for entity_id in entity_ids:
            response = False

            for binding in [#BINDING_SOAP,
                            BINDING_HTTP_POST,
                            BINDING_HTTP_REDIRECT]:
                srvs = self.metadata.single_logout_service(entity_id, "idpsso",
                                                           binding=binding)
                if not srvs:
                    continue

                destination = destinations(srvs)[0]

                logger.info("destination to provider: %s" % destination)
                request = self.create_logout_request(destination, entity_id,
                                                     subject_id, reason=reason,
                                                     expire=expire)
                
                to_sign = []
                if binding.startswith("http://"):
                    sign = True

                if sign is None:
                    sign = self.logout_requests_signed_default

                if sign:
                    request.signature = pre_signature_part(request.id,
                                                    self.sec.my_cert, 1)
                    to_sign = [(class_name(request), request.id)]

                logger.info("REQUEST: %s" % request)

                srequest = signed_instance_factory(request, self.sec, to_sign)
        
                if binding == BINDING_SOAP:
                    response = self.send_using_soap(srequest, destination)
                    if response:
                        logger.info("Verifying response")
                        response = self.logout_request_response(response)

                    if response:
                        not_done.remove(entity_id)
                        logger.info("OK response from %s" % destination)
                        responses[entity_id] = logout_response_from_string(response)
                    else:
                        logger.info("NOT OK response from %s" % destination)

                else:
                    session_id = request.id
                    rstate = self._relay_state(session_id)

                    self.state[session_id] = {"entity_id": entity_id,
                                              "operation": "SLO",
                                              "entity_ids": entity_ids,
                                              "subject_id": subject_id,
                                              "reason": reason,
                                              "not_on_of_after": expire,
                                              "sign": sign}
                    

                    if binding == BINDING_HTTP_POST:
                        response = self.use_http_form_post(srequest,
                                                           destination,
                                                           rstate)
                    else:
                        response = self.use_http_get(srequest, destination,
                                                     rstate)

                    responses[entity_id] = response
                    not_done.remove(entity_id)

                # only try one binding
                break

        if not_done:
            # upstream should try later
            raise LogoutError("%s" % (entity_ids,))
        
        return responses
예제 #47
0
class Server(object):
    """ A class that does things that IdPs or AAs do """
    def __init__(self, config_file="", config=None, _cache="", stype="idp"):
        self.ident = None
        if config_file:
            self.load_config(config_file, stype)
        elif config:
            self.conf = config
        else:
            raise Exception("Missing configuration")

        self.conf.setup_logger()
            
        self.metadata = self.conf.metadata
        self.sec = security_context(self.conf)
        self._cache = _cache

        # if cache:
        #     if isinstance(cache, basestring):
        #         self.cache = Cache(cache)
        #     else:
        #         self.cache = cache
        # else:
        #     self.cache = Cache()
        
    def load_config(self, config_file, stype="idp"):
        """ Load the server configuration 
        
        :param config_file: The name of the configuration file
        :param stype: The type of Server ("idp"/"aa")
        """
        self.conf = config_factory(stype, config_file)
        if stype == "aa":
            return
        
        try:
            # subject information is stored in a database
            # default database is a shelve database which is OK in some setups
            dbspec = self.conf.subject_data
            idb = None
            if isinstance(dbspec, basestring):
                idb = shelve.open(dbspec, writeback=True)
            else: # database spec is a a 2-tuple (type, address)
                print >> sys.stderr, "DBSPEC: %s" % dbspec
                (typ, addr) = dbspec
                if typ == "shelve":
                    idb = shelve.open(addr, writeback=True)
                elif typ == "memcached":
                    idb = memcache.Client(addr)
                elif typ == "dict": # in-memory dictionary
                    idb = addr
                    
            if idb is not None:
                self.ident = Identifier(idb, self.conf.virtual_organization)
            else:
                raise Exception("Couldn't open identity database: %s" %
                                (dbspec,))
        except AttributeError:
            self.ident = None
    
    def issuer(self, entityid=None):
        """ Return an Issuer precursor """
        if entityid:
            return saml.Issuer(text=entityid,
                                format=saml.NAMEID_FORMAT_ENTITY)
        else:
            return saml.Issuer(text=self.conf.entityid,
                                format=saml.NAMEID_FORMAT_ENTITY)
        
    def parse_authn_request(self, enc_request, binding=BINDING_HTTP_REDIRECT):
        """Parse a Authentication Request
        
        :param enc_request: The request in its transport format
        :param binding: Which binding that was used to transport the message
            to this entity.
        :return: A dictionary with keys:
            consumer_url - as gotten from the SPs entity_id and the metadata
            id - the id of the request
            sp_entity_id - the entity id of the SP
            request - The verified request
        """
        
        response = {}
        _log_info = logger.info
        _log_debug = logger.debug

        # The addresses I should receive messages like this on
        receiver_addresses = self.conf.endpoint("single_sign_on_service",
                                                 binding)
        _log_info("receiver addresses: %s" % receiver_addresses)
        _log_info("Binding: %s" % binding)


        try:
            timeslack = self.conf.accepted_time_diff
            if not timeslack:
                timeslack = 0
        except AttributeError:
            timeslack = 0

        authn_request = AuthnRequest(self.sec,
                                     self.conf.attribute_converters,
                                     receiver_addresses, timeslack=timeslack)

        if binding == BINDING_SOAP or binding == BINDING_PAOS:
            # not base64 decoding and unzipping
            authn_request.debug=True
            _log_info("Don't decode")
            authn_request = authn_request.loads(enc_request, decode=False)
        else:
            authn_request = authn_request.loads(enc_request)

        _log_debug("Loaded authn_request")

        if authn_request:
            authn_request = authn_request.verify()

        _log_debug("Verified authn_request")

        if not authn_request:
            return None
            
        response["id"] = authn_request.message.id # put in in_reply_to

        sp_entity_id = authn_request.message.issuer.text
        # try to find return address in metadata
        try:
            # What's the binding ? ProtocolBinding
            _binding = authn_request.message.protocol_binding
            consumer_url = self.metadata.consumer_url(sp_entity_id,
                                                      binding=_binding)
        except KeyError:
            _log_info("Failed to find consumer URL for %s" % sp_entity_id)
            _log_info("entities: %s" % self.metadata.entity.keys())
            raise UnknownPrincipal(sp_entity_id)
            
        if not consumer_url: # what to do ?
            _log_info("Couldn't find a consumer URL binding=%s" % _binding)
            raise UnsupportedBinding(sp_entity_id)

        response["sp_entity_id"] = sp_entity_id

        if authn_request.message.assertion_consumer_service_url:
            return_destination = \
                        authn_request.message.assertion_consumer_service_url
        
            if consumer_url != return_destination:
                # serious error on someones behalf
                _log_info("%s != %s" % (consumer_url, return_destination))
                raise OtherError("ConsumerURL and return destination mismatch")
        
        response["consumer_url"] = consumer_url
        response["request"] = authn_request.message

        return response
                        
    def wants(self, sp_entity_id):
        """ Returns what attributes the SP requiers and which are optional
        if any such demands are registered in the Metadata.
        
        :param sp_entity_id: The entity id of the SP
        :return: 2-tuple, list of required and list of optional attributes
        """
        return self.metadata.requests(sp_entity_id)
        
    def parse_attribute_query(self, xml_string, decode=True):
        """ Parse an attribute query
        
        :param xml_string: The Attribute Query as an XML string
        :param decode: Whether the xmlstring is base64encoded and zipped
        :return: 3-Tuple containing:
            subject - identifier of the subject
            attribute - which attributes that the requestor wants back
            query - the whole query
        """
        receiver_addresses = self.conf.endpoint("attribute_service")
        attribute_query = AttributeQuery( self.sec, receiver_addresses)

        attribute_query = attribute_query.loads(xml_string, decode=decode)
        attribute_query = attribute_query.verify()

        logger.info("KEYS: %s" % attribute_query.message.keys())
        # Subject is described in the a saml.Subject instance
        subject = attribute_query.subject_id()
        attribute = attribute_query.attribute()

        return subject, attribute, attribute_query.message
            
    # ------------------------------------------------------------------------

    def _response(self, in_response_to, consumer_url=None, sp_entity_id=None, 
                    identity=None, name_id=None, status=None, sign=False,
                    policy=Policy(), authn=None, authn_decl=None, issuer=None):
        """ Create a Response that adhers to the ??? profile.
        
        :param in_response_to: The session identifier of the request
        :param consumer_url: The URL which should receive the response
        :param sp_entity_id: The entity identifier of the SP
        :param identity: A dictionary with attributes and values that are
            expected to be the bases for the assertion in the response.
        :param name_id: The identifier of the subject
        :param status: The status of the response
        :param sign: Whether the assertion should be signed or not 
        :param policy: The attribute release policy for this instance
        :param authn: A 2-tuple denoting the authn class and the authn
            authority
        :param authn_decl:
        :param issuer: The issuer of the response
        :return: A Response instance
        """
                
        to_sign = []

        if not status: 
            status = success_status_factory()

        _issuer = self.issuer(issuer)

        response = response_factory(
            issuer=_issuer,
            in_response_to = in_response_to,
            status = status,
            )

        if consumer_url:
            response.destination = consumer_url

        if identity:            
            ast = Assertion(identity)
            try:
                ast.apply_policy(sp_entity_id, policy, self.metadata)
            except MissingValue, exc:
                return self.error_response(in_response_to, consumer_url, 
                                               sp_entity_id, exc, name_id)

            if authn: # expected to be a 2-tuple class+authority
                (authn_class, authn_authn) = authn
                assertion = ast.construct(sp_entity_id, in_response_to, 
                                            consumer_url, name_id,
                                            self.conf.attribute_converters,
                                            policy, issuer=_issuer, 
                                            authn_class=authn_class, 
                                            authn_auth=authn_authn)
            elif authn_decl:
                assertion = ast.construct(sp_entity_id, in_response_to, 
                                            consumer_url, name_id,
                                            self.conf.attribute_converters,
                                            policy, issuer=_issuer, 
                                            authn_decl=authn_decl)
            else:
                assertion = ast.construct(sp_entity_id, in_response_to, 
                                            consumer_url, name_id,
                                            self.conf.attribute_converters,
                                            policy, issuer=_issuer)
            
            if sign:
                assertion.signature = pre_signature_part(assertion.id,
                                                        self.sec.my_cert, 1)
                # Just the assertion or the response and the assertion ?
                to_sign = [(class_name(assertion), assertion.id)]

            # Store which assertion that has been sent to which SP about which
            # subject.
            
            # self.cache.set(assertion.subject.name_id.text, 
            #                 sp_entity_id, {"ava": identity, "authn": authn}, 
            #                 assertion.conditions.not_on_or_after)
            
            response.assertion = assertion
                
        return signed_instance_factory(response, self.sec, to_sign)