Rename project: ubuntu-fido -> authforge
Renames the package and all artifacts to authforge to drop the
distro-specific prefix, since the roadmap targets Ubuntu + Debian +
KDE + eventually Fedora (option C in the design).
- deb packages: authforge, authforge-{daemon,pam,cli,gui,gnome-integration}
- binaries: authforged, authforgectl, authforge (GUI)
- D-Bus name: io.dangerousthings.AuthForge
- PAM module: pam_authforge_pending.so
- Paths: /etc/authforge/, /var/lib/authforge/, /usr/share/pam-configs/authforge
- PPA: ppa:dangerousthings/authforge
Filesystem path /home/work/VSCodeProjects/ubuntu_fido/ left as-is for
historical reference; can rename later via git mv at the dir level.
Verified: cargo build/test/clippy/fmt clean, pam builds, gui builds,
all 5 debs produced.
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
# ubuntu-fido — Design Document
|
||||
# authforge — Design Document
|
||||
|
||||
**Date:** 2026-04-26
|
||||
**Status:** Draft (brainstorm complete, validated through Section 2 with stakeholder)
|
||||
@@ -22,21 +22,21 @@ This project ships a single deb package that gives end users and admins a turnke
|
||||
| 2 | **v1 target: Ubuntu LTS + GNOME.** Ultimate target: Ubuntu + Debian × GNOME + KDE Plasma. | ~25–30% of Linux desktop on day one, ~50–60% at target state. v1 ships in months not years. |
|
||||
| 3 | **GUI: standalone GTK4/libadwaita app + optional gnome-control-center Users-panel shortcut deb.** | gnome-control-center has no stable plugin API. Standalone app is forward-compatible; shortcut deb adds discoverability without coupling to GNOME release cycle. |
|
||||
| 4 | **Authenticators: U2F + FIDO2 passkey + TOTP.** TOTP behind a build-time feature flag. | Full scope as written; flag lets us ship a beta without TOTP if the QR/recovery-code UX slips schedule. |
|
||||
| 5 | **Policy contexts: 3 in main GUI (gdm-password, sudo, sshd) with Disabled / Optional / Required modes.** Full list (polkit, su, login, plus auto-detected stacks) under pkexec admin gate or via `/etc/ubuntu-fido/policy.d/*.conf`. | 95% case stays simple; advanced/fleet path unrestricted. Mandatory pre-commit lockout simulation. |
|
||||
| 6 | **First-login enrollment: `chage -d 0` + autostart enrollment app + small `pam_ubuntu_fido_pending.so` blocking module.** | Belt-and-suspenders: leverages existing forced-password-change, adds enrollment via autostart, PAM module ensures user can't bypass by killing the modal. |
|
||||
| 5 | **Policy contexts: 3 in main GUI (gdm-password, sudo, sshd) with Disabled / Optional / Required modes.** Full list (polkit, su, login, plus auto-detected stacks) under pkexec admin gate or via `/etc/authforge/policy.d/*.conf`. | 95% case stays simple; advanced/fleet path unrestricted. Mandatory pre-commit lockout simulation. |
|
||||
| 6 | **First-login enrollment: `chage -d 0` + autostart enrollment app + small `pam_authforge_pending.so` blocking module.** | Belt-and-suspenders: leverages existing forced-password-change, adds enrollment via autostart, PAM module ensures user can't bypass by killing the modal. |
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
┌─────────────────────────┐ ┌──────────────────────────┐ ┌──────────────┐
|
||||
│ ubuntu-fido GTK app │ │ ubuntu-fidoctl (CLI) │ │ Future KDE │
|
||||
│ authforge GTK app │ │ authforgectl (CLI) │ │ Future KDE │
|
||||
│ (libadwaita panel) │ │ (admin/fleet scripting) │ │ KCM module │
|
||||
└─────────────┬───────────┘ └────────────┬─────────────┘ └──────┬───────┘
|
||||
│ D-Bus (org.dt.UbuntuFido) │ │
|
||||
│ D-Bus (io.dangerousthings.AuthForge) │ │
|
||||
└─────────────┬─────────────┴────────────────────────┘
|
||||
▼
|
||||
┌────────────────────────────────────┐
|
||||
│ ubuntu-fidod (system daemon) │ ← polkit-mediated
|
||||
│ authforged (system daemon) │ ← polkit-mediated
|
||||
│ - enrollment orchestration │
|
||||
│ - policy read/write + lockout │
|
||||
│ safety simulation │
|
||||
@@ -47,7 +47,7 @@ This project ships a single deb package that gives end users and admins a turnke
|
||||
▼
|
||||
┌─────────────────┬───────┴────────┬──────────────────────┐
|
||||
▼ ▼ ▼ ▼
|
||||
/etc/pam.d/* /etc/ubuntu-fido/ ~/.config/Yubico/ /var/lib/ubuntu-fido/
|
||||
/etc/pam.d/* /etc/authforge/ ~/.config/Yubico/ /var/lib/authforge/
|
||||
(stack edits policy.d/*.conf u2f_keys (per-user) pending/<user>
|
||||
via pam-auth- (admin/fleet /etc/u2f_mappings (first-login flag)
|
||||
update) drop-ins) (central override)
|
||||
@@ -55,7 +55,7 @@ update) drop-ins) (central override)
|
||||
|
||||
### Trust boundary
|
||||
|
||||
The daemon owns all writes to `/etc/pam.d/`, `/etc/ubuntu-fido/`, and `/var/lib/ubuntu-fido/`. GUIs never write these directly. polkit policies decide who can call which method:
|
||||
The daemon owns all writes to `/etc/pam.d/`, `/etc/authforge/`, and `/var/lib/authforge/`. GUIs never write these directly. polkit policies decide who can call which method:
|
||||
|
||||
| D-Bus method | Default polkit action |
|
||||
|---|---|
|
||||
@@ -74,18 +74,18 @@ The daemon owns all writes to `/etc/pam.d/`, `/etc/ubuntu-fido/`, and `/var/lib/
|
||||
|
||||
| Package | Contents | Type |
|
||||
|---|---|---|
|
||||
| `ubuntu-fido` | Empty metapackage. | Depends |
|
||||
| `ubuntu-fido-daemon` | `/usr/sbin/ubuntu-fidod`, systemd unit (`ubuntu-fido.service`), D-Bus service file, polkit rules under `/usr/share/polkit-1/actions/` | Hard dep of metapackage |
|
||||
| `ubuntu-fido-pam` | `/usr/lib/$DEB_HOST_MULTIARCH/security/pam_ubuntu_fido_pending.so`, pam-auth-update profile at `/usr/share/pam-configs/ubuntu-fido` | Hard dep |
|
||||
| `ubuntu-fido-cli` | `/usr/bin/ubuntu-fidoctl` (Rust binary, talks D-Bus) | Hard dep |
|
||||
| `ubuntu-fido-gui` | `/usr/bin/ubuntu-fido` (GTK4/libadwaita), `.desktop` file with `Categories=Settings;Security;`, app icon | **Recommends** (so headless servers can skip) |
|
||||
| `ubuntu-fido-gnome-integration` | Tiny shim that adds a "Configure security…" launcher button to gnome-control-center's Users panel via overlay `.desktop` extension | **Suggests** (not auto-installed) |
|
||||
| `authforge` | Empty metapackage. | Depends |
|
||||
| `authforge-daemon` | `/usr/sbin/authforged`, systemd unit (`authforge.service`), D-Bus service file, polkit rules under `/usr/share/polkit-1/actions/` | Hard dep of metapackage |
|
||||
| `authforge-pam` | `/usr/lib/$DEB_HOST_MULTIARCH/security/pam_authforge_pending.so`, pam-auth-update profile at `/usr/share/pam-configs/authforge` | Hard dep |
|
||||
| `authforge-cli` | `/usr/bin/authforgectl` (Rust binary, talks D-Bus) | Hard dep |
|
||||
| `authforge-gui` | `/usr/bin/authforge` (GTK4/libadwaita), `.desktop` file with `Categories=Settings;Security;`, app icon | **Recommends** (so headless servers can skip) |
|
||||
| `authforge-gnome-integration` | Tiny shim that adds a "Configure security…" launcher button to gnome-control-center's Users panel via overlay `.desktop` extension | **Suggests** (not auto-installed) |
|
||||
|
||||
### Headline install
|
||||
|
||||
```bash
|
||||
sudo add-apt-repository ppa:dangerousthings/ubuntu-fido
|
||||
sudo apt install ubuntu-fido
|
||||
sudo add-apt-repository ppa:dangerousthings/authforge
|
||||
sudo apt install authforge
|
||||
```
|
||||
|
||||
Two commands. After install:
|
||||
@@ -97,20 +97,20 @@ Two commands. After install:
|
||||
### Headless / fleet install
|
||||
|
||||
```bash
|
||||
apt install ubuntu-fido-daemon ubuntu-fido-pam ubuntu-fido-cli
|
||||
apt install authforge-daemon authforge-pam authforge-cli
|
||||
```
|
||||
Skips the GUI metadata. Configure via `/etc/ubuntu-fido/policy.d/90-fleet.conf` or `ubuntu-fidoctl`. We additionally publish:
|
||||
Skips the GUI metadata. Configure via `/etc/authforge/policy.d/90-fleet.conf` or `authforgectl`. We additionally publish:
|
||||
|
||||
- An **Ansible role** `dangerousthings.ubuntu_fido` on Galaxy wrapping `apt + debconf + drop-in config`.
|
||||
- An **Ansible role** `dangerousthings.authforge` on Galaxy wrapping `apt + debconf + drop-in config`.
|
||||
- A **debconf preseed schema** so `debian-installer`/cloud-init can answer questions at install time.
|
||||
|
||||
### Clean uninstall
|
||||
|
||||
`apt purge ubuntu-fido*` runs `pam-auth-update --remove` (cleanly retracts our PAM hooks), stops and disables the systemd unit, removes `/etc/ubuntu-fido/` only on `purge` (not `remove`), and leaves `~/.config/Yubico/u2f_keys` files alone (so reinstall is painless).
|
||||
`apt purge authforge*` runs `pam-auth-update --remove` (cleanly retracts our PAM hooks), stops and disables the systemd unit, removes `/etc/authforge/` only on `purge` (not `remove`), and leaves `~/.config/Yubico/u2f_keys` files alone (so reinstall is painless).
|
||||
|
||||
## GUI design
|
||||
|
||||
### App: `ubuntu-fido`
|
||||
### App: `authforge`
|
||||
|
||||
GTK4 + libadwaita. Single-window adaptive layout, looks like a stock Settings panel. Top-level navigation via libadwaita `AdwViewStack`:
|
||||
|
||||
@@ -138,23 +138,23 @@ GTK4 + libadwaita. Single-window adaptive layout, looks like a stock Settings pa
|
||||
|
||||
### App: gnome-control-center Users panel shortcut
|
||||
|
||||
Optional `ubuntu-fido-gnome-integration` package ships an overlay file under `/usr/share/gnome-control-center/users/` (or whatever the current GNOME version uses) that adds an additional row labeled **"Authentication & Security Keys…"** to each user's detail view. Clicking launches `ubuntu-fido --user <username>` with elevated D-Bus permissions if the launching user is in `sudo`/`admin` group.
|
||||
Optional `authforge-gnome-integration` package ships an overlay file under `/usr/share/gnome-control-center/users/` (or whatever the current GNOME version uses) that adds an additional row labeled **"Authentication & Security Keys…"** to each user's detail view. Clicking launches `authforge --user <username>` with elevated D-Bus permissions if the launching user is in `sudo`/`admin` group.
|
||||
|
||||
The overlay is shipped separately precisely because gnome-control-center has no stable plugin API — this package may need re-tuning every GNOME release. If it ever breaks, the standalone app keeps working; only the discoverability shortcut is lost.
|
||||
|
||||
### Add User flow extension
|
||||
|
||||
When `ubuntu-fido-gnome-integration` is installed, the **gnome-control-center Users → Add User** dialog gains a new section: **Configure security**, with three radio options:
|
||||
When `authforge-gnome-integration` is installed, the **gnome-control-center Users → Add User** dialog gains a new section: **Configure security**, with three radio options:
|
||||
|
||||
1. **Enroll security credential now** — opens enrollment modal, admin must have the user's key/implant present. Sets a real password (admin-supplied).
|
||||
2. **Require user to set up at first login** — admin sets a temp password (or accepts a generated one). We run `chage -d 0 <user>` and create `/var/lib/ubuntu-fido/pending/<user>`.
|
||||
2. **Require user to set up at first login** — admin sets a temp password (or accepts a generated one). We run `chage -d 0 <user>` and create `/var/lib/authforge/pending/<user>`.
|
||||
3. **No MFA** — only available if local policy permits ("Required" stacks would block this option with a tooltip).
|
||||
|
||||
## Enrollment flows
|
||||
|
||||
### Flow A: User self-enrollment (the common case)
|
||||
|
||||
1. User opens `ubuntu-fido` from Activities.
|
||||
1. User opens `authforge` from Activities.
|
||||
2. Clicks "+ Add Security Key".
|
||||
3. Modal: "Plug in your key now or tap your NFC implant to a reader." Daemon polls `libfido2` for new device.
|
||||
4. Device detected → optional PIN/UV prompt for FIDO2 → daemon emits `pamu2fcfg`-equivalent registration line.
|
||||
@@ -178,49 +178,49 @@ polkit asks admin password.
|
||||
**At account creation (admin side):**
|
||||
1. Admin picks "Require user to set up at first login", enters/accepts temp password.
|
||||
2. Daemon runs `chage -d 0 <user>` (built-in Linux mechanism: forces password change at next login).
|
||||
3. Daemon writes flag file `/var/lib/ubuntu-fido/pending/<user>` containing JSON: `{"required_methods": ["fido2"], "created": "...", "deadline": null}`.
|
||||
3. Daemon writes flag file `/var/lib/authforge/pending/<user>` containing JSON: `{"required_methods": ["fido2"], "created": "...", "deadline": null}`.
|
||||
|
||||
**First login (user side):**
|
||||
1. User logs into GDM with temp password.
|
||||
2. PAM `passwd` module forces password change (existing Ubuntu behavior, no work for us).
|
||||
3. GNOME session starts.
|
||||
4. Our autostart entry `/etc/xdg/autostart/ubuntu-fido-firstrun.desktop` runs `ubuntu-fido --first-run`.
|
||||
4. Our autostart entry `/etc/xdg/autostart/authforge-firstrun.desktop` runs `authforge --first-run`.
|
||||
5. Detects pending flag, takes over the screen with a fullscreen modal: "Welcome. Before you continue, please enroll a security key."
|
||||
6. User enrolls (Flow A inside the modal).
|
||||
7. On success, daemon clears pending flag.
|
||||
8. Modal closes, user lands on a normal desktop.
|
||||
|
||||
**Backstop (the PAM module):**
|
||||
- If user kills `ubuntu-fido --first-run` and tries to do anything sudo/login-related, `pam_ubuntu_fido_pending.so` is in their auth stack; it sees the pending flag and denies auth with a friendly message: "Account setup incomplete. Please complete enrollment in the Authentication app."
|
||||
- A watchdog inside `ubuntu-fido --first-run` calls `gnome-session-quit --logout --no-prompt` after 60 seconds of inactivity in the modal.
|
||||
- If user kills `authforge --first-run` and tries to do anything sudo/login-related, `pam_authforge_pending.so` is in their auth stack; it sees the pending flag and denies auth with a friendly message: "Account setup incomplete. Please complete enrollment in the Authentication app."
|
||||
- A watchdog inside `authforge --first-run` calls `gnome-session-quit --logout --no-prompt` after 60 seconds of inactivity in the modal.
|
||||
|
||||
### Flow D: Lost key recovery
|
||||
|
||||
1. User can't authenticate.
|
||||
2. User contacts admin.
|
||||
3. Admin runs `ubuntu-fidoctl recovery generate <user>` (or clicks button in GUI). Outputs an 8-digit one-time code valid 24 h.
|
||||
4. User enters code at GDM password prompt — `pam_ubuntu_fido_pending.so` recognizes recovery code prefix, lets them through with a forced re-enrollment flag set.
|
||||
3. Admin runs `authforgectl recovery generate <user>` (or clicks button in GUI). Outputs an 8-digit one-time code valid 24 h.
|
||||
4. User enters code at GDM password prompt — `pam_authforge_pending.so` recognizes recovery code prefix, lets them through with a forced re-enrollment flag set.
|
||||
5. User logs in, immediately sees first-login-style modal forcing them to enroll a new key before doing anything else.
|
||||
|
||||
## PAM and policy details
|
||||
|
||||
### pam-auth-update profile
|
||||
|
||||
`/usr/share/pam-configs/ubuntu-fido`:
|
||||
`/usr/share/pam-configs/authforge`:
|
||||
|
||||
```
|
||||
Name: Dangerous Things ubuntu-fido MFA
|
||||
Name: Dangerous Things authforge MFA
|
||||
Default: no
|
||||
Priority: 192
|
||||
Auth-Type: Additional
|
||||
Auth:
|
||||
[success=ok default=1 ignore=ignore] pam_u2f.so cue authfile=/etc/u2f_mappings
|
||||
[success=ok default=die] pam_ubuntu_fido_pending.so
|
||||
[success=ok default=die] pam_authforge_pending.so
|
||||
```
|
||||
|
||||
Default `no` means the package install does not enable enforcement — admins / GUI explicitly turn it on per stack.
|
||||
|
||||
### Policy file format (`/etc/ubuntu-fido/policy.d/*.conf`)
|
||||
### Policy file format (`/etc/authforge/policy.d/*.conf`)
|
||||
|
||||
TOML, parsed in lexical order, last-key-wins:
|
||||
|
||||
@@ -252,7 +252,7 @@ Daemon reloads on `SIGHUP` or when a watched file changes (uses `inotify`).
|
||||
|
||||
Before applying any policy change, daemon simulates the new policy against:
|
||||
- The currently logged-in interactive user (resolved via `loginctl`).
|
||||
- Every user listed in `/var/lib/ubuntu-fido/users.db` (cached enrollment registry).
|
||||
- Every user listed in `/var/lib/authforge/users.db` (cached enrollment registry).
|
||||
|
||||
For each user, it runs the new policy through a dry-run PAM check. If the result would deny login *without* a way to recover (no enrolled credentials of any required method), the daemon refuses the change and returns an actionable error: "Applying this policy would lock out user `alice` from `gdm-password` (no fido2 credentials enrolled). Enroll a credential for alice or set this stack to 'optional'."
|
||||
|
||||
@@ -283,7 +283,7 @@ The architecture is designed so each step here is additive — no refactor of v1
|
||||
|---|---|---|
|
||||
| **v1.0** | Ubuntu LTS + GNOME, U2F + FIDO2 passkey + TOTP. | Reference. |
|
||||
| **v1.1** | Debian stable packaging (same source, second build target). | ~2 weeks. |
|
||||
| **v1.2** | KDE Plasma front-end as a KCM module (`kcm_ubuntu_fido`). Reuses the same daemon over D-Bus. Built with KF6/Qt6. | ~6–8 weeks (mostly Qt port of GUI). |
|
||||
| **v1.2** | KDE Plasma front-end as a KCM module (`kcm_authforge`). Reuses the same daemon over D-Bus. Built with KF6/Qt6. | ~6–8 weeks (mostly Qt port of GUI). |
|
||||
| **v1.3** | Fedora/RHEL spec file. PAM module and daemon already work; needs `.rpm` packaging and SELinux policy. GNOME GUI works as-is. | ~3–4 weeks. |
|
||||
| **v2.0** | Optional: organization-wide credential sync via FreeIPA / LDAP integration. Pure backend feature. | Out of scope for now. |
|
||||
|
||||
@@ -307,4 +307,4 @@ The architecture is designed so each step here is additive — no refactor of v1
|
||||
|
||||
---
|
||||
|
||||
*This design was developed via guided brainstorming on 2026-04-26. The next artifact is a detailed implementation plan in `2026-04-26-ubuntu-fido-implementation-plan.md`.*
|
||||
*This design was developed via guided brainstorming on 2026-04-26. The next artifact is a detailed implementation plan in `2026-04-26-authforge-implementation-plan.md`.*
|
||||
@@ -1,16 +1,16 @@
|
||||
# ubuntu-fido Implementation Plan
|
||||
# authforge Implementation Plan
|
||||
|
||||
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
|
||||
>
|
||||
> **Note on plan structure:** This is a multi-month project. Phase 0 is fully detailed at step granularity. Phases 1–18 are specified with goals, deliverables, file targets, and task lists at sufficient detail to begin implementation. Each subsequent phase should re-invoke `superpowers:writing-plans` to expand its tasks to step-level granularity at the moment that phase begins (state from prior phases informs the expansion).
|
||||
|
||||
**Goal:** Ship `ubuntu-fido` as an apt package on a PPA that turns U2F / FIDO2 passkey / TOTP MFA on Ubuntu desktops into a two-command install with a polished libadwaita GUI, sane policy, and a first-login enrollment flow.
|
||||
**Goal:** Ship `authforge` as an apt package on a PPA that turns U2F / FIDO2 passkey / TOTP MFA on Ubuntu desktops into a two-command install with a polished libadwaita GUI, sane policy, and a first-login enrollment flow.
|
||||
|
||||
**Architecture:** Rust system daemon (`ubuntu-fidod`) exposes a D-Bus interface. A GTK4 / libadwaita app and a CLI are thin clients. A small C PAM module (`pam_ubuntu_fido_pending.so`) backstops first-login enrollment. PAM stack edits go through `pam-auth-update`. Policy is drop-in TOML in `/etc/ubuntu-fido/policy.d/`. Full design in `docs/plans/2026-04-26-ubuntu-fido-design.md`.
|
||||
**Architecture:** Rust system daemon (`authforged`) exposes a D-Bus interface. A GTK4 / libadwaita app and a CLI are thin clients. A small C PAM module (`pam_authforge_pending.so`) backstops first-login enrollment. PAM stack edits go through `pam-auth-update`. Policy is drop-in TOML in `/etc/authforge/policy.d/`. Full design in `docs/plans/2026-04-26-authforge-design.md`.
|
||||
|
||||
**Tech Stack:** Rust 2021 edition (daemon, CLI), GTK4 + libadwaita via `gtk4-rs` and `libadwaita-rs` (GUI), C (PAM module), `libfido2` via `ctap-hid-fido2` crate, D-Bus via `zbus`, polkit, debhelper-compat 13 packaging, sbuild for clean builds, GitHub Actions CI, Launchpad PPA for distribution.
|
||||
|
||||
**Reference design:** [docs/plans/2026-04-26-ubuntu-fido-design.md](2026-04-26-ubuntu-fido-design.md)
|
||||
**Reference design:** [docs/plans/2026-04-26-authforge-design.md](2026-04-26-authforge-design.md)
|
||||
|
||||
---
|
||||
|
||||
@@ -24,8 +24,8 @@
|
||||
| 3 | Daemon: FIDO2 enrollment backend via `ctap-hid-fido2` | 5–7 days | Spec'd |
|
||||
| 4 | Daemon: policy apply via pam-auth-update wrapper | 4 days | Spec'd |
|
||||
| 5 | Daemon: lockout simulator | 3 days | Spec'd |
|
||||
| 6 | PAM module: `pam_ubuntu_fido_pending.so` (C) | 3 days | Spec'd |
|
||||
| 7 | CLI: `ubuntu-fidoctl` | 4 days | Spec'd |
|
||||
| 6 | PAM module: `pam_authforge_pending.so` (C) | 3 days | Spec'd |
|
||||
| 7 | CLI: `authforgectl` | 4 days | Spec'd |
|
||||
| 8 | GUI: app shell + Security Keys tab | 6–8 days | Spec'd |
|
||||
| 9 | GUI: Policy tab + lockout-warning UX | 4 days | Spec'd |
|
||||
| 10 | First-login flow: autostart entry + fullscreen modal | 4 days | Spec'd |
|
||||
@@ -33,8 +33,8 @@
|
||||
| 12 | Recovery flow (codes + emergency unlock) | 4 days | Spec'd |
|
||||
| 13 | Debian packaging finalization (postinst, debconf, purge) | 4 days | Spec'd |
|
||||
| 14 | Launchpad PPA build setup | 2 days | Spec'd |
|
||||
| 15 | `ubuntu-fido-gnome-integration` (Users panel shortcut) | 3 days | Spec'd |
|
||||
| 16 | Ansible role `dangerousthings.ubuntu_fido` | 2 days | Spec'd |
|
||||
| 15 | `authforge-gnome-integration` (Users panel shortcut) | 3 days | Spec'd |
|
||||
| 16 | Ansible role `dangerousthings.authforge` | 2 days | Spec'd |
|
||||
| 17 | Integration test harness (Multipass / LXD VM) | 4 days | Spec'd |
|
||||
| 18 | User docs + onboarding site | 3 days | Spec'd |
|
||||
| **R** | **v1.0 release** | 1 day | — |
|
||||
@@ -82,7 +82,7 @@ debian/.debhelper/
|
||||
debian/files
|
||||
debian/*.substvars
|
||||
debian/*.debhelper.log
|
||||
debian/ubuntu-fido*/
|
||||
debian/authforge*/
|
||||
build/
|
||||
.vscode/
|
||||
*.swp
|
||||
@@ -93,14 +93,14 @@ build/
|
||||
**Step 4:** Write minimal `README.md`:
|
||||
|
||||
```markdown
|
||||
# ubuntu-fido
|
||||
# authforge
|
||||
|
||||
Turnkey U2F / FIDO2 passkey / TOTP MFA for Ubuntu desktops.
|
||||
|
||||
## Install (end users)
|
||||
|
||||
sudo add-apt-repository ppa:dangerousthings/ubuntu-fido
|
||||
sudo apt install ubuntu-fido
|
||||
sudo add-apt-repository ppa:dangerousthings/authforge
|
||||
sudo apt install authforge
|
||||
|
||||
## Build from source
|
||||
|
||||
@@ -137,7 +137,7 @@ version = "0.1.0"
|
||||
edition = "2021"
|
||||
license = "Apache-2.0"
|
||||
authors = ["Dangerous Things <ops@dangerousthings.com>"]
|
||||
repository = "https://github.com/dangerousthings/ubuntu-fido"
|
||||
repository = "https://github.com/dangerousthings/authforge"
|
||||
rust-version = "1.78"
|
||||
|
||||
[workspace.dependencies]
|
||||
@@ -185,7 +185,7 @@ rustflags = ["-D", "warnings"]
|
||||
|
||||
```toml
|
||||
[package]
|
||||
name = "ubuntu-fido-common"
|
||||
name = "authforge-common"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
@@ -248,7 +248,7 @@ mod tests {
|
||||
|
||||
This needs `serde_json` as a dev-dep; add `[dev-dependencies] serde_json = { workspace = true }` to `common/Cargo.toml`.
|
||||
|
||||
**Step 6:** Run `cargo test -p ubuntu-fido-common`. Expected: PASS.
|
||||
**Step 6:** Run `cargo test -p authforge-common`. Expected: PASS.
|
||||
|
||||
**Step 7:** Commit.
|
||||
|
||||
@@ -267,17 +267,17 @@ git commit -m "Add common crate with shared Mode and Method types"
|
||||
|
||||
```toml
|
||||
[package]
|
||||
name = "ubuntu-fidod"
|
||||
name = "authforged"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
||||
[[bin]]
|
||||
name = "ubuntu-fidod"
|
||||
name = "authforged"
|
||||
path = "src/main.rs"
|
||||
|
||||
[dependencies]
|
||||
ubuntu-fido-common = { path = "../common" }
|
||||
authforge-common = { path = "../common" }
|
||||
zbus = { workspace = true }
|
||||
tokio = { workspace = true }
|
||||
tracing = { workspace = true }
|
||||
@@ -296,13 +296,13 @@ async fn main() -> Result<()> {
|
||||
tracing_subscriber::fmt()
|
||||
.with_env_filter(tracing_subscriber::EnvFilter::from_default_env())
|
||||
.init();
|
||||
info!("ubuntu-fidod {} starting", env!("CARGO_PKG_VERSION"));
|
||||
info!("authforged {} starting", env!("CARGO_PKG_VERSION"));
|
||||
// D-Bus service registration in Phase 1.
|
||||
Ok(())
|
||||
}
|
||||
```
|
||||
|
||||
**Step 3:** `cargo build -p ubuntu-fidod`. Expected: success.
|
||||
**Step 3:** `cargo build -p authforged`. Expected: success.
|
||||
|
||||
**Step 4:** Commit.
|
||||
|
||||
@@ -321,17 +321,17 @@ git commit -m "Add daemon crate skeleton"
|
||||
|
||||
```toml
|
||||
[package]
|
||||
name = "ubuntu-fidoctl"
|
||||
name = "authforgectl"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
||||
[[bin]]
|
||||
name = "ubuntu-fidoctl"
|
||||
name = "authforgectl"
|
||||
path = "src/main.rs"
|
||||
|
||||
[dependencies]
|
||||
ubuntu-fido-common = { path = "../common" }
|
||||
authforge-common = { path = "../common" }
|
||||
clap = { workspace = true }
|
||||
anyhow = { workspace = true }
|
||||
zbus = { workspace = true }
|
||||
@@ -345,7 +345,7 @@ use anyhow::Result;
|
||||
use clap::Parser;
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(name = "ubuntu-fidoctl", version, about = "Manage ubuntu-fido configuration")]
|
||||
#[command(name = "authforgectl", version, about = "Manage authforge configuration")]
|
||||
struct Cli {
|
||||
#[command(subcommand)]
|
||||
cmd: Cmd,
|
||||
@@ -360,7 +360,7 @@ enum Cmd {
|
||||
async fn main() -> Result<()> {
|
||||
let args = Cli::parse();
|
||||
match args.cmd {
|
||||
Cmd::Status => println!("ubuntu-fidoctl: not yet implemented"),
|
||||
Cmd::Status => println!("authforgectl: not yet implemented"),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -379,9 +379,9 @@ git commit -m "Add cli crate skeleton"
|
||||
|
||||
**Files:**
|
||||
- Create: `pam/Makefile`
|
||||
- Create: `pam/pam_ubuntu_fido_pending.c`
|
||||
- Create: `pam/pam_authforge_pending.c`
|
||||
|
||||
**Step 1:** `pam/pam_ubuntu_fido_pending.c`:
|
||||
**Step 1:** `pam/pam_authforge_pending.c`:
|
||||
|
||||
```c
|
||||
#define PAM_SM_AUTH
|
||||
@@ -392,7 +392,7 @@ git commit -m "Add cli crate skeleton"
|
||||
PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags,
|
||||
int argc, const char **argv) {
|
||||
(void)flags; (void)argc; (void)argv;
|
||||
pam_syslog(pamh, LOG_INFO, "ubuntu_fido_pending: stub - allowing");
|
||||
pam_syslog(pamh, LOG_INFO, "authforge_pending: stub - allowing");
|
||||
return PAM_IGNORE; /* implemented in Phase 6 */
|
||||
}
|
||||
|
||||
@@ -409,14 +409,14 @@ PAM_EXTERN int pam_sm_setcred(pam_handle_t *pamh, int flags,
|
||||
CFLAGS ?= -Wall -Wextra -Werror -fPIC -O2
|
||||
LIBDIR ?= /usr/lib/$(shell dpkg-architecture -qDEB_HOST_MULTIARCH)/security
|
||||
|
||||
pam_ubuntu_fido_pending.so: pam_ubuntu_fido_pending.c
|
||||
pam_authforge_pending.so: pam_authforge_pending.c
|
||||
$(CC) $(CFLAGS) -shared -o $@ $< -lpam
|
||||
|
||||
install: pam_ubuntu_fido_pending.so
|
||||
install -D -m 0644 pam_ubuntu_fido_pending.so $(DESTDIR)$(LIBDIR)/pam_ubuntu_fido_pending.so
|
||||
install: pam_authforge_pending.so
|
||||
install -D -m 0644 pam_authforge_pending.so $(DESTDIR)$(LIBDIR)/pam_authforge_pending.so
|
||||
|
||||
clean:
|
||||
rm -f pam_ubuntu_fido_pending.so
|
||||
rm -f pam_authforge_pending.so
|
||||
|
||||
.PHONY: install clean
|
||||
```
|
||||
@@ -427,7 +427,7 @@ clean:
|
||||
cd pam && make && cd ..
|
||||
```
|
||||
|
||||
Expected: produces `pam/pam_ubuntu_fido_pending.so` (~10 KB). Requires `libpam0g-dev` (will be in build-deps).
|
||||
Expected: produces `pam/pam_authforge_pending.so` (~10 KB). Requires `libpam0g-dev` (will be in build-deps).
|
||||
|
||||
**Step 4:** Commit.
|
||||
|
||||
@@ -441,8 +441,8 @@ git commit -m "Add PAM module stub"
|
||||
**Files:**
|
||||
- Create: `gui/Cargo.toml`
|
||||
- Create: `gui/src/main.rs`
|
||||
- Create: `gui/data/io.dangerousthings.UbuntuFido.desktop`
|
||||
- Create: `gui/data/io.dangerousthings.UbuntuFido.svg` (1KB placeholder icon)
|
||||
- Create: `gui/data/io.dangerousthings.AuthForge.desktop`
|
||||
- Create: `gui/data/io.dangerousthings.AuthForge.svg` (1KB placeholder icon)
|
||||
|
||||
**Step 1:** Add `gui` to workspace members in root `Cargo.toml`.
|
||||
|
||||
@@ -450,19 +450,19 @@ git commit -m "Add PAM module stub"
|
||||
|
||||
```toml
|
||||
[package]
|
||||
name = "ubuntu-fido-gui"
|
||||
name = "authforge-gui"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
||||
[[bin]]
|
||||
name = "ubuntu-fido"
|
||||
name = "authforge"
|
||||
path = "src/main.rs"
|
||||
|
||||
[dependencies]
|
||||
gtk = { package = "gtk4", version = "0.8" }
|
||||
adw = { package = "libadwaita", version = "0.6" }
|
||||
ubuntu-fido-common = { path = "../common" }
|
||||
authforge-common = { path = "../common" }
|
||||
anyhow = { workspace = true }
|
||||
```
|
||||
|
||||
@@ -472,7 +472,7 @@ anyhow = { workspace = true }
|
||||
use adw::prelude::*;
|
||||
use gtk::glib;
|
||||
|
||||
const APP_ID: &str = "io.dangerousthings.UbuntuFido";
|
||||
const APP_ID: &str = "io.dangerousthings.AuthForge";
|
||||
|
||||
fn main() -> glib::ExitCode {
|
||||
let app = adw::Application::builder().application_id(APP_ID).build();
|
||||
@@ -499,15 +499,15 @@ fn main() -> glib::ExitCode {
|
||||
}
|
||||
```
|
||||
|
||||
**Step 4:** `.desktop` file at `gui/data/io.dangerousthings.UbuntuFido.desktop`:
|
||||
**Step 4:** `.desktop` file at `gui/data/io.dangerousthings.AuthForge.desktop`:
|
||||
|
||||
```desktop
|
||||
[Desktop Entry]
|
||||
Name=Authentication
|
||||
GenericName=Security Keys & MFA
|
||||
Comment=Manage U2F/FIDO2 keys and authentication policy
|
||||
Exec=ubuntu-fido
|
||||
Icon=io.dangerousthings.UbuntuFido
|
||||
Exec=authforge
|
||||
Icon=io.dangerousthings.AuthForge
|
||||
Terminal=false
|
||||
Type=Application
|
||||
Categories=Settings;Security;
|
||||
@@ -515,12 +515,12 @@ Keywords=mfa;u2f;fido2;passkey;totp;security;
|
||||
StartupNotify=true
|
||||
```
|
||||
|
||||
**Step 5:** Placeholder SVG icon — a simple gray key glyph; sourced from any open icon set under a compatible license. Save at `gui/data/io.dangerousthings.UbuntuFido.svg`.
|
||||
**Step 5:** Placeholder SVG icon — a simple gray key glyph; sourced from any open icon set under a compatible license. Save at `gui/data/io.dangerousthings.AuthForge.svg`.
|
||||
|
||||
**Step 6:** Build (assumes GTK4 / libadwaita dev packages installed: `libgtk-4-dev`, `libadwaita-1-dev`).
|
||||
|
||||
```bash
|
||||
cargo build -p ubuntu-fido-gui
|
||||
cargo build -p authforge-gui
|
||||
```
|
||||
|
||||
Expected: success.
|
||||
@@ -541,17 +541,17 @@ git commit -m "Add GUI crate skeleton with libadwaita placeholder window"
|
||||
- Create: `debian/rules`
|
||||
- Create: `debian/source/format`
|
||||
- Create: `debian/compat` (or use `debhelper-compat (= 13)` in control)
|
||||
- Create: `debian/ubuntu-fido.install`
|
||||
- Create: `debian/ubuntu-fido-daemon.install`
|
||||
- Create: `debian/ubuntu-fido-daemon.service`
|
||||
- Create: `debian/ubuntu-fido-pam.install`
|
||||
- Create: `debian/ubuntu-fido-cli.install`
|
||||
- Create: `debian/ubuntu-fido-gui.install`
|
||||
- Create: `debian/authforge.install`
|
||||
- Create: `debian/authforge-daemon.install`
|
||||
- Create: `debian/authforge-daemon.service`
|
||||
- Create: `debian/authforge-pam.install`
|
||||
- Create: `debian/authforge-cli.install`
|
||||
- Create: `debian/authforge-gui.install`
|
||||
|
||||
**Step 1:** `debian/changelog`:
|
||||
|
||||
```
|
||||
ubuntu-fido (0.1.0-1) UNRELEASED; urgency=low
|
||||
authforge (0.1.0-1) UNRELEASED; urgency=low
|
||||
|
||||
* Initial packaging skeleton.
|
||||
|
||||
@@ -567,7 +567,7 @@ ubuntu-fido (0.1.0-1) UNRELEASED; urgency=low
|
||||
**Step 3:** `debian/control` — declares all 5 binary packages and their relationships:
|
||||
|
||||
```
|
||||
Source: ubuntu-fido
|
||||
Source: authforge
|
||||
Section: admin
|
||||
Priority: optional
|
||||
Maintainer: Dangerous Things <ops@dangerousthings.com>
|
||||
@@ -581,46 +581,46 @@ Build-Depends:
|
||||
libfido2-dev,
|
||||
pkg-config
|
||||
Standards-Version: 4.6.2
|
||||
Homepage: https://github.com/dangerousthings/ubuntu-fido
|
||||
Vcs-Browser: https://github.com/dangerousthings/ubuntu-fido
|
||||
Vcs-Git: https://github.com/dangerousthings/ubuntu-fido.git
|
||||
Homepage: https://github.com/dangerousthings/authforge
|
||||
Vcs-Browser: https://github.com/dangerousthings/authforge
|
||||
Vcs-Git: https://github.com/dangerousthings/authforge.git
|
||||
|
||||
Package: ubuntu-fido
|
||||
Package: authforge
|
||||
Architecture: any
|
||||
Depends: ubuntu-fido-daemon (= ${binary:Version}),
|
||||
ubuntu-fido-pam (= ${binary:Version}),
|
||||
ubuntu-fido-cli (= ${binary:Version}),
|
||||
Depends: authforge-daemon (= ${binary:Version}),
|
||||
authforge-pam (= ${binary:Version}),
|
||||
authforge-cli (= ${binary:Version}),
|
||||
${misc:Depends}
|
||||
Recommends: ubuntu-fido-gui (= ${binary:Version})
|
||||
Suggests: ubuntu-fido-gnome-integration
|
||||
Recommends: authforge-gui (= ${binary:Version})
|
||||
Suggests: authforge-gnome-integration
|
||||
Description: Turnkey FIDO2/U2F/TOTP MFA for Ubuntu (metapackage)
|
||||
Installs the full ubuntu-fido stack: daemon, PAM module, CLI, and
|
||||
Installs the full authforge stack: daemon, PAM module, CLI, and
|
||||
(if recommended) GUI.
|
||||
|
||||
Package: ubuntu-fido-daemon
|
||||
Package: authforge-daemon
|
||||
Architecture: any
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}, libpam-u2f, libfido2-1
|
||||
Description: System daemon for ubuntu-fido MFA management
|
||||
Description: System daemon for authforge MFA management
|
||||
Provides the privileged D-Bus service that orchestrates enrollment,
|
||||
policy edits, and lockout-prevention checks.
|
||||
|
||||
Package: ubuntu-fido-pam
|
||||
Package: authforge-pam
|
||||
Architecture: any
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}, libpam-runtime
|
||||
Description: PAM module backstopping ubuntu-fido first-login enrollment
|
||||
Refuses authentication when /var/lib/ubuntu-fido/pending/<user> exists
|
||||
Description: PAM module backstopping authforge first-login enrollment
|
||||
Refuses authentication when /var/lib/authforge/pending/<user> exists
|
||||
and the user has not completed first-login MFA setup.
|
||||
|
||||
Package: ubuntu-fido-cli
|
||||
Package: authforge-cli
|
||||
Architecture: any
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}, ubuntu-fido-daemon
|
||||
Description: CLI for ubuntu-fido (admin and fleet)
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}, authforge-daemon
|
||||
Description: CLI for authforge (admin and fleet)
|
||||
Configure policy, enroll on behalf of users, generate recovery codes.
|
||||
|
||||
Package: ubuntu-fido-gui
|
||||
Package: authforge-gui
|
||||
Architecture: any
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}, ubuntu-fido-daemon
|
||||
Description: GTK4/libadwaita UI for ubuntu-fido
|
||||
Depends: ${shlibs:Depends}, ${misc:Depends}, authforge-daemon
|
||||
Description: GTK4/libadwaita UI for authforge
|
||||
End-user-facing settings panel for enrollment and policy.
|
||||
```
|
||||
|
||||
@@ -640,20 +640,20 @@ override_dh_auto_build:
|
||||
|
||||
override_dh_auto_install:
|
||||
# Daemon
|
||||
install -D -m 0755 target/release/ubuntu-fidod \
|
||||
debian/ubuntu-fido-daemon/usr/sbin/ubuntu-fidod
|
||||
install -D -m 0755 target/release/authforged \
|
||||
debian/authforge-daemon/usr/sbin/authforged
|
||||
# CLI
|
||||
install -D -m 0755 target/release/ubuntu-fidoctl \
|
||||
debian/ubuntu-fido-cli/usr/bin/ubuntu-fidoctl
|
||||
install -D -m 0755 target/release/authforgectl \
|
||||
debian/authforge-cli/usr/bin/authforgectl
|
||||
# GUI
|
||||
install -D -m 0755 target/release/ubuntu-fido \
|
||||
debian/ubuntu-fido-gui/usr/bin/ubuntu-fido
|
||||
install -D -m 0644 gui/data/io.dangerousthings.UbuntuFido.desktop \
|
||||
debian/ubuntu-fido-gui/usr/share/applications/io.dangerousthings.UbuntuFido.desktop
|
||||
install -D -m 0644 gui/data/io.dangerousthings.UbuntuFido.svg \
|
||||
debian/ubuntu-fido-gui/usr/share/icons/hicolor/scalable/apps/io.dangerousthings.UbuntuFido.svg
|
||||
install -D -m 0755 target/release/authforge \
|
||||
debian/authforge-gui/usr/bin/authforge
|
||||
install -D -m 0644 gui/data/io.dangerousthings.AuthForge.desktop \
|
||||
debian/authforge-gui/usr/share/applications/io.dangerousthings.AuthForge.desktop
|
||||
install -D -m 0644 gui/data/io.dangerousthings.AuthForge.svg \
|
||||
debian/authforge-gui/usr/share/icons/hicolor/scalable/apps/io.dangerousthings.AuthForge.svg
|
||||
# PAM
|
||||
$(MAKE) -C pam install DESTDIR=$(CURDIR)/debian/ubuntu-fido-pam
|
||||
$(MAKE) -C pam install DESTDIR=$(CURDIR)/debian/authforge-pam
|
||||
|
||||
override_dh_auto_test:
|
||||
cargo test --workspace --release
|
||||
@@ -680,9 +680,9 @@ Expected: produces 5 `.deb` files in the parent directory. Lintian may complain
|
||||
**Step 8:** Verify install + remove on a throwaway VM (Multipass shell or LXD container).
|
||||
|
||||
```bash
|
||||
sudo dpkg -i ../ubuntu-fido*.deb || sudo apt -f install
|
||||
sudo systemctl status ubuntu-fido.service # will fail until Phase 1 ships unit
|
||||
sudo apt purge ubuntu-fido*
|
||||
sudo dpkg -i ../authforge*.deb || sudo apt -f install
|
||||
sudo systemctl status authforge.service # will fail until Phase 1 ships unit
|
||||
sudo apt purge authforge*
|
||||
```
|
||||
|
||||
**Step 9:** Commit.
|
||||
@@ -721,7 +721,7 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
- run: sudo apt-get update && sudo apt-get install -y debhelper devscripts lintian libpam0g-dev libgtk-4-dev libadwaita-1-dev libfido2-dev pkg-config cargo rustc
|
||||
- run: debuild -us -uc -b
|
||||
- run: lintian --info --display-info ../ubuntu-fido*.changes || true # warnings allowed in Phase 0
|
||||
- run: lintian --info --display-info ../authforge*.changes || true # warnings allowed in Phase 0
|
||||
```
|
||||
|
||||
**Step 2:** Push and verify both jobs go green.
|
||||
@@ -740,9 +740,9 @@ Verify all of the following before declaring Phase 0 complete:
|
||||
- [ ] `cargo build --workspace --release` succeeds.
|
||||
- [ ] `cargo test --workspace` succeeds (1 test in `common`).
|
||||
- [ ] `cargo clippy --workspace -- -D warnings` is clean.
|
||||
- [ ] `make -C pam` produces `pam_ubuntu_fido_pending.so`.
|
||||
- [ ] `make -C pam` produces `pam_authforge_pending.so`.
|
||||
- [ ] `debuild -us -uc -b` produces 5 `.deb` files.
|
||||
- [ ] On an Ubuntu 24.04 LXD container: `sudo dpkg -i ../ubuntu-fido*.deb` succeeds, `sudo apt purge ubuntu-fido*` cleanly removes.
|
||||
- [ ] On an Ubuntu 24.04 LXD container: `sudo dpkg -i ../authforge*.deb` succeeds, `sudo apt purge authforge*` cleanly removes.
|
||||
- [ ] CI is green on `main`.
|
||||
|
||||
If all check, tag `v0.1.0-scaffolding`:
|
||||
@@ -755,24 +755,24 @@ git tag -a v0.1.0-scaffolding -m "Phase 0: repository scaffolding complete"
|
||||
|
||||
# Phase 1: Daemon — D-Bus Interface, systemd, polkit
|
||||
|
||||
**Goal:** `ubuntu-fidod` registers on the system bus as `io.dangerousthings.UbuntuFido`, gets started by systemd, and enforces polkit-mediated method-level authorization. Methods are stubs returning sensible test data.
|
||||
**Goal:** `authforged` registers on the system bus as `io.dangerousthings.AuthForge`, gets started by systemd, and enforces polkit-mediated method-level authorization. Methods are stubs returning sensible test data.
|
||||
|
||||
**Re-invoke `superpowers:writing-plans` at start of this phase to expand to step granularity.**
|
||||
|
||||
**Files to create:**
|
||||
- `daemon/src/dbus.rs` — zbus `interface` definition
|
||||
- `daemon/src/state.rs` — in-memory state shell
|
||||
- `debian/ubuntu-fido-daemon.service` — systemd unit
|
||||
- `debian/io.dangerousthings.UbuntuFido.conf` — D-Bus policy
|
||||
- `debian/io.dangerousthings.UbuntuFido.service` — D-Bus activation file
|
||||
- `debian/io.dangerousthings.UbuntuFido.policy` — polkit actions
|
||||
- `debian/ubuntu-fido-daemon.postinst` — enable + start unit
|
||||
- `debian/authforge-daemon.service` — systemd unit
|
||||
- `debian/io.dangerousthings.AuthForge.conf` — D-Bus policy
|
||||
- `debian/io.dangerousthings.AuthForge.service` — D-Bus activation file
|
||||
- `debian/io.dangerousthings.AuthForge.policy` — polkit actions
|
||||
- `debian/authforge-daemon.postinst` — enable + start unit
|
||||
|
||||
**D-Bus interface skeleton:**
|
||||
|
||||
```rust
|
||||
#[zbus::interface(name = "io.dangerousthings.UbuntuFido1")]
|
||||
impl UbuntuFido {
|
||||
#[zbus::interface(name = "io.dangerousthings.AuthForge1")]
|
||||
impl AuthForge {
|
||||
async fn list_credentials(&self, user: String) -> zbus::fdo::Result<Vec<Credential>> { ... }
|
||||
async fn enroll_own(&self, user: String, nickname: String) -> zbus::fdo::Result<Credential> { ... }
|
||||
async fn remove_own(&self, user: String, cred_id: String) -> zbus::fdo::Result<()> { ... }
|
||||
@@ -785,26 +785,26 @@ impl UbuntuFido {
|
||||
}
|
||||
```
|
||||
|
||||
**polkit actions** (XML in `io.dangerousthings.UbuntuFido.policy`):
|
||||
**polkit actions** (XML in `io.dangerousthings.AuthForge.policy`):
|
||||
|
||||
| Action | Default for active session |
|
||||
|---|---|
|
||||
| `io.dangerousthings.UbuntuFido.enroll-own` | `auth_self_keep` |
|
||||
| `io.dangerousthings.UbuntuFido.remove-own` | `auth_self_keep` |
|
||||
| `io.dangerousthings.UbuntuFido.enroll-other` | `auth_admin_keep` |
|
||||
| `io.dangerousthings.UbuntuFido.set-policy` | `auth_admin_keep` |
|
||||
| `io.dangerousthings.UbuntuFido.set-pending` | `auth_admin_keep` |
|
||||
| `io.dangerousthings.UbuntuFido.clear-pending` | `auth_admin_keep` |
|
||||
| `io.dangerousthings.UbuntuFido.generate-recovery` | `auth_admin_keep` |
|
||||
| `io.dangerousthings.AuthForge.enroll-own` | `auth_self_keep` |
|
||||
| `io.dangerousthings.AuthForge.remove-own` | `auth_self_keep` |
|
||||
| `io.dangerousthings.AuthForge.enroll-other` | `auth_admin_keep` |
|
||||
| `io.dangerousthings.AuthForge.set-policy` | `auth_admin_keep` |
|
||||
| `io.dangerousthings.AuthForge.set-pending` | `auth_admin_keep` |
|
||||
| `io.dangerousthings.AuthForge.clear-pending` | `auth_admin_keep` |
|
||||
| `io.dangerousthings.AuthForge.generate-recovery` | `auth_admin_keep` |
|
||||
|
||||
**Tasks:**
|
||||
1. Add zbus interface module with stubs returning fixture data.
|
||||
2. Wire up `connection.request_name("io.dangerousthings.UbuntuFido")`.
|
||||
3. Write systemd unit (`Type=dbus`, `BusName=io.dangerousthings.UbuntuFido`, `User=root`).
|
||||
2. Wire up `connection.request_name("io.dangerousthings.AuthForge")`.
|
||||
3. Write systemd unit (`Type=dbus`, `BusName=io.dangerousthings.AuthForge`, `User=root`).
|
||||
4. Write D-Bus system policy (allow root to own; allow `at_console` to call read methods; restrict write methods).
|
||||
5. Write polkit policy XML; daemon checks each method against polkit before executing.
|
||||
6. Wire postinst: `systemctl daemon-reload && systemctl enable --now ubuntu-fido.service`.
|
||||
7. Test: `busctl call io.dangerousthings.UbuntuFido /io/dangerousthings/UbuntuFido io.dangerousthings.UbuntuFido1 ListCredentials s "$USER"` returns the fixture data.
|
||||
6. Wire postinst: `systemctl daemon-reload && systemctl enable --now authforge.service`.
|
||||
7. Test: `busctl call io.dangerousthings.AuthForge /io/dangerousthings/AuthForge io.dangerousthings.AuthForge1 ListCredentials s "$USER"` returns the fixture data.
|
||||
8. Test: as non-root, `SetPolicy` triggers polkit prompt.
|
||||
|
||||
**Acceptance:** D-Bus introspection works (`busctl introspect ...`), all 9 methods are callable as stubs, polkit prompts appear at correct times.
|
||||
@@ -813,14 +813,14 @@ impl UbuntuFido {
|
||||
|
||||
# Phase 2: Daemon — Storage Layer
|
||||
|
||||
**Goal:** Real I/O to `/etc/ubuntu-fido/policy.d/`, `/var/lib/ubuntu-fido/pending/`, and `~/.config/Yubico/u2f_keys` (or `/etc/u2f_mappings`). Replaces fixtures from Phase 1.
|
||||
**Goal:** Real I/O to `/etc/authforge/policy.d/`, `/var/lib/authforge/pending/`, and `~/.config/Yubico/u2f_keys` (or `/etc/u2f_mappings`). Replaces fixtures from Phase 1.
|
||||
|
||||
**Files:**
|
||||
- `common/src/policy.rs` — fully implemented TOML parser with last-key-wins merge
|
||||
- `daemon/src/storage/policy.rs` — read/write policy.d/ dir, inotify watcher
|
||||
- `daemon/src/storage/pending.rs` — read/write pending flags
|
||||
- `daemon/src/storage/credentials.rs` — manipulate u2f_keys files (per-user vs central)
|
||||
- `daemon/src/storage/userdb.rs` — `/var/lib/ubuntu-fido/users.db` cache (sqlite via `rusqlite`)
|
||||
- `daemon/src/storage/userdb.rs` — `/var/lib/authforge/users.db` cache (sqlite via `rusqlite`)
|
||||
|
||||
**Tasks:**
|
||||
1. Implement `Policy::load_from_dir(path)` with merge semantics. TDD: write 3 test fixture dirs, assert merge order.
|
||||
@@ -864,10 +864,10 @@ impl UbuntuFido {
|
||||
**Files:**
|
||||
- `daemon/src/policy_apply/mod.rs`
|
||||
- `daemon/src/policy_apply/profile.rs` — generates the pam-configs file dynamically
|
||||
- `debian/ubuntu-fido-pam.install` — ships the static pam-configs profile
|
||||
- `debian/ubuntu-fido-daemon.postinst` — runs `pam-auth-update --package` on install
|
||||
- `debian/authforge-pam.install` — ships the static pam-configs profile
|
||||
- `debian/authforge-daemon.postinst` — runs `pam-auth-update --package` on install
|
||||
|
||||
**Approach:** The pam-configs profile is templated. Daemon writes the appropriate variant to `/usr/share/pam-configs/ubuntu-fido` based on which stacks are required, then invokes `pam-auth-update --package`. (Alternative: ship multiple profiles, enable/disable each. The first approach is simpler.)
|
||||
**Approach:** The pam-configs profile is templated. Daemon writes the appropriate variant to `/usr/share/pam-configs/authforge` based on which stacks are required, then invokes `pam-auth-update --package`. (Alternative: ship multiple profiles, enable/disable each. The first approach is simpler.)
|
||||
|
||||
**Tasks:**
|
||||
1. Write template renderer.
|
||||
@@ -904,20 +904,20 @@ Returns a list of (user, stack, reason) violations.
|
||||
|
||||
---
|
||||
|
||||
# Phase 6: PAM Module — `pam_ubuntu_fido_pending.so`
|
||||
# Phase 6: PAM Module — `pam_authforge_pending.so`
|
||||
|
||||
**Goal:** The C module that backstops first-login enrollment. Replaces the Phase 0 stub.
|
||||
|
||||
**Files:**
|
||||
- `pam/pam_ubuntu_fido_pending.c` — full implementation
|
||||
- `pam/pam_authforge_pending.c` — full implementation
|
||||
- `pam/Makefile` — already exists from Phase 0
|
||||
|
||||
**Behavior:**
|
||||
- `pam_sm_authenticate`:
|
||||
1. Get `PAM_USER`.
|
||||
2. Check for `/var/lib/ubuntu-fido/pending/<user>` (use `stat()`, root-owned, mode 0644, no setuid surprises).
|
||||
2. Check for `/var/lib/authforge/pending/<user>` (use `stat()`, root-owned, mode 0644, no setuid surprises).
|
||||
3. If exists:
|
||||
a. If recovery code provided and matches `/var/lib/ubuntu-fido/recovery/<user>` (8-digit, 24h validity), accept and re-flag for re-enrollment.
|
||||
a. If recovery code provided and matches `/var/lib/authforge/recovery/<user>` (8-digit, 24h validity), accept and re-flag for re-enrollment.
|
||||
b. Otherwise return `PAM_AUTH_ERR` with conv message: "Account setup incomplete. Please complete enrollment in the Authentication app."
|
||||
4. If no flag: return `PAM_IGNORE`.
|
||||
- `pam_sm_setcred`: `PAM_SUCCESS`.
|
||||
@@ -928,11 +928,11 @@ Returns a list of (user, stack, reason) violations.
|
||||
3. Add structured logging via `pam_syslog`.
|
||||
4. Test with `pamtester`:
|
||||
```
|
||||
sudo touch /var/lib/ubuntu-fido/pending/alice
|
||||
pamtester ubuntu-fido alice authenticate
|
||||
sudo touch /var/lib/authforge/pending/alice
|
||||
pamtester authforge alice authenticate
|
||||
# expect: failure with our message
|
||||
sudo rm /var/lib/ubuntu-fido/pending/alice
|
||||
pamtester ubuntu-fido alice authenticate
|
||||
sudo rm /var/lib/authforge/pending/alice
|
||||
pamtester authforge alice authenticate
|
||||
# expect: success (PAM_IGNORE → other modules carry it)
|
||||
```
|
||||
|
||||
@@ -940,7 +940,7 @@ Returns a list of (user, stack, reason) violations.
|
||||
|
||||
---
|
||||
|
||||
# Phase 7: CLI — `ubuntu-fidoctl`
|
||||
# Phase 7: CLI — `authforgectl`
|
||||
|
||||
**Goal:** Full admin/fleet CLI. Talks D-Bus to the daemon. No magic — every command is a thin wrapper around a D-Bus call.
|
||||
|
||||
@@ -951,19 +951,19 @@ Returns a list of (user, stack, reason) violations.
|
||||
**Subcommands:**
|
||||
|
||||
```
|
||||
ubuntu-fidoctl status
|
||||
ubuntu-fidoctl enroll [--user USER] [--nickname NAME]
|
||||
ubuntu-fidoctl list [--user USER]
|
||||
ubuntu-fidoctl remove [--user USER] CRED_ID
|
||||
ubuntu-fidoctl policy show
|
||||
ubuntu-fidoctl policy set <stack> <mode> [--methods METHOD,...]
|
||||
ubuntu-fidoctl policy apply [--force-i-know-what-im-doing]
|
||||
ubuntu-fidoctl policy validate
|
||||
ubuntu-fidoctl pending set USER [--methods METHOD,...]
|
||||
ubuntu-fidoctl pending clear USER
|
||||
ubuntu-fidoctl pending list
|
||||
ubuntu-fidoctl recovery generate USER
|
||||
ubuntu-fidoctl recovery list USER
|
||||
authforgectl status
|
||||
authforgectl enroll [--user USER] [--nickname NAME]
|
||||
authforgectl list [--user USER]
|
||||
authforgectl remove [--user USER] CRED_ID
|
||||
authforgectl policy show
|
||||
authforgectl policy set <stack> <mode> [--methods METHOD,...]
|
||||
authforgectl policy apply [--force-i-know-what-im-doing]
|
||||
authforgectl policy validate
|
||||
authforgectl pending set USER [--methods METHOD,...]
|
||||
authforgectl pending clear USER
|
||||
authforgectl pending list
|
||||
authforgectl recovery generate USER
|
||||
authforgectl recovery list USER
|
||||
```
|
||||
|
||||
**Output:** human-readable by default; `--json` flag for machine-parseable output (essential for Ansible integration).
|
||||
@@ -1023,12 +1023,12 @@ ubuntu-fidoctl recovery list USER
|
||||
|
||||
**Files:**
|
||||
- `gui/src/views/firstrun.rs` — fullscreen modal mode
|
||||
- `gui/data/ubuntu-fido-firstrun.desktop` — autostart entry
|
||||
- `debian/ubuntu-fido-gui.install` — install autostart entry to `/etc/xdg/autostart/`
|
||||
- `gui/data/authforge-firstrun.desktop` — autostart entry
|
||||
- `debian/authforge-gui.install` — install autostart entry to `/etc/xdg/autostart/`
|
||||
- `gui/src/main.rs` — handle `--first-run` CLI flag
|
||||
|
||||
**Tasks:**
|
||||
1. Add `--first-run` flag to `ubuntu-fido` binary; alters startup to fullscreen modal mode (no header bar, no decorations, sticky-on-top).
|
||||
1. Add `--first-run` flag to `authforge` binary; alters startup to fullscreen modal mode (no header bar, no decorations, sticky-on-top).
|
||||
2. On startup in first-run mode, query daemon for `pending_flag(current_user)`; if absent, exit immediately.
|
||||
3. Show welcome page + run enrollment flow.
|
||||
4. On successful enrollment, call `clear_pending_flag` via D-Bus, exit cleanly.
|
||||
@@ -1037,9 +1037,9 @@ ubuntu-fidoctl recovery list USER
|
||||
|
||||
**Test (manual, in VM):**
|
||||
1. `useradd -m testuser`, `passwd testuser` (set tempPW), `chage -d 0 testuser`.
|
||||
2. `sudo ubuntu-fidoctl pending set testuser --methods fido2`.
|
||||
2. `sudo authforgectl pending set testuser --methods fido2`.
|
||||
3. Log out, log in as testuser → forced password change → enrollment modal appears → enroll Yubikey → modal closes → desktop usable.
|
||||
4. Verify: subsequent SSH-as-testuser-without-key is blocked by `pam_ubuntu_fido_pending.so` if pending wasn't cleared.
|
||||
4. Verify: subsequent SSH-as-testuser-without-key is blocked by `pam_authforge_pending.so` if pending wasn't cleared.
|
||||
|
||||
**Acceptance:** End-to-end flow C works in a VM smoke test.
|
||||
|
||||
@@ -1053,7 +1053,7 @@ ubuntu-fidoctl recovery list USER
|
||||
- `daemon/Cargo.toml` — add `totp` feature
|
||||
- `daemon/src/totp/mod.rs` — secret generation, recovery codes
|
||||
- `gui/src/views/totp.rs` — QR code display, secret enrollment
|
||||
- `debian/ubuntu-fido-daemon.install` — conditionally install pam-configs entry for TOTP
|
||||
- `debian/authforge-daemon.install` — conditionally install pam-configs entry for TOTP
|
||||
- `debian/control` — `Recommends: libpam-google-authenticator` when feature enabled
|
||||
|
||||
**Tasks:**
|
||||
@@ -1077,9 +1077,9 @@ ubuntu-fidoctl recovery list USER
|
||||
- `gui/src/views/recovery.rs`
|
||||
|
||||
**Tasks:**
|
||||
1. `generate_recovery_code(user)` writes `/var/lib/ubuntu-fido/recovery/<user>` (root-owned, 0600) containing Argon2id hash + expiry timestamp.
|
||||
2. PAM module checks recovery code at password prompt (already added in Phase 6); on success, removes recovery file and writes a `/var/lib/ubuntu-fido/pending/<user>` flag with `re_enroll = true`.
|
||||
3. CLI: `ubuntu-fidoctl recovery generate alice` outputs the 8-digit code.
|
||||
1. `generate_recovery_code(user)` writes `/var/lib/authforge/recovery/<user>` (root-owned, 0600) containing Argon2id hash + expiry timestamp.
|
||||
2. PAM module checks recovery code at password prompt (already added in Phase 6); on success, removes recovery file and writes a `/var/lib/authforge/pending/<user>` flag with `re_enroll = true`.
|
||||
3. CLI: `authforgectl recovery generate alice` outputs the 8-digit code.
|
||||
4. GUI: "Recovery" tab shows generate / list / revoke.
|
||||
5. Print-PDF feature: `gtk_print_unix_dialog` with template containing user's TOTP secret (opt-in only) and recovery codes.
|
||||
|
||||
@@ -1092,32 +1092,32 @@ ubuntu-fidoctl recovery list USER
|
||||
**Goal:** All packages install cleanly, postinst/prerm/postrm scripts handle every state transition correctly, debconf preseed works.
|
||||
|
||||
**Files:**
|
||||
- `debian/ubuntu-fido-daemon.{postinst,prerm,postrm}`
|
||||
- `debian/ubuntu-fido-pam.{postinst,prerm,postrm}`
|
||||
- `debian/ubuntu-fido.config` — debconf script
|
||||
- `debian/ubuntu-fido.templates` — debconf templates
|
||||
- `debian/authforge-daemon.{postinst,prerm,postrm}`
|
||||
- `debian/authforge-pam.{postinst,prerm,postrm}`
|
||||
- `debian/authforge.config` — debconf script
|
||||
- `debian/authforge.templates` — debconf templates
|
||||
|
||||
**Tasks:**
|
||||
1. postinst: enable + start daemon; run `pam-auth-update --package`; if first-time install and debconf provided answers, write initial `/etc/ubuntu-fido/policy.d/00-debconf.conf`.
|
||||
1. postinst: enable + start daemon; run `pam-auth-update --package`; if first-time install and debconf provided answers, write initial `/etc/authforge/policy.d/00-debconf.conf`.
|
||||
2. prerm: disable PAM enforcement (`pam-auth-update --package --remove`) so removal can't lock anyone out.
|
||||
3. postrm purge: rm `/etc/ubuntu-fido/`, `/var/lib/ubuntu-fido/`.
|
||||
3. postrm purge: rm `/etc/authforge/`, `/var/lib/authforge/`.
|
||||
4. debconf templates: ask "Default policy? (None / Optional everywhere / Required for sudo)".
|
||||
5. lintian: get all warnings down to zero or explicitly overridden with rationale.
|
||||
6. Test matrix: install → upgrade (from 0.0.x → 0.1.0) → remove → purge → reinstall, on Ubuntu 22.04 and 24.04.
|
||||
|
||||
**Acceptance:** `piuparts ubuntu-fido_0.1.0-1_amd64.deb` passes.
|
||||
**Acceptance:** `piuparts authforge_0.1.0-1_amd64.deb` passes.
|
||||
|
||||
---
|
||||
|
||||
# Phase 14: Launchpad PPA Setup
|
||||
|
||||
**Goal:** End users can `sudo add-apt-repository ppa:dangerousthings/ubuntu-fido`.
|
||||
**Goal:** End users can `sudo add-apt-repository ppa:dangerousthings/authforge`.
|
||||
|
||||
**Tasks:**
|
||||
1. Create Launchpad team `dangerousthings` (or use existing).
|
||||
2. Create PPA `ubuntu-fido`.
|
||||
2. Create PPA `authforge`.
|
||||
3. Generate signing key (gpg, store passphrase in 1Password / vault).
|
||||
4. `dput ppa:dangerousthings/ubuntu-fido ubuntu-fido_0.1.0-1_source.changes` (note: Launchpad builds from source).
|
||||
4. `dput ppa:dangerousthings/authforge authforge_0.1.0-1_source.changes` (note: Launchpad builds from source).
|
||||
5. Wait for build, verify install on a fresh VM.
|
||||
6. Document signing key fingerprint in README.
|
||||
|
||||
@@ -1125,13 +1125,13 @@ ubuntu-fidoctl recovery list USER
|
||||
|
||||
---
|
||||
|
||||
# Phase 15: `ubuntu-fido-gnome-integration`
|
||||
# Phase 15: `authforge-gnome-integration`
|
||||
|
||||
**Goal:** Optional shortcut deb that makes ubuntu-fido discoverable from `gnome-control-center` Users panel.
|
||||
**Goal:** Optional shortcut deb that makes authforge discoverable from `gnome-control-center` Users panel.
|
||||
|
||||
**Files:**
|
||||
- New source tree under `gnome-integration/` (separate Cargo workspace member or pure-data deb)
|
||||
- `debian/ubuntu-fido-gnome-integration.install`
|
||||
- `debian/authforge-gnome-integration.install`
|
||||
|
||||
**Approach (research required during this phase):** GNOME 46+ allows panel extensions via dbus-activated services. Ship a small JS/GJS extension or a dynamic library loaded by gnome-control-center. If neither stable approach exists, ship a `.desktop` file under `/usr/share/applications/` tagged with `X-GNOME-Settings-Panel=user-accounts` or similar — exact mechanism is GNOME-version-dependent.
|
||||
|
||||
@@ -1141,13 +1141,13 @@ ubuntu-fidoctl recovery list USER
|
||||
3. Test against current Ubuntu LTS GNOME version.
|
||||
4. Pin Recommends to specific gnome-control-center major version range.
|
||||
|
||||
**Acceptance:** Opening Settings → Users → some-user shows a "Configure security…" link that launches `ubuntu-fido --user some-user` with proper polkit context.
|
||||
**Acceptance:** Opening Settings → Users → some-user shows a "Configure security…" link that launches `authforge --user some-user` with proper polkit context.
|
||||
|
||||
---
|
||||
|
||||
# Phase 16: Ansible Role
|
||||
|
||||
**Goal:** `dangerousthings.ubuntu_fido` role on Ansible Galaxy that handles install, policy, and enrollment for fleet deployments.
|
||||
**Goal:** `dangerousthings.authforge` role on Ansible Galaxy that handles install, policy, and enrollment for fleet deployments.
|
||||
|
||||
**Files (in a separate `ansible-role` tree, possibly its own repo):**
|
||||
- `ansible-role/tasks/main.yml`
|
||||
@@ -1156,7 +1156,7 @@ ubuntu-fidoctl recovery list USER
|
||||
- `ansible-role/meta/main.yml`
|
||||
|
||||
**Tasks:**
|
||||
1. Role tasks: add PPA, install packages, drop policy file at `/etc/ubuntu-fido/policy.d/90-fleet.conf`, restart daemon.
|
||||
1. Role tasks: add PPA, install packages, drop policy file at `/etc/authforge/policy.d/90-fleet.conf`, restart daemon.
|
||||
2. Variables for: enabled stacks, modes per stack, central credential storage on/off, default firstrun methods.
|
||||
3. Examples in `examples/playbook.yml`.
|
||||
4. Publish to Galaxy.
|
||||
@@ -1196,7 +1196,7 @@ Use `umockdev` to simulate USB devices in CI; require real hardware for nightly
|
||||
- `docs/user/fleet-deployment.md`
|
||||
- `docs/user/recovery.md`
|
||||
- `docs/user/troubleshooting.md`
|
||||
- Optional: small static site (mdBook or Docusaurus) at `https://ubuntu-fido.dangerousthings.com`
|
||||
- Optional: small static site (mdBook or Docusaurus) at `https://authforge.dangerousthings.com`
|
||||
|
||||
**Tasks:**
|
||||
1. Getting started: end-user view of "install + enroll my Yubikey + require it for sudo".
|
||||
@@ -1247,7 +1247,7 @@ Use `umockdev` to simulate USB devices in CI; require real hardware for nightly
|
||||
|
||||
When the user returns:
|
||||
|
||||
> Plan complete and saved to `docs/plans/2026-04-26-ubuntu-fido-implementation.md`. The companion design doc is at `docs/plans/2026-04-26-ubuntu-fido-design.md`. Phase 0 is fully detailed; phases 1–18 are spec'd to a level sufficient to begin work. Each later phase should re-invoke `superpowers:writing-plans` for step-level expansion as it begins.
|
||||
> Plan complete and saved to `docs/plans/2026-04-26-authforge-implementation.md`. The companion design doc is at `docs/plans/2026-04-26-authforge-design.md`. Phase 0 is fully detailed; phases 1–18 are spec'd to a level sufficient to begin work. Each later phase should re-invoke `superpowers:writing-plans` for step-level expansion as it begins.
|
||||
>
|
||||
> Two execution options:
|
||||
>
|
||||
Reference in New Issue
Block a user