Skip to content

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.

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