def verify(self, **kwargs): super(IdToken, self).verify(**kwargs) try: if kwargs["iss"] != self["iss"]: raise IssuerMismatch("{} != {}".format(kwargs["iss"], self["iss"])) except KeyError: pass if "aud" in self: if "client_id" in kwargs: # check that I'm among the recipients if kwargs["client_id"] not in self["aud"]: raise NotForMe( "{} not in aud:{}".format(kwargs["client_id"], self["aud"]), self, ) # Then azp has to be present and be one of the aud values if len(self["aud"]) > 1: if "azp" not in self: raise VerificationError("azp missing", self) if self["azp"] not in self["aud"]: raise VerificationError( "Mismatch between azp and aud claims", self) if "azp" in self: if "client_id" in kwargs: if kwargs["client_id"] != self["azp"]: raise NotForMe( "{} != azp:{}".format(kwargs["client_id"], self["azp"]), self) _now = time_util.utc_time_sans_frac() try: _skew = kwargs["skew"] except KeyError: _skew = 0 try: _exp = self["exp"] except KeyError: raise MissingRequiredAttribute("exp") else: if (_now - _skew) > _exp: raise EXPError("Invalid expiration time") try: _storage_time = kwargs["nonce_storage_time"] except KeyError: _storage_time = NONCE_STORAGE_TIME try: _iat = self["iat"] except KeyError: raise MissingRequiredAttribute("iat") else: if (_iat + _storage_time) < (_now - _skew): raise IATError("Issued too long ago") return True
def handle_response(self, r, csi): data = self.conv.events.last_item(EV_REQUEST) try: state = data['state'] except KeyError: state = '' if 300 < r.status_code < 400: resp = self.conv.entity.parse_response(self.response, info=r.headers['location'], sformat="urlencoded", state=state) elif r.status_code == 200: if "response_mode" in csi and csi["response_mode"] == "form_post": resp = self.response() forms = BeautifulSoup(r.text).findAll('form') for inp in forms[0].find_all("input"): resp[inp.attrs["name"]] = inp.attrs["value"] else: if r.is_redirect or r.is_permanent_redirect: resp = self.conv.entity.parse_response( self.response, info=r.headers['location'], sformat="urlencoded", state=state) else: resp = self.conv.entity.parse_response(self.response, info=r.text, sformat="json", state=state) _ent = self.conv.entity if isinstance(resp, AccessTokenResponse): if 'id_token' in resp and isinstance(resp['id_token'], IdToken): pass else: resp.verify(keyjar=_ent.keyjar, client_id=_ent.client_id, iss=_ent.provider_info['issuer']) else: resp.verify(keyjar=_ent.keyjar, client_id=_ent.client_id, iss=_ent.provider_info['issuer']) elif r.status_code == 400: if r.headers['content-type'] == 'application/json': resp = ErrorResponse().from_json(r.text) else: resp = ErrorResponse(error='service_error', error_description=r.text) else: resp = r if not isinstance(resp, Response): # Not a HTTP response try: try: _id_token = resp["id_token"] except KeyError: pass else: if _id_token.jws_header: self.conv.events.store('JWS header', _id_token.jws_header) if _id_token.jwe_header: self.conv.events.store('JWE header', _id_token.jwe_header) if "kid" not in _id_token.jws_header and not \ _id_token.jws_header["alg"] == "HS256": keys = self.conv.entity.keyjar.keys_by_alg_and_usage( issuer=_id_token['iss'], alg=_id_token.jws_header["alg"], usage='sig') if len(keys) > 1: raise ParameterError( "No 'kid' in id_token header!") try: if self.req_args['nonce'] != _id_token['nonce']: raise ParameterError( "invalid nonce! {} != {}".format( self.req_args['nonce'], _id_token['nonce'])) except KeyError: pass if not same_issuer(self.conv.info["issuer"], _id_token["iss"]): raise IssuerMismatch(" {} != {}".format( self.conv.info["issuer"], _id_token["iss"])) self.conv.entity.id_token = _id_token except KeyError: pass return resp