def verify_id_token(msg, check_hash=False, claim='id_token', **kwargs): # Try to decode the JWT, checks the signature args = {} for arg in ID_TOKEN_VERIFY_ARGS: try: args[arg] = kwargs[arg] except KeyError: pass _jws = jws_factory(msg[claim]) if not _jws: raise ValueError('{} not a signed JWT'.format(claim)) if _jws.jwt.headers['alg'] == 'none': try: _allow_none = kwargs['allow_sign_alg_none'] except KeyError: logger.info('Signing algorithm None not allowed') return False else: if not _allow_none: logger.info('Signing algorithm None not allowed') return False _body = _jws.jwt.payload() if 'keyjar' in kwargs: try: if _body['iss'] not in kwargs['keyjar']: raise ValueError('Unknown issuer') except KeyError: raise MissingRequiredAttribute('iss') idt = IdToken().from_jwt(str(msg[claim]), **args) if not idt.verify(**kwargs): return False if check_hash: _alg = idt.jws_header["alg"] hfunc = "HS" + _alg[-3:] if "access_token" in msg: if "at_hash" not in idt: raise MissingRequiredAttribute("Missing at_hash property", idt) if idt["at_hash"] != left_hash(msg["access_token"], hfunc): raise AtHashError("Failed to verify access_token hash", idt) if "code" in msg: if "c_hash" not in idt: raise MissingRequiredAttribute("Missing c_hash property", idt) if idt["c_hash"] != left_hash(msg["code"], hfunc): raise CHashError("Failed to verify code hash", idt) msg[verified_claim_name(claim)] = idt logger.info('Verified {}: {}'.format(claim, idt.to_dict())) return True
def verify_id_token(msg, check_hash=False, claim="id_token", **kwargs): # Try to decode the JWT, checks the signature args = {} for arg in ID_TOKEN_VERIFY_ARGS: try: args[arg] = kwargs[arg] except KeyError: pass _jws = jws_factory(msg[claim]) if not _jws: raise ValueError("{} not a signed JWT".format(claim)) if _jws.jwt.headers["alg"] == "none": _signed = False _sign_alg = kwargs.get("sigalg") if _sign_alg == "none": _allowed = True else: # There might or might not be a specified signing alg if kwargs.get("allow_sign_alg_none", False) is False: logger.info("Signing algorithm None not allowed") raise UnsupportedAlgorithm("Signing algorithm None not allowed") else: _signed = True if "allowed_sign_alg" in kwargs: if _jws.jwt.headers["alg"] != kwargs["allowed_sign_alg"]: _msg = "Wrong token signing algorithm, {} != {}".format( _jws.jwt.headers["alg"], kwargs["allowed_sign_alg"] ) logger.error(_msg) raise UnsupportedAlgorithm(_msg) _body = _jws.jwt.payload() if _signed and "keyjar" in kwargs: try: if _body["iss"] not in kwargs["keyjar"]: logger.info("KeyJar issuers: {}".format(kwargs["keyjar"])) raise ValueError('Unknown issuer: "{}"'.format(_body["iss"])) except KeyError: raise MissingRequiredAttribute("iss") idt = IdToken().from_jwt(str(msg[claim]), **args) if not idt.verify(**kwargs): return False if _signed and check_hash: _alg = idt.jws_header["alg"] hfunc = "HS" + _alg[-3:] if "access_token" in msg: if "at_hash" not in idt: raise MissingRequiredAttribute("Missing at_hash property", idt) if idt["at_hash"] != left_hash(msg["access_token"], hfunc): raise AtHashError("Failed to verify access_token hash", idt) if "code" in msg: if "c_hash" not in idt: raise MissingRequiredAttribute("Missing c_hash property", idt) if idt["c_hash"] != left_hash(msg["code"], hfunc): raise CHashError("Failed to verify code hash", idt) msg[verified_claim_name(claim)] = idt logger.info("Verified {}: {}".format(claim, idt.to_dict())) return True
def from_jwt(self, txt, keyjar, verify=True, **kwargs): """ Given a signed and/or encrypted JWT, verify its correctness and then create a class instance from the content. :param txt: The JWT :param key: keys that might be used to decrypt and/or verify the signature of the JWT :param verify: Whether the signature should be verified or not :param keyjar: A KeyJar that might contain the necessary key. :param kwargs: Extra key word arguments :return: A class instance """ algarg = {} if 'encalg' in kwargs: algarg['alg'] = kwargs['encalg'] if 'encenc' in kwargs: algarg['enc'] = kwargs['encenc'] _decryptor = jwe_factory(txt, **algarg) if _decryptor: logger.debug("JWE headers: %s", _decryptor.jwt.headers) dkeys = keyjar.get_decrypt_key(owner="") logger.debug('Decrypt class: %s', _decryptor.__class__) _res = _decryptor.decrypt(txt, dkeys) logger.debug('decrypted message: %s', _res) if isinstance(_res, tuple): txt = as_unicode(_res[0]) elif isinstance(_res, list) and len(_res) == 2: txt = as_unicode(_res[0]) else: txt = as_unicode(_res) self.jwe_header = _decryptor.jwt.headers if kwargs.get('sigalg'): _verifier = jws_factory(txt, alg=kwargs['sigalg']) else: _verifier = jws_factory(txt) if _verifier: _jwt = _verifier.jwt jso = _jwt.payload() _header = _jwt.headers key = [] # if "sender" in kwargs: # key.extend(keyjar.get_verify_key(owner=kwargs["sender"])) logger.debug("Raw JSON: %s", jso) logger.debug("JWS header: %s", _header) if _header["alg"] == "none": pass elif verify: if keyjar: key.extend(keyjar.get_jwt_verify_keys(_jwt, **kwargs)) if "alg" in _header and _header["alg"] != "none": if not key: raise MissingSigningKey("alg=%s" % _header["alg"]) logger.debug("Found signing key.") try: _verifier.verify_compact(txt, key) except NoSuitableSigningKeys: if keyjar: keyjar.update() key = keyjar.get_jwt_verify_keys(_jwt, **kwargs) _verifier.verify_compact(txt, key) self.jws_header = _jwt.headers else: jso = json.loads(txt) self.jwt = txt return self.from_dict(jso)