Skip to main content
Table of Contents

Class IdentityDirectoryServiceCollectionExtensions

Namespace
Microsoft.Extensions.DependencyInjection
Assembly
Stratara.Identity.EntityFrameworkCore.dll

DI extensions that register the Stratara identity-directory plane: the EF-backed tenant membership store, the membership-backed authorization provider, and the membership-backed cross-tenant authorizer.

public static class IdentityDirectoryServiceCollectionExtensions
Inheritance
IdentityDirectoryServiceCollectionExtensions
Inherited Members

Methods

AddApiKeyStoreFromContextFactory<TContext>(IServiceCollection)

Register the EF Core IApiKeyStore against TContext, taking a fresh context for each operation from the registered context factory.

public static IServiceCollection AddApiKeyStoreFromContextFactory<TContext>(this IServiceCollection services) where TContext : DbContext

Parameters

services IServiceCollection

The service collection to mutate.

Returns

IServiceCollection

The same service collection, to enable chaining.

Type Parameters

TContext

The DbContext hosting the directory tables.

Examples

Needs AddDbContextFactory<TContext>(); one context per operation:

services.AddDbContextFactory<DirectoryDbContext>();
services.AddApiKeyStoreFromContextFactory<DirectoryDbContext>();

Remarks

Each operation creates its own context from the registered IDbContextFactory<TContext> and disposes it afterwards, so directory operations issued concurrently within one scope do not contend and a store's commit reaches only its own rows. In exchange, a store write does not take part in a transaction the consumer opened on their own scoped context.

Requires AddDbContextFactory<TContext>(); a missing registration fails at first resolution rather than silently. Keep the factory's options aligned with the scoped registration — interceptors, query filters and conventions are configured per registration, not per context type.

Calling this together with AddApiKeyStore<TContext>(IServiceCollection) leaves whichever ran first in place; they do not compose.

AddApiKeyStore<TContext>(IServiceCollection)

Register the EF Core IApiKeyStore against TContext — issuance (raw key shown once, hash stored), idempotent import of a caller-supplied key for bootstrap scenarios, fail-closed validation, revocation, and per-tenant/per-user erasure sweeps. Machine keys are materialized as memberships of their tenant, so they flow through the same role/permission plane as human actors.

public static IServiceCollection AddApiKeyStore<TContext>(this IServiceCollection services) where TContext : DbContext

Parameters

services IServiceCollection

The service collection to mutate.

Returns

IServiceCollection

The same service collection, to enable chaining.

Type Parameters

TContext

The DbContext hosting the directory tables.

Examples

services.AddApiKeyStore<DirectoryDbContext>();

Remarks

The store shares the context registered for the request, so directory operations issued concurrently within one scope fail on whichever arrives second — a database context serves one operation at a time — and the store's own commit also commits whatever else the consumer has left unsaved on that context. Register the store with AddApiKeyStoreFromContextFactory<TContext>(IServiceCollection) instead to give each operation its own context.

Calling both registrations leaves whichever ran first in place; they do not compose.

AddCatalogPermissionResolver(IServiceCollection)

Register CatalogPermissionResolver as the IPermissionResolver — permissions derive from tenant-scoped membership roles mapped through the catalog's role grants. Use the generic overload (AddCatalogPermissionResolver<TUser>(IServiceCollection)) when global ASP.NET Identity roles should also grant permissions.

public static IServiceCollection AddCatalogPermissionResolver(this IServiceCollection services)

Parameters

services IServiceCollection

The service collection to mutate.

Returns

IServiceCollection

The same service collection, to enable chaining.

Examples

Resolves a principal's permissions by running its membership roles through the catalog:

services.AddPermissionCatalog(c => c.Add("sims.read"));
services.AddCatalogPermissionResolver();

AddCatalogPermissionResolver<TUser>(IServiceCollection)

Register CatalogPermissionResolver<TUser> as the IPermissionResolver — permissions derive from tenant-scoped membership roles and global ASP.NET Identity roles, mapped through the catalog's role grants. Requires the host's Identity registration (UserManager<TUser> resolvable).

public static IServiceCollection AddCatalogPermissionResolver<TUser>(this IServiceCollection services) where TUser : class

Parameters

services IServiceCollection

The service collection to mutate.

Returns

IServiceCollection

The same service collection, to enable chaining.

Type Parameters

TUser

The host's ASP.NET Identity user entity.

Examples

The generic overload also considers the user's global ASP.NET Core Identity roles:

services.AddCatalogPermissionResolver<ApplicationUser>();

AddMembershipAuthorization(IServiceCollection)

Register MembershipAuthorizationProvider as the IAuthorizationProvider — role checks pass on tenant-scoped membership roles only. Use the generic overload (AddMembershipAuthorization<TUser>(IServiceCollection)) when the host also gates on global ASP.NET Identity roles.

public static IServiceCollection AddMembershipAuthorization(this IServiceCollection services)

