Skip to content

Security role assignment

AppManagerBase reduces application-level authorization to a single enum value, AppSecurityRole, and derives every caller-visible accessibility flag from that one value. A subclass's OnCheckSecurity() hook (declared MustOverride, implemented by consuming application managers) is the expected place to evaluate whatever criteria the application uses and then call one of the three role-setting methods.

Field Value
Operation ID OP-APP-02
Trigger Subclass OnCheckSecurity() implementation (or any other subclass code) calls MarkUpdate(), MarkViewOnly(), or MarkNoAccess()
Inputs Whatever caller/application state the subclass's security evaluation logic examines (not part of this library)
Outputs Updated m_AppSecurityRole value; derived SecurityRole, IsAccessible, IsUpdateable, IsViewOnly, IsRestricted property values
Primary components AppManagerBase.MarkUpdate, AppManagerBase.MarkViewOnly, AppManagerBase.MarkNoAccess, AppManagerBase.SecurityRole, AppManagerBase.IsAccessible, AppManagerBase.IsUpdateable, AppManagerBase.IsViewOnly, AppManagerBase.IsRestricted
Entry point Application\SAIF.Application\AppManagerBase.vb

Steps

  1. Manager starts with no access. The private field m_AppSecurityRole is initialized to AppSecurityRole.NoAccess at declaration, so any manager instance is restricted by default until its security evaluation explicitly grants a different role (BR-001).
  2. Subclass evaluates security state. The subclass's OnCheckSecurity() override runs whatever caller/context checks the consuming application requires (for example, comparing an AppSecurityRole derived from an AD group lookup or resource check performed via AD resource access check (cached)).
  3. This step may embed a call into UserAccess.HasAccess(...) to decide which role to assign; see that operation's own steps for how the underlying authorization decision is made and cached.
  4. Assign exactly one role. The subclass calls exactly one of:
  5. MarkUpdate() — sets m_AppSecurityRole = AppSecurityRole.Update.
  6. MarkViewOnly() — sets m_AppSecurityRole = AppSecurityRole.ViewOnly.
  7. MarkNoAccess() — sets m_AppSecurityRole = AppSecurityRole.NoAccess.
  8. Each method unconditionally overwrites m_AppSecurityRole with no validation of the prior value, so calling more than one in sequence simply leaves the role at whichever was called last (BR-001).
  9. Derive read-only accessibility flags. Callers read any of the following properties, each of which recomputes its result from the single m_AppSecurityRole value on every access (no caching):
  10. SecurityRole returns m_AppSecurityRole directly.
  11. IsAccessible returns True when SecurityRole <> AppSecurityRole.NoAccess.
  12. IsRestricted returns True when SecurityRole = AppSecurityRole.NoAccess.
  13. IsUpdateable returns True when SecurityRole = AppSecurityRole.Update.
  14. IsViewOnly returns True when SecurityRole = AppSecurityRole.ViewOnly.
  15. Because these are simple derivations of one field, IsAccessible and IsRestricted are always complements of each other, and exactly one of IsUpdateable / IsViewOnly / IsRestricted is True at any time (BR-001).

Process flow

The following diagram visualizes how a role assignment call updates the derived accessibility flags.

flowchart TD
    Start([Subclass OnCheckSecurity runs]) --> Eval[Evaluate caller / application state]
    Eval --> Which{Which role applies?}
    Which -->|Full access| MarkUpdate[MarkUpdate sets Update]
    Which -->|Read only| MarkViewOnly[MarkViewOnly sets ViewOnly]
    Which -->|No access| MarkNoAccess[MarkNoAccess sets NoAccess]
    MarkUpdate --> Derive[Callers read SecurityRole,<br>IsAccessible, IsUpdateable,<br>IsViewOnly, IsRestricted]
    MarkViewOnly --> Derive
    MarkNoAccess --> Derive
    Derive --> End([Caller adjusts UI / logic<br>based on flags])

Failure and edge-case behavior

  • AppManagerBase never calls OnCheckSecurity() itself in the code shown in this library — it is a MustOverride hook that the consuming application is responsible for invoking at the appropriate point in its own lifecycle; if a subclass never calls it (or never calls one of the Mark* methods), the manager remains at the default NoAccess role (BR-001).
  • Calling more than one Mark* method leaves the role at the last call; there is no guard against contradictory sequential assignment within a single evaluation.*
  • No event or notification is raised when the role changes; callers must re-read the accessibility properties after each OnCheckSecurity() cycle to see updated values.*

Note: Statements marked with * were inferred from code structure, naming conventions, or contextual evidence where direct confirmation was not available in source artifacts.

Sources

  • Application\SAIF.Application\AppManagerBase.vb
  • Application\SAIF.Application\Enums.vb