zitadel icon indicating copy to clipboard operation
zitadel copied to clipboard

Inbound SCIM Support for Users

Open hifabienne opened this issue 1 year ago • 4 comments

As an identity administrator, I want ZITADEL to support the SCIM (System for Cross-domain Identity Management) standard for inbound user provisioning, so that other systems can automatically provision and manage users within ZITADEL. This includes the ability to create, update, and delete users based on the user data changes in the external system. This feature will streamline user management across systems and ensure user states are consistent.

Acceptance Criteria

  • [ ] ZITADEL provides a REST only inbound SCIM Interface according to the standard SCIM 2.0 for users: https://scim.cloud/
  • [ ] All SCIM standard attributes are implemented (e.g username, email, displayname, etc)
  • [ ] The following operations are implemented:
    • [ ] Create: POST https://example.com/{v}/{resource}
    • [ ] Read: GET https://example.com/{v}/{resource}/{id}
    • [ ] Replace: PUT https://example.com/{v}/{resource}/{id}
    • [ ] Delete: DELETE https://example.com/{v}/{resource}/{id}
    • [ ] Update: PATCH https://example.com/{v}/{resource}/{id}
    • [ ] Search: GET https://example.com/{v}/{resource}?filter={attribute}{op}{value}&sortBy={attributeName}&sortOrder={ascending|descending}
  • [ ] The SCIM API can only be called by an authenticated user, and the permission follow the internal ZITADEL permissions (manager), Example to create a user the permission user.write is needed
  • [ ] The SCIM API is documented
  • [ ] We provide a guide with an example of the create and deactivate flow

User schema

Add an extension for scim

  • [ ] allow to select the schema type by jsonpath filter (e.g. exists $[?(@."urn:ietf:params:scim:schemas:extension:CustomExtensionName:2.0:User")])
  • [ ] add field extension for mapping scim field to schema field by jsonpath
  • [ ] Define mapping of enum types inside schema

Excluded

In this implementation only the User resource will be implemented, the groups resource is not a part of the implementation. This also includes the groups field of the user. For group mapping, we should take into account the "User Group Authorization" #5822 issue, later on.

Additional Context

How can this be implemented with User Schema?

hifabienne avatar Jun 14 '24 14:06 hifabienne

Additions to OP

Acceptance Criteria

  • [ ] The following REST only operations are implemented:

User schema

Add an extension for scim

  • [ ] allow to select the schema type by jsonpath filter (e.g. exists urn:ietf:params:scim:schemas:extension:CustomExtensionName:2.0:User)
  • [ ] add field extension for mapping scim field to schema field by jsonpath
  • [ ] Define mapping of enum types inside schema

adlerhurst avatar Jun 17 '24 08:06 adlerhurst

Use case from a conversation: Delete user per SCIM is important when offering a "per-seat" pricing of a SaaS application. When a customer deletes/offboards an account the user should also be deleted from the IDP.

mffap avatar Jul 19 '24 09:07 mffap

Today, we had another potential B2B SaaS customer who specifically requested SCIM. They consider other methods for user synchronization outdated and have listed SCIM as a requirement on their checklist for evaluating new software. Conclusion: We would highly appreciate the possibility :).

sueess avatar Sep 26 '24 15:09 sueess

I mentioned it in the SCIM discussion, but it might be more relevant here: even just read-only support for SCIM (and custom schemas) would let us solve #7909 with a generic helper, only using OIDC & SCIM rather than Zitadel-specific APIs.

nicoonoclaste avatar Sep 28 '24 12:09 nicoonoclaste

Just want to confirm what I've researched. The inbound use case means that ZITADEL acts as a SCIM server and IdP platforms act as SCIM clients. ZITADEL provides the REST endpoints and the IdP admins / HR click on their UI for adding/removing users to a given app. As a SaaS developer, inbound direction / SCIM server is what I need. Is that correct?

hyperknot avatar Nov 11 '24 16:11 hyperknot

Just want to confirm what I've researched. The inbound use case means that ZITADEL acts as a SCIM server and IdP platforms act as SCIM clients. ZITADEL provides the REST endpoints and the IdP admins / HR click on their UI for adding/removing users to a given app. As a SaaS developer, inbound direction / SCIM server is what I need. Is that correct?

You are right, inbound means an external service is able to provision users to ZITADEL through a SCIM interface. Outbound on the other hand mean, that ZITADEL will send users out to an external service through a SCIM interface. To make it more clear twi examples:

  • Inbound: You create a user in your entra id, the user is then sent to ZITADELs SCIM interface and will be created in ZITADEL.
  • Outbound: You create a user in ZITADEL, the user will then be sent to your entra ID with the SCIM standard, and can be created in your entra ID.

hifabienne avatar Nov 12 '24 09:11 hifabienne

