Skip to content

Commit a6bd5dc

Browse files
author
Rafał Safin
committed
jwt and password core tests added
Signed-off-by: Rafał Safin <rafal.safin@rafsaf.pl>
1 parent 326e1bf commit a6bd5dc

File tree

6 files changed

+106
-3
lines changed

6 files changed

+106
-3
lines changed

app/core/security/jwt.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ def verify_jwt_token(token: str) -> JWTTokenPayload:
5858
get_settings().security.jwt_secret_key.get_secret_value(),
5959
algorithms=[JWT_ALGORITHM],
6060
options={"verify_signature": True},
61+
issuer=get_settings().security.jwt_issuer,
6162
)
6263
except jwt.InvalidTokenError as e:
6364
raise HTTPException(

app/tests/conftest.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,13 @@ async def fixture_setup_new_test_database() -> None:
7070
await conn.run_sync(Base.metadata.create_all)
7171

7272

73+
@pytest_asyncio.fixture(scope="function", autouse=True)
74+
async def fixture_clean_get_settings_between_tests() -> AsyncGenerator[None, None]:
75+
yield
76+
77+
get_settings.cache_clear()
78+
79+
7380
@pytest_asyncio.fixture(name="default_hashed_password", scope="session")
7481
async def fixture_default_hashed_password() -> str:
7582
return get_password_hash(default_user_password)

app/tests/test_auth/test_auth_refresh_token.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -121,11 +121,11 @@ async def test_refresh_token_success_old_token_is_used(
121121
},
122122
)
123123

124-
test_refresh_token = await session.scalar(
124+
used_test_refresh_token = await session.scalar(
125125
select(RefreshToken).where(RefreshToken.refresh_token == "blaxx")
126126
)
127-
assert test_refresh_token is not None
128-
assert test_refresh_token.used
127+
assert used_test_refresh_token is not None
128+
assert used_test_refresh_token.used
129129

130130

131131
async def test_refresh_token_success_jwt_has_valid_token_type(

app/tests/test_core/__init__.py

Whitespace-only changes.

app/tests/test_core/test_jwt.py

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import time
2+
3+
import pytest
4+
from fastapi import HTTPException
5+
from freezegun import freeze_time
6+
from pydantic import SecretStr
7+
8+
from app.core.config import get_settings
9+
from app.core.security import jwt
10+
11+
12+
def test_jwt_access_token_can_be_decoded_back_into_user_id() -> None:
13+
user_id = "test_user_id"
14+
token = jwt.create_jwt_token(user_id)
15+
16+
payload = jwt.verify_jwt_token(token=token.access_token)
17+
assert payload.sub == user_id
18+
19+
20+
@freeze_time("2024-01-01")
21+
def test_jwt_payload_is_correct() -> None:
22+
user_id = "test_user_id"
23+
token = jwt.create_jwt_token(user_id)
24+
25+
assert token.payload.iat == int(time.time())
26+
assert token.payload.sub == user_id
27+
assert token.payload.iss == get_settings().security.jwt_issuer
28+
assert (
29+
token.payload.exp
30+
== int(time.time()) + get_settings().security.jwt_access_token_expire_secs
31+
)
32+
33+
34+
def test_jwt_error_after_exp_time() -> None:
35+
user_id = "test_user_id"
36+
with freeze_time("2024-01-01"):
37+
token = jwt.create_jwt_token(user_id)
38+
with freeze_time("2024-02-01"):
39+
with pytest.raises(HTTPException) as e:
40+
jwt.verify_jwt_token(token=token.access_token)
41+
42+
assert e.value.detail == "Token invalid: Signature has expired"
43+
44+
45+
def test_jwt_error_before_iat_time() -> None:
46+
user_id = "test_user_id"
47+
with freeze_time("2024-01-01"):
48+
token = jwt.create_jwt_token(user_id)
49+
with freeze_time("2023-12-01"):
50+
with pytest.raises(HTTPException) as e:
51+
jwt.verify_jwt_token(token=token.access_token)
52+
53+
assert e.value.detail == "Token invalid: The token is not yet valid (iat)"
54+
55+
56+
def test_jwt_error_with_invalid_token() -> None:
57+
with pytest.raises(HTTPException) as e:
58+
jwt.verify_jwt_token(token="invalid!")
59+
60+
assert e.value.detail == "Token invalid: Not enough segments"
61+
62+
63+
def test_jwt_error_with_invalid_issuer() -> None:
64+
user_id = "test_user_id"
65+
token = jwt.create_jwt_token(user_id)
66+
67+
get_settings().security.jwt_issuer = "another_issuer"
68+
69+
with pytest.raises(HTTPException) as e:
70+
jwt.verify_jwt_token(token=token.access_token)
71+
72+
assert e.value.detail == "Token invalid: Invalid issuer"
73+
74+
75+
def test_jwt_error_with_invalid_secret_key() -> None:
76+
user_id = "test_user_id"
77+
token = jwt.create_jwt_token(user_id)
78+
79+
get_settings().security.jwt_secret_key = SecretStr("the secret has changed now!")
80+
81+
with pytest.raises(HTTPException) as e:
82+
jwt.verify_jwt_token(token=token.access_token)
83+
84+
assert e.value.detail == "Token invalid: Signature verification failed"

app/tests/test_core/test_password.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from app.core.security.password import get_password_hash, verify_password
2+
3+
4+
def test_hashed_password_is_verified() -> None:
5+
pwd_hash = get_password_hash("my_password")
6+
assert verify_password("my_password", pwd_hash)
7+
8+
9+
def test_invalid_password_is_not_verified() -> None:
10+
pwd_hash = get_password_hash("my_password")
11+
assert not verify_password("my_password_invalid", pwd_hash)

0 commit comments

Comments
 (0)