providers/scim: add compatibility mode for AWS & Slack (#13342)

* providers/scim: override AWS patch support

AWS /ServiceProviderConfig query responds that it supports patch,
 but they only support patching a single group property.
resolves #12321

* introduce compatibility mode for scim provider instead of hack

Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>

* add option for slack

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

---------

Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
Co-authored-by: Jens Langhammer <jens@goauthentik.io>
This commit is contained in:
Jo Rhett
2025-03-12 09:56:30 -07:00
committed by GitHub
parent 23c0d90b3e
commit c47fb2612a
7 changed files with 109 additions and 2 deletions

View File

@ -28,6 +28,7 @@ class SCIMProviderSerializer(ProviderSerializer):
"url", "url",
"verify_certificates", "verify_certificates",
"token", "token",
"compatibility_mode",
"exclude_users_service_account", "exclude_users_service_account",
"filter_group", "filter_group",
"dry_run", "dry_run",

View File

@ -22,7 +22,7 @@ from authentik.lib.sync.outgoing.exceptions import (
from authentik.lib.utils.http import get_http_session from authentik.lib.utils.http import get_http_session
from authentik.providers.scim.clients.exceptions import SCIMRequestException from authentik.providers.scim.clients.exceptions import SCIMRequestException
from authentik.providers.scim.clients.schema import ServiceProviderConfiguration from authentik.providers.scim.clients.schema import ServiceProviderConfiguration
from authentik.providers.scim.models import SCIMProvider from authentik.providers.scim.models import SCIMCompatibilityMode, SCIMProvider
if TYPE_CHECKING: if TYPE_CHECKING:
from django.db.models import Model from django.db.models import Model
@ -90,9 +90,14 @@ class SCIMClient[TModel: "Model", TConnection: "Model", TSchema: "BaseModel"](
"""Get Service provider config""" """Get Service provider config"""
default_config = ServiceProviderConfiguration.default() default_config = ServiceProviderConfiguration.default()
try: try:
return ServiceProviderConfiguration.model_validate( config = ServiceProviderConfiguration.model_validate(
self._request("GET", "/ServiceProviderConfig") self._request("GET", "/ServiceProviderConfig")
) )
if self.provider.compatibility_mode == SCIMCompatibilityMode.AWS:
config.patch.supported = False
if self.provider.compatibility_mode == SCIMCompatibilityMode.SLACK:
config.filter.supported = True
return config
except (ValidationError, SCIMRequestException, NotFoundSyncException) as exc: except (ValidationError, SCIMRequestException, NotFoundSyncException) as exc:
self.logger.warning("failed to get ServiceProviderConfig", exc=exc) self.logger.warning("failed to get ServiceProviderConfig", exc=exc)
return default_config return default_config

View File

@ -0,0 +1,24 @@
# Generated by Django 5.0.12 on 2025-03-07 23:35
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("authentik_providers_scim", "0011_scimprovider_dry_run"),
]
operations = [
migrations.AddField(
model_name="scimprovider",
name="compatibility_mode",
field=models.CharField(
choices=[("default", "Default"), ("aws", "AWS"), ("slack", "Slack")],
default="default",
help_text="Alter authentik behavior for vendor-specific SCIM implementations.",
max_length=30,
verbose_name="SCIM Compatibility Mode",
),
),
]

View File

@ -57,6 +57,14 @@ class SCIMProviderGroup(SerializerModel):
return f"SCIM Provider Group {self.group_id} to {self.provider_id}" return f"SCIM Provider Group {self.group_id} to {self.provider_id}"
class SCIMCompatibilityMode(models.TextChoices):
"""SCIM compatibility mode"""
DEFAULT = "default", _("Default")
AWS = "aws", _("AWS")
SLACK = "slack", _("Slack")
class SCIMProvider(OutgoingSyncProvider, BackchannelProvider): class SCIMProvider(OutgoingSyncProvider, BackchannelProvider):
"""SCIM 2.0 provider to create users and groups in external applications""" """SCIM 2.0 provider to create users and groups in external applications"""
@ -77,6 +85,14 @@ class SCIMProvider(OutgoingSyncProvider, BackchannelProvider):
help_text=_("Property mappings used for group creation/updating."), help_text=_("Property mappings used for group creation/updating."),
) )
compatibility_mode = models.CharField(
max_length=30,
choices=SCIMCompatibilityMode.choices,
default=SCIMCompatibilityMode.DEFAULT,
verbose_name=_("SCIM Compatibility Mode"),
help_text=_("Alter authentik behavior for vendor-specific SCIM implementations."),
)
@property @property
def icon_url(self) -> str | None: def icon_url(self) -> str | None:
return static("authentik/sources/scim.png") return static("authentik/sources/scim.png")

