---
title: SAIF.Services security and authorization
summary: Authorization requirements, AD resource groups, security enforcement points, and data-level access control.
status: draft
owner: SAIF Doc Gen
last_reviewed: 2026-09-24
library: SAIF.Services
reference_type: package
---

# SAIF.Services security and authorization

This page documents authorization mechanisms implemented or consumed by SAIF.Services. Authentication is handled entirely by infrastructure (NTLM/AD) and is not application-level — all code receives a `WindowsIdentity` on the request context. SAIF.Services has **77 distinct static AD resource names** referenced (64 actively checked + 13 declared-but-unused, plus 1 dynamic/data-driven resource), **66 programmatic authorization-enforcement members** performing **102 `IsAuthorized` invocations** across 101 source lines, **0 attribute-based checks**, **9 data-level authorization mechanisms** (DL-01–DL-09), and **3 segregation-of-duties/privilege-delegation rules** (SOD-01–SOD-03). This library has **three confirmed security concerns** (below) that carry elevated risk and should be reviewed before modifying the affected classes.

## Confirmed security findings

> **These three findings are CONFIRMED in code (not inferred) and are prominently documented per doc-gen policy. Severities are reported as found — HIGH is not softened.**

### SEC-01 Bill entry search returns unfiltered bills

| Field | Value |
| --- | --- |
| **Severity** | **HIGH** |
| **Status** | Confirmed in code |
| **Component** | `Claims.Bills.BillQueryService.GetBillEntryBillsByCriteria` |
| **Finding** | `GetBillEntryBillsByCriteria` (`Claims/Bills/BillQueryService.cs` L204-280) builds `secure = new ClaimUserSecurityAccess(...)` (L253), computes `filteredItems` excluding conflict-worker claims the caller may not see (L264-272), and sets `result.SecurityFiltered = bills.Count() > filteredItems.Count()` (L274) — but then maps **`bills`**, not `filteredItems`, into `result.Items` (L276). Every bill matching the criteria (up to 300) is therefore returned, including bills on conflict claims, while `SecurityFiltered` can report `true`, telling the caller that filtering happened when it did not. |
| **Secondary defect** | The filter on the claim-number branch (L264-267) is applied only when the caller **has** a security override; when no override exists, `filteredItems` stays equal to `bills`. The condition looks inverted*, though it has no effect today because of the L276 defect. |
| **Comparison** | The sibling method `BillEntryService.GetInboxBillsByResponsiblePartyId` correctly maps `filteredBills` (`Claims/Bills/BillEntryService.cs` L640-645), confirming the defect is local to `BillQueryService`. |
| **Impact** | Users without `ConflictClaim` can see bill data (provider, worker tax id, claim number, amounts) for conflict claims through the bill-entry search. |
| **Recommended remediation (documentation framing only)** | Map `filteredItems` (not `bills`) into `result.Items` at L276, and review whether the override condition at L264-267 should be inverted. This is a documentation-only recommendation; no code change was made as part of this documentation task. |
| **Source** | `Services/SAIF.Services/Claims/Bills/BillQueryService.cs` L204-280 |

### SEC-02 Certificate renew and resend perform no server-side permission check

| Field | Value |
| --- | --- |
| **Severity** | **MEDIUM** |
| **Status** | Confirmed in code |
| **Component** | `Policies.Certificates.CertificateService.RenewCertificate` / `ResendCertificate` |
| **Finding** | `RenewCertificate` (`Policies/Certificates/CertificateService.cs` L356-396) calls only the private static `ValidateCertificateCanBeRenewed` (L637-642), which throws only if the certificate is null or `HasBeenRenewed` — it never calls `CertificateSecurityService.CertificateCanBeRenewed(...)` (`CertificateSecurityService.cs` L281), the method that evaluates the `CertificatesRenew`/`CertificatesRenewExt`/`CertificatesRenewOSC`/`CertificatesRenewOSCExt` AD resources (L206-207, L223-224). The renewal then writes a new certificate, images it, and distributes it (L378-386). `ResendCertificate` (L399-410) loads the certificate by id, renders it, and calls `CertificateDistributionService.DistributeCertificateStream(...)` with no permission or ownership check at all; the corresponding `CertificateSecurityService.CertificateCanBeResent` (L349-353) unconditionally returns `true` (the cancel-date rule is commented out) and is not even called from `CertificateService`. |
| **Contrast** | Add, edit, and delete ARE enforced server-side: `ValidateUserCanAddCertificate` (L623-629) and `ValidateUserCanEditOrDeleteCertificate` (L631-635) throw `SaifValidationException` when `CertificateSecurityService` denies. |
| **Impact** | Any caller of `ICertificateService` that does not itself gate on `CanCurrentUserRenew`/`CanCurrentUserRenewOsc` can renew or resend any certificate id; `ResendCertificate`'s `DistributionOptions` recipient is caller-controlled, so a resend could redirect certificate content to an arbitrary recipient*. Whether a front end compensates is unknown**. |
| **Recommended remediation (documentation framing only)** | Call `CertificateSecurityService.CertificateCanBeRenewed(...)` from `RenewCertificate` and implement/enforce a real `CertificateCanBeResent` check (including ownership/policy association) in `ResendCertificate`, mirroring the pattern already used for add/edit/delete. This is a documentation-only recommendation; no code change was made as part of this documentation task. |
| **Source** | `Services/SAIF.Services/Policies/Certificates/CertificateService.cs` L356-410, L637-642; `Services/SAIF.Services/Policies/Certificates/CertificateSecurityService.cs` L206-224, L281, L349-353 |

### SEC-03 MCO and medical-provider users can see all non-secure policies

| Field | Value |
| --- | --- |
| **Severity** | **MEDIUM** (possible over-permission; could be intended*) |
| **Status** | Confirmed in code |
| **Component** | `Policies.SecurityServices.PolicySecurityService` |
| **Finding** | `IsValidPolicyForUser` (L89-96) and `ValidatePolicyListForUser` (L112-133) route MCO and medical-provider users to `IsValidForMco` (L161-164) and `IsValidForMedProvider` (L165-168). Both simply return `IsValidForSaifPolicyAccess(policyNumber)` (L260-267), which returns `true` for every policy not in `SaifCorpSecurePolicies()` (`SecurePolicyCode == "SAIF"`, L233-239). For SAIF-secure policies it requires `SAIFPolicyInfo`, which external users are unlikely to hold*. |
| **Comparison** | Unlike agents (book of business, L143-155, L177-231) and policyholders (own policy plus associations, L137-142, L245-256), the MCO and medical-provider paths never use `CustomerId`/`CustomerGroupId`, and never check a relationship between the provider/MCO and the policy (for example via claims or enrollment). The type codes `MCO_USER_TYPE_CODE = "MCO"` and `MED_PROVIDER_TYPE_CODE = "MEDPR"` (L26-27) are declared but unused, which suggests a relationship check was planned but not implemented*. |
| **Impact** | Any external user holding `MCO` or `MedicalProvidersExternal` passes `ContextValidator.ValidatePolicyNumber` (`OutputDocuments/ContextValidator.cs` L27) for virtually any policy, and so can reach policy output documents for employers they have no relationship with. Whether this is an accepted business rule is unknown**. |
| **Recommended remediation (documentation framing only)** | Introduce a relationship check for MCO/medical-provider users analogous to the agent book-of-business and policyholder association checks (for example, via claims or enrollment data linking the provider/MCO to the policy) before treating `IsValidForSaifPolicyAccess` as sufficient. This is a documentation-only recommendation; no code change was made as part of this documentation task. |
| **Source** | `Services/SAIF.Services/Policies/SecurityServices/PolicySecurityService.cs` L89-96, L112-133, L161-168, L233-239, L260-267 |

