pgkiln 0.65.0 → 0.67.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/SECURITY.md +1 -0
- package/db/migrations/134_idp_mfa.sql +46 -0
- package/docs/apex-feature-parity.md +10 -1
- package/docs/guide/01-installation.md +5 -2
- package/docs/guide/03-builder.md +40 -3
- package/docs/guide/08-security.md +41 -3
- package/docs/guide/12-development.md +8 -2
- package/docs/guide/18-cli.md +3 -0
- package/docs/guide/19-rest-data-sources.md +2 -2
- package/package.json +1 -1
- package/public/builder.css +6 -0
- package/src/builder/i18n/de.ts +15 -0
- package/src/builder/i18n/en.ts +15 -0
- package/src/builder/i18n/es.ts +15 -0
- package/src/builder/i18n/fr.ts +15 -0
- package/src/builder/i18n/nl.ts +15 -0
- package/src/builder/i18n/pt.ts +15 -0
- package/src/builder/instance.ts +27 -0
- package/src/builder/login-page.ts +14 -16
- package/src/builder/routes.ts +24 -8
- package/src/builder/users.ts +24 -5
- package/src/builder/workspace-home.ts +7 -1
- package/src/cli/main.ts +58 -7
- package/src/instance-checks.ts +260 -0
- package/src/instance.ts +1 -1
- package/src/release-check.ts +10 -0
- package/src/runtime/routes.ts +39 -3
- package/src/runtime/two-step.ts +21 -1
- package/src/saml.ts +34 -11
- package/src/secrets.ts +16 -6
- package/src/server.ts +10 -0
- package/src/sso.ts +72 -11
- package/src/webauthn.ts +6 -2
package/SECURITY.md
CHANGED
|
@@ -117,6 +117,7 @@ first version (MVP). Every finding below has a regression test in
|
|
|
117
117
|
| Passkey sign-in without a password, workspace rule (0.62.0) | *Sign in with a passkey* asks the browser for any passkey of this site (empty allow list) with `userVerification: required`, and the server refuses an answer whose authenticator data lacks the user-verified flag, so the passkey alone stands for possession plus a fingerprint, face or PIN. The credential id is looked up for this relying party only; a user handle, when the browser sends one, must be the developer's (a SHA-256-derived handle, not the user name). The same one-time challenge, origin, RP ID hash, signature and counter checks as at the second step apply; failures are logged as `login_failed` with the developer's name when the key is known and count for the per-user and per-IP lockout. Administrators turn it off in Instance settings. A workspace's rule (administrators and its own administrators only, CSRF-checked) can only add a requirement; `pgkiln admin set-2fa-policy off` clears every workspace's rule. While a second factor is required of a developer, a sign-in with the default password leads only to the password change. |
|
|
118
118
|
| Single sign-on for developers (0.63.0) | A provider or directory signs developers in only with *builder* turned on. The flow is the applications' (state, PKCE, nonce, browser-binding cookie, ID token or SAML assertion checks) with a pending row without an application; developers are found by the provider's stable subject in `meta.developer_identity`, never by a name alone. An existing developer is linked by name only when the administrator allows it, once, never a break-glass administrator, and an e-mail user name only when verified; otherwise the developer links the identity on Security, which needs their session and CSRF token to start and the same browser to finish, and one identity can't be linked to two developers. Automatic accounts need the developers group when one is set and start as developers; the administrators group decides the role at every sign-in but never demotes a break-glass administrator. A workspace's single sign-on rule (administrators and its own administrators, CSRF-checked) refuses the pgkiln password and a passkey alone, after the password check so it reveals nothing; it can only be turned on while a break-glass administrator exists and by someone who could still sign in; the last break-glass administrator and a developer's last identity can't be removed while it applies. Failures are logged as `login_failed` with the reason. |
|
|
119
119
|
| Two-factor sign-in for application users (0.64.0) | Per application (`meta.app.mfa`: off, optional, required, required for roles). The account's TOTP secrets are encrypted with `PGKILN_SECRET_KEY` and stored only after a code confirms them; recovery codes are SHA-256 and used up atomically; each 30-second step once, one step either side. A password or LDAP sign-in that needs the step creates no session: the pending sign-in (5 minutes, 10 while adding an app) lives in the signed-out session, bound to it and to the page's CSRF token, and a forged token ends it. Wrong codes count as failed sign-ins (the per-user and per-IP lockout). A *Keep me signed in* or session-sharing token stands in for the step only when its method ends in `+2fa`; an identity provider's sign-in is left to the provider. Without the instance key the step can't be required and enrolment refuses rather than skips. Removing an app needs a current or recovery code and is refused for the last app while the application requires it; a developer's reset (Users, with a reason) removes the apps and codes and ends the account's sessions, remembered and shared sign-ins. Every enrolment, removal, reset and used recovery code is in the activity log. The factor tables are closed to the runtime roles. |
|
|
120
|
+
| Lockout checks and key rotation (0.67.0) | Only administrators see the checks and confirm a key backup (CSRF); the page shows a 16-character fingerprint of `PGKILN_SECRET_KEY` from a separate derivation, never the key; values from the database (RP IDs, names) are escaped. `pgkiln admin rotate-key` reads both keys from the environment (never arguments, so not in the shell history or the process list), decrypts every secret before it writes, and changes everything or nothing in one transaction; it is logged and mailed to the administrators. The runtime role reads none of the encrypted columns (tested for every `*_enc` column) |
|
|
120
121
|
|
|
121
122
|
## Findings of the MVP review and their fixes
|
|
122
123
|
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
-- ---------------------------------------------------------------------
|
|
2
|
+
-- 134: make sure an identity provider really did multi-factor sign-in
|
|
3
|
+
-- (sprint 132, SEC-4; beyond APEX, which trusts the IdP's sign-on policy).
|
|
4
|
+
--
|
|
5
|
+
-- meta.auth_provider:
|
|
6
|
+
-- mfa_required refuse a sign-in (to applications and to the builder)
|
|
7
|
+
-- unless the provider says it asked for a second factor:
|
|
8
|
+
-- OpenID Connect through the ID token's amr or acr claim,
|
|
9
|
+
-- SAML through the assertion's AuthnContextClassRef.
|
|
10
|
+
-- mfa_request what to ask the provider for, space separated: OpenID
|
|
11
|
+
-- Connect acr_values, or SAML AuthnContextClassRef values
|
|
12
|
+
-- (a RequestedAuthnContext). null: ask for nothing.
|
|
13
|
+
-- mfa_values the amr / acr / AuthnContextClassRef values that count
|
|
14
|
+
-- as a second factor (any one of them is enough).
|
|
15
|
+
-- local_second_step after a sign-in through this provider, pgkiln asks its
|
|
16
|
+
-- own second step as after a password (the application's
|
|
17
|
+
-- two-step rule; the developer's factor for the builder),
|
|
18
|
+
-- for providers that cannot enforce MFA themselves.
|
|
19
|
+
--
|
|
20
|
+
-- meta.sso_pending.stepup_session: a step-up through the provider (an
|
|
21
|
+
-- authorization scheme with mfa_minutes, 133): the signed-in session the
|
|
22
|
+
-- provider's fresh multi-factor sign-in confirms. The provider is asked to
|
|
23
|
+
-- sign the user in again (prompt=login / max_age=0, SAML ForceAuthn).
|
|
24
|
+
-- ---------------------------------------------------------------------
|
|
25
|
+
alter table meta.auth_provider
|
|
26
|
+
add column mfa_required boolean not null default false,
|
|
27
|
+
add column mfa_request text check (length(mfa_request) <= 500),
|
|
28
|
+
add column mfa_values text[] not null default array[
|
|
29
|
+
'mfa',
|
|
30
|
+
'http://schemas.microsoft.com/claims/multipleauthn',
|
|
31
|
+
'urn:oasis:names:tc:SAML:2.0:ac:classes:MobileTwoFactorContract',
|
|
32
|
+
'urn:oasis:names:tc:SAML:2.0:ac:classes:MobileTwoFactorUnregistered'],
|
|
33
|
+
add column local_second_step boolean not null default false;
|
|
34
|
+
comment on column meta.auth_provider.mfa_required is
|
|
35
|
+
'Refuse sign-ins the provider does not mark as multi-factor (amr / acr, SAML AuthnContextClassRef; 134).';
|
|
36
|
+
comment on column meta.auth_provider.mfa_request is
|
|
37
|
+
'acr_values (OpenID Connect) or AuthnContextClassRef values (SAML) to request, space separated (134).';
|
|
38
|
+
comment on column meta.auth_provider.mfa_values is
|
|
39
|
+
'amr / acr / AuthnContextClassRef values that count as a second factor (134).';
|
|
40
|
+
comment on column meta.auth_provider.local_second_step is
|
|
41
|
+
'After a sign-in through this provider, pgkiln asks its own second step too (134).';
|
|
42
|
+
|
|
43
|
+
alter table meta.sso_pending
|
|
44
|
+
add column stepup_session uuid references meta.session (id) on delete cascade;
|
|
45
|
+
comment on column meta.sso_pending.stepup_session is
|
|
46
|
+
'A step-up through the provider: the signed-in session it confirms (134).';
|
|
@@ -138,7 +138,7 @@ the 26.2 comparison.)
|
|
|
138
138
|
| APEX accounts | ✅ | Instance-wide user directory, bcrypt, session rotation, idle and absolute timeouts |
|
|
139
139
|
| Application Access Control (roles per app, any-user switch) | ✅ | Access control per application |
|
|
140
140
|
| Social sign-in / OpenID Connect | ✅ | Any OIDC provider (Entra ID, Google, Okta, Keycloak, …): PKCE, group → role mapping, account linking, automatic accounts |
|
|
141
|
-
| Multi-factor authentication | ✅ | As in APEX: through the identity provider (OpenID Connect, SAML). Beyond APEX (sprints 126–128): the builder itself has two-factor sign-in with passkeys (WebAuthn, also on their own without a password), authenticator apps (TOTP) and recovery codes, trusted browsers, an instance and per-workspace policy with a grace period and lockout recovery ([chapter 3](guide/03-builder.md#two-factor-sign-in)). Sprint 130: application users too, per application (off, optional, required, required for roles) with authenticator apps and recovery codes, added while signing in or on My account, reset from Users; sprint 131: passkeys, e-mail codes as a fallback, step-up per authorization scheme and REST API tokens only after a second step ([chapter 8](guide/08-security.md#two-factor-sign-in)) |
|
|
141
|
+
| Multi-factor authentication | ✅ | As in APEX: through the identity provider (OpenID Connect, SAML). Beyond APEX (sprints 126–128): the builder itself has two-factor sign-in with passkeys (WebAuthn, also on their own without a password), authenticator apps (TOTP) and recovery codes, trusted browsers, an instance and per-workspace policy with a grace period and lockout recovery ([chapter 3](guide/03-builder.md#two-factor-sign-in)). Sprint 130: application users too, per application (off, optional, required, required for roles) with authenticator apps and recovery codes, added while signing in or on My account, reset from Users; sprint 131: passkeys, e-mail codes as a fallback, step-up per authorization scheme and REST API tokens only after a second step ([chapter 8](guide/08-security.md#two-factor-sign-in)). Sprint 132: pgkiln checks that the identity provider did multi-factor sign-in (`amr` / `acr`, SAML `AuthnContextClassRef`), requests it, steps up through the provider, or asks its own second step after it ([chapter 8](guide/08-security.md#multi-factor-sign-in-at-the-identity-provider)). Sprint 133: lockout checks (instance key and its backup, clock, passkey domain, break-glass administrators) and `pgkiln admin rotate-key` ([chapter 3](guide/03-builder.md#lockout-checks)) |
|
|
142
142
|
| Change own password | ✅ | A built-in *My account* page (APEX offers the API `CHANGE_CURRENT_USER_PW`) |
|
|
143
143
|
| Password expiry, change on first use, admin reset, complexity | ✅ | Lifetime in days, expire/unexpire, admin reset, length and letters+digits rules, unlock |
|
|
144
144
|
| Lockout after failed sign-ins | ✅ | Per user and per IP, time-based (APEX: until an administrator unlocks) |
|
|
@@ -305,6 +305,15 @@ Small but real differences, for teams comparing the two:
|
|
|
305
305
|
before sensitive pages (an authorization scheme's *Second step within*) and REST API tokens only after a second step
|
|
306
306
|
([chapter 8](guide/08-security.md#two-factor-sign-in)).
|
|
307
307
|
APEX's application authentication schemes have no second factor.
|
|
308
|
+
- (sprint 132) **Proof that the identity provider did multi-factor sign-in**: a provider can be required to say so in
|
|
309
|
+
the ID token's `amr` / `acr` or the SAML `AuthnContextClassRef`, step-up goes back to it for a fresh multi-factor
|
|
310
|
+
sign-in, and pgkiln's own second step can follow a provider that cannot enforce MFA
|
|
311
|
+
([chapter 8](guide/08-security.md#multi-factor-sign-in-at-the-identity-provider)). APEX trusts the provider's policy.
|
|
312
|
+
- (sprint 133) **Lockout checks**: Instance settings and `pgkiln admin check` warn before anyone is locked out: secrets
|
|
313
|
+
the instance key can't decrypt, a key without a confirmed backup, clock drift that breaks authenticator codes,
|
|
314
|
+
passkeys of another domain (also before a move, with `--url`) and single sign-on without a break-glass
|
|
315
|
+
administrator; `pgkiln admin rotate-key` changes the instance key in one transaction
|
|
316
|
+
([chapter 3](guide/03-builder.md#lockout-checks)).
|
|
308
317
|
- One RLS policy set protects both the web UI and the REST API.
|
|
309
318
|
- An import can be checked before it commits (`pgkiln import --check`): SQL that names a missing
|
|
310
319
|
table or column refuses the deployment instead of failing at run time.
|
|
@@ -185,7 +185,8 @@ which is read at startup; real environment variables take precedence.
|
|
|
185
185
|
| `OPENAI_API_KEY` | *(none)* | Default API key of AI services with the provider OpenAI that have no key of their own |
|
|
186
186
|
| `GEMINI_API_KEY` | *(none)* | (sprint 111) Default API key of AI services with the provider Gemini that have no key of their own |
|
|
187
187
|
| `OPENAI_COMPATIBLE_API_KEY` | *(none)* | (sprint 111) Default API key of OpenAI-compatible AI services (Ollama, vLLM, Azure OpenAI) that have no key of their own; without either, no key is sent (`none`) |
|
|
188
|
-
| `PGKILN_SECRET_KEY` | *(none)* | Encrypts the secrets of web credentials and the API keys of AI services; at least 32 characters (e.g. `openssl rand -base64 32`). Keep it outside the database;
|
|
188
|
+
| `PGKILN_SECRET_KEY` | *(none)* | Encrypts the secrets of web credentials and the API keys of AI services; at least 32 characters (e.g. `openssl rand -base64 32`). Keep it outside the database; change it with `pgkiln admin rotate-key` ([chapter 3](03-builder.md#lockout-checks)), otherwise the secrets must be entered again |
|
|
189
|
+
| `PGKILN_OLD_SECRET_KEY` | *(none)* | (0.67) Only for `pgkiln admin rotate-key`: the key the secrets are stored with now |
|
|
189
190
|
| `PGKILN_REST_ALLOWED_HOSTS` | *(none: no outgoing calls)* | Hosts REST data sources and `invoke_api` may call: `api.example.com`, `*.example.com`, `host:8443`, `*` (any public host) ([chapter 19](19-rest-data-sources.md#server-configuration-and-the-allow-list)); a workspace's [network access list](03-builder.md#network-access) can narrow it, and the SMTP server of a workspace's own mail service must be on it |
|
|
190
191
|
| `PGKILN_REST_PRIVATE_HOSTS` | *(none)* | Hosts that may resolve to private, loopback or link-local addresses (also allows them) |
|
|
191
192
|
| `PGKILN_PUSH_HOSTS` | the browsers' push services | The hosts push notifications may be posted to: `fcm.googleapis.com,updates.push.services.mozilla.com,web.push.apple.com,*.notify.windows.com` when unset ([chapter 17](17-mobile.md#push-notifications)) |
|
|
@@ -272,7 +273,9 @@ fixed version in `PGKILN_IMAGE`, change it first); `up -d` replaces the containe
|
|
|
272
273
|
container migrates the database before it starts serving. A `compose.yaml` from pgkiln 0.51.0 or older has
|
|
273
274
|
`pull_policy: missing` under `pgkiln`, which makes `docker compose pull` skip an image that is already present:
|
|
274
275
|
delete that line (or take the current `deploy/compose.yaml`) before the first upgrade this way. Back up first (`docker compose exec db pg_dump -U pgkiln pgkiln > backup.sql`).
|
|
275
|
-
Keep `PGKILN_SECRET_KEY`: without it, stored secrets (web credentials, AI keys, push keys) can't
|
|
276
|
+
Keep `PGKILN_SECRET_KEY`: without it, stored secrets (web credentials, AI keys, push keys, authenticator apps) can't
|
|
277
|
+
be decrypted. Keep a copy outside the server and confirm it on Instance settings; to change it, use
|
|
278
|
+
`pgkiln admin rotate-key` ([chapter 3](03-builder.md#lockout-checks)).
|
|
276
279
|
|
|
277
280
|
## Upgrading
|
|
278
281
|
|
package/docs/guide/03-builder.md
CHANGED
|
@@ -138,7 +138,11 @@ started it (in the same browser). The region lists linked identities, with **Unl
|
|
|
138
138
|
developers linked to it; administrators unlink any of them.
|
|
139
139
|
|
|
140
140
|
Signing in through a provider skips pgkiln's own second step and the enrolment on Security: the provider decides on
|
|
141
|
-
the second factor.
|
|
141
|
+
the second factor. (0.66) The provider's *Require multi-factor sign-in at this provider* makes pgkiln check that it
|
|
142
|
+
did (the ID token's `amr` / `acr`, SAML's `AuthnContextClassRef`) and refuse the sign-in otherwise; *Ask pgkiln's own
|
|
143
|
+
second step after this provider* makes a developer with a second factor give it after the provider too
|
|
144
|
+
([chapter 8](08-security.md#multi-factor-sign-in-at-the-identity-provider)). A directory checks a password, so
|
|
145
|
+
pgkiln's second step follows as with the pgkiln password.
|
|
142
146
|
|
|
143
147
|
**Requiring it per workspace.** A workspace's page (*Preferences* → *Single sign-on*) has *This workspace's
|
|
144
148
|
developers must sign in through an identity provider* (or a directory). Its developers' pgkiln password and a passkey
|
|
@@ -166,13 +170,46 @@ Sign-ins are in the activity log as `login` with *builder sso:company* or *build
|
|
|
166
170
|
| No administrator can sign in | On the server: `pgkiln admin reset-2fa <developer> --reason "…"` ([chapter 18](18-cli.md)), then sign in with the password |
|
|
167
171
|
| The policy locks everyone out | On the server: `pgkiln admin set-2fa-policy off` (also clears the workspaces' own rules) |
|
|
168
172
|
| The identity provider is down and a workspace requires single sign-on | A break-glass administrator signs in with the password and turns the workspace's rule off; without one, on the server: `pgkiln admin builder-sign-in password` |
|
|
169
|
-
| Codes are always wrong | Check the time on the phone and on the server (codes allow 30 seconds either way) |
|
|
170
|
-
| The instance key was
|
|
173
|
+
| Codes are always wrong | Check the time on the phone and on the server (codes allow 30 seconds either way); *Lockout checks* compares the server's clock |
|
|
174
|
+
| The instance key was changed | Set the old key again and rotate properly: `pgkiln admin rotate-key` ([below](#lockout-checks)) |
|
|
175
|
+
| The instance key was lost | The apps' secrets can't be read: reset the developers (`pgkiln admin reset-2fa`); passkeys and recovery codes still work |
|
|
171
176
|
|
|
172
177
|
The command line needs the owner's database connection (`DATABASE_URL`), so only someone with access to the server
|
|
173
178
|
can use it. It writes to the activity log and mails the administrators too. With Docker:
|
|
174
179
|
`docker compose exec pgkiln node bin/pgkiln.js admin reset-2fa admin`.
|
|
175
180
|
|
|
181
|
+
### Lockout checks
|
|
182
|
+
|
|
183
|
+
(0.67) **Instance settings** starts with *Lockout checks*: what could keep developers or application users out later,
|
|
184
|
+
found before it happens. The Workspace home tells administrators how many need attention.
|
|
185
|
+
|
|
186
|
+
| Check | Needs attention when |
|
|
187
|
+
|---|---|
|
|
188
|
+
| Instance key | Secrets are stored but `PGKILN_SECRET_KEY` is not set, or some can't be decrypted with it (the key changed without a rotation) |
|
|
189
|
+
| Instance key backed up | No administrator confirmed a copy of the current key (*I have a copy of this key*, or `pgkiln admin key-backed-up`). The confirmation is kept per key fingerprint, so a new key asks again |
|
|
190
|
+
| Clock | The server's clock is 10 seconds or more off the database's, or GitHub's when the [release check](#workspace-home) is on; from 30 seconds authenticator codes fail |
|
|
191
|
+
| Passkey domain | Passkeys were made for another domain than `PUBLIC_URL` (or `PGKILN_RP_ID`) gives, with the number of people who have no other factor |
|
|
192
|
+
| Break-glass administrators | A workspace requires single sign-on and there is no break-glass administrator, or one without a second factor while two-factor sign-in is required |
|
|
193
|
+
|
|
194
|
+
The server writes the same problems to its log when it starts, and `pgkiln admin check` prints them on the server
|
|
195
|
+
(exit code 1 when one needs attention). **Before moving to another address**, run `pgkiln admin check --url
|
|
196
|
+
https://new.example.com`: it lists the passkeys that won't work there and who has no other factor, so they can add an
|
|
197
|
+
authenticator app or keep their recovery codes at hand first.
|
|
198
|
+
|
|
199
|
+
**Rotating the instance key.** Authenticator apps of developers and app users, web credentials, mail and AI keys and
|
|
200
|
+
the push key are encrypted with `PGKILN_SECRET_KEY`; passkeys and recovery codes are not. To change the key, stop the
|
|
201
|
+
servers (or accept that sign-ins with an authenticator app fail for the minute in between), then on the server:
|
|
202
|
+
|
|
203
|
+
```bash
|
|
204
|
+
PGKILN_OLD_SECRET_KEY='the current key' PGKILN_SECRET_KEY='the new key' pgkiln admin rotate-key --dry-run
|
|
205
|
+
PGKILN_OLD_SECRET_KEY='the current key' PGKILN_SECRET_KEY='the new key' pgkiln admin rotate-key
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
It re-encrypts every stored secret in one transaction: a secret that neither key decrypts stops it and nothing
|
|
209
|
+
changes; a secret already under the new key is left alone, so running it twice is harmless. Start the servers with the
|
|
210
|
+
new key (an isolated workspace's database logins get their new passwords on first use), keep a copy of it and confirm
|
|
211
|
+
that on Instance settings. The rotation is in the activity log (`secret_key`) and mailed to the administrators.
|
|
212
|
+
|
|
176
213
|
## Workspaces
|
|
177
214
|
|
|
178
215
|
A workspace (APEX: a workspace) groups applications and the developers who build them, for example per team or
|
|
@@ -244,6 +244,40 @@ psql "$DATABASE_URL" -f examples/keycloak-saml.sql # reads Keycloak's signing
|
|
|
244
244
|
|
|
245
245
|
The HR login page then offers *Sign in with Keycloak (SAML)*, with the same Keycloak users.
|
|
246
246
|
|
|
247
|
+
### Multi-factor sign-in at the identity provider
|
|
248
|
+
|
|
249
|
+
With single sign-on the provider asks for the second factor, in its own sign-on policy (Entra ID Conditional Access,
|
|
250
|
+
Okta and Keycloak authentication flows, OCI IAM sign-on policies). APEX trusts that policy blindly; pgkiln (0.66) can
|
|
251
|
+
check that the provider really did it. On the provider (**Users → Identity providers**), under *Multi-factor sign-in*:
|
|
252
|
+
|
|
253
|
+
| Field | Meaning |
|
|
254
|
+
|---|---|
|
|
255
|
+
| Require multi-factor sign-in at this provider | Refuse every sign-in through this provider, to applications and to the builder, that the provider does not mark as multi-factor. The user sees *The identity provider did not confirm a second factor*; the Activity monitor logs it as a failed sign-in |
|
|
256
|
+
| Ask the provider for | Sent with every sign-in: OpenID Connect `acr_values`, or SAML `AuthnContextClassRef` values (a `RequestedAuthnContext`, comparison *exact*), separated by spaces. Empty: nothing is asked for |
|
|
257
|
+
| Values that mean multi-factor | The values that count, separated by spaces; any one is enough. OpenID Connect: an entry of the ID token's `amr` claim (RFC 8176) or its `acr`. SAML: the assertion's `AuthnContextClassRef` |
|
|
258
|
+
| Ask pgkiln's own second step after this provider | For providers that cannot require MFA themselves: see below |
|
|
259
|
+
|
|
260
|
+
The default values are `mfa` (Entra ID, Okta and Auth0 put it in `amr` after a second factor), Entra ID's SAML
|
|
261
|
+
`http://schemas.microsoft.com/claims/multipleauthn`, and SAML's `MobileTwoFactorContract` and
|
|
262
|
+
`MobileTwoFactorUnregistered`. For Keycloak, name the level of your step-up flow (for example request and accept
|
|
263
|
+
`gold`, or `2` with the default level-of-authentication mapping); for a SAML IdP, the class it sends after a second
|
|
264
|
+
factor. Without *Require*, a provider that does say `mfa` still counts: the session then has a recent second step for
|
|
265
|
+
[step-up](#asking-again-before-a-sensitive-page-step-up), and the Activity monitor shows `sso:<provider> (mfa)`.
|
|
266
|
+
|
|
267
|
+
**Step-up through the provider.** A user who signed in through a provider and opens a page behind an authorization
|
|
268
|
+
scheme with *Second step within (minutes)* goes back to that provider, which is asked to sign them in again
|
|
269
|
+
(OpenID Connect `prompt=login` and `max_age=0`; SAML `ForceAuthn`) with the requested context. The answer must carry
|
|
270
|
+
one of the multi-factor values, a sign-in time (`auth_time`, or the SAML `AuthnInstant`) of the last ten minutes,
|
|
271
|
+
and the identity already linked to the signed-in account; nothing is created or linked on the way. The page then
|
|
272
|
+
opens.
|
|
273
|
+
|
|
274
|
+
**pgkiln's own second step after the provider.** With *Ask pgkiln's own second step after this provider* on, a sign-in
|
|
275
|
+
through the provider is followed by the application's [two-factor rule](#two-factor-sign-in) exactly as after a
|
|
276
|
+
password (users add an app or a passkey on *My account*, or while signing in when the application requires one), and
|
|
277
|
+
step-up asks for that factor instead of going back to the provider. For the builder, a developer with a second factor
|
|
278
|
+
gives it after the provider; one without is treated like a password sign-in, so a two-factor rule of the instance or
|
|
279
|
+
workspace makes them add one.
|
|
280
|
+
|
|
247
281
|
### LDAP and Active Directory
|
|
248
282
|
|
|
249
283
|
Applications can check passwords against **LDAP directories** (OpenLDAP, Active Directory,
|
|
@@ -426,7 +460,8 @@ sign-on policy asks for one, or a hand-written TOTP check in a custom authentica
|
|
|
426
460
|
How it works:
|
|
427
461
|
|
|
428
462
|
- The second step follows the user directory's **password** and **LDAP** directories. An identity provider
|
|
429
|
-
([OpenID Connect](#single-sign-on-openid-connect), [SAML](#single-sign-on-saml-20)) asks for its own second factor
|
|
463
|
+
([OpenID Connect](#single-sign-on-openid-connect), [SAML](#single-sign-on-saml-20)) asks for its own second factor,
|
|
464
|
+
which pgkiln can [check](#multi-factor-sign-in-at-the-identity-provider), or leaves it to pgkiln's second step;
|
|
430
465
|
database accounts, custom authentication and HTTP header authentication are not covered.
|
|
431
466
|
- The code comes from any authenticator app (TOTP, RFC 6238: Google Authenticator, Microsoft Authenticator,
|
|
432
467
|
1Password …), each code once, one 30-second step either side for clock drift. A **recovery code** (ten per account,
|
|
@@ -472,7 +507,9 @@ An authorization scheme's **Second step within (minutes)** makes it pass only wh
|
|
|
472
507
|
the scheme otherwise to *Confirm it's you* (the second-step page) and back to the page afterwards; regions, buttons and
|
|
473
508
|
processes behind it stay hidden or skipped until then. A user without a factor is told to add one on *My account*.
|
|
474
509
|
Typical: `SALARY_EDIT` (role `hr_manager`, second step within 15 minutes) on the page that changes salaries. A
|
|
475
|
-
*Keep me signed in
|
|
510
|
+
*Keep me signed in* or shared session has no recent second step of pgkiln's own, so it is asked too; a single sign-on
|
|
511
|
+
session goes back to its [identity provider](#multi-factor-sign-in-at-the-identity-provider) for a new multi-factor
|
|
512
|
+
sign-in (or to pgkiln's own second step, when the provider leaves it to pgkiln).
|
|
476
513
|
A form posted after the time ran out is not processed: the user confirms, comes back to the page and submits again.
|
|
477
514
|
|
|
478
515
|
#### REST API tokens
|
|
@@ -493,7 +530,8 @@ application users, so nothing to cover there.
|
|
|
493
530
|
- **Stale sessions**: 60 minutes idle or 8 hours total (configurable).
|
|
494
531
|
- **Stolen passwords**: [two-factor sign-in](#two-factor-sign-in) asks for a code from an authenticator app or a
|
|
495
532
|
passkey, for every user or for some roles, and again before sensitive pages ([step-up](#asking-again-before-a-sensitive-page-step-up)); with an identity provider ([OpenID Connect](#single-sign-on-openid-connect),
|
|
496
|
-
[SAML](#single-sign-on-saml-20)) the provider asks for its own
|
|
533
|
+
[SAML](#single-sign-on-saml-20)) the provider asks for its own, and pgkiln
|
|
534
|
+
[checks that it did](#multi-factor-sign-in-at-the-identity-provider). Developers have
|
|
497
535
|
[two-factor sign-in](03-builder.md#two-factor-sign-in) for the builder too.
|
|
498
536
|
|
|
499
537
|
All sign-ins, failures and lockouts appear in the **Activity** monitor.
|
|
@@ -22,6 +22,10 @@ src/
|
|
|
22
22
|
env.ts .env loader (imported first)
|
|
23
23
|
migrate.ts applies db/migrations and examples (scripts/migrate.ts, pgkiln migrate); logs each run that applies
|
|
24
24
|
instance.ts instance settings (meta.setting over environment variables, cached 30 s) and the configuration overview
|
|
25
|
+
instance-checks.ts (sprint 133, SEC-6) lockout checks: instance key (unreadable secrets, backup confirmed per fingerprint in
|
|
26
|
+
meta.setting secret_key_backup), clock against the database and GitHub's Date header, passkeys of another
|
|
27
|
+
RP ID, break-glass administrators; rotateKey() re-encrypts every *_enc column in one transaction;
|
|
28
|
+
used by Instance settings, the Workspace home (cached count), server start-up and `pgkiln admin check`
|
|
25
29
|
release-check.ts (sprint 109) "pgkiln X is available": meta.setting 'release_check' over PGKILN_RELEASE_CHECK (off by default);
|
|
26
30
|
GitHub's releases/latest (PGKILN_RELEASE_URL in tests), 5 s timeout, 1 MB, cached a day per process,
|
|
27
31
|
never under node --test without PGKILN_RELEASE_URL; parseRelease keeps a semver and an https link only
|
|
@@ -143,7 +147,8 @@ src/
|
|
|
143
147
|
nextRuns in a time zone, describeSchedule in words, the builder's presets and fields
|
|
144
148
|
pgcron.ts (sprint 101, DA-12) pg_cron for SQL Workshop → Scheduling: cronState (installed, loaded, cron.database_name,
|
|
145
149
|
access), jobs and runs, jobSql/activeSql/unscheduleSql/purgeSql (reviewed, then applySql), runNow
|
|
146
|
-
secrets.ts secrets at rest (web credentials): AES-256-GCM with PGKILN_SECRET_KEY
|
|
150
|
+
secrets.ts secrets at rest (web credentials): AES-256-GCM with PGKILN_SECRET_KEY (or a key given, for rotate-key);
|
|
151
|
+
keyFingerprint()
|
|
147
152
|
websources.ts web credentials (OAuth2 client credentials/password/refresh token grants, token cache, stored refresh
|
|
148
153
|
tokens) and REST data sources: requests, JSON paths, typed rows, response cache, write-back operations
|
|
149
154
|
(callOperation); invoke(): the invoke API call shared by the invoke_api process and workflow step
|
|
@@ -420,7 +425,8 @@ src/
|
|
|
420
425
|
write-back operations, synchronisation settings, Synchronise now and run history
|
|
421
426
|
templates.ts template components: preview, plug-in export/import, region settings, report column templates
|
|
422
427
|
code-editor.ts code fields (data-code marks), /builder/code/completions (scoped to the app's role), /builder/code/check
|
|
423
|
-
instance.ts Workspace utilities → Instance settings (src/instance.ts: session and sign-in settings, configuration overview
|
|
428
|
+
instance.ts Workspace utilities → Instance settings (src/instance.ts: session and sign-in settings, configuration overview;
|
|
429
|
+
Lockout checks from src/instance-checks.ts and POST /instance/key-backup)
|
|
424
430
|
gallery.ts the App Gallery (sprint 61, 120): examples/gallery/gallery.json, sample apps (administrators: migrate --example,
|
|
425
431
|
or one SQL file of examples/ or examples/gallery/samples/ in one transaction), starter and utility apps
|
|
426
432
|
(blueprints of starters/ and utilities/ → openBlueprint's review), custom apps (the workspace's boilerplates);
|
package/docs/guide/18-cli.md
CHANGED
|
@@ -55,6 +55,9 @@ any (see [what is not exported](03-builder.md#export-format)).
|
|
|
55
55
|
| `pgkiln admin reset-2fa <developer> [--reason <text>]` | (0.60) Removes a developer's authenticator apps and recovery codes and ends their builder sessions: [locked out?](03-builder.md#locked-out) |
|
|
56
56
|
| `pgkiln admin set-2fa-policy off\|admins\|all [--grace <days>]` | (0.60) Sets the builder's [two-factor policy](03-builder.md#two-factor-sign-in); `off` always works (and, 0.62, clears every workspace's own rule), the others need two administrators with an app |
|
|
57
57
|
| `pgkiln admin builder-sign-in password` | (0.63) Turns off every workspace's [single sign-on rule](03-builder.md#single-sign-on-for-developers), so developers may sign in with the pgkiln password again; logged and mailed to the administrators |
|
|
58
|
+
| `pgkiln admin rotate-key [--dry-run]` | (0.67) Re-encrypts every stored secret from `PGKILN_OLD_SECRET_KEY` to `PGKILN_SECRET_KEY` in one transaction ([rotating the instance key](03-builder.md#lockout-checks)); logged and mailed to the administrators |
|
|
59
|
+
| `pgkiln admin key-backed-up` | (0.67) Records that a copy of the current `PGKILN_SECRET_KEY` is kept outside the server |
|
|
60
|
+
| `pgkiln admin check [--url <address>]` | (0.67) Prints the [lockout checks](03-builder.md#lockout-checks); `--url` checks passkeys against a new public address. Exit code 1 when one needs attention |
|
|
58
61
|
|
|
59
62
|
`users` reads the password from standard input (the first line, e.g. from a secret store:
|
|
60
63
|
`printf '%s\n' "$PW" | pgkiln users add ops --developer`) or asks for it twice on a terminal. It is
|
|
@@ -63,8 +63,8 @@ sources (including write-back, synchronisation and the response cache), `meta.we
|
|
|
63
63
|
API, token endpoints, object storage and REST source catalogs. Refusals are logged in the
|
|
64
64
|
application's debug log and listed under *Refused calls*.
|
|
65
65
|
|
|
66
|
-
**Changing `PGKILN_SECRET_KEY`**
|
|
67
|
-
the secret must be entered again. Keep the key with your other server secrets, outside the
|
|
66
|
+
**Changing `PGKILN_SECRET_KEY`** without `pgkiln admin rotate-key` ([chapter 3](03-builder.md#lockout-checks))
|
|
67
|
+
makes the stored secrets unreadable: pgkiln then reports that the secret must be entered again. Keep the key with your other server secrets, outside the
|
|
68
68
|
database: a database dump alone does not reveal the secrets.
|
|
69
69
|
|
|
70
70
|
## Web credentials
|
package/package.json
CHANGED
package/public/builder.css
CHANGED
|
@@ -1576,3 +1576,9 @@ pre.wrap-pre { white-space: pre-wrap; overflow-wrap: anywhere; }
|
|
|
1576
1576
|
.mfa-steps { padding-left: 1.25rem; }
|
|
1577
1577
|
.mfa-codes { columns: 2; column-gap: 2rem; padding-left: 1.5rem; font-size: 1.05em; }
|
|
1578
1578
|
@media (max-width: 480px) { .mfa-codes { columns: 1; } }
|
|
1579
|
+
|
|
1580
|
+
/* Settings → Sign-in: a checkbox under a grid of fields gets room, and long help stays readable */
|
|
1581
|
+
.settings-panel[data-tab="signin"] .form-grid + .field { margin-top: 0.75rem; }
|
|
1582
|
+
.settings-panel[data-tab="signin"] .field > .help,
|
|
1583
|
+
.settings-panel[data-tab="signin"] p.small { max-width: 75ch; }
|
|
1584
|
+
.settings-panel[data-tab="signin"] h3:not(:first-child) { margin-top: 1.5rem; }
|
package/src/builder/i18n/de.ts
CHANGED
|
@@ -171,6 +171,8 @@ export const de: BuilderMessages = {
|
|
|
171
171
|
'wh.how_upgrade': 'So aktualisieren Sie',
|
|
172
172
|
'wh.upgrade_steps': 'Zum Aktualisieren: Sichern Sie die Datenbank, installieren Sie die neue Version ({npm} oder das Docker-Image {docker}), führen Sie {migrate} aus und starten Sie den Server neu.',
|
|
173
173
|
'wh.check_off': 'Die Prüfung auf neue Versionen ist deaktiviert.',
|
|
174
|
+
'wh.lockout': 'Prüfungen gegen Aussperren, die Aufmerksamkeit brauchen: {count}.',
|
|
175
|
+
'wh.lockout_open': 'Instanzeinstellungen',
|
|
174
176
|
'wh.check_failed': 'Die letzte Prüfung ist fehlgeschlagen ({error}).',
|
|
175
177
|
'wh.check_failed_older': 'Die letzte Prüfung ist fehlgeschlagen ({error}); das obige Ergebnis ist älter.',
|
|
176
178
|
'wh.checked': 'Geprüft {ago}.',
|
|
@@ -1295,6 +1297,9 @@ export const de: BuilderMessages = {
|
|
|
1295
1297
|
'st.custom_post_help': 'Optionales PL/pgSQL nach einer erfolgreichen Prüfung, mit p_username (und meta.app_user()), z. B. um die letzte Anmeldung zu speichern. Eine Exception lehnt die Anmeldung ab. Anwendungsprozesse „after login“ laufen danach wie gewohnt.',
|
|
1296
1298
|
'st.signin': 'Anmeldung',
|
|
1297
1299
|
'st.methods': 'Anmeldemethoden',
|
|
1300
|
+
'st.signin_page': 'Anmeldeseite',
|
|
1301
|
+
'st.staying': 'Angemeldet bleiben',
|
|
1302
|
+
'st.two_factor': 'Zwei-Faktor-Anmeldung',
|
|
1298
1303
|
'st.local': 'Benutzername und Passwort',
|
|
1299
1304
|
'st.ldap': 'Passwörter aus LDAP: {name}',
|
|
1300
1305
|
'st.disabled': '(deaktiviert)',
|
|
@@ -1509,6 +1514,16 @@ export const de: BuilderMessages = {
|
|
|
1509
1514
|
'idp.disabled_s': 'deaktiviert',
|
|
1510
1515
|
'idp.auto_s': 'automatisch anlegen',
|
|
1511
1516
|
'idp.links_s': 'verknüpft vorhandene Konten',
|
|
1517
|
+
'idp.mfa_title': 'Mehrstufige Anmeldung',
|
|
1518
|
+
'idp.mfa_required': 'Mehrstufige Anmeldung bei diesem Anbieter verlangen',
|
|
1519
|
+
'idp.mfa_required_help': 'Anmeldungen (bei Anwendungen und im Builder) ablehnen, die der Anbieter nicht als mehrstufig kennzeichnet: bei OpenID Connect über den amr- oder acr-Claim des ID-Tokens, bei SAML über die AuthnContextClassRef.',
|
|
1520
|
+
'idp.mfa_request': 'Beim Anbieter anfordern',
|
|
1521
|
+
'idp.mfa_request_help': 'OpenID-Connect-acr_values oder SAML-AuthnContextClassRef-Werte, durch Leerzeichen getrennt. Leer: nichts anfordern.',
|
|
1522
|
+
'idp.mfa_values': 'Werte, die mehrstufig bedeuten',
|
|
1523
|
+
'idp.mfa_values_help': 'amr-, acr- oder AuthnContextClassRef-Werte, durch Leerzeichen getrennt; einer davon genügt. Entra ID und Okta setzen „mfa“ in amr.',
|
|
1524
|
+
'idp.local_step': 'Nach diesem Anbieter den eigenen zweiten Schritt von pgkiln verlangen',
|
|
1525
|
+
'idp.local_step_help': 'Für Anbieter, die keine mehrstufige Anmeldung erzwingen können: Die Zwei-Schritt-Regel der Anwendung gilt wie nach einem Passwort, und Entwickler mit einem zweiten Faktor geben ihn ebenfalls an. Eine erneute Bestätigung fragt dann nach dem Faktor in pgkiln, statt sich erneut beim Anbieter anzumelden.',
|
|
1526
|
+
'idp.mfa_s': 'verlangt MFA',
|
|
1512
1527
|
'idp.none': 'Noch keine Identitätsanbieter.',
|
|
1513
1528
|
'idp.settings': 'Einstellungen',
|
|
1514
1529
|
'idp.delete_confirm': '{name} löschen? Verknüpfte Identitäten werden entfernt; die Konten bleiben.',
|
package/src/builder/i18n/en.ts
CHANGED
|
@@ -174,6 +174,8 @@ export const en = {
|
|
|
174
174
|
'wh.how_upgrade': 'How to upgrade',
|
|
175
175
|
'wh.upgrade_steps': 'To upgrade: back up the database, install the new version ({npm}, or the Docker image {docker}), run {migrate} and restart the server.',
|
|
176
176
|
'wh.check_off': 'The check for new versions is off.',
|
|
177
|
+
'wh.lockout': 'Lockout checks that need attention: {count}.',
|
|
178
|
+
'wh.lockout_open': 'Instance settings',
|
|
177
179
|
'wh.check_failed': 'The last check failed ({error}).',
|
|
178
180
|
'wh.check_failed_older': 'The last check failed ({error}); the result above is older.',
|
|
179
181
|
'wh.checked': 'Checked {ago}.',
|
|
@@ -1298,6 +1300,9 @@ export const en = {
|
|
|
1298
1300
|
'st.custom_post_help': 'Optional PL/pgSQL run after a successful check, with p_username (and meta.app_user()), e.g. to record the last sign-in. Raising an exception refuses the sign-in. Application processes "after login" run afterwards as usual.',
|
|
1299
1301
|
'st.signin': 'Sign-in',
|
|
1300
1302
|
'st.methods': 'Sign-in methods',
|
|
1303
|
+
'st.signin_page': 'Sign-in page',
|
|
1304
|
+
'st.staying': 'Staying signed in',
|
|
1305
|
+
'st.two_factor': 'Two-factor sign-in',
|
|
1301
1306
|
'st.local': 'Username and password',
|
|
1302
1307
|
'st.ldap': 'Passwords from LDAP: {name}',
|
|
1303
1308
|
'st.disabled': '(disabled)',
|
|
@@ -1512,6 +1517,16 @@ export const en = {
|
|
|
1512
1517
|
'idp.disabled_s': 'disabled',
|
|
1513
1518
|
'idp.auto_s': 'auto-create',
|
|
1514
1519
|
'idp.links_s': 'links existing accounts',
|
|
1520
|
+
'idp.mfa_title': 'Multi-factor sign-in',
|
|
1521
|
+
'idp.mfa_required': 'Require multi-factor sign-in at this provider',
|
|
1522
|
+
'idp.mfa_required_help': "Refuse sign-ins (to applications and to the builder) that the provider does not mark as multi-factor: OpenID Connect through the ID token's amr or acr claim, SAML through the AuthnContextClassRef.",
|
|
1523
|
+
'idp.mfa_request': 'Ask the provider for',
|
|
1524
|
+
'idp.mfa_request_help': 'OpenID Connect acr_values or SAML AuthnContextClassRef values, separated by spaces. Empty: ask for nothing.',
|
|
1525
|
+
'idp.mfa_values': 'Values that mean multi-factor',
|
|
1526
|
+
'idp.mfa_values_help': 'amr, acr or AuthnContextClassRef values, separated by spaces; any one of them is enough. Entra ID and Okta put "mfa" in amr.',
|
|
1527
|
+
'idp.local_step': "Ask pgkiln's own second step after this provider",
|
|
1528
|
+
'idp.local_step_help': "For providers that cannot require multi-factor sign-in: the application's two-step rule applies as after a password, and developers with a second factor give it too. Step-up then asks for pgkiln's factor instead of signing in at the provider again.",
|
|
1529
|
+
'idp.mfa_s': 'requires MFA',
|
|
1515
1530
|
'idp.none': 'No identity providers yet.',
|
|
1516
1531
|
'idp.settings': 'Settings',
|
|
1517
1532
|
'idp.delete_confirm': 'Delete {name}? Linked identities are removed; accounts stay.',
|
package/src/builder/i18n/es.ts
CHANGED
|
@@ -171,6 +171,8 @@ export const es: BuilderMessages = {
|
|
|
171
171
|
'wh.how_upgrade': 'Cómo actualizar',
|
|
172
172
|
'wh.upgrade_steps': 'Para actualizar: haga una copia de seguridad de la base de datos, instale la nueva versión ({npm}, o la imagen Docker {docker}), ejecute {migrate} y reinicie el servidor.',
|
|
173
173
|
'wh.check_off': 'La comprobación de nuevas versiones está desactivada.',
|
|
174
|
+
'wh.lockout': 'Comprobaciones de bloqueo que requieren atención: {count}.',
|
|
175
|
+
'wh.lockout_open': 'Ajustes de la instancia',
|
|
174
176
|
'wh.check_failed': 'La última comprobación ha fallado ({error}).',
|
|
175
177
|
'wh.check_failed_older': 'La última comprobación ha fallado ({error}); el resultado anterior es más antiguo.',
|
|
176
178
|
'wh.checked': 'Comprobado {ago}.',
|
|
@@ -1295,6 +1297,9 @@ export const es: BuilderMessages = {
|
|
|
1295
1297
|
'st.custom_post_help': 'PL/pgSQL opcional que se ejecuta tras una comprobación correcta, con p_username (y meta.app_user()), p. ej. para registrar el último inicio de sesión. Lanzar una excepción rechaza el inicio de sesión. Los procesos de aplicación «after login» se ejecutan después como siempre.',
|
|
1296
1298
|
'st.signin': 'Inicio de sesión',
|
|
1297
1299
|
'st.methods': 'Métodos de inicio de sesión',
|
|
1300
|
+
'st.signin_page': 'Página de inicio de sesión',
|
|
1301
|
+
'st.staying': 'Mantener la sesión',
|
|
1302
|
+
'st.two_factor': 'Inicio de sesión en dos pasos',
|
|
1298
1303
|
'st.local': 'Nombre de usuario y contraseña',
|
|
1299
1304
|
'st.ldap': 'Contraseñas de LDAP: {name}',
|
|
1300
1305
|
'st.disabled': '(desactivado)',
|
|
@@ -1509,6 +1514,16 @@ export const es: BuilderMessages = {
|
|
|
1509
1514
|
'idp.disabled_s': 'desactivado',
|
|
1510
1515
|
'idp.auto_s': 'creación automática',
|
|
1511
1516
|
'idp.links_s': 'vincula cuentas existentes',
|
|
1517
|
+
'idp.mfa_title': 'Inicio de sesión multifactor',
|
|
1518
|
+
'idp.mfa_required': 'Exigir inicio de sesión multifactor en este proveedor',
|
|
1519
|
+
'idp.mfa_required_help': 'Rechaza los inicios de sesión (en aplicaciones y en el builder) que el proveedor no marca como multifactor: en OpenID Connect por el claim amr o acr del token de ID, en SAML por el AuthnContextClassRef.',
|
|
1520
|
+
'idp.mfa_request': 'Solicitar al proveedor',
|
|
1521
|
+
'idp.mfa_request_help': 'Valores acr_values de OpenID Connect o AuthnContextClassRef de SAML, separados por espacios. Vacío: no solicitar nada.',
|
|
1522
|
+
'idp.mfa_values': 'Valores que significan multifactor',
|
|
1523
|
+
'idp.mfa_values_help': 'Valores amr, acr o AuthnContextClassRef, separados por espacios; basta con uno. Entra ID y Okta ponen «mfa» en amr.',
|
|
1524
|
+
'idp.local_step': 'Pedir el segundo paso propio de pgkiln después de este proveedor',
|
|
1525
|
+
'idp.local_step_help': 'Para proveedores que no pueden exigir multifactor: la regla de dos pasos de la aplicación se aplica como después de una contraseña, y los desarrolladores con un segundo factor también lo indican. La nueva confirmación pide entonces el factor de pgkiln en lugar de volver a iniciar sesión en el proveedor.',
|
|
1526
|
+
'idp.mfa_s': 'exige MFA',
|
|
1512
1527
|
'idp.none': 'Todavía no hay proveedores de identidad.',
|
|
1513
1528
|
'idp.settings': 'Ajustes',
|
|
1514
1529
|
'idp.delete_confirm': '¿Eliminar {name}? Se quitan las identidades vinculadas; las cuentas se mantienen.',
|
package/src/builder/i18n/fr.ts
CHANGED
|
@@ -171,6 +171,8 @@ export const fr: BuilderMessages = {
|
|
|
171
171
|
'wh.how_upgrade': 'Comment mettre à niveau',
|
|
172
172
|
'wh.upgrade_steps': "Pour mettre à niveau : sauvegardez la base de données, installez la nouvelle version ({npm}, ou l'image Docker {docker}), exécutez {migrate} et redémarrez le serveur.",
|
|
173
173
|
'wh.check_off': 'La recherche de nouvelles versions est désactivée.',
|
|
174
|
+
'wh.lockout': 'Contrôles contre le verrouillage à examiner : {count}.',
|
|
175
|
+
'wh.lockout_open': 'Paramètres de l’instance',
|
|
174
176
|
'wh.check_failed': 'La dernière vérification a échoué ({error}).',
|
|
175
177
|
'wh.check_failed_older': 'La dernière vérification a échoué ({error}) ; le résultat ci-dessus est plus ancien.',
|
|
176
178
|
'wh.checked': 'Vérifié {ago}.',
|
|
@@ -1295,6 +1297,9 @@ export const fr: BuilderMessages = {
|
|
|
1295
1297
|
'st.custom_post_help': 'PL/pgSQL facultatif exécuté après une vérification réussie, avec p_username (et meta.app_user()), p. ex. pour enregistrer la dernière connexion. Lever une exception refuse la connexion. Les processus d’application « after login » s’exécutent ensuite comme d’habitude.',
|
|
1296
1298
|
'st.signin': 'Connexion',
|
|
1297
1299
|
'st.methods': 'Méthodes de connexion',
|
|
1300
|
+
'st.signin_page': 'Page de connexion',
|
|
1301
|
+
'st.staying': 'Rester connecté',
|
|
1302
|
+
'st.two_factor': 'Connexion en deux étapes',
|
|
1298
1303
|
'st.local': 'Nom d’utilisateur et mot de passe',
|
|
1299
1304
|
'st.ldap': 'Mots de passe LDAP : {name}',
|
|
1300
1305
|
'st.disabled': '(désactivé)',
|
|
@@ -1509,6 +1514,16 @@ export const fr: BuilderMessages = {
|
|
|
1509
1514
|
'idp.disabled_s': 'désactivé',
|
|
1510
1515
|
'idp.auto_s': 'création automatique',
|
|
1511
1516
|
'idp.links_s': 'lie les comptes existants',
|
|
1517
|
+
'idp.mfa_title': 'Connexion multifacteur',
|
|
1518
|
+
'idp.mfa_required': 'Exiger une connexion multifacteur chez ce fournisseur',
|
|
1519
|
+
'idp.mfa_required_help': 'Refuser les connexions (aux applications et au builder) que le fournisseur ne marque pas comme multifacteur : en OpenID Connect par le claim amr ou acr du jeton d’identité, en SAML par l’AuthnContextClassRef.',
|
|
1520
|
+
'idp.mfa_request': 'Demander au fournisseur',
|
|
1521
|
+
'idp.mfa_request_help': 'Valeurs acr_values (OpenID Connect) ou AuthnContextClassRef (SAML), séparées par des espaces. Vide : ne rien demander.',
|
|
1522
|
+
'idp.mfa_values': 'Valeurs qui signifient multifacteur',
|
|
1523
|
+
'idp.mfa_values_help': 'Valeurs amr, acr ou AuthnContextClassRef, séparées par des espaces ; une seule suffit. Entra ID et Okta mettent « mfa » dans amr.',
|
|
1524
|
+
'idp.local_step': 'Demander la deuxième étape de pgkiln après ce fournisseur',
|
|
1525
|
+
'idp.local_step_help': 'Pour les fournisseurs qui ne peuvent pas exiger le multifacteur : la règle de connexion en deux étapes de l’application s’applique comme après un mot de passe, et les développeurs ayant un second facteur le donnent aussi. Une nouvelle confirmation demande alors le facteur de pgkiln au lieu de se reconnecter chez le fournisseur.',
|
|
1526
|
+
'idp.mfa_s': 'exige la MFA',
|
|
1512
1527
|
'idp.none': 'Pas encore de fournisseurs d’identité.',
|
|
1513
1528
|
'idp.settings': 'Paramètres',
|
|
1514
1529
|
'idp.delete_confirm': 'Supprimer {name} ? Les identités liées sont retirées ; les comptes restent.',
|
package/src/builder/i18n/nl.ts
CHANGED
|
@@ -171,6 +171,8 @@ export const nl: BuilderMessages = {
|
|
|
171
171
|
'wh.how_upgrade': 'Zo upgrade je',
|
|
172
172
|
'wh.upgrade_steps': 'Upgraden: maak een back-up van de database, installeer de nieuwe versie ({npm}, of de Docker-image {docker}), voer {migrate} uit en herstart de server.',
|
|
173
173
|
'wh.check_off': 'Het controleren op nieuwe versies staat uit.',
|
|
174
|
+
'wh.lockout': 'Controles tegen buitensluiten die aandacht nodig hebben: {count}.',
|
|
175
|
+
'wh.lockout_open': 'Instantie-instellingen',
|
|
174
176
|
'wh.check_failed': 'De laatste controle is mislukt ({error}).',
|
|
175
177
|
'wh.check_failed_older': 'De laatste controle is mislukt ({error}); het resultaat hierboven is ouder.',
|
|
176
178
|
'wh.checked': '{ago} gecontroleerd.',
|
|
@@ -1295,6 +1297,9 @@ export const nl: BuilderMessages = {
|
|
|
1295
1297
|
'st.custom_post_help': 'Optionele PL/pgSQL die draait na een geslaagde controle, met p_username (en meta.app_user()), bijv. om de laatste aanmelding vast te leggen. Een exception weigert de aanmelding. Applicatieprocessen “after login” draaien daarna zoals gewoonlijk.',
|
|
1296
1298
|
'st.signin': 'Aanmelden',
|
|
1297
1299
|
'st.methods': 'Aanmeldmethoden',
|
|
1300
|
+
'st.signin_page': 'Aanmeldpagina',
|
|
1301
|
+
'st.staying': 'Aangemeld blijven',
|
|
1302
|
+
'st.two_factor': 'Aanmelden in twee stappen',
|
|
1298
1303
|
'st.local': 'Gebruikersnaam en wachtwoord',
|
|
1299
1304
|
'st.ldap': 'Wachtwoorden uit LDAP: {name}',
|
|
1300
1305
|
'st.disabled': '(uitgeschakeld)',
|
|
@@ -1509,6 +1514,16 @@ export const nl: BuilderMessages = {
|
|
|
1509
1514
|
'idp.disabled_s': 'uitgeschakeld',
|
|
1510
1515
|
'idp.auto_s': 'automatisch aanmaken',
|
|
1511
1516
|
'idp.links_s': 'koppelt bestaande accounts',
|
|
1517
|
+
'idp.mfa_title': 'Meervoudige aanmelding',
|
|
1518
|
+
'idp.mfa_required': 'Meervoudige aanmelding bij deze provider vereisen',
|
|
1519
|
+
'idp.mfa_required_help': 'Aanmeldingen (bij applicaties en in de builder) weigeren die de provider niet als meervoudig aanmerkt: bij OpenID Connect via de amr- of acr-claim van het ID-token, bij SAML via de AuthnContextClassRef.',
|
|
1520
|
+
'idp.mfa_request': 'Vragen aan de provider',
|
|
1521
|
+
'idp.mfa_request_help': 'OpenID Connect-acr_values of SAML-AuthnContextClassRef-waarden, gescheiden door spaties. Leeg: niets vragen.',
|
|
1522
|
+
'idp.mfa_values': 'Waarden die meervoudig betekenen',
|
|
1523
|
+
'idp.mfa_values_help': 'amr-, acr- of AuthnContextClassRef-waarden, gescheiden door spaties; één ervan is genoeg. Entra ID en Okta zetten "mfa" in amr.',
|
|
1524
|
+
'idp.local_step': 'Na deze provider ook de eigen tweede stap van pgkiln vragen',
|
|
1525
|
+
'idp.local_step_help': 'Voor providers die geen meervoudige aanmelding kunnen afdwingen: de tweestapsregel van de applicatie geldt zoals na een wachtwoord, en ontwikkelaars met een tweede factor geven die ook. Opnieuw bevestigen vraagt dan de factor in pgkiln in plaats van opnieuw aanmelden bij de provider.',
|
|
1526
|
+
'idp.mfa_s': 'vereist MFA',
|
|
1512
1527
|
'idp.none': 'Nog geen identiteitsproviders.',
|
|
1513
1528
|
'idp.settings': 'Instellingen',
|
|
1514
1529
|
'idp.delete_confirm': '{name} verwijderen? Gekoppelde identiteiten worden verwijderd; de accounts blijven.',
|
package/src/builder/i18n/pt.ts
CHANGED
|
@@ -171,6 +171,8 @@ export const pt: BuilderMessages = {
|
|
|
171
171
|
'wh.how_upgrade': 'Como atualizar',
|
|
172
172
|
'wh.upgrade_steps': 'Para atualizar: faça backup do banco de dados, instale a nova versão ({npm}, ou a imagem Docker {docker}), execute {migrate} e reinicie o servidor.',
|
|
173
173
|
'wh.check_off': 'A verificação de novas versões está desativada.',
|
|
174
|
+
'wh.lockout': 'Verificações contra bloqueio que precisam de atenção: {count}.',
|
|
175
|
+
'wh.lockout_open': 'Configurações da instância',
|
|
174
176
|
'wh.check_failed': 'A última verificação falhou ({error}).',
|
|
175
177
|
'wh.check_failed_older': 'A última verificação falhou ({error}); o resultado acima é mais antigo.',
|
|
176
178
|
'wh.checked': 'Verificado {ago}.',
|
|
@@ -1295,6 +1297,9 @@ export const pt: BuilderMessages = {
|
|
|
1295
1297
|
'st.custom_post_help': 'PL/pgSQL opcional executado após uma verificação bem-sucedida, com p_username (e meta.app_user()), por exemplo para registrar o último login. Lançar uma exceção recusa o login. Processos de aplicação “after login” são executados depois, como de costume.',
|
|
1296
1298
|
'st.signin': 'Login',
|
|
1297
1299
|
'st.methods': 'Métodos de login',
|
|
1300
|
+
'st.signin_page': 'Página de acesso',
|
|
1301
|
+
'st.staying': 'Manter o acesso',
|
|
1302
|
+
'st.two_factor': 'Acesso em duas etapas',
|
|
1298
1303
|
'st.local': 'Nome de usuário e senha',
|
|
1299
1304
|
'st.ldap': 'Senhas do LDAP: {name}',
|
|
1300
1305
|
'st.disabled': '(desativado)',
|
|
@@ -1509,6 +1514,16 @@ export const pt: BuilderMessages = {
|
|
|
1509
1514
|
'idp.disabled_s': 'desativado',
|
|
1510
1515
|
'idp.auto_s': 'criação automática',
|
|
1511
1516
|
'idp.links_s': 'vincula contas existentes',
|
|
1517
|
+
'idp.mfa_title': 'Acesso multifator',
|
|
1518
|
+
'idp.mfa_required': 'Exigir acesso multifator neste provedor',
|
|
1519
|
+
'idp.mfa_required_help': 'Recusar acessos (às aplicações e ao builder) que o provedor não marca como multifator: no OpenID Connect pelo claim amr ou acr do token de ID, no SAML pelo AuthnContextClassRef.',
|
|
1520
|
+
'idp.mfa_request': 'Pedir ao provedor',
|
|
1521
|
+
'idp.mfa_request_help': 'Valores acr_values do OpenID Connect ou AuthnContextClassRef do SAML, separados por espaços. Vazio: não pedir nada.',
|
|
1522
|
+
'idp.mfa_values': 'Valores que significam multifator',
|
|
1523
|
+
'idp.mfa_values_help': 'Valores amr, acr ou AuthnContextClassRef, separados por espaços; basta um deles. Entra ID e Okta colocam "mfa" em amr.',
|
|
1524
|
+
'idp.local_step': 'Pedir a segunda etapa do próprio pgkiln após este provedor',
|
|
1525
|
+
'idp.local_step_help': 'Para provedores que não conseguem exigir multifator: a regra de duas etapas da aplicação vale como após uma senha, e desenvolvedores com um segundo fator também o informam. A nova confirmação pede então o fator do pgkiln em vez de entrar de novo no provedor.',
|
|
1526
|
+
'idp.mfa_s': 'exige MFA',
|
|
1512
1527
|
'idp.none': 'Ainda não há provedores de identidade.',
|
|
1513
1528
|
'idp.settings': 'Configurações',
|
|
1514
1529
|
'idp.delete_confirm': 'Excluir {name}? As identidades vinculadas são removidas; as contas ficam.',
|