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

1"""User accounts stored in a database table. 

2 

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. 

7 

8Accounts table 

9-------------- 

10 

11The table can have an arbitrary name and should contain the following columns:: 

12 

13 id int primary key generated always as identity, 

14 

15 email text not null, -- user email 

16 status int default 0, -- account status 

17 

18 password text, -- password hash 

19 mfauid text, -- MFA adapter uid, if used 

20 mfasecret text, -- MFA secret value 

21 

22 tc text, -- storage for a temporary code 

23 tctime int, -- temporary code timestamp 

24 tccategory text, -- temporary code category 

25 

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

30 

31Account status 

32-------------- 

33 

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. 

36 

37Onboarding 

38---------- 

39 

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

46 

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

50 

51Modules 

52------- 

53 

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. 

57 

58``admin_action`` 

59 Action ``accountadmin``: administration of accounts in the client (``Sidebar.AccountAdmin``), 

60 including the reset of an account. 

61 

62``account_action`` 

63 Action ``account``: the onboarding procedure for end users (``Account.Dialog``). 

64 

65``auth_provider`` 

66 Authorization provider ``account``: authenticates active users against the accounts table. 

67 

68``cli`` 

69 The CLI command ``accountReset``, which resets accounts by their ids. 

70 

71``core`` 

72 Constants: column names, account status values, temporary code categories. 

73 

74The components are optional and can be used together or separately. All of them require the helper to be configured. 

75 

76Example:: 

77 

78 @# global configuration 

79 

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 } 

98 

99 auth.providers+ { 

100 type "account" 

101 } 

102 

103 @# administration project 

104 

105 projects+ { 

106 ... 

107 actions+ { 

108 type "accountadmin" 

109 permissions.read "allow admin, deny all" 

110 } 

111 client.addElements+ { tag "Sidebar.AccountAdmin" } 

112 } 

113 

114 @# onboarding project, the target of onboardingUrl 

115 

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"""