## Authorization architecture

SAIF.Services uses **delegated programmatic authorization**: the library never looks up AD group membership itself; it calls `IsAuthorized(resource)` on profiles supplied by `IUserProfileService` (namespace `SAIF.Core.Services.UserProfile`; interface not present in this repository's source, supplied by a referenced package such as `SAIF.Framework.Core`** — see `Services/SAIF.Services/SAIF.Services.csproj` L121-122). Resolution of `IsAuthorized` to AD membership happens behind that interface*. Security services are registered per request in consuming dependency maps (for example `DependencyMaps/SAIF.DependencyMaps.Web.AgencyPortal/DependencyMap.cs` L106-111 and `DependencyMaps/SAIF.DependencyMaps.Web.Certs/DependencyMap.cs` L151-154, L203-206), so the per-user caches in `PolicySecurityService` and `CertificateSecurityService` do not leak across requests. This library does **not** consume the WCF `SecurityService` directly: no `SecurityServiceClient`, `IsAuthorized2`, `securityServiceUrl`, or `WCF/Security` reference exists under `Services/SAIF.Services/`; the only trace is a commented-out import `//using SAIF.Services.WCF.Services.Security;` in `Policies/SecurityServices/PolicySecurityService.cs` L12. The provider side of that service lives in the sibling library `Services/SAIF.Services.WCF` (`SecurityService.cs` L78-95, implementing `IsAuthorized(userId, role)` via `WindowsPrincipal.IsInRole(role)`), documented separately; whether `IUserProfileService.IsAuthorized` in consuming hosts routes to that endpoint is unknown from this library**.

```mermaid
flowchart TD
    Caller[SAIF.Services class] --> Profile["IUserProfileService.GetCurrentUser()<br>/ GetSystemUser() / GetApplicationUser()"]
    Profile --> IsAuth["profile.IsAuthorized(resourceName)"]
    IsAuth --> Host["Host-registered IUserProfileService<br>implementation (e.g. SAIF.Framework.Core)"]
    Host -.->|"not traced from this library**"| WCF["Services/SAIF.Services.WCF<br>SecurityService (WindowsPrincipal.IsInRole)"]
    WCF --> AD[("Active Directory")]
```

| Metric | Count | Notes |
| --- | --- | --- |
| AD resource names actively checked | 64 static + 1 dynamic | Catalog rows 1-65 below |
| AD resource names declared but never checked | 13 | See "Declared but never checked" |
| Total distinct resource names referenced | 77 static + 1 dynamic | |
| Attribute-based enforcement points | 0 | |
| Programmatic enforcement members | 66 | |
| `IsAuthorized` invocations | 102 on 101 source lines | Commented-out lines excluded |
| Data-level authorization mechanisms | 9 | DL-01 to DL-09 |
| Segregation-of-duties / privilege-delegation rules | 3 | SOD-01 to SOD-03 |
| Machine authorization present | No | |
| Direct WCF `SecurityService` usage | No | Provider lives in `Services/SAIF.Services.WCF` |

## AD resource catalog

Each row is one AD resource name referenced by this library. Per SAIF convention the environment suffix (`Resource`/`TestResource`) is appended by the framework principal, not by this library*; names below are the base names exactly as written in code.

### Claims resources

| # | Resource name | Purpose | Enforcement point | Source file | Status |
| --- | --- | --- | --- | --- | --- |
| 1 | `ClaimAuthorityUpdate` | Grants the `CanUpdate` flag on employee payment/reserve authority screens | `ClaimAuthorityService.CanUserUpdate` | `Claims/Authority/ClaimAuthorityService.cs` L28, L429 | Active |
| 2 | `ClaimAuthorityEAIPUpdate` | Same as above (alternate resource; either grants update) | `ClaimAuthorityService.CanUserUpdate` | `Claims/Authority/ClaimAuthorityService.cs` L28, L429 | Active |
| 3 | `CTNoteUpdate` | Claim-note editing rights; note preference conversion eligibility | `ClaimNotesService.IsUpdateUser`; `NotePreferenceConversionService.SavePreferences` | `Claims/Notes/ClaimNotesService.cs` L85; `Claims/Notes/NotePreferenceConversionService.cs` L91 | Active |
| 4 | `CTNoteSupervisor` | Claim-note supervisor (edit/delete others' notes); update-user; preference conversion | `ClaimNotesService.IsUpdateUser`, `GetNotes`, `GetNote`; `NotePreferenceConversionService.SavePreferences` | `Claims/Notes/ClaimNotesService.cs` L86, L123, L139 | Active |
| 5 | `RTWAdmin` | Return-to-work administrator counts as a claim-note update user | `ClaimNotesService.IsUpdateUser` | `Claims/Notes/ClaimNotesService.cs` L87 | Active |
| 6 | `RTWInternalUpdate` | Internal RTW user counts as a claim-note update user | `ClaimNotesService.IsUpdateUser` | `Claims/Notes/ClaimNotesService.cs` L88 | Active |
| 7 | `RTWExternalUpdate` | External RTW vendor: restricts claim access to assigned RTW cases, filters task lists to activities, valid task assignee, note audit suffix | `ClaimNotesService.IsUpdateUser`, `SaveNote`, `CreateNote`; `RTWService.CanAccessRTWClaim`; `TaskService.ApplyAdditionalFilters`, `CanUserEdit`, `CreateTaskNote` | `Claims/Notes/ClaimNotesService.cs` L89, L197, L303; `Claims/RTW/RTWService.cs` L46; `Claims/Tasks/TaskService.cs` L318, L416, L811 | Active |
| 8 | `CTNCENotes` | NCE (non-claim employee*) note user; update-user; preference conversion | `ClaimNotesService.IsUpdateUser`, `IsNCEUser`; `NotePreferenceConversionService.SavePreferences` | `Claims/Notes/ClaimNotesService.cs` L90, L97 | Active |
| 9 | `SecureClaim` | Access to secure (and inmate) claims: unmasking, note edit rights, bill/task filtering | `ClaimSecurityService.GetClaimSecurity`; `ClaimUserSecurityAccess` ctor; `ClaimNotesService.GetNotes`, `GetNote` | `Security/ClaimSecurityRoles.cs` L8; `Security/ClaimSecurityService.cs` L30; `Security/ClaimUserSecurityAccess.cs` L16 | Active |
| 10 | `ConflictClaim` | Access to conflict (employee/conflict-of-interest*) claims: bill search/inbox filtering, worker-name unmasking, pend-request validation | `ClaimSecurityService.GetClaimSecurity`; `ClaimUserSecurityAccess` ctor | `Security/ClaimSecurityRoles.cs` L7; `Security/ClaimSecurityService.cs` L29 | Active |
| 11 | `CTTaskUpdate` | Valid claim-task assignee / task edit | `TaskService.CanUserEdit` | `Claims/Tasks/TaskService.cs` L416 | Active |

### Legal and collections resources

| # | Resource name | Purpose | Enforcement point | Source file | Status |
| --- | --- | --- | --- | --- | --- |
| 12 | `LNConflict` | View conflict-worker legal cases; unmask claimants in legal bill and subpoena inboxes | `LegalService` ctor; `BillService` ctor; `SubpoenaService` ctor | `Legal/LegalService.cs` L41; `Legal/Bills/BillService.cs` L58; `Legal/Subpoenas/SubpoenaService.cs` L76 | Active |
| 13 | `LNBillUpdate` | Enter legal bills / case costs; build list of bill-update employees | `CaseCostService.CanEnterBills`; `BillService.CanEnterBills`, `BillUpdateEmployeesList` | `Legal/CaseCostService.cs` L77; `Legal/Bills/BillService.cs` L259, L294 | Active |
| 14 | `LNBillView` | View-only legal bill mode | `BillService.IsViewOnlyUser` | `Legal/Bills/BillService.cs` L254 | Active |
| 15 | `LNUpdate` | Create/update legal notes; valid legal-task assignee | `LegalNotesService.IsUpdateUser`; `LegalTaskService.CanUserEdit` | `Legal/Notes/LegalNotesService.cs` L58; `Legal/Tasks/LegalTaskService.cs` L504 | Active |
| 16 | `LNNoteSupervisor` | Edit/delete other users' legal notes | `LegalNotesService.SetNoteAccessProperties` | `Legal/Notes/LegalNotesService.cs` L106 | Active |
| 17 | `LNSubpoenaUpdate` | Enter subpoenas | `SubpoenaService.CanEnterSubpoenas` | `Legal/Subpoenas/SubpoenaService.cs` L406 | Active |
| 18 | `LNSecured` | Sets **both** conflict and secure access for legal tasks | `LegalTaskService` ctor (const `AccessResourseForSecuredClaims`) | `Legal/Tasks/LegalTaskService.cs` L45, L139-140 | Active |
| 19 | `LegalColUpdate` | Collections update user; shows unmasked SSNs in debtor results | `CollectionsService.IsUpdateUser` | `Collections/CollectionsService.cs` L1761 | Active |

### Documents, policy and policy-document API resources

| # | Resource name | Purpose | Enforcement point | Source file | Status |
| --- | --- | --- | --- | --- | --- |
| 20 | `DocCenterDevAdmin` | DocCenter template administrator (non-prod*) — see all templates | `TemplateSearchService.userCanSeeAll` | `Documents/TemplateSearchService.cs` L29, L60 | Active (also declared, unused, in `Documents/DocumentRequestService.cs` L31) |
| 21 | `DocCenterProdAdmin` | DocCenter template administrator (prod*) — see all templates | `TemplateSearchService.userCanSeeAll` | `Documents/TemplateSearchService.cs` L28, L61 | Active (also declared, unused, in `Documents/DocumentRequestService.cs` L30) |
| 22 | `SAIFPolicyInfo` | Access to SAIF corporate secure policies (`SecurePolicyCode == "SAIF"`) | `PolicySecurityService.HasSaifPolicyAccess` | `Policies/SecurityServices/PolicySecurityService.cs` L22, L320 | Active |
| 23 | `AgencyExternal` | Classifies an external user as agency (agent) user | `PolicySecurityService.IsOneOfAgentTypes`; `SecurityExtensions.IsAgent` | `Policies/SecurityServices/PolicySecurityService.cs` L30, L358, L444 | Active |
| 24 | `ARPAgencyExternal` | Classifies an external user as ARP agency user | `PolicySecurityService.IsOneOfAgentTypes`; `SecurityExtensions.IsAgent` | `Policies/SecurityServices/PolicySecurityService.cs` L31, L359, L445 | Active |
| 25 | `ProducerExternal` | Classifies an external user as producer (individual agent) | `PolicySecurityService.IsOneOfAgentTypes`, `IsProducer`; `SecurityExtensions.IsAgent` | `Policies/SecurityServices/PolicySecurityService.cs` L32, L360, L381, L446 | Active |
| 26 | `ClaimProfileExternalPolicyholder` | Classifies an external user as policyholder | `PolicySecurityService.IsPolicyholder` | `Policies/SecurityServices/PolicySecurityService.cs` L33, L418 | Active |
| 27 | `MCO` | Classifies an external user as managed-care organization | `PolicySecurityService.IsMco` | `Policies/SecurityServices/PolicySecurityService.cs` L43, L394 | Active (see SEC-03) |
| 28 | `MedicalProvidersExternal` | Classifies an external user as medical provider | `PolicySecurityService.IsMedProvider` | `Policies/SecurityServices/PolicySecurityService.cs` L42, L406 | Active (see SEC-03) |
| 29 | `PolicyPayrollReportExternal` | Policy documents API — payroll report access | `PolicyDocumentsApiService.GetPayrollReportAccess` | `Policies/PolicyDocumentsApi/PolicyDocumentsApiService.cs` L22, L163 | Active |
| 30 | `PolInfoMntUpdtExt` | Policy documents API — policy view/update access | `PolicyDocumentsApiService.GetPolicyViewAccess` | `Policies/PolicyDocumentsApi/PolicyDocumentsApiService.cs` L23, L154 | Active |

### Certificate resources

Constants are in `Policies/Certificates/SecurityResources.cs`; checks are in `Policies/Certificates/CertificateSecurityService.cs` unless noted. `MaximumEditibleDays = 9` (L11) governs the edit/delete window.

| # | Resource name | Purpose | Enforcement point | Source file | Status |
| --- | --- | --- | --- | --- | --- |
| 31 | `CertificatesPreferences` | Save certificate preferences (internal) | `CertificatePreferenceService.CertificatePreferenceCanBeUpdated` | `SecurityResources.cs` L14; `CertificatePreferenceService.cs` L164 | Active |
| 32 | `CertificatesPreferencesExt` | Save certificate preferences (external) | `CertificatePreferenceService.CertificatePreferenceCanBeUpdated` | `SecurityResources.cs` L43; `CertificatePreferenceService.cs` L165 | Active |
| 33 | `Certs` | Save certificate preferences (legacy/general certificate user*) | `CertificatePreferenceService.CertificatePreferenceCanBeUpdated` | `CertificatePreferenceService.cs` L166 | Active |
| 34 | `CertificatesOtherCoverages` | Maintain other-coverage text (internal) | `CertificateSecurityService.CertificateOtherCoveragesCanBeMaintained` | `SecurityResources.cs` L17; `CertificateSecurityService.cs` L187 | Active |
| 35 | `CertificatesOtherCoveragesExt` | Maintain other-coverage text (external) | `CertificateSecurityService.CertificateOtherCoveragesCanBeMaintained` | `SecurityResources.cs` L19; `CertificateSecurityService.cs` L188 | Active |
| 36 | `CertificatesViewOSC` | View other-states-coverage (OSC) certificates (internal) | `CertificateSecurityService.CanCurrentUserViewOsc` | `SecurityResources.cs` L23; `CertificateSecurityService.cs` L88 | Active |
| 37 | `CertificatesViewOSCExt` | View OSC certificates (external) | `CertificateSecurityService.CanCurrentUserViewOsc` | `SecurityResources.cs` L46; `CertificateSecurityService.cs` L89 | Active |
| 38 | `CertificatesMaintainOwn` | Add standard/bid certificates; edit/delete own | `CurrentUserCanMaintainOwnStandard`; `CurrentUserCanAddStandardOrBidCertificates` | `SecurityResources.cs` L24; `CertificateSecurityService.cs` L138, L323 | Active |
| 39 | `CertificatesMaintainOwnExt` | External equivalent of row 38 | `CurrentUserCanMaintainOwnStandard`; `CurrentUserCanAddStandardOrBidCertificates` | `SecurityResources.cs` L48; `CertificateSecurityService.cs` L139, L325 | Active |
| 40 | `CertificatesMaintainOthers` | Add standard/bid; edit/delete any standard certificate | `CurrentUserCanMaintainAllStandard`; `CurrentUserCanAddStandardOrBidCertificates` | `SecurityResources.cs` L25; `CertificateSecurityService.cs` L123, L322 | Active |
| 41 | `CertificatesMaintainOthersExt` | External equivalent of row 40 | `CurrentUserCanMaintainAllStandard`; `CurrentUserCanAddStandardOrBidCertificates` | `SecurityResources.cs` L49; `CertificateSecurityService.cs` L124, L324 | Active |
| 42 | `CertificatesMaintainOwnOSC` | Add OSC; edit/delete own OSC certificates | `CurrentUserCanMaintainOwnOsc`; `CurrentUserCanAddOtherStatesCertificates` | `SecurityResources.cs` L27; `CertificateSecurityService.cs` L172, L305 | Active |
| 43 | `CertificatesMaintainOwnOSCExt` | External equivalent of row 42 | `CurrentUserCanMaintainOwnOsc`; `CurrentUserCanAddOtherStatesCertificates` | `SecurityResources.cs` L51; `CertificateSecurityService.cs` L173, L307 | Active |
| 44 | `CertificatesMaintainOthersOSC` | Add OSC; edit/delete any OSC certificate | `CurrentUserCanMaintainAllOsc`; `CurrentUserCanAddOtherStatesCertificates` | `SecurityResources.cs` L29; `CertificateSecurityService.cs` L155, L304 | Active |
| 45 | `CertificatesMaintainOthersOSCExt` | External equivalent of row 44 | `CurrentUserCanMaintainAllOsc`; `CurrentUserCanAddOtherStatesCertificates` | `SecurityResources.cs` L53; `CertificateSecurityService.cs` L156, L306 | Active |
| 46 | `CertificatesRenew` | Renew standard certificates | `CertificateSecurityService.CurrentUserCanRenewStandard` | `SecurityResources.cs` L31; `CertificateSecurityService.cs` L206 | Active (**not enforced by `CertificateService.RenewCertificate` — see SEC-02**) |
| 47 | `CertificatesRenewExt` | External equivalent of row 46 | `CertificateSecurityService.CurrentUserCanRenewStandard` | `SecurityResources.cs` L35; `CertificateSecurityService.cs` L207 | Active (see SEC-02) |
| 48 | `CertificatesRenewOSC` | Renew OSC certificates | `CertificateSecurityService.CurrentUserCanRenewOsc` | `SecurityResources.cs` L34; `CertificateSecurityService.cs` L223 | Active (see SEC-02) |
| 49 | `CertificatesRenewOSCExt` | External equivalent of row 48 | `CertificateSecurityService.CurrentUserCanRenewOsc` | `SecurityResources.cs` L37; `CertificateSecurityService.cs` L224 | Active (see SEC-02) |

### Agency, group, online-message and system-user resources

| # | Resource name | Purpose | Enforcement point | Source file | Status |
| --- | --- | --- | --- | --- | --- |
| 50 | `AgencyImagingEdit` | Edit agency images | `Agencies/Imaging/ImageService.CanUserEditImages` | `Core/SAIF.Core/Contracts/Agencies/Imaging/SecurityRoles.cs` L7; `Agencies/Imaging/ImageService.cs` L79 | Active |
| 51 | `AgencyImagingConfidential` | See confidential (SecurityLevel 50) agency images | `ImageService.CanUserSeeConfidentialImages` | `Agencies/Imaging/ImageService.cs` L63 | Active |
| 52 | `AgencyImagingDeleted` | See deleted agency images | `ImageService.CanUserSeeDeletedImages` | `Agencies/Imaging/ImageService.cs` L71 | Active |
| 53 | `AgencyNotePadEdit` | Edit agency notes (full edit within two work days, append-only after) | `Agencies/Notes/NoteService.IsEditUser`; `MoreReadableNoteService.IsEditUser` | `Agencies/Notes/NoteService.cs` L555, L981 | Active (not in Stage 1 catalog) |
| 54 | `AgencyNotePadDelete` | "Super delete" of agency notes | `NoteService.IsSuperDeleteUser`; `MoreReadableNoteService.IsSuperDeleteUser` | `Agencies/Notes/NoteService.cs` L517, L949 | Active (not in Stage 1 catalog) |
| 55 | `AgencyNotePadConfidential` | See confidential agency notes | `NoteService.CanUserSeeConfidentialNotes`; `MoreReadableNoteService.CanUserSeeConfidentialNotes` | `Agencies/Notes/NoteService.cs` L69, L620 | Active (not in Stage 1 catalog) |
| 56 | `GroupImagingEdit` | Edit group images | `Groups/Imaging/GroupImageSecurityProvider.CanUserEditImages` | `Groups/Imaging/GroupImageSecurityProvider.cs` L32 | Active |
| 57 | `GroupImagingConfidential` | See confidential group images | `GroupImageSecurityProvider.CanUserSeeConfidentialImages` | `Groups/Imaging/GroupImageSecurityProvider.cs` L22 | Active |
| 58 | `GroupImagingDeleted` | See deleted group images | `GroupImageSecurityProvider.CanUserSeeDeletedImages` | `Groups/Imaging/GroupImageSecurityProvider.cs` L27 | Active |
| 59 | `GroupNotePadEdit` | Edit group notes | `Groups/Notes/NoteService.IsEditUser` | `Groups/Notes/NoteService.cs` L499 | Active (not in Stage 1 catalog) |
| 60 | `GroupNotePadDelete` | "Super delete" of group notes | `Groups/Notes/NoteService.IsSuperDeleteUser` | `Groups/Notes/NoteService.cs` L508 | Active (not in Stage 1 catalog) |
| 61 | `GroupNotePadConfidential` | See confidential group notes | `Groups/Notes/NoteService.CanUserSeeConfidentialNotes` | `Groups/Notes/NoteService.cs` L477 | Active (not in Stage 1 catalog) |
| 62 | `PolicyCenter` | Guidewire PolicyCenter access flag, evaluated for the **target** user being extracted | `UserExtractService.UpdateUserAccess` (via `GetApplicationUser(userName)`) | `SystemUsers/UserExtractService.cs` L37 | Active |
| 63 | `BillingCenter` | Guidewire BillingCenter access flag for the target user | `UserExtractService.UpdateUserAccess` | `SystemUsers/UserExtractService.cs` L38 | Active |
| 64 | `ContactManager` | Guidewire ContactManager access flag for the target user | `UserExtractService.UpdateUserAccess` | `SystemUsers/UserExtractService.cs` L39 | Active |
| 65 | `userCode.SecurityGroupName` (data-driven) | Online-message visibility for non-employee user types; resource name is read from the online-user-type code table | `OnlineMessagesApiService.UserHasAccessToMessage` | `OnlineMessages/OnlineMessagesApiService.cs` L80-81 | Dynamic |

### Declared but never checked

These names are defined as constants reachable from this library but are never passed to `IsAuthorized` here. They may be used by front ends or other libraries**.

| Resource name | Declared in | Note |
| --- | --- | --- |
| `CertificatesView`, `CertificatesViewExt` | `Policies/Certificates/SecurityResources.cs` L21, L44 | No check found |
| `CertsExternal` (`ExternalAccessCerts`) | `Policies/Certificates/SecurityResources.cs` L42 | No check found |
| `AuditorExternal`, `DemoUser`, `GroupsOnlineExternal`, `LossControlExternal`, `PolicyPayrollQuickFileExternal` | `Policies/SecurityServices/PolicySecurityService.cs` L34-40 | Demo checks use `IsDemoUser()` instead of `DemoUser` |
| `DocCenterAdmin` (`AdminOnlyRole`) | `Documents/TemplateSearchService.cs` L27 | `"Corporate"`/`"Admin"` (L25-26) are business-group/subgroup defaults, not resources |
| `AgencyImagingView`, `AgencyNotePadView`, `GroupImagingView`, `GroupNotePadView` | `Core/SAIF.Core/Contracts/{Agencies,Groups}/{Imaging,Notes}/SecurityRoles.cs` L6 | View roles are never checked in this library |

## Authorization enforcement points

### Attribute-based authorization

None. A search of all `*.cs` and `*.config` files under `Services/SAIF.Services/` for `SaifAuthorize`, `SAIFAuthorize`, `AuthorizeAttribute`, `PrincipalPermission`, and `IsInRole` returned no matches. This is expected for a service-layer library; attribute enforcement, if any, lives in the consuming MVC front ends**.

### Programmatic authorization checks

Every check calls `IsAuthorized(string)` on an `IApplicationUserProfile`/`ISystemUserProfile`/`ISaifUserProfile` obtained from `IUserProfileService.GetCurrentUser()`, `GetSystemUser(userId)`, or `GetApplicationUser(userId)`. "Subject" identifies whose rights are checked: **Current** (the caller), **Other** (a user id supplied as data), or **Profile** (whatever profile the caller passes in).

| # | Class | Method | Resource / Role | Check type | Source |
| --- | --- | --- | --- | --- | --- |
| 1 | `Agencies.Imaging.ImageService` | `CanUserSeeConfidentialImages` | `AgencyImagingConfidential` | `IsAuthorized` — visibility filter (Current) | `Agencies/Imaging/ImageService.cs` L63 |
| 2 | `Agencies.Imaging.ImageService` | `CanUserSeeDeletedImages` | `AgencyImagingDeleted` | `IsAuthorized` — visibility filter (Current) | `Agencies/Imaging/ImageService.cs` L71 |
| 3 | `Agencies.Imaging.ImageService` | `CanUserEditImages` | `AgencyImagingEdit` | `IsAuthorized` — edit capability (Current) | `Agencies/Imaging/ImageService.cs` L79 |
| 4 | `Agencies.Notes.NoteService` | `CanUserSeeConfidentialNotes` | `AgencyNotePadConfidential` | `IsAuthorized` — visibility filter (Current) | `Agencies/Notes/NoteService.cs` L69 |
| 5 | `Agencies.Notes.NoteService` | `IsSuperDeleteUser` | `AgencyNotePadDelete` | `IsAuthorized` — delete capability (Current) | `Agencies/Notes/NoteService.cs` L517 |
| 6 | `Agencies.Notes.NoteService` | `IsEditUser` (cached) | `AgencyNotePadEdit` | `IsAuthorized` — edit mode (Current) | `Agencies/Notes/NoteService.cs` L555 |
| 7 | `Agencies.Notes.MoreReadableNoteService` | `CanUserSeeConfidentialNotes` | `AgencyNotePadConfidential` | `IsAuthorized` — visibility filter (Current) | `Agencies/Notes/NoteService.cs` L620 |
| 8 | `Agencies.Notes.MoreReadableNoteService` | `IsSuperDeleteUser` | `AgencyNotePadDelete` | `IsAuthorized` — delete capability (Current) | `Agencies/Notes/NoteService.cs` L949 |
| 9 | `Agencies.Notes.MoreReadableNoteService` | `IsEditUser` (cached) | `AgencyNotePadEdit` | `IsAuthorized` — edit mode (Current) | `Agencies/Notes/NoteService.cs` L981 |
| 10 | `Claims.Authority.ClaimAuthorityService` | `CanUserUpdate` | `ClaimAuthorityUpdate` OR `ClaimAuthorityEAIPUpdate` | `IsAuthorized` — returned as flag only, see OBS-01 (Current) | `Claims/Authority/ClaimAuthorityService.cs` L429 |
| 11 | `Claims.Notes.ClaimNotesService` | `IsUpdateUser` | `CTNoteUpdate` OR `CTNoteSupervisor` OR `RTWAdmin` OR `RTWInternalUpdate` OR `RTWExternalUpdate` OR `CTNCENotes` | `IsAuthorized` — note create/update gate (Current) | `Claims/Notes/ClaimNotesService.cs` L85-90 |
| 12 | `Claims.Notes.ClaimNotesService` | `IsNCEUser` | `CTNCENotes` | `IsAuthorized` — NCE note behavior (Current) | `Claims/Notes/ClaimNotesService.cs` L97 |
| 13 | `Claims.Notes.ClaimNotesService` | `GetNotes` | `CTNoteSupervisor`; `SecureClaim` (inmate/secure claims only) | `IsAuthorized` — per-note edit/delete flags (Current) | `Claims/Notes/ClaimNotesService.cs` L123, L126 |
| 14 | `Claims.Notes.ClaimNotesService` | `GetNote` | `CTNoteSupervisor`; `SecureClaim` (inmate/secure claims) | `IsAuthorized` — per-note access flags (Current) | `Claims/Notes/ClaimNotesService.cs` L139, L145 |
| 15 | `Claims.Notes.ClaimNotesService` | `SaveNote` | `RTWExternalUpdate` (with RTW load code) | `IsAuthorized` — external RTW note handling (Current) | `Claims/Notes/ClaimNotesService.cs` L197 |
| 16 | `Claims.Notes.ClaimNotesService` | `CreateNote` | `RTWExternalUpdate` (with RTW load code) | `IsAuthorized` — external RTW note handling (Current) | `Claims/Notes/ClaimNotesService.cs` L303 |
| 17 | `Claims.Notes.NotePreferenceConversionService` | `SavePreferences` | `CTNoteUpdate` OR `CTNoteSupervisor` OR `CTNCENotes` | `IsAuthorized` — batch eligibility (Other: `userName`) | `Claims/Notes/NotePreferenceConversionService.cs` L91-93 |
| 18 | `Claims.RTW.RTWService` | `CanAccessRTWClaim` | `RTWExternalUpdate` | `IsAuthorized` — claim must be assigned RTW case, else allow (Profile) | `Claims/RTW/RTWService.cs` L46 |
| 19 | `Claims.Tasks.TaskService` | `ApplyAdditionalFilters` | `RTWExternalUpdate` (with `IsExternal`) | `IsAuthorized` — restricts task query to activities (Current) | `Claims/Tasks/TaskService.cs` L318 |
| 20 | `Claims.Tasks.TaskService` | `CanUserEdit(userId)` | `CTTaskUpdate` OR `RTWExternalUpdate` | `IsAuthorized` — valid assignee (Other: `userId`*) | `Claims/Tasks/TaskService.cs` L416 |
| 21 | `Claims.Tasks.TaskService` | `CreateTaskNote` | `RTWExternalUpdate` | `IsAuthorized` — note audit suffix (Other) | `Claims/Tasks/TaskService.cs` L811 |
| 22 | `Collections.CollectionsService` | `IsUpdateUser` | `LegalColUpdate` | `IsAuthorized` — unmasks SSNs in `GetDebtors` (Current) | `Collections/CollectionsService.cs` L1761 |
| 23 | `Documents.TemplateSearchService` | `userCanSeeAll` | `DocCenterDevAdmin` OR `DocCenterProdAdmin` | `IsAuthorized` — template visibility (Profile) | `Documents/TemplateSearchService.cs` L60-61 |
| 24 | `Groups.Imaging.GroupImageSecurityProvider` | `CanUserSeeConfidentialImages` | `GroupImagingConfidential` | `IsAuthorized` — repository filter flag (Current) | `Groups/Imaging/GroupImageSecurityProvider.cs` L22 |
| 25 | `Groups.Imaging.GroupImageSecurityProvider` | `CanUserSeeDeletedImages` | `GroupImagingDeleted` | `IsAuthorized` — repository filter flag (Current) | `Groups/Imaging/GroupImageSecurityProvider.cs` L27 |
| 26 | `Groups.Imaging.GroupImageSecurityProvider` | `CanUserEditImages` | `GroupImagingEdit` | `IsAuthorized` — edit capability (Current) | `Groups/Imaging/GroupImageSecurityProvider.cs` L32 |
| 27 | `Groups.Notes.NoteService` | `CanUserSeeConfidentialNotes` | `GroupNotePadConfidential` | `IsAuthorized` — visibility filter (Current) | `Groups/Notes/NoteService.cs` L477 |
| 28 | `Groups.Notes.NoteService` | `IsEditUser` (cached) | `GroupNotePadEdit` | `IsAuthorized` — edit mode (Current) | `Groups/Notes/NoteService.cs` L499 |
| 29 | `Groups.Notes.NoteService` | `IsSuperDeleteUser` | `GroupNotePadDelete` | `IsAuthorized` — delete capability (Current) | `Groups/Notes/NoteService.cs` L508 |
| 30 | `Legal.CaseCostService` | `CanEnterBills` | `LNBillUpdate` | `IsAuthorized` — paid-bill/subpoena flags* (Current) | `Legal/CaseCostService.cs` L77 |
| 31 | `Legal.LegalService` | constructor | `LNConflict` | `IsAuthorized` — cached conflict access for `GetCaseList` (Current) | `Legal/LegalService.cs` L41 |
| 32 | `Legal.Bills.BillService` | constructor | `LNConflict` | `IsAuthorized` — cached conflict access for claimant masking (Current) | `Legal/Bills/BillService.cs` L58 |
| 33 | `Legal.Bills.BillService` | `IsViewOnlyUser` | `LNBillView` | `IsAuthorized` — view-only mode (Current) | `Legal/Bills/BillService.cs` L254 |
| 34 | `Legal.Bills.BillService` | `CanEnterBills` | `LNBillUpdate` | `IsAuthorized` — bill entry (Current) | `Legal/Bills/BillService.cs` L259 |
| 35 | `Legal.Bills.BillService` | `BillUpdateEmployeesList` | `LNBillUpdate` | `IsAuthorized` — lists employees holding the resource (Other: each employee) | `Legal/Bills/BillService.cs` L294 |
| 36 | `Legal.Notes.LegalNotesService` | `IsUpdateUser` | `LNUpdate` | `IsAuthorized` — legal note create/update (Current) | `Legal/Notes/LegalNotesService.cs` L58 |
| 37 | `Legal.Notes.LegalNotesService` | `SetNoteAccessProperties` | `LNNoteSupervisor` | `IsAuthorized` — edit/delete others' notes (Current) | `Legal/Notes/LegalNotesService.cs` L106 |
| 38 | `Legal.Subpoenas.SubpoenaService` | constructor | `LNConflict` | `IsAuthorized` — cached conflict access (Current) | `Legal/Subpoenas/SubpoenaService.cs` L76 |
| 39 | `Legal.Subpoenas.SubpoenaService` | `CanEnterSubpoenas` | `LNSubpoenaUpdate` | `IsAuthorized` — subpoena entry (Current) | `Legal/Subpoenas/SubpoenaService.cs` L406 |
| 40 | `Legal.Tasks.LegalTaskService` | constructor | `LNSecured` (twice: conflict and secure) | `IsAuthorized` — cached access flags, see OBS-02 (Current) | `Legal/Tasks/LegalTaskService.cs` L139-140 |
| 41 | `Legal.Tasks.LegalTaskService` | `CanUserEdit(userId)` | `LNUpdate` | `IsAuthorized` — valid legal-task assignee (Other) | `Legal/Tasks/LegalTaskService.cs` L504 |
| 42 | `OnlineMessages.OnlineMessagesApiService` | `UserHasAccessToMessage` | `userCode.SecurityGroupName` (dynamic) | `IsAuthorized` — message visibility for non-employee types (Current) | `OnlineMessages/OnlineMessagesApiService.cs` L81 |
| 43 | `Policies.Certificates.CertificatePreferenceService` | `CertificatePreferenceCanBeUpdated` | `CertificatesPreferences` OR `CertificatesPreferencesExt` OR `Certs` | `IsAuthorized` — save-preferences gate (Profile) | `Policies/Certificates/CertificatePreferenceService.cs` L164-166 |
| 44 | `Policies.Certificates.CertificateSecurityService` | `CanCurrentUserViewOsc` (cached) | `CertificatesViewOSC` OR `CertificatesViewOSCExt` | `IsAuthorized` — OSC visibility (Current) | `CertificateSecurityService.cs` L88-89 |
| 45 | `CertificateSecurityService` | `CurrentUserCanMaintainAllStandard` | `CertificatesMaintainOthers` OR `CertificatesMaintainOthersExt` | `IsAuthorized` — edit/delete any standard certificate (Current) | `CertificateSecurityService.cs` L123-124 |
| 46 | `CertificateSecurityService` | `CurrentUserCanMaintainOwnStandard` | `CertificatesMaintainOwn` OR `CertificatesMaintainOwnExt` | `IsAuthorized` — edit/delete own standard certificate (Current) | `CertificateSecurityService.cs` L138-139 |
| 47 | `CertificateSecurityService` | `CurrentUserCanMaintainAllOsc` | `CertificatesMaintainOthersOSC` OR `CertificatesMaintainOthersOSCExt` | `IsAuthorized` — edit/delete any OSC certificate (Current) | `CertificateSecurityService.cs` L155-156 |
| 48 | `CertificateSecurityService` | `CurrentUserCanMaintainOwnOsc` | `CertificatesMaintainOwnOSC` OR `CertificatesMaintainOwnOSCExt` | `IsAuthorized` — edit/delete own OSC (Current) | `CertificateSecurityService.cs` L172-173 |
| 49 | `CertificateSecurityService` | `CertificateOtherCoveragesCanBeMaintained` | `CertificatesOtherCoverages` OR `CertificatesOtherCoveragesExt` | `IsAuthorized` — other-coverage editing (Current) | `CertificateSecurityService.cs` L187-188 |
| 50 | `CertificateSecurityService` | `CurrentUserCanRenewStandard` | `CertificatesRenew` OR `CertificatesRenewExt` | `IsAuthorized` — see SEC-02 (Current) | `CertificateSecurityService.cs` L206-207 |
| 51 | `CertificateSecurityService` | `CurrentUserCanRenewOsc` | `CertificatesRenewOSC` OR `CertificatesRenewOSCExt` | `IsAuthorized` — see SEC-02 (Current) | `CertificateSecurityService.cs` L223-224 |
| 52 | `CertificateSecurityService` | `CurrentUserCanAddOtherStatesCertificates` | Any of four OSC maintain resources | `IsAuthorized` — add-OSC gate (Current) | `CertificateSecurityService.cs` L304-307 |
| 53 | `CertificateSecurityService` | `CurrentUserCanAddStandardOrBidCertificates` | Any of four standard maintain resources | `IsAuthorized` — add-standard/bid gate (Current) | `CertificateSecurityService.cs` L322-325 |
| 54 | `Policies.PolicyDocumentsApi.PolicyDocumentsApiService` | `GetPolicyViewAccess` | `PolInfoMntUpdtExt` | `IsAuthorized` — feeds `HasValidCurrentUserAccess` (Current) | `PolicyDocumentsApiService.cs` L154 |
| 55 | `PolicyDocumentsApiService` | `GetPayrollReportAccess` | `PolicyPayrollReportExternal` | `IsAuthorized` — feeds `HasValidCurrentUserAccess` (Current) | `PolicyDocumentsApiService.cs` L163 |
| 56 | `Policies.SecurityServices.PolicySecurityService` | `HasSaifPolicyAccess` (cached per user) | `SAIFPolicyInfo` | `IsAuthorized` — SAIF-secure policy access (Current or Other) | `PolicySecurityService.cs` L320 |
| 57 | `PolicySecurityService` | `IsOneOfAgentTypes` (cached) | `AgencyExternal` OR `ARPAgencyExternal` OR `ProducerExternal` | `IsAuthorized` — user-type classification (Current or Other) | `PolicySecurityService.cs` L358-360 |
| 58 | `PolicySecurityService` | `IsProducer` (cached) | `ProducerExternal` (and `CustomerGroupId != CustomerId`) | `IsAuthorized` — user-type classification (Current or Other) | `PolicySecurityService.cs` L381 |
| 59 | `PolicySecurityService` | `IsMco` (cached) | `MCO` (and `IsExternal`) | `IsAuthorized` — user-type classification, see SEC-03 (Current or Other) | `PolicySecurityService.cs` L394 |
| 60 | `PolicySecurityService` | `IsMedProvider` (cached) | `MedicalProvidersExternal` (and `IsExternal`) | `IsAuthorized` — user-type classification, see SEC-03 (Current or Other) | `PolicySecurityService.cs` L406 |
| 61 | `PolicySecurityService` | `IsPolicyholder` (cached) | `ClaimProfileExternalPolicyholder` (and `IsExternal`) | `IsAuthorized` — user-type classification (Current or Other) | `PolicySecurityService.cs` L418 |
| 62 | `SecurityExtensions` (global namespace) | `IsAgent(this IApplicationUserProfile)` | `AgencyExternal` OR `ARPAgencyExternal` OR `ProducerExternal` | `IsAuthorized` — used by `CertificateSecurityService.CurrentUserIsAgent` (Profile) | `PolicySecurityService.cs` L444-446 |
| 63 | `Security.ClaimSecurityService` | `GetClaimSecurity(IClaimSecurityAttributes)` | `ConflictClaim`, `SecureClaim` (only when the claim carries the flag) | `IsAuthorized` — produces `ClaimSecurityAccess` (Current) | `Security/ClaimSecurityService.cs` L25-30 |
| 64 | `Security.ClaimUserSecurityAccess` | ctor `(ISystemUserProfile)` | `ConflictClaim`, `SecureClaim` | `IsAuthorized` — precomputed `HasConflict`/`HasSecure` (Profile) | `Security/ClaimUserSecurityAccess.cs` L15-16 |
| 65 | `Security.ClaimUserSecurityAccess` | ctor `(profile, conflictResource, secureResource)` | Caller-supplied names | `IsAuthorized` — pluggable conflict/secure resources (Profile) | `Security/ClaimUserSecurityAccess.cs` L25-26 |
| 66 | `SystemUsers.UserExtractService` | `UpdateUserAccess` | `PolicyCenter`, `BillingCenter`, `ContactManager` | `IsAuthorized` — writes Guidewire access flags, not a caller gate (Other: each extracted user) | `SystemUsers/UserExtractService.cs` L37-39 |

## Data-level authorization

| Id | Entity type | Validation method | Mechanism | Source |
| --- | --- | --- | --- | --- |
| DL-01 | Claim | `ClaimSecurityService.GetClaimSecurity`/`LoadClaimSecurity` | `HasConflictAccess = !claim.IsConflictClaim \|\| IsAuthorized(ConflictClaim)`; `HasSecureAccess = !claim.IsSecureClaim \|\| IsAuthorized(SecureClaim)` | `Security/ClaimSecurityService.cs` L20-66 |
| DL-02 | Claim bills, bill-entry inbox, tasks | `ClaimUserSecurityAccess` filtering | `HasConflict`/`HasSecure` used to filter/mask in `BillQueryService.SearchByCriteria` (L162-177), `SearchByResponsiblePartyId` (L290-316), `BillEntryService.GetInboxBillsByResponsiblePartyId` (L624-647), `TaskService` worker-name masking (L132, L439-486) | `Security/ClaimUserSecurityAccess.cs` L11-27 |
| DL-03 | Claim bills | Pend-request recipient check | `SendPendRequestValidator.ValidateBillIds` rejects pending bills to a recipient (`SendtoMailId`) who lacks conflict access to any bill's claim | `Claims/Bills/Validators/SendPendRequestValidator.cs` L37, L42-65 |
| DL-04 | Claim | Claim security override | `ClaimInformationService.HasSecurityOverride(claimId/claimNumber, userId)` → `ClaimSecurityOverrideProvider.HasClaimSecurityOverride` unmasks worker names in tasks and legal tasks | `Claims/Information/ClaimInformationService.cs` L113-127 |
| DL-05 | Claim | External RTW case scoping | `RTWService.CanAccessRTWClaim` requires an `RTWCase` matching claim id and the user's RTW load code when the user holds `RTWExternalUpdate` | `Claims/RTW/RTWService.cs` L44-55 |
| DL-06 | Policy | `PolicySecurityService` policy scoping | Per user type: SAIF employee → any policy except SAIF-secure without `SAIFPolicyInfo`; agent → agency book of active producers; producer → own book; policyholder → own policy plus associations; MCO/medical provider → see SEC-03 | `Policies/SecurityServices/PolicySecurityService.cs` L78-269, L336-341 |
| DL-07 | Policy | Output-document context validation | `ContextValidator.ValidatePolicyNumber` throws `InvalidContextForUserException` unless `IsValidPolicyForCurrentUser`, and blocks status group `"APP"`; `PolicyDocumentsService` filters associations and masks demo users | `OutputDocuments/ContextValidator.cs` L22-31 |
| DL-08 | Certificate | Certificate ownership and OSC scoping | Maintain-own resources only allow edit/delete when `CreateUser` equals the caller; edit/delete only within `MaximumEditibleDays`; OSC access for agents limited to their agent/agency id | `Policies/Certificates/CertificateSecurityService.cs` L98-109, L338-405 |
| DL-09 | Policy documents | Policy documents API identity | `HasValidCurrentUserAccess` returns true when any one of `PolInfoMntUpdtExt`, `PolicyPayrollReportExternal`, or `Domain == "SAIF"` holds (OR, not AND) | `Policies/PolicyDocumentsApi/PolicyDocumentsApiService.cs` L152-186 |

Related non-authorization controls observed: demo-user name masking (`Agencies/AgencyService.cs` L76-77), exclusion of test users in production (`Agencies/AgencyService.cs` L137), online-message fallback visibility for users not in AD for `All`/`Urgent` messages (`OnlineMessages/OnlineMessagesApiService.cs` L75-79). `Collections/Validators/RequestValidator.IsValidPolicy`/`IsValidClaim` validate that a policy or claim context exists, not that the caller may access it*, so they are not counted as authorization.

## Segregation of duties

No classic SOD mechanism exists: there are no `*SegregationOfDuties*`/`*SOD*` classes and no `employee_access`/`menu_structure` queries under `Services/SAIF.Services/`. The following privilege-combination and delegation rules act as SOD-style controls.

| Rule | Description | Conflicting privileges / mechanism | Source |
| --- | --- | --- | --- |
| SOD-001 | A grantor cannot delegate payment/reserve authority beyond their own: the function type, approval type, and maximum amount granted must exist within the authorizing employee's own limits | `ClaimAuthorityAuthorizationValidator` ("You are not authorized to grant this authority / Approval type / amount"); the grantor's authority is attached by `ClaimAuthorityService.SetAuthorizingEmployeePaymentAuthority` | `Claims/Authority/Validators/ClaimAuthorityAuthorizationValidator.cs` L13-46 |
| SOD-002 | Override authority is disabled in production | `ClaimAuthorityService` forces `authorityEdit.IsOverrideAuthority = false` when `IsProduction` | `Claims/Authority/ClaimAuthorityService.cs` L480-483 |
| SOD-003 | Separate Initiate and Approve authority limits for legal bills and subpoenas; pending bills are flagged when the amount exceeds both limits | `BillServiceHelper.UserAuthorityLevel(employeeId, ApprovalTypes.Initiate/Approve, paymentType)` against `EmployeeAuthorityLimit` | `Legal/Bills/BillServiceHelper.cs` L50-54 |

Every authority change is also audit-stamped: `AuthorizedByEmplid` is set to the current employee, and history rows go to `EmployeeAuthorityPaymentLimitHistory` (`Claims/Authority/ClaimAuthorityService.cs` L170-192, L214, L284, L444).

## Additional observations (non-confirmed / lower severity)

These items were surfaced during the same analysis pass as SEC-01/02/03 but are lower severity, informational, or explicitly noted as possibly intentional; they are recorded here for completeness and are **not** part of the "three confirmed security concerns" required by this documentation run.

| Id | Finding | Severity | Source |
| --- | --- | --- | --- |
| OBS-01 | `ClaimAuthorityService.CanUserUpdate` is only returned as a flag; `AddEditAuthorityLimit` does not enforce it server-side (SOD-001 still limits what can be granted) | LOW-MEDIUM* | `Claims/Authority/ClaimAuthorityService.cs` L56-70, L401, L427-430, L465 |
| OBS-02 | `LegalTaskService` derives both conflict and secure access from `LNSecured`; `LNConflict` is not consulted, unlike other Legal services | LOW | `Legal/Tasks/LegalTaskService.cs` L45, L139-140 |
| OBS-03 | Claim bill searches admit restricted (secure) claims based on `HasConflict` only; `HasSecure` is ignored | LOW* | `Claims/Bills/BillQueryService.cs` L162-170, L290-307 |
| OBS-04 | Six Agency/Group NotePad resources (rows 53, 54, 55, 59, 60, 61 above) were not present in an earlier Stage 1 catalog pass | Informational | `Agencies/Notes/NoteService.cs`, `Groups/Notes/NoteService.cs` |
| OBS-05 | 13 declared resource constants are never checked in this library (dead or front-end-only*) | Informational | See "Declared but never checked" |

## Security interfaces and contracts

| Interface / Class | Role | Consumers | Source |
| --- | --- | --- | --- |
| `IUserProfileService` | Supplies `IApplicationUserProfile`/`ISystemUserProfile`/`ISaifUserProfile` with `IsAuthorized(resource)` | Nearly every service class listed in the enforcement tables above | `SAIF.Core.Services.UserProfile` (external to this library**) |
| `ClaimSecurityService` / `IClaimSecurityService` | Centralizes claim conflict/secure access computation | `BillQueryService`, `ClaimNotesService`, `TaskService`, and other Claims services | `Security/ClaimSecurityService.cs` |
| `ClaimUserSecurityAccess` | Precomputed per-user conflict/secure access flags, pluggable resource names | `BillQueryService`, `BillEntryService`, `TaskService` | `Security/ClaimUserSecurityAccess.cs` |
| `PolicySecurityService` / `IPolicySecurityService` | Centralizes policy-level access scoping by user type | `OutputDocuments/ContextValidator`, `OutputDocuments/PolicyDocumentsService`, `CertificateSecurityService` | `Policies/SecurityServices/PolicySecurityService.cs` |
| `CertificateSecurityService` / `ICertificateSecurityService` | Centralizes certificate maintain/renew/resend/view access scoping | `CertificateService`, `CertificatePreferenceService` | `Policies/Certificates/CertificateSecurityService.cs` |

## Machine/application authorization

Not detected. No machine-account handling (`$` suffix stripping), `MachineSecurityService`, or service-account-specific authorization exists under `Services/SAIF.Services/`. The only non-caller authorization lookups are the batch-style checks against other users' profiles: `UserExtractService.UpdateUserAccess`, `NotePreferenceConversionService.SavePreferences`, `BillService.BillUpdateEmployeesList`, `TaskService.CanUserEdit`/`CreateTaskNote`, `LegalTaskService.CanUserEdit`, and `SendPendRequestValidator.ValidateBillIds`. They evaluate named users' resources as data, not the identity of a calling machine.

## Notes
- Mark inferred statements with `*` and unknown statements with `**`.
- AD resource names listed here use base names only. The framework appends `Resource` (production) or `TestResource` (non-production) at runtime.

## Related documentation
- [Index](index.md)
- [Overview](overview.md)
- [Architecture](architecture.md)
- [Dependencies](dependencies.md)
- [Configuration](configuration.md)
- [Operations and processes](operations-processes.md)
- [Business rules](business-rules.md)
- [Database tables](database-tables.md)
- [SQL catalog](sql/index.md)
- [API reference](api/index.md)

## Sources
- `Services/SAIF.Services/Security/`
- `Services/SAIF.Services/Policies/SecurityServices/PolicySecurityService.cs`
- `Services/SAIF.Services/Policies/Certificates/CertificateSecurityService.cs`
- `Services/SAIF.Services/Policies/Certificates/CertificateService.cs`
- `Services/SAIF.Services/Claims/Bills/BillQueryService.cs`
- `Services/SAIF.Services/Claims/Bills/BillEntryService.cs`
- `Services/SAIF.Services/Claims/Authority/ClaimAuthorityService.cs`
- `Services/SAIF.Services/Legal/`
- `Services/SAIF.Services/Agencies/`
- `Services/SAIF.Services/Groups/`
- `Services/SAIF.Services/SystemUsers/UserExtractService.cs`
- `Services/SAIF.Services/OnlineMessages/OnlineMessagesApiService.cs`
- `Services/SAIF.Services/OutputDocuments/ContextValidator.cs`
- `Services/SAIF.Services.WCF/Services/Security/SecurityService.cs`
