---
title: Principal identity initialization
summary: Establishes the current web or Windows principal and impersonation context.
status: draft
owner: <owner>
last_reviewed: 2026-07-30
library: SAIF.Framework.Security
reference_type: package
operation_id: OP-001
trigger: `clsSecurityPrincipal` construction or `Instance` access
---

# Principal identity initialization

Every other operation in this library depends on `clsSecurityPrincipal` already knowing who the caller is, so this is the first thing that runs on any request. It chooses between two identity sources — a decrypted Forms authentication ticket for web callers, or the Windows thread/process identity for everyone else — populates the principal from whichever source applies, and, if that identity is accepted as authenticated, impersonates it so later calls run in the caller's security context.

| Field | Value |
| --- | --- |
| **Operation ID** | OP-001 |
| **Trigger** | `clsSecurityPrincipal` construction or `Instance` access |
| **Inputs** | `HttpContext.Current`, `Thread.CurrentPrincipal`, current platform, existing Forms authentication cookie |
| **Outputs** | Populated domain and user fields, base principal and identity, authentication flag, optional impersonation context |
| **Primary components** | `clsSecurityPrincipal.init`, `clsSecurityPrincipal.InitFormsIdentity`, `clsSecurityPrincipal.InitWindowsIdentity` |
| **Entry point** | `SAIF.Framework.Security\clsSecurityPrincipal.vb` |

## Steps

1. `Instance` or the constructor first decides whether to reuse a principal already cached for the current web session or to build a fresh `clsSecurityPrincipal`. `init()` then routes to the Forms-identity path whenever the current thread principal is a `GenericPrincipal` backed by a `FormsIdentity`; every other case falls through to Windows-identity initialization.
   - Authorization context: this routing decision establishes the subject that [Authorization enforcement points](../security-authorization.md#authorization-enforcement-points) later evaluate.
2. On the Forms path, `InitFormsIdentity()` reads the Forms authentication cookie, decrypts the underlying ticket, splits its name into `user` and `domain`, marks the principal authenticated, and builds `WindowsPrincipal` / `WindowsIdentity` objects from the ticket's name so the rest of the library can treat a web login the same way it treats a Windows identity.
   - If `HttpContext` or the cookie is missing: the method leaves the principal's fields unchanged rather than raising an error.
   - On failure: a ticket-decryption exception is not caught locally, so it propagates to the caller.
3. When the Forms path is not selected, `InitWindowsIdentity()` records the `IsProduction` flag, switches the AppDomain's principal policy to `WindowsPrincipal`, clears the cached list of available resources, and picks either `WindowsIdentity.GetCurrent()` or `Thread.CurrentPrincipal` as the base identity, depending on the current platform and the type of principal already attached to the thread.
   - If the caller is on the Windows platform and the thread principal is not already a `WindowsPrincipal`: the method falls back to `WindowsIdentity.GetCurrent()` so the resolved identity is authoritative regardless of what the thread started with.
4. Before the principal is considered usable, the web branch rejects anonymous identities and screens out the built-in `ASPNET` worker account, then backfills `domain\user` into the principal fields — enforcing [BR-004](../business-rules.md#br-004-aspnet-and-anonymous-identities-are-never-authenticated-on-web) so the ASP.NET process identity is never mistaken for a real end user.
   - Authorization context: whether this gate passes determines if subsequent checks in [Programmatic authorization checks](../security-authorization.md#programmatic-authorization-checks) run under an authenticated subject at all.
   - If the identity is anonymous or fails the worker-account gate: the principal remains unauthenticated, and no domain/user values are backfilled.
5. Once authentication succeeds, the resolved base identity is impersonated and the resulting context is stored in `m_ImpersonatedUser`, so downstream authorization calls and any external service calls execute as the caller rather than the hosting process.
   - If authentication did not succeed: no impersonation context is created, and later operations run under whatever identity the host process already had.

## Process flow

The following diagram visualizes this operation's control flow.

```mermaid
flowchart TD
	Start([Principal requested]) --> Mode{Forms identity?}
	Mode -->|Yes| Forms[Decrypt Forms cookie]
	Mode -->|No| Windows[Resolve Windows identity]
	Forms --> Auth{Authenticated?}
	Windows --> Auth
	Auth -->|Yes| Imp[Impersonate base identity]
	Auth -->|No| EndErr([Leave principal unauthenticated])
	Imp --> EndOk([Principal ready])
```

## Failure and edge-case behavior

- A missing Forms authentication cookie leaves the principal uninitialized rather than raising an explicit error.
- Forms ticket decryption failures are not wrapped locally and propagate to the caller.
- Web callers whose resolved identity is anonymous, or matches the `ASPNET` worker account, are left unauthenticated and receive no impersonation context.

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

## Sources
- `SAIF.Framework.Security\clsSecurityPrincipal.vb`
- `SAIF.Framework.Security\AppGlobal.vb`
