This page lists the behavioral rules that BolMiddleware enforces on every consumer Razor Page. Each rule has its own section with a Field/Value table. Rules are enforced by the abstract page model chain (BolContextModel, BolMenuModel, BolPolicyModel), the service facades, and the shared Razor views. The library holds no database tables, so no rule has a table or SQL source.
BR-BOLMIDDLEWARE-001 Web context resolution precedence¶
Field
Value
Statement
The BOL web context for a request is resolved from the first available source in this order: the BolContext cookie, a re-read of the cookie, the referring application, the WebContextId form value or cid query value, the session, and finally a newly created context.
Trigger
Every Razor Page handler selection on a page that derives from BolContextModel.
Enforcement
BolContextModel.OnPageHandlerExecuting calls TryGetContext, which calls WebContextService.GetContext and NewContext through the request helper. The cookie is read earlier, in OnPageHandlerSelected.
Outcome
WebContext is populated for the handler. When no source yields a context a new context is created, the middleware session cookie is added, and the BolContext cookie is set.
The context is written to the cookie whenever it has content. It is saved through the remote BOL Context API only when the caller forces the save or the target application differs from the current application. It is always saved to the session.
Trigger
A consumer page calls SaveContext, or navigation calls it while moving to another application.
Enforcement
BolContextModel.SaveContext(bool forceSave) evaluates the cookie, API, and session writes independently.
Outcome
The API call is skipped for same-application requests unless forceSave is true; the session copy is always refreshed.
A context has content when it has an Id. A context with no Id but with a session id is given a newly generated GUID as its Id and counts as having content.
Trigger
Any call to HasContent before saving or cookie writing.
Enforcement
WebContextExtensions.HasContent mutates the ContextResult.Id as a side effect.
Outcome
A check for content can mint an Id; a context with neither Id nor session id has no content and is not persisted.
BR-BOLMIDDLEWARE-004 Context cookie lifetime and flags¶
Field
Value
Statement
The BolContext cookie lives for ten seconds and is flagged HttpOnly. It carries no Secure or SameSite attribute. Its expiry is computed from the local server clock.
Trigger
Context creation and every context save that writes the cookie.
Enforcement
CookieService.SetCookie and SetCookieObject build CookieOptions with HttpOnly = true and an Expires value from DateTime.Now.
Outcome
The cookie works as a short hand-off between consecutive requests during cross-application navigation. It is sent over HTTP and cross-site requests if the host permits.
BR-BOLMIDDLEWARE-006 External user information lookup once¶
Field
Value
Statement
External user information is requested from the security client (ISecurityClient.GetExternalUser) only while the context cookie user state is New. After a successful lookup the state becomes Validated. The Policy Core API is not involved in this lookup; it is used only for policy access validation (BR-BOLMIDDLEWARE-009).
Trigger
A request from an external user where the cookie user state is New.
Enforcement
BolContextModel.OnPageHandlerExecuting calls GetExternalUserInformationForContext, which calls SecurityService.GetCurrentExternalUserAsync once and updates contextCookie.userState and userType. Exceptions are swallowed.
Outcome
Later requests inside the cookie lifetime reuse the stored user type and state without calling the security client again.
The menu is read from the session when present. Otherwise it is requested from the BOL Menu API for the current user and stored in the session. When the API returns nothing the menu stays empty.
Trigger
Handler execution on a page that derives from BolMenuModel.
Enforcement
BolMenuModel.OnPageHandlerExecuting checks the session before calling MenuService.GetMenu.
Outcome
MenuData is the session copy, the API copy, or the default empty menu.
BR-BOLMIDDLEWARE-008 Context value classification¶
Field
Value
Statement
A posted context value whose length is less than seven or exactly nine characters is treated as a policy number. Any other length is treated as a claim number.
Trigger
A user submits the context textbox with a new value on a page with the context field.
Enforcement
BolMenuModel.OnPageHandlerExecuting inspects ContextValue.Length and stores it under the policy or claim context item.
Outcome
The context is updated with a policy number or claim number before the page continues.
Access to a policy is validated for the current user through IsValidPolicyForCurrentUser. The result is read synchronously and drives the AccessAllowed flag.
Trigger
A policy header page resolves a policy number.
Enforcement
BolPolicyModel.GetPolicyHeader reads Task.Result of the validation call and sets AccessAllowed and ErrorMessage.
Outcome
Failed validation sets an error message so that the view renders the error view. Enforcement is soft: derived pages must check AccessAllowed themselves.
ParentAccount is reset to zero, and the stored ParentAccount context value is set to 0, only when the posted contextvalue (the policy select value from the context textbox) is non-empty, meaning a new policy was entered. When it is empty the reset does not occur. Afterwards TryGetPolicyHeader restores ParentAccount from the context value when that value is greater than zero, and derives it from the header (BR-BOLMIDDLEWARE-011) only while ParentAccount is zero.
Trigger
BolPolicyModel.OnPageHandlerExecuting with a non-empty posted contextvalue.
Enforcement
The handler assigns ParentAccount = 0 and calls WebContext.SetContextValue("ParentAccount", "0") inside an if (!string.IsNullOrEmpty(policyselect)) block, before header resolution.
Outcome
Entering a new policy discards the earlier parent account. Requests without a posted contextvalue keep any stored parent account greater than zero.
The dropdown is shown only when the header has at least one association and one of these conditions holds. External user: the web context CustomerId is non-empty and equals the header relationship policy or rate account, or the header has a ManualAffiliation association and CustomerId equals ParentAccount. Internal user: the header policy number equals the rate account or relationship policy, or ParentAccount equals the relationship policy or rate account. No minimum of two associations is required.
Trigger
After a policy header is resolved.
Enforcement
BolPolicyModel.CanViewPolicyDropdown(isUserExternal) sets ShowPolicyDropdown; BolPolicyHeader view renders either the select or a plain label.
Outcome
Eligible users can switch policy from the header; others see the policy number and name only. This is a presentation gate; a chosen policy is re-validated by policy access validation.
BR-BOLMIDDLEWARE-013 External association filtering¶
Field
Value
Statement
The Policy Header API is called with the policy number and an external-user flag (true when the web context customer id is greater than zero). For an external user, user type code POLCY replaces the header associations with those returned by a second header lookup for the customer id; user type code AGNCY keeps only associations that contain a policy whose AgencyId equals the customer id. Any other user type code leaves the associations unchanged.
Trigger
The policy header is requested through IPolicyHeaderService.GetHeader with a customer id greater than zero.
Enforcement
PolicyHeaderService.GetHeader switches on the user type code after IPolicyHeaderApiClient.GetHeader(policyNumber, isExternalUser).
Outcome
The dropdown offers the customer's policies for POLCY, the agency's policies for AGNCY, and the unfiltered associations otherwise. The customer id and type code come from the web context, not from the identity on each request.
A policy header stored in the session is reused when it matches the requested policy number; otherwise the header is requested from the API and saved to the session.
Trigger
TryGetPolicyHeader on a policy header page.
Enforcement
BolPolicyModel.TryGetPolicyHeader compares the session header's policy number with the context policy number.
Outcome
API calls are avoided for repeated requests on the same policy.
Dropdown entries are ordered by policy number descending, with the currently selected policy moved to the first position. Each policy number may appear only once.
Trigger
The BolPolicyHeader view renders the dropdown.
Enforcement
HeaderExtensions.GetPolicyAssociationDropdown sorts, moves the current policy, and fills a dictionary using Add.
Outcome
A duplicate policy number across associations throws an ArgumentException while the view renders.
BR-BOLMIDDLEWARE-018 External profile and logoff links¶
Field
Value
Statement
Profile and logoff links in the page header appear only for external users. The target host is account.saif.com when the environment name contains prod and account-qa.saif.com otherwise.
Trigger
The _BolPageHeaderPartial renders for an external user.
Enforcement
The partial checks Model.IsUserExternal and IWebHostEnvironment.EnvironmentName.
Outcome
External users get profile and logoff navigation; internal users get none. An environment such as preprod also matches the production host.
The context textbox in the layouts is rendered as a visible text input when the page sets ChangeContextPrivilege, and as a hidden input otherwise. This is a presentation behavior only, not server-side authorization.
Trigger
A layout renders the web context form.
Enforcement
The layouts test ChangeContextPrivilege on the page model to choose type="text" or type="hidden". BolMenuModel reads the posted contextvalue without checking the flag.
Outcome
Hiding the input does not stop a crafted form post from changing the policy or claim context. The library never assigns the flag; the consuming application sets it.
The session id used for context lookups comes from a named cookie when the environment key bolmiddleware:UseSessionCookie is true, and from the ASP.NET Core session otherwise.
Trigger
Every request through BolContextModel that needs a session id.
Enforcement
BolContextModel.GetSessionId reads IEnvironmentClient.GetSettingValue for bolmiddleware:UseSessionCookie on every call, and reads bolmiddleware:SessionCookieName there only when UseSessionCookie is true. SessionCookieName is also read separately when a new context is created and AddMiddlewareSessionCookie appends the session cookie.
Outcome
Applications behind a shared session cookie can share a context. Missing-key behavior is unknown**.
Failures in the remote context, menu, and policy header services are logged and replaced by empty or default results instead of being thrown to the page.
Trigger
An API client exception inside WebContextService, MenuService, or PolicyHeaderService.
Enforcement
Each facade wraps client calls in try and catch blocks that log through ISaifLogService and return a default value.
Outcome
Pages render with a missing menu or context rather than failing; operators learn of faults only from the logs.