---
title: Validate password format
summary: Enforces configurable minimum/maximum password length and a disallowed-character pattern on a candidate password.
status: draft
owner: SAIF
last_reviewed: 2026-07-30
library: SAIF.Business.Security.SystemUser
reference_type: package
operation_id: OP-SU-12
trigger: Caller calls clsSystemUser.IsValidPassword(inPwd, [inMinLength], [inMaxLength])
---

# Validate password format

`IsValidPassword` is a stateless format check applied to a candidate password before it is accepted for storage (for example, before [Create or update an external user](create-or-update-external-user.md) or [Change Active Directory password](change-active-directory-password.md) persist it).

| Field | Value |
| --- | --- |
| **Operation ID** | OP-SU-12 |
| **Trigger** | Caller calls `clsSystemUser.IsValidPassword(inPwd, [inMinLength], [inMaxLength])` |
| **Inputs** | `inPwd` candidate password; optional `inMinLength` (default `5`); optional `inMaxLength` (default `20`) |
| **Outputs** | `Boolean` result |
| **Primary components** | `clsSystemUser.IsValidPassword(...)` |
| **Entry point** | `Business\SAIF.Business.Security.SystemUser\clsSystemUser.vb` |

## Steps

1. **Start valid.** `isValid` is initialized to `True`.
2. **Check the maximum length.** If `Len(inPwd) > inMaxLength`, `isValid` is set to `False` ([BR-006](../business-rules.md#br-006-password-length-must-stay-within-configured-bounds)).
3. **Check the minimum length.** Otherwise, if `Len(inPwd) < inMinLength`, `isValid` is set to `False` ([BR-006](../business-rules.md#br-006-password-length-must-stay-within-configured-bounds)).
4. **Check for disallowed characters.** Independent of the length checks, `inPwd Like BADCHARS` is evaluated against the pattern `"*[^<>.:;/\,`~@#$%&*()+='{}|\_\-\? ]*"`; a match sets `isValid = False` ([BR-007](../business-rules.md#br-007-password-characters-must-exclude-disallowed-symbols)).
5. **Return the result.** The final `isValid` value is returned.

## Process flow

The following diagram visualizes this operation's control flow.

```mermaid
flowchart TD
	Start([Caller calls IsValidPassword]) --> Init[isValid = True]
	Init --> MaxLen{Len exceeds inMaxLength?}
	MaxLen -->|Yes| Invalid[isValid = False]
	MaxLen -->|No| MinLen{Len below inMinLength?}
	MinLen -->|Yes| Invalid
	MinLen -->|No| CharCheck
	Invalid --> CharCheck{Matches BADCHARS pattern?}
	CharCheck -->|Yes| InvalidChars[isValid = False]
	CharCheck -->|No| Return([Return isValid])
	InvalidChars --> Return
```

## Failure and edge-case behavior

- The length and character checks are independent — a password can fail one, the other, or both, and the final result is `False` if any check fails, but the method gives no indication of which check failed.
- The `BADCHARS` pattern is a `Like` expression, not a documented allow-list; interpreting exactly which characters it excludes requires reading the raw pattern in source.*
- Passing a min/max length outside the caller's actual intent (e.g., `inMinLength` greater than `inMaxLength`) is not guarded against and would make all candidates fail the length check.*

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