예제 #1
0
    def _encrypt_assertion(self, encrypt_cert, sp_entity_id, response, node_xpath=None):
        """ Encryption of assertions.

        :param encrypt_cert: Certificate to be used for encryption.
        :param sp_entity_id: Entity ID for the calling service provider.
        :param response: A samlp.Response
        :param node_xpath: Unquie path to the element to be encrypted.
        :return: A new samlp.Resonse with the designated assertion encrypted.
        """
        _certs = []
        cbxs = CryptoBackendXmlSec1(self.config.xmlsec_binary)
        if encrypt_cert:
            _certs = []
            _certs.append(encrypt_cert)
        elif sp_entity_id is not None:
            _certs = self.metadata.certs(sp_entity_id, "any", "encryption")
        exception = None
        for _cert in _certs:
            try:
                begin_cert = "-----BEGIN CERTIFICATE-----\n"
                end_cert = "\n-----END CERTIFICATE-----\n"
                if begin_cert not in _cert:
                    _cert = "%s%s" % (begin_cert, _cert)
                if end_cert not in _cert:
                    _cert = "%s%s" % (_cert, end_cert)
                _, cert_file = make_temp(_cert.encode('ascii'), decode=False)
                response = cbxs.encrypt_assertion(response, cert_file,
                                                  pre_encryption_part(), node_xpath=node_xpath)
                return response
            except Exception as ex:
                exception = ex
                pass
        if exception:
            raise exception
        return response
예제 #2
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
예제 #3
0
 def sign_response(self, response):
     response = '%s' % response
     # Sign assertion in the response
     xmlsec = CryptoBackendXmlSec1(
         os.environ.get('SAML2_XMLSEC', '/usr/bin/xmlsec1'))
     seccont = SecurityContext(xmlsec,
                               key_file=os.path.join(
                                   path, 'data', 'test.key'))
     signed_response = seccont.sign_statement(
         response, 'urn:oasis:names:tc:SAML:2.0:protocol:Response')
     return signed_response
예제 #4
0
def test_enc2():
    crypto = CryptoBackendXmlSec1(xmlsec_path)

    with closing(Server("idp_conf")) as server:
        name_id = server.ident.transient_nameid(
            "urn:mace:example.com:saml:roland:sp", "id12")

        resp_ = server.create_authn_response(
            IDENTITY,
            "id12",
            "http://lingon.catalogix.se:8087/",
            "urn:mace:example.com:saml:roland:sp",
            name_id=name_id)

    enc_resp = crypto.encrypt_assertion(resp_, full_path("pubkey.pem"),
                                        pre_encryption_part())

    assert enc_resp
예제 #5
0
    def __init__(self, *args, **kwargs):
        super(SpidSpResponseCheck, self).__init__(*args, **kwargs)
        self.category = "response"

        self.template_path = kwargs.get("template_path", self.template_path)
        self.metadata_etree = kwargs.get("metadata_etree")

        self.authn_request_url = kwargs.get("authn_request_url")
        self.authn_request_data = {}

        # signing
        self.crypto_backend = CryptoBackendXmlSec1(
            xmlsec_binary=kwargs.get("xmlsec_binary") or get_xmlsec1_bin())
        self.private_key_fpath = kwargs.get(
            "key_file") or SAML2_IDP_CONFIG["key_file"]
        # not used here ... so, commented.
        # self.public_cert_fpath = kwargs.get("cert_file") or SAML2_IDP_CONFIG["cert_file"]

        # tests
        self.tests = {}
        for i in kwargs.get("test_jsons", []):
            with open(i[0], "r") as json_data:
                self.tests.update(json.loads(json_data.read()))
        if not self.tests:
            self.tests.update(settings.RESPONSE_TESTS)
        self.test_names = kwargs.get("test_names") or self.tests.keys()

        self.attr_json = kwargs.get("attr_json")

        self.html_path = kwargs.get("html_path")
        self.no_send_response = kwargs.get("no_send_response")
        self.kwargs = kwargs
        self.status_codes = None

        self.authn_plugin = kwargs.get("authn_plugin")
        self.requests_session = kwargs.get("requests_session")

        self.request_method = kwargs.get("request_method")
        self.request_body = kwargs.get("request_body")
        self.request_content_type = kwargs.get("request_content_type")
