diff --git a/gsap_broker/models/gsap.py b/gsap_broker/models/gsap.py index 82a61e9..598eb48 100644 --- a/gsap_broker/models/gsap.py +++ b/gsap_broker/models/gsap.py @@ -76,6 +76,9 @@ class AuthorizeRequest(BaseModel): accord_template: str driver_id: str session_mode: bool = False # When true, AC stays active across multiple CRs + # When set by a trusted caller (e.g. Bascule), overrides the driver-derived principal. + # The SA authenticates the request; this field says who the AC is FOR. + on_behalf_of: Optional[str] = None class AuthorizeResponse(BaseModel): status: str diff --git a/gsap_broker/routers/authorize.py b/gsap_broker/routers/authorize.py index 1b1fb7b..544af22 100644 --- a/gsap_broker/routers/authorize.py +++ b/gsap_broker/routers/authorize.py @@ -67,23 +67,27 @@ async def authorize(body: AuthorizeRequest, http_request: Request, db: AsyncSess expires = now + timedelta(minutes=settings.ac_ttl_minutes) ctx_id = uuid.uuid4() + # on_behalf_of: trusted caller (Bascule SA) asserts who the AC is for + principal_did = request.on_behalf_of or auth_result.principal_did + display_name = request.on_behalf_of.rsplit("/", 1)[-1] if request.on_behalf_of else auth_result.display_name + ac = AuthorizationContext( context_id=ctx_id, issued_at=now, expires_at=expires, - principal=Principal(did=auth_result.principal_did, display_name=auth_result.display_name, driver_id=request.driver_id), + principal=Principal(did=principal_did, display_name=display_name, driver_id=request.driver_id), accord=Accord(template=request.accord_template), operation=Operation(playbook=request.playbook, corpus_entry_cid=request.corpus_entry_cid, parameters_cid=request.parameters_cid), identity_proof=IdentityProof(token_jti=auth_result.token_jti, elevation_active=auth_result.elevation_active, mfa_satisfied=auth_result.mfa_satisfied), broker={"did": settings.broker_did, "name": settings.broker_name}) ac_db = AuthorizationContextDB( - context_id=ctx_id, principal_did=auth_result.principal_did, driver_id=request.driver_id, + context_id=ctx_id, principal_did=principal_did, driver_id=request.driver_id, playbook=request.playbook, corpus_entry_cid=request.corpus_entry_cid, parameters_cid=request.parameters_cid, accord_template=request.accord_template, token_jti=auth_result.token_jti, elevation_active=auth_result.elevation_active, mfa_satisfied=auth_result.mfa_satisfied, status="authorized", issued_at=now, expires_at=expires, session_mode=request.session_mode) db.add(ac_db) - cid = await chronicle.emit("GSAP_AC_ISSUED", {"event_code": "0x2704", "context_id": str(ctx_id), "principal_did": auth_result.principal_did, "playbook": request.playbook}) + cid = await chronicle.emit("GSAP_AC_ISSUED", {"event_code": "0x2704", "context_id": str(ctx_id), "principal_did": principal_did, "playbook": request.playbook}) ac_db.chronicle_event_cid = cid await db.commit()