---
title: SAIF.Business.Security.SystemUser business rules
summary: Enumerated business rules with per-rule trigger, enforcement, and outcomes.
status: draft
owner: SAIF
last_reviewed: 2026-07-24
library: SAIF.Business.Security.SystemUser
reference_type: package
---

# SAIF.Business.Security.SystemUser business rules

This page captures business rules enforced by `SAIF.Business.Security.SystemUser`.

## BR-001: SAIF domain users are classified as SAIFEmployee

| Field | Value |
| --- | --- |
| **Statement** | The library classifies `SAIF` domain users as `UserTypes.SAIFEmployee`. |
| **Trigger** | A `clsSystemUser` instance initializes against a `SAIF` domain principal. |
| **Enforcement** | `clsSystemUser.GetUserType()` checks `Domain = "SAIF"` before any EXTERNAL group evaluation. |
| **Outcome** | `UserType` becomes `SAIFEmployee`, and `IsSAIFEmployee` evaluates accordingly. |
| **Confidence** | Verified |
| **Source** | `Business\SAIF.Business.Security.SystemUser\clsSystemUser.vb` |

---

## BR-002: EXTERNAL users are classified by prioritized group membership

| Field | Value |
| --- | --- |
| **Statement** | The library classifies EXTERNAL users by the first matching AD group in its priority-ordered role check sequence. |
| **Trigger** | A `clsSystemUser` instance initializes against an `EXTERNAL` domain principal. |
| **Enforcement** | `clsSystemUser.GetUserType()` runs sequential `IsInRole(...)` checks for the configured EXTERNAL groups. |
| **Outcome** | The first matching group determines `UserType`; unmatched users fall through to later fallback rules. |
| **Confidence** | Verified |
| **Source** | `Business\SAIF.Business.Security.SystemUser\clsSystemUser.vb` |

---

## BR-003: WEBCOMP is classified as SAIFEmployee

| Field | Value |
| --- | --- |
| **Statement** | The special EXTERNAL user name `WEBCOMP` is classified as `UserTypes.SAIFEmployee` when no earlier group rule matches. |
| **Trigger** | An EXTERNAL-domain principal reaches the `WEBCOMP` username check in `GetUserType()`. |
| **Enforcement** | `clsSystemUser.GetUserType()` compares `UserName` to `"WEBCOMP"` after the EXTERNAL group checks. |
| **Outcome** | `UserType` becomes `SAIFEmployee` for that identity. |
| **Confidence** | Verified |
| **Source** | `Business\SAIF.Business.Security.SystemUser\clsSystemUser.vb` |

---

## BR-004: Unknown domains are unauthorized

| Field | Value |
| --- | --- |
| **Statement** | Users from domains other than `SAIF` or `EXTERNAL` are treated as unauthorized. |
| **Trigger** | Initialization receives a recognized user name but an unrecognized domain. |
| **Enforcement** | `clsSystemUser.GetUserType()` falls into its outer `Case Else` domain branch. |
| **Outcome** | `UserType` becomes `Unauthorized`. |
| **Confidence** | Verified |
| **Source** | `Business\SAIF.Business.Security.SystemUser\clsSystemUser.vb` |

---

## BR-005: Empty usernames are unauthorized

| Field | Value |
| --- | --- |
| **Statement** | An empty or missing authenticated user name results in an unauthorized classification. |
| **Trigger** | Initialization receives a `clsSecurityPrincipal` with no user name value. |
| **Enforcement** | `clsSystemUser.Initialize()` bypasses normal classification and sets the unauthorized user type. |
| **Outcome** | `UserType` becomes `Unauthorized` and the library does not treat the principal as a valid portal user. |
| **Confidence** | Verified |
| **Source** | `Business\SAIF.Business.Security.SystemUser\clsSystemUser.vb` |

---

## BR-006: Password length must stay within configured bounds

