Coverage for gws-app/gws/plugin/account/__init__.py: 100%
0 statements
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-05 13:35 +0200
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-05 13:35 +0200
1"""User accounts stored in a database table.
3This plugin manages user accounts in a PostgreSQL table. Unlike the ``sql`` authorization provider, which can only
4authorize users, it also provides account administration and a self-service onboarding procedure for new users.
5Users do not register themselves: an administrator creates an account, and the user activates it via a link
6sent by email.
8Accounts table
9--------------
11The table can have an arbitrary name and should contain the following columns::
13 id int primary key generated always as identity,
15 email text not null, -- user email
16 status int default 0, -- account status
18 password text, -- password hash
19 mfauid text, -- MFA adapter uid, if used
20 mfasecret text, -- MFA secret value
22 tc text, -- storage for a temporary code
23 tctime int, -- temporary code timestamp
24 tccategory text, -- temporary code category
26The table can also contain further columns for user info and data. These columns can be configured in the account
27models and thus made editable for account administrators. The login name is read from the ``email`` column,
28or from another column given by ``usernameColumn``. Passwords are hashed and checked in SQL, by default with
29pgcrypto's ``crypt``.
31Account status
32--------------
34An account is ``new`` (0) after it was created or reset, ``onboarding`` (1) while the user is activating it,
35and ``active`` (10) afterwards. Only active accounts can log in.
37Onboarding
38----------
40When an administrator creates or resets an account, its password and MFA secret are cleared, the status is set to
41``new``, and, if ``onboardingUrl`` is configured, an email with the link ``<onboardingUrl>?onboarding=<code>`` is sent
42to the account's email address. The temporary code expires after ``tcLifeTime`` and can be used once; every step
43of the procedure issues a new one. On the onboarding page, the user confirms the email address and sets a password,
44then selects one of the configured MFA methods, if any. The account becomes active and the client is redirected
45to ``onboardingCompletionUrl``.
47Emails are rendered from the helper's templates with the subjects ``onboarding.emailSubject`` and
48``onboarding.emailBody`` and sent by the ``email`` helper. The templates receive the ``account`` record
49and the ``url``.
51Modules
52-------
54``helper``
55 The global ``account`` helper: configuration, account queries and updates, temporary codes, passwords, MFA,
56 emails. Also implements the edit API for the administration model. All other components use it.
58``admin_action``
59 Action ``accountadmin``: administration of accounts in the client (``Sidebar.AccountAdmin``),
60 including the reset of an account.
62``account_action``
63 Action ``account``: the onboarding procedure for end users (``Account.Dialog``).
65``auth_provider``
66 Authorization provider ``account``: authenticates active users against the accounts table.
68``cli``
69 The CLI command ``accountReset``, which resets accounts by their ids.
71``core``
72 Constants: column names, account status values, temporary code categories.
74The components are optional and can be used together or separately. All of them require the helper to be configured.
76Example::
78 @# global configuration
80 helpers+ {
81 type "account"
82 usernameColumn "login"
83 onboardingUrl "https://example.com/project/user_account"
84 mfa [
85 { mfaUid "" title "No multi-factor authentication" }
86 { mfaUid "AUTH_MFA_TOTP" title "Authenticator app" }
87 ]
88 adminModel {
89 type "postgres"
90 tableName "edit.accounts"
91 isEditable true
92 permissions.edit "allow admin, deny all"
93 ...
94 }
95 templates+ { subject "onboarding.emailSubject" type "text" text "Activate your account" }
96 templates+ { subject "onboarding.emailBody" type "text" text "Activate your account: {{url}}" }
97 }
99 auth.providers+ {
100 type "account"
101 }
103 @# administration project
105 projects+ {
106 ...
107 actions+ {
108 type "accountadmin"
109 permissions.read "allow admin, deny all"
110 }
111 client.addElements+ { tag "Sidebar.AccountAdmin" }
112 }
114 @# onboarding project, the target of onboardingUrl
116 projects+ {
117 uid "user_account"
118 ...
119 actions+ {
120 type "account"
121 permissions.read "allow all"
122 }
123 client.addElements+ { tag "Account.Dialog" }
124 }
125"""