SAIF.NetCore.HttpClients security and authorization¶
This page documents the outbound credential-transmission mechanisms implemented by SAIF.NetCore.HttpClients. The library makes no access-control decisions of its own: it is an outbound HTTP client that attaches credentials and identity headers a remote service may use for its own authentication and authorization. Scope is narrow by design — 0 Active Directory resources are referenced and 0 authorization enforcement points exist in this library's code.
Authorization architecture¶
There is no authorization architecture to document for this library. HttpJsonClient holds and attaches outbound credentials (bearer, HTTP Basic, NTLM) and caller-identity headers on requests it sends to a caller-supplied base URL; it does not evaluate any access-control decision, call a security service, or consult Active Directory itself. The diagram below shows where credentials are attached in the outbound request pipeline, not an authorization decision flow.
flowchart TD
Caller["Consumer code<br>(e.g. SAIF.NetCore.ServiceExtensions,<br>SAIF.NetCore.DBConnectionClient)"] --> Client[HttpJsonClient]
Client --> Attach["Attach configured credential:<br>Bearer / Basic / NTLM<br>+ caller-identity headers"]
Attach --> Remote["Caller-supplied remote endpoint<br>(authenticates/authorizes independently)"]
Security interfaces and contracts¶
This library defines no local authorization interfaces. The contracts below are the outbound credential-facing surface that consumers configure — they describe what credentials are sent and how, not an access-control decision made by this library.
| Contract | Member(s) | Purpose | Source |
|---|---|---|---|
IHttpJsonClient |
BearerToken, SetBasicAuthentication(userName, password), SetNtlmAuthentication(userName, password), SetNtlmAuthentication() |
Public interface through which consumers configure outbound credentials; HttpJsonClient is its sole implementation |
src/SAIF.NetCore.ServiceContracts/SAIF.NetCore.ServiceContracts/SAIF.NetCore.ServiceContracts/IHttpJsonClient.cs |
HttpClientOptions |
PersistHeadersAfterRequest |
Controls whether the Headers-dictionary-based credentials (Basic auth, custom on-behalf-of headers) survive past the first request |
src/SAIF.NetCore.ServiceContracts/SAIF.NetCore.ServiceContracts/SAIF.NetCore.ServiceContracts/HttpClientOptions.cs |
ClientInfo |
MachineName, ApplicationId, UserName |
Caller-identity values propagated as unauthenticated Client-Name/Application-ID/Client-User headers (see SEC-HTTP-05) |
src/SAIF.NetCore.HttpClients/SAIF.NetCore.HttpClients/SAIF.NetCore.HttpClients/ClientInfo.cs |
None of these contracts perform authorization. They exist so other libraries can program against IHttpJsonClient/HttpClientOptions rather than RestSharp directly, while still controlling exactly which outbound credential a request carries and how long it persists on the instance.
AD resource catalog¶
No AD groups or resource names are referenced in this library. SetNtlmAuthentication() uses the current process Windows identity as a credential source for outbound calls, which is a credential source, not an AD group check.
| Resource name | Purpose | Enforcement point | Source |
|---|---|---|---|
| — (none) | — | — | — |
Authorization enforcement points¶
None. This library performs no authorization. It does not define [SAIFAuthorize]-style attributes, does not call IsAuthorized/IsInRole/HasAccess, and integrates with no WCF SecurityService. It only attaches credentials and identity headers that a remote service may use for its own authentication and authorization decisions.
Outbound credential mechanisms¶
The following mechanisms are available on HttpJsonClient to authenticate outbound requests. "Lifetime on the instance" describes whether the credential is cleared between requests under the library's default options.
| ID | Mechanism | Public member | How it is transmitted | Lifetime on the instance | Source |
|---|---|---|---|---|---|
| SEC-HTTP-01 | Bearer token | BearerToken (string get/set) |
Added as an Authorization request header whenever non-empty |
Persists until the caller changes it — a property, not a Headers entry, so it is never cleared by the library |
src/SAIF.NetCore.HttpClients/SAIF.NetCore.HttpClients/SAIF.NetCore.HttpClients/HttpJsonClient/HttpJsonClient.cs |
| SEC-HTTP-02 | HTTP Basic | SetBasicAuthentication(userName, password) |
Headers.Add("Authorization", "Basic " + Base64(UTF8("user:password"))) |
Stored in Headers; cleared after the first request unless PersistHeadersAfterRequest = true |
src/SAIF.NetCore.HttpClients/SAIF.NetCore.HttpClients/SAIF.NetCore.HttpClients/HttpJsonClient/HttpJsonClient.cs |
| SEC-HTTP-03 | NTLM (explicit credentials) | SetNtlmAuthentication(userName, password) |
NtlmAuthenticator(user, pw), assigned to every new RestClient |
Persists for the life of the instance (private field, never cleared) | src/SAIF.NetCore.HttpClients/SAIF.NetCore.HttpClients/SAIF.NetCore.HttpClients/HttpJsonClient/HttpJsonClient.cs |
| SEC-HTTP-04 | NTLM (process identity) | SetNtlmAuthentication() |
NtlmAuthenticator() (RestSharp → current process default credentials)* |
Persists for the life of the instance | src/SAIF.NetCore.HttpClients/SAIF.NetCore.HttpClients/SAIF.NetCore.HttpClients/HttpJsonClient/HttpJsonClient.cs |
| SEC-HTTP-05 | Caller identity propagation | Constructor / SetClientInfo(baseUrl, userName, machineName, applicationId) |
Headers Client-Name (machine), Application-ID, Client-User added to every request |
Persists (_clientInfo field) |
src/SAIF.NetCore.HttpClients/SAIF.NetCore.HttpClients/SAIF.NetCore.HttpClients/HttpJsonClient/HttpJsonClient.cs, src/SAIF.NetCore.HttpClients/SAIF.NetCore.HttpClients/SAIF.NetCore.HttpClients/ClientInfo.cs |
| SEC-HTTP-06 | Arbitrary custom headers (e.g. on-behalf-of user) | Headers dictionary (public get/set) |
Copied verbatim to each request | Cleared after the first request unless PersistHeadersAfterRequest = true |
src/SAIF.NetCore.HttpClients/SAIF.NetCore.HttpClients/SAIF.NetCore.HttpClients/HttpJsonClient/HttpJsonClient.cs |
The identity headers in SEC-HTTP-05 are assertions, not authenticated claims: the library sends whatever userName, machineName, and applicationId the caller supplies, with no signature or integrity protection, so a receiving service must not treat Client-User as an authenticated identity*.
Credential-handling risks¶
The following risks were identified from a full read of this library's source together with its consumers' call sites. Severity is the analyst's qualitative assessment, not a formally scored rating.
| ID | Risk | Severity | Related mechanism |
|---|---|---|---|
| SR-HTTP-01 | Passwords/secrets are accepted and held as plain string; the Basic credential is readable from the public Headers dictionary; no zeroing or disposal occurs |
Medium | SEC-HTTP-02 |
| SR-HTTP-02 | 401 is a default retry status, so Bearer/NTLM credentials are resent up to 4 times per call, amplifying failed-authentication counts and AD lockout risk for service accounts* | Medium–High | SEC-HTTP-01, SEC-HTTP-03, SEC-HTTP-04 |
| SR-HTTP-03 | With default options, Basic auth and custom headers are not resent on retry, so a 401 retry cannot succeed and only adds roughly 3 seconds of blocking latency (affects token-refresh-style callers) | Low (correctness/availability) | SEC-HTTP-02, SEC-HTTP-06 |
| SR-HTTP-04 | PersistHeadersAfterRequest = true keeps the Basic Authorization header (and any on-behalf-of identity header) on the instance for all later requests; rotating credentials then throws ArgumentException |
Medium | SEC-HTTP-02 |
| SR-HTTP-05 | A BearerToken combined with an Authorization key already in Headers produces duplicate Authorization headers on one request; server-side resolution of the duplicate is unverified** |
Low–Medium | SEC-HTTP-01, SEC-HTTP-02 |
| SR-HTTP-06 | No HTTPS enforcement exists; Basic and bearer credentials can be sent over a plain http:// base URL |
Medium (High if any production URL is HTTP)** | SEC-HTTP-01, SEC-HTTP-02 |
| SR-HTTP-07 | Mutable credential state on a shared instance can leak credentials or identity across callers or threads if a consumer holds the transient-registered instance beyond its intended scope* | Medium | All mechanisms |
| SR-HTTP-08 | Identity headers (Client-User, Client-Name, Application-ID) are unauthenticated, caller-asserted values* |
Low (for this library; depends on the receiver) | SEC-HTTP-05 |
Notes¶
- This page's scope is deliberately narrow: outbound credential transmission only. The library has 0 AD resource references, 0 authorization enforcement points, 0 data-level authorization checks, and 0 segregation-of-duties rules.
Related documentation¶
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.HttpClients/SAIF.NetCore.HttpClients/SAIF.NetCore.HttpClients/HttpJsonClient/HttpJsonClient.cssrc/SAIF.NetCore.HttpClients/SAIF.NetCore.HttpClients/SAIF.NetCore.HttpClients/ClientInfo.cssrc/SAIF.NetCore.HttpClients/SAIF.NetCore.HttpClients/SAIF.NetCore.HttpClients.Tests/HttpJsonClients/HttpJsonClientTests.cssrc/SAIF.NetCore.ServiceContracts/SAIF.NetCore.ServiceContracts/SAIF.NetCore.ServiceContracts/HttpClientOptions.cssrc/SAIF.NetCore.ServiceContracts/SAIF.NetCore.ServiceContracts/SAIF.NetCore.ServiceContracts/IHttpJsonClient.cssrc/SAIF.NetCore.DbConnectionClient/SAIF.NetCore.DBConnectionClient/SAIF.NetCore.DBConnectionClient/ConnectionClient.cssrc/SAIF.NetCore.OIDC/src/SAIF.NetCore.OIDC/Services/JwtRefreshService.cssrc/SAIF.NetCore.NtlmApiAuth/src/SAIF.NetCore.NtlmApiAuth/Extensions/IHttpJsonClientExtensions.cssrc/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions.Integration.Tests/Controllers/HttpClientController.cs