def test_decode_jwt_validation( aud, iss, nbf, iat, exp, expected_exception, private_key_pem, public_key ): token = jwt.encode(_token_data(aud, "subject", iss, iat, exp, nbf), private_key_pem, "RS256") if expected_exception is not None: with pytest.raises(InvalidTokenError) as ite: max_exp = exp_max_s_option(3600) decode( token, public_key, algorithms=["RS256"], audience="someaudience", issuer="someissuer", options=max_exp, leeway=60, ) assert ite.match(expected_exception) else: max_exp = exp_max_s_option(3600) decode( token, public_key, algorithms=["RS256"], audience="someaudience", issuer="someissuer", options=max_exp, leeway=60, )
def _execute_call(self, url, aud, auth=None, params=None): """ Executes a call to the external JWT auth provider. """ result = self.client.get(url, timeout=2, auth=auth, params=params) if result.status_code != 200: return (None, result.text or 'Could not make JWT auth call') try: result_data = json.loads(result.text) except ValueError: raise Exception( 'Returned JWT body for url %s does not contain JSON', url) # Load the JWT returned. encoded = result_data.get('token', '') exp_limit_options = jwtutil.exp_max_s_option(self.max_fresh_s) try: payload = jwtutil.decode(encoded, self.public_key, algorithms=['RS256'], audience=aud, issuer=self.issuer, options=exp_limit_options) return (payload, None) except jwtutil.InvalidTokenError: logger.exception('Exception when decoding returned JWT for url %s', url) return (None, 'Exception when decoding returned JWT')
def test_decode_jwt_invalid_key(private_key_pem): # Encode with the test private key. token = jwt.encode(_token_data("aud", "subject", "someissuer"), private_key_pem, "RS256") # Try to decode with a different public key. another_public_key = ( rsa.generate_private_key( public_exponent=65537, key_size=2048, ) .public_key() .public_bytes( encoding=serialization.Encoding.PEM, format=serialization.PublicFormat.SubjectPublicKeyInfo, ) ) with pytest.raises(InvalidTokenError) as ite: max_exp = exp_max_s_option(3600) decode( token, another_public_key, algorithms=["RS256"], audience="aud", issuer="someissuer", options=max_exp, leeway=60, ) assert ite.match("Signature verification failed")
def test_decode_jwt_invalid_algorithm(private_key_pem, public_key): # Encode with the test private key. token = jwt.encode(_token_data('aud', 'subject', 'someissuer'), private_key_pem, 'RS256') # Attempt to decode but only with a different algorithm than that used. with pytest.raises(InvalidAlgorithmError) as ite: max_exp = exp_max_s_option(3600) decode(token, public_key, algorithms=['ES256'], audience='aud', issuer='someissuer', options=max_exp, leeway=60) assert ite.match('are not whitelisted')
def decode_bearer_token(bearer_token, instance_keys, config, metric_queue=None): """ decode_bearer_token decodes the given bearer token that contains both a Key ID as well as the encoded JWT and returns the decoded and validated JWT. On any error, raises an InvalidBearerTokenException with the reason for failure. """ # Decode the key ID. try: headers = jwt.get_unverified_header(bearer_token) except jwtutil.InvalidTokenError as ite: logger.exception("Invalid token reason: %s", ite) raise InvalidBearerTokenException(ite) kid = headers.get("kid", None) if kid is None: logger.error("Missing kid header on encoded JWT: %s", bearer_token) raise InvalidBearerTokenException("Missing kid header") # Find the matching public key. public_key = instance_keys.get_service_key_public_key(kid) if public_key is None: if metric_queue is not None: metric_queue.invalid_instance_key_count.Inc(labelvalues=[kid]) logger.error( "Could not find requested service key %s with encoded JWT: %s", kid, bearer_token) raise InvalidBearerTokenException("Unknown service key") # Load the JWT returned. try: expected_issuer = instance_keys.service_name audience = config["SERVER_HOSTNAME"] max_signed_s = config.get("REGISTRY_JWT_AUTH_MAX_FRESH_S", 3660) max_exp = jwtutil.exp_max_s_option(max_signed_s) payload = jwtutil.decode( bearer_token, public_key, algorithms=[ALGORITHM], audience=audience, issuer=expected_issuer, options=max_exp, leeway=JWT_CLOCK_SKEW_SECONDS, ) except jwtutil.InvalidTokenError as ite: logger.exception("Invalid token reason: %s", ite) raise InvalidBearerTokenException(ite) if not "sub" in payload: raise InvalidBearerTokenException("Missing sub field in JWT") return payload
def test_decode_jwt_invalid_key(private_key_pem): # Encode with the test private key. token = jwt.encode(_token_data('aud', 'subject', 'someissuer'), private_key_pem, 'RS256') # Try to decode with a different public key. another_public_key = RSA.generate(2048).publickey().exportKey('PEM') with pytest.raises(InvalidTokenError) as ite: max_exp = exp_max_s_option(3600) decode(token, another_public_key, algorithms=['RS256'], audience='aud', issuer='someissuer', options=max_exp, leeway=60) assert ite.match('Signature verification failed')
def test_jwk_dict_to_public_key(private_key, private_key_pem): public_key = private_key.publickey() jwk = RSAKey(key=private_key.publickey()).serialize() converted = jwk_dict_to_public_key(jwk) # Encode with the test private key. token = jwt.encode(_token_data('aud', 'subject', 'someissuer'), private_key_pem, 'RS256') # Decode with the converted key. max_exp = exp_max_s_option(3600) decode(token, converted, algorithms=['RS256'], audience='aud', issuer='someissuer', options=max_exp, leeway=60)
def test_decode_jwt_invalid_algorithm(private_key_pem, public_key): # Encode with the test private key. token = jwt.encode(_token_data("aud", "subject", "someissuer"), private_key_pem, "RS256") # Attempt to decode but only with a different algorithm than that used. with pytest.raises(InvalidAlgorithmError) as ite: max_exp = exp_max_s_option(3600) decode( token, public_key, algorithms=["ES256"], audience="aud", issuer="someissuer", options=max_exp, leeway=60, ) assert ite.match("are not whitelisted")
def test_jwk_dict_to_public_key(private_key, private_key_pem): public_key = private_key.public_key() key_dict = jwk.dumps( public_key.public_bytes( encoding=serialization.Encoding.PEM, format=serialization.PublicFormat.SubjectPublicKeyInfo, ) ) converted = jwk_dict_to_public_key(key_dict) # Encode with the test private key. token = jwt.encode(_token_data("aud", "subject", "someissuer"), private_key_pem, "RS256") # Decode with the converted key. max_exp = exp_max_s_option(3600) decode( token, converted, algorithms=["RS256"], audience="aud", issuer="someissuer", options=max_exp, leeway=60, )