# Description Introduces a pluggable user-identity provider model covering all OPC UA Part 6 §6.5 mechanisms (Anonymous, UserName, X509, IssuedToken/JWT) on both client and server, with full `Microsoft.Extensions.DependencyInjection` integration, plus the Part 12 §9 `AuthorizationService` two-phase token-request flow **including refresh-token rotation**, the Part 12 §8 KeyCredential Push model, and a clean provider model for OPC 10000-12 §7.2 `ApplicationSelfAdmin`. The work is split across phase-by-phase commits so it can be reviewed independently; nothing here changes wire-level behaviour or forces existing applications to migrate. ### Documentation All under `Docs/`: - `IdentityProviders.md` — full developer guide: three-layer model, recipes, configuration reference, "what gets auto-wired" matrix, JWS algorithm table, identity-augmenters section, **"Implementing your own provider"** how-to subsections for Entra / OIDC / Windows / AspNetCore (sibling files merged in per review feedback). - `DependencyInjection.md` — `Identity` sections with `appsettings.json` examples, identity-extension matrix, `WithAuthorizationService` + `WithKeyCredentialPush` + `AddIdentityAugmenter` extensions documented. - `RoleBasedUserManagement.md` — claim-criteria callout describing `IIdentityClaims` probe surface. - `AuthorizationService.md` — Architecture diagram + `IAccessTokenProvider` conceptual narrative restored from master; modern `StartRequestToken` / `FinishRequestToken` flow leads; refresh-token recipe added. - `KeyCredentialService.md` — Push model + Pull vs Push vs Bridge decision matrix + Hybrid (Push + Pull) section; explicit experimental warning for the bridge. - `GDS.md` — KeyCredential Push, `StartRequestToken`, `GdsApplicationSelfAdminProvider`, **shipped Refresh-token support with rotation policy and audit semantics** all documented. - `MigrationGuide.md` — User Identity Providers section listing `[Obsolete]` markers + mechanical recipes; SelfAdmin migration via `IIdentityAugmenter`; `EnableRefreshTokens` default note. - `README.md` index entries. ## Checklist - [x] I have signed the [CLA](https://opcfoundation.org/license/cla/ContributorLicenseAgreementv1.0.pdf) and read the [CONTRIBUTING](https://github.com/OPCFoundation/UA-.NETStandard/blob/master/CONTRIBUTING.md) doc. - [x] I have added tests that prove my fix is effective or that my feature works and increased code coverage. - [x] I have added all necessary documentation. - [x] I have verified that my changes do not introduce (new) build or analyzer warnings. - [x] I ran **all** tests locally using the **UA.slnx** solution against at least .net **framework** and .net **10**, and all passed. - [x] I fixed **all** failing and flaky tests in the CI pipelines and **all** CodeQL warnings. - [x] I have addressed **all** PR feedback received.
22 KiB
OPC UA Global Discovery Server (GDS) — Developer Guide
This package implements the OPC UA Global Discovery Server (GDS) as defined in OPC 10000-12 (Part 12). It provides application registration, certificate lifecycle management (pull and push models), KeyCredentialService, AuthorizationService, and role-based access control.
Quick Links
| Topic | Document |
|---|---|
| GDS core (this file) | Directory, certificates, push management, roles |
| KeyCredentialService | Credential issuance for non-UA services |
| AuthorizationService | OAuth2-style access token issuance |
Packages
| NuGet Package | Contents |
|---|---|
Opc.Ua.Gds.Common |
Model types, encodeable types, design files |
Opc.Ua.Gds.Server.Common |
Server-side node managers, providers, authorization |
Opc.Ua.Gds.Client.Common |
Client proxies for GDS, push, KeyCredential, AuthorizationService |
1. Client API
GlobalDiscoveryServerClient
The primary client for interacting with a GDS. Manages its own session and exposes the full GDS directory and certificate management API.
using Opc.Ua.Gds.Client;
// Create and connect
var gdsClient = new GlobalDiscoveryServerClient(appConfig);
gdsClient.AdminCredentials = new UserIdentity("admin", "password");
await gdsClient.ConnectAsync("opc.tcp://gds-host:4840");
// Register an application
var appRecord = new ApplicationRecordDataType
{
ApplicationUri = "urn:my-app",
ApplicationType = ApplicationType.Server,
ApplicationNames = new[] { new LocalizedText("My App") }.ToArrayOf(),
DiscoveryUrls = new[] { "opc.tcp://my-app:4850" }.ToArrayOf()
};
NodeId appId = await gdsClient.RegisterApplicationAsync(appRecord);
// Request a new certificate (pull model)
NodeId requestId = await gdsClient.StartNewKeyPairRequestAsync(
appId, default, ObjectTypeIds.RsaSha256ApplicationCertificateType,
"CN=My App", domainNames, "PFX", null);
// Poll for completion
ByteString cert, privateKey;
ArrayOf<ByteString> issuerCerts;
do
{
await Task.Delay(2000);
(cert, privateKey, issuerCerts) =
await gdsClient.FinishRequestAsync(requestId, default);
} while (cert.IsEmpty);
// Clean up
await gdsClient.DisconnectAsync();
ServerPushConfigurationClient
Client for OPC 10000-12 §7.10 push certificate management on a target server:
var pushClient = new ServerPushConfigurationClient(appConfig);
await pushClient.ConnectAsync(serverEndpoint);
// Push a new certificate
bool restartNeeded = await pushClient.UpdateCertificateAsync(
pushClient.DefaultApplicationGroup,
ObjectTypeIds.RsaSha256ApplicationCertificateType,
newCertBlob, "PFX", privateKeyBlob, issuerCerts);
if (restartNeeded)
{
await pushClient.ApplyChangesAsync();
}
// Create a self-signed certificate on the server
await pushClient.CreateSelfSignedCertificateAsync(
pushClient.DefaultApplicationGroup,
ObjectTypeIds.RsaSha256ApplicationCertificateType,
"CN=NewSubject", domainNames);
2. Server-Side: Building a GDS
Minimal GDS Server
Use GlobalDiscoverySampleServer with dependency injection of
your storage backends:
// 1. Create storage backends
IApplicationsDatabase database = JsonApplicationsDatabase.Load(
"gds-applications.json", telemetry);
ICertificateGroup certGroup = new CertificateGroup(
gdsConfig.AuthoritiesStorePath, gdsConfig.CertificateGroups);
IUserDatabase userDb = JsonUserDatabase.Load(
"gds-users.json", telemetry);
// 2. Create the GDS server
// (database implements both IApplicationsDatabase and ICertificateRequest)
var gdsServer = new GlobalDiscoverySampleServer(
database, database, certGroup, userDb, telemetry,
autoApprove: true);
// 3. Start via ApplicationInstance
var app = new ApplicationInstance(telemetry)
{
ApplicationName = "My GDS",
ApplicationType = ApplicationType.Server,
ConfigSectionName = "Opc.Ua.GlobalDiscoveryServer"
};
var config = await app.LoadAsync("MyGds.Config.xml");
await app.CheckApplicationInstanceCertificatesAsync(false);
await app.StartAsync(gdsServer);
Using GdsNodeManagerFactory
For embedding GDS into an existing server:
// In your server's CreateMasterNodeManager:
var gdsConfig = configuration.ParseExtension<GlobalDiscoveryServerConfiguration>();
var factory = new GdsNodeManagerFactory(gdsConfig);
additionalNodeManagers.Add(factory.Create(server, configuration));
Extension Points
Every pluggable interface and its purpose:
| Interface | Purpose | Default |
|---|---|---|
IApplicationsDatabase |
Application registration store | LinqApplicationsDatabase / JsonApplicationsDatabase |
ICertificateRequest |
Certificate request lifecycle | LinqApplicationsDatabase |
ICertificateGroup |
CA operations (sign, revoke) | CertificateGroup |
IGdsUserDatabase |
User store + ApplicationAdmin bindings | Implement over LinqUserDatabase |
IKeyCredentialRequestStore |
KeyCredential lifecycle | InMemoryKeyCredentialRequestStore |
ISecretStore |
Secret storage for credentials | InMemorySecretStore |
IAccessTokenProvider |
Token issuance (AuthorizationService) | null (Bad_NotSupported) |
IConfigurationDataStore |
ManagedApplications config persistence | InMemoryConfigurationDataStore |
IManagedApplicationsNodeManager |
ManagedApplications folder | StubManagedApplicationsNodeManager |
3. Implementing Providers
IApplicationsDatabase
Stores registered application records. Must also implement
ICertificateRequest for certificate request lifecycle (or provide
a separate implementation):
public class SqlApplicationsDatabase
: ApplicationsDatabaseBase, ICertificateRequest
{
// ApplicationsDatabaseBase provides Match() and ValidateApplication()
// Override the abstract CRUD methods:
public override NodeId RegisterApplication(
ApplicationRecordDataType application)
{
ValidateApplication(application); // call base validation
return _db.InsertApplication(application);
}
public override void UpdateApplication(
ApplicationRecordDataType application)
{
ValidateApplication(application);
_db.UpdateApplication(application);
}
// ... implement remaining abstract methods
}
ICertificateGroup
Implement to use an external CA (EST, ACME, EJBCA, etc.):
public class EstCertificateGroup : ICertificateGroup
{
public async Task<(Certificate, byte[], CertificateCollection)>
NewKeyPairRequestAsync(
ApplicationRecordDataType application,
string subjectName,
string[] domainNames,
string privateKeyFormat,
string privateKeyPassword)
{
// Call your EST server's /simpleenroll endpoint
// Return (signedCert, privateKey, issuerChain)
}
// ... implement remaining interface methods
}
IGdsUserDatabase
Extend IUserDatabase to support the ApplicationAdmin role
(OPC 10000-12 §7.2). The GDS sample server automatically detects
IGdsUserDatabase during username authentication:
public class MyGdsUserDatabase : LinqUserDatabase, IGdsUserDatabase
{
private readonly Dictionary<string, List<NodeId>> _appAdminMap = new();
public IReadOnlyList<NodeId>? GetAdministeredApplicationIds(
string userName)
{
return _appAdminMap.TryGetValue(userName, out var ids)
? ids : null;
}
// Admin API to grant ApplicationAdmin for specific apps:
public void GrantApplicationAdmin(
string userName, IEnumerable<NodeId> applicationIds)
{
_appAdminMap[userName] = applicationIds.ToList();
}
}
IConfigurationDataStore
Persistence backend for ManagedApplications (§7.10.16). The
DefaultManagedApplicationsNodeManager uses this to populate
ApplicationConfigurationState nodes:
public class FileConfigurationDataStore : IConfigurationDataStore
{
public async ValueTask<IReadOnlyList<ManagedApplicationInfo>>
GetManagedApplicationsAsync(CancellationToken ct)
{
// Read from config file / database
}
public async ValueTask<uint> WriteConfigurationAsync(
string applicationUri, byte[] data,
uint currentVersion, CancellationToken ct)
{
// Persist with optimistic concurrency check
}
public async ValueTask ConfirmUpdateAsync(
string applicationUri, uint configVersion,
CancellationToken ct)
{
// Mark the configuration as applied
}
}
4. Roles and Authorization
GDS Roles (OPC 10000-12 §7.2)
| Role | Purpose |
|---|---|
DiscoveryAdmin |
Register/update/unregister any application |
CertificateAuthorityAdmin |
Manage certificate requests and trust lists |
RegistrationAuthorityAdmin |
Approve/reject certificate requests |
ApplicationSelfAdmin |
Manage own application's registration |
ApplicationAdmin |
Manage a configured set of applications |
ApplicationSelfAdmin Privilege
GdsApplicationSelfAdminProvider grants GdsRole.ApplicationSelfAdmin
when the secure-channel client certificate matches a certificate stored
for the registered ApplicationRecordDataType found by the channel
ApplicationUri. The provider is an IIdentityAugmenter, so it layers
SelfAdmin on top of any accepted identity instead of using a custom
ImpersonateUser callback.
For dependency-injection-hosted GDS servers the provider is registered with the symmetric builder extension:
services.AddOpcUa()
.AddGdsServer(opt => opt.ApplicationName = "MyGds")
.AddDefaultIdentityAuthenticators(opt => opt.EnableJwt = false)
.AddGdsApplicationSelfAdminProvider();
AddDefaultIdentityAuthenticators(...) on IGdsServerBuilder also
adds this provider so standard GDS hosts get OPC 10000-12 §7.2
SelfAdmin behavior automatically.
ApplicationAdmin Privilege
The ApplicationAdmin role allows a user to administer a specific
set of applications (not all applications like DiscoveryAdmin).
How it works:
- Assign the
GdsRole.ApplicationAdminrole to the user viaIUserDatabase.CreateUser() - Implement
IGdsUserDatabase.GetAdministeredApplicationIds()to return theApplicationIds the user may administer - During username authentication,
GlobalDiscoverySampleServerconstructs aGdsRoleBasedIdentitywithAdministeredApplicationIdspopulated AuthorizationHelper.CheckApplicationAdminPrivilege()verifies the target application is in the user's administered set
// Setup: create a user with ApplicationAdmin role
userDb.CreateUser("app-admin", passwordBytes,
[GdsRole.ApplicationAdmin]);
// If using IGdsUserDatabase:
((MyGdsUserDatabase)userDb).GrantApplicationAdmin(
"app-admin",
[registeredAppId1, registeredAppId2]);
Security: Fail-Closed Channel Validation
AuthorizationHelper.HasAuthenticatedSecureChannel() enforces that
all GDS methods are called over a signed (or encrypted) secure
channel. The check fails closed — if the system context cannot
be validated, the method throws BadSecurityModeInsufficient.
5. End-to-End Example
Complete example: register an application, get a certificate, push it to the server.
// ── 1. Start the GDS Server ─────────────────────────
var database = JsonApplicationsDatabase.Load("apps.json", telemetry);
var certGroup = new CertificateGroup(authStorePath, certGroupConfigs);
var userDb = JsonUserDatabase.Load("users.json", telemetry);
var gds = new GlobalDiscoverySampleServer(
database, database, certGroup, userDb, telemetry);
var app = new ApplicationInstance(telemetry) { ... };
await app.StartAsync(gds);
// ── 2. Client: Register and Get Certificate ─────────
var gdsClient = new GlobalDiscoveryServerClient(clientConfig);
gdsClient.AdminCredentials = new UserIdentity("admin", "password");
await gdsClient.ConnectAsync("opc.tcp://localhost:58810");
// Register
var record = new ApplicationRecordDataType
{
ApplicationUri = "urn:my-server",
ApplicationType = ApplicationType.Server,
ApplicationNames = new[] { new LocalizedText("My Server") }.ToArrayOf(),
DiscoveryUrls = new[] { "opc.tcp://my-server:4840" }.ToArrayOf()
};
NodeId appId = await gdsClient.RegisterApplicationAsync(record);
// Request certificate
NodeId reqId = await gdsClient.StartNewKeyPairRequestAsync(
appId, default,
ObjectTypeIds.RsaSha256ApplicationCertificateType,
"CN=My Server,O=My Org",
new[] { "my-server", "localhost" }.ToArrayOf(),
"PFX", null);
// Wait for completion
ByteString cert, key;
ArrayOf<ByteString> issuers;
do
{
await Task.Delay(2000);
(cert, key, issuers) =
await gdsClient.FinishRequestAsync(reqId, default);
} while (cert.IsEmpty);
// ── 3. Push Certificate to Target Server ────────────
var pushClient = new ServerPushConfigurationClient(clientConfig);
await pushClient.ConnectAsync(serverEndpoint);
bool needsRestart = await pushClient.UpdateCertificateAsync(
pushClient.DefaultApplicationGroup,
ObjectTypeIds.RsaSha256ApplicationCertificateType,
cert, "PFX", key, issuers);
if (needsRestart)
{
await pushClient.ApplyChangesAsync();
}
// ── 4. Clean Up ─────────────────────────────────────
await pushClient.DisconnectAsync();
await gdsClient.DisconnectAsync();
Conformance Matrix
Status key: ✅ Implemented | ⚠️ Partial | ❌ Not implemented | N/A Not applicable
GDS Directory (§6.5)
| Section | Feature | Status | Source |
|---|---|---|---|
| §6.5.3 | DirectoryType | ✅ | ApplicationsNodeManager.cs |
| §6.5.4 | FindApplications | ✅ | OnFindApplications |
| §6.5.5 | ApplicationRecordDataType / rcp+ rules | ✅ | ApplicationsDatabaseBase.ValidateApplication |
| §6.5.6 | RegisterApplication | ✅ | OnRegisterApplication + DiscoveryAdminOrAppAdmin |
| §6.5.7 | UpdateApplication | ✅ | OnUpdateApplication + DiscoveryAdminOrSelfAdminOrAppAdmin |
| §6.5.8 | UnregisterApplication | ✅ | OnUnregisterApplicationAsync + cert revocation |
| §6.5.9 | GetApplication | ✅ | OnGetApplication |
| §6.5.10 | QueryApplications | ✅ | OnQueryApplications |
| §6.5.11 | QueryServers | ✅ | OnQueryServers |
| §6.5.12 | ApplicationRegistrationChangedAuditEvent | ✅ | AuditEvents.ReportApplicationRegistrationChangedAuditEvent |
Certificate Management — Pull Model (§7.6)
| Section | Feature | Status | Source |
|---|---|---|---|
| §7.6.4 | StartNewKeyPairRequest | ✅ | OnStartNewKeyPairRequest + audit |
| §7.6.5 | StartSigningRequest | ✅ | OnStartSigningRequestAsync + audit |
| §7.6.6 | FinishRequest | ✅ | OnFinishRequestAsync + issuer chain |
| §7.6.7 | GetCertificateGroups | ✅ | OnGetCertificateGroups |
| §7.6.8 | GetTrustList | ✅ | OnGetTrustList |
| §7.6.9 | RevokeCertificate | ✅ | OnRevokeCertificateAsync + audit |
| §7.6.10 | GetCertificates | ✅ | OnGetCertificates |
| §7.6.11 | CheckRevocationStatus | ✅ | OnCheckRevocationStatusAsync + ValidityTime |
| §7.6.12 | GetCertificateStatus | ✅ | OnGetCertificateStatus |
Roles and Privileges (§7.2)
| Feature | Status | Source |
|---|---|---|
| DiscoveryAdmin | ✅ | GdsRole.DiscoveryAdmin |
| CertificateAuthorityAdmin | ✅ | GdsRole.CertificateAuthorityAdmin |
| RegistrationAuthorityAdmin | ✅ | GdsRole.RegistrationAuthorityAdmin |
| ApplicationSelfAdmin | ✅ | GdsRole.ApplicationSelfAdmin |
| ApplicationAdmin | ✅ | GdsRole.ApplicationAdmin + AdministeredApplicationIds |
| BadSecurityModeInsufficient | ✅ | AuthorizationHelper.HasAuthenticatedSecureChannel |
Push Management — ServerConfiguration (§7.10)
| Section | Feature | Status | Source |
|---|---|---|---|
| §7.10.3 | UpdateCertificate | ✅ | ConfigurationNodeManager.UpdateCertificateAsync |
| §7.10.4 | CreateSigningRequest | ✅ | ConfigurationNodeManager.CreateSigningRequestAsync |
| §7.10.5 | ApplyChanges | ✅ | ConfigurationNodeManager.ApplyChanges |
| §7.10.6 | CreateSelfSignedCertificate | ✅ | ConfigurationNodeManager.CreateSelfSignedCertificateAsync |
| §7.10.7 | GetCertificates | ✅ | ConfigurationNodeManager.GetCertificates |
| §7.10.8 | GetRejectedList | ✅ | ConfigurationNodeManager.GetRejectedList |
| §7.10.10 | ConfirmUpdate | ⚠️ | DefaultManagedApplicationsNodeManager + IConfigurationDataStore abstraction; optimistic concurrency via version tracking |
| §7.10.16 | ApplicationConfigurationType / ManagedApplications | ⚠️ | DefaultManagedApplicationsNodeManager creates ApplicationConfigurationState nodes; IConfigurationDataStore abstracts persistence |
TrustList (§7.8)
| Feature | Status | Source |
|---|---|---|
| TrustListType / OpenWithMasks | ✅ | Core TrustList.cs |
| CloseAndUpdate | ✅ | Core TrustList.cs + TrustListUpdatedAuditEvent |
| AddCertificate / RemoveCertificate | ✅ | Core TrustList.cs |
| LastUpdateTime | ✅ | Set during init + CloseAndUpdate |
| Writable / UserWritable | ✅ | Set to true for GDS groups |
| ActivityTimeout / DefaultValidationOptions | ✅ | Generated from model CSV |
| CertificateExpirationAlarm | ⚠️ | Property values populated at startup; timer-based re-evaluation via StartAlarmMonitoring |
| TrustListOutOfDateAlarm | ⚠️ | Property values populated at startup; timer-based re-evaluation via StartAlarmMonitoring |
Audit Events
| Event Type | Status | Source |
|---|---|---|
| ApplicationRegistrationChangedAuditEvent | ✅ | Register/Update/Unregister |
| CertificateRequestedAuditEvent | ✅ | StartNewKeyPair + StartSigning |
| CertificateDeliveredAuditEvent | ✅ | FinishRequest |
| CertificateRevokedAuditEvent | ✅ | RevokeCertificate |
| CertificateUpdateRequestedAuditEvent | ✅ | UpdateCertificate (push) |
| TrustListUpdatedAuditEvent | ✅ | Core TrustList.cs |
| KeyCredentialRequestedAuditEvent | ✅ | StartRequest |
| KeyCredentialDeliveredAuditEvent | ✅ | FinishRequest |
| KeyCredentialRevokedAuditEvent | ✅ | Revoke |
| AccessTokenIssuedAuditEvent | ✅ | RequestAccessToken |
| Secrets redacted from audit payloads | ✅ | RedactedPrivateKeyPassword / RedactedPrivateKey |
KeyCredentialService (§8)
| Feature | Status | Source |
|---|---|---|
| StartRequest | ✅ | OnKeyCredentialStartRequest |
| FinishRequest | ✅ | OnKeyCredentialFinishRequest |
| Revoke | ✅ | OnKeyCredentialRevoke |
| InMemoryKeyCredentialRequestStore | ✅ | IKeyCredentialRequestStore.cs |
| Client proxy | ✅ | KeyCredentialServiceClient.cs |
| KeyCredential Push binding | ✅ | WithKeyCredentialPush / KeyCredentialPushSubject |
AuthorizationService (§9)
| Feature | Status | Source |
|---|---|---|
| GetServiceDescription | ✅ | OnGetServiceDescription |
| RequestAccessToken | ✅ | Legacy compatibility path via IAccessTokenProvider.RequestAccessTokenAsync |
| StartRequestToken (RC) | ✅ | OnStartRequestToken / AuthorizationServiceManager |
| FinishRequestToken (RC) | ✅ | OnFinishRequestToken / AuthorizationServiceManager |
| RefreshToken (RC) | ✅ | OnRefreshTokenAsync / AuthorizationServiceManager |
| SupportedRoles (RC) | ✅ | Model property exposed |
| Client proxy | ✅ | AuthorizationServiceClient.cs |
Refresh tokens
The default in-memory AuthorizationService provider issues a refresh token from
FinishRequestToken and accepts it through RefreshToken (OPC 10000-12 §9.7). Refresh
tokens are opaque, single-use secrets: each successful refresh consumes the current token,
issues a new access token, and rotates to a new refresh token. The refresh-token lifetime
slides by AuthorizationServiceOptions.DefaultRefreshTokenLifetime (7 days by default).
Set AuthorizationServiceOptions.EnableRefreshTokens = false to preserve the legacy
behavior where FinishRequestToken returns no refresh token and RefreshToken returns
Bad_NotSupported.
var (newJwt, newJwtExpiresAt, newRefreshToken, newRefreshExpiresAt) =
await authClient.RefreshTokenAsync(resourceId, refreshToken);
refreshToken = newRefreshToken;
Refresh-token audit events include only the resourceId input and the outcome. The
refresh token itself is a secret and is never placed in audit payloads.
LDS / LDS-ME (§4–5)
| Feature | Status | Source |
|---|---|---|
| FindServers | ✅ | LdsServer.FindServersAsync |
| GetEndpoints | ✅ | LdsServer.GetEndpointsAsync |
| RegisterServer | ✅ | LdsServer.RegisterServerAsync |
| RegisterServer2 | ✅ | LdsServer.RegisterServer2Async |
| FindServersOnNetwork | ✅ | LdsServer.FindServersOnNetworkAsync |
| LDS-ME capability | ✅ | ComputeServerCapabilities |
| mDNS _opcua-tcp._tcp | ✅ | MulticastDiscovery.OpcUaServiceType |
| rcp+ reverse-connect | ✅ | MulticastDiscovery.ReverseConnectScheme |
| Annex C TXT keys | ✅ | path / caps / rc |
| Annex D identifiers | ✅ | LDS / LDS-ME |
Extension Points (Phase 2 Abstractions)
Every extension point a user needs to provide or override:
| Interface | Purpose | Default impl | User replaces when... |
|---|---|---|---|
IApplicationsDatabase |
Application registration store | LinqApplicationsDatabase / JsonApplicationsDatabase |
Using a SQL/NoSQL database |
ICertificateRequest |
Cert request lifecycle | LinqApplicationsDatabase |
Custom approval workflow |
ICertificateGroup |
CA operations | CertificateGroup |
External CA (EST, ACME, etc.) |
IKeyCredentialRequestStore |
KeyCredential lifecycle | InMemoryKeyCredentialRequestStore |
Persistent store, external IdP |
ISecretStore |
Secret storage for credentials | InMemorySecretStore |
Key Vault, DPAPI, K8s secrets |
IAccessTokenProvider |
Token issuance for AuthorizationService | null (Bad_NotSupported) |
OAuth2/JWT provider |
IConfigurationDataStore |
ManagedApplications config persistence | InMemoryConfigurationDataStore |
File-system, database |
IManagedApplicationsNodeManager |
ManagedApplications folder | StubManagedApplicationsNodeManager / DefaultManagedApplicationsNodeManager |
Full push management |
IConfigurationNodeManager |
Alarm monitoring | ConfigurationNodeManager.StartAlarmMonitoring |
Custom thresholds/sources |
IUserDatabase |
User/password store | Existing in GlobalDiscoverySampleServer |
LDAP, database |