Parameters

services IServiceCollection

The service collection to mutate.

Returns

IServiceCollection

The same service collection, to enable chaining.

Examples

Resolves roles from tenant-scoped membership. Pair it with the authorizing mediator, which is what enforces the attributes:

services.AddMembershipAuthorization();
services.AddAuthorizingMediator<MembershipAuthorizationProvider>();

Remarks

Hosts that dispatch through the authorizing mediator pass the provider type there instead (AddAuthorizingMediator<MembershipAuthorizationProvider>()); this registration serves components that resolve IAuthorizationProvider directly, such as the authorizing outbox dispatcher.

AddMembershipAuthorization<TUser>(IServiceCollection)

Register MembershipAuthorizationProvider<TUser> as the IAuthorizationProvider — role checks pass on tenant-scoped membership roles or global ASP.NET Identity roles (platform roles). Requires the host's Identity registration (UserManager<TUser> resolvable).

public static IServiceCollection AddMembershipAuthorization<TUser>(this IServiceCollection services) where TUser : class

Parameters

services IServiceCollection

The service collection to mutate.

Returns

IServiceCollection

The same service collection, to enable chaining.

Type Parameters

TUser

The host's ASP.NET Identity user entity.

Examples

The generic overload adds the user's global ASP.NET Core Identity roles to the membership roles:

services.AddMembershipAuthorization<ApplicationUser>();

AddMembershipCrossTenantAuthorizer(IServiceCollection, Action<MembershipCrossTenantAuthorizerOptions>?)

Register MembershipCrossTenantAuthorizer as the ICrossTenantAuthorizer consulted by strict tenant isolation: cross-tenant operations are allowed for actors with an active membership in the data-owner tenant or with one of the configured cross-tenant roles.

public static IServiceCollection AddMembershipCrossTenantAuthorizer(this IServiceCollection services, Action<MembershipCrossTenantAuthorizerOptions>? configure = null)

Parameters

services IServiceCollection

The service collection to mutate.

configure Action<MembershipCrossTenantAuthorizerOptions>

Optional callback to configure the permitted cross-tenant roles.

Returns

IServiceCollection

The same service collection, to enable chaining.

Examples

Strict isolation where only platform administrators may cross tenants without membership:

builder.Services
    .AddStrataraTenantIsolation(o => o.Mode = TenantIsolationMode.Strict)
    .AddMembershipCrossTenantAuthorizer(o => o.CrossTenantRoles.Add("PlatformAdmin"));

AddPermissionCatalog(IServiceCollection, Action<PermissionCatalog>)

Build and register the application's PermissionCatalog (singleton) — the declared permission vocabulary plus its role→permission grants, consumed by the catalog permission resolvers and the HTTP permission policies.

public static IServiceCollection AddPermissionCatalog(this IServiceCollection services, Action<PermissionCatalog> configure)

Parameters

services IServiceCollection

The service collection to mutate.

configure Action<PermissionCatalog>

Callback that declares permissions and role grants.

Returns

IServiceCollection

The same service collection, to enable chaining.

Examples

The catalog is the vocabulary: granting a permission it does not declare throws at start-up rather than silently granting nothing:

services.AddPermissionCatalog(c =>
{
    c.Add("sims.read", "sims.write");
    c.GrantToRole("TenantAdmin", "sims.read", "sims.write");
});

AddSettingCatalog(IServiceCollection, Action<SettingCatalog>)

Build and register the application's SettingCatalog (singleton) — the declared setting vocabulary with defaults and flags, consumed by the setting provider and the encrypting store decorator.

public static IServiceCollection AddSettingCatalog(this IServiceCollection services, Action<SettingCatalog> configure)

Parameters

services IServiceCollection

The service collection to mutate.

configure Action<SettingCatalog>

Callback that declares the settings.

Returns

IServiceCollection

The same service collection, to enable chaining.

Examples

Declares each setting with its default, whether it inherits down the scope chain, and whether it is stored encrypted:

services.AddSettingCatalog(c => c.Add(
    new SettingDefinition("ui.theme", DefaultValue: "light"),
    new SettingDefinition("billing.vatId", IsInherited: false)));

AddSettingStoreFromContextFactory<TContext>(IServiceCollection)

Register the EF Core ISettingStore against TContext and the scope-fallback ISettingProvider read facade, taking a fresh context for each operation from the registered context factory. The encrypting decorator is applied exactly as it is for the shared registration.

public static IServiceCollection AddSettingStoreFromContextFactory<TContext>(this IServiceCollection services) where TContext : DbContext

Parameters

services IServiceCollection

The service collection to mutate.

Returns

IServiceCollection

The same service collection, to enable chaining.

Type Parameters

TContext

The DbContext hosting the directory tables.

Examples

Needs AddDbContextFactory<TContext>(); one context per operation:

