mirror of
https://github.com/GNS3/gns3-server.git
synced 2026-08-27 12:30:13 +03:00
mcp: fingerprint short-lived console tokens for copy-corruption checks
node_console_info now returns token_sha256_prefix (sha256, first 8 hex chars) and token_ttl_seconds alongside the console WebSocket URL, and controller WebSocket auth rejections include the sha256 prefix of the token as received. Comparing the two immediately distinguishes a token corrupted in transfer from server-side rejection causes (expired, revoked, bad signature).
This commit is contained in:
parent
704b5d80c2
commit
200ccf0dfe
@ -15,6 +15,7 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import asyncio
|
||||
import hashlib
|
||||
import logging
|
||||
import bcrypt
|
||||
|
||||
@ -176,7 +177,14 @@ async def get_current_active_user_from_websocket(
|
||||
return user
|
||||
|
||||
except HTTPException as e:
|
||||
err_msg = f"Could not authenticate while connecting to controller WebSocket: {e.detail}"
|
||||
# Fingerprint the received token so clients can compare it against the fingerprint
|
||||
# returned when the token was issued (e.g. token_sha256_prefix from the
|
||||
# node_console_info MCP tool) and detect copy corruption on their side.
|
||||
token_sha256_prefix = hashlib.sha256(token.encode()).hexdigest()[:8]
|
||||
err_msg = (
|
||||
f"Could not authenticate while connecting to controller WebSocket: {e.detail} "
|
||||
f"(received token sha256 prefix: {token_sha256_prefix})"
|
||||
)
|
||||
websocket_error = {"action": "log.error", "event": {"message": err_msg}}
|
||||
await websocket.send_json(websocket_error)
|
||||
log.error(err_msg)
|
||||
|
||||
@ -25,6 +25,7 @@ via Gns3Connector (from custom_gns3fy).
|
||||
from typing import Any
|
||||
from concurrent.futures import ThreadPoolExecutor, as_completed
|
||||
|
||||
import hashlib
|
||||
import logging
|
||||
|
||||
from gns3server.services import auth_service
|
||||
@ -312,6 +313,12 @@ def get_node_console_info_handler(params: dict[str, Any], gns3_ctx: dict[str, An
|
||||
"ws_url": ws_url,
|
||||
"command": f"websocat -t --no-close {ws_url}",
|
||||
}
|
||||
if ws_token:
|
||||
# Fingerprint of the minted token: compare it against what actually reached the
|
||||
# server (logged on WebSocket auth rejection) to detect copy corruption, and
|
||||
# re-request the URL once token_ttl_seconds has elapsed.
|
||||
result["token_sha256_prefix"] = hashlib.sha256(ws_token.encode()).hexdigest()[:8]
|
||||
result["token_ttl_seconds"] = 600
|
||||
if console_type in ("vnc",):
|
||||
result["vnc_url"] = f"/v3/projects/{project_id}/nodes/{node_id}/console/vnc?token={gns3_ctx['jwt_token']}"
|
||||
return result
|
||||
|
||||
@ -106,7 +106,8 @@ class TestRoutes:
|
||||
async with aconnect_ws(path, client, params=params) as ws:
|
||||
json_notification = await ws.receive_json()
|
||||
assert json_notification['event'] == {
|
||||
'message': 'Could not authenticate while connecting to controller WebSocket: Invalid token (DecodeError)'
|
||||
'message': 'Could not authenticate while connecting to controller WebSocket: '
|
||||
'Invalid token (DecodeError) (received token sha256 prefix: 4d4f92fb)'
|
||||
}
|
||||
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user