Implement identity canon alignment

This commit is contained in:
2026-06-05 16:04:43 +02:00
parent fe446711de
commit c6d211f472
15 changed files with 1008 additions and 21 deletions

103
docs/canon-mapping.md Normal file
View File

@@ -0,0 +1,103 @@
# Canon Mapping
Status: candidate
Updated: 2026-06-05
This document maps current `user-engine` implementation concepts to
identity-canon and InfoTechCanon concepts. It is intentionally explicit about
owned facts, consumed facts, references, and gaps.
## Mapping Stance
`identity-canon` treats `User` as a convenience term, not the root concept.
`user-engine` keeps the existing `User` implementation class for compatibility,
but exposes canon-facing context through `identity_context` so consumers can see
the distinct account, actor, subject, principal, tenant, membership, profile,
and evidence references.
## Entity Mapping
| user-engine concept | Canon concept | Ownership | Notes |
| --- | --- | --- | --- |
| `Actor` | Actor | consumed/reference | Normalized from verified IAM claims; not persisted as source of truth. |
| `Actor.issuer + Actor.subject` | Authenticated Subject / Scoped Identifier | consumed/reference | Protocol-level identity after authentication. |
| `User` | User convenience term / profile holder | owned local record | Not treated as Natural Person unless a future mapping proves that relationship. |
| `Account` | Account | owned | Operational account state for the user-engine scope. |
| `TenantAccount` | Account scoped to Tenant | owned | Tenant-local account lifecycle state. |
| `ExternalIdentity` | Identity Record / Scoped Identifier / Synonymity Assertion seed | owned link | Links issuer-subject pairs to local user records without destructive merge. |
| `Application` | Scope / Application Service reference | owned local registry | Application-specific profile consumer and catalog owner. |
| `ApplicationBinding` | Trust Relationship / integration binding | owned local registry | Binds user-engine app IDs to external clients, protected systems, events, and catalogs. |
| `Membership` | Membership Relationship | owned when created here | Relationship from user/account context to tenant, team, application, group, or other scope. |
| `Membership.kind` | Role label / grant-like fact | owned local label | Role-like string is not a final authorization decision. |
| `ProfileValue` | Profile | owned | Scoped presentation or preference value. |
| `Catalog` / `AttributeDefinition` | Profile schema / governance metadata | owned | Attribute ownership, sensitivity, visibility, and mutability metadata. |
| `AuthorizationRequest` | Authorization request | emitted/consumed | Sent to authorization port; policy decision remains external. |
| `AuthorizationDecision` | Authorization decision | consumed/reference | Enforced locally; decision authority remains external. |
| `AuditRecord` | Evidence Source | owned local evidence, exportable | Local operational evidence; durable platform audit is external. |
| `OutboxEvent` | Lifecycle event / evidence source | owned local event | Integration event queue for downstream systems. |
## Relationship Mapping
| Relationship | Source | Target | Implementation source |
| --- | --- | --- | --- |
| `identity_link` | Identity Record | User | `ExternalIdentity.user_id` |
| `belongs_to_tenant` | User or Account | Tenant | `TenantAccount` and tenant-scoped operations |
| `authenticates_as` | Account | Authenticated Subject | normalized IAM claims |
| `evaluated_as` | Authenticated Subject | Authorization Principal | `identity_context` principal projection |
| `member_of` | User | Team / Group / Scope | `Membership(scope_type, scope_id)` |
| `role_label` | Membership Relationship | Role | `Membership.kind` |
| `scoped_to` | Access Grant or grant-like fact | Tenant / Scope | `Membership.tenant` and operation tenant |
| `governed_by` | Grant-like fact / decision | Policy reference | external policy/control resolver gap |
| `implemented_by` | Policy reference | Control reference | external policy/control resolver gap |
| `evidenced_by` | Identity-domain claim or grant-like fact | Evidence Source | local audit or external evidence exporter |
| `creates_task` | Evidence gap / integration gap | lifecycle task reference | lifecycle task sink gap |
## Read Model
`UserEngineService.identity_context(...)` returns the current implementation
surface for canon-facing identity context. It includes:
- the normalized actor;
- local user and account records;
- external identity links;
- tenant and optional application scope;
- membership facts;
- entity references for User, Account, Actor, Authenticated Subject,
Authorization Principal, Tenant, Identity Record, Scoped Identifier, Team,
Scope, Membership Relationship, and Role;
- relationship references for identity link, tenant scope, authentication,
principal evaluation, membership, role label, and grant-like scope;
- access grant-like references derived from memberships;
- evidence references derived from audit records;
- an optional effective profile projection;
- explicit gaps when evidence is missing.
## Current Gaps
- `Natural Person` is not modeled directly. A user record may represent a human
profile holder, but that relationship is not currently asserted.
- `Synonymity Assertion` is implicit in identity linking. Strong/weak link
confidence, verification method, privacy scope, and revocation state are not
first-class yet.
- `Organization`, `Customer`, `Vendor`, and `Legal Entity` are referenced only
through tenant, team, owner, or external system identifiers.
- `AccessReview`, `Policy`, `Control`, `Exception`, and lifecycle `Task`
references depend on external NetKingdom systems or future adapter
implementations.
- `Access Grant` is currently an exported grant-like reference derived from
memberships. It is not a durable authorization grant table.
- Evidence references currently derive from local audit records unless an
`EvidenceReferenceExporter` is supplied.
## Validation Hooks
The first executable checks live in `tests/test_identity_canon_alignment.py`.
They verify that:
- user, account, authenticated subject, authorization principal, tenant, team,
membership, and grant-like references remain distinct;
- service accounts project into service principals without becoming natural
persons;
- cross-tenant identity context is denied without platform scope;
- claims-enrichment context can be read without implying token issuance
ownership.