SAIF.Web.API security and authorization¶
This page documents authorization mechanisms implemented or consumed by SAIF.Web.API. Authentication is handled entirely by infrastructure (Windows/AD integrated authentication, inferred from the WindowsPrincipal cast in ApiResponseHandler)* and is not application-level — the library only reads an already-established identity. SAIF.Web.API is a consumer-side, fully delegated authorization library: it supplies the enforcement mechanism (a Web API AuthorizeAttribute subclass and an HTTPS-enforcing action filter), while the enforcement policy (which resource names guard which endpoints) and the enforcement decision (whether a user holds a resource) are both assumed to live outside this repository — no such policy or decision logic exists inside this library.*
Authorization architecture¶
Authorization is centralized and delegated: SaifAuthorizeAttribute resolves ISecurityApiClient and IEnvironmentService per request from the Web API dependency scope and delegates the actual per-role decision to ISecurityApiClient.IsAuthorized(user, role). This library defines the enforcement point, not the decision logic — the concrete authorization mechanism (WCF SecurityService facade, HTTP API, or another mechanism) is implemented in the SAIF.Framework.Core package and could not be determined from this repository.**
flowchart TD
Caller["Calling code / decorated<br>action"] --> Attr["SaifAuthorizeAttribute.<br>IsAuthorized"]
Attr --> Scope["Web API IDependencyScope"]
Scope --> Sec["ISecurityApiClient<br>(SAIF.Framework.Core)"]
Scope --> Env["IEnvironmentService<br>(SAIF.Framework.Core)"]
Sec --> Decision{"IsAuthorized(user, role)<br>for any declared role"}
Decision -->|true| Allow[Request proceeds]
Decision -->|false| Deny["HandleUnauthorized<br>Request<br>401 + SecurityException<br>log"]
AD resource catalog¶
No AD group or resource names are defined, referenced, or hard-coded anywhere in this repository — resource/role names are supplied entirely by the consuming application as params string[] roles passed to the SaifAuthorizeAttribute constructor, e.g. [SaifAuthorizeAttribute(roles)]; no such application exists inside this library.*
| Resource name | Purpose | Enforcement point | Source |
|---|---|---|---|
| (none — supplied by consumer) | Consumer-supplied resource/role names passed to the attribute constructor, e.g. [SaifAuthorize("SecureClaim")] |
SaifAuthorizeAttribute constructor → AuthorizeAttribute.Roles → ISecurityApiClient.IsAuthorized(user, role) |
src/SAIF.Web.API/SaifAuthorizeAttribute.cs |
Authorization enforcement points¶
Attribute-based authorization¶
| Controller / Action | Attribute | Resource name(s) | Source |
|---|---|---|---|
| Consumer-decorated controller/action (none exist inside this library) | [SaifAuthorize] (SaifAuthorizeAttribute, sealed, derives System.Web.Http.AuthorizeAttribute) |
Consumer-supplied via params string[] roles |
src/SAIF.Web.API/SaifAuthorizeAttribute.cs |
| Consumer-decorated controller/action (none exist inside this library) | [RequireSSL] (RequireSSLAttribute, derives System.Web.Http.Filters.ActionFilterAttribute) |
N/A (transport security, not resource-based) | src/SAIF.Web.API/RequireSSLAttribute.cs |
Neither attribute is applied anywhere inside this repository — there are no controllers or actions here. Both are library-provided primitives intended for consuming Web API applications to decorate their own controllers/actions with, though no such usage is observed in this repository.*
Programmatic authorization checks¶
| Class | Method | Resource / Role | Check type | Source |
|---|---|---|---|---|
SaifAuthorizeAttribute |
IsAuthorized(HttpActionContext) |
Caller-supplied roles (OR semantics) | ISecurityApiClient.IsAuthorized(user, role) — see BR-WEBAPI-017 |
src/SAIF.Web.API/SaifAuthorizeAttribute.cs |
No other programmatic authorization checks exist — no IsInRole, HasAccess, CheckAccess, or CheckClaim calls occur outside SaifAuthorizeAttribute, and no ISecurityManager/clsSecurityPrincipal-style types are defined or referenced anywhere in this repository.
Data-level authorization¶
None detected. No entity-ownership or data-scope validation exists — no CheckValidContext, IsValidPolicyForCurrentUser, ValidateOwnership, or equivalent methods. This library performs no database access of any kind, so no SQL-based ownership checks are possible. The entire authorization surface is coarse-grained, role/resource-name based, and evaluated per action; data-level scoping is the responsibility of consuming applications.*
Segregation of duties¶
None detected. No *SegregationOfDuties*/*SOD* types and no mutually-exclusive-privilege rules exist anywhere in the repository.
Security interfaces and contracts¶
| Interface / Class | Role | Consumers | Source |
|---|---|---|---|
ISecurityApiClient (SAIF.Core.Services.UserProfile) |
Authorization decision provider: IsAuthorized(string user, string role) |
SaifAuthorizeAttribute |
SAIF.Framework.Core NuGet package (consumed by src/SAIF.Web.API/SaifAuthorizeAttribute.cs) |
IEnvironmentService (SAIF.Core.Services) |
Current-user identity (User.Identity.Name, UserId()) and configuration access |
ApiResponseHandler, SaifAuthorizeAttribute |
SAIF.Framework.Core NuGet package |
ILogService / ILogServiceForApi (SAIF.Core.Services) |
Logging of authorization denials and API exceptions | ApiResponseHandler, SaifAuthorizeAttribute |
SAIF.Framework.Core NuGet package |
All three are resolved through ASP.NET Web API's per-request IDependencyScope service locator (request.GetDependencyScope().GetService(typeof(T))), never by constructor injection. If the hosting application does not register ISecurityApiClient and IEnvironmentService with its IDependencyResolver, SaifAuthorizeAttribute.IsAuthorized throws MissingDependencyException rather than denying access — the failure surfaces as a server error, not a 401 (see BR-WEBAPI-014); no hosting application or registration exists in this repository to confirm this end-to-end.*
Transport security¶
RequireSSLAttribute is a transport-security control, not an authorization control, but is cataloged here as a security enforcement point. It redirects a non-HTTPS request to HTTPS on port 443 unless the request is local and the host's RequireSSLForLocal app setting is absent or parses to false (see BR-WEBAPI-012 and BR-WEBAPI-013). The redirect hard-codes port 443 and uses HttpContext.Current.Response.Redirect, coupling this filter to System.Web (IIS/ASP.NET) hosting.
Security observations¶
The following observations are not business rules but are notable for downstream review:
- 401 vs. 403 semantics disagree across paths. An authenticated-but-unauthorized user denied by
SaifAuthorizeAttributereceives401 Unauthorized(BR-WEBAPI-018), whileExceptionHandler.ToHttpErrormapsSAIF.API.Exceptions.UnauthorizedAccessExceptionto403 Forbidden(BR-WEBAPI-011) — the conventional code for an authorization denial. The two paths disagree. - User name echoed in the 401 body. The denial response message
The user '{user}' is not authorized.discloses the resolved account name to the caller. - Redaction scope is limited. The password-redaction regex in
BuildTraceMessage(BR-WEBAPI-007) covers only the input-stream copy; request/response bodies and headers (including anyAuthorizationheader) are written to the debug trace un-redacted. - Error-detail exposure.
GetErrorResponsepreferserror.ExceptionMessage, so withIncludeErrorDetailPolicy.Always(which BR-WEBAPI-010's guidance text actively encourages) raw exception messages reach the client. - Base identity check bypassed.
SaifAuthorizeAttributenever callsbase.IsAuthorized(actionContext), soAuthorizeAttribute's built-inIdentity.IsAuthenticatedcheck andUsersproperty are bypassed entirely; an attribute applied with no roles authorizes every request, including unauthenticated ones (see BR-WEBAPI-015).* forceProductionRoleis dead code. TheSaifAuthorizeAttribute(bool forceProductionRole, params string[] roles)constructor stores the flag in_ForceProductionRole, which is never read anywhere in the repository; the two-argument overload behaves identically to the one-argument overload.- Identity source diverges from the request principal. Authorization is evaluated against
IEnvironmentService.User.Identity.Name, notactionContext.RequestContext.Principal— whether the host guarantees these are the same principal is unknown from this repository.**
Notes¶
- Mark inferred statements with
*and unknown statements with**. Do not use bold inline confidence labels.
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.
Related documentation¶
- Index
- Overview
- Architecture
- Dependencies
- Configuration
- Operations and processes
- Business rules
- API reference
Sources¶
src/SAIF.Web.API/SaifAuthorizeAttribute.cssrc/SAIF.Web.API/RequireSSLAttribute.cssrc/SAIF.Web.API/ExceptionHandler.cssrc/SAIF.Web.API/ApiResponseHandler.cssrc/SAIF.Web.API/HttpRequestExtensions.cssrc/SAIF.Web.API/app.configsrc/SAIF.Web.API/SAIF.Web.API.csprojsrc/SAIF.Web.API.Core/SAIFException.cs