---
title: SAIF.NetCore.DBConnectionClient security and authorization
summary: Authorization requirements, AD resource groups, security enforcement points, and data-level access control.
status: draft
owner: Framework.NCore maintainers
last_reviewed: 2026-10-02
library: SAIF.NetCore.DBConnectionClient
reference_type: package
---

# SAIF.NetCore.DBConnectionClient security and authorization

This page documents the outbound authentication behavior of `SAIF.NetCore.DBConnectionClient` and how it reacts to server-side authorization decisions. The library defines no AD resources, roles, or authorization-decision logic of its own — all authorization of secret access is delegated to the remote DBConnectionAPI, which is outside this repository.

## Authorization architecture

Authorization is delegated entirely to a remote service: access to a given connection string is decided by the DBConnectionAPI based on the NTLM identity this library presents. The library is a pure consumer of that decision — it chooses which credential to present, then reacts to the API's 401/403/404 responses. It implements no `IsAuthorized`, `IsInRole`, `HasAccess`, or `CheckAccess` logic, and has no controllers, endpoints, or attribute-based enforcement surface.

```mermaid
flowchart TD
    Setup["ConnectionClient.Setup()<br>SetNtlmAuthentication() — process identity"] --> Request["Get*Connection call"]
    Creds["ConnectionClient.SetupClientCredentials(username, password)<br>(called by ServiceExtensions)"] --> Request
    Request -->|GetAsync with NTLM identity| API["DBConnectionAPI<br>(external HTTP service)"]
    API -->|200 success| Return([Return connection string])
    API -->|401 / 403 / 404| Deny(["DBClientException, fail fast, no retry"])
```

## AD resource catalog

The library references no AD groups or resource names*. The only security principal involved is the Windows service account presented over NTLM; its name and password are not in the repository and are supplied at runtime.

| Resource / principal | Context | Enforcement point | Source |
| --- | --- | --- | --- |
| Service account (NTLM identity, name not in repo) | The Windows identity presented to the DBConnectionAPI; the API decides whether that identity may read a given connection string server-side** | Presented by `ConnectionClient.Setup` (process identity) or `ConnectionClient.SetupClientCredentials` (explicit credentials) | `src/SAIF.NetCore.DbConnectionClient/SAIF.NetCore.DBConnectionClient/SAIF.NetCore.DBConnectionClient/ConnectionClient.cs` |
| Secure setting `connectionservicecreds` / section `dbconnectionclient` | Stores the service-account credential as one `username\|password` string, unlocked with a system hash computed over the `ConnectionClient` assembly | `SAIF.NetCore.ServiceExtensions.IServiceCollectionExtensions.RegisterDBConnectionClient` (consumer code, not this library) | `src/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/IServiceCollectionExtensions.cs` |

## Authorization enforcement points

### Programmatic authorization checks

No programmatic authorization-decision checks exist in this library — it never decides whether a caller may access something*. The following points instead document credential presentation (outbound caller identity) and reaction to server-side authorization outcomes:

| Class | Method | Behavior | Source |
| --- | --- | --- | --- |
| `ConnectionClient` | `Setup()` | Calls `SetNtlmAuthentication()` with no arguments — NTLM using the current process (app-pool / service) account. | `src/SAIF.NetCore.DbConnectionClient/SAIF.NetCore.DBConnectionClient/SAIF.NetCore.DBConnectionClient/ConnectionClient.cs:56-64` |
| `ConnectionClient` | `SetupClientCredentials(string username, string password)` | Calls `SetNtlmAuthentication(username, password)`, replacing the process identity with an explicit service-account credential; neither argument is validated. | `src/SAIF.NetCore.DbConnectionClient/SAIF.NetCore.DBConnectionClient/SAIF.NetCore.DBConnectionClient/ConnectionClient.cs:71-74` |
| `ConnectionClient` | `Setup()` → `SetClientInfo(ServiceUrl, "DBConnectionClient", ApplicationHost, ApplicationName)` | Sets identification headers (`Client-User`, `Client-Name`, `Application-Id`) — identification, not credentials; whether the API uses them for authorization is unknown**. | `src/SAIF.NetCore.DbConnectionClient/SAIF.NetCore.DBConnectionClient/SAIF.NetCore.DBConnectionClient/ConnectionClient.cs:62` |
| `ConnectionClient` | `RetrieveConnectionString` | On HTTP 401: throws `DBClientException` "Failed to retrieve database connection string due to 401 error - denied access: {connectionName}" with no retry. | `src/SAIF.NetCore.DbConnectionClient/SAIF.NetCore.DBConnectionClient/SAIF.NetCore.DBConnectionClient/ConnectionClient.cs:94-116` |
| `ConnectionClient` | `RetrieveConnectionString` | On HTTP 403: throws `DBClientException` "Access denied retrieving the database connection string" with no retry. | `src/SAIF.NetCore.DbConnectionClient/SAIF.NetCore.DBConnectionClient/SAIF.NetCore.DBConnectionClient/ConnectionClient.cs:94-120` |
| `ConnectionClient` | `GetCachedConnectionString` | A 401/403 exception means `_connections.Add` is never reached, so denials are not cached; a later call for the same key hits the API again. | `src/SAIF.NetCore.DbConnectionClient/SAIF.NetCore.DBConnectionClient/SAIF.NetCore.DBConnectionClient/ConnectionClient.cs:203-216` |

