---
title: Read portal security configuration
summary: Loads the online-agreement check flag and special-user credentials from XML property files consumed by the portal login flow.
status: draft
owner: SAIF
last_reviewed: 2026-07-30
library: SAIF.Business.Security.SystemUser
reference_type: package
operation_id: OP-SU-14
trigger: Caller calls clsSystemUser.CheckOnlineSecurityAgreements() or GetSpecialUserInfo(...)
---

# Read portal security configuration

`CheckOnlineSecurityAgreements` and `GetSpecialUserInfo` both read `OnlineProperties.xml` through the shared `clsProperties` helper to answer two distinct portal-configuration questions — whether user-agreement checking is enabled, and what the special payroll-reporting-only credentials are. They are documented together because they share the same file, the same `clsProperties` access pattern, and similar defensive exception handling, even though they serve different callers.

| Field | Value |
| --- | --- |
| **Operation ID** | OP-SU-14 |
| **Trigger** | Caller calls `clsSystemUser.CheckOnlineSecurityAgreements()` to determine agreement-check policy, or `GetSpecialUserInfo(specialUserName, specialUserId, utype)` to resolve special-user credentials |
| **Inputs** | `OnlineProperties.xml` file path (resolved internally); for `GetSpecialUserInfo`, a `specialUserType` enum value (only `payrollReportsOnly` is defined) |
| **Outputs** | `CheckOnlineSecurityAgreements`: `Boolean` agreement-check flag; `GetSpecialUserInfo`: `Boolean` success flag plus by-reference `specialUserName`/`specialUserId` output parameters |
| **Primary components** | `clsSystemUser.CheckOnlineSecurityAgreements()`, `clsSystemUser.GetSpecialUserInfo(...)`, `clsSystemUser.GetPropFilePath()`, `clsProperties` |
| **Entry point** | `Business\SAIF.Business.Security.SystemUser\clsSystemUser.vb`; `Legacy\SAIFProperties\clsProperties.vb` |

## Steps

