Skip to content

Commit 43250bf

Browse files
committed
FIX: Do not allow new session if one exists
1 parent 9d1bcc7 commit 43250bf

File tree

3 files changed

+50
-6
lines changed

3 files changed

+50
-6
lines changed

src/fmu_settings_api/deps.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,9 @@ async def ensure_user_fmu_directory() -> UserFMUDirectory:
6767
UserFMUDirDep = Annotated[UserFMUDirectory, Depends(ensure_user_fmu_directory)]
6868

6969

70-
async def get_session(fmu_settings_session: str | None = Cookie(None)) -> Session:
70+
async def get_session(
71+
fmu_settings_session: Annotated[str | None, Cookie()] = None,
72+
) -> Session:
7173
"""Gets a session from the session manager."""
7274
if not fmu_settings_session:
7375
raise HTTPException(

src/fmu_settings_api/v1/main.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@
22

33
import contextlib
44
from pathlib import Path
5+
from typing import Annotated
56

6-
from fastapi import APIRouter, Depends, HTTPException, Response
7+
from fastapi import APIRouter, Cookie, Depends, HTTPException, Response
78
from fmu.settings import find_nearest_fmu_directory
89
from fmu.settings.models.user_config import UserConfig
910

@@ -40,16 +41,22 @@ async def v1_health_check() -> dict[str, str]:
4041
dependencies=[Depends(verify_auth_token)],
4142
)
4243
async def create_session(
43-
response: Response, auth_token: AuthTokenDep, user_fmu_dir: UserFMUDirDep
44+
response: Response,
45+
auth_token: AuthTokenDep,
46+
user_fmu_dir: UserFMUDirDep,
47+
fmu_settings_session: Annotated[str | None, Cookie()] = None,
4448
) -> SessionResponse:
4549
"""Establishes a user session."""
50+
if fmu_settings_session:
51+
raise HTTPException(status_code=409, detail="A session already exists")
52+
4653
try:
4754
session_id = await create_fmu_session(user_fmu_dir)
4855
response.set_cookie(
4956
key=settings.SESSION_COOKIE_KEY,
5057
value=session_id,
5158
httponly=True,
52-
secure=True,
59+
secure=False,
5360
samesite="lax",
5461
)
5562
config_dict = user_fmu_dir.config.load().model_dump()

tests/test_v1/test_create_session.py

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,20 @@
1616
from fmu_settings_api.models import FMUProject, SessionResponse
1717
from fmu_settings_api.session import ProjectSession, Session, SessionManager
1818

19-
client = TestClient(app)
20-
2119
ROUTE = "/api/v1/session"
2220

2321

2422
def test_get_session_no_token() -> None:
2523
"""Tests the fmu routes require a session."""
24+
client = TestClient(app)
2625
response = client.post(ROUTE)
2726
assert response.status_code == status.HTTP_403_FORBIDDEN, response.json()
2827
assert response.json() == {"detail": "Not authenticated"}
2928

3029

