Skip to content

Use pas.plugins.identity for authentication, with Person as the user type - #140

Draft
ericof wants to merge 6 commits into
mainfrom
issue-604
Draft

ericof wants to merge 6 commits into
mainfrom
issue-604

Conversation

@ericof

@ericof ericof commented Sep 30, 2026

Copy link
Copy Markdown
Contributor

Replaces pas.plugins.oidc and pas.plugins.authomatic with pas.plugins.identity for new sites, with Person as the user content type.

Refs: https://gitlab.kitconcept.io/kitconcept/distribution-kitconcept-intranet/-/issues/604

⚠️ Breaking change

Site creation now refuses the keycloak, oidc, authomatic-github and authomatic-google providers with UnsupportedAuthenticationProvider, and the error names the replacement. The shared schema definitions injected into every distribution's schema changed from keycloak, oidc, authomatic-github and authomatic-google to identity-keycloak, identity-oidc, identity-github and identity-google.

Before a distribution bumps kitconcept.core, it has to update its schema.json to the identity-* providers. Existing sites keep their pas.plugins.oidc and pas.plugins.authomatic configuration.

What changed

Users as Person

  • pas.plugins.identity (1.0.0a13) is always installed, as a dependency of kitconcept.core:dependencies.
  • Each user account is a Person in /users, a PrincipalsContainer that allows only Person. Groups stay in source_groups.
  • The Person schema extends IUserContent. A subscriber marks only the Persons created with a login as IUserProfile, so other Persons, such as team pages, stay plain content and are never listed as users.
  • Person gets the user attributes the identity plugins read (userid, login, fullname, emails, email, verified_emails), plus an optional kitconcept.core.person_emails behavior.
  • fullname returns exactly the name a provider last wrote. Because of that, a later login can still update the name, and a name edited on the Person is kept.
  • UserProfile and UserGroup are no longer globally addable.
  • Upgrade step 20260929001 installs the add-on on existing sites and creates a Person for each user in source_users.

Authentication providers

  • New site creation providers: identity-keycloak, identity-oidc, identity-github and identity-google. They're configured with identity-* answers or SITE_AUTHENTICATION_IDENTITY-* environment variables. An optional identity-site-url sets the callback URL to <site-url>/login-identity.
  • With identity-keycloak, the realm's groups come from pas.plugins.keycloakgroups, and Plone userids are minted from the Keycloak sub, which is the user id that plugin looks up.
  • internal (Plone login) stays, and remains the default.
  • The SITE_AUTHENTICATION_OIDC-* and SITE_AUTHENTICATION_AUTHOMATIC-* environment variables are ignored, with a warning.
  • setup_oidc_auth, setup_keycloak_auth and setup_authomatic are deprecated and emit a DeprecationWarning.
  • The testing distribution offers only internal and the identity-* providers.

Upstream work

While integrating, we found three problems in pas.plugins.identity. All are fixed and released in 1.0.0a13:

Tests

  • 524 tests pass, and make lint is clean. mypy shows only the 3 errors that main already has.
  • New login tests: federated and source_users logins create a Person, the name claim is synced and updated, every user is listed exactly once, and a Person without a login is never listed. On 1.0.0a12, 10 of these tests fail or error.
  • Mutation checks were run for:
    • the refusal of the old providers;
    • the Keycloak groups setup;
    • the userid_source default;
    • the empty group_content_type;
    • the fullname getter.

Not in this PR

  • Downstream distributions (kitconcept-intranet, kitconcept-website):
    • update schema.json to the identity-* providers;
    • replace the oidc/authomatic frontend login with @plone-collective/volto-identity, which hides the Plone password form by default.
  • Migrating existing sites off pas.plugins.oidc and pas.plugins.authomatic (provider configuration and user links). Upstream ships migration/oidc.py and migration/authomatic.py; this will be a follow-up issue.
  • A live Keycloak check of groups with sub userids. The client's service account needs to be able to view users and query groups.

ericof and others added 6 commits September 29, 2026 19:57
Install pas.plugins.identity with the dependencies profile, and represent
each user account as a Person in /users. Groups stay in source_groups,
and Person objects that are not accounts, like team pages, stay plain
content.

