def _load(jwt): if isinstance(jwt, six.text_type): jwt = jwt.encode('utf-8') try: signing_input, crypto_segment = jwt.rsplit(b'.', 1) header_segment, claims_segment = signing_input.split(b'.', 1) header_data = base64url_decode(header_segment) except ValueError: raise JWSError('Not enough segments') except (TypeError, binascii.Error): raise JWSError('Invalid header padding') try: header = json.loads(header_data.decode('utf-8')) except ValueError as e: raise JWSError('Invalid header string: %s' % e) if not isinstance(header, Mapping): raise JWSError('Invalid header string: must be a json object') try: payload = base64url_decode(claims_segment) except (TypeError, binascii.Error): raise JWSError('Invalid payload padding') try: signature = base64url_decode(crypto_segment) except (TypeError, binascii.Error): raise JWSError('Invalid crypto padding') return (header, payload, signing_input, signature)
def _get_token(self): # Fetch key from server http_protocol = "http" if DMC_INSECURE else "https" self._logger.info( "attempting to authenticate on %s://%s" % (http_protocol, DMC_URI) ) key = requests.get('{}://{}/drone/keys.json'.format(http_protocol, DMC_URI)) if key.status_code >= 299: self._logger.error("could not fetch keys, server error") raise AuthException('could not access keys: {}'.format(key.status_code)) key = key.json() # Authenticate anip_uri = DMC_ANIP_URI or "{}/drone/auth".format(DMC_URI) self._logger.info("fetching token from %s" % anip_uri) ret = requests.post("{}://{}".format(http_protocol, anip_uri), json={ 'id': self.drone_id, 'password': self.password }) if ret.status_code >= 500: raise AuthException('could not fetch token, server error') elif ret.status_code > 299: raise AuthException('unauthorized: {}'.format(ret)) # Verify recieved token with key from server token = ret.json()['token'] rsa_key = jwk.construct(key) message, encoded_sig = token.rsplit('.', 1) decoded_sig = base64url_decode(str(encoded_sig)) if not rsa_key.verify(message, decoded_sig): raise AuthException('invalid token') payload = message.split('.')[1] auth = json.loads(base64url_decode(str(payload))) return token, auth
def test_zip_header_not_present_when_none(self): enc = ALGORITHMS.A256CBC_HS512 alg = ALGORITHMS.RSA_OAEP_256 encrypted = jwe.encrypt("Text", PUBLIC_KEY_PEM, enc, alg, zip=ZIPS.NONE) header = json.loads(six.ensure_str(base64url_decode(encrypted.split(b".")[0]))) assert "zip" not in header
def test_cty_header_present_when_provided(self): enc = ALGORITHMS.A256CBC_HS512 alg = ALGORITHMS.RSA_OAEP_256 encrypted = jwe.encrypt("Text", PUBLIC_KEY_PEM, enc, alg, cty="expected") header = json.loads(six.ensure_str(base64url_decode(encrypted.split(b".")[0]))) assert header["cty"] == "expected"
def lambda_handler(event, context): token = event['token'] # get the kid from the headers prior to verification headers = jwt.get_unverified_headers(token) kid = headers['kid'] # search for the kid in the downloaded public keys key_index = -1 for i in range(len(keys)): if kid == keys[i]['kid']: key_index = i break if key_index == -1: print('Public key not found in jwks.json') return False # construct the public key public_key = jwk.construct(keys[key_index]) # 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) # verify the signature if public_key.verify(message, decoded_signature): print('Signature successfully verified') # since we passed the verification, now we can safely # get the unverified claims claims = jwt.get_unverified_claims(token) # do some stuff with our claims print(claims) return claims else: print('Signature verification failed') return False
def token_decoder(token): set_cognito_data_global() headers = jwt.get_unverified_headers(token) kid = headers['kid'] result = {} for item in POOL_KEYS: result[item['kid']] = item public_key = jwk.construct(result.get(kid)) message, encoded_signature = str(token).rsplit('.', 1) decoded_signature = base64url_decode(encoded_signature.encode('utf-8')) if not public_key.verify(message.encode("utf8"), decoded_signature): app.logger.error('Signature verification failed') raise Exception app.logger.debug('Signature successfully verified') claims = jwt.get_unverified_claims(token) if time.time() > claims['exp']: app.logger.error('Token is expired') raise Exception app.logger.debug(claims) return claims
def validate_token(access_token, issuer, audience, client_ids): # Client ID's list cid_list = [] if not isinstance(client_ids, list): cid_list = client_ids.split(',') else: cid_list = client_ids check_presence_of(access_token, issuer, audience, cid_list) # Decoding Header & Payload from token header = jwt.get_unverified_header(access_token) payload = jwt.get_unverified_claims(access_token) # Verifying Claims verify_claims(payload, issuer, audience, cid_list) # Verifying Signature jwks_key = fetch_jwk_for(header, payload) key = jwk.construct(jwks_key) message, encoded_sig = access_token.rsplit('.', 1) decoded_sig = base64url_decode(encoded_sig.encode('utf-8')) valid = key.verify(message.encode(), decoded_sig) # If the token is valid, it returns the payload if valid == True: return payload else: raise Exception('Invalid Token')
def get_username_from_token(self, token): if self.keys is None: (self.keys, self.keys_iss) = self.__get_userpool_keys() try: headers = jwt.get_unverified_header(token) except: return None if not headers.get('kid'): return None kid = headers['kid'] key_index = -1 for i in range(len(self.keys)): if kid == self.keys[i]['kid']: key_index = i break if key_index == -1: return None public_key = jwk.construct(self.keys[key_index]) message, encoded_signature = str(token).rsplit('.', 1) decoded_signature = base64url_decode(encoded_signature.encode('utf-8')) if not public_key.verify(message.encode("utf8"), decoded_signature): return None claims = jwt.get_unverified_claims(token) return claims["username"]
def verify_signature(self, token, pkey_data): """ #Verifica si no a modificado Payload del token #Mediante la signature Args: token (string): jwt pkey_data ([type]): [description] Raises: VerifyTokenException: [description] VerifyTokenException: [description] """ try: # Key data public_key = jwk.construct(pkey_data) except JOSEError: raise CustomException(status_code=401, type='signature', detail='Token inválido') #Obtiene Signature message, encoded_signature = str(token).rsplit(".", 1) # Decodifica Signature decoded_signature = base64url_decode(encoded_signature.encode("utf-8")) # Verifica Signature if not public_key.verify(message.encode("utf8"), decoded_signature): raise CustomException( status_code=401, type='signature', detail='Token a sido Modificado, Signature inválido!')
def test_deterministic_headers(self): from collections import OrderedDict from jose.utils import base64url_decode claims = {"a": "b"} key = "secret" headers1 = OrderedDict(( ('kid', 'my-key-id'), ('another_key', 'another_value'), )) encoded1 = jwt.encode(claims, key, algorithm='HS256', headers=headers1) encoded_headers1 = encoded1.split('.', 1)[0] headers2 = OrderedDict(( ('another_key', 'another_value'), ('kid', 'my-key-id'), )) encoded2 = jwt.encode(claims, key, algorithm='HS256', headers=headers2) encoded_headers2 = encoded2.split('.', 1)[0] assert encoded_headers1 == encoded_headers2 # manually decode header to compare it to known good decoded_headers1 = base64url_decode(encoded_headers1.encode('utf-8')) assert decoded_headers1 == b"""{"alg":"HS256","another_key":"another_value","kid":"my-key-id","typ":"JWT"}"""
def lambda_handler(event, context): print(event) token = event['request']['headers']['v-cognito-user-jwt'] headers = jwt.get_unverified_headers(token) kid = headers['kid'] key_index = -1 for i in range(len(KEYS)): if kid == KEYS[i]['kid']: key_index = i break if key_index == -1: print('Public key not found in jwks.json') return 'jwks failed validation - return Public key' public_key = jwk.construct(KEYS[key_index]) message, encoded_signature = str(token).rsplit('.', 1) decoded_signature = base64url_decode(encoded_signature.encode('utf-8')) if not public_key.verify(message.encode('utf8'), decoded_signature): print('Signature verification failed') return 'jwks failed validation - return Signature' claims = jwt.get_unverified_claims(token) print(claims) print(claims['email']) claims['cognito_username'] = claims['cognito:username'] claims['cognito_groups'] = claims['cognito:groups'] return claims
def get_claims(logger: logging.Logger, token: str) -> Dict[str, Union[str, int]]: # client_id = os.environ["COGNITO_APP_CLIENT_ID"] # get the kid from the headers prior to verification headers: Dict[str, str] = cast(Dict[str, str], jwt.get_unverified_headers(token=token)) kid: str = headers["kid"] # search for the kid in the downloaded public keys for key in _get_keys(logger): if kid == key["kid"]: # construct the public key public_key = jwk.construct(key_data=key) break else: raise ValueError("Public key not found in JWK.") # get the last two sections of the token, # message and signature (encoded in base64) message, encoded_signature = token.rsplit(".", 1) # decode the signature decoded_signature: bytes = base64url_decode(encoded_signature.encode("utf-8")) # verify the signature if public_key.verify(msg=message.encode("utf8"), sig=decoded_signature) is False: raise RuntimeError("Signature verification failed.") logger.debug("Signature validaded.") # since we passed the verification, we can now safely use the unverified claims claims = jwt.get_unverified_claims(token) # additionally we can verify the token expiration if time.time() > int(claims["exp"]): raise ValueError("Token expired.") logger.debug("Token not expired.") logger.debug("claims: %s", claims) return cast(Dict[str, Union[str, int]], claims)
def get_claims(token: str) -> Dict[str, Union[str, int]]: # get the kid from the headers prior to verification headers: Dict[str, str] = cast(Dict[str, str], jwt.get_unverified_headers(token=token)) kid: str = headers["kid"] # search for the kid in the downloaded public keys for key in _get_keys(): if kid == key["kid"]: # construct the public key public_key = jwk.construct(key_data=key) break else: raise ValueError("Public key not found in JWK.") # get the last two sections of the token, # message and signature (encoded in base64) message, encoded_signature = token.rsplit(".", 1) # decode the signature decoded_signature: bytes = base64url_decode(encoded_signature.encode("utf-8")) # verify the signature if public_key.verify(msg=message.encode("utf8"), sig=decoded_signature) is False: raise RuntimeError("Signature verification failed.") print("Signature validaded.") # since we passed the verification, we can now safely use the unverified claims claims: Dict[str, Union[str, int]] = cast(Dict[str, Union[str, int]], jwt.get_unverified_claims(token)) # additionally we can verify the token expiration if time.time() > int(claims["exp"]): raise ValueError("Token expired.") print("Token not expired.") # and the Audience (use claims['client_id'] if verifying an access token) if claims["aud"] != COGNITO_USER_POOL_CLIENT_ID: raise ValueError("Token was not issued for this audience.") # now we can use the claims return claims
def test_zip_header_present_when_provided(self): enc = ALGORITHMS.A256CBC_HS512 alg = ALGORITHMS.RSA_OAEP_256 encrypted = jwe.encrypt("Text", PUBLIC_KEY_PEM, enc, alg, zip=ZIPS.DEF) header = json.loads( six.ensure_str(base64url_decode(encrypted.split(".")[0]))) assert header["zip"] == ZIPS.DEF
def run(self): self.identifier = self.signed_se['header']['uniqueId'] print('\tUnique ID: {}'.format(self.identifier.upper())) # Decode the protected header protected = json.loads( base64url_decode(self.signed_se['protected'].encode('ascii'))) if protected['kid'] != self.verification_cert_kid_b64: raise ValueError('kid does not match certificate value') if protected['x5t#S256'] != self.verification_cert_x5t_s256_b64: raise ValueError('x5t#S256 does not match certificate value') # Convert JWS to compact form as required by python-jose jws_compact = '.'.join([ self.signed_se['protected'], self.signed_se['payload'], self.signed_se['signature'] ]) # Verify and decode the payload. If verification fails an exception will # be raised. se = json.loads( jose.jws.verify(token=jws_compact, key=self.verification_public_key_pem, algorithms=verification_algorithms)) try: public_keys = se['publicKeySet']['keys'] except KeyError: public_keys = [] for jwk in public_keys: cert_chain = '' for cert_b64 in jwk.get('x5c', []): cert = x509.load_der_x509_certificate( data=b64decode(cert_b64), backend=default_backend()) self.certificate_chain = self.certificate_chain + cert.public_bytes( encoding=serialization.Encoding.PEM).decode('ascii')
def find_valid_key(self, id_token): for key in self.get_jwks_keys(): rsakey = jwk.construct(key) message, encoded_sig = id_token.rsplit('.', 1) decoded_sig = base64url_decode(encoded_sig.encode('utf-8')) if rsakey.verify(message.encode('utf-8'), decoded_sig): return key
def verified_claims(token: str, app_client_id: str = os.environ.get('COGNITO_CLIENT_ID'), public_keys: dict = None) -> bool: """ verified token signature, expiry and app_id then returns claims """ headers = jwt.get_unverified_headers(token) kid = headers['kid'] public_keys = public_keys or get_cognito_public_keys() public_key = jwk.construct(public_keys[kid]) message, encoded_signature = str(token).rsplit('.', 1) decoded_signature = base64url_decode(encoded_signature.encode('utf-8')) if not public_key.verify(message.encode("utf8"), decoded_signature): raise RuntimeError(f'Signature verification failed') claims = jwt.get_unverified_claims(token) if time.time() > claims['exp']: expiry = datetime.fromtimestamp(claims['exp']) raise RuntimeError( f"Token expired at {expiry}, it is now {datetime.now()}") if app_client_id and claims['client_id'] != app_client_id: raise RuntimeError( f"Token audience {claims['aud']} was not issued for this audience {app_client_id}" ) return claims
def test_alg_enc_headers(self): enc = ALGORITHMS.A256CBC_HS512 alg = ALGORITHMS.RSA_OAEP_256 encrypted = jwe.encrypt("Text", PUBLIC_KEY_PEM, enc, alg) header = json.loads(base64url_decode(encrypted.split(b".")[0])) assert header["enc"] == enc assert header["alg"] == alg
def __validateSignatureJWS(self, token): userPoolId = settings.AWS_CONFIG['USER_POOL_ID'] region = settings.AWS_CONFIG['REGION'] keysUrl = 'https://cognito-idp.{}.amazonaws.com/{}/.well-known/jwks.json'.format( region, userPoolId) with urllib.request.urlopen(keysUrl) as f: response = f.read() keys = json.loads(response.decode('utf-8'))['keys'] headers = jwt.get_unverified_headers(token) kid = headers['kid'] keyIndex = -1 for i in range(len(keys)): if kid == keys[i]['kid']: keyIndex = i break if keyIndex == -1: return False, 'Public key not found in jwks.json' publicKey = jwk.construct(keys[keyIndex]) payload, signature = str(token).rsplit('.', 1) decodedSignature = base64url_decode(signature.encode('utf-8')) if not publicKey.verify(payload.encode("utf8"), decodedSignature): return False, 'Signature verification failed' return True, None
def get_and_verify_claims(token): # get the kid from the headers prior to verification headers = jwt.get_unverified_headers(token) kid = headers['kid'] # search for the kid in the downloaded public keys key_index = -1 for i in range(len(keys)): if kid == keys[i]['kid']: key_index = i break if key_index == -1: raise Exception("Public key not found in jwks.json") # construct the public key public_key = jwk.construct(keys[key_index]) # 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 public_key.verify(message.encode("utf8"), decoded_signature): raise Exception('Signature verification failed') # since we passed the verification, we can now safely # use the unverified claims claims = jwt.get_unverified_claims(token) # additionally we can verify the token expiration if time.time() > claims['exp']: raise Exception('Token is expired') # and the Audience (use claims['client_id'] if verifying an access token) if claims['aud'] != app_client_id: raise Exception('Token was not issued for this audience') # now we can use the claims return claims
def token_decoder(token): """ The ID token expires one hour after the user authenticates. You should not process the ID token in your client or web API after it has expired. https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-using-tokens-with-identity-providers.html :param token: :return: """ set_cognito_data_global() token = remove_barer(token) headers = jwt.get_unverified_headers(token) kid = headers['kid'] result = {} for item in POOL_KEYS: result[item['kid']] = item public_key = jwk.construct(result.get(kid)) message, encoded_signature = str(token).rsplit('.', 1) decoded_signature = base64url_decode(encoded_signature.encode('utf-8')) if not public_key.verify(message.encode("utf8"), decoded_signature): raise UnauthorizedError('Invalid Token') claims = jwt.get_unverified_claims(token) if time.time() > claims['exp']: raise UnauthorizedError('Token in expired!') return claims
def test_kid_header_not_present_when_not_provided(self): enc = ALGORITHMS.A256CBC_HS512 alg = ALGORITHMS.RSA_OAEP_256 encrypted = jwe.encrypt("Text", PUBLIC_KEY_PEM, enc, alg) header = json.loads( six.ensure_str(base64url_decode(encrypted.split(".")[0]))) assert "kid" not in header
def extract_public_data_pem(self, se_object): ''' Function extract the publickey JWK object from secure element and return it in pem format Inputs: se_object contains secure element object Outputs: slots contains public keys in pem format ''' try: public_keys = se_object['publicKeySet']['keys'] except KeyError: public_keys = [] slots = [] for jwk in public_keys: if jwk['kty'] not in ['EC', 'RSA', 'oct']: print('Unsupported {}'.format(json.dumps({'kty': jwk['kty']}))) continue if jwk['crv'] not in ['P-256', 'P-384', 'P-521']: print('Unsupported {}'.format(json.dumps({'crv': jwk['crv']}))) continue slot = {} slot.update({'id': jwk['kid']}) public_key = ec.EllipticCurvePublicNumbers( curve=ec.SECP256R1(), x=int.from_bytes(base64url_decode( jwk['x'].encode('utf8')), byteorder='big', signed=False), y=int.from_bytes(base64url_decode( jwk['y'].encode('utf8')), byteorder='big', signed=False) ).public_key(default_backend()) slot.update({'pub_key': public_key.public_bytes( encoding=serialization.Encoding.PEM, format=serialization.PublicFormat.SubjectPublicKeyInfo).decode('ascii')}) # Decode any available certificates slot_certs = [] for cert_b64 in jwk.get('x5c', []): cert = x509.load_der_x509_certificate( data=b64decode(cert_b64), backend=default_backend()) slot_certs.append( cert.public_bytes( encoding=serialization.Encoding.PEM).decode('ascii')) slot.update({'certs': slot_certs}) slots.append(slot) return slots
async def _verify_signature(app, jws, payload): jws_header_b64, _, signature_b64 = jws.split('.') signature = base64url_decode(signature_b64.encode()) header_str = base64url_decode(jws_header_b64.encode()) header = json.loads(header_str) if header.get('jku') != app.config.expected_jwks_uri: return False response = await app.aiohttp_session.get(app.config.expected_jwks_uri) jwks = await response.json() # Get the first key with ID matching the header's raw_key = next(k for k in jwks['keys'] if k.get('kid') == header['kid']) key = jwk.construct(raw_key) payload_b64 = base64url_encode(payload).decode() secured_input = f'{jws_header_b64}.{payload_b64}' return key.verify(secured_input.encode(), signature)
def find_valid_key(self, id_token): for key in self.get_jwks_keys(): rsakey = jwk.construct(key) message, encoded_sig = id_token.rsplit('.', 1) decoded_sig = base64url_decode(encoded_sig.encode('utf-8')) if rsakey.verify(message.encode('utf-8'), decoded_sig): return key return False
def get_current_user(db: Session = Depends(get_db), token: str = Security(reusable_oauth2)): # try: # payload = jwt.decode(token, config.SECRET_KEY, algorithms=[ALGORITHM]) # token_data = TokenPayload(**payload) # except PyJWTError: # raise HTTPException( # status_code=HTTP_403_FORBIDDEN, detail="Could not validate credentials" # ) # user = crud.user.get(db, user_id=token_data.user_id) # if not user: # raise HTTPException(status_code=404, detail="User not found") # return user # get the kid from the headers prior to verification headers = jwt.get_unverified_headers(token) kid = headers['kid'] # search for the kid in the downloaded public keys key_index = -1 for i in range(len(keys)): if kid == keys[i]['kid']: key_index = i break if key_index == -1: logger.info('Public key not found in jwks.json') return False # construct the public key public_key = jwk.construct(keys[key_index]) # 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 public_key.verify(message.encode("utf8"), decoded_signature): logger.info('Signature verification failed') return False logger.info('Signature successfully verified') # since we passed the verification, we can now safely # use the unverified claims claims = jwt.get_unverified_claims(token) # additionally we can verify the token expiration if time.time() > claims['exp']: logger.info('Token is expired') raise HTTPException(status_code=404, detail="Sessions has expired.") # and the Audience (use claims['client_id'] if verifying an access token) if claims['client_id'] != app_client_id: logger.info('Token was not issued for this audience') raise HTTPException(status_code=404, detail="Unauthorized access. Access denied") # now we can use the claims # print(claims) user = crud.user.get(db, cognito_user_id=claims["sub"]) if not user: raise HTTPException(status_code=404, detail="User not found") return user
def decode_cognito_token(token, cognito_clinet_id, aws_keys): result = {} try: headers = jwt.get_unverified_headers(token) except Exception as e: result = {"error": str(e)} logging.error(result) return result else: logging.info(json.dumps(headers)) id_kid = headers['kid'] logging.info(f'kid:{id_kid} found in idtoken') # search for the kid in the downloaded public keys key_index = -1 for count in range(len(aws_keys['keys'])): if aws_keys['keys'][count]['kid'] == id_kid: logging.info(f"matched idtoken kid with AWS kid index:{count}") key_index = count if key_index == -1: logging.error('Public key not found in jwks.json') result = {"error": "Public key not found in jwks.json"} return result # construct the public key public_key = jwk.construct(aws_keys['keys'][key_index]) # 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 public_key.verify(message.encode("utf8"), decoded_signature): logging.error('Signature verification failed') result = {"error": "Signature verification failed"} return result logging.info('Signature successfully verified') # since we passed the verification, we can now safely # use the unverified claims claims = jwt.get_unverified_claims(token) # additionally we can verify the token expiration if time.time() > claims['exp']: logging.error('Token has expired') result = {"error": "Token has expired"} return result # and the Audience (use claims['client_id'] if verifying an access token) if claims['token_use'] == 'id': if claims['aud'] != cognito_clinet_id: logging.error('Token was not issued for this audience') result = {"error": "Token was not issued for this audience"} return result if claims['token_use'] == 'access': if claims['client_id'] != cognito_clinet_id: logging.error('Token was not issued for this audience') result = {"error": "Token was not issued for this audience"} return result result['data'] = claims return result ''''''
def verify_token(self, token, username): if self.keys is None: (self.keys, self.keys_iss) = self.__get_userpool_keys() # get the kid from the headers prior to verification try: headers = jwt.get_unverified_header(token) except: return 6 if not headers.get('kid'): return 7 kid = headers['kid'] # search for the kid in the downloaded public keys key_index = -1 for i in range(len(self.keys)): if kid == self.keys[i]['kid']: key_index = i break if key_index == -1: print('Public key not found in jwks.json') return 8 # construct the public key public_key = jwk.construct(self.keys[key_index]) # 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 public_key.verify(message.encode("utf8"), decoded_signature): print('Signature verification failed') return 9 # since we passed the verification, we can now safely # use the unverified claims claims = jwt.get_unverified_claims(token) if claims["token_use"] != "access": print('Token is not an access token') return 1 curr_time = int(time.time()) if curr_time > claims["exp"] or curr_time < claims["iat"]: #print('Token is expired {} [iat {}, exp {}]'.format(curr_time, claims["iat"], claims["exp"])) return 2 if claims["client_id"] != config.CONFIG_CLIENT_ID: print('Token was not issued for this client_id') return 3 if claims["username"] != username: print('Token was not issued for this username') return 4 if claims['iss'] != self.keys_iss: print('Token was not issued for this pool_id') return 5 return 0
def _process_cert(self, key): pemLines = key.replace(b' ', b'').split() certDer = base64url_decode(b''.join(pemLines[1:-1])) certSeq = DerSequence() certSeq.decode(certDer) tbsSeq = DerSequence() tbsSeq.decode(certSeq[0]) self.prepared_key = RSA.importKey(tbsSeq[6]) return
def verify_jwt(region, user_pool_id, app_client_id, token_type, token): this_region = region this_user_pool_id = user_pool_id this_token_type = token_type this_token = token this_app_client_id = app_client_id keys_url = "https://cognito-idp.{}.amazonaws.com/{}/.well-known/jwks.json".format( this_region, this_user_pool_id ) with urllib.request.urlopen(keys_url) as f: response = f.read() keys = json.loads(response.decode("utf-8"))["keys"] headers = jwt.get_unverified_headers(this_token) kid = headers["kid"] # search for the kid in the downloaded public keys key_index = -1 for i in range(len(keys)): if kid == keys[i]["kid"]: key_index = i break if key_index == -1: log.error("Public key not found in jwks.json") return False # construct the public key public_key = jwk.construct(keys[key_index]) # get the last two sections of the token, # message and signature (encoded in base64) message, encoded_signature = str(this_token).rsplit(".", 1) # decode the signature decoded_signature = base64url_decode(encoded_signature.encode("utf-8")) # verify the signature if not public_key.verify(message.encode("utf8"), decoded_signature): log.error("Signature verification failed") return False log.info("Identity token signature successfully verified") # since we passed the verification, we can now safely # use the unverified claims claims = jwt.get_unverified_claims(this_token) # additionally we can verify the token expiration if time.time() > claims["exp"]: log.error("Token is expired") return False # and the Audience (use claims['client_id'] if verifying an access token) if this_token_type == "access_token": if claims["client_id"] != this_app_client_id: log.error("Token was not issued for this audience") return False elif this_token_type == "id_token": if claims["aud"] != this_app_client_id: log.error("Token was not issued for this audience") return False else: return False # now we can use the claims return claims
def _verify(self, token): headers = jwt.get_unverified_headers(token) kid = headers['kid'] key = self._get_key(kid) public_key = jwk.construct(key) message, encoded_signature = str(token).rsplit('.', 1) decoded_signature = base64url_decode(encoded_signature.encode('utf-8')) if not public_key.verify(message.encode("utf8"), decoded_signature): raise InvalidToken('Signature verification failed')
def _process_jwk(self, jwk_dict): if not jwk_dict.get('kty') == 'oct': raise JWKError("Incorrect key type. Expected: 'oct', Recieved: %s" % jwk_dict.get('kty')) k = jwk_dict.get('k') k = k.encode('utf-8') k = bytes(k) k = base64url_decode(k) return k