Skip to content

CheckAccess (OP-19)

Request and response

Part Type Description
(none) — This operation takes no parameters.
Part Type Description
<return> HasAccessResponse Public fields HasAccess (Boolean), Local (Boolean), EnvironmentApi (Boolean), RemoteAddress (String).

WebMethod attributes

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

Steps

  1. Initialize HasAccess = False, Local = False, EnvironmentApi = False.
  2. Set RemoteAddress = GetIncomingIp(), which reads the HTTP_X_FORWARDED_FOR server variable, falling back to REMOTE_ADDR only when that header is null or empty (BR-04) — spoofable, with no trusted-proxy validation (SEC-03, HIGH — see Authentication and authorization).
  3. If HttpContext.Current.Request.IsLocal, set HasAccess = True, Local = True (BR-02) — an unconditional local-request bypass (SEC-11).
  4. Call GetAllowedIPs(): constructs New WebEnvironmentService("aduserservices"), reads the aduserservices.allowedips configuration setting, and splits it on "," into a list. There is no null/empty guard (TD-12, MEDIUM — a missing or unreachable setting propagates as an exception; see Tech debt and Configuration).
  5. For each entry in the allow-list, call GetIncomingIp() again — re-reading the incoming IP rather than reusing the value already computed for RemoteAddress (TD-09, LOW inefficiency; see Tech debt) — and compare for exact, case-sensitive string equality. On a match, set HasAccess = True, EnvironmentApi = True (BR-03).
  6. Return the HasAccessResponse.

Process flow

flowchart TD
    A["Call CheckAccess"] --> B["Init HasAccess/Local/<br>EnvironmentApi = False"]
    B --> C["RemoteAddress =<br>GetIncomingIp"]
    C --> D{"Request.IsLocal?"}
    D -->|"Yes"| E["HasAccess = True<br>Local = True"]
    D -->|"No"| F["GetAllowedIPs<br>from configuration"]
    E --> F
    F --> G["For each allow-list entry"]
    G --> H{"entry = GetIncomingIp<br>re-read, exact match?"}
    H -->|"Yes"| I["HasAccess = True<br>EnvironmentApi = True"]
    H -->|"No"| G
    I --> J["Return HasAccessResponse"]
    G -->|"loop done"| J

Shared state effects

None — this operation touches no process-wide state. HasAccessResponse fields are local return values constructed per request, not shared state.

Error handling

This operation has no Try/Catch anywhere in its body. If the environment service is unavailable or aduserservices.allowedips is missing, the resulting exception propagates as a framework SOAP fault — whether CheckAccess is invoked directly as this operation, or indirectly via H4 from within any of the eight gated operations that call it first. See Faults for the service-wide fault model.

Authorization

This operation has none — because it is the access-control primitive that every gated operation calls first. It is itself published and unauthenticated, making it an oracle a caller can use to probe the allow-list (SEC-04, MEDIUM). See Authentication and authorization for the full mechanism description; this page documents only CheckAccess's own steps.

Sources

  • src\ADUserServices\clsADUserServices.asmx.vb (lines 752-796)