Application security and authorization¶
This page documents the application-wide authorization architecture for ClaimBillEntry, consolidating the authorization patterns reachable from the application's own controllers and the consumed SAIF.SAIFCode.Core package (SAIF.Services assembly). Authentication is handled entirely by infrastructure and is not application-level — all requests arrive with a WindowsIdentity established by IIS Windows authentication (NTLM or Kerberos negotiation), with anonymous access disabled. See Tech debt for the NTLM finding.
Authentication architecture¶
Authentication is handled entirely by infrastructure and is not part of application code. IIS establishes a WindowsIdentity on the request context before any ClaimBillEntry action runs; the application has no code for the authentication mechanism itself.
Authorization architecture¶
ClaimBillEntry's authorization model layers an attribute-based controller role gate with a narrower, proven claim-level check, plus package-computed flags whose full consumption is not established by this run's evidence. The diagram below separates what is proven at each layer from what remains computed-but-unconsumed or untraced, per ClaimBillEntry/Controllers/EntryController.cs:224-239 and ClaimBillEntry/Controllers/BaseController.cs:31-34,38-48.
flowchart TD
Pkg["SAIF.Services ClaimSecurityService<br>computes HasConflictAccess and<br>HasSecureAccess (SVC-BR-SEC-01)"]
Pkg --> ConflictFlag["HasConflictAccess"]
Pkg --> SecureFlag["HasSecureAccess<br>(computed; no consuming<br>check found in traced code)"]
User[User request] --> IIS[IIS Windows authentication]
IIS --> Identity[WindowsIdentity established]
Identity --> Scope{"Entry, Inbox, or<br>Search controller?"}
Scope -->|"No"| Unguarded["No SaifAuthorize role check<br>(grid/provider controllers - TD-003)"]
Scope -->|"Yes"| Attr["SaifAuthorizeAttribute<br>Roles = CBPEnterBill"]
Attr -->|"Role missing"| Deny1[Access denied]
Attr -->|"Role present"| GetBill["EntryController.GetBill"]
GetBill --> ConflictCheck["UserHasAccessToClaim:<br>independent local check -<br>IsConflictClaim and<br>IsAuthorized(ConflictClaim)"]
ConflictCheck -->|"Fails"| Deny2["Error: not authorized<br>to view claim"]
ConflictCheck -->|"Passes"| Allow["Bill data returned"]
BaseCheck["BaseController.CheckSecurity<br>override returns HasConflictAccess only"]
ConflictFlag -.-> BaseCheck
BaseCheck -.-> Unknown["Inherited ClaimControllerBase<br>CheckSecurity / action-filter mechanics:<br>unknown, not traced beyond call site"]
Discard["ApplicationUser.IsAuthorized<br>(CBEDiscardBill)"] --> UIOnly["CanDiscardBill view-model flag:<br>UI button visibility only -<br>DiscardBill enforces no permission<br>beyond the CBPEnterBill role"]
SaifAuthorizeAttribute's declared-role check, IUserProfileService/ILogService/IEnvironmentService requirements, and its SecurityException-and-redirect denial path are documented via the Legends CLI† in Request pipeline and composition. The diagram is scoped to the Entry, Inbox, and Search controllers, where [SaifAuthorize(Roles = "CBPEnterBill")] is applied; the grid controllers (DiagnosisGrid, ProcedureGrid, ServiceGrid, NoteGrid) and ProviderController carry no controller-level role attribute, per Tech debt TD-003 and Hosted endpoints. EntryController.GetBill (lines 83-95, 224-239) proves only its own, independent conflict-claim check: the local UserHasAccessToClaim method calls IClaimInformationService.GetClaimSecurity(claimId).IsConflictClaim and, when true, ApplicationUser.IsAuthorized("ConflictClaim") — this does not read or consume the package-computed HasConflictAccess flag. BaseController.CheckSecurity (overriding ClaimControllerBase) is the sole proven consumer of HasConflictAccess, returning access.HasConflictAccess only (BaseController.cs:31-34); no code path in EntryController or BaseController was found consuming HasSecureAccess/SecureClaim, even though ClaimSecurityService computes it† (SVC-BR-SEC-01) — this is reported as a gap in proof, not as evidence the check does not exist elsewhere. OnActionExecuting skips the inherited base-class action-filter logic entirely for AJAX requests (BaseController.cs:38-48), so whether CheckSecurity actually runs on every request reaching BaseController-derived controllers is itself not fully traced. Internal mechanics of SaifAuthorizeAttribute (SAIF.Framework.Web.Mvc) beyond its call site are documented via retrieved behavior† above; ClaimControllerBase.CheckSecurity (SAIF.SAIFCode.Web.Mvc) internals beyond its call site remain untraced — unknown, not verified by this run**. CBEDiscardBill is checked only to populate the CanDiscardBill view-model flag that hides or shows the Discard button (EntryController.cs:65,159-167,209); DiscardBill itself performs no server-side authorization check beyond the controller-level CBPEnterBill role — see BR-SCR-006.
AD resource catalog¶
4 Active Directory resources are reachable from ClaimBillEntry's consumed interface surface.
| Resource name | Purpose | Libraries using | Enforcement type |
|---|---|---|---|
CBPEnterBill |
Primary controller-level gate — a user must hold this role to reach any action on the Entry, Inbox, or Search controllers |
SAIF.Framework.Web.Mvc (SaifAuthorizeAttribute) |
Attribute |
ConflictClaim |
Claim-level conflict access; ClaimSecurityService computes HasConflictAccess† (SVC-BR-SEC-01); proven consumed only by BaseController.CheckSecurity. EntryController.GetBill separately performs its own independent local ConflictClaim check (UserHasAccessToClaim) that does not read this flag. |
SAIF.Services (ClaimSecurityService) |
Programmatic |
SecureClaim |
Claim-level secure access; ClaimSecurityService computes HasSecureAccess† (SVC-BR-SEC-01), but no consuming check was found in traced EntryController/BaseController code — unknown whether any path enforces it** |
SAIF.Services (ClaimSecurityService) |
Programmatic (computed; consumption unproven) |
CBEDiscardBill |
Controls only the client-visible CanDiscardBill view-model flag; not a server-side discard gate |
ClaimBillEntry (EntryController, local check only) |
Programmatic (UI-visibility only) |
Scope exception¶
The template's AD-resource catalog expects a minimum of 5 entries. ClaimBillEntry reaches only 4. This is a legitimate scope exception, not a gap: SAIF.Services declares roughly 75 AD resources in total, spanning Legal, Agency, Policy, Certificate, and other domain resources, but ClaimBillEntry's consumed interface surface — IBillEntryService, IBillDiagnosisService, IBillProcedureService, IBillServiceService, INoteService, IProviderQueryProvider, IClaimInformationService, IClaimSecurityService, plus the local CBEDiscardBill check and the SAIF.Framework.Web.Mvc CBPEnterBill attribute — never constructs or calls PolicySecurityService, CertificateSecurityService, or any legal/agency resource check. The remaining roughly 71 resources are correctly excluded as not reachable from any ClaimBillEntry entry point, not fabricated as ClaimBillEntry authorization and not padded into this catalog to reach a numeric minimum. ClaimBillEntry's application surface is narrow by design — three screens over a focused set of bill-entry services — so a 4-of-5+ catalog accurately reflects the reachable authorization resources for this application; full end-to-end consumption of every resource (notably SecureClaim) was not proven by this run's evidence.
Security enforcement summary¶
| Layer | Enforcement mechanism | Count | Source |
|---|---|---|---|
| Presentation | [SaifAuthorize(Roles = "CBPEnterBill")] on Entry, Inbox, and Search controllers; no role attribute on the grid or Provider controllers |
1 resource | SAIF.Framework.Web.Mvc (SaifAuthorizeAttribute) |
| Business logic (claim-level, proven) | Programmatic ClaimSecurityService.HasConflictAccess via IsAuthorized(ConflictClaim)† (SVC-BR-SEC-01), consumed only by BaseController.CheckSecurity |
1 resource | SAIF.Services (ClaimSecurityService), reached via ClaimControllerBase/BaseController |
| Business logic (claim-level, local, independent) | EntryController.GetBill's local UserHasAccessToClaim check: IClaimInformationService.GetClaimSecurity().IsConflictClaim + ApplicationUser.IsAuthorized("ConflictClaim") — a separate enforcement point that does not read the HasConflictAccess flag above |
1 resource (same ConflictClaim AD resource, reached by an independent code path) |
ClaimBillEntry/Controllers/EntryController.cs:83-95,224-239 |
| Business logic (claim-level, computed but unconsumed) | ClaimSecurityService.HasSecureAccess via IsAuthorized(SecureClaim) is computed† (SVC-BR-SEC-01), but no consuming check was found in traced EntryController/BaseController code — unknown whether it is enforced elsewhere** |
1 resource | SAIF.Services (ClaimSecurityService) |
| Business logic (bill-level, local, UI-only) | ISystemUserProfile.IsAuthorized("CBEDiscardBill") gates only the CanDiscardBill view-model flag; not a server-side gate |
1 resource | ClaimBillEntry/Controllers/EntryController.cs |
| Data access | No data-ownership validation beyond the claim-level checks above was traced | 0 | — |
Cross-cutting authorization rules¶
Bill entry requires the CBPEnterBill role¶
| Field | Value |
|---|---|
| Statement | A user must hold the CBPEnterBill role to reach any action on the Entry, Inbox, or Search controllers. |
| Trigger | Any request to a bill-entry, inbox, or search action. |
| Enforcement | Attribute-based: [SaifAuthorize(Roles = "CBPEnterBill")], evaluated before the action method runs. |
| Enforcing libraries | SAIF.Framework.Web.Mvc (SaifAuthorizeAttribute) |
| Outcome | Request denied with a SecurityException-driven redirect when the role is missing; action proceeds when present. |
| Related resources | CBPEnterBill |
The conflict/secure claim access formulas and the bill discard permission check are not restated here as new rule identifiers, to avoid duplicating sanctioned IDs. The full ClaimSecurityService formula is defined once, as SVC-BR-SEC-01 in Business rules — see the "Authorization architecture" diagram above for what ClaimBillEntry actually consumes from it. The client-only enforcement of CBEDiscardBill is defined once, as BR-SCR-006 in Business rules, and as TD-003 in Tech debt.
Data-level authorization¶
| Entity type | Validation pattern | Enforcement library | Source |
|---|---|---|---|
| Claim (conflict, proven, package-computed) | ClaimSecurityService computes HasConflictAccess from the claim's IsConflictClaim flag and the caller's ConflictClaim resource membership† (SVC-BR-SEC-01); consumed only by BaseController.CheckSecurity |
SAIF.Services |
ClaimControllerBase ctor → IClaimSecurityService; BaseController.CheckSecurity → access.HasConflictAccess |
| Claim (conflict, local, independent) | EntryController.GetBill separately validates ConflictClaim access via its own local UserHasAccessToClaim method — this is not a consumer of ClaimSecurityService.HasConflictAccess |
ClaimBillEntry (EntryController) |
EntryController.GetBill → IClaimInformationService.GetClaimSecurity().IsConflictClaim + ApplicationUser.IsAuthorized("ConflictClaim") |
| Claim (secure, computed but unconsumed) | ClaimSecurityService also computes HasSecureAccess from IsSecureClaim/SecureClaim† (SVC-BR-SEC-01), but no ClaimBillEntry code path was found consuming it — unknown whether it is enforced elsewhere** |
SAIF.Services |
ClaimControllerBase ctor → IClaimSecurityService |
Security dependencies¶
| Dependency | Type | Purpose |
|---|---|---|
| IIS Windows authentication (NTLM/Kerberos) | Infrastructure | Establishes the WindowsIdentity on every request; anonymous access disabled |
SAIF.Framework.Web.Mvc |
NuGet package | Ships SaifAuthorizeAttribute, the attribute-based CBPEnterBill role gate |
SAIF.SAIFCode.Core package (SAIF.Services assembly) |
NuGet package | Ships ClaimSecurityService, the programmatic ConflictClaim/SecureClaim checks |
SAIF.SAIFCode.Web.Mvc |
NuGet package | Ships ClaimControllerBase, the base controller that constructs ClaimSecurityService |
| Active Directory | Infrastructure | User/role membership store underlying IsAuthorized/IUserProfileService resolution |
Notes¶
- The AD resource catalog intentionally lists 4 entries, not the template's minimum of 5 — see "Scope exception" above.
SaifAuthorizeAttribute(SAIF.Framework.Web.Mvc) role-check behavior is documented via retrieved behavior† in Request pipeline and composition.ClaimControllerBase.CheckSecurity(SAIF.SAIFCode.Web.Mvc) internals beyond its call site remain untraced — not verified by this run.
Related documentation¶
- Index
- Overview
- Architecture
- Dependencies
- Configuration
- Operations and processes
- Business rules
- Data model
- Tech debt
- Hosted endpoints
- Screen catalog
Note: Statements marked with
†are derived from dependency library documentation via the Legends CLI. Statements marked with**could not be confirmed; treat as unknown until verified.
Sources¶
- ClaimBillEntry/Controllers/EntryController.cs
- ClaimBillEntry/Controllers/BaseController.cs