[Web] Add SCIM 2.0 provider for IdP user provisioning#7148
[Web] Add SCIM 2.0 provider for IdP user provisioning#7148Fly7113 wants to merge 6 commits intomailcow:stagingfrom
Conversation
|
Fixes #6974 |
|
Just a small testing update: in these past few days I had the chance to test this PR on my production system, alongside Authentik as SCIM and OIDC IdP. As far as I'm concerned all the features are working as expected, even in a fully production system having users with mixed The are only two things of which I'm not fully convinced:
Before moving forward with a decision I'd like to hear the consensus of the maintainers team. |
|
Sorry for pushing these new quite conspicuous two commits, but in these further days of testing I realised that the UI (and part of the logic about the IP check) was badly done, so I decided to work on it. |
Implements a SCIM 2.0 (RFC 7643/7644) server endpoint so any Identity Provider — Keycloak, Entra ID, Okta, or any LDAP/OIDC IdP — can push user lifecycle events to mailcow in real time, independently of whichever login protocol is configured. ## Protocol support - Full Users CRUD: POST, GET, PUT, PATCH (RFC 7644 §3.5.2), DELETE - SCIM DELETE is a soft-deactivate (active=0); mail data is never removed - Filtering: filter=userName eq "..." on list endpoint - Pagination: startIndex / count - Discovery: ServiceProviderConfig, Schemas, ResourceTypes - Groups: out of scope ## Authentication & token management Bearer tokens are generated in the admin UI (System > Configuration > Access > SCIM). The raw token is shown once at creation and never stored; only its SHA-256 hash is kept. Each token supports: - Optional domain restriction (limits which mailboxes the token can manage) - Optional mailbox template (applied on user creation) - Optional IP allow-list / skip-IP-check flag - Active/inactive toggle ## Database schema Two new tables added via the existing init_db migration mechanism: - scim_tokens: stores token metadata and hashed credentials - scim_maps: maps IdP externalId values to mailcow usernames per token The mailbox.authsource ENUM is extended with 'scim'. ## Authsource & login design SCIM is a provisioning protocol, not an authentication protocol. mailbox.authsource='scim' records who manages the user; login is handled by the globally configured IAM provider: - Keycloak / Generic-OIDC: SCIM users pass through the existing verify-sso OIDC flow (identity_provider 'verify-sso' case). - LDAP: SCIM users authenticate via ldap_mbox_login(), with full TFA support, matching the behaviour of authsource='ldap' users. - No IAM configured: SCIM users cannot log in; the admin UI shows a warning on the SCIM configuration tab. Attempting a password login as a SCIM user when an OIDC provider is configured returns a clear error directing the user to their IdP. ## Claiming pre-existing users A SCIM POST for a user who already has authsource='scim' (e.g. set manually by the admin to prepare a migration) is treated as a claim: attributes are updated, scim_maps is upserted, and 200 is returned. A SCIM POST for a user managed by a different authsource returns 409 with an actionable message explaining how to transfer ownership. ## Admin UI - New SCIM tab under System > Configuration > Access (alongside Identity Provider settings) - Token table with active toggle and delete; one-time raw token modal - Mailbox edit form gains a SCIM authsource option, shown only when SCIM tokens exist (or the mailbox is already set to SCIM) - Contextual warning when no external IdP is configured for login
Restored the original protocol detection that was modified during development and badly restored. Updated the SCIM base URL building to avoid hardcoded protocol.
The flag was redundant: the IP check logic already skips enforcement when allow_from is empty, making "Allow from any IP" equivalent to leaving the IP list blank. Removing it simplifies the data model and the UI — an empty allow_from means unrestricted access, a populated one enforces the ACL.
Each SCIM token now supports a list of mailcow_template attribute value -> mailbox template mappings, mirroring the attribute mapping feature of the OIDC identity providers. When a user is provisioned, the incoming 'mailcow_template' attribute (top-level or inside the enterprise extension URN) is matched against the token's mapper list; the first hit wins, with default_template as fallback. The old 'template' column is replaced by 'default_template' for naming consistency with the identity_provider table. Two new JSON columns 'mappers'/'templates' store the per-token mapping pairs. A full token edit modal is also introduced. Previously only active/inactive could be toggled after creation. Both the edit modal and the add form expose the attribute mapping section, using the same two-column (attribute value | template select) layout as the OIDC identity provider settings.
Signed-off-by: Lorenzo Moscati <lorenzo@moscati.page>
Signed-off-by: Lorenzo Moscati <lorenzo@moscati.page>
Contribution Guidelines
What does this PR include?
Short Description
Implements a SCIM 2.0 (RFC 7643/7644) server endpoint so any Identity Provider — Keycloak, Entra ID, Okta, or any LDAP/OIDC IdP — can push user lifecycle events to mailcow in real time, independently of whichever login protocol is configured.
Protocol support
Authentication & token management
Bearer tokens are generated in the admin UI (System > Configuration > Access > SCIM). The raw token is shown once at creation and never stored; only its SHA-256 hash is kept. Each token supports:
Database schema
Two new tables added via the existing init_db migration mechanism:
Authsource & login design
SCIM is a provisioning protocol, not an authentication protocol. mailbox.authsource='scim' records who manages the user; login is handled by the globally configured IAM provider:
Attempting a password login as a SCIM user when an OIDC provider is configured returns a clear error directing the user to their IdP.
Claiming pre-existing users
A SCIM POST for a user who already has authsource='scim' (e.g. set manually by the admin to prepare a migration) is treated as a claim: attributes are updated, scim_maps is upserted, and 200 is returned. A SCIM POST for a user managed by a different authsource returns 409 with an actionable message explaining how to transfer ownership.
Admin UI
Affected Containers
Did you run tests?
What did you tested?
What were the final results? (Awaited, got)
All the tests gave results conforming to the described behaviours.