OP-024: Expand group membership from Active Directory, optionally recursive and optionally including disabled accounts¶
GetUsersByGroup is invoked over the Security route on SAIF.Services.WCF.Services.Security.SecurityService; this page documents the process end to end, from route dispatch to the message the caller receives.
Field
Value
Operation ID
OP-024
Trigger
Caller invokes GetUsersByGroup over the Security route.
LogRequestDetails logs the operation name and arguments (BR-WCF-032).
new ADService(), then GetUsersByGroup: open a PrincipalContext on the supplied domain (default "saif") and resolve the group; a missing group returns null, not an empty array (BR-WCF-035).
Open a DirectoryEntry on the supplied ldap string and run GetMembershipRecursively with a DirectorySearcher filter of "(&(objectClass=" + objectClass + ")(memberOf=" + groupDn + "))", PageSize = 1000, SizeLimit = 0, sorted by sAMAccountName (BR-WCF-036).
When recurse is true, nested groups are expanded depth-first with a visited-group list preventing cycles (BR-WCF-037).
Unless includeDisabled, each user's userAccountControl is converted to binary and the second-from-last bit tested; a set bit means disabled and the user is skipped (BR-WCF-038).
Project sAMAccountName, then .Distinct().OrderBy(x => x).ToArray() (BR-WCF-039).
Return.
On failure: a directory exception is logged by the installed error handler and surfaced as a generic SOAP fault with exception detail included.
The following diagram visualizes this process's control flow.
flowchart TD
A["Log request details"]
B["Resolve group via ADService"]
B1{"Group resolved?"}
B2["Missing group: return null,<br>not an empty array"]
C["Search directory for group members"]
D1{"recurse"}
D["Expand nested groups (recursive)"]
D2["Nested groups are not expanded"]
E1{"includeDisabled"}
E["Filter out disabled accounts"]
E2["Disabled accounts are not<br>filtered out"]
F["Deduplicate and sort account names"]
G["Return."]
A --> B
B --> B1
B1 -->|"No"| B2
B1 -->|"Yes"| C
B2 --> G
C --> D1
D1 -->|"true"| D
D1 -->|"false"| D2
D --> E1
D2 --> E1
E1 -->|"false"| E
E1 -->|"true"| E2
E --> F
E2 --> F
F --> G
Note: Statements marked with * were inferred from code structure, naming
conventions, or contextual evidence where direct confirmation was not available
in source artifacts. Statements marked with ** could not be confirmed; treat
as unknown until verified.