mirror of
https://github.com/goauthentik/authentik.git
synced 2026-06-17 19:09:11 +03:00
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:
@@ -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 {}
|
||||||
|
try:
|
||||||
return response.json()
|
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"),
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -11226,6 +11226,7 @@
|
|||||||
"aws",
|
"aws",
|
||||||
"slack",
|
"slack",
|
||||||
"sfdc",
|
"sfdc",
|
||||||
|
"gitlab",
|
||||||
"webex",
|
"webex",
|
||||||
"vcenter"
|
"vcenter"
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
Reference in New Issue
Block a user