---
title: AD resource access check (cached)
summary: Evaluates whether the current user is authorized for a named AD resource, caching the outcome so repeat checks avoid re-evaluating the security principal.
status: draft
owner: SAIF Doc Gen
last_reviewed: 2026-07-30
library: SAIF.Application
reference_type: package
operation_id: OP-APP-06
trigger: Calling code invokes HasAccess(resourceName) or CheckAccess(resourceNames) on a UserAccess instance
---

# AD resource access check (cached)

`UserAccess` is an abstract cache wrapper over the framework's `clsSecurityPrincipal.IsAuthorized(...)` check. A concrete subclass supplies the principal through the protected `SetPrincipal(...)` method; callers then ask `HasAccess(resourceName)` (or the multi-resource `CheckAccess(...)`) whether the current principal is authorized for a resource, and the first answer for any given resource name is cached for the life of the `UserAccess` instance.

| Field | Value |
| --- | --- |
| **Operation ID** | OP-APP-06 |
| **Trigger** | Caller invokes `HasAccess(inResourceName)` directly, or `CheckAccess(ParamArray inResourceName())` for one or more resource names |
| **Inputs** | One or more AD resource-name strings; the `clsSecurityPrincipal` set on the subclass via `SetPrincipal(...)` |
| **Outputs** | Boolean authorization outcome for `HasAccess`; `CheckAccess` produces no caller-visible aggregate result (see failure notes) |
| **Primary components** | `UserAccess.HasAccess`, `UserAccess.CheckAccess`, `UserAccess.SetPrincipal`, `clsSecurityPrincipal.IsAuthorized` |
| **Entry point** | `Application\SAIF.Application\UserAccess.vb` |

## Steps

1. **Subclass supplies the principal.** A concrete `UserAccess` subclass calls the protected `SetPrincipal(inPrincipal As clsSecurityPrincipal)` to store the framework security principal used for all subsequent authorization checks on that instance.
2. **Caller checks a single resource.** `HasAccess(inResourceName As String)`:
   1. Looks up `inResourceName.ToLower` in the private `m_AccessControl` sorted list.
   2. If the lower-cased key is already present: returns the cached boolean immediately without calling the principal ([BR-003](../business-rules.md#br-003-authorization-results-are-cached-per-resource-name)).
   3. If the key is not present: calls `m_Principal.IsAuthorized(inResourceName)` (using the **original**, non-lower-cased resource name), stores the result in `m_AccessControl` under the lower-cased key, and returns that result.
      > **Origin**: The actual authorization decision is made by `clsSecurityPrincipal.IsAuthorized(...)`, provided by the `SAIF.BOF.Framework` (`SAIF.BOF.Security`) NuGet package dependency. That package is consumed as a framework dependency rather than a locally documented operation in this repository; its own authorization logic is out of scope for this library's documentation.**
3. **Caller checks multiple resources.** `CheckAccess(ParamArray inResourceName As String())`:
   1. Iterates every supplied resource name and calls `HasAccess(inKey)` for each, reassigning the loop's local `Result` variable to the return value on every iteration — so only the last resource name's result is ever held.
   2. After the loop completes, `Result = Nothing` resets that local variable to `False` (VB.NET's default for `Boolean`).
   3. The method has no return value and does not expose `Result` to the caller in any way — the entire computed value is discarded ([see failure note below]).
4. **Subsequent checks for the same resource are served from cache.** Any later `HasAccess(...)` call for a resource name whose lower-cased form is already a key in `m_AccessControl` skips the principal check entirely, per [BR-003](../business-rules.md#br-003-authorization-results-are-cached-per-resource-name).

## Process flow

The following diagram visualizes the cache-first authorization check and the discarded-result behavior of the batch entry point.

```mermaid
flowchart TD
	Start([Caller requests access check]) --> Which{HasAccess or CheckAccess?}
	Which -->|HasAccess single resource| CacheCheck{Resource already<br>cached lower-cased?}
	CacheCheck -->|Yes| ReturnCached([Return cached boolean])
	CacheCheck -->|No| CallPrincipal[Call clsSecurityPrincipal.IsAuthorized]
	CallPrincipal --> StoreCache[Store result under<br>lower-cased key]
	StoreCache --> ReturnNew([Return new result])
	Which -->|CheckAccess multiple resources| Loop[For each resource name:<br>call HasAccess, overwrite Result]
	Loop --> Reset[Result = Nothing<br>after loop]
	Reset --> Discard([No value returned to caller;<br>only cache side effects persist])
```

## Failure and edge-case behavior

- `CheckAccess(...)` populates the cache as a side effect (each `HasAccess` call inside the loop still caches its own resource), but the method itself exposes no aggregate authorization result — callers who intend to learn "is the user authorized for all of these resources" from `CheckAccess` alone get nothing usable back; they must call `HasAccess` per resource name themselves to read a result.
- The explicit `Result = Nothing` after the loop in `CheckAccess` reinforces that the local variable's final value is intentionally discarded, not returned — this looks like dead code that a caller could mistakenly assume has an effect.*
- `HasAccess` caches on the **lower-cased** resource name but calls `IsAuthorized` with the **original-case** resource name, so if `clsSecurityPrincipal.IsAuthorized` is itself case-sensitive, the cache key normalization does not guarantee that two differently-cased calls for "the same" resource actually reach the principal with identical casing on the first (cache-populating) call.*
- If `SetPrincipal(...)` is never called before `HasAccess(...)` runs, `m_Principal` is `Nothing` and the call to `m_Principal.IsAuthorized(...)` raises a `NullReferenceException`.*

> **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.

## Related documentation

- [Operations and processes](../operations-processes.md)
- [Business rules](../business-rules.md)
- [Security and authorization](../security-authorization.md)
- [Dependencies](../dependencies.md)

## Sources

- `Application\SAIF.Application\UserAccess.vb`
