From 566c27bebb7120055cf2b4300fbac7f89591bc84 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 10 Oct 2026 15:32:22 +0000 Subject: [PATCH 1/3] dir-sim plan: V17 mailbox delegation, V18 document access (design) V17 models Exchange's three mailbox rights (FullAccess, SendAs, SendOnBehalf) as (object, trustee, right) relations with their witness, resolved through group membership. V18 records the SharePoint/OneDrive document-access proposal as open. Both answer gaps HubSPO-rs listed in its comms API map. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01G22yT6htkcdyXsihxxXdrg --- docs/DIRECTORY-SIMULATION-POC.md | 60 ++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/docs/DIRECTORY-SIMULATION-POC.md b/docs/DIRECTORY-SIMULATION-POC.md index b947e9c..de83225 100644 --- a/docs/DIRECTORY-SIMULATION-POC.md +++ b/docs/DIRECTORY-SIMULATION-POC.md @@ -451,5 +451,65 @@ no-population-intermediate rule. a synthetic DN for the cloud-only user that a real LDAP client can bind as; whether the emulated domain name is the on-premises one or the tenant's initial domain when there is no hybrid. +- **V17 — Mailbox delegation (design, 2026-10-10).** Exchange grants three + rights on a recipient to another principal (the trustee). They answer + different questions and none implies another: + - **FullAccess**: the trustee opens and reads the mailbox as its owner. + A mailbox permission (`Add-MailboxPermission`); on-premises in the + mailbox security descriptor. `msExchDelegateListLink` on the mailbox + lists only the FullAccess trustees that are automapped, so it is a + witness of some grants, not of all. + - **SendAs**: the trustee sends with the recipient's address as From and + leaves no trace of itself. An Active Directory extended right on the + recipient object (`Send-As`, rights GUID + `ab721a54-1e2f-11d0-9819-00aa0040529b`; `Add-RecipientPermission` in + Exchange Online). + - **SendOnBehalf**: From is the recipient and Sender is the trustee. + `publicDelegates` on the recipient (`GrantSendOnBehalfTo`). + + Decisions: + - **A grant is a relation, not a property.** `(object, trustee, right)` + is its own record, like a membership, and changes by add and remove; + no node carries a list of trustees. + - **The trustee is a user or a group.** A user holds a right on an + object when it is granted to the user or to any group the user belongs + to, transitively. + - **Each grant carries the witness that asserted it.** LDIF supplies + `publicDelegates` and `msExchDelegateListLink`; Graph supplies none of + the three; the Exchange permission output (`Get-MailboxPermission`, + `Get-RecipientPermission`, `GrantSendOnBehalfTo`) supplies all of them + and is read through the same read-only encoder as V12. Witnesses that + disagree both stay; an absent witness is not a refusal. + - **Consumers.** Spear's mailbox IAM lets a FullAccess trustee read the + mailbox's rows. SendAs and SendOnBehalf gate sending: a consumer that + submits through Stalwart picks the identity, and with SendOnBehalf sets + `Sender` to the trustee. + + Not modelled: folder-level permissions (`Add-MailboxFolderPermission`), + calendar delegates, and deny entries, which Exchange allows on + FullAccess. +- **V18 — Document access (design, open, 2026-10-10).** Nothing in Spear, + dir-sim or Stalwart decides who may read or change a document (HubSPO-rs + `comms-api-surface.md` §2). SharePoint and OneDrive grant a role (read, + write, owner) to a principal on a site, library, folder or item. An item + inherits its parent's grants until inheritance is broken, and sharing + links grant to whoever holds the link (anyone, the organization, or named + people); Graph reports these as a drive item's `permissions` with + `roles`, `grantedToV2`, `link` and `inheritedFrom`. + + Proposal, not yet decided: + - A grant is a relation `(resource, principal, role)`, as in V17. The + resource is a document, folder or drive node with a parent. + - A principal's effective role is the highest role granted to it, or to + a group it belongs to, on the item or on an ancestor up to the nearest + broken inheritance. + - A sharing link is a principal of its own kind. + - Spear evaluates it with an RBAC plug over the document classid, the + way `RBAC_PLUG` covers mail. + + Open: whether SharePoint groups are dir-sim groups; "limited access", + SharePoint's implicit role on an ancestor of a shared item; where the + folder tree lives (Spear's `DriveScope` names a drive and an item, not a + path). - **V5 — CI.** CI builds `lance-graph-dir-sim` against the OGAR checkout, so it needs this OGAR PR merged first. From 93d048eee75c9cbe8538b013af33edbcdf850c4b Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 10 Oct 2026 15:39:41 +0000 Subject: [PATCH 2/3] dir-sim plan V17/V18: deny wins, object types, nested groups, how Stalwart sends; two document regimes Folds in the HubSPO-rs review on #344: - FullAccess needs a mailbox; SendAs and SendOnBehalf also apply to a distribution group. - group trustees reach users through nested-group expansion, which dir-sim does not have yet (lance-graph W-4); until then only direct members. - a deny from any witness removes the right and is reported; grants alone would fail open. - sending through Stalwart: an identity may only carry its own account's addresses, so SendOnBehalf goes from the trustee's account with Sender set, and SendAs goes to the object's account by master-user impersonation after the V17 check. - V18: record attachments take access from their record; only library and OneDrive files follow the SharePoint model. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01G22yT6htkcdyXsihxxXdrg --- docs/DIRECTORY-SIMULATION-POC.md | 45 +++++++++++++++++++++++++------- 1 file changed, 36 insertions(+), 9 deletions(-) diff --git a/docs/DIRECTORY-SIMULATION-POC.md b/docs/DIRECTORY-SIMULATION-POC.md index de83225..d68b7b7 100644 --- a/docs/DIRECTORY-SIMULATION-POC.md +++ b/docs/DIRECTORY-SIMULATION-POC.md @@ -471,9 +471,22 @@ no-population-intermediate rule. - **A grant is a relation, not a property.** `(object, trustee, right)` is its own record, like a membership, and changes by add and remove; no node carries a list of trustees. + - **The object.** FullAccess needs a mailbox; a grant of it on anything + else is a violation. SendAs and SendOnBehalf also apply to a + distribution group, which has no mailbox of its own. - **The trustee is a user or a group.** A user holds a right on an object when it is granted to the user or to any group the user belongs - to, transitively. + to, transitively. This depends on nested-group expansion, which dir-sim + does not have yet: a nested group is held by identity and never + expanded (lance-graph `lance-graph-dir-sim/src/snapshot.rs`, W-4 of + lance-graph's HubSPO-rs handover). Until it lands, a grant to a group + reaches only the group's direct members. + - **Deny wins.** Exchange allows deny entries on FullAccess, and Active + Directory allows them on SendAs. A deny for `(object, trustee, right)` + from any witness, for the user or for any group the user belongs to, + removes the right whatever grants exist. A deny that cancels a grant + is reported, so it is visible rather than silent. Reading grants + without denies would fail open. - **Each grant carries the witness that asserted it.** LDIF supplies `publicDelegates` and `msExchDelegateListLink`; Graph supplies none of the three; the Exchange permission output (`Get-MailboxPermission`, @@ -481,13 +494,21 @@ no-population-intermediate rule. and is read through the same read-only encoder as V12. Witnesses that disagree both stay; an absent witness is not a refusal. - **Consumers.** Spear's mailbox IAM lets a FullAccess trustee read the - mailbox's rows. SendAs and SendOnBehalf gate sending: a consumer that - submits through Stalwart picks the identity, and with SendOnBehalf sets - `Sender` to the trustee. - - Not modelled: folder-level permissions (`Add-MailboxFolderPermission`), - calendar delegates, and deny entries, which Exchange allows on - FullAccess. + mailbox's rows. SendAs and SendOnBehalf gate sending, and the consumer + checks the right before every submission; Stalwart does not know about + V17. Stalwart's JMAP submission compares the envelope `mailFrom` with + the identity's address (`crates/jmap/src/submission/set.rs`, + `forbiddenFrom`), and an identity may only carry one of its own + account's addresses (`crates/jmap/src/identity/set.rs`). So: + - **SendOnBehalf** is sent from the trustee's own account and + identity, with `From` set to the object and `Sender` to the trustee. + - **SendAs** cannot be sent from the trustee's account, which has no + identity with the object's address. It is submitted to the object's + own account through master-user impersonation (`object%master`, + `Impersonate` permission), after the V17 check. + + Not modelled: folder-level permissions (`Add-MailboxFolderPermission`) + and calendar delegates. - **V18 — Document access (design, open, 2026-10-10).** Nothing in Spear, dir-sim or Stalwart decides who may read or change a document (HubSPO-rs `comms-api-surface.md` §2). SharePoint and OneDrive grant a role (read, @@ -497,7 +518,13 @@ no-population-intermediate rule. people); Graph reports these as a drive item's `permissions` with `roles`, `grantedToV2`, `link` and `inheritedFrom`. - Proposal, not yet decided: + Two regimes, kept apart: + - **Files attached to a record** (a ticket's or a deal's attachments in + HubSPO-rs) take their access from the record they belong to. They are + not SharePoint items and get no grants of their own. + - **Files in a library or a OneDrive** follow the SharePoint model below. + + Proposal for the second regime, not yet decided: - A grant is a relation `(resource, principal, role)`, as in V17. The resource is a document, folder or drive node with a parent. - A principal's effective role is the highest role granted to it, or to From b7787af96be211be3b32980abb9e569da2d859e8 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 10 Oct 2026 15:46:56 +0000 Subject: [PATCH 3/3] dir-sim plan V18: inheritance from the tree, sharing links keep their scope Graph does not return inheritedFrom for SharePoint and OneDrive for Business, so inheritance is read from the parentReference walk and SharePoint's HasUniqueRoleAssignments flag. A sharing link keeps its scope: only anonymous links admit any holder; organization links need a user signed in to the tenant; users links admit only their named identities. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01G22yT6htkcdyXsihxxXdrg --- docs/DIRECTORY-SIMULATION-POC.md | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/docs/DIRECTORY-SIMULATION-POC.md b/docs/DIRECTORY-SIMULATION-POC.md index d68b7b7..fd26920 100644 --- a/docs/DIRECTORY-SIMULATION-POC.md +++ b/docs/DIRECTORY-SIMULATION-POC.md @@ -513,10 +513,14 @@ no-population-intermediate rule. dir-sim or Stalwart decides who may read or change a document (HubSPO-rs `comms-api-surface.md` §2). SharePoint and OneDrive grant a role (read, write, owner) to a principal on a site, library, folder or item. An item - inherits its parent's grants until inheritance is broken, and sharing - links grant to whoever holds the link (anyone, the organization, or named - people); Graph reports these as a drive item's `permissions` with - `roles`, `grantedToV2`, `link` and `inheritedFrom`. + inherits its parent's grants until inheritance is broken. A sharing link + has a scope: `anonymous` admits whoever holds it, `organization` admits a + user signed in to the same tenant who holds it, and `users` admits only + the people it was granted to. Graph reports a drive item's `permissions` + with `roles`, `grantedToV2`, `grantedToIdentitiesV2` and `link` + (`link.scope`). It does not return `inheritedFrom` for SharePoint and + OneDrive for Business, so the permission list cannot say which ancestor + supplied a grant or where inheritance breaks. Two regimes, kept apart: - **Files attached to a record** (a ticket's or a deal's attachments in @@ -527,10 +531,24 @@ no-population-intermediate rule. Proposal for the second regime, not yet decided: - A grant is a relation `(resource, principal, role)`, as in V17. The resource is a document, folder or drive node with a parent. + - Inheritance comes from the tree, not from `inheritedFrom`. The folder + tree is read by walking each item's `parentReference`, and where + inheritance breaks is read from SharePoint's own flag on each + securable object (`HasUniqueRoleAssignments` in the SharePoint REST + API), with its role assignments read at that object. An item without + unique assignments takes its grants from the nearest ancestor that has + them. Until that flag is read, the grants on an item are its + effective permissions as Graph returns them, with no inheritance + inferred. - A principal's effective role is the highest role granted to it, or to a group it belongs to, on the item or on an ancestor up to the nearest broken inheritance. - - A sharing link is a principal of its own kind. + - A sharing link is a grant that keeps its scope. Holding the link is + never enough on its own: `anonymous` admits any holder, `organization` + admits a holder signed in to the tenant (an external or guest identity + from another tenant is refused), and `users` admits only the identities + in `grantedToIdentitiesV2`, which are evaluated as ordinary principals. + A link is never folded into one shared link principal. - Spear evaluates it with an RBAC plug over the document classid, the way `RBAC_PLUG` covers mail.