Both `Setup` and `SetupClientCredentials` are `virtual`, so a subclass can change or skip credential setup*. The 401 and 403 messages include only the connection name — never the server's `ErrorMessage`, the connection string, or the credential. `ConnectionClient`'s own outer retry loop (see [Retrieve with retry](operations/retrieve-with-retry.md)) never retries a 401/403 itself, so this library does not amplify a denial by re-issuing the same outer request. This is not an end-to-end guarantee, though: when the standard `HttpJsonClient` implementation (`SAIF.NetCore.HttpClients`) is registered, its independent inner retry policy defaults to retrying on HTTP 401 (along with 502/503) and re-presents the same NTLM credentials for up to three further inner attempts before this library's outer step ever observes the final result, so a single outer 401 can still correspond to multiple authentication attempts against the server beneath this operation*.

## Security interfaces and contracts

| Interface / Class | Role | Consumers | Source |
| --- | --- | --- | --- |
| `IDBConnectionClient` (ServiceContracts) | Contract implemented by `ConnectionClient`; its XML doc states the deployment requirement that the application must use a service account in IIS to retrieve SQL and Oracle connection strings. | `ConnectionClient` | `src/SAIF.NetCore.ServiceContracts/SAIF.NetCore.ServiceContracts/SAIF.NetCore.ServiceContracts/IDBConnectionClient.cs` |
| `IHttpJsonClient` (ServiceContracts) | Exposes `SetClientInfo` and the `SetNtlmAuthentication` overloads this library calls to present credentials. | `ConnectionClient` | `src/SAIF.NetCore.ServiceContracts/SAIF.NetCore.ServiceContracts/SAIF.NetCore.ServiceContracts/IHttpJsonClient.cs` |

## Notes
- Database connection strings, which probably include passwords, stay in managed memory as plain strings with no expiry or invalidation; a memory dump of the host process would expose them*.
- The service-account password travels as a plain `string`, not `SecureString`/`NetworkCredential`, and remains in memory as long as the HTTP client keeps it*.
- Transport security (HTTP vs. HTTPS) is not enforced by this library; `ServiceUrl` comes from configuration and is not checked**.
- Database-secret rotation on the server side is not reflected until the cached entry is refreshed, which requires replacing the `ConnectionClient` instance — restarting the usual singleton-hosted process is the typical way to do this. Rotating the outbound NTLM service-account credential is a separate concern: it changes the identity presented on the next uncached request but does not itself clear any already-cached connection string*.

## Related documentation
- [Index](index.md)
- [Overview](overview.md)
- [Architecture](architecture.md)
- [Dependencies](dependencies.md)
- [Configuration](configuration.md)
- [Operations and processes](operations-processes.md)
- [Business rules](business-rules.md)
- [API reference](api/index.md)

> **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.DbConnectionClient/SAIF.NetCore.DBConnectionClient/SAIF.NetCore.DBConnectionClient/ConnectionClient.cs`
- `src/SAIF.NetCore.DbConnectionClient/SAIF.NetCore.DBConnectionClient/SAIF.NetCore.DBConnectionClient/ClientException.cs`
- `src/SAIF.NetCore.ServiceContracts/SAIF.NetCore.ServiceContracts/SAIF.NetCore.ServiceContracts/IDBConnectionClient.cs`
- `src/SAIF.NetCore.ServiceContracts/SAIF.NetCore.ServiceContracts/SAIF.NetCore.ServiceContracts/IHttpJsonClient.cs`
- `src/SAIF.NetCore.ServiceContracts/SAIF.NetCore.ServiceContracts/SAIF.NetCore.ServiceContracts/HttpClientOptions.cs` (default `RetryOnStatusCodes` includes 401)
- `src/SAIF.NetCore.HttpClients/SAIF.NetCore.HttpClients/SAIF.NetCore.HttpClients/HttpJsonClient/HttpJsonClient.cs` (`ExecuteRestCall` — inner retry-on-401 detail reached when the standard `IHttpJsonClient` implementation is registered)
- `src/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/IServiceCollectionExtensions.cs`
