Ejemplo n.º 1
0
    def correctly_signed_response(self, decoded_xml, must=False, origdoc=None):
        """ Check if a instance is correctly signed, if we have metadata for
        the IdP that sent the info use that, if not use the key that are in
        the message if any.

        :param decoded_xml: The SAML message as a XML string
        :param must: Whether there must be a signature
        :return: None if the signature can not be verified otherwise an instance
        """

        response = samlp.any_response_from_string(decoded_xml)
        if not response:
            raise TypeError("Not a Response")

        if response.signature:
            self._check_signature(decoded_xml, response, class_name(response),
                                  origdoc)

        if isinstance(response, Response) and response.assertion:
            # Try to find the signing cert in the assertion
            for assertion in response.assertion:
                if not assertion.signature:
                    logger.debug("unsigned")
                    if must:
                        raise SignatureError("Signature missing")
                    continue
                else:
                    logger.debug("signed")

                try:
                    self._check_signature(decoded_xml, assertion,
                                          class_name(assertion), origdoc)
                except Exception, exc:
                    logger.error("correctly_signed_response: %s" % exc)
                    raise
Ejemplo n.º 2
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, 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, err:
                logger.error("Signature Error: %s" % err)
                raise
Ejemplo n.º 3
0
    def urlhandler_acs_post(self, sh, environ, local_webenv, path, start_response, tester, webio):
        formdata = get_post(environ).decode('utf8')
        resp = dict([(k, v[0]) for k, v in parse_qs(formdata).items()])

        try:
            test_id = sh['conv'].test_id
        except KeyError as err:
            test_id = None

        if not test_id:
            """
                Do we have been initialized already, or is the user just on the wrong page ?
            """
            if not resp:
                return tester.display_test_list()
            """
            In other words: we've been contacted by robobrowser and are in a different environment now, than the
            code expects us to be. .... Hopefully, trickery and recreating of the environment will lead mostly
            to more intended effects than unintended ones.

            This is unfinished business: You can add other bindings here, to expand what RB can be used to test.
            """
            try:
                txt = resp['SAMLResponse']
                xmlstr = Entity.unravel(txt, BINDING_HTTP_POST)
            except Exception as e:
                msg = 'Decoding not supported in the SP'
                raise Exception(msg)

            rsp = samlp.any_response_from_string(xmlstr)
            original_request_id = rsp.in_response_to
            requester_session = self.session_store.get_session_by_conv_id(original_request_id)

            # recreating the environment. lets hope it is somewhat reentrant resistant
            sh = requester_session
            webio = WebIO(session=sh, **local_webenv)
            webio.environ = environ
            webio.start_response = start_response

            tester = Tester(webio, sh, **local_webenv)

        profile_handler = local_webenv['profile_handler']
        _sh = profile_handler(sh)
        # filename = self.webenv['profile_handler'](sh).log_path(test_id)
        # _sh.session.update({'conv': 'foozbar'})
        logfilename = _sh.log_path(test_id)

        content = do_next(tester, resp, sh, webio, logfilename, path)
        return content
Ejemplo n.º 4
0
    def correctly_signed_response(self, decoded_xml, must=False, origdoc=None):
        """ Check if a instance is correctly signed, if we have metadata for
        the IdP that sent the info use that, if not use the key that are in
        the message if any.

        :param decoded_xml: The SAML message as a XML string
        :param must: Whether there must be a signature
        :param origdoc:
        :return: None if the signature can not be verified otherwise an instance
        """

        response = samlp.any_response_from_string(decoded_xml)
        if not response:
            raise TypeError("Not a Response")

        if response.signature:
            self._check_signature(decoded_xml, response, class_name(response),
                                  origdoc)

        if isinstance(response, Response) and response.assertion:
            # Try to find the signing cert in the assertion
            for assertion in response.assertion:
                if not assertion.signature:
                    logger.debug("unsigned")
                    if must:
                        raise SignatureError("Signature missing")
                    continue
                else:
                    logger.debug("signed")

                try:
                    self._check_signature(decoded_xml, assertion,
                                          class_name(assertion), origdoc)
                except Exception, exc:
                    logger.error("correctly_signed_response: %s" % exc)
                    raise
Ejemplo n.º 5
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