Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SCIM provisioning API basic implementation #17144

Open
wants to merge 46 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
f0aa456
feat: SCIM implementation
azmeuk Feb 6, 2024
28fc1a2
fix: scim typing lint errors
azmeuk Aug 13, 2024
c6dbad3
update to scim-models 0.1.15 and fix a bunch of mypy errors
azmeuk Aug 18, 2024
634a22d
Merge branch 'develop' into msc4098-scim
azmeuk Aug 19, 2024
04c39c0
update to scim-models 0.2.0
azmeuk Aug 19, 2024
c2fb23a
Merge branch 'develop' into msc4098-scim
azmeuk Aug 21, 2024
5fafaf8
Merge branch 'develop' into msc4098-scim
azmeuk Aug 26, 2024
8c0d548
Merge branch 'develop' into msc4098-scim
azmeuk Aug 30, 2024
f1c1afd
Merge branch 'develop' into msc4098-scim
azmeuk Sep 12, 2024
8904913
fix poetry.lock
azmeuk Sep 12, 2024
0fe2423
avoid raising ImportError if scim2_models is absent
azmeuk Sep 12, 2024
965a341
avoid raising ImportError if scim2_models is absent
azmeuk Sep 12, 2024
7c6f673
use forwardrefs to avoid using possibly unimported types
azmeuk Sep 12, 2024
6f23459
skip scim2 tests if scim2-models is not installed
azmeuk Sep 12, 2024
a548e44
Merge branch 'develop' into msc4098-scim
azmeuk Sep 12, 2024
76afb5d
Merge branch 'develop' into msc4098-scim
azmeuk Sep 13, 2024
06cd88f
use SCIM_PREFIX in homeserver.py
azmeuk Sep 16, 2024
35da83c
Merge branch 'develop' into msc4098-scim
azmeuk Sep 17, 2024
4311e65
make SCIM_PREFIX resource not the last from homeserver
azmeuk Sep 17, 2024
38bfddc
Update synapse/rest/scim.py
azmeuk Nov 13, 2024
63cd06c
Merge branch 'develop' into msc4098-scim
azmeuk Nov 13, 2024
f2619f3
fix: regenerated poetry.lock from the develop branch
azmeuk Nov 13, 2024
86fa3d1
feat: hide the SCIM API endpoint behind the msc4098 experimental feature
azmeuk Nov 13, 2024
c6199a3
doc: indications about SCIM being an experimental feature
azmeuk Nov 13, 2024
bd25a92
refactor: move the SCIM path from /_matrix/client/unstable/coop.yaal/…
azmeuk Nov 13, 2024
6e36431
doc: fix an internal documentation link
azmeuk Nov 13, 2024
afbd62d
fix: start and count attributes cannot be negative
azmeuk Nov 13, 2024
344b11e
doc: new attempt to fix the internal link to user_admin_api.md
azmeuk Nov 13, 2024
5f24645
tests: asserts that users are deactivated after a call to the DELETE …
azmeuk Nov 13, 2024
d8ebb1c
refactor: rename 'default_display_name' var into 'display_name'
azmeuk Nov 13, 2024
d042676
doc: add docstrings to the SCIM endpoints
azmeuk Nov 13, 2024
4c0b639
fix: Disable SCIM if Pydantic version is under 2.7
azmeuk Nov 13, 2024
55107bb
fix: parse the request with scim2-models for POST and PUT endpoints
azmeuk Nov 13, 2024
5774d32
refactor: remove an useless call to _create_registration_details
azmeuk Nov 13, 2024
6a163ce
fix: remove falsy mention to HTTP Basic auth
azmeuk Nov 13, 2024
3ebdad7
chore: bump to scim2-models 0.2.5
azmeuk Nov 13, 2024
feb5eba
fix: remove scim from the 'all' extra
azmeuk Nov 13, 2024
0ed5962
fix: linting
azmeuk Nov 13, 2024
a5a2717
fix: add the 'scim' extra to the mypy GHA step
azmeuk Nov 13, 2024
05f773f
refactor: move set_avatar_url from SsoHandler to ProfileHandler
azmeuk Nov 15, 2024
0e0abef
refactor: extract mxc_to_http to make usable outside of jinja contexts
azmeuk Nov 15, 2024
aeaf74d
fix: SCIM API actually downloads the avatar pictures and store them
azmeuk Nov 15, 2024
462ad10
Merge branch 'develop' into msc4098-scim
azmeuk Nov 17, 2024
48306b0
fix: the page count is maxed to 1000
azmeuk Nov 17, 2024
0f264ec
fix: properly store external_ids in a special __scim__ auth provider
azmeuk Nov 17, 2024
c48e731
fix: lint
azmeuk Nov 17, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ jobs:
uses: matrix-org/setup-python-poetry@v1
with:
# We want to make use of type hints in optional dependencies too.
extras: all
extras: "all scim"
# We have seen odd mypy failures that were resolved when we started
# installing the project again:
# https://github.com/matrix-org/synapse/pull/15376#issuecomment-1498983775
Expand Down
1 change: 1 addition & 0 deletions changelog.d/17144.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Implement a SCIM provisioning API.
1 change: 1 addition & 0 deletions docs/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@
- [Users](admin_api/user_admin_api.md)
- [Server Version](admin_api/version_api.md)
- [Federation](usage/administration/admin_api/federation.md)
- [SCIM provisioning](usage/administration/admin_api/scim_api.md)
- [Manhole](manhole.md)
- [Monitoring](metrics-howto.md)
- [Reporting Homeserver Usage Statistics](usage/administration/monitoring/reporting_homeserver_usage_statistics.md)
Expand Down
282 changes: 282 additions & 0 deletions docs/usage/administration/admin_api/scim_api.md
Copy link
Contributor