| Field | Value |
| --- | --- |
| **Statement** | Passwords must remain within the configured minimum and maximum lengths, with defaults of 5 and 20 characters. |
| **Trigger** | `IsValidPassword()` evaluates a candidate password. |
| **Enforcement** | `clsSystemUser.IsValidPassword()` rejects values outside the minimum or maximum bounds. |
| **Outcome** | Invalid password candidates return `False`. |
| **Confidence** | Verified |
| **Source** | `Business\SAIF.Business.Security.SystemUser\clsSystemUser.vb` |

---

## BR-007: Password characters must exclude disallowed symbols

| Field | Value |
| --- | --- |
| **Statement** | Passwords must not contain characters excluded by the library's validation pattern. |
| **Trigger** | `IsValidPassword()` evaluates a candidate password. |
| **Enforcement** | `clsSystemUser.IsValidPassword()` applies its disallowed-character pattern check. |
| **Outcome** | Candidates containing excluded characters return `False`. |
| **Confidence** | Verified |
| **Source** | `Business\SAIF.Business.Security.SystemUser\clsSystemUser.vb` |

---

## BR-008: User IDs follow password-style validation rules

| Field | Value |
| --- | --- |
| **Statement** | User IDs must satisfy the same default length and character constraints used for password validation. |
| **Trigger** | `IsValidUserID()` evaluates a candidate user ID. |
| **Enforcement** | `clsSystemUser.IsValidUserID()` applies the same bounds and character-screening rules used for passwords. |
| **Outcome** | Invalid user IDs return `False`. |
| **Confidence** | Verified |
| **Source** | `Business\SAIF.Business.Security.SystemUser\clsSystemUser.vb` |

---

## BR-009: Payment passwords must differ from the stored payment password

| Field | Value |
| --- | --- |
| **Statement** | A new payment password cannot match the current stored payment password. |
| **Trigger** | `IsUniquePaymentPWD()` evaluates a candidate payment password. |
| **Enforcement** | `clsSystemUser.IsUniquePaymentPWD()` requires `Not CheckPaymentPWD(inPaymentPwd)`. |
| **Outcome** | Matching the stored payment password returns `False`. |
| **Confidence** | Verified |
| **Source** | `Business\SAIF.Business.Security.SystemUser\clsSystemUser.vb` |

---

## BR-010: Payment passwords must differ from the login password

| Field | Value |
| --- | --- |
| **Statement** | A new payment password cannot authenticate as the current login password. |
| **Trigger** | `IsUniquePaymentPWD()` evaluates a candidate payment password. |
| **Enforcement** | `clsSystemUser.IsUniquePaymentPWD()` attempts authentication with a temporary `clsSecurityPrincipal` and rejects authenticated matches. |
| **Outcome** | Candidates that also function as the login password return `False`. |
| **Confidence** | Verified |
| **Source** | `Business\SAIF.Business.Security.SystemUser\clsSystemUser.vb` |

---

## BR-011: Payment password comparisons use encrypted values

| Field | Value |
| --- | --- |
| **Statement** | Payment-password comparisons are performed against the encrypted form of the candidate password. |
| **Trigger** | `CheckPaymentPWD()` evaluates a candidate payment password. |
| **Enforcement** | `clsSystemUser.CheckPaymentPWD()` encrypts the candidate through `clsSecureEncrypt.EncryptString()` and compares the result to `PaymentPWD`. |
| **Outcome** | Plaintext comparison is avoided, and only matching encrypted values return `True`. |
| **Confidence** | Verified |
| **Source** | `Business\SAIF.Business.Security.SystemUser\clsSystemUser.vb` |

---

## BR-012: Test-user flags are stored in the AD Description attribute

| Field | Value |
| --- | --- |
| **Statement** | The library stores the test-user flag as `"Y"` or `"N"` in the AD `Description` attribute. |
| **Trigger** | `AddNewUser()` or `UpdateUser()` persists a `UserStructure` value. |
| **Enforcement** | `clsSystemUser.AddNewUser()` and `UpdateUser()` assign the `Description` attribute from `UserStructure.isTestUser`. |
| **Outcome** | The `TestUser` property can later read the flag as a Boolean value. |
| **Confidence** | Verified |
| **Source** | `Business\SAIF.Business.Security.SystemUser\clsSystemUser.vb` |

