Skip to content

Operations and processes

clsADUserServices implements 19 processes, one per published WebMethod, with no dispatcher or handler class between the SOAP entry point and the process logic — every operation calls its own process directly. Eight processes are gated by the network-origin allow-list documented in Authentication and authorization; the other eleven are directory reads and oracles with no application-layer gate. All processing is against Active Directory; there is no database and no process-wide shared state (see Architecture).

This page is the process catalog and hub. Each process's detailed, step-by-step logic lives in its own page under operations/.

Process catalog

ID Process Entry operation Trigger Owning component Rules
OP-01 Hello World greeting HelloWorld Any SOAP call clsADUserServices.HelloWorld —
OP-02 Create AD account AddUser Caller requests account creation clsADUserServices.AddUser BR-01, BR-05, BR-07–BR-13, BR-34
OP-03 Unlock AD account UnlockAccount Caller requests unlock clsADUserServices.UnlockAccount BR-01, BR-14, BR-15
OP-04 Grant group membership AddUserToGroup Caller requests membership grant clsADUserServices.AddUserToGroup BR-01, BR-16, BR-17, BR-33
OP-05 Delete AD account DeleteUser Caller requests deletion clsADUserServices.DeleteUser BR-01, BR-18
OP-06 Revoke group membership DeleteUserFromGroup Caller requests membership revocation clsADUserServices.DeleteUserFromGroup BR-01, BR-19, BR-20
OP-07 Test account existence DoesUserExist Caller queries existence clsADUserServices.DoesUserExist BR-06, BR-21
OP-08 Test transitive resource membership DoesUserHaveResource Caller queries resource membership clsADUserServices.DoesUserHaveResource BR-06, BR-22
OP-09 Update account attributes ChangeUserAccount Caller requests an attribute change clsADUserServices.ChangeUserAccount BR-01, BR-13, BR-23, BR-24
OP-10 Reset password (sentinel on failure) ChangeUserPassword Caller requests a password reset clsADUserServices.ChangeUserPassword BR-01, BR-25, BR-26
OP-11 Reset password (faulting variant) ChangeUserPasswordOrGetException Caller requests a password reset and wants failures as faults clsADUserServices.ChangeUserPasswordOrGetException BR-01, BR-25, BR-26
OP-12 Read email attribute GetUserEmail Caller queries email clsADUserServices.GetUserEmail BR-06, BR-27
OP-13 Read all group names GetUserGroups Caller queries group membership clsADUserServices.GetUserGroups BR-06, BR-28
OP-14 Read filtered resource group names GetUserResources Caller queries resource entitlements clsADUserServices.GetUserResources BR-06, BR-29
OP-15 Read fax attribute GetUserFAX Caller queries fax number clsADUserServices.GetUserFAX BR-06, BR-27
OP-16 Read last-logon timestamp GetUserLastLogon Caller queries last logon clsADUserServices.GetUserLastLogon BR-06, BR-30
OP-17 Read printer attribute (internal domain only) GetUserPrinter Caller queries printer assignment clsADUserServices.GetUserPrinter BR-06, BR-31
OP-18 Test direct group membership IsUserInGroup Caller queries direct membership clsADUserServices.IsUserInGroup BR-06, BR-32, BR-33
OP-19 Evaluate allow-list decision CheckAccess Any SOAP call to CheckAccess, or internally from each of the eight gated operations clsADUserServices.CheckAccess BR-02–BR-04, BR-06

Cross-process flow diagram

The diagram below traces how a caller's operation request is routed through the OP-19 CheckAccess gate to either a mutating process or a read process, both of which operate against Active Directory.

flowchart TD
    Caller["SOAP caller"] --> Gate{"Gated operation?<br>OP-02 OP-03 OP-04 OP-05<br>OP-06 OP-09 OP-10 OP-11"}
    Gate -->|"Yes"| CheckAccess["OP-19 CheckAccess<br>local request or IP allow-list"]
    CheckAccess -->|"Denied"| Denied["AccessDenied sentinel<br>Response = Failure"]
    CheckAccess -->|"Approved"| Mutate["Execute mutating process<br>against external.saif.com"]
    Gate -->|"No — read operation<br>OP-01 OP-07 OP-08 OP-12-18"| Read["Execute read process<br>against caller-selected domain"]
    Mutate --> AD["Active Directory"]
    Read --> AD
    AD --> Response["ADServiceResponse / Boolean / ArrayList<br>returned to caller"]
    Denied --> Response

Failure and edge-case behavior

  • Access denied (OP-02–OP-06, OP-09–OP-11): caller receives ADServiceResponse{Response=Failure, Message="Access Denied"} as a normal SOAP response, never a fault — see Faults and error pipeline.
  • Allow-list setting missing or environment service unreachable (any gated operation, via OP-19): the unhandled exception propagates as a framework SOAP fault out of the calling operation instead of returning AccessDenied — see Tech debt TD-12.
  • User not found (most operations): reported as UserDoesNotExist, False, or an empty list depending on the operation's return shape — the same signal a genuine directory failure produces via BR-34, so "not found" and "directory unreachable" are indistinguishable to the caller.
  • Group removal or resource lookup failure (OP-06, OP-08): DeleteUserFromGroup's catch block deliberately swallows any exception and reports Success (TD-20); DoesUserHaveResource has no Try/Catch at all and a directory failure surfaces as a framework SOAP fault.
  • No transactional rollback across two-stage writes (OP-02 AddUser, OP-09 ChangeUserAccount): neither process opens a database transaction — there is no database — and each of userPrin.Save()/principal-level Save() and dirEntry.CommitChanges()/directory-level CommitChanges() commits independently, with no enclosing transaction and no rollback trigger; a failure between the two stages leaves the object partially applied in Active Directory, a tech-debt finding rather than a documented recovery mechanism (TD-18).
  • Partial write on exception (OP-02 AddUser): a caught Save() failure sets Response = Failure but execution continues into the directory-attribute block, operating on an unsaved principal (TD-18).
  • Silent no-op on commit (OP-09 ChangeUserAccount): a request that changes only company and/or info never sets the modified flag, so CommitChanges() is skipped while the caller still receives Success (TD-19).
  • Empty-catch swallow (OP-13 GetUserGroups, OP-14 GetUserResources): any directory failure yields an empty ArrayList, indistinguishable from "user has no groups/resources" (TD-21).

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.

Sources

  • src\ADUserServices\clsADUserServices.asmx.vb
  • .saifdocgen\state\runs\20260922-101326-aduserservices\analysis\aduserservices-analysis.md