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.
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).
LogRequestDetails appends the operation name and its arguments to the IIS log (BR-WCF-032).
IsAuthorized delegates to IsAuthorized2(userId, role, true) (BR-WCF-030).
Enforce.ArgumentNotNullOrWhiteSpace on userId and role; the third guard passes role under the label "domain", so domain is never actually validated (BR-WCF-023).
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).
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).
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.
Return the boolean.
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.
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
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.