uanetstandard-test-suite · v1.2.x
Docs · Authentication

User accounts and roles

The four built-in user accounts, their passwords, and the role-based access semantics they exercise. Plus the negative paths your tests should cover.

When a server has OPCUA_AUTH_USERS=true, it validates username/password credentials against config/users.json. The suite ships four canned accounts covering the three role tiers plus a convenience admin.

The four accounts

Username Password Role Why it exists
admin admin123 admin Full-access role tests
operator operator123 operator Mid-tier read+write tests
viewer viewer123 viewer Read-only tests, write-rejection tests
test test admin Convenience login for ad-hoc tests

Plaintext passwords are intentional — this is a test suite, not a real auth system. Don't mirror this config into a real deployment.

What each role implies

The role maps to a set of OPC UA role identifiers (per the spec's WellKnownRoles):

admin

AuthenticatedUser, ConfigureAdmin, SecurityAdmin, Operator, Engineer
  • Read: every variable.
  • Write: every writable variable, including AccessControl/AdminOnly and AccessControl/OperatorLevel.
  • Method calls: all.
  • History: full read.

operator

AuthenticatedUser, Operator
  • Read: every variable.
  • Write: AccessControl/OperatorLevel variables, regular _RW variables. Cannot write AccessControl/AdminOnly.
  • Method calls: all (method-level role checks are not enforced).
  • History: read.

viewer

AuthenticatedUser
  • Read: every readable variable.
  • Write: none. Any write returns Bad_UserAccessDenied.
  • Method calls: yes (consistent with the spec — methods aren't role-gated in the test suite).
  • History: read.

anonymous (no user)

  • Read: variables marked anonymous-allowed.
  • Write: depends on server.
  • No role identifiers.

Which servers accept which auth

Server Anonymous Username Cert auth
opcua-no-security (4840)
opcua-userpass (4841)
opcua-certificate (4842)
opcua-all-security (4843)
opcua-discovery (4844)
opcua-auto-accept (4845)
opcua-sign-only (4846)
opcua-legacy (4847)
opcua-ecc-nist (4848)
opcua-ecc-brainpool (4849)
opcua-sks (4851)

Test patterns

Happy path

Server User Expected
opcua-userpass admin Session created, full RW
opcua-userpass operator Session created, RW on operator nodes
opcua-userpass viewer Session created, RO only
opcua-userpass test Session created, full RW

Negative path — auth failure

Server Identity Expected
opcua-userpass admin + wrong password Bad_UserAccessDenied
opcua-userpass unknown + any password Bad_UserAccessDenied
opcua-userpass Anonymous Bad_IdentityTokenRejected

The two failure codes are distinct — Bad_UserAccessDenied means "the credentials were of the right type but failed validation" (wrong password or unknown user), while Bad_IdentityTokenRejected means "the token type itself is not accepted on this endpoint" (Anonymous on a server with AllowAnonymous=false, or Certificate on a server with AuthCertificate=false). Asserting on the wrong code will hide bugs in either branch.

Negative path — role-based write rejection

Server User Action Expected
opcua-userpass viewer Write to AccessControl/OperatorLevel/Setpoint Bad_UserAccessDenied
opcua-userpass operator Same OK
opcua-userpass admin Write to AccessControl/AdminOnly/SecretConfig OK
opcua-userpass operator Same Bad_UserAccessDenied

Adding users (fork)

Edit config/users.json and restart the server:

text config/users.json
[
  { "username": "admin",      "password": "admin123",      "role": "admin"    },
  { "username": "operator",   "password": "operator123",   "role": "operator" },
  { "username": "viewer",     "password": "viewer123",     "role": "viewer"   },
  { "username": "test",       "password": "test",          "role": "admin"    },
  { "username": "plc_svc",    "password": "s3cure!",       "role": "operator" }
]
bash terminal
docker compose restart opcua-userpass

The new user is now valid. UserManager only exposes GetRole(username) → string, IsAdmin, IsOperator and HasPermission(username, permission); there is no GetUserRoles() method. For role-aware write hooks beyond operator/admin, extend IsOperator/IsAdmin (or add a new helper) and the switch in AccessControlBuilder.CreateRoleProtectedVariable. See Customization.