def test_jwt_invalid_audience(app): url = '/protected' jwtM = get_jwt_manager(app) test_client = app.test_client() # No audience claim expected or provided - OK access_token = encode_token(app, {'identity': 'me'}) response = test_client.get(url, headers=make_headers(access_token)) assert response.status_code == 200 # Audience claim expected and not provided - not OK app.config['JWT_DECODE_AUDIENCE'] = 'my_audience' access_token = encode_token(app, {'identity': 'me'}) response = test_client.get(url, headers=make_headers(access_token)) assert response.status_code == 422 assert response.get_json() == {'msg': 'Token is missing the "aud" claim'} # Audience claim still expected and wrong one provided - not OK access_token = encode_token(app, { 'aud': 'different_audience', 'identity': 'me' }) response = test_client.get(url, headers=make_headers(access_token)) assert response.status_code == 422 assert response.get_json() == {'msg': 'Invalid audience'}
def test_valid_aud(app, default_access_token): app.config['JWT_DECODE_AUDIENCE'] = 'foo' default_access_token['aud'] = 'bar' invalid_token = encode_token(app, default_access_token) with pytest.raises(InvalidAudienceError): with app.test_request_context(): decode_token(invalid_token) default_access_token['aud'] = 'foo' valid_token = encode_token(app, default_access_token) with app.test_request_context(): decoded = decode_token(valid_token) assert decoded['aud'] == 'foo'
def test_supports_decoding_other_token_types(app, default_access_token): default_access_token["type"] = "app" other_token = encode_token(app, default_access_token) with app.test_request_context(): decoded = decode_token(other_token) assert decoded["type"] == "app"
def test_missing_jti_claim(app, default_access_token, missing_claim): del default_access_token[missing_claim] missing_jwt_token = encode_token(app, default_access_token) with pytest.raises(JWTDecodeError): with app.test_request_context(): decode_token(missing_jwt_token)
def test_missing_claims(app, default_access_token, missing_claims): del default_access_token[missing_claims] missing_jwt_token = encode_token(app, default_access_token) with pytest.raises(JWTDecodeError): with app.test_request_context(): decode_token(missing_jwt_token, csrf_value="abcd")
def test_bad_token_type(app, default_access_token): default_access_token['type'] = 'banana' bad_type_token = encode_token(app, default_access_token) with pytest.raises(JWTDecodeError): with app.test_request_context(): decode_token(bad_type_token)
def test_alternate_identity_claim(app, default_access_token): app.config["JWT_IDENTITY_CLAIM"] = "banana" # Insure decoding fails if the claim isn't there token = encode_token(app, default_access_token) with pytest.raises(JWTDecodeError): with app.test_request_context(): decode_token(token) # Insure the claim exists in the decoded jwt del default_access_token["sub"] default_access_token["banana"] = "username" token = encode_token(app, default_access_token) with app.test_request_context(): decoded = decode_token(token) assert "banana" in decoded assert "sub" not in decoded
def test_alternate_identity_claim(app, default_access_token): app.config['JWT_IDENTITY_CLAIM'] = 'sub' # Insure decoding fails if the claim isn't there token = encode_token(app, default_access_token) with pytest.raises(JWTDecodeError): with app.test_request_context(): decode_token(token) # Insure the claim exists in the decoded jwt del default_access_token['identity'] default_access_token['sub'] = 'username' token = encode_token(app, default_access_token) with app.test_request_context(): decoded = decode_token(token) assert 'sub' in decoded assert 'identity' not in decoded
def test_jwt_missing_claims(app): url = '/protected' test_client = app.test_client() token = encode_token(app, {'foo': 'bar'}) response = test_client.get(url, headers=make_headers(token)) assert response.status_code == 422 assert response.get_json() == {'msg': 'Missing claim: identity'}
def test_valid_decode_iss(app, default_access_token): app.config["JWT_DECODE_ISSUER"] = "foobar" default_access_token["iss"] = "foobar" valid_token = encode_token(app, default_access_token) with app.test_request_context(): decoded = decode_token(valid_token) assert decoded["iss"] == "foobar"
def test_invalid_decode_iss(app, default_access_token): app.config["JWT_DECODE_ISSUER"] = "baz" default_access_token["iss"] = "foobar" invalid_token = encode_token(app, default_access_token) with pytest.raises(InvalidIssuerError): with app.test_request_context(): decode_token(invalid_token)
def test_jwt_missing_claims(app): url = "/protected" test_client = app.test_client() token = encode_token(app, {"foo": "bar"}) response = test_client.get(url, headers=make_headers(token)) assert response.status_code == 422 assert response.get_json() == {"msg": "Missing claim: sub"}
def test_valid_decode_iss(app, default_access_token): app.config['JWT_DECODE_ISSUER'] = 'foobar' default_access_token['iss'] = 'foobar' valid_token = encode_token(app, default_access_token) with app.test_request_context(): decoded = decode_token(valid_token) assert decoded['iss'] == 'foobar'
def test_valid_aud(app, default_access_token, token_aud): app.config['JWT_DECODE_AUDIENCE'] = ['foo', 'bar'] default_access_token['aud'] = token_aud valid_token = encode_token(app, default_access_token) with app.test_request_context(): decoded = decode_token(valid_token) assert decoded['aud'] == token_aud
def test_invalid_aud(app, default_access_token, token_aud): app.config["JWT_DECODE_AUDIENCE"] = "foo" default_access_token["aud"] = token_aud invalid_token = encode_token(app, default_access_token) with pytest.raises(InvalidAudienceError): with app.test_request_context(): decode_token(invalid_token)
def test_invalid_iss(app, default_access_token): app.config['JWT_DECODE_ISSUER'] = 'baz' default_access_token['iss'] = 'foobar' invalid_token = encode_token(app, default_access_token) with pytest.raises(InvalidIssuerError): with app.test_request_context(): decode_token(invalid_token)
def test_verify_no_aud(app, default_access_token, token_aud): app.config["JWT_DECODE_AUDIENCE"] = None default_access_token["aud"] = token_aud valid_token = encode_token(app, default_access_token) with app.test_request_context(): decoded = decode_token(valid_token) assert decoded["aud"] == token_aud
def test_jwt_missing_claims(app): url = '/protected' test_client = app.test_client() token = encode_token(app, {'foo': 'bar'}) response = test_client.get(url, headers=make_headers(token)) json_data = json.loads(response.get_data(as_text=True)) assert response.status_code == 422 assert json_data == {'msg': 'Missing claim: jti'}
def test_default_decode_token_values(app, default_access_token): del default_access_token["type"] del default_access_token["jti"] del default_access_token["fresh"] token = encode_token(app, default_access_token) with app.test_request_context(): decoded = decode_token(token) assert decoded["type"] == "access" assert decoded["jti"] is None assert decoded["fresh"] is False
def test_default_decode_token_values(app, default_access_token): del default_access_token['type'] del default_access_token['jti'] del default_access_token['fresh'] token = encode_token(app, default_access_token) with app.test_request_context(): decoded = decode_token(token) assert decoded['type'] == 'access' assert decoded['jti'] is None assert decoded['fresh'] is False
def test_jwt_invalid_issuer(app): url = "/protected" test_client = app.test_client() # No issuer claim expected or provided - OK access_token = encode_token(app, {"sub": "me"}) response = test_client.get(url, headers=make_headers(access_token)) assert response.status_code == 200 # Issuer claim expected and not provided - not OK app.config["JWT_DECODE_ISSUER"] = "my_issuer" access_token = encode_token(app, {"sub": "me"}) response = test_client.get(url, headers=make_headers(access_token)) assert response.status_code == 422 assert response.get_json() == {"msg": 'Token is missing the "iss" claim'} # Issuer claim still expected and wrong one provided - not OK access_token = encode_token(app, {"iss": "different_issuer", "sub": "me"}) response = test_client.get(url, headers=make_headers(access_token)) assert response.status_code == 422 assert response.get_json() == {"msg": "Invalid issuer"}
def test_decode_key_callback(app, default_access_token): jwtM = get_jwt_manager(app) app.config['JWT_SECRET_KEY'] = 'correct secret' @jwtM.decode_key_loader def get_decode_key_1(claims): return 'different secret' assert jwtM._decode_key_callback({}) == 'different secret' with pytest.raises(InvalidSignatureError): with app.test_request_context(): token = encode_token(app, default_access_token) decode_token(token) @jwtM.decode_key_loader def get_decode_key_2(claims): return 'correct secret' with app.test_request_context(): token = encode_token(app, default_access_token) decode_token(token)
def test_jwt_invalid_issuer(app): url = '/protected' test_client = app.test_client() # No issuer claim expected or provided - OK access_token = encode_token(app, {'identity': 'me'}) response = test_client.get(url, headers=make_headers(access_token)) assert response.status_code == 200 # Issuer claim expected and not provided - not OK app.config['JWT_DECODE_ISSUER'] = 'my_issuer' access_token = encode_token(app, {'identity': 'me'}) response = test_client.get(url, headers=make_headers(access_token)) assert response.status_code == 422 assert response.get_json() == {'msg': 'Token is missing the "iss" claim'} # Issuer claim still expected and wrong one provided - not OK access_token = encode_token(app, { 'iss': 'different_issuer', 'identity': 'me' }) response = test_client.get(url, headers=make_headers(access_token)) assert response.status_code == 422 assert response.get_json() == {'msg': 'Invalid issuer'}
def test_jwt_invalid_audience(app): url = "/protected" test_client = app.test_client() # No audience claim expected or provided - OK access_token = encode_token(app, {"sub": "me"}) response = test_client.get(url, headers=make_headers(access_token)) assert response.status_code == 200 # Audience claim expected and not provided - not OK app.config["JWT_DECODE_AUDIENCE"] = "my_audience" access_token = encode_token(app, {"sub": "me"}) response = test_client.get(url, headers=make_headers(access_token)) assert response.status_code == 422 assert response.get_json() == {"msg": 'Token is missing the "aud" claim'} # Audience claim still expected and wrong one provided - not OK access_token = encode_token(app, { "aud": "different_audience", "sub": "me" }) response = test_client.get(url, headers=make_headers(access_token)) assert response.status_code == 422 assert response.get_json() == {"msg": "Invalid audience"}
def test_legacy_decode_key_callback(app, default_access_token): jwtM = get_jwt_manager(app) app.config['JWT_SECRET_KEY'] = 'foobarbaz' # test decode key callback with one argument (backwards compatibility) with warnings.catch_warnings(record=True) as w: warnings.simplefilter("always") @jwtM.decode_key_loader def get_decode_key_legacy(claims): return 'foobarbaz' with app.test_request_context(): token = encode_token(app, default_access_token) decode_token(token) assert len(w) == 1 assert issubclass(w[-1].category, DeprecationWarning)
def test_loading_user_does_not_parse_standard_claims(self, jwt_partial_payload): current_ts = int(time.time()) standard_claims = { **jwt_partial_payload, "sub": str(uuid4()), "token_use": "id", "auth_time": current_ts, } id_token = encode_token( { "cognito:username": str(uuid4()), "custom:id": str(uuid4()), **standard_claims, } ) user = User(id_token) for key in standard_claims: assert not hasattr(user, key)
def setup_class(self): # pylint: disable=attribute-defined-outside-init self.cognito_user = { "cognito:username": str(uuid4()), "email": f"{str(uuid4())}@{str(uuid4())}.com", "custom:id": str(uuid4()), "custom:1": str(uuid4()), "custom:2": str(uuid4()), "aud": os.environ["ALLOWED_AUDIENCES"].split(",")[ 0 ], # moved due pylint and minimising scope of PR "iss": ALLOWED_ISS, "exp": int((datetime.utcnow() + timedelta(hours=6)).timestamp()), "iat": int(datetime.utcnow().timestamp()), "custom:3": str(uuid4()), "custom:4": str(uuid4()), "custom:5": str(uuid4()), } self.id_token = encode_token(self.cognito_user) self.pool_id = str(uuid4) self.sample_user = User(self.id_token)
def user_token(user_cognito) -> str: # pylint: disable=redefined-outer-name return encode_token(user_cognito)
def test_nth_cognito_client_validated_as_audience(self): test_allowed_audiences = [str(uuid4()) for _ in range(10)] with patch("lbz.jwt_utils.ALLOWED_AUDIENCES", test_allowed_audiences): assert User(encode_token({**self.cognito_user, "aud": test_allowed_audiences[9]}))
def test_get_jti(app, default_access_token): token = encode_token(app, default_access_token) with app.test_request_context(): assert default_access_token["jti"] == get_jti(token)