---
title: Classify authenticated user
summary: Resolves the caller's UserTypes classification from domain and Active Directory group membership when clsSystemUser is constructed.
status: draft
owner: SAIF
last_reviewed: 2026-07-30
library: SAIF.Business.Security.SystemUser
reference_type: package
operation_id: OP-SU-01
trigger: New clsSystemUser(...) constructor call
---

# 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`.
   - 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)`.
   - The `Finally` block always disposes the `clsProperties` instance if it was created.
   - The two-argument constructor (`inSecurityPrincipal`, `inUserid`, `inPWD`) skips this step and calls `Initialize` directly with caller-supplied credentials.
2. **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](../business-rules.md#br-013-external-ldap-binds-use-a-saif-prefix)).
   - Otherwise, the same connection is made but the bind user ID is prefixed with `"saif\"` before use ([BR-013](../business-rules.md#br-013-external-ldap-binds-use-a-saif-prefix)).
3. **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](../business-rules.md#br-005-empty-usernames-are-unauthorized)).
   - 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](../business-rules.md#br-005-empty-usernames-are-unauthorized)).
4. **Classify by domain (`GetUserType`).** For a `SAIF`-domain principal, the classification is `SAIFEmployee` immediately, with no group checks performed ([BR-001](../business-rules.md#br-001-saif-domain-users-are-classified-as-saifemployee)).
5. **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](../business-rules.md#br-002-external-users-are-classified-by-prioritized-group-membership)):
   - `agents`, `Producers`, or `ARPAgents` → `Agent`
   - `Bookkeepers` → `Bookkeeper`
   - `FeeAuditors` → `Auditor`
   - `Groups` → `Group`
   - `Loss Control` → `LossControl`
   - `MCO` → `MCO`
   - `Medical Providers` → `MedProv`
   - `policyholders` → `PolicyHolder`
   - `Workers` → `Worker`
   - If none of the above groups match and the user name equals `WEBCOMP`: classification falls back to `SAIFEmployee` ([BR-003](../business-rules.md#br-003-webcomp-is-classified-as-saifemployee)).
   - If none of the above match at all: classification is `Unauthorized`.
6. **Classify any other domain as unauthorized.** A domain that is neither `SAIF` nor `EXTERNAL` classifies as `Unauthorized` with no group evaluation ([BR-004](../business-rules.md#br-004-unknown-domains-are-unauthorized)).
7. **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.

```mermaid
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.*

## Related documentation

- [Operations and processes](../operations-processes.md)
- [Business rules](../business-rules.md)

> **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`