A remark to the mapping: Shouldn't the externalIid be mapped to a IdP link on the user? Additionally, (maybe only for the future) wouldn't it make sense to have some customization on mapping groups to authorizations before we have the groups feature.

Typical use case i see is that one wants to onboard a new employee and provision their accounts from EntraID to ZITADEL and grant necessary permissions. As soon as the user then first signs in, ZITADEL ideally already know the federated userid and does not even need to do JIT provisioning / linking.

livio-a avatar Nov 28 '24 06:11 livio-a

A remark to the mapping: Shouldn't the externalIid be mapped to a IdP link on the user? Additionally, (maybe only for the future) wouldn't it make sense to have some customization on mapping groups to authorizations before we have the groups feature.

Typical use case i see is that one wants to onboard a new employee and provision their accounts from EntraID to ZITADEL and grant necessary permissions. As soon as the user then first signs in, ZITADEL ideally already know the federated userid and does not even need to do JIT provisioning / linking.

I agree on both, the externalid might be difficult as we would also need to know to which idp. For a first mvp I would leave that out. and we can extend in a second version

Another thing that just came to my mind, how do we know to which organization the user belongs? My suggestion, if there is a matching domain on the primary email / username we map to the corresponding organization. we might want to introduce a custom attribute where we can send the org id. If we have nothing else, to the default organization

hifabienne avatar Nov 28 '24 07:11 hifabienne

I think we can leave the org ID logically the same as the other APIs. As the SCIM requests are authenticated by a machine user, we can default to it's organization. We also have the org header to override this.

In any case the machine user needs proper permissions to manage users on a given org.

Therefore I think we should reuse the existing middleware and definition of org selection. We can go with custom fields later if needed.

muhlemmer avatar Nov 28 '24 08:11 muhlemmer

I think we can leave the org ID logically the same as the other APIs. As the SCIM requests are authenticated by a machine user, we can default to it's organization. We also have the org header to override this.

In any case the machine user needs proper permissions to manage users on a given org.

Therefore I think we should reuse the existing middleware and definition of org selection. We can go with custom fields later if needed.

As SCIM is a standard implementation, I am pretty sure those SCIM clients can't just send an organization header. A custom field would be the better choice in that case. I guess just adding the org id as custom field would already be enough, without any other email domain logic.

hifabienne avatar Nov 28 '24 08:11 hifabienne

Looks good to me. I edited some metadata keys as the profileURL key was used in multiple places. Possibly copy/paste error.

We should add that the Email and Phone verified option is configurable in ZITADEL, right? So that is is either true or false for all users.

muhlemmer avatar Nov 28 '24 16:11 muhlemmer

Looks good to me. I edited some metadata keys as the profileURL key was used in multiple places. Possibly copy/paste error.

We should add that the Email and Phone verified option is configurable in ZITADEL, right? So that is is either true or false for all users.

Great thanks, I added your recommendation and also the org id as custom attribute

hifabienne avatar Nov 29 '24 07:11 hifabienne

Proposal for PATCH:

SCIM ZITADEL PATCH
id userid patch not possible
externalid user metadata: key: externalid Add, Replace, and Remove
username username replace
  loginnames
name  
name.formatted profile.displayName Add, Replace, and Remove
name.familyName profile.familyName Add, Replace
name.givenName profile.givenName Add, Replace
name.middleName user metadata: key: name.middleName Add, Replace, and Remove
name.honorificPrefix user metadata: key: name.honorificPrefix Add, Replace, and Remove
name.honorificSuffix user metadata: key: name.honorificSuffix Add, Replace, and Remove
displayName profile.displayName Add, Replace, and Remove
nickName profile.nickName Add, Replace, and Remove
not mapped gender patch not possible
profileUrl  user metadata: key: profileURL Add, Replace, and Remove
title  user metadata: key: title Add, Replace, and Remove
preferredLanguage profile.preferredLanguage Add, Replace, and Remove
locale  user metadata: key: locale Add, Replace, and Remove
timezone  user metadata: key: timezone Add, Replace, and Remove
active user.state Replace (active = activate, active false = deactivate, only if it has changed)
password password.password Add, Replace
Emails (list) - Value - Type - primary Email (single) Note: only primary email will be mapped- email.emaile - mail.isVerified? Replace
phoneNumbers  (list) - Value - type Phone  (single) Note: only primary phone will be mapped- phone.phone - phone.isVerified Add, Replace, Remove
ims user metadata: key: ims Add, Replace, Remove
photos user metadata: key: photos Add, Replace, Remove
addresses user metadata: key: addresses Add, Replace, Remove
groups user metadata: key: groups Add, Replace, Remove
entitlements user metadata: key: entitlements Add, Replace, Remove
roles user metadata: key: roles Add, Replace, Remove

hifabienne avatar Dec 16 '24 13:12 hifabienne