---

## BR-013: EXTERNAL LDAP binds use a saif prefix

| Field | Value |
| --- | --- |
| **Statement** | When connecting to the EXTERNAL domain, elevated credentials are prefixed with `saif\`. |
| **Trigger** | `Initialize()` binds to a non-`SAIF` domain connection path. |
| **Enforcement** | `clsSystemUser.Initialize()` constructs the EXTERNAL bind by concatenating `"saif\"` with the supplied user ID. |
| **Outcome** | Cross-domain binds use the expected prefixed credential format. |
| **Confidence** | Verified |
| **Source** | `Business\SAIF.Business.Security.SystemUser\clsSystemUser.vb` |

---

## BR-014: Security agreement checks default to enabled unless a resolvable file or node explicitly disables them

| Field | Value |
| --- | --- |
| **Statement** | `CheckOnlineSecurityAgreements()` initializes its result to enabled (`True`) and only overrides that default to disabled (`False`) in three cases: (1) an exception is raised while resolving the configured XML path, (2) `OnlineProperties.xml` exists at that path but its `CHECK_FOR_USER_AGREEMENTS` node is missing, or (3) an exception is raised while reading/parsing the file. When the configured path is empty, when the file does not exist, or when the file exists and the node is present but its text is empty, the method returns the enabled default (`True`). When the node is present with non-empty text, that text is parsed as a `Boolean` and returned directly. |
| **Trigger** | `CheckOnlineSecurityAgreements()` is called to determine whether user agreement checking should be enforced. |
| **Enforcement** | `clsSystemUser.CheckOnlineSecurityAgreements()` initializes `checkEm = True`. It returns `True` immediately if `clsProperties.XMLPath()` is empty, and returns `False` if that lookup raises an exception. If `OnlineProperties.xml` exists at the resolved path, it looks up the `CHECK_FOR_USER_AGREEMENTS` node: if the node is missing, `checkEm` is set to `False`; if the node is present and its trimmed, upper-cased text has length 0, `checkEm` remains `True`; if the text is non-empty, `checkEm` is set by casting the text to `Boolean`. Any exception while reading the file or node sets `checkEm = False`. If the file does not exist at all, `checkEm` remains at its initial `True`. |
| **Outcome** | Agreement checking defaults to enabled for an empty configured path, a missing properties file, or a present file whose expected node has empty text. It is reported as disabled only for a path-resolution exception, a present file with a missing expected node, or any other exception while reading the file/node. When the node has non-empty text, the outcome directly reflects that text parsed as a boolean. |
| **Confidence** | Verified |
| **Source** | `Business\SAIF.Business.Security.SystemUser\clsSystemUser.vb` |

---

## BR-015: Generated passwords exclude visually ambiguous characters

| Field | Value |
| --- | --- |
| **Statement** | Generated passwords use a restricted character set that excludes visually ambiguous characters such as `0`, `O`, `I`, `l`, and `1`. |
| **Trigger** | `GenerateRandomPWD()` creates a candidate password. |
| **Enforcement** | `clsSystemUser.GenerateRandomPWD()` selects characters from the library's constrained password-character constant. |
| **Outcome** | Generated passwords avoid the excluded ambiguous characters. |
| **Confidence** | Verified |
| **Source** | `Business\SAIF.Business.Security.SystemUser\clsSystemUser.vb` |

## Related documentation
- [Index](index.md)
- [Overview](overview.md)
- [Architecture](architecture.md)
- [Dependencies](dependencies.md)
- [Operations and processes](operations-processes.md)
- [Security and authorization](security-authorization.md)
- [API reference](api/index.md)
- [Configuration](configuration.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`
