Application security and authorization¶
This page documents the application-wide authorization architecture for LegalMaintenance, consolidating authorization patterns from all libraries and the front-end layer. Authentication is handled entirely by infrastructure (NTLM/AD) and is not application-level — all code receives a WindowsIdentity on the request context.
Authentication architecture¶
Authentication is handled entirely by infrastructure and is not part of application code. All requests arrive with a WindowsIdentity established by IIS via NTLM/Windows-integrated authentication (<authentication mode="Windows" />); the application has no code for the authentication mechanism itself.
Authorization architecture¶
All authorization in this application resolves to a single primitive: clsSecurityPrincipal.IsAuthorized(resourceName), supplied by the SAIF.BOF.Framework NuGet package (SAIF.Framework.Security). The web tier never names an AD group directly — it names a base resource name, and the framework appends an environment suffix (Resource in production, TestResource in non-production) before performing the AD group-membership lookup.* The clsSecurityPrincipal travels from Model.Context.SecurityPrincipal (session-held view state) → manager constructor → LegalManagerBase.SecurityPrincipal → IsAuthorized; the web tier never constructs or mutates a principal.
flowchart TD
User[User Request] --> IIS[IIS NTLM Authentication]
IIS --> Identity[WindowsIdentity Established]
Identity --> Manager["LegalManagerBase-derived<br>Manager"]
Manager --> Principal[clsSecurityPrincipal]
Principal --> IsAuth[IsAuthorized resourceName]
IsAuth --> AD[("Active Directory group<br>membership")]
AD --> Result[Access Decision]
AD resource catalog¶
| Resource name | Purpose | Libraries using | Enforcement type |
|---|---|---|---|
LNView |
Legal view-only membership; when the principal is in the group, editing is suppressed | SAIF.Application.Claim.Legal | Programmatic (LegalManagerBase.IsInViewOnly) — the only resource reached by LegalMaintenance web-tier code (6 call sites) |
LNAdmin |
Legal administrator; bypasses claim conflict/exposure gating in manager retrieve logic | SAIF.Application.Claim.Legal | Programmatic (LegalManagerBase.IsInAdminGroup) — no direct screen call, reached transitively |
LNCaseUpdate |
Legal case update authority | SAIF.Application.Claim.Legal | Programmatic (LegalManagerBase.IsInCaseUpdateGroup) — not consumed by LegalMaintenance; used by sibling LegalNet case managers |
LNConflict |
Visibility of worker-conflict (confidential) claims | SAIF.Application.Claim.Legal | Programmatic (LegalManagerBase.HasLegalConflictAccess) — manager-internal, no direct screen call |
LNExposure |
Visibility of exposure / health-issue claims | SAIF.Application.Claim.Legal | Programmatic (LegalManagerBase.HasLegalExposureAccess) — manager-internal, no direct screen call |
ConflictClaim |
Claim-level conflict access token | SAIF.Application.Claim | Programmatic (ClaimUserAccess.ConflictAccess → UserAccess.HasAccess) — requires a claim context, which LegalMaintenance never sets |
LNNoteView |
Legal case-note read access | SAIF.Application.Claim.Legal | Programmatic (clsCaseNotesManager) — LegalNet application only, not LegalMaintenance |
LNUpdate |
Legal case-note update access | SAIF.Application.Claim.Legal | Programmatic (clsCaseNotesManager) — LegalNet application only |
LNLCEUpdate |
Legal calendar-event update | SAIF.Application.Claim.Legal | Programmatic (clsScheduleManager) — LegalNet application only |
LNDueDateUpdate |
Legal due-date update | SAIF.Application.Claim.Legal | Programmatic (clsScheduleManager) — LegalNet application only |
Security enforcement summary¶
| Layer | Enforcement mechanism | Count | Libraries |
|---|---|---|---|
| Presentation | No [SAIFAuthorize]/[SaifAuthorize] attributes found; screens display/hide toolbar state based on manager properties |
0 | LegalMaintenance |
| Business logic | Programmatic IsAuthorized/HasAccess calls |
10 (13 total resources in reachable hierarchy, 1 actually evaluated by web-tier code) | SAIF.Application, SAIF.Application.Claim.Legal, SAIF.Application.Claim |
| Data access | Data ownership validation | 1 (confidential-claim/case gating, computed but only ConflictAccess hard-blocked) |
SAIF.Application.Claim, SAIF.Application.Claim.Legal |
| Infrastructure | SOD checks | 0 | n/a |
Authorization enforcement points¶
Every screen builds its manager in Page_Init with the identical two-argument pattern Model.SetActiveManager(New Manager(Model.DatabaseEnvironment, Model.Context.SecurityPrincipal)). The clsSecurityPrincipal travels Model.Context.SecurityPrincipal (session-held view state) → manager constructor → LegalManagerBase.SecurityPrincipal → IsAuthorized; the web tier never constructs or mutates a principal.
| Screen | File | Check | Guard condition | Effect on evaluation True |
|---|---|---|---|---|
| Attorney Assignment | frmAttorneyAssignment.aspx.vb |
Manager.IsInViewOnly |
Inside If Not IsPostBack, after BindObjects() |
DeleteButton/InsertButton/SaveButton.Enabled = False |
| Attorney Profile | frmAttorneyProfile.aspx.vb |
Manager.IsInViewOnly |
Inside If Not IsPostBack, after Manager.GetProfiles() |
Delete/Insert/Save disabled |
| Attorney Profile | frmAttorneyProfile.aspx.vb |
Manager.IsViewOnly |
Inside LoadData(), called from the Page_Load first-load branch |
Utilities.clsControlManager.EnablePageControl(Me, False) — disables every control on the page*, unreachable in practice (see below) |
| Hearing Location | frmHearingLocation.aspx.vb |
Manager.IsInViewOnly |
Inside If Not IsPostBack, after LoadData() + ApplyPrefs() |
Delete/Insert/Save disabled |
| Legal Person | frmLegalPerson.aspx.vb |
Manager.IsInViewOnly |
Inside If Not IsPostBack |
Delete/Insert/Save disabled |
| Other Firms | frmOtherFirms.aspx.vb |
Manager.IsInViewOnly |
Inside If Not IsPostBack |
Delete/Insert/Save disabled |
| Rotation | frmRotation.aspx.vb |
Manager.IsInViewOnly |
Inside If Not IsPostBack, after LoadData() |
Delete/Insert/Save disabled |
Total enforcement points in the web project: 7 (6 × IsInViewOnly + 1 × IsViewOnly). Every IsInViewOnly block is a pure demotion of a toolbar that is set enabled immediately beforehand.
Pages with zero authorization enforcement: Default (redirect-only landing page), frmPrintPreview (streams a generated PDF; relies on the caller having already produced the report into the session model plus possession of the __SAIFPID view ID, with no resource check), SessionPing (keep-alive only), and DataHelper (see below).
frmAttorneyProfile's IsViewOnly gate reads AppManagerBase.SecurityRole, which defaults to AppSecurityRole.NoAccess and is mutated only via ClaimAppManager.OnCheckSecurity, reachable only through SetClaimContext. No LegalMaintenance code-behind calls SetClaimContext, so SecurityRole remains NoAccess for the lifetime of a LegalMaintenance manager and the whole-page lockdown on Attorney Profile never executes — it is dead code.*
DataHelper.aspx (Inherits System.Web.UI.Page, bypassing clsLegalMaintenanceAncestor) copies every Request.Form key/value into a dictionary with no filtering, resolves its manager by reading session directly via an attacker-supplied ViewID, and calls Manager.ProcessAjaxRequest(requestItems) inside a Try/Catch with an empty catch block. It performs no IsInViewOnly/IsViewOnly/resource check — a principal in the LNView group has the toolbar disabled on every screen but is not prevented from posting to this endpoint (see SEC-APP-003 below).
All enforcement is UI-only: no Save/Insert/Delete handler in the web project re-tests authorization before invoking manager mutations, and there is no fail-closed default anywhere in the web tier — the floor of the permission model is a fully enabled toolbar.
Security interfaces and contracts¶
| Interface / contract | Type | Purpose | Consumers |
|---|---|---|---|
clsSecurityPrincipal.IsAuthorized(resourceName As String) As Boolean |
Method on SAIF.Framework.Security (SAIF.BOF.Framework NuGet package) |
Single primitive through which all authorization in this application resolves; the framework appends an environment suffix (Resource in production, TestResource in non-production) to the supplied base resource name before performing the AD group-membership lookup* |
LegalManagerBase.IsInViewOnly, LegalManagerBase.IsInAdminGroup, LegalManagerBase.IsInCaseUpdateGroup, LegalManagerBase.HasLegalConflictAccess, LegalManagerBase.HasLegalExposureAccess |
LegalManagerBase.SecurityPrincipal |
Property (constructor-injected) | Carries the clsSecurityPrincipal from Model.Context.SecurityPrincipal into manager instances; the web tier never constructs or mutates a principal |
All LegalManagerBase-derived managers |
AppSecurityRole enum (ViewOnly, Update, NoAccess) |
Enum + AppManagerBase.SecurityRole property |
Non-AD, claim-context-driven authorization role; defaults to NoAccess and is set only via ClaimAppManager.OnCheckSecurity |
AppManagerBase.IsViewOnly, IsUpdateable, IsRestricted/IsAccessible |
ClaimAppManager.OnCheckSecurity() / SetClaimContext(inClaimID) |
Method pair | Would populate AppSecurityRole and claim-level access tokens (ConflictAccess, ExposureAccess, SecureClaimAccess, HealthIssueAccess) for a given claim context |
Not invoked by any LegalMaintenance code-behind — this application never sets a claim context |
clsAttorneyTableManager.ProcessAjaxRequest(requestItems As Dictionary(Of String, String)) |
Method | Entry point for DataHelper.aspx's unauthenticated-at-the-web-tier grid mutation dispatch |
DataHelper.aspx.vb |
WCF SecurityService (resolved inside SAIF.BOF.Framework) |
External service | Backing AD group-membership lookup for IsAuthorized; no endpoint URL/configuration key is present in this repository** |
clsSecurityPrincipal (framework-internal) |
Cross-cutting authorization rules¶
SEC-APP-001 AD-group-gated legal access is inconsistently enforced¶
| Field | Value |
|---|---|
| Statement | Of the 13 AD resource names in the reachable type hierarchy, exactly one — LNView — is evaluated by LegalMaintenance screen code. |
| Trigger | Every screen load of a LegalManagerBase-derived maintenance screen |
| Enforcement | LegalManagerBase.IsInViewOnly checks LNView; other resources evaluated only transitively inside manager retrieve logic or unused |
| Enforcing libraries | SAIF.Application, SAIF.Application.Claim.Legal |
| Outcome | Toolbar disabled for LNView-authorized users; other resources have no direct enforcement point in this application |
| Related resources | LNView, LNAdmin, LNCaseUpdate, LNConflict, LNExposure |
SEC-APP-002 Confidential-claimcase gating is not active in LegalMaintenance¶
| Field | Value |
|---|---|
| Statement | LegalManagerBase.OnRetrieve combines AD group membership (LNAdmin, LNConflict, LNExposure) with claim data attributes (IsWorkerConflict, IsExposure) and a database-backed per-claim override — the canonical SAIF data-level authorization pattern — but this composite gate does not fire in LegalMaintenance because no screen sets a claim context or reads CanViewClaim. |
| Trigger | Manager retrieve logic (OnRetrieve) upon a claim-context change |
| Enforcement | LegalManagerBase.OnRetrieve composite gate at LegalManagerBase.vb:334-355 |
| Enforcing libraries | SAIF.Application.Claim, SAIF.Application.Claim.Legal |
| Outcome | Documented for architectural completeness; not an active enforcement path from LegalMaintenance screens |
| Related resources | LNAdmin, LNConflict, LNExposure |
SEC-APP-003 Inline AJAX grid edit has no authorization gate¶
| Field | Value |
|---|---|
| Statement | DataHelper.aspx bypasses the shared page ancestor and performs no IsInViewOnly/IsViewOnly/resource check before dispatching to clsAttorneyTableManager.ProcessAjaxRequest; a principal in the LNView (view-only) group can still mutate data through this path. |
| Trigger | Any AJAX POST issued by a maintenance-screen grid to DataHelper.aspx |
| Enforcement | None — no resource check exists on this endpoint |
| Enforcing libraries | SAIF.Application.Claim.Legal |
| Outcome | View-only users can mutate attorney table data through this endpoint; exceptions are silently swallowed |
| Related resources | LNView |
SEC-APP-004 LNView semantics are inverted relative to its name¶
| Field | Value |
|---|---|
| Statement | IsInViewOnly returns True when the principal is authorized for LNView, and the screens then disable editing; users in no legal group at all evaluate IsInViewOnly = False and get a fully enabled toolbar — the opposite of what a "view" permission name implies, and unconfirmed by any domain SME.* |
| Trigger | Every screen load evaluating IsInViewOnly |
| Enforcement | LegalManagerBase.IsInViewOnly |
| Enforcing libraries | SAIF.Application.Claim.Legal |
| Outcome | Users in no legal group at all receive a fully enabled toolbar rather than being locked out, contrary to a least-privilege expectation |
| Related resources | LNView |
Data-level authorization¶
| Entity type | Validation pattern | Enforcement library | Source |
|---|---|---|---|
| Legal case/claim (confidential) | ClaimSecurity.CheckClaim(inClaim) sets ConflictAccess/ExposureAccess/HealthIssueAccess/SecureClaimAccess by testing claim attributes against the user's resource tokens; only invoked from ClaimAppManager.OnCheckSecurity, which requires SetClaimContext (not exercised by LegalMaintenance screens) |
SAIF.Application.Claim | LegalMaintenance web application (LegalMaintenance/*.aspx.vb) |
Segregation of duties¶
No SOD rules exist in the analyzed libraries: no class, method, or constant matching SegregationOfDuties/SOD/employee_access/menu_structure was found in LegalMaintenance or the directly-referenced SAIF.Application* projects, and the five LN* resources are tested independently and combined only with OrElse (permissive union) rather than a mutual-exclusion restriction.
Security dependencies¶
| Dependency | Type | Purpose |
|---|---|---|
WCF SecurityService / clsSecurityPrincipal (SAIF.BOF.Framework) |
External service / NuGet package | Centralized AD group membership checks via IsAuthorized(<resourceName>) |
| Active Directory | Infrastructure | User/group/machine identity store |
| SAIF.Framework.Security | NuGet package | Supplies clsSecurityPrincipal and the resource-suffix convention |
Notes¶
- AD resource names use base names only — the framework appends
Resource(production) orTestResource(non-production) at runtime. - The absence of any dual-control or SOD constraint on a master-data maintenance application (attorneys, firms, hearing locations, rotation assignments) is worth surfacing to a domain SME.*
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
- Data model
- Tech debt
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¶
- LegalMaintenance web application (LegalMaintenance/*.aspx.vb)