async def test_jwt_optional(app, delta_func): url = "/optional_protected" test_client = app.test_client() async with app.test_request_context("/protected"): access_token = create_access_token("username") fresh_access_token = create_access_token("username", fresh=True) refresh_token = create_refresh_token("username") expired_token = create_access_token( identity="username", expires_delta=delta_func(minutes=-1)) response = await test_client.get(url, headers=make_headers(fresh_access_token)) assert response.status_code == 200 assert await response.get_json() == {"foo": "baz"} response = await test_client.get(url, headers=make_headers(access_token)) assert response.status_code == 200 assert await response.get_json() == {"foo": "baz"} response = await test_client.get(url, headers=make_headers(refresh_token)) assert response.status_code == 422 assert await response.get_json() == { "msg": "Only access tokens are allowed" } response = await test_client.get(url, headers=None) assert response.status_code == 200 assert await response.get_json() == {"foo": "bar"} response = await test_client.get(url, headers=make_headers(expired_token)) assert response.status_code == 401 assert await response.get_json() == {"msg": "Token has expired"}
async def test_custom_encode_decode_key_callbacks(app, default_access_token): jwtM = get_jwt_manager(app) app.config["JWT_SECRET_KEY"] = "foobarbaz" @jwtM.encode_key_loader def get_encode_key_1(identity): assert identity == "username" return "different secret" with pytest.raises(InvalidSignatureError): async with app.test_request_context("/protected"): token = create_access_token("username") decode_token(token) with pytest.raises(InvalidSignatureError): async with app.test_request_context("/protected"): token = create_refresh_token("username") decode_token(token) @jwtM.decode_key_loader def get_decode_key_1(claims, headers): assert claims["identity"] == "username" return "different secret" async with app.test_request_context("/protected"): token = create_access_token("username") decode_token(token) token = create_refresh_token("username") decode_token(token)
async def test_jwt_required(app): url = "/protected" test_client = app.test_client() async with app.test_request_context("/protected"): access_token = create_access_token("username") fresh_access_token = create_access_token("username", fresh=True) refresh_token = create_refresh_token("username") # Access and fresh access should be able to access this for token in (access_token, fresh_access_token): response = await test_client.get(url, headers=make_headers(token)) assert response.status_code == 200 assert await response.get_json() == {"foo": "bar"} # Test accessing jwt_required with no jwt in the request response = await test_client.get(url, headers=None) assert response.status_code == 401 assert await response.get_json() == {"msg": "Missing Authorization Header"} # Test refresh token access to jwt_required response = await test_client.get(url, headers=make_headers(refresh_token)) assert response.status_code == 422 assert await response.get_json() == { "msg": "Only access tokens are allowed" }
async def test_refresh_jwt_required(app): url = "/refresh_protected" test_client = app.test_client() async with app.test_request_context("/protected"): access_token = create_access_token("username") fresh_access_token = create_access_token("username", fresh=True) refresh_token = create_refresh_token("username") response = await test_client.get(url, headers=make_headers(fresh_access_token)) assert response.status_code == 422 assert await response.get_json() == { "msg": "Only refresh tokens are allowed" } response = await test_client.get(url, headers=make_headers(access_token)) assert response.status_code == 422 assert await response.get_json() == { "msg": "Only refresh tokens are allowed" } response = await test_client.get(url, headers=None) assert response.status_code == 401 assert await response.get_json() == {"msg": "Missing Authorization Header"} response = await test_client.get(url, headers=make_headers(refresh_token)) assert response.status_code == 200 assert await response.get_json() == {"foo": "bar"}
async def test_nbf_token_in_future(app, patch_datetime_now): with pytest.raises(ImmatureSignatureError): async with app.test_request_context("/protected"): access_token = create_access_token("username") decode_token(access_token) async with app.test_request_context("/protected"): app.config["JWT_DECODE_LEEWAY"] = 30 access_token = create_access_token("username") decode_token(access_token)
async def test_non_serializable_user_claims(app): jwt = get_jwt_manager(app) @jwt.additional_headers_loader def add_jwt_headers(identity): return app with pytest.raises(TypeError): async with app.test_request_context("/protected"): create_access_token("username")
async def test_fresh_jwt_required(app): jwtM = get_jwt_manager(app) url = "/fresh_protected" test_client = app.test_client() async with app.test_request_context("/protected"): access_token = create_access_token("username") fresh_access_token = create_access_token("username", fresh=True) refresh_token = create_refresh_token("username") fresh_timed_access_token = create_access_token( identity="username", fresh=timedelta(minutes=5)) stale_timed_access_token = create_access_token( identity="username", fresh=timedelta(minutes=-1)) response = await test_client.get(url, headers=make_headers(fresh_access_token)) assert response.status_code == 200 assert await response.get_json() == {"foo": "bar"} response = await test_client.get(url, headers=make_headers(access_token)) assert response.status_code == 401 assert await response.get_json() == {"msg": "Fresh token required"} response = await test_client.get( url, headers=make_headers(fresh_timed_access_token)) assert response.status_code == 200 assert await response.get_json() == {"foo": "bar"} response = await test_client.get( url, headers=make_headers(stale_timed_access_token)) assert response.status_code == 401 assert await response.get_json() == {"msg": "Fresh token required"} response = await test_client.get(url, headers=None) assert response.status_code == 401 assert await response.get_json() == {"msg": "Missing Authorization Header"} response = await test_client.get(url, headers=make_headers(refresh_token)) assert response.status_code == 422 assert await response.get_json() == { "msg": "Only access tokens are allowed" } # Test with custom response @jwtM.needs_fresh_token_loader def custom_response(): return jsonify(msg="foobar"), 201 response = await test_client.get(url, headers=make_headers(access_token)) assert response.status_code == 201 assert await response.get_json() == {"msg": "foobar"}
async def test_encode_iss(app, default_access_token): app.config["JWT_ENCODE_ISSUER"] = "foobar" async with app.test_request_context("/protected"): access_token = create_access_token("username") decoded = decode_token(access_token) assert decoded["iss"] == "foobar"
async def test_jwt_headers(app): jwt_header = {"foo": "bar"} async with app.test_request_context("/protected"): access_token = create_access_token("username", headers=jwt_header) refresh_token = create_refresh_token("username", headers=jwt_header) assert get_unverified_jwt_headers(access_token)["foo"] == "bar" assert get_unverified_jwt_headers(refresh_token)["foo"] == "bar"
async def test_custom_header_name(app): app.config["JWT_HEADER_NAME"] = "Foo" test_client = app.test_client() async with app.test_request_context("/protected"): access_token = create_access_token("username") # Insure 'default' headers no longer work access_headers = {"Authorization": "Bearer {}".format(access_token)} response = await test_client.get("/protected", headers=access_headers) assert response.status_code == 401 assert await response.get_json() == {"msg": "Missing Foo Header"} # Insure new headers do work access_headers = {"Foo": "Bearer {}".format(access_token)} response = await test_client.get("/protected", headers=access_headers) assert response.status_code == 200 assert await response.get_json() == {"foo": "bar"} # Ensure new headers work with multiple field values access_headers = { "Foo": "Bearer {}, Basic randomcredshere".format(access_token) } response = await test_client.get("/protected", headers=access_headers) assert response.status_code == 200 assert await response.get_json() == {"foo": "bar"} # Ensure new headers work with multiple field values in any position access_headers = { "Foo": "Basic randomcredshere, Bearer {}".format(access_token) } response = await test_client.get("/protected", headers=access_headers) assert response.status_code == 200 assert await response.get_json() == {"foo": "bar"}
async def test_missing_query_paramater(app): test_client = app.test_client() jwtM = get_jwt_manager(app) async with app.test_request_context("/protected"): access_token = create_access_token("username") # Insure no query paramaters doesn't give a response response = await test_client.get("/protected") assert response.status_code == 401 assert await response.get_json() == { "msg": 'Missing "jwt" query paramater' } # Insure headers don't work access_headers = {"Authorization": "Bearer {}".format(access_token)} response = await test_client.get("/protected", headers=access_headers) assert response.status_code == 401 assert await response.get_json() == { "msg": 'Missing "jwt" query paramater' } # Test custom response works @jwtM.unauthorized_loader def custom_response(err_str): return jsonify(foo="bar"), 201 response = await test_client.get("/protected") assert response.status_code == 201 assert await response.get_json() == {"foo": "bar"}
async def test_token_from_complex_object(app): class TestObject: def __init__(self, username): self.username = username jwt = get_jwt_manager(app) @jwt.user_claims_loader def add_claims(test_obj): return {"username": test_obj.username} @jwt.user_identity_loader def add_claims(test_obj): return test_obj.username async with app.test_request_context("/protected"): access_token = create_access_token(TestObject("username")) # Make sure the changes appear in the token decoded_token = decode_token(access_token) assert decoded_token["identity"] == "username" assert decoded_token["user_claims"] == {"username": "******"} test_client = app.test_client() response = await test_client.get("/protected", headers=make_headers(access_token)) assert await response.get_json() == {"username": "******"} assert response.status_code == 200
async def post(cls): get_user_details = await request.get_json() try: user = login_schema.load(get_user_details) except ValidationError as err: return err.messages, 400 get_user_from_db = await UserModel.find_user_by_email( get_user_details['email']) if get_user_from_db and psw.check_password_hash( get_user_from_db.password, user['password']): confirmation = get_user_from_db.recent_confirmation if confirmation and confirmation.confirmed: access_token = create_access_token( identity=get_user_from_db.email, fresh=True) refresh_token = create_refresh_token(get_user_from_db.email) return { "Access_Token": access_token, "Refresh_Token": refresh_token }, 200 return { "message": NOT_ACTIVATED.format(get_user_from_db.email) }, 400 return {"message": INCORRECT_EMAIL_OR_PASSWORD}, 400
async def test_never_expire_token(app): async with app.test_request_context("/protected"): access_token = create_access_token("username", expires_delta=False) refresh_token = create_refresh_token("username", expires_delta=False) for token in (access_token, refresh_token): decoded = decode_token(token) assert "exp" not in decoded
async def test_custom_body_key(app): app.config["JWT_JSON_KEY"] = "Foo" app.config["JWT_REFRESH_JSON_KEY"] = "Bar" test_client = app.test_client() async with app.test_request_context("/protected"): access_token = create_access_token("username") refresh_token = create_refresh_token("username") # Ensure 'default' keys no longer work data = {"access_token": access_token} response = await test_client.post("/protected", json=data) assert response.status_code == 401 assert await response.get_json() == { "msg": 'Missing "Foo" key in json data.' } data = {"refresh_token": refresh_token} response = await test_client.post("/refresh", json=data) assert response.status_code == 401 assert await response.get_json() == { "msg": 'Missing "Bar" key in json data.' } # Ensure new keys do work data = {"Foo": access_token} response = await test_client.post("/protected", json=data) assert response.status_code == 200 assert await response.get_json() == {"foo": "bar"} data = {"Bar": refresh_token} response = await test_client.post("/refresh", json=data) assert response.status_code == 200 assert await response.get_json() == {"foo": "bar"}
async def login(): username = (await request.get_json()).get("username", None) password = (await request.get_json()).get("password", None) if username != "test" or password != "test": return {"msg": "Bad username or password"}, 401 access_token = create_access_token(identity=username) return dict(access_token=access_token)
async def refresh(): # Do the same thing that we did in the login endpoint here current_user = get_jwt_identity() access_token = create_access_token(identity=current_user) access_jti = get_jti(encoded_token=access_token) revoked_store.set(access_jti, "false", ACCESS_EXPIRES * 1.2) ret = {"access_token": access_token} return ret, 201
async def login(): username = (await request.get_json()).get("username", None) password = (await request.get_json()).get("password", None) if username != "test" or password != "test": return {"msg": "Bad username or password"}, 401 ret = {"access_token": create_access_token(username)} return ret, 200
async def test_mismatch_iss(app, default_access_token): app.config["JWT_ENCODE_ISSUER"] = "foobar" app.config["JWT_DECODE_ISSUER"] = "baz" with pytest.raises(InvalidIssuerError): async with app.test_request_context("/protected"): invalid_token = create_access_token("username") decode_token(invalid_token)
async def test_jwt_header_in_access_token_specified_at_creation(app): async with app.test_request_context("/protected"): access_token = create_access_token("username", headers={"foo": "bar"}) test_client = app.test_client() response = await test_client.get("/protected", headers=make_headers(access_token)) assert (await response.get_json()).get("foo") == "bar" assert response.status_code == 200
async def test_query_string_access(app): test_client = app.test_client() async with app.test_request_context("/protected"): access_token = create_access_token("username") url = "/protected?jwt={}".format(access_token) response = await test_client.get(url) assert response.status_code == 200 assert await response.get_json() == {"foo": "bar"}
async def test_header_access(app): test_client = app.test_client() async with app.test_request_context("/protected"): access_token = create_access_token("username") access_headers = {"Authorization": "Bearer {}".format(access_token)} response = await test_client.get("/protected", headers=access_headers) assert response.status_code == 200 assert await response.get_json() == {"foo": "bar"}
async def refresh(): # Create the new access token current_user = get_jwt_identity() access_token = create_access_token(identity=current_user) # Set the JWT access cookie in the response resp = {"refresh": True} set_access_cookies(resp, access_token) return resp, 200
async def fresh_login(): username = (await request.get_json()).get("username", None) password = (await request.get_json()).get("password", None) if username != "test" or password != "test": return {"msg": "Bad username or password"}, 401 new_token = create_access_token(identity=username, fresh=True) ret = {"access_token": new_token} return ret, 200
async def test_expired_token(app, delta_func): async with app.test_request_context("/protected"): delta = delta_func(minutes=-5) access_token = create_access_token("username", expires_delta=delta) refresh_token = create_refresh_token("username", expires_delta=delta) with pytest.raises(ExpiredSignatureError): decode_token(access_token) with pytest.raises(ExpiredSignatureError): decode_token(refresh_token)
async def test_allow_expired_token(app, delta_func): async with app.test_request_context("/protected"): delta = delta_func(minutes=-5) access_token = create_access_token("username", expires_delta=delta) refresh_token = create_refresh_token("username", expires_delta=delta) for token in (access_token, refresh_token): decoded = decode_token(token, allow_expired=True) assert decoded["identity"] == "username" assert "exp" in decoded
async def test_json_access(app): test_client = app.test_client() async with app.test_request_context("/protected"): access_token = create_access_token("username") data = {"access_token": access_token} response = await test_client.post("/protected", json=data) assert response.status_code == 200 assert await response.get_json() == {"foo": "bar"}
async def test_no_blacklist_callback_method_provided(app): app.config["JWT_BLACKLIST_TOKEN_CHECKS"] = ["access"] async with app.test_request_context("/protected"): access_token = create_access_token("username") test_client = app.test_client() response = await test_client.get("/protected", headers=make_headers(access_token)) assert response.status_code == 500
async def refresh(): # Create the new access token current_user = get_jwt_identity() access_token = create_access_token(identity=current_user) # Set the access JWT and CSRF double submit protection cookies # in this response resp = {"refresh": True} set_access_cookies(resp, access_token) return resp, 200
async def test_asymmetric_cropto(app): test_client = app.test_client() async with app.test_request_context("/protected"): hs256_token = create_access_token("username") app.config["JWT_ALGORITHM"] = "RS256" rs256_token = create_access_token("username") # Insure the symmetric token does not work now access_headers = {"Authorization": "Bearer {}".format(hs256_token)} response = await test_client.get("/protected", headers=access_headers) assert response.status_code == 422 assert await response.get_json() == { "msg": "The specified alg value is not allowed" } # Insure the asymmetric token does work access_headers = {"Authorization": "Bearer {}".format(rs256_token)} response = await test_client.get("/protected", headers=access_headers) assert response.status_code == 200 assert await response.get_json() == {"foo": "bar"}