check_user_account()

Checks whether a user can log in with the given password, using the same criteria as the enaio® enterprise-manager. This is the real credential check: the password is compared against the stored password of the account (unlike check_password_complexity(), which only evaluates the password rule).

Beyond the password the job also answers whether the account exists, whether it is locked and how long the password is still valid.

The session user needs the SERVER_SWITCH_JOB_CONTEXT system role (R_SRV_SWITCH_CONTEXT on the server side, JobKontext wechseln in the enterprise-manager - the same role the $SwitchContextUser*$ parameters behind impersonate() require). Without it the job fails with ECMAccessDeniedException, no matter which account is checked. check_password_complexity() does not need the role.

Failed attempts count towards the account lockout exactly like a real login, and a successful call resets the counter. The threshold is not readable through the API, so throttle the attempts yourself - a loop over candidate passwords locks the account.

1. Signature

  • Sync

  • Async

ecm.security.check_user_account(username: str, password: str) -> ECMUserAccountCheck
await ecm.security.check_user_account(username: str, password: str) -> ECMUserAccountCheck

2. Parameters

Parameter Default Description

username

required

Login name of the account, e.g. "john". Case-insensitive - the server returns the internal spelling in the result.

password

required

The plaintext password to check (or an ECMIND_KEY-encrypted value). It is encoded with the scheme the server requests (Security\PwdDecryption) before being sent.

The server manual lists Password as optional (name-only existence check). enaio® 12.0 rejects the call without it, so this method always sends one.

3. Return value

ECMUserAccountCheck:

Attribute Type Description

status

ECMUserAccountStatus

Outcome of the check, see the table below.

username

str

Internal user name (InternalName) as the server resolved it, e.g. "ROOT". Falls back to the requested name when the server sends none.

login_method

str

Authentication method, e.g. "AS" for the enaio-internal user administration. Empty when the check did not succeed.

password_expires_in_days

int | None

Remaining validity within the configured Login\PasswordExpirationInterval: -1 = does not expire within the validity period (also when the period is switched off with 0), 0 = expired and must be changed - which a one-time password reports as well - otherwise the number of days left (0 would mean today). None when the check did not succeed.

login_possible

bool (property)

True when status is LOGIN_POSSIBLE.

password_expired

bool (property)

True when password_expires_in_days is 0 - i.e. for an expired password and for a one-time password that has not been changed yet.

ECMUserAccountStatus:

Value Code Meaning

LOGIN_POSSIBLE

0

Account exists, is not locked, password matched.

USER_UNKNOWN

2

No account with that login name.

LOCKED_BY_WRONG_PASSWORD

3

The account was just locked by too many failed attempts.

WRONG_PASSWORD

4

Wrong password, another attempt is possible.

ACCOUNT_LOCKED

5

The account was already locked, login is not possible.

A wrong password, an unknown user and a locked account raise no exception - they are expected outcomes of a login check and come back as a status. The server reports them as job errors instead of the documented Action values 2/4/5; the method translates those error codes into the matching status. Any other server error stays an error.

Only Action = 0 counts as success. A missing or unknown value is a rejection, so that a changed server response cannot become an open door.

4. Errors

Exception Cause

ValueError

username or password is empty, or the password cannot be represented by the server’s scheme (e.g. more than 62 characters on a PwdDecryption=1 server).

ECMAccessDeniedException

The session user lacks the SERVER_SWITCH_JOB_CONTEXT system role.

ECMException

Subclass raised by raise_for_blue_exception on any other server failure.

5. Examples

5.1. Check credentials

  • Sync

  • Async

from ecmind_blue_client.ecm import ECMUserAccountStatus

check = ecm.security.check_user_account("john", "S3cret!")

if check.login_possible:
    print(f"login possible as {check.username} via {check.login_method}")
    if check.password_expired:
        print("password has expired and must be changed")
    elif check.password_expires_in_days > 0:
        print(f"password expires in {check.password_expires_in_days} days")
elif check.status is ECMUserAccountStatus.WRONG_PASSWORD:
    print("wrong password")
elif check.status is ECMUserAccountStatus.USER_UNKNOWN:
    print("unknown user")
else:
    print("account locked")
from ecmind_blue_client.ecm import ECMUserAccountStatus

check = await ecm.security.check_user_account("john", "S3cret!")

if check.login_possible:
    print(f"login possible as {check.username} via {check.login_method}")
elif check.status is ECMUserAccountStatus.WRONG_PASSWORD:
    print("wrong password")

5.2. Report expiring passwords

for user in ecm.security.users():
    check = ecm.security.check_user_account(user.username, service_passwords[user.username])
    if check.login_possible and 0 <= check.password_expires_in_days <= 14:
        print(f"{check.username}: password expires in {check.password_expires_in_days} days")

6. Server-side settings

Expiry and lockout behaviour are governed by four parameters in the enaio® enterprise-manager (server properties, section Login):

enterprise-manager Registry entry Meaning

Password validity period

Login\PasswordExpirationInterval

The period in days for which a password is valid; 0 switches the feature off. Default: 0. With the feature off, password_expires_in_days always reads -1.

Warning before the validity period ends

Login\PasswordExpirationWarning

The number of days before expiry from which the user gets a warning at login. Default: 5. This drives enaio’s own warning message, not the value returned by check_user_account().

Security level

Login\SecurityLevel

Behaviour on failed logins: default 0 = no restriction, higher values close the application or lock the account after three failed attempts. Does not apply to users with two-factor authentication. Not readable through the API.

One-time password

Login\PasswordSingleUse

New users are created with a one-time password and must change it right at their first login. Default: 0. Such an account reports password_expires_in_days = 0 (verified against enaio® 12.0). Per account this is the change_pwd attribute, see create_user().

The parameters are described in the enaio® administrator documentation under the server properties, the job parameters Action and PwdExpires in the enaio® server-api reference.

7. Notes

  • The check runs on the existing session; the job does not open a session for the checked user, it only returns the verdict.

  • Never pass the password in plaintext yourself: the server decodes the value and reports plaintext as "Invalid password". This is why the method always does the encoding itself.

  • Whether failed attempts lock the account is governed by the security level (Login\SecurityLevel, default 0 = no restriction; higher values close the application or lock the account after three failed attempts). The counter is per account, other users are unaffected.

  • A lockout from failed logins is not visible in the account attributes: user() keeps reporting locked = False while this check returns ACCOUNT_LOCKED.

8. See also