Feature Specification: Accounts and Ownership

Created: 2026-09-23

Status: Implemented

Input: Reconstructed from the code at 0bf4ecd36 (panel/src/panel/oidc.py, settings.py, context_processors.py, models.py, views.py, urls.py, templates/registration/login.html), pull requests #966, #967, #1129, #1248 and #1645, issues #241 and #313, api/specification.md (section "Deployment identifiers"), and the design notes of the maintainers.

User Scenarios & Testing (mandatory)

User Story 1 - Log in with the identity provider of the operator (Priority: P1)

An operator logs in to the panel with single sign-on (OpenID Connect). The panel finds the account by the email address, or makes a new account. The user name comes from the preferred_username claim.

Why this priority: the account is the key of all ownership in the panel.

Independent Test: run panel-python-tests (test_oidc.py). With an issuer, a client identifier and a client secret, the login page shows "Log in with {OIDC_DISPLAY_NAME}".

Acceptance Scenarios:

  1. Given an issuer, a client identifier and a client secret, When an operator opens the login page, Then the page offers single sign-on, and keeps the next target.
  2. Given that one of the three values is missing, When an operator opens the login page, Then the page offers only the password login.
  3. Given a new identity with the email of an existing account, When the operator logs in, Then the panel uses the existing account.

User Story 2 - Log in with a password (Priority: P2)

Without an identity provider, an operator logs in with a local user name and password.

Why this priority: development and small setups have no identity provider.

Independent Test: run panel-python-tests (test_login.py).

Acceptance Scenarios:

  1. Given a local account, When the operator logs in with the correct password, Then the panel opens the list of deployments.
  2. Given a logged-in operator, When the operator logs out, Then the panel session ends. The session of the identity provider stays.

User Story 3 - See only my own deployments (Priority: P1)

Each deployment has one owner. An operator sees and changes only the deployments that they own.

Why this priority: the panel is multi-tenant. A leak between tenants is a security failure.

Independent Test: run panel-python-tests (test_deployment_form.py). Operator B gets 404 for each page and action on a deployment of operator A.

Acceptance Scenarios:

  1. Given two operators with deployments, When one operator opens the list, Then the list shows only the deployments of that operator.
  2. Given a deployment of another operator, When an operator opens, saves, duplicates or deletes it, Then the panel returns 404 and changes nothing.

Edge Cases

  • The client secret file is missing: the panel starts, and offers only the password login. Other read errors of a secret file give a warning in the log.
  • The client secret changes: the panel restarts and reads the new secret.
  • The account of an owner is removed: the panel first queues the destroy of each deployment of the account through api, then removes the account and its deployments. If api does not queue a destroy, the removal does not occur, and the admin sees the error.

Requirements (mandatory)

Functional Requirements

  • FR-001: The panel MUST offer single sign-on only when the issuer, the client identifier and the client secret are all set.
  • FR-002: The panel MUST keep the password login available.
  • FR-003: The panel MUST keep the ownership of a deployment in its own database, and MUST use primary keys, not user names, as the keys in deployment identifiers, event channel names, tokens and the callback sub.
  • FR-004: The panel MUST limit each page, action and proxy call to the deployments of the operator that is logged in.
  • FR-005: The panel MUST NOT take the identity of a user from api.
  • FR-006: The panel MUST match a deployment identifier or a channel name only to the str(pk) of a deployment of the operator, with one database query for all identifiers of a call.
  • FR-007: When the account of an owner is removed, the panel MUST destroy the deployments of that account, and their live infrastructure, through api.

Key Entities

  • Operator: a user account of the panel. Its primary key is the key of ownership.
  • Deployment: a record of intent that one operator owns.
  • Deployment identifier: str(pk) of the deployment, a UUID. The panel makes it, and api treats it as opaque.

Success Criteria (mandatory)

Measurable Outcomes

  • SC-001: No page, action or proxy call gives data of a deployment to an operator who does not own it.
  • SC-002: An operator can log in with single sign-on, or with a password when no identity provider is configured.

Assumptions

  • The identity provider gives a stable preferred_username. Ownership does not depend on the user name, so a change of a user name keeps the deployments of that user. A trusted backend names the user by the user name in X-On-Behalf-Of.

Known Deviations

None.