예제 #6
0
def test_enc1():
    with closing(Server("idp_conf")) as server:
        name_id = server.ident.transient_nameid(
            "urn:mace:example.com:saml:roland:sp", "id12")

        resp_ = server.create_authn_response(
            IDENTITY,
            "id12",
            "http://lingon.catalogix.se:8087/",
            "urn:mace:example.com:saml:roland:sp",
            name_id=name_id)

    statement = pre_encrypt_assertion(resp_)

    tmpl = full_path("enc_tmpl.xml")
    # tmpl_file = open(tmpl, "w")
    # tmpl_file.write("%s" % pre_encryption_part())
    # tmpl_file.close()

    data = full_path("pre_enc.xml")
    # data_file = open(data, "w")
    # data_file.write("%s" % statement)
    # data_file.close()

    key_type = "des-192"
    com_list = [
        xmlsec_path, "encrypt", "--pubkey-cert-pem",
        full_path("pubkey.pem"), "--session-key", key_type, "--xml-data", data,
        "--node-xpath", ASSERT_XPATH
    ]

    crypto = CryptoBackendXmlSec1(xmlsec_path)
    (_stdout, _stderr, output) = crypto._run_xmlsec(com_list, [tmpl],
                                                    exception=EncryptError,
                                                    validate_output=False)

    print output
    assert _stderr == ""
    assert _stdout == ""
예제 #7
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
예제 #8
0
    def _parse_response(self,
                        xmlstr,
                        response_cls,
                        service,
                        binding,
                        outstanding_certs=None,
                        **kwargs):
        """ Deal with a Response

        :param xmlstr: The response as a xml string
        :param response_cls: What type of response it is
        :param binding: What type of binding this message came through.
        :param kwargs: Extra key word arguments
        :return: None if the reply doesn't contain a valid SAML Response,
            otherwise the response.
        """

        response = None

        if self.config.accepted_time_diff:
            kwargs["timeslack"] = self.config.accepted_time_diff

        if "asynchop" not in kwargs:
            if binding in [BINDING_SOAP, BINDING_PAOS]:
                kwargs["asynchop"] = False
            else:
                kwargs["asynchop"] = True

        if xmlstr:
            if "return_addrs" not in kwargs:
                if binding in [BINDING_HTTP_REDIRECT, BINDING_HTTP_POST]:
                    try:
                        # expected return address
                        kwargs["return_addrs"] = self.config.endpoint(
                            service, binding=binding)
                    except Exception:
                        logger.info("Not supposed to handle this!")
                        return None

            try:
                response = response_cls(self.sec, **kwargs)
            except Exception as exc:
                logger.info("%s" % exc)
                raise

            xmlstr = self.unravel(xmlstr, binding, response_cls.msgtype)
            origxml = xmlstr
            if outstanding_certs is not None:
                _response = samlp.any_response_from_string(xmlstr)
                if len(_response.encrypted_assertion) > 0:
                    _, cert_file = make_temp(
                        "%s" %
                        outstanding_certs[_response.in_response_to]["key"],
                        decode=False)
                    cbxs = CryptoBackendXmlSec1(self.config.xmlsec_binary)
                    xmlstr = cbxs.decrypt(xmlstr, cert_file)

            if not xmlstr:  # Not a valid reponse
                return None

            try:
                response = response.loads(xmlstr, False, origxml=origxml)
            except SigverError as err:
                logger.error("Signature Error: %s" % err)
                raise
            except UnsolicitedResponse:
                logger.error("Unsolicited response")
                raise
            except Exception as err:
                if "not well-formed" in "%s" % err:
                    logger.error("Not well-formed XML")
                    raise

            logger.debug("XMLSTR: %s" % xmlstr)

            if hasattr(response.response, 'encrypted_assertion'):
                for encrypted_assertion in response.response\
                        .encrypted_assertion:
                    if encrypted_assertion.extension_elements is not None:
                        assertion_list = extension_elements_to_elements(
                            encrypted_assertion.extension_elements, [saml])
                        for assertion in assertion_list:
                            _assertion = saml.assertion_from_string(
                                str(assertion))
                            response.response.assertion.append(_assertion)

            if response:
                response = response.verify()

            if not response:
                return None

                #logger.debug(response)

        return response
예제 #9
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