- Patch pas.plugins.identity 1.0.0a11 to use Person instead of the
  hardcoded UserProfile, and no group content type
- Person schema extends IUserContent; Person gets the user attributes
  (userid, login, fullname, emails, email, verified_emails) and an
  optional email addresses behavior
- A Person created with a login is marked as a user profile
- Disallow UserProfile and UserGroup globally
- Upgrade step 20260929001 installs the add-on and creates a Person for
  each user in source_users
- New identity-keycloak, identity-oidc, identity-github and
  identity-google site creation providers, side by side with the
  pas.plugins.oidc and pas.plugins.authomatic ones

Upstream: collective/pas-plugins-identity#127

Refs: https://gitlab.kitconcept.io/kitconcept/distribution-kitconcept-intranet/-/issues/604
1.0.0a12 reads user_content_type and group_content_type everywhere
instead of hardcoding UserProfile and UserGroup (upstream #127), so the
patch that rewrote PROFILE_PORTAL_TYPE in its modules is removed. Only
the user attributes of Person are still patched.

The type records are now seeded once at install and left to the site,
so the dependencies profile sets user_content_type to Person and an
empty group_content_type, keeping groups in source_groups.

- Replace the patch tests with checks on principal_types
- Test that new groups stay in source_groups, with no UserGroup content

Known gap until upstream #129: ensure_profile only creates the user type
when the type provides IUserProfile, so a first login no longer creates
a Person.

Upstream: collective/pas-plugins-identity#129

Refs: https://gitlab.kitconcept.io/kitconcept/distribution-kitconcept-intranet/-/issues/604
Site creation now refuses the keycloak, oidc, authomatic-github and
authomatic-google providers, naming the identity-* replacement, so any
distribution based on kitconcept.core creates sites with
pas.plugins.identity or plain Plone authentication only.

- Raise UnsupportedAuthenticationProvider for the old providers
- Deprecate setup_oidc_auth, setup_keycloak_auth and setup_authomatic
- Replace the shared schema definitions with identity-keycloak,
  identity-oidc, identity-github and identity-google
- Ignore the SITE_AUTHENTICATION_OIDC-* and AUTHOMATIC-* environment
  variables, with a warning
- Offer only internal and the identity-* providers in the testing
  schema, without the "Identity:" title prefix
- identity-keycloak installs pas.plugins.keycloakgroups for the realm
  groups, and mints userids from the Keycloak sub, the user id the
  groups plugin looks up
- Replace the old provider site creation tests, and fix two
  profile-installed tests that passed with the profile missing

Refs: https://gitlab.kitconcept.io/kitconcept/distribution-kitconcept-intranet/-/issues/604
pas.plugins.identity writes a name claim only over the value it wrote
itself. Person.fullname returned the Person title, which broke that in
two ways:

- A Person without names has the title "None" (collective.person formats
  a missing first name that way), so the first login never wrote the
  name
- The title utility does not round-trip the written value (last_first
  gives "Hopper, Grace", extra spaces collapse), so no later login could
  update the name

The getter now returns exactly the full name last written while the
first and last name still split from it, and the names joined once they
are edited, so a provider keeps a name it owns and leaves an edited one
alone.

Refs: https://gitlab.kitconcept.io/kitconcept/distribution-kitconcept-intranet/-/issues/604
1.0.0a13 creates the site's user type at login when the site marks its
objects IUserProfile one by one (upstream #129), and lists users that
only have a profile in api.user.get_users() and listMembers() (upstream
#131). With Person as the user type, an SSO first login now creates the
Person, and federated users are listed once.

- Test that federated and source_users logins create a Person, that the
  name claim is synced and updated, and that every user is listed once
  while a Person without login is never listed

Upstream: collective/pas-plugins-identity#130

Refs: https://gitlab.kitconcept.io/kitconcept/distribution-kitconcept-intranet/-/issues/604
@ericof
ericof requested a review from sneridagh September 30, 2026 18:59

@sneridagh sneridagh left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! Sorry for the delay.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants