---
title: Establish the security principal
summary: Establishes or reuses the authenticated clsSecurityPrincipal on the model context, or challenges/denies an unauthenticated caller.
status: draft
owner: SAIF Doc Gen
last_reviewed: 2026-08-17
library: SAIF.Presentation.Web.MVC
reference_type: package
operation_id: OP-MVC-02
trigger: Step 4 of Initialize a request; also callable directly by derived controllers
---

# Establish the security principal

Confirms the caller's identity and records it on the model context so downstream operations can rely on a single, already-authenticated principal for the lifetime of the request. This operation performs no Active Directory group lookup itself — it only reads the infrastructure-supplied `WindowsIdentity`/`clsSecurityPrincipal` — and never runs twice for the same model instance.

| Field | Value |
| --- | --- |
| **Operation ID** | OP-MVC-02 |
| **Trigger** | Step 4 of [Initialize a request](initialize-request.md); also callable by derived controllers |
| **Inputs** | `Model.Context.SecurityPrincipal`, `Request.UserHostAddress` |
| **Outputs** | Populated `Context.SecurityPrincipal`; `STYPE` cookie; or a 401 challenge / thrown exception |
| **Primary components** | `clsControllerBase.SecurityCheck` |
| **Entry point** | SAIF.Presentation.Web.MVC/clsControllerBase.vb |

## Steps

1. If the model context already holds a security principal, do nothing — the principal is established once per model ([BR-MVC-004](../business-rules.md#br-mvc-004-every-request-carries-a-single-established-security-principal)).
2. Otherwise construct `New clsSecurityPrincipal(clsSecurityPrincipal.Platform.Web)`.
3. If `IsAuthenticated`, assign it to `Model.Context.SecurityPrincipal`, ensure an `STYPE` response cookie exists, and set its value to the upper-cased user name — empty string when the user name is `Nothing` ([BR-MVC-004](../business-rules.md#br-mvc-004-every-request-carries-a-single-established-security-principal), [BR-MVC-014](../business-rules.md#br-mvc-014-the-authenticated-user-name-is-exposed-via-the-stype-cookie)).
4. Else if `clsEnvironment.InternalAddress(Request.UserHostAddress)` is true, buffer and clear the response, set status `401 Not Authorized`, append `WWW-Authenticate: NTLM` and `WWW-Authenticate: Basic realm="SAIF"`, and end the response — forcing an integrated-authentication challenge ([BR-MVC-005](../business-rules.md#br-mvc-005-unauthenticated-callers-are-challenged-or-refused-by-network-zone)).
   - On failure: none — this path always ends the response.
5. Else throw `New Exception("Not Authorized.")`, which surfaces through `Page_Error` → `ProcessError` → `HandleErrors` ([BR-MVC-005](../business-rules.md#br-mvc-005-unauthenticated-callers-are-challenged-or-refused-by-network-zone)).
   - On failure: exception propagates into [Page error processing](page-error-processing.md) and ultimately [Central error handling](central-error-handling.md).

## Process flow

The following diagram visualizes this operation's control flow.

```mermaid
flowchart TD
	Start([SecurityCheck]) --> S1{Principal already set?}
	S1 -->|Yes| EndOk([No-op])
	S1 -->|No| S2[New clsSecurityPrincipal]
	S2 --> S3{IsAuthenticated?}
	S3 -->|Yes| S4[Set Context.SecurityPrincipal + STYPE cookie]
	S3 -->|No, internal address| S5([401 NTLM/Basic challenge])
	S3 -->|No, external address| S6([Throw Not Authorized])
	S4 --> EndOk2([Continue])
```

## Failure and edge-case behavior
- Internal unauthenticated callers are challenged (401) rather than denied outright, expecting the browser to retry with integrated credentials.
- External unauthenticated callers receive a thrown exception rather than a challenge, since NTLM negotiation is not expected across the public boundary.

## Related documentation
- [Operations and processes](../operations-processes.md)
- [Business rules](../business-rules.md)

## Sources
- SAIF.Presentation.Web.MVC/clsControllerBase.vb
