Skip to content

SAIF.NetCore.NtlmApiAuth business rules

This page captures business rules enforced by this library, including the rules governing the dual-identity authorization check that delegates part of its decision to SAIF.NetCore.AuthService's SecurityClient.IsAuthorized.

BR-NTLM-001 OnBehalfOfUser header and claim

Field Value
Statement The on-behalf-of user is carried in an HTTP header named OnBehalfOfUser and stored as a claim of type OnBehalfOfUser; blank values are ignored.
Trigger Inbound request / outbound forward
Enforcement OnBehalfOfUserClaimService.SetOnBehalfOfUserClaim; AuthorizationHandlerContextExtensions.OnBehalfOfUser; HttpContextAccessorExtensions.OnBehalfOfUser
Outcome Claim added / header read
Source src/SAIF.NetCore.NtlmApiAuth/src/SAIF.NetCore.NtlmApiAuth/Services/OnBehalfOfUserClaimService.cs, Constants.cs

BR-NTLM-002 Claim only added for authenticated identities

Field Value
Statement The on-behalf-of claim is only added to an authenticated ClaimsIdentity; headers on anonymous requests are ignored.
Trigger Inbound request
Enforcement OnBehalfOfUserClaimService.SetOnBehalfOfUserClaim
Outcome No claim for anonymous requests
Source src/SAIF.NetCore.NtlmApiAuth/src/SAIF.NetCore.NtlmApiAuth/Services/OnBehalfOfUserClaimService.cs

BR-NTLM-003 Middleware never blocks

Field Value
Statement The claim middleware never blocks a request; enforcement happens only in authorization policies.
Trigger Every request
Enforcement OnBehalfOfUserClaimMiddleware.InvokeAsync
Outcome next() is always invoked
Source src/SAIF.NetCore.NtlmApiAuth/src/SAIF.NetCore.NtlmApiAuth/Middleware/OnBehalfOfUserClaimMiddleware.cs

BR-NTLM-004 Blank request identity is never authorized

Field Value
Statement A request with no (or blank) authenticated identity name is never authorized; SecurityAPI is not called.
Trigger Requirement evaluation
Enforcement NtlmApiAuthorizationService.IsAuthorized; RoleRequirement.HandleRequirementAsync
Outcome Returns false → context.Fail()
Source src/SAIF.NetCore.NtlmApiAuth/src/SAIF.NetCore.NtlmApiAuth/Services/NtmlApiAuthorizationService.cs, Authorization/RoleRequirement.cs

BR-NTLM-005 Request identity must itself be authorized

Field Value
Statement The calling (request) identity must itself be authorized for the role; if it is not, the on-behalf-of user is not evaluated.
Trigger Requirement evaluation
Enforcement NtlmApiAuthorizationService.IsAuthorized, which delegates to AuthService's SecurityClient.IsAuthorized(userId, role) — confirmed against the repository's 10.x source; applicability to the pinned 8.2023.319.2 package is inferred*
Outcome Returns false without evaluating the on-behalf-of user
Source src/SAIF.NetCore.NtlmApiAuth/src/SAIF.NetCore.NtlmApiAuth/Services/NtmlApiAuthorizationService.cs; src/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/Clients/SecurityClient.cs

BR-NTLM-006 Both identities must pass when on-behalf-of user is present

Field Value
Statement When an on-behalf-of user is present, both identities must be authorized for the role; when absent, the request identity alone suffices.
Trigger Requirement evaluation
Enforcement NtlmApiAuthorizationService.IsAuthorized, which delegates to AuthService's SecurityClient.IsAuthorized(userId, role) for each identity — confirmed against the repository's 10.x source; applicability to the pinned 8.2023.319.2 package is inferred*
Outcome true only if both identities pass
Source src/SAIF.NetCore.NtlmApiAuth/src/SAIF.NetCore.NtlmApiAuth/Services/NtmlApiAuthorizationService.cs; src/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/Clients/SecurityClient.cs

BR-NTLM-007 Multi-role policies are AND

