SAIF.NetCore.LegacyAuth architecture¶
SAIF.NetCore.LegacyAuth is a narrow bridging library that lets an ASP.NET Core application issue the legacy SAIFAUTH credential cookie — the user's name and password, DPAPI-encrypted with the Windows machine key and client-IP entropy — so that a legacy .NET Framework component referred to in source as "SecurityModule" can authenticate the user on the same host; it is not itself an ASP.NET Core authentication handler, and it never reads or validates a request cookie.
Responsibilities¶
- Build the tab-delimited
user/passwordpayload and encrypt it with the Windows Data Protection API (DPAPI), scoped to the local machine key and bound to the client's remote IP address as entropy. - Write the encrypted value as a raw, non-URL-encoded
Set-Cookie: SAIFAUTH=<DPAPI-encrypted-Base64-value>response header so the legacy reader can decrypt it without first URL-decoding. - Provide a
ClearCookieoperation that deletes theSAIFAUTHcookie using framework-default delete options. - Expose a small, independently reusable DPAPI encrypt wrapper (
DPAPI) over the nativecrypt32.dllP/Invoke surface, including Win32 interop structs.
Component boundaries¶
ILegacyAuthCookieService/LegacyAuthCookieService: the cookie service — builds the credential payload, encrypts it, and writes or deletes theSet-Cookieheader. Depends onIHttpContextAccessor(framework) andIOidcSettings(SAIF.NetCore.ServiceContracts, injected but never read — verified directly in source).DPAPI: a self-contained P/Invoke wrapper overCryptProtectData/CryptUnprotectDatawith UTF-8 + Base64 string helpers. Its managedDecryptstring/byte overloads areinternaland unreachable from any consumer in this repository, but both raw native externs —CryptProtectDataandCryptUnprotectData— are declaredpublic static extern, so the raw decryption capability remains publicly reachable even though the convenience wrapper is not.KeyType,DATA_BLOB,CRYPTPROTECT_PROMPTSTRUCT: supporting enum and Win32 interop structs used byDPAPI.- Contract boundary:
IOidcSettingsis declared in SAIF.NetCore.ServiceContracts and implemented by SAIF.NetCore.OIDC; this library only consumes the interface (and does not invoke any member on it).
Interaction model¶
- A consuming web application (inferred to be a login application such as "OnlineLogin"**, since no consumer exists in this repository) registers
ILegacyAuthCookieService,IHttpContextAccessor, andIOidcSettingsitself — this library ships noIServiceCollectionregistration extension. - After the application authenticates a user through its normal login flow (inferred to be OIDC-based, per an excluded source comment referencing "OnlineLogin"), it calls
SetCookie(user, password)while the plaintext password is still available, which encrypts the credential pair with DPAPI and appends theSAIFAUTHheader to the current response. - The legacy "SecurityModule" reader, which lives outside this repository, must run on the same Windows machine as the issuing application (DPAPI machine-key scope) and must supply the same client IP as entropy to decrypt the cookie**.
SAIF.NetCore.ServiceExtensions'LegacyBolAuthMiddlewareis a related but independent mechanism: it checks only for the presence of aSAIFAUTH/SAIF.BOL.Authrequest cookie and redirects if absent, without referencing this package or decrypting the value — the two libraries share only the cookie-name convention.- This library makes no API (HTTP/SOAP) calls; its only outbound calls are to the native Windows DPAPI and to ASP.NET Core's own response-header and cookie APIs.
Architecture diagram¶
The following diagram shows the cookie-issuance flow from a consuming application's login handler through DPAPI encryption to the response header.
flowchart TD
A["Consuming app:<br>user authenticates"] --> B["LegacyAuthCookieService.SetCookie(user, password)"]
B --> C["Build payload:<br>user + TAB + password + TAB"]
C --> D["Read client remote IP<br>as DPAPI entropy"]
D --> E["DPAPI.Encrypt:<br>MachineKey scope + IP entropy"]
E --> F["AddCookieToHeader:<br>raw Base64, no URL-encoding"]
F --> G["Set-Cookie: SAIFAUTH=...<br>Path=/, HttpOnly"]
G -.-> H["Legacy SecurityModule<br>(same machine, out of repo)"]
Sequence diagram¶
The following diagram shows the primary cookie-issuance sequence, including the unused IOidcSettings dependency resolved at construction.
sequenceDiagram
participant App as "Consuming application"
participant Service as LegacyAuthCookieService
participant DPAPI
participant Response as "HttpContext.Response"
App->>Service: new LegacyAuthCookieService(httpContextAccessor, oidcSettings)
App->>Service: SetCookie(user, password)
Service->>Service: Build tab-delimited payload
Service->>DPAPI: Encrypt(MachineKey, payload, remoteIp)
DPAPI-->>Service: Base64 ciphertext
Service->>Response: Append raw Set-Cookie SAIFAUTH header
Response-->>App: void
Design constraints¶
- The DPAPI P/Invoke path is hard-coded to
c:\windows\system32\crypt32.dllwith no[SupportedOSPlatform("windows")]annotation, even though the package targets cross-platformnet8.0;net10.0— the first encrypt call's native invocation throwsDllNotFoundExceptionon non-Windows hosts, but that exception is caught and rewrapped as a genericSystem.Exception("DPAPI was unable to encrypt data.")with theDllNotFoundExceptionas its inner cause, rather than surfacing directly to the caller*. - The issued cookie sets no
Secure,SameSite,Domain, orExpiresattributes, so it is a host-only session cookie that can travel over plain HTTP and in cross-site requests. IOidcSettingsis constructor-injected but never read; callers must still register an implementation or DI construction fails.- There is no consumer of this package anywhere in this repository; its only known relationship is the shared
SAIFAUTHcookie-name convention withLegacyBolAuthMiddlewareinSAIF.NetCore.ServiceExtensions, which checks presence only and does not decrypt the value.
Related documentation¶
- Index
- Overview
- Dependencies
- Operations and processes
- Business rules
- Security and authorization
- API reference
- SAIF.NetCore.ServiceContracts overview
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¶
src/SAIF.NetCore.LegacyAuth/src/SAIF.NetCore.LegacyAuth/SAIF.NetCore.LegacyAuth/ILegacyAuthCookieService.cssrc/SAIF.NetCore.LegacyAuth/src/SAIF.NetCore.LegacyAuth/SAIF.NetCore.LegacyAuth/LegacyAuthCookieService.cssrc/SAIF.NetCore.LegacyAuth/src/SAIF.NetCore.LegacyAuth/SAIF.NetCore.LegacyAuth/DPAPI.cssrc/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/Middleware/LegacyBolAuthMiddleware.cs