mirror of
https://github.com/trustgraph-ai/trustgraph.git
synced 2026-07-21 11:11:03 +02:00
fix: skip authorise() for AUTHENTICATED/PUBLIC sentinels in WebSocket mux
The mux unconditionally called auth.authorise() for every operation,
passing capability sentinels like AUTHENTICATED ("__authenticated__")
to the IAM regime. Since no role grants "__authenticated__", the regime
denied the request — breaking whoami (and any future AUTHENTICATED-only
operation) over the WebSocket path while the HTTP endpoints worked fine.
Match the guard pattern used by iam_endpoint.py and registry_endpoint.py:
only call authorise() for real capability strings, not sentinels.
This commit is contained in:
parent
60f861bac4
commit
ac9968b1e0
1 changed files with 31 additions and 25 deletions
|
|
@ -4,6 +4,8 @@ import queue
|
||||||
import uuid
|
import uuid
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
from ..capabilities import PUBLIC, AUTHENTICATED
|
||||||
|
|
||||||
# Module logger
|
# Module logger
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
@ -156,37 +158,41 @@ class Mux:
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
|
|
||||||
# Resolve workspace first (default-fill from the caller's
|
# Resolve workspace (default-fill from the caller's
|
||||||
# bound workspace), then ask the regime to authorise the
|
# bound workspace). Workspace resolution applies to all
|
||||||
# service-level capability against the matched
|
# operations regardless of capability level.
|
||||||
# operation's resource shape.
|
|
||||||
try:
|
try:
|
||||||
await enforce_workspace(data, self.identity, self.auth)
|
await enforce_workspace(data, self.identity, self.auth)
|
||||||
if isinstance(inner, dict):
|
if isinstance(inner, dict):
|
||||||
await enforce_workspace(inner, self.identity, self.auth)
|
await enforce_workspace(inner, self.identity, self.auth)
|
||||||
|
|
||||||
if data.get("flow"):
|
# Authorisation: capability sentinels short-circuit
|
||||||
resource = {
|
# the regime call; capability strings go through
|
||||||
"workspace": data.get("workspace", ""),
|
# authorise().
|
||||||
"flow": data.get("flow", ""),
|
if op.capability not in (PUBLIC, AUTHENTICATED):
|
||||||
}
|
if data.get("flow"):
|
||||||
parameters = {}
|
resource = {
|
||||||
else:
|
"workspace": data.get("workspace", ""),
|
||||||
# Build a minimal RequestContext so the matched
|
"flow": data.get("flow", ""),
|
||||||
# operation's own extractors decide resource and
|
}
|
||||||
# parameters — same path the HTTP endpoints take.
|
parameters = {}
|
||||||
from ..registry import RequestContext
|
else:
|
||||||
ctx = RequestContext(
|
# Build a minimal RequestContext so the matched
|
||||||
body=inner if isinstance(inner, dict) else {},
|
# operation's own extractors decide resource
|
||||||
match_info={},
|
# and parameters — same path the HTTP
|
||||||
identity=self.identity,
|
# endpoints take.
|
||||||
)
|
from ..registry import RequestContext
|
||||||
resource = op.extract_resource(ctx)
|
ctx = RequestContext(
|
||||||
parameters = op.extract_parameters(ctx)
|
body=inner if isinstance(inner, dict) else {},
|
||||||
|
match_info={},
|
||||||
|
identity=self.identity,
|
||||||
|
)
|
||||||
|
resource = op.extract_resource(ctx)
|
||||||
|
parameters = op.extract_parameters(ctx)
|
||||||
|
|
||||||
await self.auth.authorise(
|
await self.auth.authorise(
|
||||||
self.identity, op.capability, resource, parameters,
|
self.identity, op.capability, resource, parameters,
|
||||||
)
|
)
|
||||||
except _web.HTTPNotFound:
|
except _web.HTTPNotFound:
|
||||||
await self.ws.send_json({
|
await self.ws.send_json({
|
||||||
"id": request_id,
|
"id": request_id,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue