def decode(token, secret=None, privkey=None, pubkey=None, algorithms=['RS256','HS256']): decoded = None try: js = json.loads(token) except ValueError as err: options = { 'verify_signature': False, #We don't need to verify as its symmetric 'verify_exp': True, 'verify_nbf': False, 'verify_iat': True, 'verify_aud': False } #Version 1 return jwt.decode(token, secret, algorithms=algorithms, options=options) else: # Version 2 copy = json.loads(token) del copy['sigs'] if hm(json.dumps(copy,separators=(',', ':')),pubkey) != js['sigs']['_']['hash']: raise Exception('hash mismatch') private_key = jwk.construct(privkey, "RS256").to_dict() public_key = jwk.construct(pubkey, "RS256").to_dict() sig = jws.verify(js['sigs']['_']['sig'], public_key, algorithms, verify=True) if js['priv'] != None: js['priv'] = json.loads(jws.verify(js['priv'], public_key, algorithms, verify=False)) if str(sig,'utf-8').replace('"',"") != js['sigs']['_']['hash']: raise Exception('bad sig') return js
def verify_jwt(*args, **kwargs): try: jwt = request.headers.get("authorization").split(' ')[1] jws.verify(jwt, PUBLICKEY, algorithms=ALGORITHM) return fn(*args, **kwargs) except Exception as e: return '{}'
def disconnect(req): print("----------------------------------disconnect----------------------------------") if deb2 else None print("received data: ", req) if deb else None print("received data pub_id: ", req['pub_id']) if deb else None print("received data data: ", req['data']) if deb else None print("received data sign: ", req['sign']) if deb else None if UserFarm.query.filter_by(pub_id=req['pub_id']).first() is not None: app1 = UserFarm.query.filter_by(pub_id=req['pub_id']).first() print("UserFarm pub: ", app1.pub_id) if deb else None print("UserFarm priv: ", app1.pri_id) if deb else None print("decrypt pass on db: ", jws.verify(app1.pri_id, priv_id, algorithms=['HS256']).decode()) if deb else None try: req_data = json.loads( jws.verify(req['data'], jws.verify(app1.pri_id, priv_id, algorithms=['HS256']).decode(), algorithms=['HS256'])) except: emit('connect_estab', 5) print("decrypt data: ", req_data) if deb else None if Session.query.filter_by(session_id=req_data['ses_id'], pub_id=req['pub_id'], flag=True).first() is not None: app2 = Session.query.filter_by(session_id=req_data['ses_id'], pub_id=req['pub_id'], flag=True).first() if sign.verify_sign(app2.key, req['sign'], req['data']): print("valid sign") if deb else None app2.flag = False app2.time_end = datetime.datetime.utcnow() db.session.commit() print("DISC ---> user: "******" ses_id: ", req_data['ses_id']) if deb2 else None print("----------------------------------disconnect DONE----------------------------------") if deb2 else None emit('disc_response', 0) else: emit('disc_response', 2) else: emit('disc_response', 3) else: emit('disc_response', 1)
def connect_request(req): print("----------------------------------connect_request----------------------------------") if deb2 else None print("req pub_id: : ", req['pub_id']) if deb else None print("req key: ", req['key']) if deb else None print("req key encode utf-8: ", req['key'].encode('utf-8')) if deb else None if UserFarm.query.filter_by(pub_id=req['pub_id']).first() is not None: app1 = UserFarm.query.filter_by(pub_id=req['pub_id']).first() print("UserFarm pub_id: ", app1.pub_id) if deb else None if Session.query.filter_by(pub_id=req['pub_id'], flag=True).first() is not None: app2 = Session.query.filter_by(pub_id=req['pub_id'], flag=True).first() print("Session pub_id: ", app2.pub_id) if deb else None app2.flag = False app2.time_end = datetime.datetime.utcnow() db.session.commit() otp = ''.join(secrets.choice(alphabet) for i in range(50)) print("otp: ", otp) if deb else None cur = Session(pub_id=req['pub_id'], key=req['key'], otp=otp, flag=True, time_start=datetime.datetime.utcnow()) db.session.add(cur) db.session.commit() data = {"otp": otp, "key": key.publickey().export_key().decode("utf-8")} print("decrypt pass on db: ", jws.verify(app1.pri_id, priv_id, algorithms=['HS256']).decode()) if deb else None crypt_data = jws.sign(data, jws.verify(app1.pri_id, priv_id, algorithms=['HS256']).decode(), algorithm='HS256') print("encrypt data: ", crypt_data) if deb else None sign_crypt_data = sign.sign_data(key.exportKey(), crypt_data) print("sign encrypt data: ", sign_crypt_data) if deb else None resp = {"data": crypt_data, "sign": sign_crypt_data.decode()} print("resp: ", resp) if deb else None print("resp data: ", resp['data']) if deb else None print("CON REQ ---> user: "******"----------------------------------connect_request DONE----------------------------------") if deb2 else None emit('connect_response', resp) else: emit('connect_response', 1)
def change_confirm(req): print("----------------------------------change confirm----------------------------------") if deb2 else None print("received data: ", req) if deb else None print("received data pub_id: ", req['pub_id']) if deb else None print("received data data: ", req['data']) if deb else None print("received data sign: ", req['sign']) if deb else None if UserFarm.query.filter_by(pub_id=req['pub_id']).first() is not None: app1 = UserFarm.query.filter_by(pub_id=req['pub_id']).first() print("UserFarm pub: ", app1.pub_id) if deb else None print("UserFarm priv: ", app1.pri_id) if deb else None print("decrypt pass on db: ", jws.verify(app1.pri_id, priv_id, algorithms=['HS256']).decode()) if deb else None try: req_data = json.loads(jws.verify(req['data'], jws.verify(app1.pri_id, priv_id, algorithms=['HS256']).decode(), algorithms=['HS256'])) except: pass print("decrypt data: ", req_data) if deb else None if Session.query.filter_by(session_id=req_data['ses_id'], pub_id=req['pub_id'], flag=True).first() is not None: app2 = Session.query.filter_by(session_id=req_data['ses_id'], pub_id=req['pub_id'], flag=True).first() if sign.verify_sign(app2.key, req['sign'], req['data']): print("valid sign") if deb else None canc = Change.query.filter_by(flag=False, time_req=datetime.datetime.strptime(req_data['time_req'], "%m/%d/%Y, %H:%M:%S.%f"), pub_id=req['pub_id']).order_by(Change.time_req.asc()).first() canc.flag = True db.session.commit() print("TH CHANGE CONF ---> user: "******"----------------------------------change confirm DONE----------------------------------") if deb2 else None
def isValid(self, token): try: jws.verify(token, self.__rsaPublicJWK.prepared_key.exportKey().decode(), algorithms='RS256') except Exception as e: return False return True
def validate_jwt(txt, ec_public_key): """ Validates a signed JWT """ try: jws.verify(txt, ec_public_key, ALGORITHMS.ES256, verify=True) return True except jws.JWSError: return False
def validate_jwt(token, userpool_iss, userpool_keys): """ Perform the token validation steps as per https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-using-tokens-with-identity-providers.html :param token: jwt string :param userpool_iss: string with url base to check issuer :param userpool_keys: json with JSON Web Keys of the User Pool :return: True if validation succeeds; False otherwise """ def result(msg=None): return (True, None) if msg is None else (False, msg) log.debug("Validating token") # 2 Decode the token string into JWT format. jwt_headers = jwt.get_unverified_header(token) kid = jwt_headers["kid"] use_keys = [key for key in userpool_keys if key["kid"] == kid] if len(use_keys) != 1: return result("Obtained keys are wrong") use_key = use_keys[0] try: jwt.decode(token, use_key) except Exception as e: return result("Failed to decode token: {}".format(e)) # 3 Check iss claim claims = jwt.get_unverified_claims(token) if claims["iss"] != userpool_iss: return result("Invalid issuer in token") # 4 Check token use # Should we only allow one of the tokens or both "id" and "access"? if claims["token_use"] not in ["id", "access"]: return result("Token not of valid use") # 5 Check kid jwk_kids = [obj["kid"] for obj in userpool_keys] if kid not in jwk_kids: # Should be here; condition 2 should have guaranteed this return result("Token is not related to id provider") # 6 Verify signature of decoded JWT? try: jws.verify(token, use_key, jwt_headers["alg"]) except Exception as e: return result("Failed to verify signature {}".format(e)) # 7 Check exp and make sure it is not expired exp = claims["exp"] exp_date = datetime.datetime.utcfromtimestamp(exp) now = datetime.datetime.utcnow() if exp_date < now: return result("Token has expired {}".format(exp_date - now)) return result(None)
def connect_confirm(req): print("----------------------------------connect confirm----------------------------------") if deb2 else None print("received data: ", req) if deb else None print("received data pub_id: ", req['pub_id']) if deb else None print("received data data: ", req['data']) if deb else None print("received data sign: ", req['sign']) if deb else None if UserFarm.query.filter_by(pub_id=req['pub_id']).first() is not None: app1 = UserFarm.query.filter_by(pub_id=req['pub_id']).first() print("UserFarm pub: ", app1.pub_id) if deb else None print("UserFarm priv: ", app1.pri_id) if deb else None print("decrypt pass on db: ", jws.verify(app1.pri_id, priv_id, algorithms=['HS256']).decode()) if deb else None try: req_data = json.loads(jws.verify(req['data'], jws.verify(app1.pri_id, priv_id, algorithms=['HS256']).decode(), algorithms=['HS256'])) except: emit('connect_estab', 5) print("decrypt data: ", req_data) if deb else None if Session.query.filter_by(otp=req_data['otp'], flag=True).first() is not None: app2 = Session.query.filter_by(otp=req_data['otp'], flag=True).first() if sign.verify_sign(app2.key, req['sign'], req['data']): print("valid sign") if deb else None print("time_start : ", app2.time_start) if deb else None print("now - delta : ", datetime.datetime.utcnow() - datetime.timedelta(minutes=10)) if deb else None if app2.time_start > datetime.datetime.utcnow() - datetime.timedelta(minutes=10): ses_id = ''.join(secrets.choice(alphabet) for i in range(100)) app2.session_id = ses_id print("sid: ", request.sid) if deb else None app2.sid = request.sid db.session.commit() data = {"ses_id": ses_id} print("data resp: ", data) if deb else None print("app1.pri_id: ", jws.verify(app1.pri_id, priv_id, algorithms=['HS256']).decode()) if deb else None crypt_data = jws.sign(data, jws.verify(app1.pri_id, priv_id, algorithms=['HS256']).decode(), algorithm='HS256') print("encrypt data to send: ", crypt_data) if deb else None sign_crypt_data = sign.sign_data(key.exportKey(), crypt_data) print("sign of en data send: ", sign_crypt_data) if deb else None res2 = {"pub_id": app2.pub_id, "data": crypt_data, "sign": sign_crypt_data.decode()} print("send: ", res2) if deb else None print("TH CON CONF ---> user: "******" ses_id: ", ses_id) if deb2 else None print("----------------------------------connect_confirm DONE----------------------------------") if deb2 else None emit('connect_estab', res2) global thread if thread is None: thread = threading.Thread(target=check_changes(db)) thread.start() else: emit('connect_estab', 4) else: emit('connect_estab', 3) else: emit('connect_estab', 2) else: emit('connect_estab', 1)
def test_private_verify_raises_warning(self, payload): token = jws.sign(payload, rsa_private_key, algorithm="RS256") # verify with public jws.verify(token, rsa_public_key, algorithms="RS256") with warnings.catch_warnings(record=True) as w: # verify with private raises warning jws.verify(token, rsa_private_key, algorithms="RS256") assert ("Attempting to verify a message with a private key. " "This is not recommended.") == str(w[-1].message)
def valid_signature(token, key): if isinstance(key, dict): # verify the signature, exception should be thrown if verification failed jws.verify(token, key['pem'], [key['alg']], verify=True) else: # get the last two sections of the token, # message and signature (encoded in base64) message, encoded_signature = str(token).rsplit('.', 1) # decode the signature decoded_signature = base64url_decode(encoded_signature.encode('utf-8')) # verify the signature if not key.verify(message.encode("utf8"), decoded_signature): raise JWTError('Signature verification failed') return True
def test_multiple_keys(self): old_jwk_verify = jwk.HMACKey.verify try: token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhIjoiYiJ9.jiMyrsmD8AoHWeQgmxZ5yq8z0lXS67_QGs52AzC8Ru8' def raise_exception(self, msg, sig): if self.prepared_key == b'incorrect': raise Exception("Mocked function jose.jwk.HMACKey.verify") else: return True jwk.HMACKey.verify = raise_exception jws.verify(token, {'keys': ['incorrect', 'secret']}, ['HS256']) finally: jwk.HMACKey.verify = old_jwk_verify
def verify_token(self, token, **kwargs): """Validate the token signature.""" nonce = kwargs.get('nonce') if self.OIDC_RP_SIGN_ALGO.startswith('RS'): key = self.OIDC_RP_IDP_SIGN_KEY else: key = self.OIDC_RP_CLIENT_SECRET # Verify the token verified_token = jws.verify(token, key, algorithms=[self.OIDC_RP_SIGN_ALGO]) # The 'verified_token' will always be a byte string since it's # the result of base64.urlsafe_b64decode(). # The payload is always the result of base64.urlsafe_b64decode(). # In Python 3 and 2, that's always a byte string. # In Python3.6, the json.loads() function can accept a byte string # as it will automagically decode it to a unicode string before # deserializing https://bugs.python.org/issue17909 token_nonce = json.loads(verified_token.decode('utf-8')).get('nonce') if import_from_settings('OIDC_USE_NONCE', True) and nonce != token_nonce: msg = 'JWT Nonce verification failed.' raise SuspiciousOperation(msg) return True
def test_apple_auth(tokenid): from jose import jws res = jws.verify(tokenid, APPLE_PUBLIC_KEY_PEM, algorithms=['RS256']) print(res) import json b = json.loads(res.decode('utf-8')) print(b.get('iss'))
def validate_vapid_key(self, signed_token): try: key_data = urlsafe_b64decode(str(fix_padding(self.vapid_key))) key_string = extract_public_key(key_data) verifying_key = ecdsa.VerifyingKey.from_string( key_string, curve=ecdsa.NIST256p ) signed_token = str(fix_padding(signed_token)) try: submitted_claims_json = jws.verify( signed_token, verifying_key, algorithms=['ES256'] ) submitted_claims = json.loads(submitted_claims_json) self_claims = json.loads(self.vapid_key_token) if submitted_claims['aud'] == self_claims['aud']: self.vapid_key_status = 'valid' self.validated = timezone.now() self.save() self.start_recording() except JWSError: self.vapid_key_status = 'invalid' self.save() except ecdsa.BadSignatureError: self.vapid_key_status = 'invalid' self.save()
def decrypt(self, body): ''' :param body: Body message to be 1) decrypted and 2) check for correct signature. **REQUIRED** :returns: Decrypted body message ''' jweKeySet = self.__getJwkKeySet( location=self.clientPrivateKeySetLocation) jwkDecryptKey = self.__findJwkKeyByAlgorithm( jwkKeySet=jweKeySet, algorithm=self.encryptionAlgorithm) privateKeyToDecrypt = jwk.JWK(**jwkDecryptKey) jweToken = jwe.JWE() jweToken.deserialize(body, key=privateKeyToDecrypt) payload = jweToken.payload self.__checkJwsExpiration(payload) jwsKeySet = self.__getJwkKeySet( location=self.hyperwalletKeySetLocation) jwkCheckSignKey = self.__findJwkKeyByAlgorithm( jwkKeySet=jwsKeySet, algorithm=self.signAlgorithm) return jws.verify(payload, json.dumps(jwkCheckSignKey), algorithms=self.signAlgorithm)
def test_get_freja_state(self): user = self.app.central_userdb.get_user_by_eppn(self.test_user_eppn) proofing_state = create_proofing_state(user, self.test_user_nin) self.app.proofing_statedb.save(proofing_state) with self.session_cookie(self.browser, self.test_user_eppn) as browser: response = json.loads(browser.get('/freja/proofing').data) self.assertEqual(response['type'], 'GET_OIDC_PROOFING_FREJA_PROOFING_SUCCESS') jwk = binascii.unhexlify(self.app.config.freja_jwk_secret) jwt = response['payload']['iaRequestData'].encode('ascii') request_data = jose.verify(jwt, [jwk], self.app.config.freja_jws_algorithm) expected = { 'iarp': 'TESTRP', 'opaque': '1' + json.dumps({ 'nonce': proofing_state.nonce, 'token': proofing_state.token }), 'proto': u'1.0', } claims = json.loads(request_data.decode('ascii')) self.assertIn('exp', claims) self.assertEqual(claims['iarp'], expected['iarp']) self.assertEqual(claims['opaque'], expected['opaque']) self.assertEqual(claims['proto'], expected['proto'])
def on_changes(*resp): print('CHANGE') if deb2 else None print("------\nTH: ", resp, "\n------") if deb else None print("response: ", resp[0]) if deb else None print("data response: ", resp[0]['data']) if deb else None print("sign response: ", resp[0]['sign']) if deb else None resp_data = json.loads( jws.verify(resp[0]['data'], pri_id, algorithms=['HS256']).decode()) print("decrypt data response: ", resp_data) if deb else None print("key in data response: ", server_key) if deb else None if sign.verify_sign(server_key, resp[0]['sign'], resp[0]['data']): # update new data print("valid sign") if deb else None req_data = {"ses_id": session_id, "time_req": resp_data['time_req']} print("data to send: ", req_data) if deb else None crypt_data = jws.sign(req_data, pri_id, algorithm='HS256') print("encrypt data to send: ", crypt_data) if deb else None sign_crypt_data = sign.sign_data(key.exportKey(), crypt_data) print("sign of en data send: ", sign_crypt_data) if deb else None req2 = { "pub_id": pub_id, "data": crypt_data, "sign": sign_crypt_data.decode() } print("send: ", req2) if deb else None print("CHANGE DONE") if deb2 else None socketIO.emit('change_confirm', req2)
def add_to_pull(self): self.response.headers['Content-Type'] = "application/json" self.response.headers['Access-Control-Allow-Origin'] = '*' try: authorization = self.request.headers.get('Authorization', '').split() auth_type = authorization[0] auth_token = authorization[1] user_info = json.loads( jws.verify(auth_token, 'insecure secret', algorithms=['HS256'])) user_id = user_info.get('user_id') full_name = user_info.get('full_name') payload = json.loads(self.request.body) for entity in payload: modified_entity = { 'user_id': user_id, 'measurement_type': entity.get('name'), 'measurement_value': json.dumps(entity.get('value')), 'measurement_key': json.dumps(entity.get('mKey')), 'created_at': entity.get('timestamp') } utils.insert_in_pull_queue(queue_name="openxc-stats-pull", payload=json.dumps(modified_entity)) self.error(201) except: self.error(500) logging.error(traceback.format_exc())
def _decode_vc(jws_raw, key_resolver): # before we can verify the vc, we first need to resolve the key # the key ID is stored in the header # Per the health cards IG, ## "Issuers SHALL publish keys as JSON Web Key Sets (see RFC7517), available at <<iss value from Signed JWT>> + .well-known/jwks.json" # therefore, we need decode the claims to get the iss value in order to resolve the key # The claims are compressed via Deflate, so decompress the data # then, extract the iss claim to get access to the base URL, use that to resolve key with id = kid # then, verify the jws unverified_headers = jws.get_unverified_headers(jws_raw) # we expect data to be zipped, so deflate the data if unverified_headers.get('zip') == 'DEF': unverfied_claims_zip = jws.get_unverified_claims(jws_raw) raw_data = inflate(unverfied_claims_zip) data = json.loads(raw_data) else: raise Exception('Expecting payload to be compressed') iss = data['iss'] kid = unverified_headers['kid'] key = key_resolver(iss, kid, 'ES256') verified_jws = jws.verify(jws_raw, key, algorithms='ES256') payload = json.loads(inflate(verified_jws)) return payload
def get_and_verify(url, keys, output: str) -> bool: """Downloads and verifies metadata""" try: with urllib.request.urlopen(url) as webfile: sig = webfile.read() except urllib.error.URLError as e: raise RuntimeError("Failed to get URL " + url + " (" + str(e) + ")") jwsdict = json.loads(sig) with open(keys, 'r') as keysfile: keyset_str = keysfile.read() payload = jwsdict['payload'] for s in jwsdict['signatures']: try: protected = s['protected'] signature = s['signature'] compact = protected + "." + payload + "." + signature exp_header = jws.get_unverified_headers(compact)['exp'] exp = datetime.utcfromtimestamp(int(exp_header)) if exp < datetime.utcnow(): error_print("Signature expired at: " + str(exp)) continue verified_payload = jws.verify(compact, keyset_str, None) with open(output, 'wb') as outfile: outfile.write(verified_payload) return True except jws.JWSError: continue return False
def test_renew(self): # have to use large expires to get around a double-UTC-bug here: # https://github.com/mpdavis/python-jose/blob/deea7600eeea47aeb1bf5053a96de51cf2b9c639/jose/jwt.py#L318 token = preauth.create_renew_pre_auth(self.directory, self.args, expires=86400) # validate it like the ICI ACME server will validated_token = validate_token_signature(token, self.directory['newAuthz'], self.context) # Put the preauth JWT inside the ACME JWT signed = preauth.dehydrated_account_sign(token, self.directory, self.args, nonce='test_nonce') with open(os.path.join(self.data_dir, 'account1_pubkey.pem'), 'rb') as fd: jwk = {'keys': [fd.read()]} # validate the ACME JWT like the ICI ACME middleware would (using another JOSE implementation for now) ret = jws.verify(signed.to_compact().decode(), jwk, algorithms=SUPPORTED_ALGORITHMS) verified_data = json.loads(ret) self.assertEqual(token, verified_data['token'])
def decode_access_token(auth_header, CLIENT_ID): # Get discovery document try: token = auth_header.split(" ")[1].strip() decoded_token = jt.decode(token.decode('utf-8'), verify=False) alg = jwt.get_unverified_header(token)['alg'] kid = jwt.get_unverified_header(token)['kid'] # Validate the token values validated = token_validation(decoded_token, alg, kid, CLIENT_ID) # Validate keys for key in DIRTY_KEYS: #Validate the key try: KEYS.append(jws.verify(token, key, algorithms=[alg])) except JWSError: return JWSError if validated == True: # Verify email address is held email = "" if 'email' in decoded_token: # Id token email = decoded_token['email'] else: email = get_user_data(get_discovery_document(decoded_token)['userinfo_endpoint'], auth_header)['email'] return get_gravitar(email) else: return validated except: return {'Error' : 'Could not decode Token'} # Default Error return {'Error' : 'Unexpected error occurred'}
def __call__(self, request): if 'Authorization' in request.headers: token = request.headers.get('Authorization').split(' ')[1] if 'password' in request.GET: password = request.GET['password'] decoded_dict = {} try: decoded_dict = json.loads( jws.verify(token, password, algorithms=['HS256'])) except JWSError: JsonResponse( { 'status': 'false', 'message': 'Token is incorrect' }, status=401, content_type="application/json") email = decoded_dict.get('email') user = User.objects.filter(email=email).scalar() if not user: return JsonResponse( { 'status': 'false', 'message': 'User not found' }, status=401, content_type="application/json") request.custom_user = user response = self.get_response(request) return response
def _store_results(session, response): print("Response: " + str(response)) # Okay to store this in a local variable, encrypt if it's going to client # machine or database. Treat as a password. access_token = response['access_token'] session['microsoft_token'] = (access_token, '') session['claims'] = json.loads( jws.verify(access_token, keys, algorithms=['RS256']))
def verifyJWS(token, publicCert): pemfile = open(publicCert, 'r') keystring = pemfile.read() pemfile.close() payload = jose_jws.verify(token, keystring, algorithms=['RS256']) pp(payload) payload = json.loads(payload.decode('utf8')) pp(payload) return payload
def process_request(self, req: Request, resp: Response): self.context.logger.debug(f'process_request: {req.method} {req.path}') if req.method == 'POST': if req.content_type != 'application/jose+json': raise UnsupportedMediaTypeMalformed( detail=f'{req.content_type} is an unsupported media type') data = req.media token = f'{data["protected"]}.{data["payload"]}.{data["signature"]}' headers = jws.get_unverified_headers(token) protected = json.loads(b64_decode(data['protected'])) self.context.logger.debug(f'(Unverified) headers: {headers}') if headers.get('kid') and protected.get('jwk'): raise Unauthorized( detail='The "jwk" and "kid" fields are mutually exclusive') if headers.get('url') != req.uri: raise Unauthorized( detail=f'JWS header URL ({headers.get("url")})' f' does not match requested URL ({req.uri})') # Existing account kid = headers.get('kid', None) account = self.context.get_account_using_kid(kid) if account: if account.status != 'valid': self.context.logger.info(f'Account {account} deactivated') raise Unauthorized(detail='Account deactivated') self.context.logger.info( f'Authenticating request for account {account}') req.context['account'] = account jwk = account.jwk # Account registration elif req.path.endswith('/new-account') or req.path.endswith( '/new-account/'): jwk = protected['jwk'] if protected['alg'] not in SUPPORTED_ALGORITHMS: raise BadSignatureAlgorithm( algorithms=SUPPORTED_ALGORITHMS) req.context['account_creation'] = True else: self.context.logger.warning( f'Account not found using kid {kid}') raise Unauthorized(detail='Account not found') try: ret = jws.verify(token, jwk, algorithms=SUPPORTED_ALGORITHMS) except JOSEError as e: self.context.logger.error( f'Exception while verifying token: {e}') raise ServerInternal(detail=f'{e}') self.context.logger.debug(f'Verified data: {ret}') req.context['jose_verified_data'] = ret req.context['jose_headers'] = headers
def test_token_legitimacy(): conn = boto3.client("cognito-idp", "us-west-2") path = "../../moto/cognitoidp/resources/jwks-public.json" with open(os.path.join(os.path.dirname(__file__), path)) as f: json_web_key = json.loads(f.read())["keys"][0] outputs = authentication_flow(conn) id_token = outputs["id_token"] access_token = outputs["access_token"] client_id = outputs["client_id"] issuer = "https://cognito-idp.us-west-2.amazonaws.com/{}".format(outputs["user_pool_id"]) id_claims = json.loads(jws.verify(id_token, json_web_key, "RS256")) id_claims["iss"].should.equal(issuer) id_claims["aud"].should.equal(client_id) access_claims = json.loads(jws.verify(access_token, json_web_key, "RS256")) access_claims["iss"].should.equal(issuer) access_claims["aud"].should.equal(client_id)
def extract_jwt(token, crypto_key): """Extract the claims from the validated JWT. """ # first split and convert the jwt. if not token or not crypto_key: return {} key = decipher_public_key(crypto_key) vk = ecdsa.VerifyingKey.from_string(key, curve=ecdsa.NIST256p) return jws.verify(token, vk, algorithms=["ES256"])
def test_round_trip_with_different_key_types(self, key): signed_data = jws.sign({"testkey": "testvalue"}, key, algorithm=ALGORITHMS.HS256) verified_bytes = jws.verify(signed_data, key, algorithms=[ALGORITHMS.HS256]) verified_data = json.loads(verified_bytes.decode("utf-8")) assert "testkey" in verified_data.keys() assert verified_data["testkey"] == "testvalue"
def extract_jwt(token, crypto_key): """Extract the claims from the validated JWT. """ # first split and convert the jwt. if not token or not crypto_key: return {} key = base64.urlsafe_b64decode(fix_padding(crypto_key)) key = decipher_public_key(key) vk = ecdsa.VerifyingKey.from_string(key, curve=ecdsa.NIST256p) return jws.verify(token, vk, algorithms=["ES256"])
def setUp(self): self.claims_schema = Schema({ 'taskId': 'xyz', 'exp': int, }, extra=True, required=True) self.token = sign_task("xyz", pvt_key=PVT_KEY) self.decode = jwt.decode(self.token, PUB_KEY, algorithms=[ALGORITHMS.RS512]) self.verify = jws.verify(self.token, PUB_KEY, algorithms=[ALGORITHMS.RS512])
def login(): form = LoginForm() if form.validate_on_submit(): user = UserDevice.query.filter_by(username=form.username.data).first() if user: if jws.verify(user.password, key, algorithms=['HS256']).decode() == form.password.data: login_user(user, remember=form.remember.data) return redirect(url_for('dashboard')) return render_template('index.html', data="Invalid username or password") return render_template('login.html', form=form)
def extract_jwt(token, crypto_key): """Extract the claims from the validated JWT. """ # first split and convert the jwt. if not token or not crypto_key: return {} key = decipher_public_key(crypto_key) vk = ecdsa.VerifyingKey.from_string(key, curve=ecdsa.NIST256p) # jose offers jwt.decode(token, vk, ...) which does a full check # on the JWT object. Vapid is a bit more creative in how it # stores data into a JWT and breaks expectations. We would have to # turn off most of the validation in order for it to be useful. return json.loads(jws.verify(token, vk, algorithms=["ES256"]))
def test_sign_01(self): v = Vapid01.from_file("/tmp/private") claims = {"aud": "example.com", "sub": "*****@*****.**"} result = v.sign(claims, "id=previous") eq_(result['Crypto-Key'], 'id=previous;p256ecdsa=' + T_PUBLIC_RAW) items = jws.verify( result['Authorization'].split(' ')[1], binascii.b2a_base64(v.public_key.to_der()).decode('utf8'), algorithms=["ES256"]) eq_(json.loads(items.decode('utf8')), claims) result = v.sign(claims) eq_(result['Crypto-Key'], 'p256ecdsa=' + T_PUBLIC_RAW)
def test_sign(self): v = Vapid(private_key=T_PRIVATE) claims = {"aud": "example.com", "sub": "*****@*****.**"} result = v.sign(claims, "id=previous") eq_(result['Crypto-Key'], 'id=previous,' 'p256ecdsa=' + T_PUBLIC_RAW.strip('=')) items = jws.verify(result['Authorization'][7:], v.public_key, algorithms=["ES256"]) eq_(json.loads(items), claims) result = v.sign(claims) eq_(result['Crypto-Key'], 'p256ecdsa=' + T_PUBLIC_RAW.strip('='))
def get_user_from_token(self, token): decoded_json = jws.verify(token, settings.JWT_KEY, algorithms=[settings.JWT_ALGORITHM]) decoded_dict = JSONDeserializer().deserialize(decoded_json) username = decoded_dict.get('username', None) expiration = decoded_dict.get('expiration', None) user = None try: user = User.objects.get(username=username) if not user.is_active: raise Exception() except: raise AuthenticationFailed(_('User inactive or deleted.\n\n')) if int(expiration) < int(time.time()): raise AuthenticationFailed(_('Token Expired.\n\n')) return user or AnonymousUser()
def validate_signatures(body): att_stmts = [] if isinstance(body, list): for s in body: if 'attachments' in s: att_stmts.append(s) elif 'attachments' in body: att_stmts.append(body) if att_stmts: # find if any of those statements with attachments have a signed statement signed_stmts = [(s,a) for s in att_stmts for a in s.get('attachments', None) if a['usageType'] == "http://adlnet.gov/expapi/attachments/signature"] for ss in signed_stmts: sha2_key = ss[1]['sha2'] signature = att_cache.get(sha2_key) algorithm = jws.get_unverified_headers(signature).get('alg', None) x5c = jws.get_unverified_headers(signature).get('x5c', None) jws_payload = jws.get_unverified_claims(signature) body_payload = ss[0] # If x.509 was used to sign, the public key should be in the x5c header and you need to verify it # If using RS256, RS384, or RS512 some JWS libs require a real private key to create JWS - xAPI spec # only has SHOULD - need to look into. If x.509 is necessary then if no x5c header is found this should fail if x5c: verified = False try: verified = jws.verify(signature, cert_to_key(x5c[0]), algorithm) except Exception, e: att_cache.delete(sha2_key) raise BadRequest("The JWS is not valid: %s" % e.message) else: if not verified: att_cache.delete(sha2_key) raise BadRequest("The JWS is not valid - could not verify signature") # Compare statements if not compare_payloads(jws_payload, body_payload): att_cache.delete(sha2_key) raise BadRequest("The JWS is not valid - payload and body statements do not match") else: # Compare statements if not compare_payloads(jws_payload, body_payload): att_cache.delete(sha2_key) raise BadRequest("The JWS is not valid - payload and body statements do not match")
def validate_signature(tup, part): sha2_key = tup[1][0] signature = get_part_payload(part) algorithm = jws.get_unverified_headers(signature).get('alg', None) if not algorithm: raise BadRequest( "No signing algorithm found for JWS signature") if algorithm != 'RS256' and algorithm != 'RS384' and algorithm != 'RS512': raise BadRequest( "JWS signature must be calculated with SHA-256, SHA-384 or" \ "SHA-512 algorithms") x5c = jws.get_unverified_headers(signature).get('x5c', None) jws_payload = jws.get_unverified_claims(signature) body_payload = tup[0] # If x.509 was used to sign, the public key should be in the x5c header and you need to verify it # If using RS256, RS384, or RS512 some JWS libs require a real private key to create JWS - xAPI spec # only has SHOULD - need to look into. If x.509 is necessary then # if no x5c header is found this should fail if x5c: verified = False try: verified = jws.verify( signature, cert_to_key(x5c[0]), algorithm) except Exception as e: raise BadRequest("The JWS is not valid: %s" % e.message) else: if not verified: raise BadRequest( "The JWS is not valid - could not verify signature") # Compare statements if not compare_payloads(jws_payload, body_payload, sha2_key): raise BadRequest( "The JWS is not valid - payload and body statements do not match") else: # Compare statements if not compare_payloads(jws_payload, body_payload, sha2_key): raise BadRequest( "The JWS is not valid - payload and body statements do not match")
def test_verify(self): token = sign_task("xyz", pvt_key=PVT_KEY) claims = jws.verify(token, PUB_KEY, algorithms=[ALGORITHMS.RS512]) assert claims["taskId"] == "xyz"
def testHMAC512(self, claims): token = jws.sign(claims, 'secret', algorithm=ALGORITHMS.HS512) assert jws.verify(token, 'secret', ALGORITHMS.HS512) == claims
def test_wrong_key(self, payload): token = jws.sign(payload, 'secret', algorithm=ALGORITHMS.HS256) with pytest.raises(JWSError): jws.verify(token, 'another', ALGORITHMS.HS256)
def testHMAC512(self, payload): token = jws.sign(payload, 'secret', algorithm=ALGORITHMS.HS512) assert jws.verify(token, 'secret', ALGORITHMS.HS512) == payload
def test_claims_not_json(self): token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.dGVzdA.jiMyrsmD8AoHWeQgmxZ5yq8z0lXS67_QGs52AzC8Ru8' with pytest.raises(JWSError): jws.verify(token, 'secret', ['HS256'])
def test_claims_invalid_padding(self): token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.AeyJhIjoiYiJ9.jiMyrsmD8AoHWeQgmxZ5yq8z0lXS67_QGs52AzC8Ru8' with pytest.raises(JWSError): jws.verify(token, 'secret', ['HS256'])
def test_not_enough_segments(self): token = 'eyJhIjoiYiJ9.jiMyrsmD8AoHWeQgmxZ5yq8z0lXS67_QGs52AzC8Ru8' with pytest.raises(JWSError): jws.verify(token, 'secret', ['HS256'])
def test_header_not_json(self): token = 'dGVzdA.eyJhIjoiYiJ9.jiMyrsmD8AoHWeQgmxZ5yq8z0lXS67_QGs52AzC8Ru8' with pytest.raises(JWSError): jws.verify(token, 'secret', ['HS256'])
def test_wrong_alg(self, claims): token = jws.sign(claims, 'secret', algorithm=ALGORITHMS.HS256) with pytest.raises(JWSError): jws.verify(token, 'secret', ALGORITHMS.HS384)
def test_RSA384(self, payload): token = jws.sign(payload, rsa_private_key, algorithm=ALGORITHMS.RS384) assert jws.verify(token, rsa_public_key, ALGORITHMS.RS384) == payload
def test_jwk_set_failure(self, jwk_set): # Remove the key that was used to sign this token. del jwk_set['keys'][1] with pytest.raises(JWSError): payload = jws.verify(google_id_token, jwk_set, ALGORITHMS.RS256)
def test_jwk_set(self, jwk_set): # Would raise a JWSError if validation failed. payload = jws.verify(google_id_token, jwk_set, ALGORITHMS.RS256) iss = json.loads(payload.decode('utf-8'))['iss'] assert iss == "https://accounts.google.com"
def test_signature_padding(self): token = 'eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.eyJoZWxsbyI6ICJ3b3JsZCJ9.aatvagLDLoaiJKxOKqpBXSEGy7SYSifZhjntgm9ctpyj8' with pytest.raises(JWSError): jws.verify(token, 'secret', ['HS256'])
def test_EC512(self, payload): token = jws.sign(payload, ec_private_key, algorithm=ALGORITHMS.ES512) assert jws.verify(token, ec_public_key, ALGORITHMS.ES512) == payload
def test_unicode_token(self): token = u'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhIjoiYiJ9.jiMyrsmD8AoHWeQgmxZ5yq8z0lXS67_QGs52AzC8Ru8' jws.verify(token, 'secret', ['HS256'])
def test_wrong_alg(self, payload): token = jws.sign(payload, ec_private_key, algorithm=ALGORITHMS.ES256) with pytest.raises(JWSError): jws.verify(token, rsa_public_key, ALGORITHMS.ES384)
def decode(token, key, algorithms=None, options=None, audience=None, issuer=None, subject=None, access_token=None): """Verifies a JWT string's signature and validates reserved claims. Args: token (str): A signed JWS to be verified. key (str): A key to attempt to verify the payload with. algorithms (str or list): Valid algorithms that should be used to verify the JWS. audience (str): The intended audience of the token. If the "aud" claim is included in the claim set, then the audience must be included and must equal the provided claim. issuer (str or iterable): Acceptable value(s) for the issuer of the token. If the "iss" claim is included in the claim set, then the issuer must be given and the claim in the token must be among the acceptable values. subject (str): The subject of the token. If the "sub" claim is included in the claim set, then the subject must be included and must equal the provided claim. access_token (str): An access token returned alongside the id_token during the authorization grant flow. If the "at_hash" claim is included in the claim set, then the access_token must be included, and it must match the "at_hash" claim. options (dict): A dictionary of options for skipping validation steps. defaults = { 'verify_signature': True, 'verify_aud': True, 'verify_iat': True, 'verify_exp': True, 'verify_nbf': True, 'verify_iss': True, 'verify_sub': True, 'verify_jti': True, 'leeway': 0, } Returns: dict: The dict representation of the claims set, assuming the signature is valid and all requested data validation passes. Raises: JWTError: If the signature is invalid in any way. Examples: >>> payload = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhIjoiYiJ9.jiMyrsmD8AoHWeQgmxZ5yq8z0lXS67_QGs52AzC8Ru8' >>> jwt.decode(payload, 'secret', algorithms='HS256') """ defaults = { 'verify_signature': True, 'verify_aud': True, 'verify_iat': True, 'verify_exp': True, 'verify_nbf': True, 'verify_iss': True, 'verify_sub': True, 'verify_jti': True, 'verify_at_hash': True, 'leeway': 0, } if options: defaults.update(options) verify_signature = defaults.get('verify_signature', True) try: payload = jws.verify(token, key, algorithms, verify=verify_signature) except JWSError as e: raise JWTError(e) # Needed for at_hash verification algorithm = jws.get_unverified_header(token)['alg'] try: claims = json.loads(payload.decode('utf-8')) except ValueError as e: raise JWTError('Invalid payload string: %s' % e) if not isinstance(claims, Mapping): raise JWTError('Invalid payload string: must be a json object') _validate_claims(claims, audience=audience, issuer=issuer, subject=subject, algorithm=algorithm, access_token=access_token, options=defaults) return claims