services.AddDbContextFactory<DirectoryDbContext>();
services.AddSettingStoreFromContextFactory<DirectoryDbContext>();

Remarks

Each operation creates its own context from the registered IDbContextFactory<TContext> and disposes it afterwards, so directory operations issued concurrently within one scope do not contend and a store's commit reaches only its own rows. In exchange, a store write does not take part in a transaction the consumer opened on their own scoped context.

Requires AddDbContextFactory<TContext>(); a missing registration fails at first resolution rather than silently. Keep the factory's options aligned with the scoped registration — interceptors, query filters and conventions are configured per registration, not per context type.

Calling this together with AddSettingStore<TContext>(IServiceCollection) leaves whichever ran first in place; they do not compose.

AddSettingStore<TContext>(IServiceCollection)

Register the EF Core ISettingStore against TContext, plus the scope-fallback ISettingProvider read facade. When the registered SettingCatalog declares encrypted settings, the store is wrapped in a transparent AES-GCM decorator (requires the security plane's ISecureBlobEncryptor registration — missing it fails at first resolution, not silently).

public static IServiceCollection AddSettingStore<TContext>(this IServiceCollection services) where TContext : DbContext

Parameters

services IServiceCollection

The service collection to mutate.

Returns

IServiceCollection

The same service collection, to enable chaining.

Type Parameters

TContext

The DbContext hosting the directory tables.

Examples

Registers the store and the provider facade that walks the fallback chain. Declare the vocabulary first — a setting the catalog does not know has no default to fall back to:

services.AddSettingCatalog(c => c.Add(new SettingDefinition("ui.theme", DefaultValue: "light")));
services.AddSettingStore<DirectoryDbContext>();

Remarks

The store shares the context registered for the request, so directory operations issued concurrently within one scope fail on whichever arrives second — a database context serves one operation at a time — and the store's own commit also commits whatever else the consumer has left unsaved on that context. Register the store with AddSettingStoreFromContextFactory<TContext>(IServiceCollection) instead to give each operation its own context.

Calling both registrations leaves whichever ran first in place; they do not compose.

AddTenantMembershipStoreFromContextFactory<TContext>(IServiceCollection)

Register the EF Core ITenantMembershipStore against TContext, taking a fresh context for each operation from the registered context factory.

public static IServiceCollection AddTenantMembershipStoreFromContextFactory<TContext>(this IServiceCollection services) where TContext : DbContext

Parameters

services IServiceCollection

The service collection to mutate.

Returns

IServiceCollection

The same service collection, to enable chaining.

Type Parameters

TContext

The DbContext hosting the directory tables.

Examples

Needs AddDbContextFactory<TContext>(). Each operation takes a fresh context, so directory work issued concurrently in one scope no longer collides — in exchange, a store write does not join a transaction opened on your own scoped context:

services.AddDbContextFactory<DirectoryDbContext>();
services.AddTenantMembershipStoreFromContextFactory<DirectoryDbContext>();

Remarks

Each operation creates its own context from the registered IDbContextFactory<TContext> and disposes it afterwards, so directory operations issued concurrently within one scope do not contend and a store's commit reaches only its own rows. In exchange, a store write does not take part in a transaction the consumer opened on their own scoped context.

Requires AddDbContextFactory<TContext>(); a missing registration fails at first resolution rather than silently. Keep the factory's options aligned with the scoped registration — interceptors, query filters and conventions are configured per registration, not per context type.

Calling this together with AddTenantMembershipStore<TContext>(IServiceCollection) leaves whichever ran first in place; they do not compose.

AddTenantMembershipStore<TContext>(IServiceCollection)

Register the EF Core ITenantMembershipStore against TContext. The context's model must include the identity-directory tables — derive from IdentityDirectoryDbContext<TContext> or call ApplyIdentityDirectoryModel(ModelBuilder) in the context's OnModelCreating. The context itself must already be registered (for example via AddDbContext or a pooled factory).

public static IServiceCollection AddTenantMembershipStore<TContext>(this IServiceCollection services) where TContext : DbContext

Parameters

services IServiceCollection

The service collection to mutate.

Returns

IServiceCollection

The same service collection, to enable chaining.

Type Parameters

TContext

The DbContext hosting the directory tables.

Examples

TContext is any context whose model includes the directory tables — derive from IdentityDirectoryDbContext<TContext> or call ApplyIdentityDirectoryModel() in OnModelCreating. Every directory store in a request shares this one context:

services.AddTenantMembershipStore<DirectoryDbContext>();

Remarks

The store shares the context registered for the request, so directory operations issued concurrently within one scope fail on whichever arrives second — a database context serves one operation at a time — and the store's own commit also commits whatever else the consumer has left unsaved on that context. Register the store with AddTenantMembershipStoreFromContextFactory<TContext>(IServiceCollection) instead to give each operation its own context.

Calling both registrations leaves whichever ran first in place; they do not compose.