canonical / canonical/authd

authd: option to hide the local broker from the GDM broker picker for OIDC-only deployments

Open
#1,497 2 comments 0 reactions 0 assignees View on GitHub
Dominant language
Go
Stars
308
Forks
41
Avg merge
2d 4h
Merged PRs (30d)
58

Description

## Summary

For deployments where every authenticated GDM user is expected to come from a single configured broker (e.g. an OIDC broker pointed at the org's IdP), the **`local` broker is unconditionally surfaced in the GDM broker picker** when the user clicks "Not listed?" → enters their email. There is currently no way to hide it.

In our deployment (corporate laptops, Okta as the only intended sign-in path, plus a vault-managed local `recovery` admin account that operators only ever reach via TTY or out-of-band sudo) this causes real user confusion: end-users see two buttons — `OIDC` (or whatever `name = ...` is set to in `oidc.conf`) and `local` — and pick `local`, which then prompts for a Unix password they don't have. The result is identical to #1359: an apparent "wrong password" dead end at GDM, with no diagnostic.

The IT team's specific feedback was: *"users don't expect to be able to have a local account; the `local` button is confusing, please hide it."*

## Versions

- `authd` deb 0.5.5 from `ppa:ubuntu-enterprise-desktop/authd` on Ubuntu 24.04.3
- `authd-oidc` snap 0.4.0 (patched per #1476 + #1496, but unrelated to this issue)
- Identity provider: Okta Org Authorization Server

## Why the existing knobs don't address this

- **#1234 (`disable_local_password` in `broker.conf`)** affects the **OIDC broker's own** `Password` auth mode (the post-OIDC "set offline password" prompt), not the `id="local"` broker registered by the daemon. The local button in the picker would still appear.
- **#1124** (per-PAM-service disable, e.g. `disable_local_password = gdm`) is the right shape and I see @adombeck's sketch in the comments matches our use case, but it's been backlogged and the `jira` label was removed in Jan; we'd love to see this revived (and would gladly contribute) but want to flag the narrower picker-only flavour separately because it's a much smaller change.
- Removing the local broker's `.conf` doesn't help — there is no `.conf`. The local broker is registered unconditionally:
```go
// First broker is always the local one.
b, err := newBroker(ctx, "", nil)
brokersOrder = append(brokersOrder, b.ID)
brokers[b.ID] = &b
```
([`internal/brokers/manager.go`](https://github.com/canonical/authd/blob/main/internal/brokers/manager.go), `NewManager`)

## What "hide" means here

Important: hiding the local broker from the **picker UI** only is enough. The daemon should still register it so internal consumers (`BrokerFromSessionID("")`, NSS lookups for already-bound users, etc.) keep working. The change is purely "don't ship `id="local"` to GDM in the `brokersReceived` event when the operator opts in."

For users in our setup, hiding the local broker from the picker has no functional regression:
- The local recovery user can still log in via TTY (Ctrl+Alt+F2–F6), since TTYs don't go through the broker picker.
- The local recovery user can still log in via GDM when picked from the user list / typed by name — GDM bypasses the picker for already-known users assigned to the local broker.
- Sudo, screen-unlock, etc. continue to use the local password normally.

## Proposed shape

A daemon-level config knob, off by default, e.g. in `/etc/authd/authd.yaml`:

```yaml
# When true, the local broker is registered as usual but is filtered out of the
# AvailableBrokers() response sent to the broker chooser (typically GDM). Use this
# in OIDC-only deployments where a "local" entry in the picker is confusing and
# never selectable to a meaningful outcome.
hide_local_broker_in_picker: false
```

Implementation is ~10 lines in `Manager.AvailableBrokers()`:

```go
func (m *Manager) AvailableBrokers() (r []*Broker) {
for _, id := range m.brokersOrder {
if m.hideLocalInPicker && id == LocalBrokerName {
continue
}
r = append(r, m.brokers[id])
}
return r
}
```

Plus daemon-config plumbing and a test. Happy to file the PR if the API is acceptable; please tell me if you'd prefer a different flag name, scope (per-broker config vs daemon config), or shape.

## Workaround we are using today

None inside `authd`. We've considered carrying a downstream-patched `authd` deb with the filter applied unconditionally, but would much prefer an upstream knob.

cc @adombeck @3v1n0 (you both touched the closely-related #1357 / #1359 / #1124).

Contributor guide

Open the contributing guide

Research direction

Start in internal/brokers/manager.go, especially NewManager and AvailableBrokers, then trace the daemon configuration plumbing and existing broker tests. Add an opt-in setting that keeps the local broker registered but excludes it from the AvailableBrokers response; done means the configured picker omits local while internal local-broker consumers continue to work.

Written by the indexing model from the issue text.

Assessment

Tech stack
go
Domain
authentication, backend
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
58/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.