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:
4
.github/workflows/ci.yml
vendored
4
.github/workflows/ci.yml
vendored
@@ -41,8 +41,8 @@ jobs:
|
|||||||
cargo rustc
|
cargo rustc
|
||||||
- run: debuild -us -uc -b
|
- run: debuild -us -uc -b
|
||||||
- name: Run lintian (warnings allowed in Phase 0)
|
- name: Run lintian (warnings allowed in Phase 0)
|
||||||
run: lintian --info --display-info ../ubuntu-fido*.changes || true
|
run: lintian --info --display-info ../authforge*.changes || true
|
||||||
- uses: actions/upload-artifact@v4
|
- uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: deb-packages
|
name: deb-packages
|
||||||
path: ../ubuntu-fido*.deb
|
path: ../authforge*.deb
|
||||||
|
|||||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -8,7 +8,9 @@ debian/.debhelper/
|
|||||||
debian/files
|
debian/files
|
||||||
debian/*.substvars
|
debian/*.substvars
|
||||||
debian/*.debhelper.log
|
debian/*.debhelper.log
|
||||||
debian/ubuntu-fido*/
|
debian/authforge*/
|
||||||
|
debian/debhelper-build-stamp
|
||||||
|
pam/*.so
|
||||||
build/
|
build/
|
||||||
.vscode/
|
.vscode/
|
||||||
*.swp
|
*.swp
|
||||||
|
|||||||
2148
Cargo.lock
generated
Normal file
2148
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -2,7 +2,7 @@
|
|||||||
resolver = "2"
|
resolver = "2"
|
||||||
members = ["common", "daemon", "cli", "gui"]
|
members = ["common", "daemon", "cli", "gui"]
|
||||||
# GUI excluded from default builds because it requires libgtk-4-dev + libadwaita-1-dev
|
# GUI excluded from default builds because it requires libgtk-4-dev + libadwaita-1-dev
|
||||||
# at link time. Build it explicitly with `cargo build -p ubuntu-fido-gui`.
|
# at link time. Build it explicitly with `cargo build -p authforge-gui`.
|
||||||
default-members = ["common", "daemon", "cli"]
|
default-members = ["common", "daemon", "cli"]
|
||||||
|
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
@@ -10,7 +10,7 @@ version = "0.1.0"
|
|||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
authors = ["Dangerous Things <ops@dangerousthings.com>"]
|
authors = ["Dangerous Things <ops@dangerousthings.com>"]
|
||||||
repository = "https://github.com/dangerousthings/ubuntu-fido"
|
repository = "https://github.com/dangerousthings/authforge"
|
||||||
rust-version = "1.78"
|
rust-version = "1.78"
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
|
|||||||
12
README.md
12
README.md
@@ -1,18 +1,18 @@
|
|||||||
# ubuntu-fido
|
# authforge
|
||||||
|
|
||||||
Turnkey U2F / FIDO2 passkey / TOTP MFA for Ubuntu desktops.
|
Turnkey U2F / FIDO2 passkey / TOTP MFA for Linux desktops. v1 ships on Ubuntu LTS + GNOME; Debian and KDE Plasma are on the roadmap.
|
||||||
|
|
||||||
## Install (end users)
|
## Install (end users)
|
||||||
|
|
||||||
sudo add-apt-repository ppa:dangerousthings/ubuntu-fido
|
sudo add-apt-repository ppa:dangerousthings/authforge
|
||||||
sudo apt install ubuntu-fido
|
sudo apt install authforge
|
||||||
|
|
||||||
## Build from source
|
## Build from source
|
||||||
|
|
||||||
See `docs/BUILDING.md`.
|
See [docs/BUILDING.md](docs/BUILDING.md).
|
||||||
|
|
||||||
## Status
|
## Status
|
||||||
|
|
||||||
Pre-alpha. See `docs/plans/` for design and roadmap.
|
Pre-alpha. See [docs/plans/](docs/plans/) for design and roadmap.
|
||||||
|
|
||||||
Copyright 2026 Dangerous Things, LLC. Licensed under the Apache License, Version 2.0.
|
Copyright 2026 Dangerous Things, LLC. Licensed under the Apache License, Version 2.0.
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "ubuntu-fidoctl"
|
name = "authforge-cli"
|
||||||
version.workspace = true
|
version.workspace = true
|
||||||
edition.workspace = true
|
edition.workspace = true
|
||||||
license.workspace = true
|
license.workspace = true
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "ubuntu-fidoctl"
|
name = "authforgectl"
|
||||||
path = "src/main.rs"
|
path = "src/main.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
ubuntu-fido-common = { path = "../common" }
|
authforge-common = { path = "../common" }
|
||||||
clap = { workspace = true }
|
clap = { workspace = true }
|
||||||
anyhow = { workspace = true }
|
anyhow = { workspace = true }
|
||||||
zbus = { workspace = true }
|
zbus = { workspace = true }
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ use clap::Parser;
|
|||||||
|
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
#[command(
|
#[command(
|
||||||
name = "ubuntu-fidoctl",
|
name = "authforgectl",
|
||||||
version,
|
version,
|
||||||
about = "Manage ubuntu-fido configuration"
|
about = "Manage authforge configuration"
|
||||||
)]
|
)]
|
||||||
struct Cli {
|
struct Cli {
|
||||||
#[command(subcommand)]
|
#[command(subcommand)]
|
||||||
@@ -21,7 +21,7 @@ enum Cmd {
|
|||||||
async fn main() -> Result<()> {
|
async fn main() -> Result<()> {
|
||||||
let args = Cli::parse();
|
let args = Cli::parse();
|
||||||
match args.cmd {
|
match args.cmd {
|
||||||
Cmd::Status => println!("ubuntu-fidoctl: not yet implemented"),
|
Cmd::Status => println!("authforgectl: not yet implemented"),
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "ubuntu-fido-common"
|
name = "authforge-common"
|
||||||
version.workspace = true
|
version.workspace = true
|
||||||
edition.workspace = true
|
edition.workspace = true
|
||||||
license.workspace = true
|
license.workspace = true
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "ubuntu-fidod"
|
name = "authforge-daemon"
|
||||||
version.workspace = true
|
version.workspace = true
|
||||||
edition.workspace = true
|
edition.workspace = true
|
||||||
license.workspace = true
|
license.workspace = true
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "ubuntu-fidod"
|
name = "authforged"
|
||||||
path = "src/main.rs"
|
path = "src/main.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
ubuntu-fido-common = { path = "../common" }
|
authforge-common = { path = "../common" }
|
||||||
zbus = { workspace = true }
|
zbus = { workspace = true }
|
||||||
tokio = { workspace = true }
|
tokio = { workspace = true }
|
||||||
tracing = { workspace = true }
|
tracing = { workspace = true }
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ async fn main() -> Result<()> {
|
|||||||
tracing_subscriber::fmt()
|
tracing_subscriber::fmt()
|
||||||
.with_env_filter(tracing_subscriber::EnvFilter::from_default_env())
|
.with_env_filter(tracing_subscriber::EnvFilter::from_default_env())
|
||||||
.init();
|
.init();
|
||||||
info!("ubuntu-fidod {} starting", env!("CARGO_PKG_VERSION"));
|
info!("authforged {} starting", env!("CARGO_PKG_VERSION"));
|
||||||
// D-Bus service registration in Phase 1.
|
// D-Bus service registration in Phase 1.
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
4
debian/changelog
vendored
4
debian/changelog
vendored
@@ -1,5 +1,5 @@
|
|||||||
ubuntu-fido (0.1.0-1) UNRELEASED; urgency=low
|
authforge (0.1.0-1) UNRELEASED; urgency=low
|
||||||
|
|
||||||
* Initial packaging skeleton.
|
* Initial packaging skeleton (renamed from ubuntu-fido).
|
||||||
|
|
||||||
-- Dangerous Things <ops@dangerousthings.com> Sun, 26 Apr 2026 12:00:00 +0000
|
-- Dangerous Things <ops@dangerousthings.com> Sun, 26 Apr 2026 12:00:00 +0000
|
||||||
|
|||||||
46
debian/control
vendored
46
debian/control
vendored
@@ -1,4 +1,4 @@
|
|||||||
Source: ubuntu-fido
|
Source: authforge
|
||||||
Section: admin
|
Section: admin
|
||||||
Priority: optional
|
Priority: optional
|
||||||
Maintainer: Dangerous Things <ops@dangerousthings.com>
|
Maintainer: Dangerous Things <ops@dangerousthings.com>
|
||||||
@@ -12,44 +12,44 @@ Build-Depends:
|
|||||||
libfido2-dev,
|
libfido2-dev,
|
||||||
pkg-config
|
pkg-config
|
||||||
Standards-Version: 4.6.2
|
Standards-Version: 4.6.2
|
||||||
Homepage: https://github.com/dangerousthings/ubuntu-fido
|
Homepage: https://github.com/dangerousthings/authforge
|
||||||
Vcs-Browser: https://github.com/dangerousthings/ubuntu-fido
|
Vcs-Browser: https://github.com/dangerousthings/authforge
|
||||||
Vcs-Git: https://github.com/dangerousthings/ubuntu-fido.git
|
Vcs-Git: https://github.com/dangerousthings/authforge.git
|
||||||
|
|
||||||
Package: ubuntu-fido
|
Package: authforge
|
||||||
Architecture: any
|
Architecture: any
|
||||||
Depends: ubuntu-fido-daemon (= ${binary:Version}),
|
Depends: authforge-daemon (= ${binary:Version}),
|
||||||
ubuntu-fido-pam (= ${binary:Version}),
|
authforge-pam (= ${binary:Version}),
|
||||||
ubuntu-fido-cli (= ${binary:Version}),
|
authforge-cli (= ${binary:Version}),
|
||||||
${misc:Depends}
|
${misc:Depends}
|
||||||
Recommends: ubuntu-fido-gui (= ${binary:Version})
|
Recommends: authforge-gui (= ${binary:Version})
|
||||||
Suggests: ubuntu-fido-gnome-integration
|
Suggests: authforge-gnome-integration
|
||||||
Description: Turnkey FIDO2/U2F/TOTP MFA for Ubuntu (metapackage)
|
Description: Turnkey FIDO2/U2F/TOTP MFA for Linux desktops (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.
|
(if recommended) GUI.
|
||||||
|
|
||||||
Package: ubuntu-fido-daemon
|
Package: authforge-daemon
|
||||||
Architecture: any
|
Architecture: any
|
||||||
Depends: ${shlibs:Depends}, ${misc:Depends}, libpam-u2f, libfido2-1
|
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,
|
Provides the privileged D-Bus service that orchestrates enrollment,
|
||||||
policy edits, and lockout-prevention checks.
|
policy edits, and lockout-prevention checks.
|
||||||
|
|
||||||
Package: ubuntu-fido-pam
|
Package: authforge-pam
|
||||||
Architecture: any
|
Architecture: any
|
||||||
Depends: ${shlibs:Depends}, ${misc:Depends}, libpam-runtime
|
Depends: ${shlibs:Depends}, ${misc:Depends}, libpam-runtime
|
||||||
Description: PAM module backstopping ubuntu-fido first-login enrollment
|
Description: PAM module backstopping authforge first-login enrollment
|
||||||
Refuses authentication when /var/lib/ubuntu-fido/pending/<user> exists
|
Refuses authentication when /var/lib/authforge/pending/<user> exists
|
||||||
and the user has not completed first-login MFA setup.
|
and the user has not completed first-login MFA setup.
|
||||||
|
|
||||||
Package: ubuntu-fido-cli
|
Package: authforge-cli
|
||||||
Architecture: any
|
Architecture: any
|
||||||
Depends: ${shlibs:Depends}, ${misc:Depends}, ubuntu-fido-daemon
|
Depends: ${shlibs:Depends}, ${misc:Depends}, authforge-daemon
|
||||||
Description: CLI for ubuntu-fido (admin and fleet)
|
Description: CLI for authforge (admin and fleet)
|
||||||
Configure policy, enroll on behalf of users, generate recovery codes.
|
Configure policy, enroll on behalf of users, generate recovery codes.
|
||||||
|
|
||||||
Package: ubuntu-fido-gui
|
Package: authforge-gui
|
||||||
Architecture: any
|
Architecture: any
|
||||||
Depends: ${shlibs:Depends}, ${misc:Depends}, ubuntu-fido-daemon
|
Depends: ${shlibs:Depends}, ${misc:Depends}, authforge-daemon
|
||||||
Description: GTK4/libadwaita UI for ubuntu-fido
|
Description: GTK4/libadwaita UI for authforge
|
||||||
End-user-facing settings panel for enrollment and policy.
|
End-user-facing settings panel for enrollment and policy.
|
||||||
|
|||||||
4
debian/copyright
vendored
4
debian/copyright
vendored
@@ -1,7 +1,7 @@
|
|||||||
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
||||||
Upstream-Name: ubuntu-fido
|
Upstream-Name: authforge
|
||||||
Upstream-Contact: Dangerous Things <ops@dangerousthings.com>
|
Upstream-Contact: Dangerous Things <ops@dangerousthings.com>
|
||||||
Source: https://github.com/dangerousthings/ubuntu-fido
|
Source: https://github.com/dangerousthings/authforge
|
||||||
|
|
||||||
Files: *
|
Files: *
|
||||||
Copyright: 2026 Dangerous Things, LLC
|
Copyright: 2026 Dangerous Things, LLC
|
||||||
|
|||||||
22
debian/rules
vendored
22
debian/rules
vendored
@@ -11,20 +11,20 @@ override_dh_auto_build:
|
|||||||
|
|
||||||
override_dh_auto_install:
|
override_dh_auto_install:
|
||||||
# Daemon
|
# Daemon
|
||||||
install -D -m 0755 target/release/ubuntu-fidod \
|
install -D -m 0755 target/release/authforged \
|
||||||
debian/ubuntu-fido-daemon/usr/sbin/ubuntu-fidod
|
debian/authforge-daemon/usr/sbin/authforged
|
||||||
# CLI
|
# CLI
|
||||||
install -D -m 0755 target/release/ubuntu-fidoctl \
|
install -D -m 0755 target/release/authforgectl \
|
||||||
debian/ubuntu-fido-cli/usr/bin/ubuntu-fidoctl
|
debian/authforge-cli/usr/bin/authforgectl
|
||||||
# GUI
|
# GUI
|
||||||
install -D -m 0755 target/release/ubuntu-fido \
|
install -D -m 0755 target/release/authforge \
|
||||||
debian/ubuntu-fido-gui/usr/bin/ubuntu-fido
|
debian/authforge-gui/usr/bin/authforge
|
||||||
install -D -m 0644 gui/data/io.dangerousthings.UbuntuFido.desktop \
|
install -D -m 0644 gui/data/io.dangerousthings.AuthForge.desktop \
|
||||||
debian/ubuntu-fido-gui/usr/share/applications/io.dangerousthings.UbuntuFido.desktop
|
debian/authforge-gui/usr/share/applications/io.dangerousthings.AuthForge.desktop
|
||||||
install -D -m 0644 gui/data/io.dangerousthings.UbuntuFido.svg \
|
install -D -m 0644 gui/data/io.dangerousthings.AuthForge.svg \
|
||||||
debian/ubuntu-fido-gui/usr/share/icons/hicolor/scalable/apps/io.dangerousthings.UbuntuFido.svg
|
debian/authforge-gui/usr/share/icons/hicolor/scalable/apps/io.dangerousthings.AuthForge.svg
|
||||||
# PAM
|
# PAM
|
||||||
$(MAKE) -C pam install DESTDIR=$(CURDIR)/debian/ubuntu-fido-pam
|
$(MAKE) -C pam install DESTDIR=$(CURDIR)/debian/authforge-pam
|
||||||
|
|
||||||
override_dh_auto_test:
|
override_dh_auto_test:
|
||||||
cargo test --workspace --release
|
cargo test --workspace --release
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# Building ubuntu-fido from source
|
# Building authforge from source
|
||||||
|
|
||||||
## System dependencies
|
## System dependencies
|
||||||
|
|
||||||
@@ -19,32 +19,24 @@ Rust toolchain: stable (1.78 minimum). Install via [rustup](https://rustup.rs).
|
|||||||
cargo build --release
|
cargo build --release
|
||||||
|
|
||||||
# GUI (requires libgtk-4-dev + libadwaita-1-dev)
|
# GUI (requires libgtk-4-dev + libadwaita-1-dev)
|
||||||
cargo build -p ubuntu-fido-gui --release
|
cargo build -p authforge-gui --release
|
||||||
|
|
||||||
# PAM module (requires libpam0g-dev)
|
# PAM module (requires libpam0g-dev)
|
||||||
make -C pam
|
make -C pam
|
||||||
|
|
||||||
# Full deb build (requires all of the above)
|
# Full deb build (requires all of the above + debhelper)
|
||||||
debuild -us -uc -b
|
dpkg-buildpackage -us -uc -b
|
||||||
# Output: ../ubuntu-fido*.deb
|
# Output: ../authforge*.deb
|
||||||
```
|
```
|
||||||
|
|
||||||
## Tests
|
## Tests
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cargo test --workspace --exclude ubuntu-fido-gui
|
cargo test --workspace --exclude authforge-gui
|
||||||
```
|
```
|
||||||
|
|
||||||
The GUI crate has no automated tests in v1; manual smoke tests are documented in [docs/plans/2026-04-26-ubuntu-fido-design.md](plans/2026-04-26-ubuntu-fido-design.md#testing-strategy).
|
The GUI crate has no automated tests in v1; manual smoke tests are documented in [docs/plans/2026-04-26-authforge-design.md](plans/2026-04-26-authforge-design.md#testing-strategy).
|
||||||
|
|
||||||
## Phase 0 status
|
## Phase 0 status
|
||||||
|
|
||||||
Repository scaffolding is complete (tag `v0.1.0-scaffolding`). Subsequent phases per [docs/plans/2026-04-26-ubuntu-fido-implementation.md](plans/2026-04-26-ubuntu-fido-implementation.md).
|
Repository scaffolding is complete (tag `v0.1.0-scaffolding`, then renamed `ubuntu-fido` → `authforge`). Subsequent phases per [docs/plans/2026-04-26-authforge-implementation.md](plans/2026-04-26-authforge-implementation.md).
|
||||||
|
|
||||||
Build verifications NOT yet run on this machine (require `sudo apt install libpam0g-dev libgtk-4-dev libadwaita-1-dev libfido2-dev`):
|
|
||||||
|
|
||||||
- `make -C pam` — PAM module compile
|
|
||||||
- `cargo build -p ubuntu-fido-gui --release` — GUI link
|
|
||||||
- `debuild -us -uc -b` — full deb build
|
|
||||||
|
|
||||||
Once those packages are installed, run the three commands above to complete the Phase 0 acceptance gate.
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# ubuntu-fido — Design Document
|
# authforge — Design Document
|
||||||
|
|
||||||
**Date:** 2026-04-26
|
**Date:** 2026-04-26
|
||||||
**Status:** Draft (brainstorm complete, validated through Section 2 with stakeholder)
|
**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. |
|
| 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. |
|
| 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. |
|
| 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. |
|
| 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_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. |
|
| 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
|
## Architecture
|
||||||
|
|
||||||
```
|
```
|
||||||
┌─────────────────────────┐ ┌──────────────────────────┐ ┌──────────────┐
|
┌─────────────────────────┐ ┌──────────────────────────┐ ┌──────────────┐
|
||||||
│ ubuntu-fido GTK app │ │ ubuntu-fidoctl (CLI) │ │ Future KDE │
|
│ authforge GTK app │ │ authforgectl (CLI) │ │ Future KDE │
|
||||||
│ (libadwaita panel) │ │ (admin/fleet scripting) │ │ KCM module │
|
│ (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 │
|
│ - enrollment orchestration │
|
||||||
│ - policy read/write + lockout │
|
│ - policy read/write + lockout │
|
||||||
│ safety simulation │
|
│ 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>
|
(stack edits policy.d/*.conf u2f_keys (per-user) pending/<user>
|
||||||
via pam-auth- (admin/fleet /etc/u2f_mappings (first-login flag)
|
via pam-auth- (admin/fleet /etc/u2f_mappings (first-login flag)
|
||||||
update) drop-ins) (central override)
|
update) drop-ins) (central override)
|
||||||
@@ -55,7 +55,7 @@ update) drop-ins) (central override)
|
|||||||
|
|
||||||
### Trust boundary
|
### 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 |
|
| 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 |
|
| Package | Contents | Type |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `ubuntu-fido` | Empty metapackage. | Depends |
|
| `authforge` | 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 |
|
| `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 |
|
||||||
| `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 |
|
| `authforge-pam` | `/usr/lib/$DEB_HOST_MULTIARCH/security/pam_authforge_pending.so`, pam-auth-update profile at `/usr/share/pam-configs/authforge` | Hard dep |
|
||||||
| `ubuntu-fido-cli` | `/usr/bin/ubuntu-fidoctl` (Rust binary, talks D-Bus) | Hard dep |
|
| `authforge-cli` | `/usr/bin/authforgectl` (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) |
|
| `authforge-gui` | `/usr/bin/authforge` (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-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
|
### Headline install
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo add-apt-repository ppa:dangerousthings/ubuntu-fido
|
sudo add-apt-repository ppa:dangerousthings/authforge
|
||||||
sudo apt install ubuntu-fido
|
sudo apt install authforge
|
||||||
```
|
```
|
||||||
|
|
||||||
Two commands. After install:
|
Two commands. After install:
|
||||||
@@ -97,20 +97,20 @@ Two commands. After install:
|
|||||||
### Headless / fleet install
|
### Headless / fleet install
|
||||||
|
|
||||||
```bash
|
```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.
|
- A **debconf preseed schema** so `debian-installer`/cloud-init can answer questions at install time.
|
||||||
|
|
||||||
### Clean uninstall
|
### 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
|
## 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`:
|
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
|
### 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.
|
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
|
### 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).
|
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).
|
3. **No MFA** — only available if local policy permits ("Required" stacks would block this option with a tooltip).
|
||||||
|
|
||||||
## Enrollment flows
|
## Enrollment flows
|
||||||
|
|
||||||
### Flow A: User self-enrollment (the common case)
|
### 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".
|
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.
|
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.
|
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):**
|
**At account creation (admin side):**
|
||||||
1. Admin picks "Require user to set up at first login", enters/accepts temp password.
|
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).
|
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):**
|
**First login (user side):**
|
||||||
1. User logs into GDM with temp password.
|
1. User logs into GDM with temp password.
|
||||||
2. PAM `passwd` module forces password change (existing Ubuntu behavior, no work for us).
|
2. PAM `passwd` module forces password change (existing Ubuntu behavior, no work for us).
|
||||||
3. GNOME session starts.
|
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."
|
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).
|
6. User enrolls (Flow A inside the modal).
|
||||||
7. On success, daemon clears pending flag.
|
7. On success, daemon clears pending flag.
|
||||||
8. Modal closes, user lands on a normal desktop.
|
8. Modal closes, user lands on a normal desktop.
|
||||||
|
|
||||||
**Backstop (the PAM module):**
|
**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."
|
- 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 `ubuntu-fido --first-run` calls `gnome-session-quit --logout --no-prompt` after 60 seconds of inactivity in the modal.
|
- 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
|
### Flow D: Lost key recovery
|
||||||
|
|
||||||
1. User can't authenticate.
|
1. User can't authenticate.
|
||||||
2. User contacts admin.
|
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.
|
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_ubuntu_fido_pending.so` recognizes recovery code prefix, lets them through with a forced re-enrollment flag set.
|
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.
|
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 and policy details
|
||||||
|
|
||||||
### pam-auth-update profile
|
### 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
|
Default: no
|
||||||
Priority: 192
|
Priority: 192
|
||||||
Auth-Type: Additional
|
Auth-Type: Additional
|
||||||
Auth:
|
Auth:
|
||||||
[success=ok default=1 ignore=ignore] pam_u2f.so cue authfile=/etc/u2f_mappings
|
[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.
|
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:
|
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:
|
Before applying any policy change, daemon simulates the new policy against:
|
||||||
- The currently logged-in interactive user (resolved via `loginctl`).
|
- 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'."
|
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.0** | Ubuntu LTS + GNOME, U2F + FIDO2 passkey + TOTP. | Reference. |
|
||||||
| **v1.1** | Debian stable packaging (same source, second build target). | ~2 weeks. |
|
| **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. |
|
| **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. |
|
| **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.
|
> **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).
|
> **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.
|
**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 |
|
| 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 |
|
| 4 | Daemon: policy apply via pam-auth-update wrapper | 4 days | Spec'd |
|
||||||
| 5 | Daemon: lockout simulator | 3 days | Spec'd |
|
| 5 | Daemon: lockout simulator | 3 days | Spec'd |
|
||||||
| 6 | PAM module: `pam_ubuntu_fido_pending.so` (C) | 3 days | Spec'd |
|
| 6 | PAM module: `pam_authforge_pending.so` (C) | 3 days | Spec'd |
|
||||||
| 7 | CLI: `ubuntu-fidoctl` | 4 days | Spec'd |
|
| 7 | CLI: `authforgectl` | 4 days | Spec'd |
|
||||||
| 8 | GUI: app shell + Security Keys tab | 6–8 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 |
|
| 9 | GUI: Policy tab + lockout-warning UX | 4 days | Spec'd |
|
||||||
| 10 | First-login flow: autostart entry + fullscreen modal | 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 |
|
| 12 | Recovery flow (codes + emergency unlock) | 4 days | Spec'd |
|
||||||
| 13 | Debian packaging finalization (postinst, debconf, purge) | 4 days | Spec'd |
|
| 13 | Debian packaging finalization (postinst, debconf, purge) | 4 days | Spec'd |
|
||||||
| 14 | Launchpad PPA build setup | 2 days | Spec'd |
|
| 14 | Launchpad PPA build setup | 2 days | Spec'd |
|
||||||
| 15 | `ubuntu-fido-gnome-integration` (Users panel shortcut) | 3 days | Spec'd |
|
| 15 | `authforge-gnome-integration` (Users panel shortcut) | 3 days | Spec'd |
|
||||||
| 16 | Ansible role `dangerousthings.ubuntu_fido` | 2 days | Spec'd |
|
| 16 | Ansible role `dangerousthings.authforge` | 2 days | Spec'd |
|
||||||
| 17 | Integration test harness (Multipass / LXD VM) | 4 days | Spec'd |
|
| 17 | Integration test harness (Multipass / LXD VM) | 4 days | Spec'd |
|
||||||
| 18 | User docs + onboarding site | 3 days | Spec'd |
|
| 18 | User docs + onboarding site | 3 days | Spec'd |
|
||||||
| **R** | **v1.0 release** | 1 day | — |
|
| **R** | **v1.0 release** | 1 day | — |
|
||||||
@@ -82,7 +82,7 @@ debian/.debhelper/
|
|||||||
debian/files
|
debian/files
|
||||||
debian/*.substvars
|
debian/*.substvars
|
||||||
debian/*.debhelper.log
|
debian/*.debhelper.log
|
||||||
debian/ubuntu-fido*/
|
debian/authforge*/
|
||||||
build/
|
build/
|
||||||
.vscode/
|
.vscode/
|
||||||
*.swp
|
*.swp
|
||||||
@@ -93,14 +93,14 @@ build/
|
|||||||
**Step 4:** Write minimal `README.md`:
|
**Step 4:** Write minimal `README.md`:
|
||||||
|
|
||||||
```markdown
|
```markdown
|
||||||
# ubuntu-fido
|
# authforge
|
||||||
|
|
||||||
Turnkey U2F / FIDO2 passkey / TOTP MFA for Ubuntu desktops.
|
Turnkey U2F / FIDO2 passkey / TOTP MFA for Ubuntu desktops.
|
||||||
|
|
||||||
## Install (end users)
|
## Install (end users)
|
||||||
|
|
||||||
sudo add-apt-repository ppa:dangerousthings/ubuntu-fido
|
sudo add-apt-repository ppa:dangerousthings/authforge
|
||||||
sudo apt install ubuntu-fido
|
sudo apt install authforge
|
||||||
|
|
||||||
## Build from source
|
## Build from source
|
||||||
|
|
||||||
@@ -137,7 +137,7 @@ version = "0.1.0"
|
|||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
authors = ["Dangerous Things <ops@dangerousthings.com>"]
|
authors = ["Dangerous Things <ops@dangerousthings.com>"]
|
||||||
repository = "https://github.com/dangerousthings/ubuntu-fido"
|
repository = "https://github.com/dangerousthings/authforge"
|
||||||
rust-version = "1.78"
|
rust-version = "1.78"
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
@@ -185,7 +185,7 @@ rustflags = ["-D", "warnings"]
|
|||||||
|
|
||||||
```toml
|
```toml
|
||||||
[package]
|
[package]
|
||||||
name = "ubuntu-fido-common"
|
name = "authforge-common"
|
||||||
version.workspace = true
|
version.workspace = true
|
||||||
edition.workspace = true
|
edition.workspace = true
|
||||||
license.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`.
|
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.
|
**Step 7:** Commit.
|
||||||
|
|
||||||
@@ -267,17 +267,17 @@ git commit -m "Add common crate with shared Mode and Method types"
|
|||||||
|
|
||||||
```toml
|
```toml
|
||||||
[package]
|
[package]
|
||||||
name = "ubuntu-fidod"
|
name = "authforged"
|
||||||
version.workspace = true
|
version.workspace = true
|
||||||
edition.workspace = true
|
edition.workspace = true
|
||||||
license.workspace = true
|
license.workspace = true
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "ubuntu-fidod"
|
name = "authforged"
|
||||||
path = "src/main.rs"
|
path = "src/main.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
ubuntu-fido-common = { path = "../common" }
|
authforge-common = { path = "../common" }
|
||||||
zbus = { workspace = true }
|
zbus = { workspace = true }
|
||||||
tokio = { workspace = true }
|
tokio = { workspace = true }
|
||||||
tracing = { workspace = true }
|
tracing = { workspace = true }
|
||||||
@@ -296,13 +296,13 @@ async fn main() -> Result<()> {
|
|||||||
tracing_subscriber::fmt()
|
tracing_subscriber::fmt()
|
||||||
.with_env_filter(tracing_subscriber::EnvFilter::from_default_env())
|
.with_env_filter(tracing_subscriber::EnvFilter::from_default_env())
|
||||||
.init();
|
.init();
|
||||||
info!("ubuntu-fidod {} starting", env!("CARGO_PKG_VERSION"));
|
info!("authforged {} starting", env!("CARGO_PKG_VERSION"));
|
||||||
// D-Bus service registration in Phase 1.
|
// D-Bus service registration in Phase 1.
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
**Step 3:** `cargo build -p ubuntu-fidod`. Expected: success.
|
**Step 3:** `cargo build -p authforged`. Expected: success.
|
||||||
|
|
||||||
**Step 4:** Commit.
|
**Step 4:** Commit.
|
||||||
|
|
||||||
@@ -321,17 +321,17 @@ git commit -m "Add daemon crate skeleton"
|
|||||||
|
|
||||||
```toml
|
```toml
|
||||||
[package]
|
[package]
|
||||||
name = "ubuntu-fidoctl"
|
name = "authforgectl"
|
||||||
version.workspace = true
|
version.workspace = true
|
||||||
edition.workspace = true
|
edition.workspace = true
|
||||||
license.workspace = true
|
license.workspace = true
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "ubuntu-fidoctl"
|
name = "authforgectl"
|
||||||
path = "src/main.rs"
|
path = "src/main.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
ubuntu-fido-common = { path = "../common" }
|
authforge-common = { path = "../common" }
|
||||||
clap = { workspace = true }
|
clap = { workspace = true }
|
||||||
anyhow = { workspace = true }
|
anyhow = { workspace = true }
|
||||||
zbus = { workspace = true }
|
zbus = { workspace = true }
|
||||||
@@ -345,7 +345,7 @@ use anyhow::Result;
|
|||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
|
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
#[command(name = "ubuntu-fidoctl", version, about = "Manage ubuntu-fido configuration")]
|
#[command(name = "authforgectl", version, about = "Manage authforge configuration")]
|
||||||
struct Cli {
|
struct Cli {
|
||||||
#[command(subcommand)]
|
#[command(subcommand)]
|
||||||
cmd: Cmd,
|
cmd: Cmd,
|
||||||
@@ -360,7 +360,7 @@ enum Cmd {
|
|||||||
async fn main() -> Result<()> {
|
async fn main() -> Result<()> {
|
||||||
let args = Cli::parse();
|
let args = Cli::parse();
|
||||||
match args.cmd {
|
match args.cmd {
|
||||||
Cmd::Status => println!("ubuntu-fidoctl: not yet implemented"),
|
Cmd::Status => println!("authforgectl: not yet implemented"),
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -379,9 +379,9 @@ git commit -m "Add cli crate skeleton"
|
|||||||
|
|
||||||
**Files:**
|
**Files:**
|
||||||
- Create: `pam/Makefile`
|
- 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
|
```c
|
||||||
#define PAM_SM_AUTH
|
#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,
|
PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags,
|
||||||
int argc, const char **argv) {
|
int argc, const char **argv) {
|
||||||
(void)flags; (void)argc; (void)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 */
|
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
|
CFLAGS ?= -Wall -Wextra -Werror -fPIC -O2
|
||||||
LIBDIR ?= /usr/lib/$(shell dpkg-architecture -qDEB_HOST_MULTIARCH)/security
|
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
|
$(CC) $(CFLAGS) -shared -o $@ $< -lpam
|
||||||
|
|
||||||
install: pam_ubuntu_fido_pending.so
|
install: pam_authforge_pending.so
|
||||||
install -D -m 0644 pam_ubuntu_fido_pending.so $(DESTDIR)$(LIBDIR)/pam_ubuntu_fido_pending.so
|
install -D -m 0644 pam_authforge_pending.so $(DESTDIR)$(LIBDIR)/pam_authforge_pending.so
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f pam_ubuntu_fido_pending.so
|
rm -f pam_authforge_pending.so
|
||||||
|
|
||||||
.PHONY: install clean
|
.PHONY: install clean
|
||||||
```
|
```
|
||||||
@@ -427,7 +427,7 @@ clean:
|
|||||||
cd pam && make && cd ..
|
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.
|
**Step 4:** Commit.
|
||||||
|
|
||||||
@@ -441,8 +441,8 @@ git commit -m "Add PAM module stub"
|
|||||||
**Files:**
|
**Files:**
|
||||||
- Create: `gui/Cargo.toml`
|
- Create: `gui/Cargo.toml`
|
||||||
- Create: `gui/src/main.rs`
|
- Create: `gui/src/main.rs`
|
||||||
- Create: `gui/data/io.dangerousthings.UbuntuFido.desktop`
|
- Create: `gui/data/io.dangerousthings.AuthForge.desktop`
|
||||||
- Create: `gui/data/io.dangerousthings.UbuntuFido.svg` (1KB placeholder icon)
|
- Create: `gui/data/io.dangerousthings.AuthForge.svg` (1KB placeholder icon)
|
||||||
|
|
||||||
**Step 1:** Add `gui` to workspace members in root `Cargo.toml`.
|
**Step 1:** Add `gui` to workspace members in root `Cargo.toml`.
|
||||||
|
|
||||||
@@ -450,19 +450,19 @@ git commit -m "Add PAM module stub"
|
|||||||
|
|
||||||
```toml
|
```toml
|
||||||
[package]
|
[package]
|
||||||
name = "ubuntu-fido-gui"
|
name = "authforge-gui"
|
||||||
version.workspace = true
|
version.workspace = true
|
||||||
edition.workspace = true
|
edition.workspace = true
|
||||||
license.workspace = true
|
license.workspace = true
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "ubuntu-fido"
|
name = "authforge"
|
||||||
path = "src/main.rs"
|
path = "src/main.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
gtk = { package = "gtk4", version = "0.8" }
|
gtk = { package = "gtk4", version = "0.8" }
|
||||||
adw = { package = "libadwaita", version = "0.6" }
|
adw = { package = "libadwaita", version = "0.6" }
|
||||||
ubuntu-fido-common = { path = "../common" }
|
authforge-common = { path = "../common" }
|
||||||
anyhow = { workspace = true }
|
anyhow = { workspace = true }
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -472,7 +472,7 @@ anyhow = { workspace = true }
|
|||||||
use adw::prelude::*;
|
use adw::prelude::*;
|
||||||
use gtk::glib;
|
use gtk::glib;
|
||||||
|
|
||||||
const APP_ID: &str = "io.dangerousthings.UbuntuFido";
|
const APP_ID: &str = "io.dangerousthings.AuthForge";
|
||||||
|
|
||||||
fn main() -> glib::ExitCode {
|
fn main() -> glib::ExitCode {
|
||||||
let app = adw::Application::builder().application_id(APP_ID).build();
|
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
|
||||||
[Desktop Entry]
|
[Desktop Entry]
|
||||||
Name=Authentication
|
Name=Authentication
|
||||||
GenericName=Security Keys & MFA
|
GenericName=Security Keys & MFA
|
||||||
Comment=Manage U2F/FIDO2 keys and authentication policy
|
Comment=Manage U2F/FIDO2 keys and authentication policy
|
||||||
Exec=ubuntu-fido
|
Exec=authforge
|
||||||
Icon=io.dangerousthings.UbuntuFido
|
Icon=io.dangerousthings.AuthForge
|
||||||
Terminal=false
|
Terminal=false
|
||||||
Type=Application
|
Type=Application
|
||||||
Categories=Settings;Security;
|
Categories=Settings;Security;
|
||||||
@@ -515,12 +515,12 @@ Keywords=mfa;u2f;fido2;passkey;totp;security;
|
|||||||
StartupNotify=true
|
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`).
|
**Step 6:** Build (assumes GTK4 / libadwaita dev packages installed: `libgtk-4-dev`, `libadwaita-1-dev`).
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cargo build -p ubuntu-fido-gui
|
cargo build -p authforge-gui
|
||||||
```
|
```
|
||||||
|
|
||||||
Expected: success.
|
Expected: success.
|
||||||
@@ -541,17 +541,17 @@ git commit -m "Add GUI crate skeleton with libadwaita placeholder window"
|
|||||||
- Create: `debian/rules`
|
- Create: `debian/rules`
|
||||||
- Create: `debian/source/format`
|
- Create: `debian/source/format`
|
||||||
- Create: `debian/compat` (or use `debhelper-compat (= 13)` in control)
|
- Create: `debian/compat` (or use `debhelper-compat (= 13)` in control)
|
||||||
- Create: `debian/ubuntu-fido.install`
|
- Create: `debian/authforge.install`
|
||||||
- Create: `debian/ubuntu-fido-daemon.install`
|
- Create: `debian/authforge-daemon.install`
|
||||||
- Create: `debian/ubuntu-fido-daemon.service`
|
- Create: `debian/authforge-daemon.service`
|
||||||
- Create: `debian/ubuntu-fido-pam.install`
|
- Create: `debian/authforge-pam.install`
|
||||||
- Create: `debian/ubuntu-fido-cli.install`
|
- Create: `debian/authforge-cli.install`
|
||||||
- Create: `debian/ubuntu-fido-gui.install`
|
- Create: `debian/authforge-gui.install`
|
||||||
|
|
||||||
**Step 1:** `debian/changelog`:
|
**Step 1:** `debian/changelog`:
|
||||||
|
|
||||||
```
|
```
|
||||||
ubuntu-fido (0.1.0-1) UNRELEASED; urgency=low
|
authforge (0.1.0-1) UNRELEASED; urgency=low
|
||||||
|
|
||||||
* Initial packaging skeleton.
|
* 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:
|
**Step 3:** `debian/control` — declares all 5 binary packages and their relationships:
|
||||||
|
|
||||||
```
|
```
|
||||||
Source: ubuntu-fido
|
Source: authforge
|
||||||
Section: admin
|
Section: admin
|
||||||
Priority: optional
|
Priority: optional
|
||||||
Maintainer: Dangerous Things <ops@dangerousthings.com>
|
Maintainer: Dangerous Things <ops@dangerousthings.com>
|
||||||
@@ -581,46 +581,46 @@ Build-Depends:
|
|||||||
libfido2-dev,
|
libfido2-dev,
|
||||||
pkg-config
|
pkg-config
|
||||||
Standards-Version: 4.6.2
|
Standards-Version: 4.6.2
|
||||||
Homepage: https://github.com/dangerousthings/ubuntu-fido
|
Homepage: https://github.com/dangerousthings/authforge
|
||||||
Vcs-Browser: https://github.com/dangerousthings/ubuntu-fido
|
Vcs-Browser: https://github.com/dangerousthings/authforge
|
||||||
Vcs-Git: https://github.com/dangerousthings/ubuntu-fido.git
|
Vcs-Git: https://github.com/dangerousthings/authforge.git
|
||||||
|
|
||||||
Package: ubuntu-fido
|
Package: authforge
|
||||||
Architecture: any
|
Architecture: any
|
||||||
Depends: ubuntu-fido-daemon (= ${binary:Version}),
|
Depends: authforge-daemon (= ${binary:Version}),
|
||||||
ubuntu-fido-pam (= ${binary:Version}),
|
authforge-pam (= ${binary:Version}),
|
||||||
ubuntu-fido-cli (= ${binary:Version}),
|
authforge-cli (= ${binary:Version}),
|
||||||
${misc:Depends}
|
${misc:Depends}
|
||||||
Recommends: ubuntu-fido-gui (= ${binary:Version})
|
Recommends: authforge-gui (= ${binary:Version})
|
||||||
Suggests: ubuntu-fido-gnome-integration
|
Suggests: authforge-gnome-integration
|
||||||
Description: Turnkey FIDO2/U2F/TOTP MFA for Ubuntu (metapackage)
|
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.
|
(if recommended) GUI.
|
||||||
|
|
||||||
Package: ubuntu-fido-daemon
|
Package: authforge-daemon
|
||||||
Architecture: any
|
Architecture: any
|
||||||
Depends: ${shlibs:Depends}, ${misc:Depends}, libpam-u2f, libfido2-1
|
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,
|
Provides the privileged D-Bus service that orchestrates enrollment,
|
||||||
policy edits, and lockout-prevention checks.
|
policy edits, and lockout-prevention checks.
|
||||||
|
|
||||||
Package: ubuntu-fido-pam
|
Package: authforge-pam
|
||||||
Architecture: any
|
Architecture: any
|
||||||
Depends: ${shlibs:Depends}, ${misc:Depends}, libpam-runtime
|
Depends: ${shlibs:Depends}, ${misc:Depends}, libpam-runtime
|
||||||
Description: PAM module backstopping ubuntu-fido first-login enrollment
|
Description: PAM module backstopping authforge first-login enrollment
|
||||||
Refuses authentication when /var/lib/ubuntu-fido/pending/<user> exists
|
Refuses authentication when /var/lib/authforge/pending/<user> exists
|
||||||
and the user has not completed first-login MFA setup.
|
and the user has not completed first-login MFA setup.
|
||||||
|
|
||||||
Package: ubuntu-fido-cli
|
Package: authforge-cli
|
||||||
Architecture: any
|
Architecture: any
|
||||||
Depends: ${shlibs:Depends}, ${misc:Depends}, ubuntu-fido-daemon
|
Depends: ${shlibs:Depends}, ${misc:Depends}, authforge-daemon
|
||||||
Description: CLI for ubuntu-fido (admin and fleet)
|
Description: CLI for authforge (admin and fleet)
|
||||||
Configure policy, enroll on behalf of users, generate recovery codes.
|
Configure policy, enroll on behalf of users, generate recovery codes.
|
||||||
|
|
||||||
Package: ubuntu-fido-gui
|
Package: authforge-gui
|
||||||
Architecture: any
|
Architecture: any
|
||||||
Depends: ${shlibs:Depends}, ${misc:Depends}, ubuntu-fido-daemon
|
Depends: ${shlibs:Depends}, ${misc:Depends}, authforge-daemon
|
||||||
Description: GTK4/libadwaita UI for ubuntu-fido
|
Description: GTK4/libadwaita UI for authforge
|
||||||
End-user-facing settings panel for enrollment and policy.
|
End-user-facing settings panel for enrollment and policy.
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -640,20 +640,20 @@ override_dh_auto_build:
|
|||||||
|
|
||||||
override_dh_auto_install:
|
override_dh_auto_install:
|
||||||
# Daemon
|
# Daemon
|
||||||
install -D -m 0755 target/release/ubuntu-fidod \
|
install -D -m 0755 target/release/authforged \
|
||||||
debian/ubuntu-fido-daemon/usr/sbin/ubuntu-fidod
|
debian/authforge-daemon/usr/sbin/authforged
|
||||||
# CLI
|
# CLI
|
||||||
install -D -m 0755 target/release/ubuntu-fidoctl \
|
install -D -m 0755 target/release/authforgectl \
|
||||||
debian/ubuntu-fido-cli/usr/bin/ubuntu-fidoctl
|
debian/authforge-cli/usr/bin/authforgectl
|
||||||
# GUI
|
# GUI
|
||||||
install -D -m 0755 target/release/ubuntu-fido \
|
install -D -m 0755 target/release/authforge \
|
||||||
debian/ubuntu-fido-gui/usr/bin/ubuntu-fido
|
debian/authforge-gui/usr/bin/authforge
|
||||||
install -D -m 0644 gui/data/io.dangerousthings.UbuntuFido.desktop \
|
install -D -m 0644 gui/data/io.dangerousthings.AuthForge.desktop \
|
||||||
debian/ubuntu-fido-gui/usr/share/applications/io.dangerousthings.UbuntuFido.desktop
|
debian/authforge-gui/usr/share/applications/io.dangerousthings.AuthForge.desktop
|
||||||
install -D -m 0644 gui/data/io.dangerousthings.UbuntuFido.svg \
|
install -D -m 0644 gui/data/io.dangerousthings.AuthForge.svg \
|
||||||
debian/ubuntu-fido-gui/usr/share/icons/hicolor/scalable/apps/io.dangerousthings.UbuntuFido.svg
|
debian/authforge-gui/usr/share/icons/hicolor/scalable/apps/io.dangerousthings.AuthForge.svg
|
||||||
# PAM
|
# PAM
|
||||||
$(MAKE) -C pam install DESTDIR=$(CURDIR)/debian/ubuntu-fido-pam
|
$(MAKE) -C pam install DESTDIR=$(CURDIR)/debian/authforge-pam
|
||||||
|
|
||||||
override_dh_auto_test:
|
override_dh_auto_test:
|
||||||
cargo test --workspace --release
|
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).
|
**Step 8:** Verify install + remove on a throwaway VM (Multipass shell or LXD container).
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo dpkg -i ../ubuntu-fido*.deb || sudo apt -f install
|
sudo dpkg -i ../authforge*.deb || sudo apt -f install
|
||||||
sudo systemctl status ubuntu-fido.service # will fail until Phase 1 ships unit
|
sudo systemctl status authforge.service # will fail until Phase 1 ships unit
|
||||||
sudo apt purge ubuntu-fido*
|
sudo apt purge authforge*
|
||||||
```
|
```
|
||||||
|
|
||||||
**Step 9:** Commit.
|
**Step 9:** Commit.
|
||||||
@@ -721,7 +721,7 @@ jobs:
|
|||||||
- uses: actions/checkout@v4
|
- 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: 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: 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.
|
**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 build --workspace --release` succeeds.
|
||||||
- [ ] `cargo test --workspace` succeeds (1 test in `common`).
|
- [ ] `cargo test --workspace` succeeds (1 test in `common`).
|
||||||
- [ ] `cargo clippy --workspace -- -D warnings` is clean.
|
- [ ] `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.
|
- [ ] `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`.
|
- [ ] CI is green on `main`.
|
||||||
|
|
||||||
If all check, tag `v0.1.0-scaffolding`:
|
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
|
# 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.**
|
**Re-invoke `superpowers:writing-plans` at start of this phase to expand to step granularity.**
|
||||||
|
|
||||||
**Files to create:**
|
**Files to create:**
|
||||||
- `daemon/src/dbus.rs` — zbus `interface` definition
|
- `daemon/src/dbus.rs` — zbus `interface` definition
|
||||||
- `daemon/src/state.rs` — in-memory state shell
|
- `daemon/src/state.rs` — in-memory state shell
|
||||||
- `debian/ubuntu-fido-daemon.service` — systemd unit
|
- `debian/authforge-daemon.service` — systemd unit
|
||||||
- `debian/io.dangerousthings.UbuntuFido.conf` — D-Bus policy
|
- `debian/io.dangerousthings.AuthForge.conf` — D-Bus policy
|
||||||
- `debian/io.dangerousthings.UbuntuFido.service` — D-Bus activation file
|
- `debian/io.dangerousthings.AuthForge.service` — D-Bus activation file
|
||||||
- `debian/io.dangerousthings.UbuntuFido.policy` — polkit actions
|
- `debian/io.dangerousthings.AuthForge.policy` — polkit actions
|
||||||
- `debian/ubuntu-fido-daemon.postinst` — enable + start unit
|
- `debian/authforge-daemon.postinst` — enable + start unit
|
||||||
|
|
||||||
**D-Bus interface skeleton:**
|
**D-Bus interface skeleton:**
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
#[zbus::interface(name = "io.dangerousthings.UbuntuFido1")]
|
#[zbus::interface(name = "io.dangerousthings.AuthForge1")]
|
||||||
impl UbuntuFido {
|
impl AuthForge {
|
||||||
async fn list_credentials(&self, user: String) -> zbus::fdo::Result<Vec<Credential>> { ... }
|
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 enroll_own(&self, user: String, nickname: String) -> zbus::fdo::Result<Credential> { ... }
|
||||||
async fn remove_own(&self, user: String, cred_id: String) -> zbus::fdo::Result<()> { ... }
|
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 |
|
| Action | Default for active session |
|
||||||
|---|---|
|
|---|---|
|
||||||
| `io.dangerousthings.UbuntuFido.enroll-own` | `auth_self_keep` |
|
| `io.dangerousthings.AuthForge.enroll-own` | `auth_self_keep` |
|
||||||
| `io.dangerousthings.UbuntuFido.remove-own` | `auth_self_keep` |
|
| `io.dangerousthings.AuthForge.remove-own` | `auth_self_keep` |
|
||||||
| `io.dangerousthings.UbuntuFido.enroll-other` | `auth_admin_keep` |
|
| `io.dangerousthings.AuthForge.enroll-other` | `auth_admin_keep` |
|
||||||
| `io.dangerousthings.UbuntuFido.set-policy` | `auth_admin_keep` |
|
| `io.dangerousthings.AuthForge.set-policy` | `auth_admin_keep` |
|
||||||
| `io.dangerousthings.UbuntuFido.set-pending` | `auth_admin_keep` |
|
| `io.dangerousthings.AuthForge.set-pending` | `auth_admin_keep` |
|
||||||
| `io.dangerousthings.UbuntuFido.clear-pending` | `auth_admin_keep` |
|
| `io.dangerousthings.AuthForge.clear-pending` | `auth_admin_keep` |
|
||||||
| `io.dangerousthings.UbuntuFido.generate-recovery` | `auth_admin_keep` |
|
| `io.dangerousthings.AuthForge.generate-recovery` | `auth_admin_keep` |
|
||||||
|
|
||||||
**Tasks:**
|
**Tasks:**
|
||||||
1. Add zbus interface module with stubs returning fixture data.
|
1. Add zbus interface module with stubs returning fixture data.
|
||||||
2. Wire up `connection.request_name("io.dangerousthings.UbuntuFido")`.
|
2. Wire up `connection.request_name("io.dangerousthings.AuthForge")`.
|
||||||
3. Write systemd unit (`Type=dbus`, `BusName=io.dangerousthings.UbuntuFido`, `User=root`).
|
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).
|
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.
|
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`.
|
6. Wire postinst: `systemctl daemon-reload && systemctl enable --now authforge.service`.
|
||||||
7. Test: `busctl call io.dangerousthings.UbuntuFido /io/dangerousthings/UbuntuFido io.dangerousthings.UbuntuFido1 ListCredentials s "$USER"` returns the fixture data.
|
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.
|
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.
|
**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
|
# 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:**
|
**Files:**
|
||||||
- `common/src/policy.rs` — fully implemented TOML parser with last-key-wins merge
|
- `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/policy.rs` — read/write policy.d/ dir, inotify watcher
|
||||||
- `daemon/src/storage/pending.rs` — read/write pending flags
|
- `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/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:**
|
**Tasks:**
|
||||||
1. Implement `Policy::load_from_dir(path)` with merge semantics. TDD: write 3 test fixture dirs, assert merge order.
|
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:**
|
**Files:**
|
||||||
- `daemon/src/policy_apply/mod.rs`
|
- `daemon/src/policy_apply/mod.rs`
|
||||||
- `daemon/src/policy_apply/profile.rs` — generates the pam-configs file dynamically
|
- `daemon/src/policy_apply/profile.rs` — generates the pam-configs file dynamically
|
||||||
- `debian/ubuntu-fido-pam.install` — ships the static pam-configs profile
|
- `debian/authforge-pam.install` — ships the static pam-configs profile
|
||||||
- `debian/ubuntu-fido-daemon.postinst` — runs `pam-auth-update --package` on install
|
- `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:**
|
**Tasks:**
|
||||||
1. Write template renderer.
|
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.
|
**Goal:** The C module that backstops first-login enrollment. Replaces the Phase 0 stub.
|
||||||
|
|
||||||
**Files:**
|
**Files:**
|
||||||
- `pam/pam_ubuntu_fido_pending.c` — full implementation
|
- `pam/pam_authforge_pending.c` — full implementation
|
||||||
- `pam/Makefile` — already exists from Phase 0
|
- `pam/Makefile` — already exists from Phase 0
|
||||||
|
|
||||||
**Behavior:**
|
**Behavior:**
|
||||||
- `pam_sm_authenticate`:
|
- `pam_sm_authenticate`:
|
||||||
1. Get `PAM_USER`.
|
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:
|
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."
|
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`.
|
4. If no flag: return `PAM_IGNORE`.
|
||||||
- `pam_sm_setcred`: `PAM_SUCCESS`.
|
- `pam_sm_setcred`: `PAM_SUCCESS`.
|
||||||
@@ -928,11 +928,11 @@ Returns a list of (user, stack, reason) violations.
|
|||||||
3. Add structured logging via `pam_syslog`.
|
3. Add structured logging via `pam_syslog`.
|
||||||
4. Test with `pamtester`:
|
4. Test with `pamtester`:
|
||||||
```
|
```
|
||||||
sudo touch /var/lib/ubuntu-fido/pending/alice
|
sudo touch /var/lib/authforge/pending/alice
|
||||||
pamtester ubuntu-fido alice authenticate
|
pamtester authforge alice authenticate
|
||||||
# expect: failure with our message
|
# expect: failure with our message
|
||||||
sudo rm /var/lib/ubuntu-fido/pending/alice
|
sudo rm /var/lib/authforge/pending/alice
|
||||||
pamtester ubuntu-fido alice authenticate
|
pamtester authforge alice authenticate
|
||||||
# expect: success (PAM_IGNORE → other modules carry it)
|
# 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.
|
**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:**
|
**Subcommands:**
|
||||||
|
|
||||||
```
|
```
|
||||||
ubuntu-fidoctl status
|
authforgectl status
|
||||||
ubuntu-fidoctl enroll [--user USER] [--nickname NAME]
|
authforgectl enroll [--user USER] [--nickname NAME]
|
||||||
ubuntu-fidoctl list [--user USER]
|
authforgectl list [--user USER]
|
||||||
ubuntu-fidoctl remove [--user USER] CRED_ID
|
authforgectl remove [--user USER] CRED_ID
|
||||||
ubuntu-fidoctl policy show
|
authforgectl policy show
|
||||||
ubuntu-fidoctl policy set <stack> <mode> [--methods METHOD,...]
|
authforgectl policy set <stack> <mode> [--methods METHOD,...]
|
||||||
ubuntu-fidoctl policy apply [--force-i-know-what-im-doing]
|
authforgectl policy apply [--force-i-know-what-im-doing]
|
||||||
ubuntu-fidoctl policy validate
|
authforgectl policy validate
|
||||||
ubuntu-fidoctl pending set USER [--methods METHOD,...]
|
authforgectl pending set USER [--methods METHOD,...]
|
||||||
ubuntu-fidoctl pending clear USER
|
authforgectl pending clear USER
|
||||||
ubuntu-fidoctl pending list
|
authforgectl pending list
|
||||||
ubuntu-fidoctl recovery generate USER
|
authforgectl recovery generate USER
|
||||||
ubuntu-fidoctl recovery list USER
|
authforgectl recovery list USER
|
||||||
```
|
```
|
||||||
|
|
||||||
**Output:** human-readable by default; `--json` flag for machine-parseable output (essential for Ansible integration).
|
**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:**
|
**Files:**
|
||||||
- `gui/src/views/firstrun.rs` — fullscreen modal mode
|
- `gui/src/views/firstrun.rs` — fullscreen modal mode
|
||||||
- `gui/data/ubuntu-fido-firstrun.desktop` — autostart entry
|
- `gui/data/authforge-firstrun.desktop` — autostart entry
|
||||||
- `debian/ubuntu-fido-gui.install` — install autostart entry to `/etc/xdg/autostart/`
|
- `debian/authforge-gui.install` — install autostart entry to `/etc/xdg/autostart/`
|
||||||
- `gui/src/main.rs` — handle `--first-run` CLI flag
|
- `gui/src/main.rs` — handle `--first-run` CLI flag
|
||||||
|
|
||||||
**Tasks:**
|
**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.
|
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.
|
3. Show welcome page + run enrollment flow.
|
||||||
4. On successful enrollment, call `clear_pending_flag` via D-Bus, exit cleanly.
|
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):**
|
**Test (manual, in VM):**
|
||||||
1. `useradd -m testuser`, `passwd testuser` (set tempPW), `chage -d 0 testuser`.
|
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.
|
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.
|
**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/Cargo.toml` — add `totp` feature
|
||||||
- `daemon/src/totp/mod.rs` — secret generation, recovery codes
|
- `daemon/src/totp/mod.rs` — secret generation, recovery codes
|
||||||
- `gui/src/views/totp.rs` — QR code display, secret enrollment
|
- `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
|
- `debian/control` — `Recommends: libpam-google-authenticator` when feature enabled
|
||||||
|
|
||||||
**Tasks:**
|
**Tasks:**
|
||||||
@@ -1077,9 +1077,9 @@ ubuntu-fidoctl recovery list USER
|
|||||||
- `gui/src/views/recovery.rs`
|
- `gui/src/views/recovery.rs`
|
||||||
|
|
||||||
**Tasks:**
|
**Tasks:**
|
||||||
1. `generate_recovery_code(user)` writes `/var/lib/ubuntu-fido/recovery/<user>` (root-owned, 0600) containing Argon2id hash + expiry timestamp.
|
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/ubuntu-fido/pending/<user>` flag with `re_enroll = true`.
|
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: `ubuntu-fidoctl recovery generate alice` outputs the 8-digit code.
|
3. CLI: `authforgectl recovery generate alice` outputs the 8-digit code.
|
||||||
4. GUI: "Recovery" tab shows generate / list / revoke.
|
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.
|
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.
|
**Goal:** All packages install cleanly, postinst/prerm/postrm scripts handle every state transition correctly, debconf preseed works.
|
||||||
|
|
||||||
**Files:**
|
**Files:**
|
||||||
- `debian/ubuntu-fido-daemon.{postinst,prerm,postrm}`
|
- `debian/authforge-daemon.{postinst,prerm,postrm}`
|
||||||
- `debian/ubuntu-fido-pam.{postinst,prerm,postrm}`
|
- `debian/authforge-pam.{postinst,prerm,postrm}`
|
||||||
- `debian/ubuntu-fido.config` — debconf script
|
- `debian/authforge.config` — debconf script
|
||||||
- `debian/ubuntu-fido.templates` — debconf templates
|
- `debian/authforge.templates` — debconf templates
|
||||||
|
|
||||||
**Tasks:**
|
**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.
|
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)".
|
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.
|
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.
|
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
|
# 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:**
|
**Tasks:**
|
||||||
1. Create Launchpad team `dangerousthings` (or use existing).
|
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).
|
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.
|
5. Wait for build, verify install on a fresh VM.
|
||||||
6. Document signing key fingerprint in README.
|
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:**
|
**Files:**
|
||||||
- New source tree under `gnome-integration/` (separate Cargo workspace member or pure-data deb)
|
- 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.
|
**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.
|
3. Test against current Ubuntu LTS GNOME version.
|
||||||
4. Pin Recommends to specific gnome-control-center major version range.
|
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
|
# 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):**
|
**Files (in a separate `ansible-role` tree, possibly its own repo):**
|
||||||
- `ansible-role/tasks/main.yml`
|
- `ansible-role/tasks/main.yml`
|
||||||
@@ -1156,7 +1156,7 @@ ubuntu-fidoctl recovery list USER
|
|||||||
- `ansible-role/meta/main.yml`
|
- `ansible-role/meta/main.yml`
|
||||||
|
|
||||||
**Tasks:**
|
**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.
|
2. Variables for: enabled stacks, modes per stack, central credential storage on/off, default firstrun methods.
|
||||||
3. Examples in `examples/playbook.yml`.
|
3. Examples in `examples/playbook.yml`.
|
||||||
4. Publish to Galaxy.
|
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/fleet-deployment.md`
|
||||||
- `docs/user/recovery.md`
|
- `docs/user/recovery.md`
|
||||||
- `docs/user/troubleshooting.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:**
|
**Tasks:**
|
||||||
1. Getting started: end-user view of "install + enroll my Yubikey + require it for sudo".
|
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:
|
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:
|
> Two execution options:
|
||||||
>
|
>
|
||||||
@@ -1,15 +1,15 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "ubuntu-fido-gui"
|
name = "authforge-gui"
|
||||||
version.workspace = true
|
version.workspace = true
|
||||||
edition.workspace = true
|
edition.workspace = true
|
||||||
license.workspace = true
|
license.workspace = true
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "ubuntu-fido"
|
name = "authforge"
|
||||||
path = "src/main.rs"
|
path = "src/main.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
gtk = { package = "gtk4", version = "0.8" }
|
gtk = { package = "gtk4", version = "0.8" }
|
||||||
adw = { package = "libadwaita", version = "0.6" }
|
adw = { package = "libadwaita", version = "0.6" }
|
||||||
ubuntu-fido-common = { path = "../common" }
|
authforge-common = { path = "../common" }
|
||||||
anyhow = { workspace = true }
|
anyhow = { workspace = true }
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
Name=Authentication
|
Name=Authentication
|
||||||
GenericName=Security Keys & MFA
|
GenericName=Security Keys & MFA
|
||||||
Comment=Manage U2F/FIDO2 keys and authentication policy
|
Comment=Manage U2F/FIDO2 keys and authentication policy
|
||||||
Exec=ubuntu-fido
|
Exec=authforge
|
||||||
Icon=io.dangerousthings.UbuntuFido
|
Icon=io.dangerousthings.AuthForge
|
||||||
Terminal=false
|
Terminal=false
|
||||||
Type=Application
|
Type=Application
|
||||||
Categories=Settings;Security;
|
Categories=Settings;Security;
|
||||||
|
Before Width: | Height: | Size: 440 B After Width: | Height: | Size: 440 B |
@@ -1,7 +1,7 @@
|
|||||||
use adw::prelude::*;
|
use adw::prelude::*;
|
||||||
use gtk::glib;
|
use gtk::glib;
|
||||||
|
|
||||||
const APP_ID: &str = "io.dangerousthings.UbuntuFido";
|
const APP_ID: &str = "io.dangerousthings.AuthForge";
|
||||||
|
|
||||||
fn main() -> glib::ExitCode {
|
fn main() -> glib::ExitCode {
|
||||||
let app = adw::Application::builder().application_id(APP_ID).build();
|
let app = adw::Application::builder().application_id(APP_ID).build();
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
CFLAGS ?= -Wall -Wextra -Werror -fPIC -O2
|
CFLAGS ?= -Wall -Wextra -Werror -fPIC -O2
|
||||||
LIBDIR ?= /usr/lib/$(shell dpkg-architecture -qDEB_HOST_MULTIARCH)/security
|
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
|
$(CC) $(CFLAGS) -shared -o $@ $< -lpam
|
||||||
|
|
||||||
install: pam_ubuntu_fido_pending.so
|
install: pam_authforge_pending.so
|
||||||
install -D -m 0644 pam_ubuntu_fido_pending.so $(DESTDIR)$(LIBDIR)/pam_ubuntu_fido_pending.so
|
install -D -m 0644 pam_authforge_pending.so $(DESTDIR)$(LIBDIR)/pam_authforge_pending.so
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f pam_ubuntu_fido_pending.so
|
rm -f pam_authforge_pending.so
|
||||||
|
|
||||||
.PHONY: install clean
|
.PHONY: install clean
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags,
|
PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags,
|
||||||
int argc, const char **argv) {
|
int argc, const char **argv) {
|
||||||
(void)flags; (void)argc; (void)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 */
|
return PAM_IGNORE; /* implemented in Phase 6 */
|
||||||
}
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user