From f86f47c3cb361fbe113eb6b16f3930e8dd57f9fa Mon Sep 17 00:00:00 2001 From: Olivier Le Thanh Duong Date: Fri, 7 Jun 2024 13:50:03 +0200 Subject: [PATCH 1/2] Problem: Crash when trying to auth via websocket The auth function in websocket was crashing when the header "X-Auth-Signature" wasn't passed, even that authentification method wasn't used. Make it an option in the method so we can still have error raised in normal header auth --- src/aleph/vm/orchestrator/views/__init__.py | 4 ++-- src/aleph/vm/orchestrator/views/operator.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/aleph/vm/orchestrator/views/__init__.py b/src/aleph/vm/orchestrator/views/__init__.py index 8b7702ba4..c5dee4f86 100644 --- a/src/aleph/vm/orchestrator/views/__init__.py +++ b/src/aleph/vm/orchestrator/views/__init__.py @@ -337,11 +337,11 @@ async def status_public_config(request: web.Request): ) -def authenticate_api_request(request: web.Request) -> bool: +def authenticate_api_request(request: web.Request, raises_on_missing_header=True) -> bool: """Authenticate an API request to update the VM allocations.""" signature: bytes = request.headers.get("X-Auth-Signature", "").encode() - if not signature: + if not signature and raises_on_missing_header: raise web.HTTPUnauthorized(text="Authentication token is missing") # Use a simple authentication method: the hash of the signature should match the value in the settings diff --git a/src/aleph/vm/orchestrator/views/operator.py b/src/aleph/vm/orchestrator/views/operator.py index 298486b73..a377d212b 100644 --- a/src/aleph/vm/orchestrator/views/operator.py +++ b/src/aleph/vm/orchestrator/views/operator.py @@ -90,8 +90,8 @@ async def stream_logs(request: web.Request) -> web.StreamResponse: async def authenticate_for_vm_or_403(execution, request, vm_hash, ws): """Allow authentication via HEADER or via websocket""" - if authenticate_api_request(request): - logger.debug(f"Accepted request to access logs via the allocatioan api key on {vm_hash}") + if authenticate_api_request(request, raises_on_missing_header=False): + logger.debug(f"Accepted request to access logs via the allocation api key on {vm_hash}") return True first_message = await ws.receive_json() From ec33d1361a75945d185f42657ee4507073673757 Mon Sep 17 00:00:00 2001 From: Hugo Herter Date: Wed, 12 Jun 2024 18:50:59 +0200 Subject: [PATCH 2/2] Fix: Endpoint authenticate_api_request is not adequate for Websocket connections (#632) Fix: Endpoint `authenticate_api_request` is not adequate for Websocket connections This caused issues when header "X-Auth-Signature" was not passed. --- src/aleph/vm/orchestrator/views/__init__.py | 4 ++-- src/aleph/vm/orchestrator/views/operator.py | 13 ++++++------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/aleph/vm/orchestrator/views/__init__.py b/src/aleph/vm/orchestrator/views/__init__.py index c5dee4f86..8b7702ba4 100644 --- a/src/aleph/vm/orchestrator/views/__init__.py +++ b/src/aleph/vm/orchestrator/views/__init__.py @@ -337,11 +337,11 @@ async def status_public_config(request: web.Request): ) -def authenticate_api_request(request: web.Request, raises_on_missing_header=True) -> bool: +def authenticate_api_request(request: web.Request) -> bool: """Authenticate an API request to update the VM allocations.""" signature: bytes = request.headers.get("X-Auth-Signature", "").encode() - if not signature and raises_on_missing_header: + if not signature: raise web.HTTPUnauthorized(text="Authentication token is missing") # Use a simple authentication method: the hash of the signature should match the value in the settings diff --git a/src/aleph/vm/orchestrator/views/operator.py b/src/aleph/vm/orchestrator/views/operator.py index a377d212b..df90d84c2 100644 --- a/src/aleph/vm/orchestrator/views/operator.py +++ b/src/aleph/vm/orchestrator/views/operator.py @@ -10,7 +10,6 @@ from aleph.vm.models import VmExecution from aleph.vm.orchestrator.run import create_vm_execution -from aleph.vm.orchestrator.views import authenticate_api_request from aleph.vm.orchestrator.views.authentication import ( authenticate_websocket_message, require_jwk_authentication, @@ -68,7 +67,7 @@ async def stream_logs(request: web.Request) -> web.StreamResponse: ws = web.WebSocketResponse() await ws.prepare(request) try: - await authenticate_for_vm_or_403(execution, request, vm_hash, ws) + await authenticate_websocket_for_vm_or_403(execution, vm_hash, ws) await ws.send_json({"status": "connected"}) queue = execution.vm.get_log_queue() @@ -88,12 +87,12 @@ async def stream_logs(request: web.Request) -> web.StreamResponse: execution.vm.unregister_queue(queue) -async def authenticate_for_vm_or_403(execution, request, vm_hash, ws): - """Allow authentication via HEADER or via websocket""" - if authenticate_api_request(request, raises_on_missing_header=False): - logger.debug(f"Accepted request to access logs via the allocation api key on {vm_hash}") - return True +async def authenticate_websocket_for_vm_or_403(execution: VmExecution, vm_hash: ItemHash, ws: web.WebSocketResponse): + """Authenticate a websocket connection. + Web browsers do not allow setting headers in WebSocket requests, so the authentication + relies on the first message sent by the client. + """ first_message = await ws.receive_json() credentials = first_message["auth"] authenticated_sender = await authenticate_websocket_message(credentials)