Skip to content

IsUserInGroup (OP-18)

Request and response

Part Type Description
inUserId String The SamAccountName to look up.
inGroupName String The group's SamAccountName to look up.
inExternalDomain Boolean Selects external.saif.com when True, corp.saif.com when False (BR-07) for both the user and the group lookup.
Part Type Description
<return> ADServiceResponse Response (EResponse code) and Message (the literal "True" or "False" on success).

WebMethod attributes

<WebMethod()> — bare, no arguments supplied.

Steps

  1. No access check is performed (BR-06).
  2. Initialize myStruc.Response = Success, myStruc.Message = String.Empty.
  3. In a Try block, call H2 GetUserPrincipal with the caller-supplied inExternalDomain.
  4. If the principal is Nothing, set Response = UserDoesNotExist.
  5. Otherwise, call H3 GetGroupPrincipal with inGroupName and inExternalDomain.
  6. If the group principal is Nothing, set Response = GroupDoesNotExist.
  7. Otherwise, set Message = "True" when groupPrin.Members.Contains(userPrin), else Message = "False" (BR-32). This checks direct membership only.
  8. This differs from DoesUserHaveResource (OP-08), which walks transitive authorization groups via GetAuthorizationGroups: a user entitled only through a nested group answers "False" here even though DoesUserHaveResource would answer "True" for the same user and group — an inconsistent membership semantic across the two operations (SEC-17, HIGH — see Authentication and authorization and Tech debt).
  9. Catch: set Response = Failure, Message = ex.Message.
  10. Finally: release groupPrin and userPrin.
  11. Return the ADServiceResponse sentinel.

Process flow

flowchart TD
    A["Call IsUserInGroup"] --> B["GetUserPrincipal<br>caller-selected domain"]
    B -->|"Nothing"| C["Response = UserDoesNotExist"]
    B -->|"Found"| D["GetGroupPrincipal<br>caller-selected domain"]
    D -->|"Nothing"| E["Response = GroupDoesNotExist"]
    D -->|"Found"| F{"groupPrin.Members<br>.Contains(userPrin)?<br>direct only"}
    F -->|"Yes"| G["Message = True"]
    F -->|"No"| H["Message = False"]
    B -->|"Exception"| I["Response = Failure<br>Message = ex.Message"]
    C --> J["Return ADServiceResponse"]
    E --> J
    G --> J
    H --> J
    I --> J

Shared state effects

None — this operation touches no process-wide state; all locals are per-request.

Error handling

This operation never faults: an unresolved user, an unresolved group, or any other directory exception is caught and mapped to Response = Failure with ex.Message in Message. See Faults for the service-wide fault model.

Authorization

None in code. This is one of the eleven ungated operations that disclose directory data to any caller who can reach the endpoint. Its direct-only membership semantic also disagrees with DoesUserHaveResource's transitive semantic for the same underlying question (SEC-17, see Authentication and authorization and Tech debt).

Sources

  • src\ADUserServices\clsADUserServices.asmx.vb (lines 715-750)