CLI: positional rp-id/rp-name; init adds domains to an existing database
- 'paskia init [rp-id] [rp-name]' and 'paskia migrate [rp-id]' are now positional; comma separation and the --rp-id/--rp-name flags are gone. - With an existing paskia.kantadb, init adds the rp-id as a new domain (seeding its OIDC provider) or updates an existing domain's rp-name. - Origin allow-list semantics clarified: the bare '*' entry allows anything within the rp-id domain on any scheme and port (also the empty-list default and its display in the admin UI, replacing the synthetic '*.rp-id' row); '*.x' wildcards are https-only; exact entries match scheme, host and port. Legacy '*.rp-id' wildcards migrate to '*' to preserve their any-scheme meaning.
This commit is contained in:
+1
-1
@@ -79,7 +79,7 @@ E.g. Org admin cannot see anything of the other orgs that he has no admin access
|
||||
|
||||
Domain endpoints require the `auth:admin` permission; writes additionally require recent authentication (5 minutes). Changes are validated cross-domain and apply immediately.
|
||||
|
||||
`origins` is an object keyed by sign-in sites *within* the domain (bare hosts, `*.` wildcards, or full origins when not https); an empty object means the rp-id and all subdomains may authenticate. A value of `true` marks presence; `{"auth_host": true}` additionally marks the entry as the domain's authentication host. `related` is an object keyed by *other* domains that may assert this domain's rp-id (WebAuthn Related Origin Requests, max 5); those are published at `/.well-known/webauthn` on the rp-id host. Entries filed under the wrong map are rejected: cross-domain entries in `origins`, in-domain entries in `related`.
|
||||
`origins` is an object keyed by sign-in sites *within* the domain (bare hosts, `*.` wildcards matching the base domain and subdomains over https only, the bare `*` for anything in-domain on any scheme/port, or full origins when not https); an empty object means the rp-id and all subdomains may authenticate on any scheme. A value of `true` marks presence; `{"auth_host": true}` additionally marks the entry as the domain's authentication host. `related` is an object keyed by *other* domains that may assert this domain's rp-id (WebAuthn Related Origin Requests, max 5); those are published at `/.well-known/webauthn` on the rp-id host. Entries filed under the wrong map are rejected: cross-domain entries in `origins`, in-domain entries in `related`.
|
||||
|
||||
### WebSockets: /auth/ws/*
|
||||
|
||||
|
||||
+36
-27
@@ -167,14 +167,18 @@ class Config(msgspec.Struct, omit_defaults=True):
|
||||
URL, background jobs), the single configured domain is used, and with
|
||||
several domains the first one sorted by rp-id — never for dispatch.
|
||||
- Origin keys are bare hosts (`app.example.com`), wildcard patterns
|
||||
(`*.example.com`), or full origins when not https
|
||||
(`http://localhost:8080`) — `https://` is omitted as the common case.
|
||||
A dict value of `true` means presence only; an object carries extra
|
||||
properties (currently just `auth_host`). Ordering carries no meaning —
|
||||
display order is a UI affair.
|
||||
(`*.example.com`), full origins when not https (`http://localhost:8080`),
|
||||
or the bare `*` — `https://` is omitted as the common case. A dict value
|
||||
of `true` means presence only; an object carries extra properties
|
||||
(currently just `auth_host`). Ordering carries no meaning — display
|
||||
order is a UI affair.
|
||||
- An empty `origins` dict means the rp-id and all its subdomains may
|
||||
sign in (the default). A non-empty dict is an allow-list of in-domain
|
||||
sign-in sites; one entry may be marked `auth_host` (never a wildcard).
|
||||
sign-in sites; matching semantics per entry kind:
|
||||
- `*` — anything within the rp-id domain, any scheme and port;
|
||||
- `*.example.com` — the base domain and its subdomains, **https only**;
|
||||
- anything else — exact match on scheme, host and port.
|
||||
One entry may be marked `auth_host` (never a wildcard or `*`).
|
||||
- **Origin validation** — two separate concerns: `origins` entries must
|
||||
be within the rp-id domain. `related` entries must be outside it, are
|
||||
capped (default 5), must not be wildcards, and must not collide with
|
||||
@@ -190,22 +194,28 @@ The CLI is split so that domain options exist only at bootstrap time —
|
||||
they can never mix with runtime configuration of an already-configured
|
||||
instance:
|
||||
|
||||
- **`paskia init`** — creates `paskia.kantadb` in CWD and seeds it:
|
||||
- `--rp-id`: repeatable/comma-separated, default `["localhost"]`.
|
||||
Multiple values create multiple domains at once (useful for
|
||||
devserver/e2e).
|
||||
- `--rp-name`: applies to the **first** rp-id only. Its purpose is that
|
||||
the very first admin registration ceremony already shows the correct
|
||||
RP name; everything else (origins, auth hosts, related domains) is
|
||||
set up via the admin interface afterwards.
|
||||
- **`paskia init [rp-id] [rp-name]`** — creates `paskia.kantadb` in CWD
|
||||
and seeds it:
|
||||
- `rp-id` (positional, default `localhost`) and `rp-name` (positional,
|
||||
default same as rp-id) are the only bootstrap-time domain
|
||||
configuration; the rp-name exists so the very first admin
|
||||
registration ceremony already shows the correct name. Everything else
|
||||
(origins, auth hosts, related domains) is set up via the admin
|
||||
interface.
|
||||
- `--listen`: stored into `Config.listen` (process-global).
|
||||
- Seeds the admin user + registration reset link and prints the link.
|
||||
Refuses to run if `paskia.kantadb` already exists, or if an
|
||||
unconverted legacy `*.paskiadb` is present (`paskia migrate` converts
|
||||
it first).
|
||||
- **`paskia migrate`** — converts a legacy `<rp-id>.paskiadb` database
|
||||
(§10) to `paskia.kantadb`. With several legacy candidates, `--rp-id`
|
||||
selects `<rp-id>.paskiadb` by name; the others are left in place.
|
||||
Refuses to run if an unconverted legacy `*.paskiadb` is present
|
||||
(`paskia migrate` converts it first).
|
||||
- **With an existing `paskia.kantadb`**, init instead adds the given
|
||||
rp-id as a new domain (seeding its OIDC provider), or updates the
|
||||
rp-name of an existing one — a convenience for what the admin
|
||||
interface also does.
|
||||
- **`paskia migrate [rp-id]`** — converts a legacy `<rp-id>.paskiadb`
|
||||
database (§10) to `paskia.kantadb`. With several legacy candidates, the
|
||||
positional rp-id selects `<rp-id>.paskiadb` by name; the others are
|
||||
left in place. A legacy wildcard origin over the rp-id itself
|
||||
(`*.example.com`) converts to the bare `*` entry, preserving its
|
||||
any-scheme meaning.
|
||||
- **`paskia`** — serve. Takes **no domain options**; only `--listen`
|
||||
(per-run override of stored `Config.listen`, never persisted). Startup:
|
||||
open `paskia.kantadb` → sanitize the stored domain set best-effort →
|
||||
@@ -437,7 +447,7 @@ effective_auth_host(domain) = domain's own auth host or first configured one or
|
||||
file) becomes `paskia.kantadb`, `users/` becomes `paskia.data/users/`,
|
||||
and the old directory is renamed aside to `<name>.converted-bak`. A
|
||||
lone candidate converts without options; with several candidates
|
||||
`--rp-id <rp-id>` selects `<rp-id>.paskiadb` by name and the rest are
|
||||
a positional rp-id selects `<rp-id>.paskiadb` by name and the rest are
|
||||
left in place (e.g. a `*.bak.paskiadb` backup does not block
|
||||
conversion). Empty directories are ignored. Conversion is an explicit
|
||||
operator action, never a serve side effect — read-only opens never
|
||||
@@ -465,18 +475,17 @@ effective_auth_host(domain) = domain's own auth host or first configured one or
|
||||
|
||||
## 12. Development
|
||||
|
||||
- `scripts/devserver.py`: bootstraps via one-shot `paskia init` when no
|
||||
database exists (multi `--rp-id`, `--rp-name` for the first domain),
|
||||
then runs plain `paskia` serve. Caddy dev origins iterate all bootstrap
|
||||
rp-ids.
|
||||
- `scripts/devserver.py`: bootstraps via one-shot `paskia init` per rp-id
|
||||
when no database exists (rp-name for the first domain), then runs
|
||||
plain `paskia` serve. Caddy dev origins iterate all bootstrap rp-ids.
|
||||
- `PASKIA_AUTH_HOST` (consumed by `frontend/vite.config.js`) is a
|
||||
comma-separated list of bare hostnames; the vite dev proxy forwards
|
||||
`/.well-known/openid-configuration` and `/.well-known/webauthn` to the
|
||||
backend.
|
||||
- The example `caddy/auth/setup` snippet forwards both well-known paths
|
||||
to paskia so a static `/.well-known/*` handler does not shadow them.
|
||||
- E2E: `e2e/tests/global-setup.ts` runs `paskia init --rp-id
|
||||
localhost,test.localhost` in the test-data dir (which doubles as the
|
||||
- E2E: `e2e/tests/global-setup.ts` runs `paskia init localhost` and
|
||||
`paskia init test.localhost` in the test-data dir (which doubles as the
|
||||
server CWD) and serves; `e2e/tests/50-multidomain.spec.ts` exercises
|
||||
host dispatch, the well-known endpoint via the admin domain API, and a
|
||||
cross-domain remote login (request at test.localhost, permit at
|
||||
|
||||
Reference in New Issue
Block a user