providers/scim: Add GitLab compatibility mode (#22906)

* providers/scim: Add GitLab compatibility mode

Add a GitLab SCIM compatibility mode that skips ServiceProviderConfig probing and document when to use it.

Also wrap non-JSON SCIM responses so providers that return HTML redirects fall back through the existing ServiceProviderConfig default path.

Agent-thread: https://sdko.org/internal/thr/per/019ea36a-92dd-7651-8a2d-0d838e724a7d

A7k-product: product

A7k-product-repo: 1

Co-authored-by: Agent <agent@svc.sdko.net>

* providers/scim: Fold GitLab mode into existing migration

Agent-thread: https://sdko.org/internal/thr/ak/019ea7bd-ce63-77a2-90d6-5dcc25d4402d

A7k-product: product

A7k-product-repo: 2

Co-authored-by: Agent <agent@svc.sdko.net>

---------

Co-authored-by: Agent <agent@svc.sdko.net>
This commit is contained in:
Dominic R
2026-06-15 16:30:07 -04:00
committed by GitHub
parent e2a49911a9
commit 6df226188f
9 changed files with 51 additions and 3 deletions
+9 -3
View File
@@ -5,7 +5,7 @@ from typing import TYPE_CHECKING
from django.core.cache import cache from django.core.cache import cache
from django.http import HttpResponseBadRequest, HttpResponseNotFound from django.http import HttpResponseBadRequest, HttpResponseNotFound
from pydantic import ValidationError from pydantic import ValidationError
from requests import RequestException, Session from requests import JSONDecodeError, RequestException, Session
from authentik.lib.sync.outgoing import ( from authentik.lib.sync.outgoing import (
HTTP_CONFLICT, HTTP_CONFLICT,
@@ -84,7 +84,10 @@ class SCIMClient[TModel: "Model", TConnection: "Model", TSchema: "BaseModel"](
raise SCIMRequestException(response) raise SCIMRequestException(response)
if response.status_code == HTTP_NO_CONTENT: if response.status_code == HTTP_NO_CONTENT:
return {} return {}
return response.json() try:
return response.json()
except JSONDecodeError as exc:
raise SCIMRequestException(message="Failed to decode SCIM response") from exc
def get_service_provider_config(self): def get_service_provider_config(self):
"""Get Service provider config""" """Get Service provider config"""
@@ -97,7 +100,10 @@ class SCIMClient[TModel: "Model", TConnection: "Model", TSchema: "BaseModel"](
if cached_config is not None: if cached_config is not None:
return cached_config return cached_config
if self.provider.compatibility_mode == SCIMCompatibilityMode.VCENTER: if self.provider.compatibility_mode in [
SCIMCompatibilityMode.GITLAB,
SCIMCompatibilityMode.VCENTER,
]:
return default_config return default_config
# Attempt to fetch from remote # Attempt to fetch from remote
@@ -93,6 +93,7 @@ class Migration(migrations.Migration):
("aws", "AWS"), ("aws", "AWS"),
("slack", "Slack"), ("slack", "Slack"),
("sfdc", "Salesforce"), ("sfdc", "Salesforce"),
("gitlab", "GitLab"),
("webex", "Webex"), ("webex", "Webex"),
("vcenter", "vCenter"), ("vcenter", "vCenter"),
], ],
+1
View File
@@ -83,6 +83,7 @@ class SCIMCompatibilityMode(models.TextChoices):
AWS = "aws", _("AWS") AWS = "aws", _("AWS")
SLACK = "slack", _("Slack") SLACK = "slack", _("Slack")
SALESFORCE = "sfdc", _("Salesforce") SALESFORCE = "sfdc", _("Salesforce")
GITLAB = "gitlab", _("GitLab")
WEBEX = "webex", _("Webex") WEBEX = "webex", _("Webex")
VCENTER = "vcenter", _("vCenter") VCENTER = "vcenter", _("vCenter")
@@ -88,6 +88,18 @@ class SCIMClientTests(TestCase):
self.assertEqual(mock.call_count, 1) self.assertEqual(mock.call_count, 1)
self.assertEqual(mock.request_history[0].method, "GET") self.assertEqual(mock.request_history[0].method, "GET")
def test_config_non_json_response(self):
"""Test non-JSON config response falls back to defaults"""
with Mocker() as mock:
mock.get(
"https://localhost/ServiceProviderConfig",
text="<html></html>",
headers={"Content-Type": "text/html"},
)
SCIMClient(self.provider)
self.assertEqual(mock.call_count, 1)
self.assertEqual(mock.request_history[0].method, "GET")
def test_scim_sync(self): def test_scim_sync(self):
"""test scim_sync task""" """test scim_sync task"""
scim_sync.send(self.provider.pk).get_result() scim_sync.send(self.provider.pk).get_result()
+1
View File
@@ -11226,6 +11226,7 @@
"aws", "aws",
"slack", "slack",
"sfdc", "sfdc",
"gitlab",
"webex", "webex",
"vcenter" "vcenter"
], ],
+1
View File
@@ -21,6 +21,7 @@ export const CompatibilityModeEnum = {
Aws: "aws", Aws: "aws",
Slack: "slack", Slack: "slack",
Sfdc: "sfdc", Sfdc: "sfdc",
Gitlab: "gitlab",
Webex: "webex", Webex: "webex",
Vcenter: "vcenter", Vcenter: "vcenter",
UnknownDefaultOpenApi: "11184809", UnknownDefaultOpenApi: "11184809",
+1
View File
@@ -36608,6 +36608,7 @@ components:
- aws - aws
- slack - slack
- sfdc - sfdc
- gitlab
- webex - webex
- vcenter - vcenter
type: string type: string
@@ -121,6 +121,7 @@ Available compatibility modes are:
- **AWS**: Disables PATCH operations for AWS Identity Center compatibility - **AWS**: Disables PATCH operations for AWS Identity Center compatibility
- **Slack**: Enables filtering support for Slack's SCIM implementation - **Slack**: Enables filtering support for Slack's SCIM implementation
- **Salesforce**: Uses the non-standard `/ServiceProviderConfigs` endpoint - **Salesforce**: Uses the non-standard `/ServiceProviderConfigs` endpoint
- **GitLab**: Skips the `ServiceProviderConfig` endpoint because GitLab's SCIM implementation does not expose it
- **Webex**: Uses the vendor-specific behavior required for Webex SCIM - **Webex**: Uses the vendor-specific behavior required for Webex SCIM
- **vCenter**: Skips the `ServiceProviderConfig` endpoint, which is not implemented in VMware vCenter - **vCenter**: Skips the `ServiceProviderConfig` endpoint, which is not implemented in VMware vCenter
@@ -161,3 +161,27 @@ For further GitLab provider arguments, check the [GitLab docs](https://docs.gitl
</TabItem> </TabItem>
</Tabs> </Tabs>
## SCIM provisioning _(optional)_
GitLab self-managed instances expose SCIM endpoints for user and group provisioning when SCIM is enabled in GitLab. Use the SCIM API endpoint URL and token shown in GitLab's SCIM configuration.
### Create a SCIM provider
1. Log in to authentik as an administrator and open the authentik Admin interface.
2. Navigate to **Applications** > **Providers** and click **Create**.
3. Select **SCIM Provider** as the provider type and click **Next**.
4. Enter the following values:
- **Name**: Choose a descriptive name.
- **URL**: Paste the SCIM API endpoint URL from GitLab.
- **Token**: Paste the SCIM token from GitLab.
- **Compatibility Mode**: Select **GitLab**.
5. Click **Finish** to save the provider.
### Add the SCIM provider to your application
1. Log in to authentik as an administrator and open the authentik Admin interface.
2. Navigate to **Applications** > **Applications** and select your GitLab application.
3. Click **Edit**.
4. In the **Backchannel Providers** field, select the SCIM provider you created.
5. Click **Update** to save the application.