def test_make_id_token(): srv = Server() srv.keyjar = KEYJ srv.keyjar["http://oic.example/rp"] = KC_RSA session = {"sub": "user0", "client_id": "http://oic.example/rp"} issuer = "http://oic.example/idp" code = "abcdefghijklmnop" _idt = srv.make_id_token(session, loa="2", issuer=issuer, code=code, access_token="access_token") algo = "RS256" ckey = srv.keyjar.get_signing_key(alg2keytype(algo), session["client_id"]) _signed_jwt = _idt.to_jwt(key=ckey, algorithm="RS256") idt = IdToken().from_jwt(_signed_jwt, keyjar=srv.keyjar) print idt header = unpack(_signed_jwt) lha = left_hash(code, func="HS" + header[0]["alg"][-3:]) assert lha == idt["c_hash"] atr = AccessTokenResponse(id_token=_signed_jwt, access_token="access_token", token_type="Bearer") atr["code"] = code assert atr.verify(keyjar=srv.keyjar)
def test_assertion_jwt(): cli = Client("Foo") cli.client_secret = "secert" at = oic.assertion_jwt(cli, {}, audience="audience", algorithm="none") print at header, claim, crypto, header_b64, claim_b64 = unpack(at) jso = json.loads(claim) assert _eq(jso.keys(), ["aud", "iss", "sub", "jti", "exp", "iat"])
def test_a_1_3a(): _jwt = "eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk" #keycol = {"hmac": jwkest.intarr2bin(HMAC_KEY)} header, claim, crypto, header_b64, claim_b64 = jwkest.unpack(_jwt) hmac = jwkest.intarr2bin(HMAC_KEY) signer = SIGNER_ALGS["HS256"] info = signer.verify(header_b64 + '.' + claim_b64, crypto, hmac)
def from_jwt(self, txt, key=None, verify=True, keyjar=None, **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 :return: A class instance """ if key is None and keyjar is not None: key = keyjar.get_verify_key(owner="") elif key is None: key = {} header = json.loads(b64d(str(txt.split(".")[0]))) try: htype = header["typ"] except KeyError: htype = None jso = None if htype == "JWE" or ("alg" in header and "enc" in header): # encrypted if keyjar: dkeys = keyjar.get_decrypt_key(owner="") else: dkeys = {} txt = jwe.decrypt(txt, dkeys, "private") try: jso = json.loads(txt) except Exception: pass # assume htype == 'JWS' if not jso: try: jso = jwkest.unpack(txt)[1] if isinstance(jso, basestring): jso = json.loads(jso) if verify: if keyjar: for ent in ["iss", "aud", "client_id"]: if ent not in jso: continue if ent == "aud": for _e in jso[ent]: self._add_key(keyjar, _e, key) else: self._add_key(keyjar, jso[ent], key) jws.verify(txt, key) except Exception: raise return self.from_dict(jso)
def test_a_1_3a(): _jwt = ( "eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJle" "HAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnV" "lfQ.dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk") #keycol = {"hmac": jwkest.intarr2bin(HMAC_KEY)} header, claim, crypto, header_b64, claim_b64 = jwkest.unpack(_jwt) hmac = jwkest.intarr2bin(HMAC_KEY) signer = SIGNER_ALGS["HS256"] signer.verify(header_b64 + '.' + claim_b64, crypto, hmac)
def test_private_key_jwt(): cli = Client("FOO") cli.token_endpoint = "https://example.com/token" cli.keyjar[""] = KC_RSA cis = AccessTokenRequest() at = oic.private_key_jwt(cli, cis, algorithm="RS256") assert at == {} cas = cis["client_assertion"] header, claim, crypto, header_b64, claim_b64 = unpack(cas) jso = json.loads(claim) assert _eq(jso.keys(), ["aud", "iss", "sub", "jti", "exp", "iat"]) print header assert header == {'alg': 'RS256'}
def test_private_key_jwt(): cli = Client("FOO") cli.token_endpoint = "https://example.com/token" cli.keyjar[""] = KC_RSA cis = AccessTokenRequest() pkj = PrivateKeyJWT(cli) http_args = pkj.construct(cis, algorithm="RS256") assert http_args == {} cas = cis["client_assertion"] header, claim, crypto, header_b64, claim_b64 = jwkest.unpack(cas) jso = json.loads(claim) assert _eq(jso.keys(), ["aud", "iss", "sub", "jti", "exp", "iat"]) print header assert header == {'alg': 'RS256'}
def verify(self, **kwargs): if "aud" in self: if "client_id" in kwargs: # check that it's for me if kwargs["client_id"] not in self["aud"]: return False if "id_token" in self: # Try to decode the JWT, checks the signature args = {} for arg in ["key", "keyjar"]: try: args[arg] = kwargs[arg] except KeyError: pass idt = IdToken().from_jwt(str(self["id_token"]), **args) if not idt.verify(**kwargs): raise VerificationError("Could not verify id_token", idt) hfunc = "HS" + jwkest.unpack(self["id_token"])[0]["alg"][-3:] if "access_token" in self: try: assert "at_hash" in idt except AssertionError: raise MissingRequiredAttribute("Missing at_hash property", idt) try: assert idt["at_hash"] == jws.left_hash( self["access_token"], hfunc) except AssertionError: raise VerificationError( "Failed to verify access_token hash", idt) if "code" in self: try: assert "c_hash" in idt except AssertionError: raise MissingRequiredAttribute("Missing c_hash property", idt) try: assert idt["c_hash"] == jws.left_hash(self["code"], hfunc) except AssertionError: raise VerificationError("Failed to verify code hash", idt) self["id_token"] = idt return super(AuthorizationResponse, self).verify(**kwargs)
def test_client_secret_jwt(): cli = Client("Foo") cli.token_endpoint = "https://example.com/token" cli.client_secret = "foobar" cis = AccessTokenRequest() at = oic.client_secret_jwt(cli, cis, algorithm="HS256") assert at == {} assert cis["client_assertion_type"] == JWT_BEARER assert "client_assertion" in cis cas = cis["client_assertion"] header, claim, crypto, header_b64, claim_b64 = unpack(cas) jso = json.loads(claim) assert _eq(jso.keys(), ["aud", "iss", "sub", "jti", "exp", "iat"]) print header assert header == {'alg': 'HS256'}
def _func(self, conv=None): userinfo_claims = {} req = get_authz_request(conv) try: _scopes = req["scope"] except KeyError: return {} for scope in _scopes: try: claims = dict([(name, None) for name in SCOPE2CLAIMS[scope]]) userinfo_claims.update(claims) except KeyError: pass if "request" in req: jso = json.loads(unpack(req["request"])[1]) _uic = jso["userinfo"] for key, val in _uic["claims"].items(): userinfo_claims[key] = val # last item should be the UserInfoResponse resp = conv.response_message if userinfo_claims: for key, restr in userinfo_claims.items(): if key in resp: pass else: if restr == {"essential": True}: self._status = self.status self._message = "required attribute '%s' missing" % key return {"returned claims": resp.keys()} for key in resp.keys(): if key not in userinfo_claims: self._status = WARNING self._message = "Unexpected %s claim in response" % key return {"returned claims": resp.keys()} return {}
def _func(self, conv): client = conv.client for instance, msg in conv.protocol_response: if isinstance(instance, message.AccessTokenResponse): _dic = json.loads(msg) header = json.loads(b64d(str(_dic["id_token"].split(".")[0]))) try: assert header["alg"].startswith("RSA") except AssertionError: self._status = self.status break dkeys = client.keyjar.get_decrypt_key(owner="") txt = JWE_RSA().decrypt(_dic["id_token"], dkeys[0].key) _tmp = unpack(txt)[0] try: assert _tmp["alg"] == "RS256" except AssertionError: self._status = self.status break return {}
def test_client_secret_jwt(): cli = Client("Foo") cli.token_endpoint = "https://example.com/token" cli.client_secret = "foobar" csj = ClientSecretJWT(cli) cis = AccessTokenRequest() http_args = csj.construct(cis, algorithm="HS256") print http_args assert cis["client_assertion_type"] == JWT_BEARER assert "client_assertion" in cis cas = cis["client_assertion"] header, claim, crypto, header_b64, claim_b64 = jwkest.unpack(cas) jso = json.loads(claim) assert _eq(jso.keys(), ["aud", "iss", "sub", "jti", "exp", "iat"]) print header assert header == {'alg': 'HS256'} _rj = JWS() info = _rj.verify_compact(cas, [SYMKey(key=cli.client_secret)]) _dict = json.loads(info) assert _eq(_dict.keys(), ["aud", "iss", "sub", "jti", "exp", "iat"])
help="File containing a public RSA key") parser.add_argument('-k', dest="hmac_key", help="If using a HMAC algorithm this is the key") parser.add_argument('-x', dest="x509_file", help="File containing a X509 certificate") parser.add_argument("message", nargs="?", help="The message to verify signature on") args = parser.parse_args() keys = {} if args.rsa_file: keys = {"rsa": [rsa_load(args.rsa_file)]} elif args.hmac_key: keys = {"hmac": [args.hmac_key]} elif args.x509_file: keys = {"rsa": [x509_rsa_loads(open(args.x509_file).read())]} elif args.rsa_pub_file: keys = {"rsa": [rsa_pub_load(args.rsa_pub_file)]} if args.message == "-": message = sys.stdin.read() else: message = args.message if keys: print verify(message, keys) else: print unpack(message)[1]
dest="hmac_key", help="If using a HMAC algorithm this is the key") parser.add_argument('-x', dest="x509_file", help="File containing a X509 certificate") parser.add_argument("message", nargs="?", help="The message to verify signature on") args = parser.parse_args() keys = {} if args.rsa_file: keys = {"rsa": [rsa_load(args.rsa_file)]} elif args.hmac_key: keys = {"hmac": [args.hmac_key]} elif args.x509_file: keys = {"rsa": [x509_rsa_loads(open(args.x509_file).read())]} elif args.rsa_pub_file: keys = {"rsa": [rsa_pub_load(args.rsa_pub_file)]} if args.message == "-": message = sys.stdin.read() else: message = args.message if keys: print verify(message, keys) else: print unpack(message)[1]
def from_jwt(self, txt, key=None, verify=True, keyjar=None, **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 :return: A class instance """ if key is None and keyjar is not None: key = keyjar.get_verify_key(owner="") elif key is None: key = {} header = json.loads(b64d(str(txt.split(".")[0]))) logger.debug("header: %s" % (header, )) try: htype = header["typ"] except KeyError: htype = None try: _kid = header["kid"] except KeyError: _kid = "" jso = None if htype == "JWE" or ("alg" in header and "enc" in header): # encrypted if keyjar: dkeys = keyjar.get_decrypt_key(owner="") else: dkeys = {} txt = JWE().decrypt(txt, dkeys) try: jso = json.loads(txt) except Exception: pass # assume htype == 'JWS' _jws = JWS() if not jso: try: jso = jwkest.unpack(txt)[1] if isinstance(jso, basestring): jso = json.loads(jso) if keyjar: if "jku" in header: if not keyjar.find(header["jku"], jso["iss"]): # This is really questionable try: if kwargs["trusting"]: keyjar.add(jso["iss"], header["jku"]) except KeyError: pass if _kid: try: _key = keyjar.get_key_by_kid(_kid, jso["iss"]) if _key: key.append(_key) except KeyError: pass try: self._add_key(keyjar, kwargs["opponent_id"], key) except KeyError: pass if verify: if keyjar: for ent in ["iss", "aud", "client_id"]: if ent not in jso: continue if ent == "aud": # list or basestring if isinstance(jso["aud"], basestring): _aud = [jso["aud"]] else: _aud = jso["aud"] for _e in _aud: self._add_key(keyjar, _e, key) else: self._add_key(keyjar, jso[ent], key) if "alg" in header and header["alg"] != "none": if not key: raise MissingSigningKey("alg=%s" % header["alg"]) _jws.verify_compact(txt, key) except Exception: raise return self.from_dict(jso)
def from_jwt(self, txt, key=None, verify=True, keyjar=None, **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 """ if key is None and keyjar is not None: key = keyjar.get_verify_key(owner="") elif key is None: key = [] if keyjar is not None and "sender" in kwargs: key.extend(keyjar.get_verify_key(owner=kwargs["sender"])) _jw = jwe.factory(txt) if _jw: if "algs" in kwargs and "encalg" in kwargs["algs"]: try: assert kwargs["algs"]["encalg"] == _jw["alg"] except AssertionError: raise WrongEncryptionAlgorithm("%s != %s" % ( _jw["alg"], kwargs["algs"]["encalg"])) try: assert kwargs["algs"]["encenc"] == _jw["enc"] except AssertionError: raise WrongEncryptionAlgorithm("%s != %s" % ( _jw["enc"], kwargs["algs"]["encenc"])) if keyjar: dkeys = keyjar.get_decrypt_key(owner="") elif key: dkeys = key else: dkeys = [] txt = _jw.decrypt(txt, dkeys) self.jwe_header = _jw.dump_header() _jw = jws.factory(txt) if _jw: if "algs" in kwargs and "sign" in kwargs["algs"]: try: assert kwargs["algs"]["sign"] == _jw["alg"] except AssertionError: raise WrongSigningAlgorithm("%s != %s" % ( _jw["alg"], kwargs["algs"]["sign"])) try: p = jwkest.unpack(txt) jso = json.loads(p[1]) logger.debug("Raw JSON: %s" % jso) if _jw["alg"] == "none": pass else: if keyjar: if "jku" in _jw: if not keyjar.find(_jw["jku"], jso["iss"]): # This is really questionable try: if kwargs["trusting"]: keyjar.add(jso["iss"], _jw["jku"]) except KeyError: pass if "kid" in _jw and _jw["kid"]: try: _key = keyjar.get_key_by_kid(_jw["kid"], jso["iss"]) if _key: key.append(_key) except KeyError: pass try: self._add_key(keyjar, kwargs["opponent_id"], key) except KeyError: pass if verify: if keyjar: for ent in ["iss", "aud", "client_id"]: if ent not in jso: continue if ent == "aud": # list or basestring if isinstance(jso["aud"], basestring): _aud = [jso["aud"]] else: _aud = jso["aud"] for _e in _aud: self._add_key(keyjar, _e, key) else: self._add_key(keyjar, jso[ent], key) if "alg" in _jw and _jw["alg"] != "none": if not key: raise MissingSigningKey( "alg=%s" % _jw["alg"]) _jw.verify_compact(txt, key) except Exception: raise else: self.jws_header = _jw.dump_header() else: jso = json.loads(txt) return self.from_dict(jso)
def from_jwt(self, txt, key=None, verify=True, keyjar=None, **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 :return: A class instance """ if key is None and keyjar is not None: key = keyjar.get_verify_key(owner="") elif key is None: key = {} header = json.loads(b64d(str(txt.split(".")[0]))) logger.debug("header: %s" % (header,)) try: htype = header["typ"] except KeyError: htype = None try: _kid = header["kid"] except KeyError: _kid = "" jso = None if htype == "JWE" or ("alg" in header and "enc" in header): # encrypted if keyjar: dkeys = keyjar.get_decrypt_key(owner="") else: dkeys = {} txt = JWE().decrypt(txt, dkeys, "private") try: jso = json.loads(txt) except Exception: pass # assume htype == 'JWS' _jws = JWS() if not jso: try: jso = jwkest.unpack(txt)[1] if isinstance(jso, basestring): jso = json.loads(jso) if "jku" in header: if not keyjar.find(header["jku"], jso["iss"]): # This is really questionable try: if kwargs["trusting"]: keyjar.add(jso["iss"], header["jku"]) except KeyError: pass if _kid: _key = keyjar.get_key_by_kid(_kid, jso["iss"]) if _key: key.append(_key) try: self._add_key(keyjar, kwargs["opponent_id"], key) except KeyError: pass if verify: if keyjar: for ent in ["iss", "aud", "client_id"]: if ent not in jso: continue if ent == "aud": # list or basestring if isinstance(jso["aud"], basestring): _aud = [jso["aud"]] else: _aud = jso["aud"] for _e in _aud: self._add_key(keyjar, _e, key) else: self._add_key(keyjar, jso[ent], key) _jws.verify_compact(txt, key) except Exception: raise return self.from_dict(jso)