Files
Donkie e0074e344b auth: environment flags and instance secret key
Adds the configuration surface for the opt-in authentication system. Nothing
reads these yet beyond the startup secret-key resolution; the gates that
consume them arrive in later commits.

New variables, all documented in .env.example:

  SPOOLMAN_AUTH_ENABLED         enforce authentication (default FALSE)
  SPOOLMAN_SECRET_KEY[_FILE]    instance secret key
  SPOOLMAN_TRUSTED_PROXIES      proxies whose forwarding headers we believe
  SPOOLMAN_COOKIE_SECURE        AUTO/TRUE/FALSE override for the Secure flag
  SPOOLMAN_METRICS_PUBLIC       keep /metrics open while auth is on
  SPOOLMAN_METRICS_TOKEN[_FILE] shared token granting /metrics access

Notes:

- A private _parse_bool helper covers the new booleans. The five existing
  boolean accessors are deliberately left inlined: each carries a bespoke
  error message that users quote in bug reports, and rewriting them would
  turn this into an unrelated refactor.

- _read_env_or_file strips file contents, unlike get_password(). Key and
  token files are normally produced by a shell redirect, and an unstripped
  trailing newline would silently yield a different secret than the one the
  operator wrote.

- The generated key file is created with an exclusive open at mode 0600
  rather than a write followed by chmod, so its contents are never briefly
  world-readable under a permissive umask. An existing file with looser
  permissions warns rather than fails, since some bind mounts cannot
  represent 0600.

- ensure_secret_key() runs in startup() after the data-directory write
  check and before the alembic subprocess: it needs a writable directory
  but no schema, so a misconfiguration fails fast with an actionable
  message. It is guarded by is_auth_enabled(), so an auth-disabled instance
  never grows the file.

Phase 1 does not use the key cryptographically -- session tokens are opaque
random values stored as SHA-256, and CSRF is a double-submit cookie compare.
It is introduced now because phases 3 and 4 consume it, and adding it later
would force every phase-1 adopter to reconfigure.

Verified: generation yields mode 0600, precedence is _FILE > env > generated,
trailing newlines are stripped, a missing key file raises a clear ValueError,
and CSV/AUTO parsing round-trips.
2026-07-27 20:12:39 +02:00

16 lines
752 B
Python

"""Authentication and authorization.
Everything in this package is inert unless ``SPOOLMAN_AUTH_ENABLED`` is set. With it
unset, permission gates short-circuit to an unrestricted principal before touching the
database, so an instance behaves exactly as it did before authentication existed.
The permission model has two orthogonal axes:
* **Level** -- an ordered ``read < edit < manage`` scale carried by users and, from
phase 2, by API keys. ``read`` covers every GET, ``edit`` adds modification of
existing records, and ``manage`` adds creation and deletion.
* **Flags** -- ``is_admin`` (administers other users) and ``is_owner`` (exactly one per
instance; promotes admins and cannot be demoted by anyone else). Both imply
``manage``.
"""