1. **Agreement check — initialize to enabled.** `CheckOnlineSecurityAgreements` sets `checkEm = True` as its default before any file access is attempted ([BR-014](../business-rules.md#br-014-security-agreement-checks-default-to-enabled-unless-a-resolvable-file-or-node-explicitly-disables-them)).
2. **Agreement check — resolve the configured XML path.** A new `clsProperties` instance is created and `props.XMLPath()` is read.
   - If the resolved path is empty: the method returns `True` (the initialized default) immediately, inside the first `Try` block's own path.
   - On failure: an exception during path resolution causes the method to return `False` from the `Catch` block — the one case where the enabled default is explicitly overridden before the file is even located ([BR-014](../business-rules.md#br-014-security-agreement-checks-default-to-enabled-unless-a-resolvable-file-or-node-explicitly-disables-them)).
   - The `clsProperties` instance is disposed in the `Finally` block of this first `Try`.
3. **Agreement check — read the file if it exists.** A second `Try` block checks `System.IO.File.Exists(checkPath & "OnlineProperties.xml")`.
   - If the file exists: a new `clsProperties(OnlineProperties.xml, checkPath)` is opened and `getAppProperties("CHECK_FOR_USER_AGREEMENTS")` is read.
     - If the node is missing (`Nothing`): `checkEm` is set to `False` ([BR-014](../business-rules.md#br-014-security-agreement-checks-default-to-enabled-unless-a-resolvable-file-or-node-explicitly-disables-them)).
     - If the node is present but its trimmed, upper-cased text has length `0`: `checkEm` remains `True` (the default is preserved).
     - If the node's text is non-empty: `checkEm` is set by casting that text to `Boolean`, so the file's explicit value directly determines the outcome.
   - If the file does not exist at all: `checkEm` remains at its initialized `True` value — no override occurs.
   - On any exception while reading or parsing the file: `checkEm` is set to `False` in the `Catch` block ([BR-014](../business-rules.md#br-014-security-agreement-checks-default-to-enabled-unless-a-resolvable-file-or-node-explicitly-disables-them)).
   - The `clsProperties` instance (if created) is disposed in the `Finally` block.
4. **Agreement check — return the result.** The method returns `checkEm`.
5. **Special-user info — resolve the property-file path.** `GetSpecialUserInfo` calls `GetPropFilePath()`, which reads the current web request's `APPL_PHYSICAL_PATH` server variable, walks up to the parent directory, and appends an `XML` subfolder to build the target path — a different path-resolution strategy than the `clsProperties.XMLPath()` call used by the agreement check.*
6. **Special-user info — select the node address.** The method maps the `specialUserType` enum to a node path under `SPECIAL_USERS/`; only `payrollReportsOnly` is defined, which maps to `SPECIAL_USERS/PAYROLL_REPORTING_ONLY`. Other enum values (none currently exist) would fall through the `Case Else` with no node suffix appended.
7. **Special-user info — read the file if it exists.** If `OnlineProperties.xml` exists at the resolved path, a `clsProperties` instance opens it and reads the mapped node.
   - If the node is found: `specialUserName` and `specialUserId` (by-reference output parameters) are populated from the node's `NAME` and `ID` child elements.
   - If the node is not found: `success` is set to `False`.
   - If the file does not exist: the method falls through without setting `success` to `False` explicitly, so it remains at its initialized `True` value even though no output values were populated.*
8. **Special-user info — handle exceptions.** Any exception while reading or parsing the file sets `success = False` in the `Catch` block; the `Finally` block disposes the `clsProperties` instance if one was created.
9. **Special-user info — return the result.** The method returns `success`, with `specialUserName`/`specialUserId` populated only when a matching node was actually found.

## Process flow

The following diagram visualizes this operation's control flow across both entry points.

```mermaid
flowchart TD
	Start([Caller invokes CheckOnlineSecurityAgreements or GetSpecialUserInfo]) --> Which{Which entry point?}
	Which -->|Agreement check| InitTrue[checkEm = True]
	InitTrue --> ResolvePath[Resolve XMLPath via clsProperties]
	ResolvePath --> PathEmpty{Path empty?}
	PathEmpty -->|Yes| ReturnTrue([Return True])
	PathEmpty -.exception.-> ReturnFalsePath([Return False])
	PathEmpty -->|No| FileExists{OnlineProperties.xml exists?}
	FileExists -->|No| ReturnDefault([Return checkEm - still True])
	FileExists -->|Yes| ReadNode[Read CHECK_FOR_USER_AGREEMENTS node]
	ReadNode --> NodeMissing{Node missing?}
	NodeMissing -->|Yes| SetFalse[checkEm = False]
	NodeMissing -->|No| TextEmpty{Node text empty?}
	TextEmpty -->|Yes| KeepTrue[checkEm stays True]
	TextEmpty -->|No| ParseBool[checkEm = CBool node text]
	ReadNode -.exception.-> SetFalse
	SetFalse --> ReturnResult([Return checkEm])
	KeepTrue --> ReturnResult
	ParseBool --> ReturnResult
	Which -->|Special user info| ResolveXmlDir[GetPropFilePath: derive XML folder from web request path]
	ResolveXmlDir --> MapType[Map specialUserType to node address]
	MapType --> FileExists2{OnlineProperties.xml exists?}
	FileExists2 -->|No| ReturnSuccessDefault([Return success - still True, no values set])
	FileExists2 -->|Yes| ReadNode2[Read mapped SPECIAL_USERS node]
	ReadNode2 --> NodeFound{Node found?}
	NodeFound -->|Yes| Populate[Populate specialUserName and specialUserId]
	NodeFound -->|No| SetFalse2[success = False]
	ReadNode2 -.exception.-> SetFalse2
	Populate --> ReturnSuccess([Return success])
	SetFalse2 --> ReturnSuccess
```

## Failure and edge-case behavior

- The agreement check treats a missing configured path, a missing file, and a present-but-empty node as equivalent to "checking is enabled," while only a path-resolution exception, a missing expected node, or a read/parse exception disable it — the disable conditions are the exception, not the rule ([BR-014](../business-rules.md#br-014-security-agreement-checks-default-to-enabled-unless-a-resolvable-file-or-node-explicitly-disables-them)).
- `GetSpecialUserInfo` uses a completely different path-resolution strategy (`GetPropFilePath()`, based on the current web request) than the agreement check (`clsProperties.XMLPath()`), so the two flows can end up reading `OnlineProperties.xml` from different resolved locations in the same running application.*
- When `OnlineProperties.xml` does not exist at all, `GetSpecialUserInfo` returns `success = True` without ever populating `specialUserName`/`specialUserId` — callers must not assume a `True` result means the output parameters were actually set.*
- `GetPropFilePath()` depends on `System.Web.HttpContext.Current` being available, so calling `GetSpecialUserInfo` outside an active web request context would fail at that step.*

## 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`
- `Legacy\SAIFProperties\clsProperties.vb`
