Evaluate a SecurityApiRequirement¶
Evaluates a SecurityApiRequirement by calling the remote SecurityApi once per listed role, using OR semantics across roles.
Security enforcement points: EP-04 (SecurityApiHandler).
| Field | Value |
|---|---|
| Operation ID | OP-03 |
| Trigger | ASP.NET Core authorization middleware evaluates the built policy's SecurityApiRequirement against the current ClaimsPrincipal. |
| Inputs | AuthorizationHandlerContext (current user, requirement), SecurityApiRequirement.ProvidedRoles. |
| Outputs | context.Succeed(requirement) when any role authorizes the user; otherwise the requirement remains unsatisfied. |
| Primary components | SecurityApiHandler.HandleRequirementAsync |
| Entry point | src/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/Authorization/SecurityApiHandler.cs |
Steps¶
- If
context.User.Identity.Nameis null or whitespace, return without callingcontext.Succeed— this is an empty-name guard;HandleRequirementAsyncnever inspectsIdentity.IsAuthenticated(BR-AUTH-006) - Compute
userNameas the second\-delimited segment ofIdentity.Name(Split("\\")[1]) when the name contains a backslash, or the full name if there is no\\— not necessarily "everything after the last backslash" (BR-AUTH-007) - Split
requirement.ProvidedRoleson,. For each role,await ISecurityClient.IsAuthorized(userName, role); callcontext.Succeed(requirement)on anytrueresult, without stopping the loop and without ever reversing an earlierSucceedcall when a later role returnsfalse(BR-AUTH-008) - 3.1 Normalize the user ID: replace
\with/inuserName. - 3.2 Apply the resource-suffix rewrite to
role: trim the role; if the trimmed role ends withresource(case-insensitive), replace the last occurrence ofresourcewith the configuredSecurityClient:resourcesuffixvalue; trim the result again. - 3.3 Issue
GET /v1/Users/IsAuthorized/{userId}/{suffixRole}. - 3.4 On success, return the deserialized
bool. On a non-success response with an inner exception, throwSecurityClientException(message, innerException). On a non-success response without an inner exception, throwSecurityClientException(message)— there is no default-denyfalsefor a failed call.
Origin: Steps 3.1–3.4 are implemented in Check role authorization remotely (
SAIF.NetCore.AuthService) and executed on behalf of this operation, describing the library's registeredSecurityClientimplementation — not every possibleISecurityClienta consumer could substitute.
Process flow¶
The following diagram visualizes this operation's control flow. context.Succeed(requirement) accumulates across loop iterations — once called for any role, a later role returning false does not undo it; the requirement is satisfied if Succeed was called at least once during the loop.
flowchart TD
Start([Requirement evaluation]) --> NameCheck{Identity.Name null/whitespace?}
NameCheck -->|Yes| Deny(["Requirement not satisfied<br/>no remote call made"])
NameCheck -->|No| Strip["userName = second segment of Split('\\')<br/>or full name if no backslash"]
Strip --> Loop[For each role in ProvidedRoles]
Loop --> Call["await ISecurityClient.IsAuthorized user, role<br/>may throw SecurityClientException"]
Call --> Result{Returned true?}
Result -->|Yes| Succeed["context.Succeed requirement<br/>accumulated, not reversible"]
Result -->|No| More{More roles remain?}
Succeed --> More
More -->|Yes| Loop
More -->|No| Final{Succeed called<br/>at least once?}
Final -->|Yes| Done([Requirement satisfied])
Final -->|No| Deny2([Requirement not satisfied])
Failure and edge-case behavior¶
- A non-success response from any role's remote call throws
SecurityClientExceptionfrom inside the handler (surfaced by the shared response handler described in Check role authorization remotely), surfacing as an unhandled exception rather than a 403*. This is distinct from an ordinaryfalseresult, which simply continues the loop. - The handler never calls
context.Fail(); an unsatisfied requirement denies access purely by omission. - Once
context.Succeed(requirement)has been called for any role, the requirement is satisfied even if a later role in the same loop returnsfalse; the loop does not short-circuit on success but a laterfalsenever reverses the earlier success.
Related documentation¶
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.AuthService/SAIF.NetCore.AuthService/SAIF.NetCore.AuthService/Authorization/SecurityApiHandler.cs