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