5.2 KiB
| id | type | title | domain | repo | status | owner | topic_slug | created | updated | state_hub_workstream_id |
|---|---|---|---|---|---|---|---|---|---|---|
| KEY-WP-0005 | workplan | IAM Profile core claims: tenant, principal_type, groups, roles, assurance, tenant_roles | infotech | key-cape | ready | codex | netkingdom | 2026-07-23 | 2026-07-23 | 74ac0d31-b86e-449d-89b2-4e15263bf050 |
IAM Profile core claims: tenant, principal_type, groups, roles, assurance, tenant_roles
Discovered while planning tenant-engine/workplans/TEN-WP-0003-flex-auth-write-authorizer.md:
key-cape's token issuance (src/internal/server/oidc/token.go) does not
currently emit tenant, principal_type, groups, roles, or
assurance — none of net-kingdom/canon/standards/iam-profile_v0.3.md's
Core Claims are implemented yet, only preferred_username/email/groups
(LDAP-sourced, not the profile's normalized groups claim) and OIDC's own
base claims (nonce, etc.).
This is bigger than "add the tenant_roles claim on top of existing tenant
support" — key-cape isn't yet profile-conformant at all on the tenant/
principal/assurance axis. tenant_roles (the reason this workplan exists)
is the last, optional claim in that same set (v0.3's addition on top of
v0.2's baseline) — implementing it in isolation without the claims it
depends on for meaning (tenant, principal_type) would be incoherent.
This workplan is registered, not implemented, by the same session that
found the gap. Token issuance is security-sensitive code in a Go codebase
with its own adapter conventions (internal/adapters/{lldap,privacyidea,authelia})
that deserves dedicated context before changing, not a rushed edit from a
first read of token.go. Scoped and sequenced here so the work isn't lost.
Depends on: net-kingdom/canon/standards/iam-profile_v0.3.md (ratified).
Related: tenant-engine/workplans/TEN-WP-0003-flex-auth-write-authorizer.md
(the consumer waiting on tenant_roles); key-cape/workplans/KEY-WP-0004-binky-hedgehog-tenant-onboarding.md
(Binky's onboarding, which needs tenant claim support to produce a
correct tenant:friendly:binky token at all).
Task: Emit tenant, principal_type, groups, roles, assurance
id: KEY-WP-0005-T01
status: todo
priority: high
state_hub_task_id: "66107caf-ba26-4291-bb09-1f9e58275505"
Bring token.go's claim assembly up to iam-profile_v0.3.md's Core Claims
table baseline (the v0.2-originated set):
tenant: resolve from whatever user/service/agent-to-tenant mappingkey-cape's LLDAP/Authelia backend can provide today; if no such mapping exists yet, that's itself a sub-task — this claim cannot be stamped from nothing.principal_type:humanfor the existing Authorization Code + PKCE flow;servicefor client-credentials flows (check whetherkey-capealready issues client-credentials tokens at all —grant_types_supportedin the discovery contract claims it does, but that needs verifying against real code, the same way this workplan verifiedtenantclaim absence).groups,roles: normalize from LDAP group/role data into the profile's flat string-array shape.assurance:{level, methods, mfa, source, at}per the profile —privacyIDEA-backed MFA evidence maps toaal2; single-factor maps toaal1.
Done when: tools/iam-profile-conformance/ (already exists) passes against
these claims for both human and service token issuance paths.
Task: Emit tenant_roles (optional, cached)
id: KEY-WP-0005-T02
status: todo
priority: high
state_hub_task_id: "1b8f44b4-2763-4d5a-a3eb-1c2b9a25dd15"
At token-issuance time, call tenant-engine's cache-read endpoint
(GET /tenants/{tenant_id}/roles) using the tenant claim resolved in T01,
and stamp the result as the optional tenant_roles claim
(iam-profile_v0.3.md, "Tenant Roles" section). Follows the same adapter
pattern as internal/adapters/{lldap,privacyidea,authelia} — a new
internal/adapters/tenantengine package, not inline HTTP calls in
token.go.
Fail open on this claim specifically, not closed: tenant_roles is
documented as a cache callers must not trust for privileged decisions
anyway (flex-auth re-validates live). If tenant-engine is unreachable at
issuance time, omit the claim rather than fail the entire token issuance —
losing a performance optimization is acceptable; blocking login because a
cache source is down is not. This is the one place in the whole tenant_roles
design where fail-open is correct, precisely because the live-lookup path
exists as the real gate.
Done when: token issuance still succeeds with tenant_roles omitted when
tenant-engine is unreachable (test simulates the outage); present and
correct when reachable, for a tenant with known role grants.
Task: Closure review
id: KEY-WP-0005-T03
status: todo
priority: low
state_hub_task_id: "34555bf7-0f18-4dac-ade2-6ff3738f353f"
Confirm T01–T02 done; conformance suite green for both tasks together.
Note in closure: this unblocks KEY-WP-0004's Binky onboarding actually
producing conformant tokens, and unblocks flex-auth's side of the
tenant_roles picture receiving a real claim to reason about (though
flex-auth's live-lookup path doesn't depend on this claim existing — only
the cache-read/performance path does). Run statehub fix-consistency.