Access Control V2
Access Control V2 is de opvolger van de Persona-gebaseerde resource-toewijzing. Het koppelt medewerkers automatisch én handmatig aan Microsoft 365 resources — shared mailboxes, enterprise apps, Teams-groepen en security groups — op basis van organisatieattributen uit het OrgModel.
Het belangrijkste architecturele verschil met Persona's: Access Control V2 gebruikt inheritance (overerving langs de boomstructuur van root naar blad), terwijl Persona's het deepest-match-wins principe hanteren. Dit maakt cumulatieve resource-toewijzing over meerdere niveaus van een organisatiehiërarchie mogelijk.
Architectuur
Drie strategieën in één designer
Access Control V2 ondersteunt drie toewijzingsstrategieën, die allemaal samenkomen in één visuele boomdesigner:
Strategie | Mechanisme | Beschrijving |
|---|---|---|
ABAC | Condition nodes | Attributen uit Entra (Department, JobTitle, City, etc.) bepalen matching. Resources op elke laag erven over naar alle onderliggende niveaus. |
TBAC | Task nodes | Handmatige toewijzing van medewerkers aan taken of rollen (bijv. BHV, EHBO). Assignees staan direct op de node. |
RBAC | Via ABAC | Impliciet ondersteund doordat condition nodes op functie/rol kunnen filteren. |
Inheritance model
De rule tree is een gerichte boom van AccessControlRuleNode-objecten, verbonden via AccessControlRuleEdge-paren (sourceId → targetId). De sync engine loopt van root naar bladeren en verzamelt resources op elk gematchte niveau — er is geen vroeg stoppen zoals bij Persona's.
Voorbeeld — Jan (IT, Manager, BHV-medewerker): TeamsGroup "Alle Medewerkers" + SharedMailbox "info@" + EnterpriseApp "Jira" + EnterpriseApp "Azure" + TeamsGroup "BHV Team" = 5 resources
Vier resource types
Type | Provisioning | Graph/Exchange API |
|---|---|---|
| Full Access + optioneel Send As | Exchange Admin API via |
| App Role Assignment |
|
| M365 Group membership |
|
| Entra Security Group membership |
|
Datamodel
Domain objecten
Database tabellen (UserTypeDb)
Migratie 083_Create_AccessControlV2_Tables_UserTypeDb.cs (versienummer 20260417120000) maakt 9 tabellen aan:
Tabel | Doel |
|---|---|
| Policy definities per tenant |
| Versioned JSON payloads (draft/active semantiek) |
| RBAC platte mappings (legacy, sync leest uit tree) |
| TBAC taakdefinities (legacy, sync leest uit tree) |
| TBAC handmatige toewijzingen (legacy, sync leest uit tree) |
| Resource-koppelingen aan policies (legacy, sync leest uit tree) |
| Berekende toewijzingen per medewerker per policy |
| Actueel geprovisioneerde staat per medewerker per resource |
| Audit trail van sync-uitvoeringen |
Belangrijk: De sync engine leest resources uitsluitend uit de JSON payload in AccessControl_RuleVersions. De AccessControl_ResourceLinks, AccessControl_RoleMappings en AccessControl_TaskAssignments tabellen zijn achtergelaten als legacy structuur. De tree is de single source of truth.
AccessControl_ResourceState gebruikt twee gefilterde unique indexes om de combinatie (TenantId, EmployeeUpn, ResourceType, ResourceId, AppRoleId) uniek te houden — één voor rijen met AppRoleId IS NOT NULL en één voor rijen met AppRoleId IS NULL, omdat SQL Server geen standaard unique constraint met nullable kolommen ondersteunt.
Rule matching engine
AccessControlRuleMatchingService implementeert de inheritance walk. De centrale methode is ComputeEffectiveResources:
Algoritme:
Attribuutmatching is case-insensitive. De waarde van het OrgModel-attribuut wordt opgehaald uit het Entra-gebruikersobject via property name matching (bijv. "Department" → department veld in Graph API response).
Sync engine
Bestanden
Bestand | Verantwoordelijkheid |
|---|---|
| Core sync loop: desired state berekenen, diff uitvoeren, provisioners aanroepen |
| Rule tree walk met inheritance |
| Vier concrete provisioners plus |
Sync flow (tenant-brede sync)
Resource provisioners
Alle provisioners implementeren IResourceProvisioner:
Provisioners zijn idempotent: een 409 Conflict (al toegewezen) bij Grant en een 404 Not Found (al verwijderd) bij Revoke worden stil genegeerd en als succes beschouwd.
EnterpriseAppProvisioner — Graph API:
Grant:
POST /v1.0/servicePrincipals/{resourceId}/appRoleAssignedTomet{ principalId, resourceId, appRoleId }Revoke: zoek eerst de assignment op via filter, dan
DELETE /v1.0/servicePrincipals/{resourceId}/appRoleAssignedTo/{assignmentId}Wanneer
appRoleIdnull is, wordt00000000-0000-0000-0000-000000000000gebruikt (default app role)
SharedMailboxProvisioner — Exchange Admin API via IEntraUserService:
Grant:
IEntraUserService.GrantMailboxDelegateAccessAsyncRevoke:
IEntraUserService.RevokeMailboxDelegateAccessAsyncRequires Exchange Administrator role op de service principal
TeamsGroupProvisioner / SecurityGroupProvisioner — Graph API:
Grant:
POST /v1.0/groups/{groupId}/members/$refmet{ "@odata.id": "https://graph.microsoft.com/v1.0/directoryObjects/{userId}" }Revoke:
DELETE /v1.0/groups/{groupId}/members/{userId}/$refTeams-groepen staan geen nesting van security groups toe — individuele users worden toegevoegd
DI-registratie
Hangfire jobs
Job | Display name | Schedule / Trigger |
|---|---|---|
| Access Control Sync Dispatcher | Dagelijks 07:00 + 19:00 UTC ( |
| Access Control Tenant Sync - () | Per tenant, ge-enqueued door dispatcher, manual trigger, publish, HR sync |
| — | Per medewerker, ge-enqueued door |
| — | Na resource-wijzigingen (nu stub, nog niet geïmplementeerd) |
Registratie in Program.cs:
Dispatcher flow:
AccessControlTenantSyncJob heeft een ingebouwde timeout van 30 minuten. De job gebruikt multiTenantService.SetTenantId(tenantId) om de tenant context in te stellen voor de duur van de uitvoering.
API endpoints
Base path: /usertypes/accesscontrol
Alle endpoints verkrijgen de tenant ID via de X-Tenant-Id header via IMultiTenantService.GetTenantId(). Het tenant ID staat nooit in de request body.
Policies
Methode | Pad | Beschrijving |
|---|---|---|
|
| Alle policies voor de tenant |
|
| Policy aanmaken |
|
| Enkele policy |
|
| Policy bijwerken |
|
| Policy verwijderen |
Resources (Graph API lookups + koppelen)
Methode | Pad | Beschrijving |
|---|---|---|
|
| Shared mailboxes ophalen via Graph |
|
| Enterprise apps met app roles |
|
| Teams / M365 groepen |
|
| Entra security groups ( |
|
| Resources gekoppeld aan een policy |
|
| Resource koppelen aan policy |
|
| Resource ontkoppelen |
Rules (draft/publish lifecycle)
Methode | Pad | Beschrijving |
|---|---|---|
|
| Nieuwe draft aanmaken |
|
| Huidige draft ophalen |
|
| Draft payload opslaan (tree JSON) |
|
| Draft verwijderen |
|
| Draft publiceren → activeert + triggert sync |
|
| Actieve versie ophalen |
|
| Versiehistorie |
Draft/publish semantiek: Per tenant bestaat maximaal één draft. Bij publicatie wordt de draft gemarkeerd als IsActive = true, de vorige actieve versie wordt gedeactiveerd, en AccessControlTenantSyncJob wordt ge-enqueued met triggerSource: "Publish".
RBAC / TBAC
Methode | Pad | Beschrijving |
|---|---|---|
|
| Rol mappings ophalen |
|
| Rol mappings opslaan |
|
| Taak-toewijzingen ophalen |
|
| Medewerker toewijzen aan taak |
|
| Toewijzing verwijderen |
Sync & monitoring
Methode | Pad | Beschrijving |
|---|---|---|
|
| Handmatige sync triggeren |
|
| Recente sync-runs ophalen |
|
| Alle berekende toewijzingen |
|
| Toewijzingen per policy |
Frontend designer
Route: /usertypes/accesscontrol-v2/rules
De designer is gebouwd met Blazor.Diagrams en bestaat uit drie zones:
Zone | Component | Beschrijving |
|---|---|---|
Sidebar (links) |
| Twee drag-and-drop blokken: Eigenschap conditie en Taak/Rol |
Canvas (midden) | Blazor.Diagrams canvas | Interactief diagram met nodes, edges, zoom en auto-layout |
Config panel (rechts) | Inline in | Contextgevoelig configuratiepaneel per geselecteerde node |
Node widgets:
Component | Nodetyp | Beschrijving |
|---|---|---|
|
| De wortelknoop — niet verwijderbaar |
|
| Attribuutgebaseerde condities (ABAC) |
|
| Handmatige toewijzingsnodes (TBAC) |
Resource picker dialogs:
Dialog | Gebruik |
|---|---|
| Twee-staps: mailbox kiezen + Full Access / Send As permissie |
| Twee-staps: eerst app kiezen, dan app role selecteren |
| Generiek voor Teams-groepen, security groups en medewerkers (assignees) |
Overgeerfde resources worden in het config panel visueel onderscheiden: grayed-out stijl, slotpictogram, gestippelde rand. Ze zijn niet aanpasbaar via de huidige node.
Graph API permissions
De service principal van de tenant heeft de volgende permissions nodig:
Permission | Type | Gebruik |
|---|---|---|
| Application | Medewerkerdata ophalen uit Entra |
| Application | Security / Teams group membership beheren |
| Application | Enterprise app role assignments |
| Application | Enterprise apps en rollen ophalen |
Exchange Administrator | Directory role | Shared mailbox permissions via Exchange Admin API |
Bekende beperkingen en TODO's
Item | Status | Beschrijving |
|---|---|---|
EvaluateImpact endpoint | Stub (directory aanwezig) | Impact preview vóór publicatie — berekent hoeveel medewerkers resources krijgen of verliezen |
AccessControlChangedWorkflowTriggerJob | Stub | Moet na elke sync een workflow triggeren als resources zijn gewijzigd |
Publish validatie | Ontbreekt | Valideer tree structuur en controleer of alle nodes geconfigureerd zijn vóór publicatie |
Graph API pagination | Hardcoded | Bij tenants met meer dan 999 gebruikers worden niet alle medewerkers gesynchroniseerd |
Vergelijking met Persona's
Aspect | Persona's | Access Control V2 |
|---|---|---|
Toewijzingsmodel | Deepest match wins | Inheritance (alle matched niveaus) |
Resources | Assets, licenties, templates | M365 resources (mailbox, app, groep) |
Handmatige toewijzing | Niet ondersteund | Task nodes met assignees |
Provisioning | Workflow-gebaseerd | Direct via Graph/Exchange API |
Versioning | Versioned OrgModel tree | Versioned rule tree (draft/active) |
Designer | Blazor.Diagrams | Blazor.Diagrams (zelfde component library) |