Kapitola 05 / 09
ENSK

SmartExchange · .NET 10 · Chapter 05

Principal context and Policy

Resolver pripraví ohraničený súbor faktov. Policy vyberie, ktoré z nich oprávňujú operáciu; obsahuje business rozhodnutie vrátane väzby read → export.

Shared code · Intaker + Web APIReviewed · 2026-10-27

Tri spoločné interfaces

Reader → Resolver → Policy client
// BmcGroup.Authorization.Contracts
Task<IReadOnlyList<AuthorizationGrant>> IAuthorizationGrantReader.ReadAsync(
    AuthorizationGrantRequest request, CancellationToken cancellationToken);

Task<AuthorizationPrincipal> IAuthorizationContextResolver.ResolveAsync(
    AuthorizationContextRequest request, CancellationToken cancellationToken);

Task<AuthorizationQueryPlan> IAuthorizationPolicyClient.PlanResourcesAsync(
    AuthorizationPlanRequest request, CancellationToken cancellationToken);
// Signatures condensed; cancellationToken defaults to default in source.

AuthorizationContextRequest(UserId, Product, Resource) vyberá context. Resolver z neho zostaví AuthorizationGrantRequest(UserId, Product, ResourceKinds) pre reader. Plánovanie potom používa AuthorizationPlanRequest(RequestId, Principal, Resource, Action).

Implementovaná príprava

  1. LegacySqlAuthorizationGrantAdapter.ReadAsync() načíta aktívne assignments, permissions rolí a priamy/skupinový/verejný prístup z databázy danej product inštancie. SQL pred načítaním obmedzí scope anchors a podporované permissions.
  2. Normalize(rows, diagram, resourceKinds) preloží číselné kódy na pomenované grants a overí scopes. Surový LegacyAuthorizationGrantRow zostáva pri tomto adapteri.
  3. SmartExchangeAuthorizationContextResolver.ResolveAsync() vyberie root + anotované ciele, validuje vybrané fakty a vytvorí roles: ["user"], attr.product a attr.grants. Výber znovu presadí aj pri použití iného readera.

AuthorizationGrant má šesť polí: pôvodný assignment, ID scope záznamu, autorizovaný resource, action, scope a príznak verejného assignmentu. IsPublic=false môže byť priamy aj skupinový prístup; nerozlišuje cestu členstva.

Dočasný fakt */admin/Instance v kóde zatiaľ zostáva. Legacy pseudoakcia admin aj resource * sa pri migrácii odstránia. Resolver automaticky nemapuje databázovú rolu s názvom exportAdmin na Cerbos rolu.

Dva grants → dve derived roles → dve celé policies

Oba príklady sledujú rovnaké kroky a používajú ten istý spoločný kód. Person export prijíma Company/read grant cez vzťah. Navrhovaný InterestedParty export prijíma InterestedParty/read v Project scope. Použitie read pre export je explicitné rozhodnutie policy; nemení action grantu a nevyplýva z bežného Project/read.

Obe kompletné demo policies používajú verziu presentation-demo, importujú existujúci derived-role set a obsahujú jedno export ALLOW pravidlo. Izolujú relationship cestu; neobsahujú exportAdmin, priamy ani instance-wide root bypass. Nevyhovujúce requests sú odmietnuté. Ide o dokumentačné návrhy, nie dnešné kompletné production/default policies.

Person/export

Ilustračný CompanyReader assignment sa normalizuje na Company/read/Resource. Demo policy povoľuje export Person cez tento Company vzťah.

Normalized grant
{
  "assignmentId": "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb",
  "resourceId": "11111111-1111-1111-1111-111111111111",
  "resource": "Company",
  "action": "read",
  "scope": "Resource",
  "isPublic": false
}
Principal · celý JSON
Principal · celý JSON
{
  "id": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa",
  "roles": [
    "user"
  ],
  "attr": {
    "product": "QA",
    "grants": [
      {
        "assignmentId": "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb",
        "resourceId": "11111111-1111-1111-1111-111111111111",
        "resource": "Company",
        "action": "read",
        "scope": "Resource",
        "isPublic": false
      }
    ]
  }
}
Derived role · nasadená definícia
Derived role · nasadená definícia
# Runtime snapshot: aks-smartcloud-nonprod / dev-authorization / derived-role-person-company-read
# Read on 2026-10-27. YAML content only; not a Kubernetes installation manifest.
apiVersion: api.cerbos.dev/v1
description: >-
  Person.companyIds ReBAC condition: the user has a normalized Company/read
  grant for at least one related record. This definition alone grants no action.