3130
def test_get_session_invalid_token() -> None:
3231
"""Tests the fmu routes require a session."""
32+
client = TestClient(app)
3333
bad_token = "no" * 32
3434
response = client.post(ROUTE, headers={settings.TOKEN_HEADER_NAME: bad_token})
3535
assert response.status_code == status.HTTP_401_UNAUTHORIZED
@@ -40,6 +40,7 @@ def test_get_session_no_token_does_not_create_user_fmu(
4040
tmp_path_mocked_home: Path,
4141
) -> None:
4242
"""Tests unauthenticated requests do not create a user .fmu."""
43+
client = TestClient(app)
4344
response = client.post(ROUTE)
4445
assert response.status_code == status.HTTP_403_FORBIDDEN
4546
assert response.json() == {"detail": "Not authenticated"}
@@ -50,6 +51,7 @@ def test_get_session_invalid_token_does_not_create_user_fmu(
5051
tmp_path_mocked_home: Path,
5152
) -> None:
5253
"""Tests unauthorized requests do not create a user .fmu."""
54+
client = TestClient(app)
5355
bad_token = "no" * 32
5456
response = client.post(ROUTE, headers={settings.TOKEN_HEADER_NAME: bad_token})
5557
assert response.status_code == status.HTTP_401_UNAUTHORIZED
@@ -61,6 +63,7 @@ def test_get_session_create_user_fmu_no_permissions(
6163
user_fmu_dir_no_permissions: Path, mock_token: str
6264
) -> None:
6365
"""Tests that user .fmu directory permissions errors return a 403."""
66+
client = TestClient(app)
6467
response = client.post(ROUTE, headers={settings.TOKEN_HEADER_NAME: mock_token})
6568
assert response.status_code == status.HTTP_403_FORBIDDEN
6669
assert response.json() == {"detail": "Permission denied creating user .fmu"}
@@ -70,6 +73,7 @@ def test_get_session_creating_user_fmu_exists_as_a_file(
7073
tmp_path_mocked_home: Path, mock_token: str, monkeypatch: MonkeyPatch
7174
) -> None:
7275
"""Tests that a user .fmu as a file raises a 409."""
76+
client = TestClient(app)
7377
(tmp_path_mocked_home / "home/.fmu").touch()
7478
monkeypatch.chdir(tmp_path_mocked_home)
7579
response = client.post(ROUTE, headers={settings.TOKEN_HEADER_NAME: mock_token})
@@ -83,6 +87,7 @@ def test_get_session_creating_user_unknown_failure(
8387
tmp_path_mocked_home: Path, mock_token: str, monkeypatch: MonkeyPatch
8488
) -> None:
8589
"""Tests that an unknown exception returns 500."""
90+
client = TestClient(app)
8691
with patch(
8792
"fmu_settings_api.deps.init_user_fmu_directory",
8893
side_effect=Exception("foo"),
@@ -102,6 +107,7 @@ def test_get_session_creates_user_fmu(
102107
session_manager: SessionManager,
103108
) -> None:
104109
"""Tests that user .fmu is created when a session is created."""
110+
client = TestClient(app)
105111
user_home = tmp_path_mocked_home / "home"
106112
with pytest.raises(
107113
FileNotFoundError, match=f"No .fmu directory found at {user_home}"
@@ -125,6 +131,7 @@ async def test_get_session_creates_session(
125131
session_manager: SessionManager,
126132
) -> None:
127133
"""Tests that user .fmu is created when a session is created."""
134+
client = TestClient(app)
128135
user_home = tmp_path_mocked_home / "home"
129136
response = client.post(ROUTE, headers={settings.TOKEN_HEADER_NAME: mock_token})
130137
assert response.status_code == status.HTTP_200_OK, response.json()
@@ -147,6 +154,7 @@ async def test_get_session_finds_existing_user_fmu(
147154
session_manager: SessionManager,
148155
) -> None:
149156
"""Tests that an existing user .fmu directory is located with a session."""
157+
client = TestClient(app)
150158
user_fmu_dir = init_user_fmu_directory()
151159

152160
response = client.post(ROUTE, headers={settings.TOKEN_HEADER_NAME: mock_token})
@@ -169,6 +177,7 @@ async def test_get_session_from_project_path_returns_fmu_project(
169177
session_manager: SessionManager,
170178
) -> None:
171179
"""Tests that user .fmu is created when a session is created."""
180+
client = TestClient(app)
172181
user_fmu_dir = init_user_fmu_directory()
173182
project_fmu_dir = init_fmu_directory(tmp_path_mocked_home)
174183
ert_model_path = tmp_path_mocked_home / "project/24.0.3/ert/model"
@@ -204,3 +213,29 @@ async def test_get_session_from_project_path_returns_fmu_project(
204213

205214
assert session.project_fmu_directory.path == project_fmu_dir.path
206215
assert session.project_fmu_directory.config.load() == project_fmu_dir.config.load()
216+
217+
218+
async def test_getting_two_sessions_returns_error(
219+
tmp_path_mocked_home: Path,
220+
mock_token: str,
221+
session_manager: SessionManager,
222+
) -> None:
223+
"""Tests that user .fmu is created when a session is created."""
224+
client = TestClient(app)
225+
user_home = tmp_path_mocked_home / "home"
226+
response = client.post(ROUTE, headers={settings.TOKEN_HEADER_NAME: mock_token})
227+
assert response.status_code == status.HTTP_200_OK, response.json()
228+
229+
user_fmu_dir = UserFMUDirectory()
230+
assert user_fmu_dir.path == user_home / ".fmu"
231+
232+
session_id = response.cookies.get(settings.SESSION_COOKIE_KEY)
233+
assert session_id is not None
234+
session = await session_manager.get_session(session_id)
235+
assert session is not None
236+
assert isinstance(session, Session)
237+
assert session.user_fmu_directory.path == user_fmu_dir.path
238+
239+
response = client.post(ROUTE, headers={settings.TOKEN_HEADER_NAME: mock_token})
240+
assert response.status_code == status.HTTP_409_CONFLICT, response.json()
241+
assert response.json()["detail"] == "A session already exists"

0 commit comments

Comments
 (0)