def get_public_key(self): public_key_set = self._registration.get_key_set() key_set_url = self._registration.get_key_set_url() if not public_key_set: if key_set_url.startswith(('http://', 'https://')): public_key_set = self.fetch_public_key(key_set_url) self._registration.set_key_set(public_key_set) else: raise LtiException("Invalid URL: " + key_set_url) # Find key used to sign the JWT (matches the KID in the header) kid = self._jwt.get('header', {}).get('kid', None) alg = self._jwt.get('header', {}).get('alg', None) if not kid: raise LtiException("JWT KID not found") if not alg: raise LtiException("JWT ALG not found") for key in public_key_set['keys']: key_kid = key.get('kid') key_alg = key.get('alg', 'RS256') if key_kid and key_kid == kid and key_alg == alg: try: key_json = json.dumps(key) jwk_obj = JWK.from_json(key_json) return jwk_obj.export_to_pem() except (ValueError, TypeError): raise LtiException("Can't convert JWT key to PEM format") # Could not find public key with a matching kid and alg. raise LtiException("Unable to find public key")
def encrypt_raw_event(evt, public_key, is_dict=False): payload = evt.to_jsonld() if is_dict is True: if type(public_key) is str: public_key = JWK.from_json(json_encode(eval(public_key))) else: public_key = JWK.from_json(json_encode(public_key)) protected_header = { "alg": "RSA-OAEP-256", "enc": "A256CBC-HS512", "typ": "JWE", "kid": public_key.thumbprint(), } data = JWE(payload.encode('utf-8'), recipient=public_key, protected=protected_header) return data.serialize()
def _validate_token_offline(self, access_token): """ Validate access token using cached information from the provider :param access_token: :return: tuple(valid, credential) or tuple(False, None) """ def decode(key): log.debug('Attempt decoding using key={}'.format(key.export())) try: if 'wlcg' in issuer: audience = 'https://wlcg.cern.ch/jwt/v1/any' credential = jwt.decode(access_token, key.export_to_pem(), algorithms=[algorithm], audience=audience ) else: # We don't check audience for non-WLCG token credential = jwt.decode(access_token, key.export_to_pem(), algorithms=[algorithm], options={'verify_aud': False} ) return credential except Exception: return None log.debug('entered validate_token_offline') credential = None try: unverified_payload = jwt.decode(access_token, verify=False) unverified_header = jwt.get_unverified_header(access_token) issuer = unverified_payload['iss'] key_id = unverified_header.get('kid') algorithm = unverified_header.get('alg') log.debug('issuer={}, key_id={}, alg={}'.format(issuer, key_id, algorithm)) # Retrieval of keys keys = oidc_manager.filter_provider_keys(issuer, key_id, algorithm) jwkeys = [JWK.from_json(json.dumps(key.to_dict())) for key in keys] # Find the first key which decodes the token for jwkey in jwkeys: credential = decode(jwkey) if credential is not None: log.debug('offline_response::: {}'.format(credential)) break except Exception as ex: log.debug('return False, Exception: {}'.format(ex)) return False, None if credential is None: log.debug('No key managed to decode the token') log.debug('return {}, credential'.format(credential is not None)) return (credential is not None), credential
def get_jwk(): jwk_config = None # Get JWK (if exists) if 'jwk' in app_secrets and 'kty' in app_secrets['jwk']: key_type = app_secrets['jwk']['kty'].lower() if key_type == "oct" and 'k' in app_secrets['jwk']: jwk_config = {'kty': key_type, 'k': app_secrets['jwk']['k']} # Add support for other key types here; # For now, we only support octat sequence ("oct") if jwk_config is not None: return JWK.from_json(json.dumps(jwk_config)) return None
def upload_picture(self, picture_stream): """ Upload the file on the given path to the server via HTTP post Uses class configuration to determine the url and key to sign Authorization Bearer token with JWT """ # skip if improperly configured if not self.upload_url or not self.upload_auth_jwk_path: return if not self.upload_auth_jwk: with open(self.upload_auth_jwk_path, 'rb') as f: self.upload_auth_jwk = JWK.from_json(f.read()) try: picture_stream.seek(0) auth_token = JWT(header={'alg': 'EdDSA', 'kid': self.upload_auth_jwk.key_id}, default_claims={'iat':None, 'exp': None}) auth_token.validity=300 auth_token.claims={} auth_token.make_signed_token(self.upload_auth_jwk) auth_header = 'Bearer {}'.format(auth_token.serialize()) response = requests.post( self.upload_url, files={'file': picture_stream}, headers={ 'Authorization': auth_header } ) if not response.ok: logger.error("Error uploading snapshot. Status code {}".format(response.status_code)) except Exception as exc: logger.exception("Error uploading snapshot.") else: # log success logger.info("Snapshot uploaded") finally: picture_stream.seek(0)
import os import json import datetime import requests from jwcrypto.jwk import JWK from jwcrypto.jwt import JWT raw_token = open('temp-token.txt').read() jwks_resp = requests.get(os.environ['OAUTH_SERVER'] + '/v1/keys') first_key = jwks_resp.json()['keys'][0] key = JWK.from_json(json.dumps(first_key)) # Validate token as per procedure described in: # https://developer.okta.com/authentication-guide/tokens/validating-id-tokens/#verify-the-claims # Use built-in claim validation for exact matching # https://jwcrypto.readthedocs.io/en/latest/jwt.html expected_claims = { "iss": os.environ['OAUTH_SERVER'], "aud": os.environ['CLIENT_ID'] } # Creating JWT object also validates the signature token = JWT(jwt=raw_token, key=key, check_claims=expected_claims) claims = json.loads(token.claims) # Perform issued at and expiration time checks print('IAT validation: ' + str( datetime.datetime.fromtimestamp(claims['iat']) < datetime.datetime.now()))
async def handle_client(self, reader, writer): try: req = await read(reader) # FIXME: カプセル化…… # jwcryptoではJWTの署名を検証する前にペイロードにアクセスする良い方法がない req.token.objects['valid'] = True reqclaims = json.loads(req.token.payload.decode('utf-8')) print(f"got claims: {reqclaims}") reqtype = reqclaims['msgtype'] print(f"msgtype: {reqtype}") if reqtype == 'ctr_init': # カウンタの初期化 nonce = reqclaims['nonce'] client_pubkey = JWK.from_json(reqclaims['pubkey']) vinit = 42 # TODO: 適切な初期値 key = self.data.add_new(vinit, client_pubkey) await write( writer, { 'msgtype': 'ctr_init_ok', 'nonce': nonce, 'key': key, 'ctr': vinit }, self.privkey) elif reqtype == 'ctr_access': # カウンタに0以上加算して結果を返す nonce0 = reqclaims['nonce0'] key = reqclaims['key'] inc = reqclaims['inc'] # key がわからないと対応する公開鍵もわからない client_pubkey = self.data.pubkey(key) # reqのロード時に検証できなかったのでここで検証 try: req.token.verify(client_pubkey) except InvalidJWSSignature: await write(writer, { 'msgtype': 'error', 'info': 'invalid_signature' }, self.privkey) return nonce1 = random.randrange(2**32) await write( writer, { 'msgtype': 'ctr_access_ack0', 'nonce0': nonce0, 'nonce1': nonce1 }, self.privkey) req1 = await read(reader, client_pubkey) print(f'req1: {req1.claims}') # TODO: 署名検証の例外処理 req1claims = json.loads(req1.claims) print(f'got claims: {req1claims}') if req1claims['msgtype'] != 'ctr_access_ack1': await write(writer, { 'msgtype': 'error', 'info': 'invalid_request' }, self.privkey) return if req1claims['nonce0'] != nonce0 or req1claims[ 'nonce1'] != nonce1: await write(writer, { 'msgtype': 'error', 'info': 'nonce_mismatch' }, self.privkey) return v = self.data.increment(key, inc) await write( writer, { 'msgtype': 'ctr_access_ok', 'nonce0': nonce0, 'nonce1': nonce1, 'ctr': v }, self.privkey) elif reqtype == 'time_query': # 時刻のクエリ # クエリの署名検証はしない nonce = reqclaims["nonce"] t = time.time() await write(writer, { 'msgtype': 'time_answer', 'time': t, 'nonce': nonce }, self.privkey) else: # 不明なリクエスト await write(writer, { 'msgtype': 'error', 'info': 'invalid_request' }, self.privkey) #except KeyError: # await write(writer, {'msgtype': 'error', 'info': 'key_error'}, self.privkey) except ValueError: await write(writer, { 'msgtype': 'error', 'info': 'value_error' }, self.privkey) #except InvalidJWSSignature: # await write(writer, {'msgtype': 'error', 'info': 'invalid_signature'}, self.privkey) finally: writer.close() await writer.wait_closed()
from jwcrypto.jwk import JWK import requests import json from web.src.SAP import create_app app = create_app() # Get JWK from identity provider idp = os.environ["IDP"] headers = {"Accept": "application/json"} r = requests.get(idp + "/.well-known/jwks.json", params={}, headers=headers) jsonkeys = r.json() jsonkey = jsonkeys["keys"][0] jwk_json = json.dumps(jsonkey) jwk = JWK.from_json(jwk_json) # Convert JWK to PEM so that JWTManager can consume it pem = jwk.export_to_pem() # Configure JWTManager app.config["JWT_PUBLIC_KEY"] = pem app.config["JWT_DECODE_AUDIENCE"] = os.environ["SOFI_CLIENT_ID"] app.config["JWT_IDENTITY_CLAIM"] = "email" app.config["JWT_ALGORITHM"] = jsonkey["alg"] JWTManager(app) if __name__ == "__main__": app.run(host="0.0.0.0")
def verify_token(token, pub_key): jwk = JWK.from_json(json.dumps(pub_key)) return jwt.verify_jwt(token, jwk, ['RS256'], checks_optional=True)
def verify_token(token, pub_key): print(f"\n\n\n^^^^verifying token") jwk = JWK.from_json(json.dumps(pub_key)) print(f"\n\n\n^^^^jwk obtained") return jwt.verify_jwt(token, jwk, ["RS256"], checks_optional=True)