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.http import HttpResponseBadRequest, HttpResponseNotFound
from pydantic import ValidationError
from requests import RequestException, Session
from requests import JSONDecodeError, RequestException, Session
from authentik.lib.sync.outgoing import (
HTTP_CONFLICT,
@@ -84,7 +84,10 @@ class SCIMClient[TModel: "Model", TConnection: "Model", TSchema: "BaseModel"](
raise SCIMRequestException(response)
if response.status_code == HTTP_NO_CONTENT:
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):
"""Get Service provider config"""
@@ -97,7 +100,10 @@ class SCIMClient[TModel: "Model", TConnection: "Model", TSchema: "BaseModel"](
if cached_config is not None:
return cached_config
if self.provider.compatibility_mode == SCIMCompatibilityMode.VCENTER:
if self.provider.compatibility_mode in [
SCIMCompatibilityMode.GITLAB,
SCIMCompatibilityMode.VCENTER,
]:
return default_config
# Attempt to fetch from remote
@@ -93,6 +93,7 @@ class Migration(migrations.Migration):
("aws", "AWS"),
("slack", "Slack"),
("sfdc", "Salesforce"),
("gitlab", "GitLab"),
("webex", "Webex"),
("vcenter", "vCenter"),
],
+1
View File
@@ -83,6 +83,7 @@ class SCIMCompatibilityMode(models.TextChoices):
AWS = "aws", _("AWS")
SLACK = "slack", _("Slack")
SALESFORCE = "sfdc", _("Salesforce")
GITLAB = "gitlab", _("GitLab")
WEBEX = "webex", _("Webex")
VCENTER = "vcenter", _("vCenter")
@@ -88,6 +88,18 @@ class SCIMClientTests(TestCase):
self.assertEqual(mock.call_count, 1)
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):
"""test scim_sync task"""
scim_sync.send(self.provider.pk).get_result()
+1
View File
@@ -11226,6 +11226,7 @@
"aws",
"slack",
"sfdc",
"gitlab",
"webex",
"vcenter"
],
+1
View File
@@ -21,6 +21,7 @@ export const CompatibilityModeEnum = {
Aws: "aws",
Slack: "slack",
Sfdc: "sfdc",
Gitlab: "gitlab",
Webex: "webex",
Vcenter: "vcenter",
UnknownDefaultOpenApi: "11184809",
+1
View File
@@ -36608,6 +36608,7 @@ components:
- aws
- slack
- sfdc
- gitlab
- webex
- vcenter
type: string
@@ -121,6 +121,7 @@ Available compatibility modes are:
- **AWS**: Disables PATCH operations for AWS Identity Center compatibility
- **Slack**: Enables filtering support for Slack's SCIM implementation
- **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
- **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>
</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.