feat: implement scim and oidc integration - #2674
Open
cristianscheid wants to merge 1 commit into
Open
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
cristianscheid
force-pushed
the
feat/1861/scim-oidc-integration
branch
from
July 24, 2026 14:30
af7cec3 to
3eb9581
Compare
cristianscheid
force-pushed
the
feat/1861/scim-oidc-integration
branch
from
August 6, 2026 14:16
3eb9581 to
3b7daf7
Compare
Signed-off-by: Cristian Scheid <cristianscheid@gmail.com>
cristianscheid
force-pushed
the
feat/1861/scim-oidc-integration
branch
from
August 7, 2026 11:42
2727221 to
bd9972c
Compare
cristianscheid
marked this pull request as ready for review
August 7, 2026 13:16
cristianscheid
requested review from
ArtificialOwl and
provokateurin
as code owners
August 7, 2026 13:16
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implement support for SCIM and OIDC integration.
This is the first iteration of development of this feature, and covers the following scenario in a federated environment:
on master, SCIM server integration can be configured like:
on slave, OIDC server integration can be configured like:
How a circle representing a SCIM group is identified across instances
If master creates a circle from a SCIM group, how does a slave know which circle on the master corresponds to a membership fetched from OIDC?
A new method,
TStringTools::generateCircleIdFromString(), generates a circle ID (hash) from a string. Unliketoken()(also in this trait), which generates hash randomly, this method always returns the same generated value for the same inputThis means:
urn:geant:company.co:group:my_group#login.company.co) from SCIM and generates a circle ID from it when creating the circleNew circle config flag
A new circle config flag,
Circle::CFG_THIRD_PARTY, was introduced to mark circles managed by an external system (in this case, a SCIM server). Every circle created from a SCIM group gets this flag.How groups from SCIM are synced
On the master instance, a request is made to the SCIM server to retrieve groups. For each group, a circle ID is generated (using
TStringTools::generateCircleIdFromString(), as mentioned above), and a circle is created with theCircle::CFG_THIRD_PARTYflag, if it doesn't exist yet.It's also checked whether any existing third-party circle no longer has a corresponding group on the SCIM server, and it's destroyed accordingly.
Triggered via:
occ circles:scim:syncOCA\Circles\Cron\ScimSyncThe "remote moderator" mechanism
For a slave to be able to add one of its own users to a third-party circle on master, two things are needed:
To achieve this, the master instance should set a config,
remote_mod_circle_instances, listing which remote instances are allowed to add members to its third-party circles, e.g.:The master then makes a request to each configured
remote_mod_circle_instanceson the/index.php/apps/circles/moderator/endpoint, which creates a circle calledremote-mod-circleon slave if it doesn't exist yet, and returns its circle ID. the master stores the results inremote_mod_circle_mapping, e.g.:{ "instance-one": "qH6ucMyBtQgo4HiBNyDqR33KXAqAaIV", "instance-two": "wmqsbzRKPHhE5vlC7XDOgJLYP9KwspX" }This tells the master which circle on each slave acts as the moderator, allowed to add members to its third-party circles.
Triggered via:
occ circles:remotemod:discoverOCA\Circles\Cron\RemoteModDiscoverOnce the mapping is done, the master iterates through every third-party circle and adds each moderator circle from
remote_mod_circle_mappingas a member with moderator level.From this point on, every slave is aware of third-party circles on the master and can add members to them, using its own
remote-mod-circleas the initiator, since it has moderator level.Triggered via:
occ circles:remotemod:syncOCA\Circles\BackgroundJob\RemoteModSyncConnecting with OIDC
On a slave instance, a user can go to "Personal settings > Teams" and click "Connect" under "Connect to OIDC provider":

This redirects the user to the OIDC provider to authenticate. Once authenticated, the user is redirected back and their refresh token is stored.
How user's memberships from OIDC are synced
On slave instances, a request is made to the OIDC server for a given user, retrieving the group identifiers from the
oidc_membership_claim(e.g.entitlements). For each identifier, a circle ID is generated (usingTStringTools::generateCircleIdFromString(), as mentioned above), and the user is added to the corresponding third-party circle on master.It's also checked whether the user is a member of any third-party circle they no longer belong to, and, if so, they are removed accordingly.
User's OIDC memberships are synced in any of the following situations:
occ circles:oidc:syncOCA\Circles\Cron\OidcSyncUserLoggedInlistener adds anOidcSyncUserqueued jobOCC commands
circles:scim:synccircles:remotemod:discovercircles:remotemod:synccircles:oidc:syncJobs
OCA\Circles\Cron\ScimSyncOCA\Circles\Cron\RemoteModDiscoverOCA\Circles\BackgroundJob\RemoteModSyncRemoteModDiscoverOCA\Circles\Cron\OidcSyncOCA\Circles\BackgroundJob\OidcSyncUserUserLoggedInlistenerTODO
SCIM server integration (
OCA\Circles\Service\ScimService::fetchCircles()) still need to be tested against a real SCIM server, and adjusted as needed once access is available.Currently, this implementation only covers a federated setup where the master fetches groups from SCIM and creates circles, while slaves only fetch membership data from OIDC. A future iteration should also support a single instance configured with both SCIM and OIDC, so it can fetch memberships from OIDC and add users directly to its own SCIM circles, without needing a separate master/slave split.
When a remote instance is removed from
remote_mod_circle_instances, there's no cleanup mechanism in place, meaning the slave's remote moderator circle and its members are still kept on the master's third-party circles.occcommand for adding/removing entries fromremote_mod_circle_instancescould be implemented, as it would be a good place to trigger this cleanup, removing the remote moderator circle and its members from the master's third-party circles upon removal.When a circle is removed on the master, it doesn't seem to be propagated to slaves (federated instances). This appears to be existing behavior in Circles app, a listener to propagate circle removal to slaves may be needed.
Checklist
3. to review, feature component)stable32)AI (if applicable)