feat(groups): transitive group-in-group membership#59859
feat(groups): transitive group-in-group membership#59859KiaraGrouwstra wants to merge 1 commit intonextcloud:masterfrom
Conversation
nickvergessen
left a comment
There was a problem hiding this comment.
Sorry, meant to comment already last week.
I'm having some fear with this change from security and app-ecosystem perspective.
There will be a huge mess if this is not dealt with correctly by each app.
So from my POV the existing API must reflect the state without any changes by calling parties, to ensure no additional/unexpected data/access whatever is leaked.
Server-side encryption
If
apps/encryptionis enabled, nested-group mutations may leave the
key distribution out of sync for effective members gained or lost past
theMAX_SYNTHESIZED_USER_EVENTScap. This is not addressed
automatically; the admin must run a manual re-key pass after bulk
nesting changes on encrypted instances. A prominent warning in
nextcloud.logindicates when this is required.
E.g. this is not acceptable from my POV
e7cbb43 to
f56acad
Compare
|
Hello there, We hope that the review process is going smooth and is helpful for you. We want to ensure your pull request is reviewed to your satisfaction. If you have a moment, our community management team would very much appreciate your feedback on your experience with this PR review process. Your feedback is valuable to us as we continuously strive to improve our community developer experience. Please take a moment to complete our short survey by clicking on the following link: https://cloud.nextcloud.com/apps/forms/s/i9Ago4EQRZ7TWxjfmeEpPkf6 Thank you for contributing to Nextcloud and we hope to hear from you soon! (If you believe you should not receive this message, you can add yourself to the blocklist.) |
Add a group_group edge table maintained by OC\Group\Database, an internal INestedGroupBackend capability interface, and BFS-based transitive closure in OC\Group\Manager with per-request memoization and batched backend queries. Public API gains getUserEffectiveGroupIds, addSubGroup/removeSubGroup, getDirectChildGroupIds/getDirectParentGroupIds, and getGroupEffectiveDescendantIds/getGroupEffectiveAncestorIds. Cycles are rejected inside a serialized transaction. SubGroupAdded/SubGroupRemovedEvent are dispatched along with per-user UserAdded/UserRemovedEvent (bounded by MAX_SYNTHESIZED_USER_EVENTS) so listeners such as apps/encryption stay consistent when nesting shifts the effective recipient set of a group share. See lib/private/Group/NESTED_GROUPS.md for caveats (encryption re-keying cap, LDAP enumeration cost, delete-middle-group semantics). Refs nextcloud#36150. Signed-off-by: Kiara Grouwstra <cinereal@riseup.net>
f56acad to
69f6ee3
Compare
Adds transitive group-in-group membership to the database group backend. A group can be made a direct subgroup of another group via a new
group_group(parent_gid, child_gid)edge table. Membership composes transitively: a user in a subgroup is an effective member of every ancestor.Existing
getUserGroupIds/getUserGroupssemantics are unchanged; a newgetUserEffectiveGroupIdsis introduced for call sites that should honor nesting. OnlyOC\Group\Databaseimplements the new internalINestedGroupBackendcapability interface; LDAP, SAML and other external backends are untouched.Part 1 of a series implementing #36150. Follow-up PRs layer sub-admin delegation, access-check migration, OCS endpoints, and admin UI on top.
What is in this PR
Version34000Date20260410120000-- createsgroup_group(parent_gid, child_gid)andgroup_group_admin(admin_gid, gid)tables.OC\Group\Database--addGroupToGroup/removeGroupFromGroup/getChildGroups/getParentGroups/getChildGroupsBatch/getParentGroupsBatch/groupInGroup/isDescendantOf. Cycle check + insert wrapped in a serialized transaction so concurrent writers cannot race a cycle into existence.OC\Group\Manager-- BFS transitive closure with per-request memoization and batched backend queries (oneWHERE INper BFS level).addSubGroup/removeSubGroupdispatchSubGroupAddedEvent/SubGroupRemovedEventplus per-userUserAddedEvent/UserRemovedEventfor every user who gains or loses effective membership (bounded byMAX_SYNTHESIZED_USER_EVENTS = 500).OCP\IGroupManager:getUserEffectiveGroupIds,addSubGroup/removeSubGroup,getDirectChildGroupIds/getDirectParentGroupIds,getGroupEffectiveDescendantIds/getGroupEffectiveAncestorIds.SubGroupAddedEvent,SubGroupRemovedEvent.CycleDetectedException,NestedGroupsNotSupportedException.lib/private/Group/NESTED_GROUPS.mdcovering concept, cycle prevention, event synthesis, and caveats.Caveats (documented in
NESTED_GROUPS.md)BinA -> B -> Cdrops both edges without splicing.collectEffectiveUserIdswalks descendants viasearchUsers(''); nesting a large LDAP group may block the request.Test plan
tests/lib/Group/NestedGroupsTest.php-- transitive closure, diamond dedup, cycle rejection, idempotent add, event dispatch, cache invalidation, direct-child listing.tests/lib/Group/DatabaseTest.php-- nested CRUD, self-edge rejection, cycle rejection, edge cleanup on group deletion.Checklist
3. to review, feature component)stable32)AI (if applicable)