Choose a reason for hiding this comment

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

Given this functionality is in an unstable MSC, please can you:

  • link to MSC4098 in this document and make sure it's clear that it's unstable/experimental
  • add an experimental_features flag to the configuration for this feature. SCIM should only be enabled if it is turned on
  • make the experimental feature for SCIM conflict with the experimental feature for MAS integration (msc3861_oauth_delegation_enabled), since in that scenario Synapse is not its own authority in charge of users

?

We don't normally document experimental features however I am glad for the documentation this time. So, I'm happy to keep it, but it needs to be obvious to readers that it's experimental and not enabled by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,282 @@
# SCIM API

Synapse implements a basic subset of the SCIM 2.0 provisioning protocol as defined in [RFC7643](https://datatracker.ietf.org/doc/html/rfc7643) and [RFC7644](https://datatracker.ietf.org/doc/html/rfc7643).
This allows Identity Provider software to update user attributes in a standard and centralized way.

The SCIM endpoint is `/_synapse/admin/scim/v2`.

<div class="warning">

The synapse SCIM API is an experimental feature, and it is disabled by default.
It might be removed someday in favor of an implementation in the [Matrix Authentication Service](https://github.com/element-hq/matrix-authentication-service).

</div>

## Installation

SCIM support for Synapse requires python 3.9+. The `matrix-synapse` package should be installed with the `scim` extra. e.g. with `pip install matrix-synapse[scim]`. For compatibility reasons, the SCIM support cannot be included in the `all` extra, so you need to explicitly use the `scim` extra to enable the API.

Then it must be explicitly enabled by configuration:

```yaml
experimental_features:
msc4098: true
```

## Examples

This sections presents examples of SCIM requests and responses that are supported by the synapse implementation.
Tools like [scim2-cli](https://scim2-cli.readthedocs.io) can be used to manually build payloads and send requests to the SCIM endpoint.

### Create user

#### Request

```
POST /_synapse/admin/scim/v2/Users
```

```json
{
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
"userName": "bjensen",
"externalId": "bjensen@test",
"phoneNumbers": [{"value": "+1-12345678"}],
"emails": [{"value": "bjensen@mydomain.tld"}],
"photos": [
{
"type": "photo",
"primary": true,
"value": "https://mydomain.tld/photo.webp"
}
],
"displayName": "bjensen display name",
"password": "correct horse battery staple"
}
```

#### Response

```json
{
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
"meta": {
"resourceType": "User",
"created": "2024-07-22T16:59:16.326188+00:00",
"lastModified": "2024-07-22T16:59:16.326188+00:00",
"location": "https://synapse.example/_synapse/admin/scim/v2/Users/@bjensen:test",
},
"id": "@bjensen:test",
"externalId": "@bjensen:test",
"phoneNumbers": [{"value": "+1-12345678"}],
"userName": "bjensen",
"emails": [{"value": "bjensen@mydomain.tld"}],
"active": true,
"photos": [
{
"type": "photo",
"primary": true,
"value": "https://mydomain.tld/photo.webp"
}
],
"displayName": "bjensen display name"
}
```

### Get user

#### Request

```
GET /_synapse/admin/scim/v2/Users/@bjensen:test
```

#### Response

```json
{
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
"meta": {
"resourceType": "User",
"created": "2024-07-22T16:59:16.326188+00:00",
"lastModified": "2024-07-22T16:59:16.326188+00:00",
"location": "https://synapse.example/_synapse/admin/scim/v2/Users/@bjensen:test",
},
"id": "@bjensen:test",
"externalId": "@bjensen:test",
"phoneNumbers": [{"value": "+1-12345678"}],
"userName": "bjensen",
"emails": [{"value": "bjensen@mydomain.tld"}],
"active": true,
"photos": [
{
"type": "photo",
"primary": true,
"value": "https://mydomain.tld/photo.webp"
}
],
"displayName": "bjensen display name"
}
```

### Get users

#### Request

Note that requests can be paginated using the `startIndex` and the `count` query string parameters:

```
GET /_synapse/admin/scim/v2/Users?startIndex=10&count=1
```

<div class="warning">

For performances reason, the page count will be maxed to 1000.

</div>

#### Response

```json
{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:ListResponse"],
"totalResults": 123,
"Resources": [
{
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
"meta": {
"resourceType": "User",
"created": "2024-07-22T16:59:16.326188+00:00",
"lastModified": "2024-07-22T16:59:16.326188+00:00",
"location": "https://synapse.example/_synapse/admin/scim/v2/Users/@bjensen:test",
},
"id": "@bjensen:test",
"externalId": "@bjensen:test",
"phoneNumbers": [{"value": "+1-12345678"}],
"userName": "bjensen",
"emails": [{"value": "bjensen@mydomain.tld"}],
"active": true,
"photos": [
{
"type": "photo",
"primary": true,
"value": "https://mydomain.tld/photo.webp"
}
],
"displayName": "bjensen display name"
}
]
}
```

### Replace user

#### Request

```
PUT /_synapse/admin/scim/v2/Users/@bjensen:test
```

```json
{
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
"userName": "bjensen",
"externalId": "bjensen@test",
"phoneNumbers": [{"value": "+1-12345678"}],
"emails": [{"value": "bjensen@mydomain.tld"}],
"active": true,
"photos": [
{
"type": "photo",
"primary": true,
"value": "https://mydomain.tld/photo.webp"
}
],
"displayName": "bjensen new display name",
"password": "correct horse battery staple"
}
```

#### Response

```json
{
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
"meta": {
"resourceType": "User",
"created": "2024-07-22T16:59:16.326188+00:00",
"lastModified": "2024-07-22T17:34:12.834684+00:00",
"location": "https://synapse.example/_synapse/admin/scim/v2/Users/@bjensen:test",
},
"id": "@bjensen:test",
"externalId": "@bjensen:test",
"phoneNumbers": [{"value": "+1-12345678"}],
"userName": "bjensen",
"emails": [{"value": "bjensen@mydomain.tld"}],
"active": true,
"photos": [
{
"type": "photo",
"primary": true,
"value": "https://mydomain.tld/photo.webp"
}
],
"displayName": "bjensen new display name"
}
```

### Delete user

User deletion requests [deactivate](../../../admin_api/user_admin_api.md) users, with the `erase` option.

#### Request

```
DELETE /_synapse/admin/scim/v2/Users/@bjensen:test
```

azmeuk marked this conversation as resolved.
Show resolved Hide resolved
## Implementation details

### Models

The only SCIM resource type implemented is `User`, with the following attributes:
- `userName`
- `password`
- `emails`
- `phoneNumbers`
- `displayName`
- `photos` (as a MXC URI)
- `active`

The other SCIM User attributes will be ignored. Other resource types such as `Group` are not implemented.

### Endpoints

The implemented endpoints are:

- `/Users` (GET, POST)
- `/Users/<user_id>` (GET, PUT, DELETE)
- `/ServiceProviderConfig` (GET)
- `/Schemas` (GET)
- `/Schemas/<schema_id>` (GET)
- `/ResourceTypes` (GET)
- `/ResourceTypes/<resource_type_id>`

The following endpoints are not implemented:

- `/Users` (PATCH)
- [`/Me`](https://datatracker.ietf.org/doc/html/rfc7644#section-3.11) (GET, POST, PUT, PATCH, DELETE)
- `/Groups` (GET, POST, PUT, PATCH)
- [`/Bulk`](https://datatracker.ietf.org/doc/html/rfc7644#section-3.7) (POST)
- [`/.search`](https://datatracker.ietf.org/doc/html/rfc7644#section-3.4.3) (POST)

### Features

The following features are implemented:
- [pagination](https://datatracker.ietf.org/doc/html/rfc7644#section-3.4.2.4)

The following features are not implemented:
- [filtering](https://datatracker.ietf.org/doc/html/rfc7644#section-3.4.2.2)
- [sorting](https://datatracker.ietf.org/doc/html/rfc7644#section-3.4.2.3)
- [attributes selection](https://datatracker.ietf.org/doc/html/rfc7644#section-3.4.2.5)
- [ETags](https://datatracker.ietf.org/doc/html/rfc7644#section-3.14)
55 changes: 53 additions & 2 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading