Skip to content

OP-015: Authorize a user for a role, trying the internal domain first

IsAuthorized 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-015
Trigger Caller invokes IsAuthorized over the Security route.
Entry operation IsAuthorized
Owning component SAIF.Services.WCF.Services.Security.SecurityService.IsAuthorized
Inputs Request message parts listed below
Outputs Whether userId is authorized for role.
Failure behavior Generic SOAP fault, per Faults and error pipeline

Request and response

Direction Element Type Declared in Notes
Request userId string BCL (System) Account to check; validated non-blank. (Yes)
Request role string BCL (System) Role/group name to check; validated non-blank. (Yes)
Response bool bool BCL (System) Whether userId is authorized for role.

Steps

  1. Constructor reads LOG_REQUEST_DETAILS and LDAP_EXTERNAL_KEY from appSettings inside an empty catch, resolves the external LDAP host from the environment with a literal fallback, opens the Oracle EXTUR unit of work, constructs UserFactory, and calls AuthorizationCacheService.Init when the cache is not ready (BR-WCF-018, BR-WCF-029).
  2. LogRequestDetails appends the operation name and its arguments to the IIS log (BR-WCF-032).
  3. IsAuthorized delegates to IsAuthorized2(userId, role, true) (BR-WCF-030).
  4. Enforce.ArgumentNotNullOrWhiteSpace on userId and role; the third guard passes role under the label "domain", so domain is never actually validated (BR-WCF-023).
  5. Because tryInternalDomainFirst is true, IsAuthorizedInternal asks AuthorizationCacheService.IsAuthorized for the Internal domain; on a cache miss it constructs a WindowsIdentity for {userId}@corp.saif.com, confirms the returned SAM name matches case-insensitively, and evaluates WindowsPrincipal.IsInRole(role) (BR-WCF-030). A SecurityException indicating a disabled account returns false; one indicating a bad user name or password falls through to the external check; anything else rethrows (BR-WCF-031).
  6. When the internal answer is false, IsAuthorizedExternal asks the cache for the External domain; on a miss it opens a PrincipalContext against the mutable ldap_external field, resolves the group and the user, returns false for a missing group, a missing user, or an explicitly disabled account, and otherwise evaluates user.GetAuthorizationGroups().Contains(group) (BR-WCF-030, BR-WCF-031).
  7. AuthorizationCacheService.IsAuthorized caches the result in HttpContext.Current.Cache under a hash of {user}@{domain}/{role} with the per-domain TTL, absolute expiration, NoSlidingExpiration, Normal priority (BR-WCF-029). With no HttpContext, the cache is bypassed entirely in both directions.
  8. Return the boolean.
  9. On failure: directory exceptions other than the two handled SecurityException shapes are logged by the installed error handler and surfaced as a generic SOAP fault with exception detail included.

Process flow

The following diagram visualizes this process's control flow.

flowchart TD
    A["Initialize dependencies and<br>authorization cache"]
    B["Log request details"]
    C["Delegate to IsAuthorized2<br>(try internal domain first)"]
    D["Validate userId and role"]
    E["Check internal-domain<br>authorization cache"]
    E1{"Internal domain: cache hit?"}
    E2["Cache miss: check Windows role<br>membership via WindowsIdentity"]
    E3{"SecurityException raised?"}
    E4["Disabled account: return false"]
    E5["Bad user name or password:<br>fall through to the external check"]
    E6["Anything else: rethrow"]
    E7{"Internal answer"}
    F["Check external cache; on miss,<br>resolve AD user/group and account status"]
    G["Cache the authorization result"]
    H["Return the boolean."]
    A --> B
    B --> C
    C --> D
    D --> E
    E --> E1
    E1 -->|"Yes"| E7
    E1 -->|"No"| E2
    E2 --> E3
    E3 -->|"Disabled account"| E4
    E3 -->|"Bad user name or password"| E5
    E3 -->|"Other"| E6
    E5 --> F
    E4 --> F
    E2 -->|"No exception"| E7
    E7 -->|"true"| G
    E7 -->|"false"| F
    F --> G
    G --> H

Transaction and side effects

Aspect Finding
Unit of work OracleUnitOfWorkFactory (EXTUR), opened but not used for this decision path
Commit point Not applicable
Records written None for this path
Downstream calls Active Directory (corp.saif.com and the external LDAP host); ASP.NET HttpContext.Current.Cache
Shared state touched Reads and, on a cache miss, mutates the process-wide AuthorizationCacheService cache and the mutable ldap_external field
Repeat-call behavior A cached result short-circuits the directory calls for the TTL window

Logging

Surface Written content
HttpContext.Current.Response.AppendToLog (LogRequestDetails) Writes IIS request-detail log lines when LOG_REQUEST_DETAILS is enabled; populates the shared authorization cache
ErrorLogErrorHandler → LogService Failure-path exception logging only, carrying method signature, calling user and exception detail; see Faults and error pipeline

Faults and error handling

Failure Fault type the caller receives Produced by Source
SecurityException (uncategorized) Generic SOAP fault The ErrorLogErrorHandler installed by [LogErrorBehavior] src/WCF/SAIF.Services.WCF.Host/Services/Security/SecurityService.cs
Directory or Oracle/NHibernate exception Generic SOAP fault The ErrorLogErrorHandler installed by [LogErrorBehavior] src/WCF/SAIF.Services.WCF.Host/Services/Security/SecurityService.cs

Authorization

Requirement Enforced by Source Applies to
None in code IIS authentication on the deployment (see Activation and hosting) src/WCF/SAIF.Services.WCF.Host/Services/Security/SecurityService.cs This operation

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/WCF/SAIF.Services.WCF.Host/Services/Security/SecurityService.cs