From 68af5b05724888670151dfd34fe8d195c2923b8f Mon Sep 17 00:00:00 2001 From: Marc 'risson' Schmitt Date: Thu, 8 Aug 2024 11:36:24 +0200 Subject: [PATCH] sources/plex: add property mappings (#10772) --- .../sources/plex/api/property_mappings.py | 31 + authentik/sources/plex/api/source.py | 11 +- .../sources/plex/api/source_connection.py | 33 +- ...tion_plexsourcepropertymapping_and_more.py | 61 ++ authentik/sources/plex/models.py | 67 +- authentik/sources/plex/plex.py | 14 +- authentik/sources/plex/tests.py | 20 +- authentik/sources/plex/urls.py | 10 +- blueprints/schema.json | 274 ++++- schema.yml | 968 +++++++++++++++--- .../PropertyMappingListPage.ts | 1 + .../PropertyMappingPlexSourceForm.ts | 40 + .../PropertyMappingWizard.ts | 1 + web/src/admin/sources/plex/PlexSourceForm.ts | 98 +- 14 files changed, 1458 insertions(+), 171 deletions(-) create mode 100644 authentik/sources/plex/api/property_mappings.py create mode 100644 authentik/sources/plex/migrations/0004_groupplexsourceconnection_plexsourcepropertymapping_and_more.py create mode 100644 web/src/admin/property-mappings/PropertyMappingPlexSourceForm.ts diff --git a/authentik/sources/plex/api/property_mappings.py b/authentik/sources/plex/api/property_mappings.py new file mode 100644 index 000000000000..80a9ac3e043d --- /dev/null +++ b/authentik/sources/plex/api/property_mappings.py @@ -0,0 +1,31 @@ +"""Plex source property mappings API""" + +from rest_framework.viewsets import ModelViewSet + +from authentik.core.api.property_mappings import PropertyMappingFilterSet, PropertyMappingSerializer +from authentik.core.api.used_by import UsedByMixin +from authentik.sources.plex.models import PlexSourcePropertyMapping + + +class PlexSourcePropertyMappingSerializer(PropertyMappingSerializer): + """PlexSourcePropertyMapping Serializer""" + + class Meta(PropertyMappingSerializer.Meta): + model = PlexSourcePropertyMapping + + +class PlexSourcePropertyMappingFilter(PropertyMappingFilterSet): + """Filter for PlexSourcePropertyMapping""" + + class Meta(PropertyMappingFilterSet.Meta): + model = PlexSourcePropertyMapping + + +class PlexSourcePropertyMappingViewSet(UsedByMixin, ModelViewSet): + """PlexSourcePropertyMapping Viewset""" + + queryset = PlexSourcePropertyMapping.objects.all() + serializer_class = PlexSourcePropertyMappingSerializer + filterset_class = PlexSourcePropertyMappingFilter + search_fields = ["name"] + ordering = ["name"] diff --git a/authentik/sources/plex/api/source.py b/authentik/sources/plex/api/source.py index 4560aea3556b..f662fe9f4b5f 100644 --- a/authentik/sources/plex/api/source.py +++ b/authentik/sources/plex/api/source.py @@ -19,7 +19,7 @@ from authentik.flows.challenge import RedirectChallenge from authentik.flows.views.executor import to_stage_response from authentik.rbac.decorators import permission_required -from authentik.sources.plex.models import PlexSource, PlexSourceConnection +from authentik.sources.plex.models import PlexSource, UserPlexSourceConnection from authentik.sources.plex.plex import PlexAuth, PlexSourceFlowManager LOGGER = get_logger() @@ -31,6 +31,7 @@ class PlexSourceSerializer(SourceSerializer): class Meta: model = PlexSource fields = SourceSerializer.Meta.fields + [ + "group_matching_mode", "client_id", "allowed_servers", "allow_friends", @@ -58,6 +59,7 @@ class PlexSourceViewSet(UsedByMixin, ModelViewSet): "enrollment_flow", "policy_engine_mode", "user_matching_mode", + "group_matching_mode", "client_id", "allow_friends", ] @@ -109,7 +111,10 @@ def redeem_token(self, request: Request) -> Response: source=source, request=request, identifier=str(identifier), - user_info=user_info, + user_info={ + "info": user_info, + "auth_api": auth_api, + }, policy_context={}, ) return to_stage_response(request, sfm.get_flow(plex_token=plex_token)) @@ -158,7 +163,7 @@ def redeem_token_authenticated(self, request: Request) -> Response: friends_allowed = owner_api.check_friends_overlap(identifier) servers_allowed = auth_api.check_server_overlap() if any([friends_allowed, servers_allowed]): - PlexSourceConnection.objects.create( + UserPlexSourceConnection.objects.create( plex_token=plex_token, user=request.user, identifier=identifier, diff --git a/authentik/sources/plex/api/source_connection.py b/authentik/sources/plex/api/source_connection.py index 2b5dc139731b..cc6ae57f7f7c 100644 --- a/authentik/sources/plex/api/source_connection.py +++ b/authentik/sources/plex/api/source_connection.py @@ -2,15 +2,20 @@ from rest_framework.viewsets import ModelViewSet -from authentik.core.api.sources import UserSourceConnectionSerializer, UserSourceConnectionViewSet -from authentik.sources.plex.models import PlexSourceConnection +from authentik.core.api.sources import ( + GroupSourceConnectionSerializer, + GroupSourceConnectionViewSet, + UserSourceConnectionSerializer, + UserSourceConnectionViewSet, +) +from authentik.sources.plex.models import GroupPlexSourceConnection, UserPlexSourceConnection -class PlexSourceConnectionSerializer(UserSourceConnectionSerializer): +class UserPlexSourceConnectionSerializer(UserSourceConnectionSerializer): """Plex Source connection Serializer""" class Meta(UserSourceConnectionSerializer.Meta): - model = PlexSourceConnection + model = UserPlexSourceConnection fields = UserSourceConnectionSerializer.Meta.fields + [ "identifier", "plex_token", @@ -21,8 +26,22 @@ class Meta(UserSourceConnectionSerializer.Meta): } -class PlexSourceConnectionViewSet(UserSourceConnectionViewSet, ModelViewSet): +class UserPlexSourceConnectionViewSet(UserSourceConnectionViewSet, ModelViewSet): """Plex Source connection Serializer""" - queryset = PlexSourceConnection.objects.all() - serializer_class = PlexSourceConnectionSerializer + queryset = UserPlexSourceConnection.objects.all() + serializer_class = UserPlexSourceConnectionSerializer + + +class GroupPlexSourceConnectionSerializer(GroupSourceConnectionSerializer): + """Plex Group-Source connection Serializer""" + + class Meta(GroupSourceConnectionSerializer.Meta): + model = GroupPlexSourceConnection + + +class GroupPlexSourceConnectionViewSet(GroupSourceConnectionViewSet, ModelViewSet): + """Group-source connection Viewset""" + + queryset = GroupPlexSourceConnection.objects.all() + serializer_class = GroupPlexSourceConnectionSerializer diff --git a/authentik/sources/plex/migrations/0004_groupplexsourceconnection_plexsourcepropertymapping_and_more.py b/authentik/sources/plex/migrations/0004_groupplexsourceconnection_plexsourcepropertymapping_and_more.py new file mode 100644 index 000000000000..28e67f38b060 --- /dev/null +++ b/authentik/sources/plex/migrations/0004_groupplexsourceconnection_plexsourcepropertymapping_and_more.py @@ -0,0 +1,61 @@ +# Generated by Django 5.0.7 on 2024-08-05 11:29 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("authentik_core", "0039_source_group_matching_mode_alter_group_name_and_more"), + ("authentik_sources_plex", "0003_alter_plexsource_plex_token"), + ] + + operations = [ + migrations.CreateModel( + name="GroupPlexSourceConnection", + fields=[ + ( + "groupsourceconnection_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="authentik_core.groupsourceconnection", + ), + ), + ], + options={ + "verbose_name": "Group Plex Source Connection", + "verbose_name_plural": "Group Plex Source Connections", + }, + bases=("authentik_core.groupsourceconnection",), + ), + migrations.CreateModel( + name="PlexSourcePropertyMapping", + fields=[ + ( + "propertymapping_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="authentik_core.propertymapping", + ), + ), + ], + options={ + "verbose_name": "Plex Source Property Mapping", + "verbose_name_plural": "Plex Source Property Mappings", + }, + bases=("authentik_core.propertymapping",), + ), + migrations.RenameModel( + old_name="PlexSourceConnection", + new_name="UserPlexSourceConnection", + ), + ] diff --git a/authentik/sources/plex/models.py b/authentik/sources/plex/models.py index 12e5d92c47ca..92771014e2d4 100644 --- a/authentik/sources/plex/models.py +++ b/authentik/sources/plex/models.py @@ -1,5 +1,7 @@ """Plex source""" +from typing import Any + from django.contrib.postgres.fields import ArrayField from django.db import models from django.http.request import HttpRequest @@ -8,7 +10,12 @@ from rest_framework.fields import CharField from rest_framework.serializers import BaseSerializer, Serializer -from authentik.core.models import Source, UserSourceConnection +from authentik.core.models import ( + GroupSourceConnection, + PropertyMapping, + Source, + UserSourceConnection, +) from authentik.core.types import UILoginButton, UserSettingSerializer from authentik.flows.challenge import Challenge, ChallengeResponse from authentik.lib.generators import generate_id @@ -60,6 +67,22 @@ def serializer(self) -> type[BaseSerializer]: return PlexSourceSerializer + @property + def property_mapping_type(self) -> type[PropertyMapping]: + return PlexSourcePropertyMapping + + def get_base_user_properties(self, info: dict[str, Any], **kwargs): + return { + "username": info.get("username"), + "email": info.get("email"), + "name": info.get("title"), + } + + def get_base_group_properties(self, group_id: str, **kwargs): + return { + "name": group_id, + } + @property def icon_url(self) -> str: icon = super().icon_url @@ -95,18 +118,52 @@ class Meta: verbose_name_plural = _("Plex Sources") -class PlexSourceConnection(UserSourceConnection): +class PlexSourcePropertyMapping(PropertyMapping): + """Map Plex properties to User of Group object attributes""" + + @property + def component(self) -> str: + return "ak-property-mapping-plex-source-form" + + @property + def serializer(self) -> type[Serializer]: + from authentik.sources.plex.api.property_mappings import PlexSourcePropertyMappingSerializer + + return PlexSourcePropertyMappingSerializer + + class Meta: + verbose_name = _("Plex Source Property Mapping") + verbose_name_plural = _("Plex Source Property Mappings") + + +class UserPlexSourceConnection(UserSourceConnection): """Connect user and plex source""" plex_token = models.TextField() identifier = models.TextField() @property - def serializer(self) -> Serializer: - from authentik.sources.plex.api.source_connection import PlexSourceConnectionSerializer + def serializer(self) -> type[Serializer]: + from authentik.sources.plex.api.source_connection import UserPlexSourceConnectionSerializer - return PlexSourceConnectionSerializer + return UserPlexSourceConnectionSerializer class Meta: verbose_name = _("User Plex Source Connection") verbose_name_plural = _("User Plex Source Connections") + + +class GroupPlexSourceConnection(GroupSourceConnection): + """Group-source connection""" + + @property + def serializer(self) -> type[Serializer]: + from authentik.sources.plex.api.source_connection import ( + GroupPlexSourceConnectionSerializer, + ) + + return GroupPlexSourceConnectionSerializer + + class Meta: + verbose_name = _("Group Plex Source Connection") + verbose_name_plural = _("Group Plex Source Connections") diff --git a/authentik/sources/plex/plex.py b/authentik/sources/plex/plex.py index 60bc5e1c2bb7..4ac280905a16 100644 --- a/authentik/sources/plex/plex.py +++ b/authentik/sources/plex/plex.py @@ -9,7 +9,7 @@ from authentik import __version__ from authentik.core.sources.flow_manager import SourceFlowManager from authentik.lib.utils.http import get_http_session -from authentik.sources.plex.models import PlexSource, PlexSourceConnection +from authentik.sources.plex.models import PlexSource, UserPlexSourceConnection LOGGER = get_logger() @@ -73,11 +73,7 @@ def get_user_info(self) -> tuple[dict, int]: ) response.raise_for_status() raw_user_info = response.json() - return { - "username": raw_user_info.get("username"), - "email": raw_user_info.get("email"), - "name": raw_user_info.get("title"), - }, raw_user_info.get("id") + return raw_user_info, raw_user_info.get("id") def check_server_overlap(self) -> bool: """Check if the plex-token has any server overlap with our configured servers""" @@ -113,11 +109,11 @@ def check_friends_overlap(self, user_ident: int) -> bool: class PlexSourceFlowManager(SourceFlowManager): """Flow manager for plex sources""" - user_connection_type = PlexSourceConnection + user_connection_type = UserPlexSourceConnection def update_user_connection( - self, connection: PlexSourceConnection, **kwargs - ) -> PlexSourceConnection: + self, connection: UserPlexSourceConnection, **kwargs + ) -> UserPlexSourceConnection: """Set the access_token on the connection""" connection.plex_token = kwargs.get("plex_token") return connection diff --git a/authentik/sources/plex/tests.py b/authentik/sources/plex/tests.py index 3b78e714cfe7..53be3c77ce48 100644 --- a/authentik/sources/plex/tests.py +++ b/authentik/sources/plex/tests.py @@ -54,7 +54,7 @@ def test_get_user_info(self): self.assertEqual( api.get_user_info(), ( - {"username": "username", "email": "foo@bar.baz", "name": "title"}, + USER_INFO_RESPONSE, 1234123419, ), ) @@ -82,3 +82,21 @@ def test_check_task(self): mocker.get("https://plex.tv/api/v2/user", exc=RequestException()) check_plex_token_all() self.assertTrue(Event.objects.filter(action=EventAction.CONFIGURATION_ERROR).exists()) + + def test_user_base_properties(self): + """Test user base properties""" + properties = self.source.get_base_user_properties(info=USER_INFO_RESPONSE) + self.assertEqual( + properties, + { + "username": "username", + "name": "title", + "email": "foo@bar.baz", + }, + ) + + def test_group_base_properties(self): + """Test group base properties""" + for group_id in ["group 1", "group 2"]: + properties = self.source.get_base_group_properties(group_id=group_id) + self.assertEqual(properties, {"name": group_id}) diff --git a/authentik/sources/plex/urls.py b/authentik/sources/plex/urls.py index d1fa679dad96..2460d52a4e44 100644 --- a/authentik/sources/plex/urls.py +++ b/authentik/sources/plex/urls.py @@ -1,9 +1,15 @@ """API URLs""" +from authentik.sources.plex.api.property_mappings import PlexSourcePropertyMappingViewSet from authentik.sources.plex.api.source import PlexSourceViewSet -from authentik.sources.plex.api.source_connection import PlexSourceConnectionViewSet +from authentik.sources.plex.api.source_connection import ( + GroupPlexSourceConnectionViewSet, + UserPlexSourceConnectionViewSet, +) api_urlpatterns = [ - ("sources/user_connections/plex", PlexSourceConnectionViewSet), + ("propertymappings/source/plex", PlexSourcePropertyMappingViewSet), + ("sources/user_connections/plex", UserPlexSourceConnectionViewSet), + ("sources/group_connections/plex", GroupPlexSourceConnectionViewSet), ("sources/plex", PlexSourceViewSet), ] diff --git a/blueprints/schema.json b/blueprints/schema.json index 8ae6d8156f8c..ec03caedef59 100644 --- a/blueprints/schema.json +++ b/blueprints/schema.json @@ -1369,7 +1369,7 @@ ], "properties": { "model": { - "const": "authentik_sources_plex.plexsourceconnection" + "const": "authentik_sources_plex.plexsourcepropertymapping" }, "id": { "type": "string" @@ -1391,13 +1391,93 @@ } }, "permissions": { - "$ref": "#/$defs/model_authentik_sources_plex.plexsourceconnection_permissions" + "$ref": "#/$defs/model_authentik_sources_plex.plexsourcepropertymapping_permissions" }, "attrs": { - "$ref": "#/$defs/model_authentik_sources_plex.plexsourceconnection" + "$ref": "#/$defs/model_authentik_sources_plex.plexsourcepropertymapping" }, "identifiers": { - "$ref": "#/$defs/model_authentik_sources_plex.plexsourceconnection" + "$ref": "#/$defs/model_authentik_sources_plex.plexsourcepropertymapping" + } + } + }, + { + "type": "object", + "required": [ + "model", + "identifiers" + ], + "properties": { + "model": { + "const": "authentik_sources_plex.userplexsourceconnection" + }, + "id": { + "type": "string" + }, + "state": { + "type": "string", + "enum": [ + "absent", + "present", + "created", + "must_created" + ], + "default": "present" + }, + "conditions": { + "type": "array", + "items": { + "type": "boolean" + } + }, + "permissions": { + "$ref": "#/$defs/model_authentik_sources_plex.userplexsourceconnection_permissions" + }, + "attrs": { + "$ref": "#/$defs/model_authentik_sources_plex.userplexsourceconnection" + }, + "identifiers": { + "$ref": "#/$defs/model_authentik_sources_plex.userplexsourceconnection" + } + } + }, + { + "type": "object", + "required": [ + "model", + "identifiers" + ], + "properties": { + "model": { + "const": "authentik_sources_plex.groupplexsourceconnection" + }, + "id": { + "type": "string" + }, + "state": { + "type": "string", + "enum": [ + "absent", + "present", + "created", + "must_created" + ], + "default": "present" + }, + "conditions": { + "type": "array", + "items": { + "type": "boolean" + } + }, + "permissions": { + "$ref": "#/$defs/model_authentik_sources_plex.groupplexsourceconnection_permissions" + }, + "attrs": { + "$ref": "#/$defs/model_authentik_sources_plex.groupplexsourceconnection" + }, + "identifiers": { + "$ref": "#/$defs/model_authentik_sources_plex.groupplexsourceconnection" } } }, @@ -4270,7 +4350,9 @@ "authentik_sources_oauth.useroauthsourceconnection", "authentik_sources_oauth.groupoauthsourceconnection", "authentik_sources_plex.plexsource", - "authentik_sources_plex.plexsourceconnection", + "authentik_sources_plex.plexsourcepropertymapping", + "authentik_sources_plex.userplexsourceconnection", + "authentik_sources_plex.groupplexsourceconnection", "authentik_sources_saml.samlsource", "authentik_sources_saml.samlsourcepropertymapping", "authentik_sources_saml.usersamlsourceconnection", @@ -5966,6 +6048,10 @@ "authentik_core.delete_group", "authentik_core.remove_user_from_group", "authentik_core.view_group", + "authentik_core.add_groupsourceconnection", + "authentik_core.change_groupsourceconnection", + "authentik_core.delete_groupsourceconnection", + "authentik_core.view_groupsourceconnection", "authentik_core.add_propertymapping", "authentik_core.change_propertymapping", "authentik_core.delete_propertymapping", @@ -6235,6 +6321,22 @@ "authentik_rbac.edit_system_settings", "authentik_rbac.view_system_info", "authentik_rbac.view_system_settings", + "authentik_sources_kerberos.add_groupkerberossourceconnection", + "authentik_sources_kerberos.change_groupkerberossourceconnection", + "authentik_sources_kerberos.delete_groupkerberossourceconnection", + "authentik_sources_kerberos.view_groupkerberossourceconnection", + "authentik_sources_kerberos.add_kerberospropertymapping", + "authentik_sources_kerberos.change_kerberospropertymapping", + "authentik_sources_kerberos.delete_kerberospropertymapping", + "authentik_sources_kerberos.view_kerberospropertymapping", + "authentik_sources_kerberos.add_kerberossource", + "authentik_sources_kerberos.change_kerberossource", + "authentik_sources_kerberos.delete_kerberossource", + "authentik_sources_kerberos.view_kerberossource", + "authentik_sources_kerberos.add_userkerberossourceconnection", + "authentik_sources_kerberos.change_userkerberossourceconnection", + "authentik_sources_kerberos.delete_userkerberossourceconnection", + "authentik_sources_kerberos.view_userkerberossourceconnection", "authentik_sources_ldap.add_ldapsource", "authentik_sources_ldap.change_ldapsource", "authentik_sources_ldap.delete_ldapsource", @@ -6243,10 +6345,18 @@ "authentik_sources_ldap.change_ldapsourcepropertymapping", "authentik_sources_ldap.delete_ldapsourcepropertymapping", "authentik_sources_ldap.view_ldapsourcepropertymapping", + "authentik_sources_oauth.add_groupoauthsourceconnection", + "authentik_sources_oauth.change_groupoauthsourceconnection", + "authentik_sources_oauth.delete_groupoauthsourceconnection", + "authentik_sources_oauth.view_groupoauthsourceconnection", "authentik_sources_oauth.add_oauthsource", "authentik_sources_oauth.change_oauthsource", "authentik_sources_oauth.delete_oauthsource", "authentik_sources_oauth.view_oauthsource", + "authentik_sources_oauth.add_oauthsourcepropertymapping", + "authentik_sources_oauth.change_oauthsourcepropertymapping", + "authentik_sources_oauth.delete_oauthsourcepropertymapping", + "authentik_sources_oauth.view_oauthsourcepropertymapping", "authentik_sources_oauth.add_useroauthsourceconnection", "authentik_sources_oauth.change_useroauthsourceconnection", "authentik_sources_oauth.delete_useroauthsourceconnection", @@ -6259,10 +6369,18 @@ "authentik_sources_plex.change_plexsourceconnection", "authentik_sources_plex.delete_plexsourceconnection", "authentik_sources_plex.view_plexsourceconnection", + "authentik_sources_saml.add_groupsamlsourceconnection", + "authentik_sources_saml.change_groupsamlsourceconnection", + "authentik_sources_saml.delete_groupsamlsourceconnection", + "authentik_sources_saml.view_groupsamlsourceconnection", "authentik_sources_saml.add_samlsource", "authentik_sources_saml.change_samlsource", "authentik_sources_saml.delete_samlsource", "authentik_sources_saml.view_samlsource", + "authentik_sources_saml.add_samlsourcepropertymapping", + "authentik_sources_saml.change_samlsourcepropertymapping", + "authentik_sources_saml.delete_samlsourcepropertymapping", + "authentik_sources_saml.view_samlsourcepropertymapping", "authentik_sources_saml.add_usersamlsourceconnection", "authentik_sources_saml.change_usersamlsourceconnection", "authentik_sources_saml.delete_usersamlsourceconnection", @@ -7118,6 +7236,16 @@ "minLength": 1, "title": "Icon" }, + "group_matching_mode": { + "type": "string", + "enum": [ + "identifier", + "name_link", + "name_deny" + ], + "title": "Group matching mode", + "description": "How the source determines if an existing group should be used or a new group created." + }, "client_id": { "type": "string", "minLength": 1, @@ -7174,7 +7302,58 @@ } } }, - "model_authentik_sources_plex.plexsourceconnection": { + "model_authentik_sources_plex.plexsourcepropertymapping": { + "type": "object", + "properties": { + "managed": { + "type": [ + "string", + "null" + ], + "minLength": 1, + "title": "Managed by authentik", + "description": "Objects that are managed by authentik. These objects are created and updated automatically. This flag only indicates that an object can be overwritten by migrations. You can still modify the objects via the API, but expect changes to be overwritten in a later update." + }, + "name": { + "type": "string", + "minLength": 1, + "title": "Name" + }, + "expression": { + "type": "string", + "minLength": 1, + "title": "Expression" + } + }, + "required": [] + }, + "model_authentik_sources_plex.plexsourcepropertymapping_permissions": { + "type": "array", + "items": { + "type": "object", + "required": [ + "permission" + ], + "properties": { + "permission": { + "type": "string", + "enum": [ + "add_plexsourcepropertymapping", + "change_plexsourcepropertymapping", + "delete_plexsourcepropertymapping", + "view_plexsourcepropertymapping" + ] + }, + "user": { + "type": "integer" + }, + "role": { + "type": "string" + } + } + } + }, + "model_authentik_sources_plex.userplexsourceconnection": { "type": "object", "properties": { "identifier": { @@ -7195,7 +7374,44 @@ }, "required": [] }, - "model_authentik_sources_plex.plexsourceconnection_permissions": { + "model_authentik_sources_plex.userplexsourceconnection_permissions": { + "type": "array", + "items": { + "type": "object", + "required": [ + "permission" + ], + "properties": { + "permission": { + "type": "string", + "enum": [ + "add_userplexsourceconnection", + "change_userplexsourceconnection", + "delete_userplexsourceconnection", + "view_userplexsourceconnection" + ] + }, + "user": { + "type": "integer" + }, + "role": { + "type": "string" + } + } + } + }, + "model_authentik_sources_plex.groupplexsourceconnection": { + "type": "object", + "properties": { + "icon": { + "type": "string", + "minLength": 1, + "title": "Icon" + } + }, + "required": [] + }, + "model_authentik_sources_plex.groupplexsourceconnection_permissions": { "type": "array", "items": { "type": "object", @@ -7206,10 +7422,10 @@ "permission": { "type": "string", "enum": [ - "add_plexsourceconnection", - "change_plexsourceconnection", - "delete_plexsourceconnection", - "view_plexsourceconnection" + "add_groupplexsourceconnection", + "change_groupplexsourceconnection", + "delete_groupplexsourceconnection", + "view_groupplexsourceconnection" ] }, "user": { @@ -11495,6 +11711,10 @@ "authentik_core.delete_group", "authentik_core.remove_user_from_group", "authentik_core.view_group", + "authentik_core.add_groupsourceconnection", + "authentik_core.change_groupsourceconnection", + "authentik_core.delete_groupsourceconnection", + "authentik_core.view_groupsourceconnection", "authentik_core.add_propertymapping", "authentik_core.change_propertymapping", "authentik_core.delete_propertymapping", @@ -11764,6 +11984,22 @@ "authentik_rbac.edit_system_settings", "authentik_rbac.view_system_info", "authentik_rbac.view_system_settings", + "authentik_sources_kerberos.add_groupkerberossourceconnection", + "authentik_sources_kerberos.change_groupkerberossourceconnection", + "authentik_sources_kerberos.delete_groupkerberossourceconnection", + "authentik_sources_kerberos.view_groupkerberossourceconnection", + "authentik_sources_kerberos.add_kerberospropertymapping", + "authentik_sources_kerberos.change_kerberospropertymapping", + "authentik_sources_kerberos.delete_kerberospropertymapping", + "authentik_sources_kerberos.view_kerberospropertymapping", + "authentik_sources_kerberos.add_kerberossource", + "authentik_sources_kerberos.change_kerberossource", + "authentik_sources_kerberos.delete_kerberossource", + "authentik_sources_kerberos.view_kerberossource", + "authentik_sources_kerberos.add_userkerberossourceconnection", + "authentik_sources_kerberos.change_userkerberossourceconnection", + "authentik_sources_kerberos.delete_userkerberossourceconnection", + "authentik_sources_kerberos.view_userkerberossourceconnection", "authentik_sources_ldap.add_ldapsource", "authentik_sources_ldap.change_ldapsource", "authentik_sources_ldap.delete_ldapsource", @@ -11772,10 +12008,18 @@ "authentik_sources_ldap.change_ldapsourcepropertymapping", "authentik_sources_ldap.delete_ldapsourcepropertymapping", "authentik_sources_ldap.view_ldapsourcepropertymapping", + "authentik_sources_oauth.add_groupoauthsourceconnection", + "authentik_sources_oauth.change_groupoauthsourceconnection", + "authentik_sources_oauth.delete_groupoauthsourceconnection", + "authentik_sources_oauth.view_groupoauthsourceconnection", "authentik_sources_oauth.add_oauthsource", "authentik_sources_oauth.change_oauthsource", "authentik_sources_oauth.delete_oauthsource", "authentik_sources_oauth.view_oauthsource", + "authentik_sources_oauth.add_oauthsourcepropertymapping", + "authentik_sources_oauth.change_oauthsourcepropertymapping", + "authentik_sources_oauth.delete_oauthsourcepropertymapping", + "authentik_sources_oauth.view_oauthsourcepropertymapping", "authentik_sources_oauth.add_useroauthsourceconnection", "authentik_sources_oauth.change_useroauthsourceconnection", "authentik_sources_oauth.delete_useroauthsourceconnection", @@ -11788,10 +12032,18 @@ "authentik_sources_plex.change_plexsourceconnection", "authentik_sources_plex.delete_plexsourceconnection", "authentik_sources_plex.view_plexsourceconnection", + "authentik_sources_saml.add_groupsamlsourceconnection", + "authentik_sources_saml.change_groupsamlsourceconnection", + "authentik_sources_saml.delete_groupsamlsourceconnection", + "authentik_sources_saml.view_groupsamlsourceconnection", "authentik_sources_saml.add_samlsource", "authentik_sources_saml.change_samlsource", "authentik_sources_saml.delete_samlsource", "authentik_sources_saml.view_samlsource", + "authentik_sources_saml.add_samlsourcepropertymapping", + "authentik_sources_saml.change_samlsourcepropertymapping", + "authentik_sources_saml.delete_samlsourcepropertymapping", + "authentik_sources_saml.view_samlsourcepropertymapping", "authentik_sources_saml.add_usersamlsourceconnection", "authentik_sources_saml.change_usersamlsourceconnection", "authentik_sources_saml.delete_usersamlsourceconnection", diff --git a/schema.yml b/schema.yml index e504873ea4d7..e5c8013ffc8b 100644 --- a/schema.yml +++ b/schema.yml @@ -16540,10 +16540,10 @@ paths: schema: $ref: '#/components/schemas/GenericError' description: '' - /propertymappings/source/saml/: + /propertymappings/source/plex/: get: - operationId: propertymappings_source_saml_list - description: SAMLSourcePropertyMapping Viewset + operationId: propertymappings_source_plex_list + description: PlexSourcePropertyMapping Viewset parameters: - in: query name: managed @@ -16594,7 +16594,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/PaginatedSAMLSourcePropertyMappingList' + $ref: '#/components/schemas/PaginatedPlexSourcePropertyMappingList' description: '' '400': content: @@ -16609,15 +16609,15 @@ paths: $ref: '#/components/schemas/GenericError' description: '' post: - operationId: propertymappings_source_saml_create - description: SAMLSourcePropertyMapping Viewset + operationId: propertymappings_source_plex_create + description: PlexSourcePropertyMapping Viewset tags: - propertymappings requestBody: content: application/json: schema: - $ref: '#/components/schemas/SAMLSourcePropertyMappingRequest' + $ref: '#/components/schemas/PlexSourcePropertyMappingRequest' required: true security: - authentik: [] @@ -16626,7 +16626,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/SAMLSourcePropertyMapping' + $ref: '#/components/schemas/PlexSourcePropertyMapping' description: '' '400': content: @@ -16640,17 +16640,17 @@ paths: schema: $ref: '#/components/schemas/GenericError' description: '' - /propertymappings/source/saml/{pm_uuid}/: + /propertymappings/source/plex/{pm_uuid}/: get: - operationId: propertymappings_source_saml_retrieve - description: SAMLSourcePropertyMapping Viewset + operationId: propertymappings_source_plex_retrieve + description: PlexSourcePropertyMapping Viewset parameters: - in: path name: pm_uuid schema: type: string format: uuid - description: A UUID string identifying this SAML Source Property Mapping. + description: A UUID string identifying this Plex Source Property Mapping. required: true tags: - propertymappings @@ -16661,7 +16661,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/SAMLSourcePropertyMapping' + $ref: '#/components/schemas/PlexSourcePropertyMapping' description: '' '400': content: @@ -16676,15 +16676,15 @@ paths: $ref: '#/components/schemas/GenericError' description: '' put: - operationId: propertymappings_source_saml_update - description: SAMLSourcePropertyMapping Viewset + operationId: propertymappings_source_plex_update + description: PlexSourcePropertyMapping Viewset parameters: - in: path name: pm_uuid schema: type: string format: uuid - description: A UUID string identifying this SAML Source Property Mapping. + description: A UUID string identifying this Plex Source Property Mapping. required: true tags: - propertymappings @@ -16692,7 +16692,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/SAMLSourcePropertyMappingRequest' + $ref: '#/components/schemas/PlexSourcePropertyMappingRequest' required: true security: - authentik: [] @@ -16701,7 +16701,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/SAMLSourcePropertyMapping' + $ref: '#/components/schemas/PlexSourcePropertyMapping' description: '' '400': content: @@ -16716,15 +16716,15 @@ paths: $ref: '#/components/schemas/GenericError' description: '' patch: - operationId: propertymappings_source_saml_partial_update - description: SAMLSourcePropertyMapping Viewset + operationId: propertymappings_source_plex_partial_update + description: PlexSourcePropertyMapping Viewset parameters: - in: path name: pm_uuid schema: type: string format: uuid - description: A UUID string identifying this SAML Source Property Mapping. + description: A UUID string identifying this Plex Source Property Mapping. required: true tags: - propertymappings @@ -16732,7 +16732,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/PatchedSAMLSourcePropertyMappingRequest' + $ref: '#/components/schemas/PatchedPlexSourcePropertyMappingRequest' security: - authentik: [] responses: @@ -16740,7 +16740,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/SAMLSourcePropertyMapping' + $ref: '#/components/schemas/PlexSourcePropertyMapping' description: '' '400': content: @@ -16755,15 +16755,15 @@ paths: $ref: '#/components/schemas/GenericError' description: '' delete: - operationId: propertymappings_source_saml_destroy - description: SAMLSourcePropertyMapping Viewset + operationId: propertymappings_source_plex_destroy + description: PlexSourcePropertyMapping Viewset parameters: - in: path name: pm_uuid schema: type: string format: uuid - description: A UUID string identifying this SAML Source Property Mapping. + description: A UUID string identifying this Plex Source Property Mapping. required: true tags: - propertymappings @@ -16784,9 +16784,9 @@ paths: schema: $ref: '#/components/schemas/GenericError' description: '' - /propertymappings/source/saml/{pm_uuid}/used_by/: + /propertymappings/source/plex/{pm_uuid}/used_by/: get: - operationId: propertymappings_source_saml_used_by_list + operationId: propertymappings_source_plex_used_by_list description: Get a list of all objects that use this object parameters: - in: path @@ -16794,7 +16794,7 @@ paths: schema: type: string format: uuid - description: A UUID string identifying this SAML Source Property Mapping. + description: A UUID string identifying this Plex Source Property Mapping. required: true tags: - propertymappings @@ -16821,10 +16821,10 @@ paths: schema: $ref: '#/components/schemas/GenericError' description: '' - /propertymappings/source/scim/: + /propertymappings/source/saml/: get: - operationId: propertymappings_source_scim_list - description: SCIMSourcePropertyMapping Viewset + operationId: propertymappings_source_saml_list + description: SAMLSourcePropertyMapping Viewset parameters: - in: query name: managed @@ -16875,7 +16875,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/PaginatedSCIMSourcePropertyMappingList' + $ref: '#/components/schemas/PaginatedSAMLSourcePropertyMappingList' description: '' '400': content: @@ -16890,15 +16890,15 @@ paths: $ref: '#/components/schemas/GenericError' description: '' post: - operationId: propertymappings_source_scim_create - description: SCIMSourcePropertyMapping Viewset + operationId: propertymappings_source_saml_create + description: SAMLSourcePropertyMapping Viewset tags: - propertymappings requestBody: content: application/json: schema: - $ref: '#/components/schemas/SCIMSourcePropertyMappingRequest' + $ref: '#/components/schemas/SAMLSourcePropertyMappingRequest' required: true security: - authentik: [] @@ -16907,7 +16907,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/SCIMSourcePropertyMapping' + $ref: '#/components/schemas/SAMLSourcePropertyMapping' description: '' '400': content: @@ -16921,17 +16921,17 @@ paths: schema: $ref: '#/components/schemas/GenericError' description: '' - /propertymappings/source/scim/{pm_uuid}/: + /propertymappings/source/saml/{pm_uuid}/: get: - operationId: propertymappings_source_scim_retrieve - description: SCIMSourcePropertyMapping Viewset + operationId: propertymappings_source_saml_retrieve + description: SAMLSourcePropertyMapping Viewset parameters: - in: path name: pm_uuid schema: type: string format: uuid - description: A UUID string identifying this SCIM Source Property Mapping. + description: A UUID string identifying this SAML Source Property Mapping. required: true tags: - propertymappings @@ -16942,7 +16942,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/SCIMSourcePropertyMapping' + $ref: '#/components/schemas/SAMLSourcePropertyMapping' description: '' '400': content: @@ -16957,15 +16957,15 @@ paths: $ref: '#/components/schemas/GenericError' description: '' put: - operationId: propertymappings_source_scim_update - description: SCIMSourcePropertyMapping Viewset + operationId: propertymappings_source_saml_update + description: SAMLSourcePropertyMapping Viewset parameters: - in: path name: pm_uuid schema: type: string format: uuid - description: A UUID string identifying this SCIM Source Property Mapping. + description: A UUID string identifying this SAML Source Property Mapping. required: true tags: - propertymappings @@ -16973,7 +16973,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/SCIMSourcePropertyMappingRequest' + $ref: '#/components/schemas/SAMLSourcePropertyMappingRequest' required: true security: - authentik: [] @@ -16982,7 +16982,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/SCIMSourcePropertyMapping' + $ref: '#/components/schemas/SAMLSourcePropertyMapping' description: '' '400': content: @@ -16997,15 +16997,15 @@ paths: $ref: '#/components/schemas/GenericError' description: '' patch: - operationId: propertymappings_source_scim_partial_update - description: SCIMSourcePropertyMapping Viewset + operationId: propertymappings_source_saml_partial_update + description: SAMLSourcePropertyMapping Viewset parameters: - in: path name: pm_uuid schema: type: string format: uuid - description: A UUID string identifying this SCIM Source Property Mapping. + description: A UUID string identifying this SAML Source Property Mapping. required: true tags: - propertymappings @@ -17013,7 +17013,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/PatchedSCIMSourcePropertyMappingRequest' + $ref: '#/components/schemas/PatchedSAMLSourcePropertyMappingRequest' security: - authentik: [] responses: @@ -17021,7 +17021,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/SCIMSourcePropertyMapping' + $ref: '#/components/schemas/SAMLSourcePropertyMapping' description: '' '400': content: @@ -17036,15 +17036,15 @@ paths: $ref: '#/components/schemas/GenericError' description: '' delete: - operationId: propertymappings_source_scim_destroy - description: SCIMSourcePropertyMapping Viewset + operationId: propertymappings_source_saml_destroy + description: SAMLSourcePropertyMapping Viewset parameters: - in: path name: pm_uuid schema: type: string format: uuid - description: A UUID string identifying this SCIM Source Property Mapping. + description: A UUID string identifying this SAML Source Property Mapping. required: true tags: - propertymappings @@ -17065,9 +17065,9 @@ paths: schema: $ref: '#/components/schemas/GenericError' description: '' - /propertymappings/source/scim/{pm_uuid}/used_by/: + /propertymappings/source/saml/{pm_uuid}/used_by/: get: - operationId: propertymappings_source_scim_used_by_list + operationId: propertymappings_source_saml_used_by_list description: Get a list of all objects that use this object parameters: - in: path @@ -17075,7 +17075,7 @@ paths: schema: type: string format: uuid - description: A UUID string identifying this SCIM Source Property Mapping. + description: A UUID string identifying this SAML Source Property Mapping. required: true tags: - propertymappings @@ -17102,22 +17102,27 @@ paths: schema: $ref: '#/components/schemas/GenericError' description: '' - /providers/all/: + /propertymappings/source/scim/: get: - operationId: providers_all_list - description: Provider Viewset + operationId: propertymappings_source_scim_list + description: SCIMSourcePropertyMapping Viewset parameters: - in: query - name: application__isnull + name: managed schema: - type: boolean + type: array + items: + type: string + explode: true + style: form - in: query - name: backchannel + name: managed__isnull schema: type: boolean - description: When not set all providers are returned. When set to true, only - backchannel providers are returned. When set to false, backchannel providers - are excluded + - in: query + name: name + schema: + type: string - name: ordering required: false in: query @@ -17143,7 +17148,7 @@ paths: schema: type: string tags: - - providers + - propertymappings security: - authentik: [] responses: @@ -17151,7 +17156,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/PaginatedProviderList' + $ref: '#/components/schemas/PaginatedSCIMSourcePropertyMappingList' description: '' '400': content: @@ -17165,19 +17170,52 @@ paths: schema: $ref: '#/components/schemas/GenericError' description: '' - /providers/all/{id}/: + post: + operationId: propertymappings_source_scim_create + description: SCIMSourcePropertyMapping Viewset + tags: + - propertymappings + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/SCIMSourcePropertyMappingRequest' + required: true + security: + - authentik: [] + responses: + '201': + content: + application/json: + schema: + $ref: '#/components/schemas/SCIMSourcePropertyMapping' + description: '' + '400': + content: + application/json: + schema: + $ref: '#/components/schemas/ValidationError' + description: '' + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/GenericError' + description: '' + /propertymappings/source/scim/{pm_uuid}/: get: - operationId: providers_all_retrieve - description: Provider Viewset + operationId: propertymappings_source_scim_retrieve + description: SCIMSourcePropertyMapping Viewset parameters: - in: path - name: id + name: pm_uuid schema: - type: integer - description: A unique integer value identifying this provider. + type: string + format: uuid + description: A UUID string identifying this SCIM Source Property Mapping. required: true tags: - - providers + - propertymappings security: - authentik: [] responses: @@ -17185,7 +17223,86 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/Provider' + $ref: '#/components/schemas/SCIMSourcePropertyMapping' + description: '' + '400': + content: + application/json: + schema: + $ref: '#/components/schemas/ValidationError' + description: '' + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/GenericError' + description: '' + put: + operationId: propertymappings_source_scim_update + description: SCIMSourcePropertyMapping Viewset + parameters: + - in: path + name: pm_uuid + schema: + type: string + format: uuid + description: A UUID string identifying this SCIM Source Property Mapping. + required: true + tags: + - propertymappings + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/SCIMSourcePropertyMappingRequest' + required: true + security: + - authentik: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/SCIMSourcePropertyMapping' + description: '' + '400': + content: + application/json: + schema: + $ref: '#/components/schemas/ValidationError' + description: '' + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/GenericError' + description: '' + patch: + operationId: propertymappings_source_scim_partial_update + description: SCIMSourcePropertyMapping Viewset + parameters: + - in: path + name: pm_uuid + schema: + type: string + format: uuid + description: A UUID string identifying this SCIM Source Property Mapping. + required: true + tags: + - propertymappings + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/PatchedSCIMSourcePropertyMappingRequest' + security: + - authentik: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/SCIMSourcePropertyMapping' description: '' '400': content: @@ -17200,17 +17317,18 @@ paths: $ref: '#/components/schemas/GenericError' description: '' delete: - operationId: providers_all_destroy - description: Provider Viewset + operationId: propertymappings_source_scim_destroy + description: SCIMSourcePropertyMapping Viewset parameters: - in: path - name: id + name: pm_uuid schema: - type: integer - description: A unique integer value identifying this provider. + type: string + format: uuid + description: A UUID string identifying this SCIM Source Property Mapping. required: true tags: - - providers + - propertymappings security: - authentik: [] responses: @@ -17228,19 +17346,182 @@ paths: schema: $ref: '#/components/schemas/GenericError' description: '' - /providers/all/{id}/used_by/: + /propertymappings/source/scim/{pm_uuid}/used_by/: get: - operationId: providers_all_used_by_list + operationId: propertymappings_source_scim_used_by_list description: Get a list of all objects that use this object parameters: - in: path - name: id + name: pm_uuid schema: - type: integer - description: A unique integer value identifying this provider. + type: string + format: uuid + description: A UUID string identifying this SCIM Source Property Mapping. required: true tags: - - providers + - propertymappings + security: + - authentik: [] + responses: + '200': + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/UsedBy' + description: '' + '400': + content: + application/json: + schema: + $ref: '#/components/schemas/ValidationError' + description: '' + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/GenericError' + description: '' + /providers/all/: + get: + operationId: providers_all_list + description: Provider Viewset + parameters: + - in: query + name: application__isnull + schema: + type: boolean + - in: query + name: backchannel + schema: + type: boolean + description: When not set all providers are returned. When set to true, only + backchannel providers are returned. When set to false, backchannel providers + are excluded + - name: ordering + required: false + in: query + description: Which field to use when ordering the results. + schema: + type: string + - name: page + required: false + in: query + description: A page number within the paginated result set. + schema: + type: integer + - name: page_size + required: false + in: query + description: Number of results to return per page. + schema: + type: integer + - name: search + required: false + in: query + description: A search term. + schema: + type: string + tags: + - providers + security: + - authentik: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/PaginatedProviderList' + description: '' + '400': + content: + application/json: + schema: + $ref: '#/components/schemas/ValidationError' + description: '' + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/GenericError' + description: '' + /providers/all/{id}/: + get: + operationId: providers_all_retrieve + description: Provider Viewset + parameters: + - in: path + name: id + schema: + type: integer + description: A unique integer value identifying this provider. + required: true + tags: + - providers + security: + - authentik: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/Provider' + description: '' + '400': + content: + application/json: + schema: + $ref: '#/components/schemas/ValidationError' + description: '' + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/GenericError' + description: '' + delete: + operationId: providers_all_destroy + description: Provider Viewset + parameters: + - in: path + name: id + schema: + type: integer + description: A unique integer value identifying this provider. + required: true + tags: + - providers + security: + - authentik: [] + responses: + '204': + description: No response body + '400': + content: + application/json: + schema: + $ref: '#/components/schemas/ValidationError' + description: '' + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/GenericError' + description: '' + /providers/all/{id}/used_by/: + get: + operationId: providers_all_used_by_list + description: Get a list of all objects that use this object + parameters: + - in: path + name: id + schema: + type: integer + description: A unique integer value identifying this provider. + required: true + tags: + - providers security: - authentik: [] responses: @@ -22175,8 +22456,10 @@ paths: - authentik_sources_oauth.oauthsource - authentik_sources_oauth.oauthsourcepropertymapping - authentik_sources_oauth.useroauthsourceconnection + - authentik_sources_plex.groupplexsourceconnection - authentik_sources_plex.plexsource - - authentik_sources_plex.plexsourceconnection + - authentik_sources_plex.plexsourcepropertymapping + - authentik_sources_plex.userplexsourceconnection - authentik_sources_saml.groupsamlsourceconnection - authentik_sources_saml.samlsource - authentik_sources_saml.samlsourcepropertymapping @@ -22407,8 +22690,10 @@ paths: - authentik_sources_oauth.oauthsource - authentik_sources_oauth.oauthsourcepropertymapping - authentik_sources_oauth.useroauthsourceconnection + - authentik_sources_plex.groupplexsourceconnection - authentik_sources_plex.plexsource - - authentik_sources_plex.plexsourceconnection + - authentik_sources_plex.plexsourcepropertymapping + - authentik_sources_plex.userplexsourceconnection - authentik_sources_saml.groupsamlsourceconnection - authentik_sources_saml.samlsource - authentik_sources_saml.samlsourcepropertymapping @@ -23958,6 +24243,258 @@ paths: schema: $ref: '#/components/schemas/GenericError' description: '' + /sources/group_connections/plex/: + get: + operationId: sources_group_connections_plex_list + description: Group-source connection Viewset + parameters: + - in: query + name: group + schema: + type: string + format: uuid + - name: ordering + required: false + in: query + description: Which field to use when ordering the results. + schema: + type: string + - name: page + required: false + in: query + description: A page number within the paginated result set. + schema: + type: integer + - name: page_size + required: false + in: query + description: Number of results to return per page. + schema: + type: integer + - name: search + required: false + in: query + description: A search term. + schema: + type: string + - in: query + name: source__slug + schema: + type: string + tags: + - sources + security: + - authentik: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/PaginatedGroupPlexSourceConnectionList' + description: '' + '400': + content: + application/json: + schema: + $ref: '#/components/schemas/ValidationError' + description: '' + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/GenericError' + description: '' + post: + operationId: sources_group_connections_plex_create + description: Group-source connection Viewset + tags: + - sources + security: + - authentik: [] + responses: + '201': + content: + application/json: + schema: + $ref: '#/components/schemas/GroupPlexSourceConnection' + description: '' + '400': + content: + application/json: + schema: + $ref: '#/components/schemas/ValidationError' + description: '' + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/GenericError' + description: '' + /sources/group_connections/plex/{id}/: + get: + operationId: sources_group_connections_plex_retrieve + description: Group-source connection Viewset + parameters: + - in: path + name: id + schema: + type: integer + description: A unique integer value identifying this Group Plex Source Connection. + required: true + tags: + - sources + security: + - authentik: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/GroupPlexSourceConnection' + description: '' + '400': + content: + application/json: + schema: + $ref: '#/components/schemas/ValidationError' + description: '' + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/GenericError' + description: '' + put: + operationId: sources_group_connections_plex_update + description: Group-source connection Viewset + parameters: + - in: path + name: id + schema: + type: integer + description: A unique integer value identifying this Group Plex Source Connection. + required: true + tags: + - sources + security: + - authentik: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/GroupPlexSourceConnection' + description: '' + '400': + content: + application/json: + schema: + $ref: '#/components/schemas/ValidationError' + description: '' + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/GenericError' + description: '' + patch: + operationId: sources_group_connections_plex_partial_update + description: Group-source connection Viewset + parameters: + - in: path + name: id + schema: + type: integer + description: A unique integer value identifying this Group Plex Source Connection. + required: true + tags: + - sources + security: + - authentik: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/GroupPlexSourceConnection' + description: '' + '400': + content: + application/json: + schema: + $ref: '#/components/schemas/ValidationError' + description: '' + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/GenericError' + description: '' + delete: + operationId: sources_group_connections_plex_destroy + description: Group-source connection Viewset + parameters: + - in: path + name: id + schema: + type: integer + description: A unique integer value identifying this Group Plex Source Connection. + required: true + tags: + - sources + security: + - authentik: [] + responses: + '204': + description: No response body + '400': + content: + application/json: + schema: + $ref: '#/components/schemas/ValidationError' + description: '' + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/GenericError' + description: '' + /sources/group_connections/plex/{id}/used_by/: + get: + operationId: sources_group_connections_plex_used_by_list + description: Get a list of all objects that use this object + parameters: + - in: path + name: id + schema: + type: integer + description: A unique integer value identifying this Group Plex Source Connection. + required: true + tags: + - sources + security: + - authentik: [] + responses: + '200': + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/UsedBy' + description: '' + '400': + content: + application/json: + schema: + $ref: '#/components/schemas/ValidationError' + description: '' + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/GenericError' + description: '' /sources/group_connections/saml/: get: operationId: sources_group_connections_saml_list @@ -25026,6 +25563,17 @@ paths: schema: type: string format: uuid + - in: query + name: group_matching_mode + schema: + type: string + enum: + - identifier + - name_deny + - name_link + description: |+ + How the source determines if an existing group should be used or a new group created. + - in: query name: name schema: @@ -27139,7 +27687,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/PaginatedPlexSourceConnectionList' + $ref: '#/components/schemas/PaginatedUserPlexSourceConnectionList' description: '' '400': content: @@ -27162,7 +27710,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/PlexSourceConnectionRequest' + $ref: '#/components/schemas/UserPlexSourceConnectionRequest' required: true security: - authentik: [] @@ -27171,7 +27719,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/PlexSourceConnection' + $ref: '#/components/schemas/UserPlexSourceConnection' description: '' '400': content: @@ -27205,7 +27753,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/PlexSourceConnection' + $ref: '#/components/schemas/UserPlexSourceConnection' description: '' '400': content: @@ -27235,7 +27783,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/PlexSourceConnectionRequest' + $ref: '#/components/schemas/UserPlexSourceConnectionRequest' required: true security: - authentik: [] @@ -27244,7 +27792,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/PlexSourceConnection' + $ref: '#/components/schemas/UserPlexSourceConnection' description: '' '400': content: @@ -27274,7 +27822,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/PatchedPlexSourceConnectionRequest' + $ref: '#/components/schemas/PatchedUserPlexSourceConnectionRequest' security: - authentik: [] responses: @@ -27282,7 +27830,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/PlexSourceConnection' + $ref: '#/components/schemas/UserPlexSourceConnection' description: '' '400': content: @@ -39635,6 +40183,35 @@ components: - identifier - pk - source + GroupPlexSourceConnection: + type: object + description: Plex Group-Source connection Serializer + properties: + pk: + type: integer + readOnly: true + title: ID + group: + type: string + format: uuid + readOnly: true + source: + allOf: + - $ref: '#/components/schemas/Source' + readOnly: true + identifier: + type: string + readOnly: true + created: + type: string + format: date-time + readOnly: true + required: + - created + - group + - identifier + - pk + - source GroupRequest: type: object description: Group Serializer @@ -41235,7 +41812,9 @@ components: - authentik_sources_oauth.useroauthsourceconnection - authentik_sources_oauth.groupoauthsourceconnection - authentik_sources_plex.plexsource - - authentik_sources_plex.plexsourceconnection + - authentik_sources_plex.plexsourcepropertymapping + - authentik_sources_plex.userplexsourceconnection + - authentik_sources_plex.groupplexsourceconnection - authentik_sources_saml.samlsource - authentik_sources_saml.samlsourcepropertymapping - authentik_sources_saml.usersamlsourceconnection @@ -42764,6 +43343,18 @@ components: required: - pagination - results + PaginatedGroupPlexSourceConnectionList: + type: object + properties: + pagination: + $ref: '#/components/schemas/Pagination' + results: + type: array + items: + $ref: '#/components/schemas/GroupPlexSourceConnection' + required: + - pagination + - results PaginatedGroupSAMLSourceConnectionList: type: object properties: @@ -43076,7 +43667,7 @@ components: required: - pagination - results - PaginatedPlexSourceConnectionList: + PaginatedPlexSourceList: type: object properties: pagination: @@ -43084,11 +43675,11 @@ components: results: type: array items: - $ref: '#/components/schemas/PlexSourceConnection' + $ref: '#/components/schemas/PlexSource' required: - pagination - results - PaginatedPlexSourceList: + PaginatedPlexSourcePropertyMappingList: type: object properties: pagination: @@ -43096,7 +43687,7 @@ components: results: type: array items: - $ref: '#/components/schemas/PlexSource' + $ref: '#/components/schemas/PlexSourcePropertyMapping' required: - pagination - results @@ -43676,6 +44267,18 @@ components: required: - pagination - results + PaginatedUserPlexSourceConnectionList: + type: object + properties: + pagination: + $ref: '#/components/schemas/Pagination' + results: + type: array + items: + $ref: '#/components/schemas/UserPlexSourceConnection' + required: + - pagination + - results PaginatedUserSAMLSourceConnectionList: type: object properties: @@ -45733,16 +46336,24 @@ components: object_pk: type: string minLength: 1 - PatchedPlexSourceConnectionRequest: + PatchedPlexSourcePropertyMappingRequest: type: object - description: Plex Source connection Serializer + description: PlexSourcePropertyMapping Serializer properties: - identifier: + managed: type: string + nullable: true minLength: 1 - plex_token: + title: Managed by authentik + description: Objects that are managed by authentik. These objects are created + and updated automatically. This flag only indicates that an object can + be overwritten by migrations. You can still modify the objects via the + API, but expect changes to be overwritten in a later update. + name: + type: string + minLength: 1 + expression: type: string - writeOnly: true minLength: 1 PatchedPlexSourceRequest: type: object @@ -45790,6 +46401,11 @@ components: user_path_template: type: string minLength: 1 + group_matching_mode: + allOf: + - $ref: '#/components/schemas/GroupMatchingModeEnum' + description: How the source determines if an existing group should be used + or a new group created. client_id: type: string minLength: 1 @@ -46719,6 +47335,17 @@ components: type: string writeOnly: true nullable: true + PatchedUserPlexSourceConnectionRequest: + type: object + description: Plex Source connection Serializer + properties: + identifier: + type: string + minLength: 1 + plex_token: + type: string + writeOnly: true + minLength: 1 PatchedUserRequest: type: object description: User Serializer @@ -46963,6 +47590,11 @@ components: icon: type: string readOnly: true + group_matching_mode: + allOf: + - $ref: '#/components/schemas/GroupMatchingModeEnum' + description: How the source determines if an existing group should be used + or a new group created. client_id: type: string description: Client identifier used to talk to Plex. @@ -46989,47 +47621,73 @@ components: - slug - verbose_name - verbose_name_plural - PlexSourceConnection: + PlexSourcePropertyMapping: type: object - description: Plex Source connection Serializer + description: PlexSourcePropertyMapping Serializer properties: pk: - type: integer + type: string + format: uuid readOnly: true - title: ID - user: - type: integer + title: Pm uuid + managed: + type: string + nullable: true + title: Managed by authentik + description: Objects that are managed by authentik. These objects are created + and updated automatically. This flag only indicates that an object can + be overwritten by migrations. You can still modify the objects via the + API, but expect changes to be overwritten in a later update. + name: + type: string + expression: + type: string + component: + type: string + description: Get object's component so that we know how to edit the object readOnly: true - source: - allOf: - - $ref: '#/components/schemas/Source' + verbose_name: + type: string + description: Return object's verbose_name readOnly: true - created: + verbose_name_plural: type: string - format: date-time + description: Return object's plural verbose_name readOnly: true - identifier: + meta_model_name: type: string + description: Return internal model name + readOnly: true required: - - created - - identifier + - component + - expression + - meta_model_name + - name - pk - - source - - user - PlexSourceConnectionRequest: + - verbose_name + - verbose_name_plural + PlexSourcePropertyMappingRequest: type: object - description: Plex Source connection Serializer + description: PlexSourcePropertyMapping Serializer properties: - identifier: + managed: type: string + nullable: true minLength: 1 - plex_token: + title: Managed by authentik + description: Objects that are managed by authentik. These objects are created + and updated automatically. This flag only indicates that an object can + be overwritten by migrations. You can still modify the objects via the + API, but expect changes to be overwritten in a later update. + name: + type: string + minLength: 1 + expression: type: string - writeOnly: true minLength: 1 required: - - identifier - - plex_token + - expression + - name PlexSourceRequest: type: object description: Plex Source Serializer @@ -47076,6 +47734,11 @@ components: user_path_template: type: string minLength: 1 + group_matching_mode: + allOf: + - $ref: '#/components/schemas/GroupMatchingModeEnum' + description: How the source determines if an existing group should be used + or a new group created. client_id: type: string minLength: 1 @@ -51639,6 +52302,47 @@ components: readOnly: true required: - paths + UserPlexSourceConnection: + type: object + description: Plex Source connection Serializer + properties: + pk: + type: integer + readOnly: true + title: ID + user: + type: integer + readOnly: true + source: + allOf: + - $ref: '#/components/schemas/Source' + readOnly: true + created: + type: string + format: date-time + readOnly: true + identifier: + type: string + required: + - created + - identifier + - pk + - source + - user + UserPlexSourceConnectionRequest: + type: object + description: Plex Source connection Serializer + properties: + identifier: + type: string + minLength: 1 + plex_token: + type: string + writeOnly: true + minLength: 1 + required: + - identifier + - plex_token UserRequest: type: object description: User Serializer diff --git a/web/src/admin/property-mappings/PropertyMappingListPage.ts b/web/src/admin/property-mappings/PropertyMappingListPage.ts index 5d4b32450cd7..3a55062ef8ae 100644 --- a/web/src/admin/property-mappings/PropertyMappingListPage.ts +++ b/web/src/admin/property-mappings/PropertyMappingListPage.ts @@ -3,6 +3,7 @@ import "@goauthentik/admin/property-mappings/PropertyMappingLDAPSourceForm"; import "@goauthentik/admin/property-mappings/PropertyMappingMicrosoftEntraForm"; import "@goauthentik/admin/property-mappings/PropertyMappingNotification"; import "@goauthentik/admin/property-mappings/PropertyMappingOAuthSourceForm"; +import "@goauthentik/admin/property-mappings/PropertyMappingPlexSourceForm"; import "@goauthentik/admin/property-mappings/PropertyMappingRACForm"; import "@goauthentik/admin/property-mappings/PropertyMappingRadiusForm"; import "@goauthentik/admin/property-mappings/PropertyMappingSAMLForm"; diff --git a/web/src/admin/property-mappings/PropertyMappingPlexSourceForm.ts b/web/src/admin/property-mappings/PropertyMappingPlexSourceForm.ts new file mode 100644 index 000000000000..e19277858b17 --- /dev/null +++ b/web/src/admin/property-mappings/PropertyMappingPlexSourceForm.ts @@ -0,0 +1,40 @@ +import { BasePropertyMappingForm } from "@goauthentik/admin/property-mappings/BasePropertyMappingForm"; +import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; +import "@goauthentik/elements/CodeMirror"; +import "@goauthentik/elements/forms/HorizontalFormElement"; + +import { customElement } from "lit/decorators.js"; + +import { PlexSourcePropertyMapping, PropertymappingsApi } from "@goauthentik/api"; + +@customElement("ak-property-mapping-plex-source-form") +export class PropertyMappingPlexSourceForm extends BasePropertyMappingForm { + docLink(): string { + return "/docs/sources/property-mappings/expression?utm_source=authentik"; + } + + loadInstance(pk: string): Promise { + return new PropertymappingsApi(DEFAULT_CONFIG).propertymappingsSourcePlexRetrieve({ + pmUuid: pk, + }); + } + + async send(data: PlexSourcePropertyMapping): Promise { + if (this.instance) { + return new PropertymappingsApi(DEFAULT_CONFIG).propertymappingsSourcePlexUpdate({ + pmUuid: this.instance.pk, + plexSourcePropertyMappingRequest: data, + }); + } else { + return new PropertymappingsApi(DEFAULT_CONFIG).propertymappingsSourcePlexCreate({ + plexSourcePropertyMappingRequest: data, + }); + } + } +} + +declare global { + interface HTMLElementTagNameMap { + "ak-property-mapping-plex-source-form": PropertyMappingPlexSourceForm; + } +} diff --git a/web/src/admin/property-mappings/PropertyMappingWizard.ts b/web/src/admin/property-mappings/PropertyMappingWizard.ts index c2ec879367ad..ea236fc0c08e 100644 --- a/web/src/admin/property-mappings/PropertyMappingWizard.ts +++ b/web/src/admin/property-mappings/PropertyMappingWizard.ts @@ -1,6 +1,7 @@ import "@goauthentik/admin/property-mappings/PropertyMappingLDAPSourceForm"; import "@goauthentik/admin/property-mappings/PropertyMappingNotification"; import "@goauthentik/admin/property-mappings/PropertyMappingOAuthSourceForm"; +import "@goauthentik/admin/property-mappings/PropertyMappingPlexSourceForm"; import "@goauthentik/admin/property-mappings/PropertyMappingRACForm"; import "@goauthentik/admin/property-mappings/PropertyMappingSAMLForm"; import "@goauthentik/admin/property-mappings/PropertyMappingSAMLSourceForm"; diff --git a/web/src/admin/sources/plex/PlexSourceForm.ts b/web/src/admin/sources/plex/PlexSourceForm.ts index 3e4c1374a4b8..530c73fb620d 100644 --- a/web/src/admin/sources/plex/PlexSourceForm.ts +++ b/web/src/admin/sources/plex/PlexSourceForm.ts @@ -1,7 +1,10 @@ import "@goauthentik/admin/common/ak-flow-search/ak-source-flow-search"; import { iconHelperText, placeholderHelperText } from "@goauthentik/admin/helperText"; import { BaseSourceForm } from "@goauthentik/admin/sources/BaseSourceForm"; -import { UserMatchingModeToLabel } from "@goauthentik/admin/sources/oauth/utils"; +import { + GroupMatchingModeToLabel, + UserMatchingModeToLabel, +} from "@goauthentik/admin/sources/oauth/utils"; import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; import { PlexAPIClient, PlexResource, popupCenterScreen } from "@goauthentik/common/helpers/plex"; import { ascii_letters, digits, first, randomString } from "@goauthentik/common/utils"; @@ -9,6 +12,8 @@ import { CapabilitiesEnum, WithCapabilitiesConfig, } from "@goauthentik/elements/Interface/capabilitiesProvider"; +import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js"; +import { DualSelectPair } from "@goauthentik/elements/ak-dual-select/types.js"; import "@goauthentik/elements/forms/FormGroup"; import "@goauthentik/elements/forms/HorizontalFormElement"; import "@goauthentik/elements/forms/SearchSelect"; @@ -20,11 +25,36 @@ import { ifDefined } from "lit/directives/if-defined.js"; import { FlowsInstancesListDesignationEnum, + GroupMatchingModeEnum, PlexSource, + PlexSourcePropertyMapping, + PropertymappingsApi, SourcesApi, UserMatchingModeEnum, } from "@goauthentik/api"; +async function propertyMappingsProvider(page = 1, search = "") { + const propertyMappings = await new PropertymappingsApi( + DEFAULT_CONFIG, + ).propertymappingsSourcePlexList({ + ordering: "managed", + pageSize: 20, + search: search.trim(), + page, + }); + return { + pagination: propertyMappings.pagination, + options: propertyMappings.results.map((m) => [m.pk, m.name, m.name, m]), + }; +} + +function makePropertyMappingsSelector(instanceMappings?: string[]) { + const localMappings = instanceMappings ? new Set(instanceMappings) : undefined; + return localMappings + ? ([pk, _]: DualSelectPair) => localMappings.has(pk) + : ([_0, _1, _2, _]: DualSelectPair) => false; +} + @customElement("ak-source-plex-form") export class PlexSourceForm extends WithCapabilitiesConfig(BaseSourceForm) { async loadInstance(pk: string): Promise { @@ -245,6 +275,35 @@ export class PlexSourceForm extends WithCapabilitiesConfig(BaseSourceForm + + + + + + ${msg("Plex Attribute mapping")} +
+ + +

+ ${msg("Property mappings for user creation.")} +

+
+ + +

+ ${msg("Property mappings for group creation.")} +

+
+
`; } }