Skip to content

Issue the legacy auth cookie

This operation builds the tab-delimited credential payload, encrypts it with Windows DPAPI, and writes the resulting value as the SAIFAUTH response cookie so a legacy .NET Framework "SecurityModule" can authenticate the user on the same host.

Field Value
Operation ID OP-01
Trigger A consuming application calls it after the user has authenticated, inferred to be while the plaintext password is still available*
Inputs user, password; the ambient HttpContext from IHttpContextAccessor
Outputs A Set-Cookie: SAIFAUTH=<base64>; path=/; httponly header appended to the current response. Returns void.
Primary components LegacyAuthCookieService.SetCookie
Entry point src/SAIF.NetCore.LegacyAuth/src/SAIF.NetCore.LegacyAuth/SAIF.NetCore.LegacyAuth/LegacyAuthCookieService.cs

Steps

  1. Read the current HttpContext from _httpContextAccessor.HttpContext.
  2. On failure: outside an active request, context is null and the next step throws NullReferenceException (BR-10)
  3. Build the plaintext payload "{user}\t{password}\t" (BR-02)
  4. Null user/password interpolate as empty strings; a tab character embedded in either value is not escaped and may corrupt the legacy reader's parsing*.
  5. Take the client's remote IP address as a string to use as DPAPI entropy (BR-03)
  6. On failure: RemoteIpAddress can be null under some in-process hosts, producing NullReferenceException (BR-10)
  7. Encrypt the payload with DPAPI using the machine key scope, the IP entropy, and an empty description (BR-04)
  8. 4.1 Apply defaults through the overload chain down to the four-argument Encrypt(KeyType, string, string, string) call (BR-07)
  9. 4.2 Coerce a null plaintext or entropy argument to "" (BR-08)
  10. 4.3 UTF-8 encode the plaintext and entropy, then Base64-encode the returned ciphertext (BR-09)
  11. On failure: any exception raised inside the byte-array encrypt call's own try block is rethrown as Exception("DPAPI was unable to encrypt data.") (BR-12); failures in UTF-8/Base64 conversion or argument coercion outside that try block propagate unwrapped.

Origin: Steps 4.1–4.3 are implemented in Encrypt a string with DPAPI and executed on behalf of this operation. 5. Write the encrypted Base64 value as the SAIFAUTH cookie (BR-01, BR-05, BR-06) - 5.1 Create a SetCookieHeaderValue(key, value) with Path = "/" and HttpOnly = true. - 5.2 Render it to a header string with no URL-encoding. - 5.3 Append the string to any existing Set-Cookie values with StringValues.Concat.

Origin: Steps 5.1–5.3 are implemented in Append a raw Set-Cookie header and executed on behalf of this operation.

Process flow

The following diagram visualizes this operation's control flow, including the embedded encrypt and header-write sub-operations.

flowchart TD
    Start(["Trigger: SetCookie called"]) --> S1["Read HttpContext<br>from accessor"]
    S1 --> D1{HttpContext null?}
    D1 -->|Yes| ErrNull1([NullReferenceException])
    D1 -->|No| S2["Build payload:<br>user + TAB + password + TAB"]
    S2 --> S3["Read client remote IP<br>as DPAPI entropy"]
    S3 --> D2{RemoteIpAddress null?}
    D2 -->|Yes| ErrNull2([NullReferenceException])
    D2 -->|No| S4["Encrypt with DPAPI:<br>MachineKey scope + IP entropy"]
    S4 --> D3{Encryption failed?}
    D3 -->|Yes| ErrEnc(["Exception:<br>unable to encrypt data"])
    D3 -->|No| S5["Write Set-Cookie SAIFAUTH<br>header, raw Base64"]
    S5 --> EndOk([Set-Cookie header written])

Failure and edge-case behavior

  • Calling SetCookie outside an active HTTP request, or when RemoteIpAddress is unavailable, throws NullReferenceException before any cookie is written (BR-10)
  • An exception raised inside the byte-array encrypt call's own try block — including running on a non-Windows host or a non-default Windows installation directory — is wrapped as a generic System.Exception("DPAPI was unable to encrypt data.") (BR-12, BR-13). UTF-8/Base64 conversion in this operation's string payload handling, and argument coercion that runs before that try block, are not wrapped by this rule.
  • A tab character embedded in user or password is not escaped and may corrupt the legacy reader's parsing of the payload (BR-02)

Note: Statements marked with * were inferred from code structure, naming conventions, or contextual evidence where direct confirmation was not available in source artifacts.

Sources

  • src/SAIF.NetCore.LegacyAuth/src/SAIF.NetCore.LegacyAuth/SAIF.NetCore.LegacyAuth/LegacyAuthCookieService.cs