derivedRoles:
  name: person_company_read
  variables:
    local:
      personCompanyReadAll: >-
        has(P.attr.grants) && P.attr.grants.exists(g,
          g.resource == "Company" && g.action == "read" && g.scope == "Instance")
      personCompanyReadIds: >-
        has(P.attr.grants) ? P.attr.grants.filter(g,
          g.resource == "Company" && g.action == "read" && g.scope == "Resource" &&
          g.resourceId != "00000000-0000-0000-0000-000000000000").map(g, g.resourceId) : []
  definitions:
    - name: person_with_readable_company
      parentRoles: [user]
      condition:
        match:
          expr: >-
            R.kind == "Person" &&
            R.attr.companyIds.exists(relatedId,
              V.personCompanyReadAll || relatedId in V.personCompanyReadIds)
Resource policy · celý demo YAML
Resource policy · celý demo YAML
# Documentation proposal only; not deployed. Separate version, no admin/direct bypass.
apiVersion: api.cerbos.dev/v1
description: Person export using read access to a related Company.
resourcePolicy:
  version: presentation-demo
  resource: Person
  importDerivedRoles:
    - person_company_read
  rules:
    - name: export-persons-through-readable-company
      actions: [export]
      derivedRoles: [person_with_readable_company]
      effect: EFFECT_ALLOW

Derived-role YAML · Celá demo policy · Plan request

InterestedParty/export

Assignment roly Project View zo snapshotu sa normalizuje na InterestedParty/read/Project. Export je navrhovaná ďalšia operácia, ktorú táto demo policy akceptuje.

Normalized grant
{
  "assignmentId": "a7f53aab-6f40-4204-b1d3-02ea54f1713e",
  "resourceId": "b48e464a-88cf-4743-bbce-98d6ba89e399",
  "resource": "InterestedParty",
  "action": "read",
  "scope": "Project",
  "isPublic": false
}
Principal · celý JSON
Principal · celý JSON
{
  "id": "5a3e5b0f-fb6d-4abf-ba4f-8b581365a795",
  "roles": [
    "user"
  ],
  "attr": {
    "product": "API_Dev1",
    "grants": [
      {
        "assignmentId": "a7f53aab-6f40-4204-b1d3-02ea54f1713e",
        "resourceId": "b48e464a-88cf-4743-bbce-98d6ba89e399",
        "resource": "InterestedParty",
        "action": "read",
        "scope": "Project",
        "isPublic": false
      }
    ]
  }
}
Derived role · nasadená definícia
Derived role · nasadená definícia
# Runtime snapshot: aks-smartcloud-nonprod / dev-authorization / derived-role-interested-party-project-scope
# Read on 2026-10-27. YAML content only; not a Kubernetes installation manifest.
apiVersion: api.cerbos.dev/v1
description: InterestedParty read restricted by an explicit Project scope.
derivedRoles:
  name: interested_party_project_scope
  variables:
    local:
      projectScopeIds: >-
        has(P.attr.grants) ? P.attr.grants.filter(g,
          g.resource == "InterestedParty" &&
          g.action == "read" &&
          g.scope == "Project" &&
          g.resourceId != "00000000-0000-0000-0000-000000000000"
        ).map(g, g.resourceId) : []
  definitions:
    - name: interested_party_in_project_scope
      parentRoles: [user]
      condition:
        match:
          expr: >-
            R.kind == "InterestedParty" &&
            size(V.projectScopeIds) > 0 &&
            R.attr.projectIds.exists(projectId,
              projectId in V.projectScopeIds)
Resource policy · celý demo YAML
Resource policy · celý demo YAML
# Documentation proposal only; not deployed. Separate version, no admin/direct bypass.
apiVersion: api.cerbos.dev/v1
description: InterestedParty export using explicit read permission in Project scope.
resourcePolicy:
  version: presentation-demo
  resource: InterestedParty
  importDerivedRoles:
    - interested_party_project_scope
  rules:
    - name: export-interested-parties-in-project-scope
      actions: [export]
      derivedRoles: [interested_party_in_project_scope]
      effect: EFFECT_ALLOW

Derived-role YAML · Celá demo policy · Plan request

Rovnaký mechanizmus, iný význam grantu. Person rola kontroluje Company/read grants. InterestedParty rola kontroluje InterestedParty/read so scope Project; nesmieme ju nahradiť nasadenou rolou nad cieľovým Project/read. Samotný import derived-role set neudeľuje akciu; resource policy musí použiť danú rolu.

Aktuálny kód/runtime, oddelene od týchto ukážok: Person source policy · Person live default · InterestedParty live default. Person v zdrojovej policy zapisuje vzťah inline; demo ukazuje zodpovedajúcu kompozíciu cez derived role. InterestedParty/default dnes povoľuje túto scoped rolu pre read, nie pre export.