feat(auth): moved to httponly token

This commit is contained in:
2025-02-17 15:14:28 +01:00
parent 5abbec19c8
commit 0b107c9882
25 changed files with 293 additions and 150 deletions

View File

@ -118,4 +118,5 @@ def backend(redis_server):
"bec_atlas.router.redis_router.BECAsyncRedisManager", PatchedBECAsyncRedisManager
):
with TestClient(app.app) as _client:
app.user_router.use_ssl = False # disable ssl to allow for httponly cookies
yield _client, app

View File

@ -13,7 +13,6 @@ def logged_in_client(backend):
token = response.json()
assert isinstance(token, str)
assert len(token) > 20
client.headers.update({"Authorization": f"Bearer {token}"})
return client

View File

@ -11,7 +11,6 @@ def logged_in_client(backend):
token = response.json()
assert isinstance(token, str)
assert len(token) > 20
client.headers.update({"Authorization": f"Bearer {token}"})
return client
@ -70,7 +69,6 @@ def test_deployment_credential_rejects_unauthorized_user(backend):
token = response.json()
assert isinstance(token, str)
assert len(token) > 20
client.headers.update({"Authorization": f"Bearer {token}"})
deployments = client.get(
"/api/v1/deployments/realm", params={"realm": "demo_beamline_1"}
@ -96,7 +94,6 @@ def test_refresh_deployment_credentials_rejects_unauthorized_user(backend):
token = response.json()
assert isinstance(token, str)
assert len(token) > 20
client.headers.update({"Authorization": f"Bearer {token}"})
deployments = client.get(
"/api/v1/deployments/realm", params={"realm": "demo_beamline_1"}

View File

@ -11,7 +11,6 @@ def logged_in_client(backend):
token = response.json()
assert isinstance(token, str)
assert len(token) > 20
client.headers.update({"Authorization": f"Bearer {token}"})
return client

View File

@ -2,9 +2,10 @@ import json
from unittest import mock
import pytest
from bec_atlas.router.redis_router import RedisAtlasEndpoints
from bec_lib.endpoints import MessageEndpoints
from bec_atlas.router.redis_router import RedisAtlasEndpoints, RemoteAccess
@pytest.fixture
def backend_client(backend):
@ -12,48 +13,75 @@ def backend_client(backend):
app.server = mock.Mock()
app.server.should_exit = False
app.redis_websocket.users = {}
yield client, app
# app.redis_websocket.redis._redis_conn.flushall()
response = client.post(
"/api/v1/user/login", json={"username": "admin@bec_atlas.ch", "password": "admin"}
)
assert response.status_code == 200
token = response.json()
assert isinstance(token, str)
assert len(token) > 20
return client, app
@pytest.fixture
@pytest.mark.asyncio(loop_scope="session")
async def connected_ws(backend_client):
client, app = backend_client
deployment = client.get("/api/v1/deployments/realm", params={"realm": "demo_beamline_1"}).json()
with mock.patch.object(app.redis_websocket, "get_access", return_value=RemoteAccess.READ):
await app.redis_websocket.socket.handlers["/"]["connect"](
"sid",
{
"HTTP_QUERY": json.dumps({"deployment": deployment[0]["_id"]}),
"HTTP_COOKIE": f"access_token={client.cookies.get('access_token')}",
},
)
yield backend_client
@pytest.mark.asyncio(loop_scope="session")
async def test_redis_websocket_connect(backend_client):
client, app = backend_client
await app.redis_websocket.socket.handlers["/"]["connect"](
"sid", {"HTTP_QUERY": '{"user": "test", "deployment": "test"}'}
)
async def test_redis_websocket_connect(connected_ws):
_, app = await anext(connected_ws)
assert "sid" in app.redis_websocket.users
@pytest.mark.asyncio(loop_scope="session")
async def test_redis_websocket_disconnect(backend_client):
client, app = backend_client
app.redis_websocket.users["sid"] = {"user": "test", "subscriptions": []}
async def test_redis_websocket_disconnect(connected_ws):
_, app = await anext(connected_ws)
await app.redis_websocket.socket.handlers["/"]["disconnect"]("sid")
assert "sid" not in app.redis_websocket.users
@pytest.mark.asyncio(loop_scope="session")
async def test_redis_websocket_multiple_connect(backend_client):
client, app = backend_client
async def test_redis_websocket_multiple_connect(connected_ws):
client, app = await anext(connected_ws)
await app.redis_websocket.socket.handlers["/"]["connect"](
"sid1", {"HTTP_QUERY": '{"user": "test", "deployment": "test"}'}
"sid2",
{
"HTTP_QUERY": json.dumps(
{"deployment": app.redis_websocket.users["sid"]["deployment"]}
),
"HTTP_COOKIE": f"access_token={client.cookies.get('access_token')}",
},
)
await app.redis_websocket.socket.handlers["/"]["connect"](
"sid2", {"HTTP_QUERY": '{"user": "test", "deployment": "test"}'}
)
assert "sid1" in app.redis_websocket.users
assert "sid" in app.redis_websocket.users
assert "sid2" in app.redis_websocket.users
@pytest.mark.asyncio(loop_scope="session")
async def test_redis_websocket_multiple_connect_same_sid(backend_client):
client, app = backend_client
async def test_redis_websocket_multiple_connect_same_sid(connected_ws):
client, app = await anext(connected_ws)
await app.redis_websocket.socket.handlers["/"]["connect"](
"sid", {"HTTP_QUERY": '{"user": "test", "deployment": "test"}'}
)
await app.redis_websocket.socket.handlers["/"]["connect"](
"sid", {"HTTP_QUERY": '{"user": "test", "deployment": "test"}'}
"sid",
{
"HTTP_QUERY": json.dumps(
{"deployment": app.redis_websocket.users["sid"]["deployment"]}
),
"HTTP_COOKIE": f"access_token={client.cookies.get('access_token')}",
},
)
assert "sid" in app.redis_websocket.users
@ -61,9 +89,8 @@ async def test_redis_websocket_multiple_connect_same_sid(backend_client):
@pytest.mark.asyncio(loop_scope="session")
async def test_redis_websocket_multiple_disconnect_same_sid(backend_client):
client, app = backend_client
app.redis_websocket.users["sid"] = {"user": "test", "subscriptions": []}
async def test_redis_websocket_multiple_disconnect_same_sid(connected_ws):
client, app = await anext(connected_ws)
await app.redis_websocket.socket.handlers["/"]["disconnect"]("sid")
await app.redis_websocket.socket.handlers["/"]["disconnect"]("sid")
assert "sid" not in app.redis_websocket.users
@ -82,14 +109,10 @@ async def test_redis_websocket_register_wrong_endpoint_raises(backend_client):
@pytest.mark.asyncio(loop_scope="session")
async def test_redis_websocket_register(backend_client):
client, app = backend_client
async def test_redis_websocket_register(connected_ws):
client, app = await anext(connected_ws)
with mock.patch.object(app.redis_websocket.socket, "emit") as emit:
with mock.patch.object(app.redis_websocket.socket, "enter_room") as enter_room:
await app.redis_websocket.socket.handlers["/"]["connect"](
"sid", {"HTTP_QUERY": '{"user": "test", "deployment": "test"}'}
)
await app.redis_websocket.socket.handlers["/"]["register"](
"sid", json.dumps({"endpoint": "scan_status"})
)
@ -97,7 +120,8 @@ async def test_redis_websocket_register(backend_client):
enter_room.assert_called_with(
"sid",
RedisAtlasEndpoints.socketio_endpoint_room(
"test", MessageEndpoints.scan_status().endpoint
app.redis_websocket.users["sid"]["deployment"],
MessageEndpoints.scan_status().endpoint,
),
)

View File

@ -91,7 +91,6 @@ def test_scan_ingestor_create_scan(scan_ingestor, backend):
response = client.post(
"/api/v1/user/login", json={"username": "admin@bec_atlas.ch", "password": "admin"}
)
client.headers.update({"Authorization": f"Bearer {response.json()}"})
session_id = msg.info.get("session_id")
scan_id = msg.scan_id

View File

@ -14,7 +14,6 @@ def logged_in_client(backend):
token = response.json()
assert isinstance(token, str)
assert len(token) > 20
client.headers.update({"Authorization": f"Bearer {token}"})
return client