def _func(self, conv=None, output=None): response = conv.events.get_message(EV_PROTOCOL_RESPONSE, AuthnResponse).response # Assumes only one assertion # TODO deal with more then one assertion if necessary subj = response.assertion[0].subject request = conv.events.get_message(EV_PROTOCOL_REQUEST, AuthnRequest) # Nameid format nformat = sp_name_qualifier = '' if "name_id.format" in self._kwargs: nformat = self._kwargs["name_id.format"] else: if request.name_id_policy: nformat = request.name_id_policy.format sp_name_qualifier = request.name_id_policy.sp_name_qualifier if request.name_id_policy: sp_name_qualifier = request.name_id_policy.sp_name_qualifier res = TestResult(self.cid) if nformat: if subj.name_id.format == nformat: if sp_name_qualifier: if subj.name_id.sp_name_qualifier != sp_name_qualifier: res.message = "The IdP returns wrong NameID format" res.status = CRITICAL else: res.message = "The IdP returns wrong NameID format" res.status = CRITICAL return res
def _func(self, conv): signing_algorithms = conv.crypto_algorithms['signing_algorithms'] req = conv.events.get_message(EV_PROTOCOL_REQUEST, request.AuthnRequest) res = TestResult(self.cid) if req.message.signature is None: res.message = 'Missing response signature' res.status = CRITICAL sig_alg = req.message.signature.signed_info.signature_method.algorithm if sig_alg not in signing_algorithms: res.message = "Not allowed digest algorithm: {}".format(sig_alg) res.status = CRITICAL return res
def _func(self, conv): digest_algorithms = conv.crypto_algorithms['digest_algorithms'] req = conv.events.get_message(EV_PROTOCOL_REQUEST, request.AuthnRequest) res = TestResult(self.cid) if req.message.signature is None: res.message = 'Missing response signature' res.status = CRITICAL for ref in req.message.signature.signed_info.reference: if ref.digest_method.algorithm not in digest_algorithms: res.message = "Not allowed digest algorithm: {}".format( ref.digest_method.algorithm) res.status = CRITICAL break return res
def _binding_support(self, conv, request, binding, typ): service = REQ2SRV[request] md = conv.entity.metadata entity_id = conv.entity_id func = getattr(md, service, None) res = TestResult(self.cid) try: func(entity_id, binding, typ) except UnknownPrincipal: res.message = "Unknown principal: %s" % entity_id res.status = CRITICAL except UnsupportedBinding: res.message = "Unsupported binding at the IdP: %s" % binding res.status = CRITICAL return res
def _func(self, conv=None): ava = conv.events.get_message(EV_PROTOCOL_RESPONSE, AuthnResponse).ava conf = conv.entity.config entcat = conv.extra_args["entcat"] req_attr = conf.getattr('required_attributes', 'sp') ec_attr = [] for ec in conf.entity_category: ec_attr.extend(entcat[ec]) # I would expect IdPs to release attributes that I'm allowed # to receive according to the ent cat classification and # I require them missing = [] if req_attr: for attr in req_attr: if attr in ec_attr and attr not in ava: missing.append(attr) res = TestResult(self.cid) if missing: res.message = "Attributes I expected but not received: {}".format( missing) res.status = CRITICAL return res
def _func(self, conv): entity_id = conv.events.last_item('issuer') md = conv.entity.metadata res = TestResult(self.cid) try: srv = md.service(entity_id, self._kwargs['typ'], self._kwargs['service'], binding=self._kwargs['binding']) except KeyError: res.message = "Can't find service" res.status = CRITICAL else: if not srv: res.message = "Can't find service" res.status = CRITICAL return res
def _func(self, conv): # Check that the logout response says it was a success resp = conv.events.last_item(EV_PROTOCOL_RESPONSE) status = resp.response.status res = TestResult(self.cid) if status.status_code.value != STATUS_SUCCESS: res.message = self.msg res.status = CRITICAL else: # Check that there are no valid cookies # should only result in a warning if conv.entity.cookies(conv.destination): res.message = "Remaining cookie ?" res.status = WARNING return res
def _func(self, conv): req = conv.events.last_item(EV_RESPONSE) res = TestResult(self.cid) # First, was the whole message signed if 'SigAlg' in req: if not verify_redirect_signature( req['SAMLRequest'], conv.entity.sec): res.message = "Was not able to verify Redirect message " \ "signature" res.status = CRITICAL # Secondly, was the XML doc signed req = conv.events.get_message(EV_PROTOCOL_REQUEST, request.AuthnRequest) if req.message.signature is None: res.message = 'Missing response signature' res.status = CRITICAL return res
def _func(self, conv): html = conv.events.last_item(EV_HTML_SRC) pattern = conv.extra_args['target_info']['echopageContentPattern'] res = TestResult(self.cid) for pat in pattern: if not re.search(pat, html): res.message = "Could not find '{}' on page".format(pat) res.status = CRITICAL return res
def _func(self, conv): redirect = conv.events.last_item(EV_REDIRECT_URL) res = TestResult(self.cid) if '?' not in redirect: res.message = "Incorrect redirect url" res.status = CRITICAL return res req = dict( [(k, v[0]) for k, v in parse_qs(redirect.split('?')[1]).items()]) try: saml_req = req["SAMLRequest"] except KeyError: res.message = "No SAMLRequest query parameter" res.status = CRITICAL return res _srv = conv.entity if not _srv.parse_authn_request(saml_req): res.message = "No or incorrect AuthnRequest" res.status = CRITICAL return res
def __call__(self): mdict = self.conv.entity.metadata.metadata # Should only be one of each md = list(mdict.values())[0] ed = list(md.entity.values())[0] res = TestResult('CheckSaml2IntMetaData') assert len(ed["idpsso_descriptor"]) idpsso = ed["idpsso_descriptor"][0] # contact person if "contact_person" not in idpsso and "contact_person" not in ed: res.message = "Metadata should contain contact person information" res.status = WARNING return res else: item = [] if "contact_person" in idpsso: for contact in idpsso["contact_person"]: item.append(contact["contact_type"]) if "contact_person" in ed: for contact in ed["contact_person"]: item.append(contact["contact_type"]) if "support" in item and "technical" in item: pass elif "support" not in item and "technical" not in item: res.message = "Missing technical and support contact information" res.status = WARNING elif "technical" not in item: res.message = "Missing technical contact information" res.status = WARNING elif "support" not in item: res.message = "Missing support contact information" res.status = WARNING if res: return res # NameID format if "name_id_format" not in idpsso: res.message = "Metadata should specify NameID format support" res.status = WARNING return res else: # should support Transient id_formats = [] for nformat in idpsso["name_id_format"]: id_formats.append(nformat["text"]) if NAMEID_FORMAT_TRANSIENT not in id_formats: res.message = "IdP should support Transient NameID Format" res.status = WARNING return res
def _func(self, conv=None, output=None): res = TestResult(self.cid) if "saml_status" in self._kwargs: status_value = self._kwargs["saml_status"] else: res.message = "Configuration Error: Missing saml_status in assert verify_saml_status" res.status = CRITICAL return res if status_value == 'urn:oasis:names:tc:SAML:2.0:status:Success': """ We can't check for success because saml2 testing doesn't tell. So we assume, that if we don't see any status errors it should have been a success. """ we_had_errors = False for test_exception in STATUSCODE2EXCEPTION: try: exception = conv.events.get_message(EV_PROTOCOL_RESPONSE, test_exception) except Exception as e: pass else: we_had_errors = True if we_had_errors: res.message = "ERROR: {}: {}".format(exception.__class__.__name__, str(exception)) res.status = CRITICAL else: res.message = "No errors reported, assuming {}".format(status_value) return res else: try: status_error_exception = STATUSCODE2EXCEPTION[status_value] except Exception as e: res.message = "Configuration Error: Can not find a definition for {} ".format(status_value) res.status = CRITICAL return res try: exception = conv.events.get_message(EV_PROTOCOL_RESPONSE, status_error_exception) except Exception as e: res.message = "Status error {} was not found ".format(status_value) res.status = CRITICAL return res res.message = "{}: {}".format(exception.__class__.__name__, str(exception)) return res if "saml_status" in self._kwargs: status_value = self._kwargs["saml_status"] if response.status.status_code.value == status_value: res = TestResult(self.cid) else: res.message = "The test target returned status = %s, but the " "test configuration expected %s." % \ (response.status.status_code.value.status_value) res.status = CRITICAL else: res.message = "Missing saml_status in assert verify_saml_status" res.status = CRITICAL return res