Enumerate AD group membership¶
This operation is the library's local LDAP traversal workflow and the data source that machine authorization ultimately depends on. It resolves the target AD group, optionally walks nested subgroups, accumulates distinct user accounts while guarding against cycles and duplicates, and returns the sorted sAMAccountName list that authorization logic compares against.
| Field | Value |
|---|---|
| Operation ID | OP-ENV-008 |
| Trigger | Caller requests the users contained in an AD group |
| Inputs | groupName, ldap, domain, recurse |
| Outputs | Distinct sorted string[] of sAMAccountName values, or null |
| Primary components | ADService.GetUsersByGroup, ADService.GetMembership, ADService.GetMembershipRecursively |
| Entry point | SAIF.Framework.Security.EnvironmentApi\Core\Services\ADService.cs |
Steps¶
- Open a
PrincipalContextfor the requested domain and resolve the target group withGroupPrincipal.FindByIdentity. - If the group cannot be found, return
nullwithout throwing, so a caller can distinguish "group does not exist" from "group has no members." - Open a
DirectoryEntryrooted at the supplied LDAP path and begin traversal from the group's distinguished name. - Query direct membership with a
DirectorySearcherfilter of(&(objectClass=<type>)(memberOf=<groupDn>)), loadingobjectGUID,sAMAccountName, anddistinguishedName, and sorting the results bysAMAccountName. - When
recurseistrue, visit subgroup results first, skipping any subgroup name that has already been traversed so nested membership cycles cannot cause infinite or duplicated work. - Visit user results, skipping any user name that has already been yielded so the same account does not appear twice when it belongs to multiple groups in the traversal path.
- Project the collected results to
sAMAccountName, applyDistinct()andOrderBy(), and return the final array that authorization checks consume (BR-006).
Process flow¶
The following diagram visualizes this operation's control flow.
flowchart TD
Start([Caller requests AD group members]) --> Group[Resolve group identity]
Group --> Exists{Group found?}
Exists -->|No| ReturnNull([Return null])
Exists -->|Yes| Root[Open LDAP root]
Root --> Nested{Recurse into subgroups?}
Nested -->|Yes| Walk[Walk unseen subgroups]
Nested -->|No| Users[Read direct users]
Walk --> Users
Users --> Distinct[Deduplicate and sort sAMAccountName values]
Distinct --> End([Return member array])
Failure and edge-case behavior¶
- A missing group returns
nullrather than an empty array, so callers can tell "no such group" apart from "group exists but is empty." - Recursion tracks seen subgroup and user names in separate sets to prevent both infinite cycles and duplicate output.
- The method does not catch LDAP or directory-service exceptions; those propagate to the caller unhandled.
Related documentation¶
Sources¶
- SAIF.Framework.Security.EnvironmentApi\Core\Services\ADService.cs