def get_id(): parsed_qs = dict(parse_qsl(request.query_string.decode())) try: jwt = parsed_qs["jwt"] except KeyError: abort(400) try: params = jws.factory(jwt).verify_compact(jwt, current_app.al.trusted_keys) except jwkest.Invalid as e: logger.debug("received invalid id request: %s", jwt) abort(400) try: data = IdRequest(params) except ValueError: logger.debug("received invalid id request: %s", params) abort(400) try: uuid = current_app.al.get_uuid(data.key) return uuid, 200 except ALserviceNoSuchKey: logger.debug("no key found for request: ", data) ticket = current_app.al.create_ticket(data) return ticket, 404
def test_make_signed_metadata_statements(): mds = MetaDataStore('mds') liss = list(FO.values()) liss.extend(list(OA.values())) key_bundle = make_fs_jwks_bundle(TEST_ISS, liss, SIGN_KEYJAR, KEYDEFS, './') operator = {} for entity, _keyjar in key_bundle.items(): operator[entity] = Operator(iss=entity, keyjar=_keyjar) _spec = SMS_DEF[OA['sunet']]["discovery"][FO['swamid']] ms = make_signed_metadata_statement(_spec, operator, mds=mds, base_uri='https:/example.org/ms') assert ms _spec = SMS_DEF[OA['sunet']]["discovery"][FO['edugain']] res = make_signed_metadata_statement(_spec, operator, mds=mds, base_uri='https:/example.org/ms') assert list(res['ms_uri'].keys()) == [FO['edugain']] _spec = SMS_DEF[OA['sunet']]["discovery"][FO['example']] res = make_signed_metadata_statement(_spec, operator, mds=mds, base_uri='https:/example.org/ms') assert list(res['ms'].keys()) == [FO['example']] _jws = factory(res['ms'][FO['example']]) assert _jws
def unpack(self, token): """ Unpack a received signed or signed and encrypted Json Web Token :param token: The Json Web Token :return: If decryption and signature verification work the payload will be returned as a Message instance. """ if not token: raise KeyError _rj = jwe.factory(token) if _rj: token = self._decrypt(_rj, token) _rj = jws.factory(token) if _rj: info = self._verify(_rj, token) else: raise Exception() if self.message_type: return self.message_type(**info) else: return info
def test_create_fo_keys_bundle(): jb = JWKSBundle(ORGOP.iss, ORGOP.keyjar) jb[FOP.iss] = FOP.keyjar jb[FO1P.iss] = FO1P.keyjar sb = jb.create_signed_bundle() _jw = jws.factory(sb) assert _jw
def test_no_kid_multiple_keys(self): """ This is extremely strict """ _jwt = factory(self.sjwt_a) # remove kid reference _jwt.jwt.headers['kid'] = '' keys = self.keyjar.get_jwt_verify_keys(_jwt.jwt) assert len(keys) == 0
def verify_self_signed_jwks(sjwt): """ Verify the signature of a signed JWT containing a JWKS. The JWT is signed by one of the keys in the JWKS. In the JWT the JWKS is stored using this format :: 'jwks': { 'keys': [ ] } :param sjwt: Signed Jason Web Token :return: Dictionary containing 'jwks' (the JWKS) and 'iss' (the issuer of the JWT) """ _jws = factory(sjwt) _json = _jws.jwt.part[1] _body = json.loads(as_unicode(_json)) iss = _body['iss'] _jwks = _body['jwks'] _kj = jwks_to_keyjar(_jwks, iss) try: _kid = _jws.jwt.headers['kid'] except KeyError: _keys = _kj.get_signing_key(owner=iss) else: _keys = _kj.get_signing_key(owner=iss, kid=_kid) _ver = _jws.verify_compact(sjwt, _keys) return {'jwks': _ver['jwks'], 'iss': iss}
def _verify_signature(self, txt=None): if not txt: txt = self.sws_jwt _jw = jws.factory(txt) if not _jw: raise BadSignature("SWS message not signed") _jw.verify_compact(txt, self._get_cert_key(self._dict["iss"]))
def _parse_remote_response(self, response): """ Parse simple JWKS or signed JWKS from the HTTP response. :param response: HTTP response from the 'jwks_uri' or 'signed_jwks_uri' endpoint :return: response parsed as JSON """ # Check if the content type is the right one. try: if response.headers["Content-Type"] == 'application/json': logger.debug("Loaded JWKS: %s from %s" % (response.text, self.source)) try: return json.loads(response.text) except ValueError: return None elif response.headers["Content-Type"] == 'application/jose': logger.debug("Signed JWKS: %s from %s" % (response.text, self.source)) _jws = factory(response.text) _resp = _jws.verify_compact( response.text, keys=self.verify_keys.get_signing_key()) return _resp else: logger.error('Wrong content type: {}'.format( response.headers['Content-Type'])) return None except KeyError: pass
def verify(self, signature, **kwargs): _jw = jws.factory(signature) if not _jw: raise ValidationError("Not a signed request") try: unpacked_req = _jw.verify_compact(signature, keys=[self.key]) except JWKESTException: raise ValidationError("Could not verify signature") _header = _jw.jwt.headers if "typ" not in _header or _header["typ"] != "pop": raise ValidationError("Incorrect JWS header 'typ', must be 'pop'") hash_size = get_hash_size(_header["alg"]) for arg, (key, func) in SIMPLE_OPER.items(): if arg == "time_stamp": continue try: if func is None: _val = kwargs[arg] else: _val = func(kwargs[arg]) _equals(unpacked_req[key], _val) except KeyError: pass for arg, (key, format) in PARAM_ARGS.items(): try: _attr = "strict_{}_verification".format(arg) _strict_verify = kwargs[_attr] except KeyError: _strict_verify = False try: _verify_params( kwargs[arg], unpacked_req[key], format, hash_size, _strict_verify, key, ) except KeyError: pass if "b" not in unpacked_req and "body" not in kwargs: pass elif "b" in unpacked_req and "body" in kwargs: _equals(b64_hash(kwargs.get("body", ""), hash_size), unpacked_req.get("b", "")) else: if "b" in unpacked_req: raise ValidationError("Body sent but not received!!") else: raise ValidationError("Body received but not sent!!") return unpacked_req
def check_key_availability(inst, jwt): _rj = jws.factory(jwt) payload = json.loads(as_unicode(_rj.jwt.part[1])) _cid = payload['iss'] if _cid not in inst.keyjar: cinfo = inst.cdb[_cid] inst.keyjar.add_symmetric(_cid, cinfo['client_secret'], ['enc', 'sig']) inst.keyjar.add(_cid, cinfo['jwks_uri'])
def _decrypt(self, rj, token): keys = self.keyjar.get_verify_key(owner='') msg = rj.decrypt(token, keys) _rj = jws.factory(msg) if not _rj: raise KeyError() else: return self._verify(_rj, msg)
def test_dj_usage(): key_string = open(full_path("./size2048.key"), 'r').read() key = RSA.importKey(key_string) payload = "Please take a moment to register today" keys = [RSAKey(key=key, kid=md5(key_string.encode('utf-8')).hexdigest())] _jws = JWS(payload, alg='RS256') sjwt = _jws.sign_compact(keys) _jwt = factory(sjwt) assert _jwt.jwt.headers['alg'] == 'RS256'
def _verify_jwt(jwt: str, keys: list): """ Verify teh signature of the jwt :type keys: list[str] :param jwt: A signed jwt :param keys: A list of keys to use when verifying the signature """ _jw = jws.factory(jwt) _jw.verify_compact(jwt, keys)
def print_metadata_statement(txt, sms): _jwt = factory(sms) _sos = json.loads(_jwt.jwt.part[1].decode('utf8')) print(70 * "=") print(txt) print(70 * "=") print_lines( json.dumps(_sos, sort_keys=True, indent=2, separators=(',', ': ')))
def unfurl(jwt): """ Return the body of a signed JWT, without verifying the signature. :param jwt: A signed JWT :return: The body of the JWT as a 'UTF-8' string """ _rp_jwt = factory(jwt) return json.loads(_rp_jwt.jwt.part[1].decode('utf8'))
def resign_bundle(iss, signed_bundle, sign_key): _jw = jws.factory(signed_bundle) _jwt = _jw.jwt.payload() _bundle = json.loads(_jwt['bundle']) jb = JWKSBundle(iss, sign_key) for iss, jwks in _bundle.items(): jb[iss] = jwks return jb
def test_signer_ps512(): payload = "Please take a moment to register today" # Key has to be big enough > 512+512+2 keys = [RSAKey(key=import_rsa_key_from_file(full_path("./size2048.key")))] #keys[0]._keytype = "private" _jws = JWS(payload, alg="PS521") _jwt = _jws.sign_compact(keys) _rj = factory(_jwt) info = _rj.verify_compact(_jwt, keys) assert info == payload
def verify(self, signature, **kwargs): _jw = jws.factory(signature) if not _jw: raise ValidationError("Not a signed request") try: unpacked_req = _jw.verify_compact(signature, keys=[self.key]) except JWKESTException: raise ValidationError("Could not verify signature") _header = _jw.jwt.headers if "typ" not in _header or _header["typ"] != "pop": raise ValidationError("Incorrect JWS header 'typ', must be 'pop'") hash_size = get_hash_size(_header["alg"]) for arg, (key, func) in SIMPLE_OPER.items(): if arg == 'time_stamp': continue try: if func is None: _val = kwargs[arg] else: _val = func(kwargs[arg]) _equals(unpacked_req[key], _val) except KeyError: pass for arg, (key, format) in PARAM_ARGS.items(): try: _attr = 'strict_{}_verification'.format(arg) _strict_verify = kwargs[_attr] except KeyError: _strict_verify = False try: _verify_params(kwargs[arg], unpacked_req[key], format, hash_size, _strict_verify, key) except KeyError: pass if 'b' not in unpacked_req and 'body' not in kwargs: pass elif 'b' in unpacked_req and 'body' in kwargs: _equals(b64_hash(kwargs.get("body", ""), hash_size), unpacked_req.get("b", "")) else: if 'b' in unpacked_req: raise ValidationError('Body sent but not received!!') else: raise ValidationError('Body received but not sent!!') return unpacked_req
def test_signer_ps512(): payload = "Please take a moment to register today" # Key has to be big enough > 512+512+2 keys = [RSAKey(key=import_rsa_key_from_file(full_path("./size2048.key")))] #keys[0]._keytype = "private" _jws = JWS(payload, alg="PS512") _jwt = _jws.sign_compact(keys) _rj = factory(_jwt) info = _rj.verify_compact(_jwt, keys) assert info == payload
def test_pack_metadata_statement_other_alg(): _keyjar = build_keyjar(KEYDEFS)[1] op = Operator(keyjar=_keyjar, iss='https://example.com/') req = MetadataStatement(issuer='https://example.org/op') sms = op.pack_metadata_statement(req, alg='ES256') assert sms # Should be a signed JWT _jwt = factory(sms) _body = json.loads(as_unicode(_jwt.jwt.part[1])) assert _body['iss'] == 'https://example.com/' # verify signature r = _jwt.verify_compact(sms, _keyjar.get_signing_key()) assert r
def test_no_kid_multiple_keys_no_kid_issuer_lim(self): a_kids = [ k.kid for k in self.keyjar.get_verify_key(owner='A', key_type='RSA') ] no_kid_issuer = {'A': []} _jwt = factory(self.sjwt_a) _jwt.jwt.headers['kid'] = '' keys = self.keyjar.get_jwt_verify_keys(_jwt.jwt, no_kid_issuer=no_kid_issuer) assert len(keys) == 3 assert set([k.kid for k in keys]) == set(a_kids)
def _get_client_public_key(self, access_token): _jws = jws.factory(access_token) if _jws: data = _jws.verify_compact(access_token, self.keyjar.get_verify_key(owner="")) try: return keyrep(data["cnf"]["jwk"]) except KeyError: raise NonPoPTokenError( "Could not extract public key as JWK from access token") raise NonPoPTokenError("Unsigned access token, maybe not PoP?")
def test_create_fed_provider_info(self): fedpi = self.op.create_fed_providerinfo() assert 'signing_keys' not in fedpi assert len(fedpi['metadata_statements']) == 1 _js = jws.factory(fedpi['metadata_statements'][FO['swamid']]) assert _js assert _js.jwt.headers['alg'] == 'RS256' _body = json.loads(as_unicode(_js.jwt.part[1])) assert _body[ 'iss'] == self.op.federation_entity.signer.signing_service.iss
def _func(self, conv): # returns a list, should only be one item in the list response = get_protocol_response(conv, AccessTokenResponse)[0] res = {} _tok = response['access_token'] _jwt = jws.factory(_tok) if _jwt: _keys = conv.entity.keyjar.get_issuer_keys( conv.entity.provider_info['issuer']) _json = _jwt.verify_compact(_tok, _keys) missing = [] for x in ['iss', 'azp', 'sub', 'kid', 'exp', 'jti']: if x not in _json: missing.append(x) if missing: self._message = "The following claims are missing from the " \ "access token: {}".format(missing) self._status = WARNING try: _tok = response['refresh_token'] except KeyError: pass else: _jwt = jws.factory(_tok) if _jwt: missing = [] _keys = conv.entity.keyjar.get_issuer_keys( conv.entity.provider_info['issuer']) _json = _jwt.verify_compact(_tok, _keys) for x in ['iss', 'azp', 'sub', 'kid', 'exp', 'jti']: if x not in _json: missing.append(x) if missing: self._message = "The following claims are missing from " \ "the refresh token: {}".format(missing) self._status = WARNING return res
def test_provider_endpoint(self): pi_resp = self.op.providerinfo_endpoint() assert isinstance(pi_resp, Response) assert pi_resp.status == "200 OK" _info = json.loads(pi_resp.message) assert list(_info['metadata_statements'].keys()) == [FO['swamid']] _js = jws.factory(_info['metadata_statements'][FO['swamid']]) assert _js assert _js.jwt.headers['alg'] == 'RS256' _body = json.loads(as_unicode(_js.jwt.part[1])) assert _body[ 'iss'] == self.op.federation_entity.signer.signing_service.iss
def test_aud(self): self.keyjar.import_jwks(JWK1, issuer='D') _jws = JWS('{"iss": "D", "aud": "A"}', alg='HS256') sig_key = self.keyjar.get_signing_key('oct', owner='D')[0] _sjwt = _jws.sign_compact([sig_key]) no_kid_issuer = {'D': []} _jwt = factory(_sjwt) keys = self.keyjar.get_jwt_verify_keys(_jwt.jwt, no_kid_issuer=no_kid_issuer) assert len(keys) == 1
def test_pack_metadata_statement(): jb = FSJWKSBundle('', None, 'fo_jwks', key_conv={'to': quote_plus, 'from': unquote_plus}) _keyjar = build_keyjar(KEYDEFS)[1] op = Operator(keyjar=_keyjar, jwks_bundle=jb, iss='https://example.com/') req = MetadataStatement(issuer='https://example.org/op') sms = op.pack_metadata_statement(req) assert sms # Should be a signed JWT _jwt = factory(sms) assert _jwt assert _jwt.jwt.headers['alg'] == 'RS256' _body = json.loads(as_unicode(_jwt.jwt.part[1])) assert _body['iss'] == op.iss assert _body['issuer'] == 'https://example.org/op' # verify signature r = _jwt.verify_compact(sms, _keyjar.get_signing_key()) assert r
def unpack(self, token): if not token: raise KeyError _rj = jws.factory(token) if _rj: info = self._verify(_rj, token) else: _rj = jwe.factory(token) if not _rj: raise KeyError() info = self._decrypt(_rj, token) if self.message_type: return self.message_type(**info) else: return info
def check_key_availability(inst, jwt): """ If the server is restarted it will NOT load keys from jwks_uris for all the clients that has been registered. So this function is there to get a clients keys when needed. :param inst: OP instance :param jwt: A JWT that has to be verified or decrypted """ _rj = jws.factory(jwt) payload = json.loads(as_unicode(_rj.jwt.part[1])) _cid = payload['iss'] if _cid not in inst.keyjar: cinfo = inst.cdb[_cid] inst.keyjar.add_symmetric(_cid, cinfo['client_secret'], ['enc', 'sig']) inst.keyjar.add(_cid, cinfo['jwks_uri'])
def test_rpt(): kb = KeyBundle(JWKS["keys"]) kj = KeyJar() kj.issuer_keys[''] = [kb] token_factory = JWT(kj, lifetime=3600, iss=issuer) client_id = 'https://example.com/client' ressrv_id = 'https://rs.example.org/' rpt = token_factory.pack(kid='sign1', aud=[client_id, ressrv_id], azp=ressrv_id, type='rpt') _rj = jws.factory(rpt) jti = json.loads(_rj.jwt.part[1].decode('utf8'))['jti'] info = token_factory.unpack(rpt) assert set(info.keys()), {'aud', 'azp', 'ext', 'iat', 'iss', 'jti', 'kid', 'type'}
def __call__(self, req, **kwargs): r = requests.post(self.url, json=req, verify=False) if 200 <= r.status_code < 300: _jw = factory(r.text) # First Just checking the issuer ID *not* verifying the Signature body = json.loads(as_unicode(_jw.jwt.part[1])) assert body['iss'] == self.iss # Now verifying the signature try: _jw.verify_compact(r.text, self.keyjar.get_verify_key(owner=self.iss)) except AssertionError: raise JWSException('JWS signature verification error') return r.text else: raise SigningServiceError("{}: {}".format(r.status_code, r.text))
def verify(self, signature, **kwargs): _jw = jws.factory(signature) if not _jw: raise ValidationError("Not a signed request") try: unpacked_req = _jw.verify_compact(signature, keys=[self.key]) _header = _jw.jwt.headers hash_size = _get_hash_size(_header["alg"]) except BadSignature: raise ValidationError("Could not verify signature") for arg, (key, func) in SIMPLE_OPER.items(): if arg == 'time_stamp': continue try: if func is None: _val = kwargs[arg] else: _val = func(kwargs[arg]) _equals(unpacked_req[key], _val) except KeyError: pass for arg, (key, format) in PARAM_ARGS.items(): try: _attr = 'strict_{}_verification'.format(arg) _strict_verify = kwargs[_attr] except KeyError: _strict_verify = False try: _verify_params(kwargs[arg], unpacked_req[key], format, hash_size, _strict_verify, key) except KeyError: pass try: _equals(b64_hash(kwargs['body'], hash_size), unpacked_req["b"]) except KeyError: pass return unpacked_req
def get_signed_keys(self, uri, signing_keys): """ :param uri: Where the signed JWKS can be found :param signing_keys: Dictionary representation of a JWKS :return: list of KeyBundle instances or None """ r = self.server.http_request(uri, allow_redirects=True) if r.status_code == 200: _skj = KeyJar() _skj.import_jwks(signing_keys, '') _jws = factory(r.text) _jwks = _jws.verify_compact(r.text, Keys=_skj.get_signing_key()) _kj = KeyJar() _kj.import_jwks(json.loads(_jwks), '') return _kj.issuer_keys[''] else: return None
def assert_registstration_req(self, request, sign_key_str): split_path = request.path_url.lstrip("/").split("/") assert len(split_path) == 2 jwks = split_path[1] # Verify signature public_key = import_rsa_key(private_to_public_key(sign_key_str)) sign_key = RSAKey().load_key(public_key) sign_key.use = "sig" _jw = jws.factory(jwks) _jw.verify_compact(jwks, [sign_key]) # Verify JWT _jwt = JWT().unpack(jwks) consent_args = _jwt.payload() assert "attr" in consent_args assert "redirect_endpoint" in consent_args assert "id" in consent_args
def test_use_signing_service(self): _fe = self.op.federation_entity statement = self.op.create_providerinfo() req = _fe.add_signing_keys(statement) sjwt = _fe.signer.create_signed_metadata_statement( req, 'discovery', fos=_fe.signer.metadata_statements.keys(), single=True) assert sjwt # should be a signed JWT _js = jws.factory(sjwt) assert _js assert _js.jwt.headers['alg'] == 'RS256' _req = json.loads(as_unicode(_js.jwt.part[1])) assert _req['iss'] == OA['sunet']
def save_consent_request(self, jwt: str): """ Saves a consent request, in the form of a JWT. :param jwt: JWT represented as a string """ try: request = jws.factory(jwt).verify_compact(jwt, self.trusted_keys) except jwkest.Invalid as e: logger.debug('invalid signature: %s', str(e)) raise InvalidConsentRequestError('Invalid signature') from e try: data = ConsentRequest(request) except ValueError: logger.debug('invalid consent request: %s', json.dumps(request)) raise InvalidConsentRequestError('Invalid consent request') ticket = hashlib.sha256((jwt + str(mktime(gmtime()))).encode("UTF-8")).hexdigest() self.ticket_db.save_consent_request(ticket, data) return ticket
def check_key_availability(inst, jwt): """ Try to refresh keys. If the server is restarted it will NOT load keys from jwks_uris for all the clients that has been registered. So this function is there to get a clients keys when needed. :param inst: OP instance :param jwt: A JWT that has to be verified or decrypted """ _rj = jws.factory(jwt) payload = json.loads(as_unicode(_rj.jwt.part[1])) _cid = payload["iss"] if _cid not in inst.keyjar: cinfo = inst.cdb[_cid] inst.keyjar.add_symmetric(_cid, cinfo["client_secret"], ["enc", "sig"]) if cinfo.get("jwks_uri") is not None: inst.keyjar.add(_cid, cinfo["jwks_uri"]) elif cinfo.get("jwks") is not None: inst.keyjar.import_jwks(cinfo["jwks"], _cid)
def _unpack_jwt(self, token, only_info=False): if not token: raise KeyError _rj = factory(token) _msg = json.loads(_rj.jwt.part[1].decode('utf8')) if _msg['iss'] == self.iss: owner = '' else: owner = _msg['iss'] keys = self.keyjar.get_signing_key(alg2keytype(_rj.jwt.headers['alg']), owner=owner) info = _rj.verify_compact(token, keys) if only_info: return info try: sid = self.db[info['jti']] except KeyError: raise return sid, info
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.jwt.headers _jw = jws.factory(txt) if _jw: if "algs" in kwargs and "sign" in kwargs["algs"]: _alg = _jw.jwt.headers["alg"] try: assert kwargs["algs"]["sign"] == _alg except AssertionError: raise WrongSigningAlgorithm("%s != %s" % ( _alg, kwargs["algs"]["sign"])) try: _jwt = JWT().unpack(txt) jso = json.loads(_jwt.part[1]) _header = _jwt.headers logger.debug("Raw JSON: %s" % jso) if _header["alg"] == "none": pass else: 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" in _header and _header["kid"]: _jw["kid"] = _header["kid"] try: _key = keyjar.get_key_by_kid(_header["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"]) _jw.verify_compact(txt, key) except Exception: raise else: self.jws_header = _jwt.headers else: jso = json.loads(txt) return self.from_dict(jso)
print_lines(json.dumps(ssreq.to_dict(), sort_keys=True, indent=2, separators=(',', ': '))) # ----------------------------------------------------------------------------- # The SWAMID FO constructs Software statement # ----------------------------------------------------------------------------- ssreq.update({ "response_types": ["code", "code id_token", "token"], "token_endpoint_auth_method": "private_key_jwt", "scopes": ['openid', 'email', 'phone'] }) dev_swamid_sost = make_software_statement(swamid_keyjar, swamid_issuer, **ssreq.to_dict()) _jwt = factory(dev_swamid_sost) _sos = json.loads(_jwt.jwt.part[1].decode('utf8')) print(70 * "-") print('SWAMID extended software statement') print(70 * "-") print_lines(json.dumps(_sos, sort_keys=True, indent=2, separators=(',', ': '))) # ----------------------------------------------------------------------------- # -- construct JSON document to be signed by InCommon # ----------------------------------------------------------------------------- ssreq = SoftwareStatement( contacts=['*****@*****.**'], policy_uri='https://example.com/policy.html', tos_uri='https://example.com/tos.html',
print_lines(json.dumps(ssreq.to_dict(), sort_keys=True, indent=2, separators=(",", ": "))) # ----------------------------------------------------------------------------- # The FO constructs Software statement # ----------------------------------------------------------------------------- ssreq.update( { "response_types": ["code", "token"], "token_endpoint_auth_method": "private_key_jwt", "scopes_allowed": ["openid", "email", "phone"], } ) sost = make_software_statement(fo_keyjar, "https://fo.example.com/", **ssreq.to_dict()) _jwt = factory(sost) _sos = json.loads(_jwt.jwt.part[1].decode("utf8")) print(70 * "-") print("FO extended software statement") print(70 * "-") print_lines(json.dumps(_sos, sort_keys=True, indent=2, separators=(",", ": "))) print() print_lines(sost) # ----------------------------------------------------------------------------- # Create intermediate key pair # ----------------------------------------------------------------------------- im_jwks, im_keyjar = build_keyjar(key_conf)[:-1]
def unfurl(jwt): _rp_jwt = factory(jwt) return json.loads(_rp_jwt.jwt.part[1].decode('utf8'))
def verify_http_request(key, signature, method="", host="", path="", query_params=None, headers=None, body=None, strict_query_param_verification=False, strict_headers_verification=False): """ :param key: verification key :param signature: signature of the request :param method: HTTP method :param host: url host :param path: url path :param query_params: query parameters :param headers: HTTP headers :param body: request body :param strict_query_param_verification: :param strict_headers_verification: :return: """ _jw = jws.factory(signature) if not _jw: raise ValidationError("Not a signed request") try: unpacked_req = _jw.verify_compact(signature, keys=[key]) _header = _jw.jwt.headers hash_size = _get_hash_size(_header["alg"]) except BadSignature: raise ValidationError("Could not verify signature") if "m" in unpacked_req: _equals(unpacked_req["m"], method) if "u" in unpacked_req: _equals(unpacked_req["u"], host) if "p" in unpacked_req: _equals(unpacked_req["p"], path) if "q" in unpacked_req: param_keys, param_hash = unpacked_req["q"] cmp_hash_str = "".join( [QUERY_PARAM_FORMAT.format(k, query_params[k]) for k in param_keys]) cmp_hash = urlsafe_b64encode( _hash_value(hash_size, cmp_hash_str)).decode("utf-8") _equals(cmp_hash, param_hash) if strict_query_param_verification and len(param_keys) != len( query_params): raise ValidationError("Too many or too few query params") if "h" in unpacked_req: header_keys, header_hash = unpacked_req["h"] cmp_hash_str = "".join( [REQUEST_HEADER_FORMAT.format(k, headers[k]) for k in header_keys]) cmp_hash = urlsafe_b64encode( _hash_value(hash_size, cmp_hash_str)).decode("utf-8") _equals(cmp_hash, header_hash) if strict_headers_verification and len(header_keys) != len(headers): raise ValidationError("Too many or too few headers") if "b" in unpacked_req: cmp_body = urlsafe_b64encode(_hash_value(hash_size, body)).decode("utf-8") _equals(cmp_body, unpacked_req["b"]) return unpacked_req
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 = as_unicode(_jw.decrypt(txt, dkeys)) self.jwe_header = _jw.jwt.headers _jw = jws.factory(txt) if _jw: if "algs" in kwargs and "sign" in kwargs["algs"]: _alg = _jw.jwt.headers["alg"] try: assert kwargs["algs"]["sign"] == _alg except AssertionError: raise WrongSigningAlgorithm("%s != %s" % ( _alg, kwargs["algs"]["sign"])) try: _jwt = JWT().unpack(txt) jso = _jwt.payload() _header = _jwt.headers logger.debug("Raw JSON: {}".format(jso)) logger.debug("header: {}".format(_header)) if _header["alg"] == "none": pass elif verify: if keyjar: key = self.get_verify_keys(keyjar, key, jso, _header, _jw, **kwargs) if "alg" in _header and _header["alg"] != "none": if not key: raise MissingSigningKey( "alg=%s" % _header["alg"]) logger.debug("Verify keys: {}".format(key)) try: _jw.verify_compact(txt, key) except NoSuitableSigningKeys: if keyjar: update_keyjar(keyjar) key = self.get_verify_keys(keyjar, key, jso, _header, _jw, **kwargs) _jw.verify_compact(txt, key) except Exception: raise else: self.jws_header = _jwt.headers else: jso = json.loads(txt) return self.from_dict(jso)
#!/usr/bin/env python import sys from jwkest import jwe from jwkest import jws __author__ = 'roland' jwt = open(sys.argv[1]).read() _jw = jwe.factory(jwt) if _jw: print("jwe") else: _jw = jws.factory(jwt) if _jw: print("jws") print(_jw.jwt.headers) print(_jw.jwt.part[1])