Field Value
Statement A policy built with AddPolicies(string policyName, params string[] roles) contains one requirement per role; every requirement must succeed, and any failing RoleRequirement calls context.Fail(), so multi-role policies behave as AND, contradicting the README's OR description.*
Trigger Policy evaluation
Enforcement ConfigureRoleAuthorizationOptions.AddPolicies; RoleRequirement.HandleRequirementAsync
Outcome context.Fail() for the authorization requirement unless every per-role RoleRequirement succeeds; ASP.NET Core's authorization middleware and the host then translate an overall-failed authorization result into the actual response (typically 403, but this is a framework/host behavior, not something this library sets directly)*
Source src/SAIF.NetCore.NtlmApiAuth/src/SAIF.NetCore.NtlmApiAuth/Options/ConfigureRoleAuthorizationOptions.cs, Authorization/RoleRequirement.cs

BR-NTLM-008 SecurityAPI failures fail closed via exception

Field Value
Statement A SecurityAPI failure is not treated as "not authorized"; SecurityClientException propagates out of the handler to the caller.
Trigger Remote call failure
Enforcement RoleRequirement.HandleRequirementAsync (no try/catch); originates in AuthService's SecurityClient.HandleSecurityServiceGetResponse<T> — confirmed against the repository's 10.x source; applicability to the pinned 8.2023.319.2 package is inferred*
Outcome The uncaught exception propagates out of HandleRequirementAsync to whatever invoked authorization (typically ASP.NET Core's authorization middleware); the resulting HTTP response is produced by that caller/host's own exception handling, not by this library*
Source src/SAIF.NetCore.NtlmApiAuth/src/SAIF.NetCore.NtlmApiAuth/Authorization/RoleRequirement.cs; src/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/Clients/SecurityClient.cs

BR-NTLM-009 Header configuration enables persistence

Field Value
Statement Configuring a client for on-behalf-of authorization enables header persistence, so the user header is sent on every request made by that client instance, and resets other client options to defaults.
Trigger Client configuration
Enforcement IHttpJsonClientExtensions.ConfigureOnBehalfOfUserAuthorization
Outcome PersistHeadersAfterRequest = true
Source src/SAIF.NetCore.NtlmApiAuth/src/SAIF.NetCore.NtlmApiAuth/Extensions/IHttpJsonClientExtensions.cs

BR-NTLM-010 Header added only when non-blank; duplicate add throws

Field Value
Statement The outbound header is only added when the user name is non-empty/non-blank; adding it twice to the same client throws ArgumentException.*
Trigger Client configuration / forward
Enforcement ConfigureOnBehalfOfUserAuthorization; ForwardOnBehalfOfUserHeader
Outcome Header added, or ArgumentException
Source src/SAIF.NetCore.NtlmApiAuth/src/SAIF.NetCore.NtlmApiAuth/Extensions/IHttpJsonClientExtensions.cs, Extensions/HttpContextAccessorExtensions.cs

BR-NTLM-011 User name normalization

Field Value
Statement User names are normalized by removing a DOMAIN\ prefix and an @domain suffix (only when the separator index is greater than 1). Applied to the request user on the server and, by default, to the outbound user name on the client.
Trigger Name extraction
Enforcement StringExtensions.DomainlessUser; called from RoleRequirement, MvcCurrentUserService, BlazorCurrentUserService
Outcome Short (domainless) name
Source src/SAIF.NetCore.NtlmApiAuth/src/SAIF.NetCore.NtlmApiAuth/Extensions/StringExtensions.cs

BR-NTLM-012 Policies defined by subclassing ConfigureRoleAuthorizationOptions

Field Value
Statement Policies are defined in code by subclassing ConfigureRoleAuthorizationOptions and overriding SetPolicies; each role becomes a SecurityAPI-backed requirement.
Trigger Startup
Enforcement ConfigureRoleAuthorizationOptions.Configure/AddPolicies; IServiceCollectionExtensions.AddNtlmApiAuthorization<T>
Outcome Named policies registered
Source src/SAIF.NetCore.NtlmApiAuth/src/SAIF.NetCore.NtlmApiAuth/Options/ConfigureRoleAuthorizationOptions.cs

BR-NTLM-013 Current-user source depends on client type

Field Value
Statement The current-user source depends on client type: MVC uses HttpContext.User; Blazor uses AuthenticationStateProvider. MVC is the default.
Trigger Client registration
Enforcement AddNtmlApiAuthorizationClientServices
Outcome ICurrentUserService implementation chosen
Source src/SAIF.NetCore.NtlmApiAuth/src/SAIF.NetCore.NtlmApiAuth/Extensions/IServiceCollectionExtensions.cs

BR-NTLM-014 Swagger header only shown when debugging

Field Value
Statement The Swagger OnBehalfOfUser header parameter is only added when a debugger is attached at startup.
Trigger Swagger configuration
Enforcement SwaggerGenOptionsExtensions.AddDebuggerOnBehalfOfHeader
Outcome Header parameter shown in debug Swagger UI only
Source src/SAIF.NetCore.NtlmApiAuth/src/SAIF.NetCore.NtlmApiAuth/Extensions/SwaggerGenOptionsExtensions.cs

BR-NTLM-015 AuthorizationResource suffix rewrite — unwired utility

Field Value
Statement A public, unwired utility converts an AD resource group to its environment counterpart by replacing a trailing resource with the supplied suffix, or appending the suffix if absent.*
Trigger Caller-invoked
Enforcement StringExtensions.AuthorizationResource
Outcome e.g. SomeGroupTestResource
Source src/SAIF.NetCore.NtlmApiAuth/src/SAIF.NetCore.NtlmApiAuth/Extensions/StringExtensions.cs

BR-NTLM-016 Environment role-suffix rewrite and domain separator normalization

Field Value
Statement Role names are rewritten for the environment (a role name ending in the literal resource has that trailing token replaced with the configured resourcesuffix value) and the user's \ is replaced with / before every SecurityAPI call made on behalf of this library. This was confirmed by inspecting the repository's 10.x SecurityClient source; applicability to the pinned 8.2023.319.2 package version consumed by this library is inferred*.
Trigger Each ISecurityClient.IsAuthorized call reached from NtlmApiAuthorizationService
Enforcement AuthService's SecurityClient.IsAuthorized / GetSuffixRole
Outcome Environment-specific AD group checked
Source src/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/Clients/SecurityClient.cs

Notes

  • BR-NTLM-005, BR-NTLM-006, BR-NTLM-008, and BR-NTLM-016 describe behavior partly implemented in SAIF.NetCore.AuthService's SecurityClient.IsAuthorized, reached transitively from NtlmApiAuthorizationService.IsAuthorized (see Dependencies for the full call-chain citation); they are retained here because they determine the outcome of this library's own authorization decision. This same-repository AuthService behavior was confirmed by inspecting the repository's 10.x SecurityClient source; its applicability to the 8.2023.319.2 package version actually pinned by this library is inferred*.

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.NtlmApiAuth/src/SAIF.NetCore.NtlmApiAuth/Services/NtmlApiAuthorizationService.cs
  • src/SAIF.NetCore.NtlmApiAuth/src/SAIF.NetCore.NtlmApiAuth/Authorization/RoleRequirement.cs
  • src/SAIF.NetCore.NtlmApiAuth/src/SAIF.NetCore.NtlmApiAuth/Options/ConfigureRoleAuthorizationOptions.cs
  • src/SAIF.NetCore.NtlmApiAuth/src/SAIF.NetCore.NtlmApiAuth/Middleware/OnBehalfOfUserClaimMiddleware.cs
  • src/SAIF.NetCore.NtlmApiAuth/src/SAIF.NetCore.NtlmApiAuth/Services/OnBehalfOfUserClaimService.cs
  • src/SAIF.NetCore.NtlmApiAuth/src/SAIF.NetCore.NtlmApiAuth/Extensions/IHttpJsonClientExtensions.cs
  • src/SAIF.NetCore.NtlmApiAuth/src/SAIF.NetCore.NtlmApiAuth/Extensions/HttpContextAccessorExtensions.cs
  • src/SAIF.NetCore.NtlmApiAuth/src/SAIF.NetCore.NtlmApiAuth/Extensions/StringExtensions.cs
  • src/SAIF.NetCore.NtlmApiAuth/src/SAIF.NetCore.NtlmApiAuth/Extensions/IServiceCollectionExtensions.cs
  • src/SAIF.NetCore.NtlmApiAuth/src/SAIF.NetCore.NtlmApiAuth/Extensions/SwaggerGenOptionsExtensions.cs
  • src/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/Clients/SecurityClient.cs
  • src/SAIF.NetCore.NtlmApiAuth/README.md