Skip to content

SAIF.Framework.SecurityModule architecture

SAIF.Framework.SecurityModule is an ASP.NET IHttpModule-based authentication module that hooks the HttpApplication.AuthenticateRequest pipeline event and orchestrates Windows authentication for hosted web applications, using either an encrypted-cookie fast path or an NTLM/Basic browser challenge depending on whether the requesting host is classified as internal or external.

Responsibilities

  • Plug into the ASP.NET request pipeline via clsSecurityModule.Init, wiring AuthRequest_Handler to HttpApplication.AuthenticateRequest.
  • Determine whether a request's host is "internal" or "external" and route it to the corresponding authentication strategy (InternalUserAuthenticator / ExternalUserAuthenticator).
  • Perform silent re-authentication from an encrypted SAIFAUTH cookie by decrypting it (DPAPI) and exchanging the recovered credentials for a Windows logon token.
  • Fall back to an NTLM/Basic browser credential challenge (internal hosts) or a redirect to a configured login page (external hosts) when cookie authentication fails.
  • Provide cross-cutting DPAPI-based value encryption/decryption (DPAPI) and structured log4net-backed diagnostic logging (mdlLogging) used throughout the module.
  • Handle authentication-flow exceptions, distinguishing benign ThreadAbortExceptions (from Response.Redirect) from real errors, and redirect real errors to a configured error page.

Source: SAIF.Framework.SecurityModule\clsSecurityModule.vb, SAIF.Framework.SecurityModule\Authenticators\UserAuthenticator.vb.

Component boundaries

  • clsSecurityModule (implements System.Web.IHttpModule): pipeline entry point. Registers AuthRequest_Handler on HttpApplication.AuthenticateRequest, catches and routes exceptions to ErrorPage, and owns the sec-errorpage setting. Source: SAIF.Framework.SecurityModule\clsSecurityModule.vb.
  • UserAuthenticator (abstract base) with ExternalUserAuthenticator and InternalUserAuthenticator subclasses: factory-selected (UserAuthenticator.Find) strategy layer that decides internal-vs-external handling and defines the abstract Authenticate(WebContext) contract; also owns the "already authenticated" short-circuit (IsAuthenticated). Source: SAIF.Framework.SecurityModule\Authenticators\UserAuthenticator.vb.
  • CookieAuthenticator: decrypts and validates the SAIFAUTH cookie, obtains a Windows logon token via TokenProvider, and builds/assigns the WindowsIdentity/WindowsPrincipal. Source: SAIF.Framework.SecurityModule\Authenticators\CookieAuthenticator.vb.
  • BrowserAuthenticator: issues the HTTP 401 response with WWW-Authenticate (NTLM/configured type, plus Basic realm="SAIF") to trigger a native browser credential prompt for internal hosts when cookie authentication fails. Source: SAIF.Framework.SecurityModule\Authenticators\BrowserAuthenticator.vb.
  • TokenProvider (Friend-scoped): wraps Win32 LogonUser/DuplicateToken/token-release P/Invoke calls (advapi32.dll, Kernel32.dll) to exchange decrypted credentials for a Windows token. Source: SAIF.Framework.SecurityModule\TokenProvider.vb.
  • DPAPI: wraps Win32 CryptProtectData/CryptUnprotectData (crypt32.dll) for encrypting/decrypting the SAIFAUTH cookie value and other secrets. Source: SAIF.Framework.SecurityModule\DAPIEncrypt.vb.
  • mdlLogging: shared log4net-backed logging facility (Log, LogInfo/LogWarn/LogError/LogDebug) consumed by every class in the module, formatting entries with host address, request URL, application name, and a reflection-derived call-stack trail. Source: SAIF.Framework.SecurityModule\mdlLogging.vb.

This is a leaf/utility library: its .vbproj contains no <ProjectReference> elements to other SAIF.Framework.* projects.*

Interaction model

  • The module is consumed by hosting ASP.NET web applications, which register clsSecurityModule in Web.config's <httpModules>/<system.webServer><modules> section (inferred from the IHttpModule implementation; no consumer Web.config exists inside this library's own folder to confirm registration).**
  • Control flow on each request: clsSecurityModule.AuthRequest_Handler → UserAuthenticator.IsAuthenticated (short-circuit if already authenticated) → UserAuthenticator.Find(host, ExternalHostNames) selects ExternalUserAuthenticator or InternalUserAuthenticator → concrete Authenticate(WebContext) calls CookieAuthenticator.Authenticate → CookieAuthenticator decrypts the SAIFAUTH cookie via DPAPI.Decrypt and calls TokenProvider.GetToken → a WindowsIdentity/WindowsPrincipal is assigned to HttpContext.Current.User.
  • On cookie-authentication failure, ExternalUserAuthenticator redirects to the configured login page (sec-loginpage); InternalUserAuthenticator falls back to BrowserAuthenticator.Authenticate, issuing an HTTP 401 NTLM/Basic challenge.
  • Every class in the module calls into mdlLogging for diagnostic logging, and DPAPI/TokenProvider are invoked only from CookieAuthenticator within this control flow.
  • Exceptions raised anywhere in the try block of AuthRequest_Handler are caught: ThreadAbortException (from Response.Redirect) is suppressed via Thread.ResetAbort(), and all other exceptions redirect to ErrorPage (sec-errorpage) with the exception message appended.