View File

@ -6661,6 +6661,16 @@
"title": "Token", "title": "Token",
"description": "Authentication token" "description": "Authentication token"
}, },
"compatibility_mode": {
"type": "string",
"enum": [
"default",
"aws",
"slack"
],
"title": "SCIM Compatibility Mode",
"description": "Alter authentik behavior for vendor-specific SCIM implementations."
},
"exclude_users_service_account": { "exclude_users_service_account": {
"type": "boolean", "type": "boolean",
"title": "Exclude users service account" "title": "Exclude users service account"

View File

@ -41582,6 +41582,12 @@ components:
- confidential - confidential
- public - public
type: string type: string
CompatibilityModeEnum:
enum:
- default
- aws
- slack
type: string
Config: Config:
type: object type: object
description: Serialize authentik Config into DRF Object description: Serialize authentik Config into DRF Object
@ -52441,6 +52447,11 @@ components:
type: string type: string
minLength: 1 minLength: 1
description: Authentication token description: Authentication token
compatibility_mode:
allOf:
- $ref: '#/components/schemas/CompatibilityModeEnum'
title: SCIM Compatibility Mode
description: Alter authentik behavior for vendor-specific SCIM implementations.
exclude_users_service_account: exclude_users_service_account:
type: boolean type: boolean
filter_group: filter_group:
@ -55841,6 +55852,11 @@ components:
token: token:
type: string type: string
description: Authentication token description: Authentication token
compatibility_mode:
allOf:
- $ref: '#/components/schemas/CompatibilityModeEnum'
title: SCIM Compatibility Mode
description: Alter authentik behavior for vendor-specific SCIM implementations.
exclude_users_service_account: exclude_users_service_account:
type: boolean type: boolean
filter_group: filter_group:
@ -55931,6 +55947,11 @@ components:
type: string type: string
minLength: 1 minLength: 1
description: Authentication token description: Authentication token
compatibility_mode:
allOf:
- $ref: '#/components/schemas/CompatibilityModeEnum'
title: SCIM Compatibility Mode
description: Alter authentik behavior for vendor-specific SCIM implementations.
exclude_users_service_account: exclude_users_service_account:
type: boolean type: boolean
filter_group: filter_group:

View File

@ -11,6 +11,7 @@ import { html } from "lit";
import { ifDefined } from "lit/directives/if-defined.js"; import { ifDefined } from "lit/directives/if-defined.js";
import { import {
CompatibilityModeEnum,
CoreApi, CoreApi,
CoreGroupsListRequest, CoreGroupsListRequest,
Group, Group,
@ -61,6 +62,35 @@ export function renderForm(provider?: Partial<SCIMProvider>, errors: ValidationE
)} )}
inputHint="code" inputHint="code"
></ak-text-input> ></ak-text-input>
<ak-radio-input
name="compatibilityMode"
label=${msg("Compatibility Mode")}
.value=${provider?.compatibilityMode}
required
.options=${[
{
label: msg("Default"),
value: CompatibilityModeEnum.Default,
default: true,
description: html`${msg("Default behavior.")}`,
},
{
label: msg("AWS"),
value: CompatibilityModeEnum.Aws,
description: html`${msg(
"Altered behavior for usage with Amazon Web Services.",
)}`,
},
{
label: msg("Slack"),
value: CompatibilityModeEnum.Slack,
description: html`${msg("Altered behavior for usage with Slack.")}`,
},
]}
help=${msg(
"Alter authentik's behavior for vendor-specific SCIM implementations.",
)}
></ak-radio-input>
<ak-form-element-horizontal name="dryRun"> <ak-form-element-horizontal name="dryRun">
<label class="pf-c-switch"> <label class="pf-c-switch">
<input <input