Skip to content

Classify authenticated user

Classification happens once, at construction. clsSystemUser binds to Active Directory using either elevated credentials read from an XML properties file or credentials passed directly by the caller, resolves the authenticated principal's directory entry, and derives a UserTypes value that every IsXxx property and downstream operation relies on for the lifetime of the object.

Field Value
Operation ID OP-SU-01
Trigger Caller constructs clsSystemUser with either (inPropertiesFileName, inPropertiesFilePath, inSecurityPrincipal) or (inSecurityPrincipal, inUserid, inPWD)
Inputs clsSecurityPrincipal (domain, user name, roles); elevated bind user ID and password (read from XML or passed directly)
Outputs Populated m_DirServer and m_DirUser context; m_UserType classification; UserType and IsXxx properties derived from it
Primary components clsSystemUser.New(...), clsSystemUser.Initialize(...), clsSystemUser.GetUserType()
Entry point Business\SAIF.Business.Security.SystemUser\clsSystemUser.vb

Steps

  1. Resolve elevated bind credentials. The three-argument constructor opens the named properties file through clsProperties, reads the ONLINE/SECURITY/USERID and ONLINE/SECURITY/PASSWORD nodes, and passes them to Initialize.
  2. On failure: any exception while reading the properties file or nodes is wrapped and re-thrown as ApplicationException("Error while retrieving security user from properties.", ex).
  3. The Finally block always disposes the clsProperties instance if it was created.
  4. The two-argument constructor (inSecurityPrincipal, inUserid, inPWD) skips this step and calls Initialize directly with caller-supplied credentials.
  5. Bind to the correct LDAP path. Initialize inspects inSecurityPrincipal.Domain. If the domain (case-insensitively) is SAIF, clsDirectoryServer connects to "LDAP://" + Domain using the resolved bind user ID as-is (BR-013).
  6. Otherwise, the same connection is made but the bind user ID is prefixed with "saif\" before use (BR-013).
  7. Resolve the authenticated principal or fall back to unauthenticated. If m_SecPrinc.UserName is non-Nothing and non-empty, the directory server looks the user up by that user name and classification proceeds via GetUserType() (step 4) (BR-005).
  8. If UserName is Nothing or empty (the unauthenticated-caller path used by the online login application), the directory server instead looks up the raw bind user ID (inUserid) and m_UserType is set directly to Unauthorized without running GetUserType() (BR-005).
  9. Classify by domain (GetUserType). For a SAIF-domain principal, the classification is SAIFEmployee immediately, with no group checks performed (BR-001).
  10. Classify EXTERNAL-domain principals by prioritized group membership. For an EXTERNAL-domain principal, GetUserType() evaluates m_SecPrinc.IsInRole(...) in a fixed priority order and stops at the first match (BR-002):
  11. agents, Producers, or ARPAgents → Agent
  12. Bookkeepers → Bookkeeper
  13. FeeAuditors → Auditor
  14. Groups → Group
  15. Loss Control → LossControl
  16. MCO → MCO
  17. Medical Providers → MedProv
  18. policyholders → PolicyHolder
  19. Workers → Worker
  20. If none of the above groups match and the user name equals WEBCOMP: classification falls back to SAIFEmployee (BR-003).
  21. If none of the above match at all: classification is Unauthorized.
  22. Classify any other domain as unauthorized. A domain that is neither SAIF nor EXTERNAL classifies as Unauthorized with no group evaluation (BR-004).
  23. Expose the classification. m_UserType is stored on a Shared field and read back through the UserType property and the family of IsXxx Boolean properties (IsAgent, IsBookkeeper, IsSAIFEmployee, IsUnAuthorized, etc.) for the remainder of the object's use.

Process flow

The following diagram visualizes this operation's control flow.

flowchart TD
    Start([Constructor invoked]) --> Creds{Which constructor?}
    Creds -->|3-arg| ReadXml[Read elevated bind credentials from XML]
    Creds -->|2-arg| Init[Initialize with supplied credentials]
    ReadXml --> Init
    Init --> Bind{Domain = SAIF?}
    Bind -->|Yes| BindSaif[Bind LDAP with bind user ID as-is]
    Bind -->|No| BindExt[Bind LDAP with saif\ prefix]
    BindSaif --> HasUser{UserName populated?}
    BindExt --> HasUser
    HasUser -->|No| Unauth([Unauthorized - unauthenticated caller])
    HasUser -->|Yes| DomainCheck{Domain value}
    DomainCheck -->|SAIF| Emp([SAIFEmployee])
    DomainCheck -->|EXTERNAL| Roles[Evaluate group checks in priority order]
    DomainCheck -->|Other| UnauthDomain([Unauthorized])
    Roles --> Match{Group match found?}
    Match -->|Yes| Typed([Matching UserType])
    Match -->|No| Webcomp{UserName = WEBCOMP?}
    Webcomp -->|Yes| Emp
    Webcomp -->|No| UnauthNoMatch([Unauthorized])

Failure and edge-case behavior

  • A missing or unreadable elevated-credentials properties file aborts construction entirely via a thrown ApplicationException; there is no fallback classification for this path.
  • An unauthenticated caller (empty UserName) is always classified Unauthorized regardless of domain, without evaluating any IsInRole checks.
  • The EXTERNAL group-priority order is fixed in code; a user in multiple mapped groups is classified by whichever group is checked first, not by any explicit precedence configuration.*
  • WEBCOMP is the only user name with a name-based fallback; all other unmatched EXTERNAL users are Unauthorized.
  • m_UserType is a Shared field on the class rather than an instance field, so classification state is process-wide rather than per-instance.*

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

Sources

  • Business\SAIF.Business.Security.SystemUser\clsSystemUser.vb