Source: SAIF.Framework.SecurityModule\clsSecurityModule.vb, SAIF.Framework.SecurityModule\Authenticators\UserAuthenticator.vb, SAIF.Framework.SecurityModule\Authenticators\CookieAuthenticator.vb, SAIF.Framework.SecurityModule\Authenticators\BrowserAuthenticator.vb, SAIF.Framework.SecurityModule\TokenProvider.vb, SAIF.Framework.SecurityModule\DAPIEncrypt.vb.

The following diagram shows the high-level component interactions within the authentication pipeline.

flowchart TD
    A[clsSecurityModule<br>IHttpModule] --> B[UserAuthenticator<br>factory / IsAuthenticated]
    B --> C[ExternalUserAuthenticator]
    B --> D[InternalUserAuthenticator]
    C --> E[CookieAuthenticator]
    D --> E
    E --> F[DPAPI<br>Decrypt SAIFAUTH cookie]
    E --> G[TokenProvider<br>Win32 LogonUser]
    C --> H[Login page redirect]
    D --> I[BrowserAuthenticator<br>NTLM/Basic 401 challenge]
    A --> J[mdlLogging<br>log4net diagnostics]
    E --> J
    G --> J
    F --> J
    I --> J

Sequence diagram

The following diagram shows the primary request authentication sequence, including the cookie fast path and browser-challenge fallback.

sequenceDiagram
    participant Client
    participant clsSecurityModule
    participant UserAuthenticator
    participant CookieAuthenticator
    participant TokenProvider
    participant BrowserAuthenticator

    Client->>clsSecurityModule: HTTP request (AuthenticateRequest)
    clsSecurityModule->>UserAuthenticator: IsAuthenticated / Find(host)
    UserAuthenticator->>CookieAuthenticator: Authenticate(WebContext)
    CookieAuthenticator->>CookieAuthenticator: DPAPI.Decrypt(SAIFAUTH cookie)
    CookieAuthenticator->>TokenProvider: GetToken(username, password)
    TokenProvider-->>CookieAuthenticator: Windows token or failure
    CookieAuthenticator-->>UserAuthenticator: WindowsPrincipal or failure
    alt Cookie auth failed, external host
        UserAuthenticator-->>Client: Redirect to sec-loginpage
    else Cookie auth failed, internal host
        UserAuthenticator->>BrowserAuthenticator: Authenticate(response, authType)
        BrowserAuthenticator-->>Client: HTTP 401 WWW-Authenticate NTLM/Basic
    else Cookie auth succeeded
        clsSecurityModule-->>Client: Request proceeds authenticated
    end

Design constraints

  • No <ProjectReference> dependencies exist on other SAIF.Framework.* projects; the module is a self-contained leaf library.*
  • The library targets .NET Framework v3.5 and depends on unmanaged Win32 APIs (advapi32.dll, Kernel32.dll for logon/token handling; crypt32.dll for DPAPI), which ties authentication to the Windows platform and machine/user DPAPI key scope.
  • Authentication behavior is driven by AppSettings keys (sec-errorpage, ExternalHostNames, sec-loginpage, sec-browser-authtype, sec-logindomain) read via ConfigurationManager.AppSettings, with code-level fallback defaults; no consumer Web.config exists in this library's own folder to confirm final registered values.*
  • Host classification as "external" uses a case-insensitive substring match against the ExternalHostNames setting, directly determining which fallback path (login redirect vs. NTLM/Basic challenge) is used.
  • ThreadAbortExceptions raised by Response.Redirect inside the authentication handler are explicitly suppressed via Thread.ResetAbort() so that normal redirects are not misreported as authentication errors.
  • Assembly carries a SecurityPermissionAttribute(SecurityAction.RequestMinimum, UnmanagedCode:=True) attribute (declared in clsSecurityModule.vb and again in DAPIEncrypt.vb), reflecting the module's reliance on unmanaged P/Invoke calls; TokenProvider.GetToken additionally carries a method-level SecurityPermissionAttribute(SecurityAction.Assert, ...).

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

  • SAIF.Framework.SecurityModule\clsSecurityModule.vb
  • SAIF.Framework.SecurityModule\Authenticators\UserAuthenticator.vb
  • SAIF.Framework.SecurityModule\Authenticators\CookieAuthenticator.vb
  • SAIF.Framework.SecurityModule\Authenticators\BrowserAuthenticator.vb
  • SAIF.Framework.SecurityModule\TokenProvider.vb
  • SAIF.Framework.SecurityModule\DAPIEncrypt.vb
  • SAIF.Framework.SecurityModule\mdlLogging.vb
  • SAIF.Framework.SecurityModule\SAIF.Framework.SecurityModule.vbproj