sources/plex: add property mappings (#10772)

This commit is contained in:
Marc 'risson' Schmitt
2024-08-08 11:36:24 +02:00
committed by GitHub
parent 82017fac8c
commit 68af5b0572
14 changed files with 1380 additions and 93 deletions

View File

@ -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"]

View File

@ -19,7 +19,7 @@ from authentik.core.api.utils import PassiveSerializer
from authentik.flows.challenge import RedirectChallenge from authentik.flows.challenge import RedirectChallenge
from authentik.flows.views.executor import to_stage_response from authentik.flows.views.executor import to_stage_response
from authentik.rbac.decorators import permission_required 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 from authentik.sources.plex.plex import PlexAuth, PlexSourceFlowManager
LOGGER = get_logger() LOGGER = get_logger()
@ -31,6 +31,7 @@ class PlexSourceSerializer(SourceSerializer):
class Meta: class Meta:
model = PlexSource model = PlexSource
fields = SourceSerializer.Meta.fields + [ fields = SourceSerializer.Meta.fields + [
"group_matching_mode",
"client_id", "client_id",
"allowed_servers", "allowed_servers",
"allow_friends", "allow_friends",
@ -58,6 +59,7 @@ class PlexSourceViewSet(UsedByMixin, ModelViewSet):
"enrollment_flow", "enrollment_flow",
"policy_engine_mode", "policy_engine_mode",
"user_matching_mode", "user_matching_mode",
"group_matching_mode",
"client_id", "client_id",
"allow_friends", "allow_friends",
] ]
@ -109,7 +111,10 @@ class PlexSourceViewSet(UsedByMixin, ModelViewSet):
source=source, source=source,
request=request, request=request,
identifier=str(identifier), identifier=str(identifier),
user_info=user_info, user_info={
"info": user_info,
"auth_api": auth_api,
},
policy_context={}, policy_context={},
) )
return to_stage_response(request, sfm.get_flow(plex_token=plex_token)) return to_stage_response(request, sfm.get_flow(plex_token=plex_token))
@ -158,7 +163,7 @@ class PlexSourceViewSet(UsedByMixin, ModelViewSet):
friends_allowed = owner_api.check_friends_overlap(identifier) friends_allowed = owner_api.check_friends_overlap(identifier)
servers_allowed = auth_api.check_server_overlap() servers_allowed = auth_api.check_server_overlap()
if any([friends_allowed, servers_allowed]): if any([friends_allowed, servers_allowed]):
PlexSourceConnection.objects.create( UserPlexSourceConnection.objects.create(
plex_token=plex_token, plex_token=plex_token,
user=request.user, user=request.user,
identifier=identifier, identifier=identifier,

View File

@ -2,15 +2,20 @@
from rest_framework.viewsets import ModelViewSet from rest_framework.viewsets import ModelViewSet
from authentik.core.api.sources import UserSourceConnectionSerializer, UserSourceConnectionViewSet from authentik.core.api.sources import (
from authentik.sources.plex.models import PlexSourceConnection GroupSourceConnectionSerializer,
GroupSourceConnectionViewSet,
UserSourceConnectionSerializer,
UserSourceConnectionViewSet,
)
from authentik.sources.plex.models import GroupPlexSourceConnection, UserPlexSourceConnection
class PlexSourceConnectionSerializer(UserSourceConnectionSerializer): class UserPlexSourceConnectionSerializer(UserSourceConnectionSerializer):
"""Plex Source connection Serializer""" """Plex Source connection Serializer"""
class Meta(UserSourceConnectionSerializer.Meta): class Meta(UserSourceConnectionSerializer.Meta):
model = PlexSourceConnection model = UserPlexSourceConnection
fields = UserSourceConnectionSerializer.Meta.fields + [ fields = UserSourceConnectionSerializer.Meta.fields + [
"identifier", "identifier",
"plex_token", "plex_token",
@ -21,8 +26,22 @@ class PlexSourceConnectionSerializer(UserSourceConnectionSerializer):
} }
class PlexSourceConnectionViewSet(UserSourceConnectionViewSet, ModelViewSet): class UserPlexSourceConnectionViewSet(UserSourceConnectionViewSet, ModelViewSet):
"""Plex Source connection Serializer""" """Plex Source connection Serializer"""
queryset = PlexSourceConnection.objects.all() queryset = UserPlexSourceConnection.objects.all()
serializer_class = PlexSourceConnectionSerializer 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

View File

@ -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",
),
]

View File

@ -1,5 +1,7 @@
"""Plex source""" """Plex source"""
from typing import Any
from django.contrib.postgres.fields import ArrayField from django.contrib.postgres.fields import ArrayField
from django.db import models from django.db import models
from django.http.request import HttpRequest from django.http.request import HttpRequest
@ -8,7 +10,12 @@ from django.utils.translation import gettext_lazy as _
from rest_framework.fields import CharField from rest_framework.fields import CharField
from rest_framework.serializers import BaseSerializer, Serializer 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.core.types import UILoginButton, UserSettingSerializer
from authentik.flows.challenge import Challenge, ChallengeResponse from authentik.flows.challenge import Challenge, ChallengeResponse
from authentik.lib.generators import generate_id from authentik.lib.generators import generate_id
@ -60,6 +67,22 @@ class PlexSource(Source):
return PlexSourceSerializer 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 @property
def icon_url(self) -> str: def icon_url(self) -> str:
icon = super().icon_url icon = super().icon_url
@ -95,18 +118,52 @@ class PlexSource(Source):
verbose_name_plural = _("Plex Sources") 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""" """Connect user and plex source"""
plex_token = models.TextField() plex_token = models.TextField()
identifier = models.TextField() identifier = models.TextField()
@property @property
def serializer(self) -> Serializer: def serializer(self) -> type[Serializer]:
from authentik.sources.plex.api.source_connection import PlexSourceConnectionSerializer from authentik.sources.plex.api.source_connection import UserPlexSourceConnectionSerializer
return PlexSourceConnectionSerializer return UserPlexSourceConnectionSerializer
class Meta: class Meta:
verbose_name = _("User Plex Source Connection") verbose_name = _("User Plex Source Connection")
verbose_name_plural = _("User Plex Source Connections") 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")

View File

@ -9,7 +9,7 @@ from structlog.stdlib import get_logger
from authentik import __version__ from authentik import __version__
from authentik.core.sources.flow_manager import SourceFlowManager from authentik.core.sources.flow_manager import SourceFlowManager
from authentik.lib.utils.http import get_http_session 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() LOGGER = get_logger()
@ -73,11 +73,7 @@ class PlexAuth:
) )
response.raise_for_status() response.raise_for_status()
raw_user_info = response.json() raw_user_info = response.json()
return { return raw_user_info, raw_user_info.get("id")
"username": raw_user_info.get("username"),
"email": raw_user_info.get("email"),
"name": raw_user_info.get("title"),
}, raw_user_info.get("id")
def check_server_overlap(self) -> bool: def check_server_overlap(self) -> bool:
"""Check if the plex-token has any server overlap with our configured servers""" """Check if the plex-token has any server overlap with our configured servers"""
@ -113,11 +109,11 @@ class PlexAuth:
class PlexSourceFlowManager(SourceFlowManager): class PlexSourceFlowManager(SourceFlowManager):
"""Flow manager for plex sources""" """Flow manager for plex sources"""
user_connection_type = PlexSourceConnection user_connection_type = UserPlexSourceConnection
def update_user_connection( def update_user_connection(
self, connection: PlexSourceConnection, **kwargs self, connection: UserPlexSourceConnection, **kwargs
) -> PlexSourceConnection: ) -> UserPlexSourceConnection:
"""Set the access_token on the connection""" """Set the access_token on the connection"""
connection.plex_token = kwargs.get("plex_token") connection.plex_token = kwargs.get("plex_token")
return connection return connection

View File

@ -54,7 +54,7 @@ class TestPlexSource(TestCase):
self.assertEqual( self.assertEqual(
api.get_user_info(), api.get_user_info(),
( (
{"username": "username", "email": "foo@bar.baz", "name": "title"}, USER_INFO_RESPONSE,
1234123419, 1234123419,
), ),
) )
@ -82,3 +82,21 @@ class TestPlexSource(TestCase):
mocker.get("https://plex.tv/api/v2/user", exc=RequestException()) mocker.get("https://plex.tv/api/v2/user", exc=RequestException())
check_plex_token_all() check_plex_token_all()
self.assertTrue(Event.objects.filter(action=EventAction.CONFIGURATION_ERROR).exists()) 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})

View File

@ -1,9 +1,15 @@
"""API URLs""" """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 import PlexSourceViewSet
from authentik.sources.plex.api.source_connection import PlexSourceConnectionViewSet from authentik.sources.plex.api.source_connection import (
GroupPlexSourceConnectionViewSet,
UserPlexSourceConnectionViewSet,
)
api_urlpatterns = [ api_urlpatterns = [
("sources/user_connections/plex", PlexSourceConnectionViewSet), ("propertymappings/source/plex", PlexSourcePropertyMappingViewSet),
("sources/user_connections/plex", UserPlexSourceConnectionViewSet),
("sources/group_connections/plex", GroupPlexSourceConnectionViewSet),
("sources/plex", PlexSourceViewSet), ("sources/plex", PlexSourceViewSet),
] ]

View File

@ -1369,7 +1369,7 @@
], ],
"properties": { "properties": {
"model": { "model": {
"const": "authentik_sources_plex.plexsourceconnection" "const": "authentik_sources_plex.plexsourcepropertymapping"
}, },
"id": { "id": {
"type": "string" "type": "string"
@ -1391,13 +1391,93 @@
} }
}, },
"permissions": { "permissions": {
"$ref": "#/$defs/model_authentik_sources_plex.plexsourceconnection_permissions" "$ref": "#/$defs/model_authentik_sources_plex.plexsourcepropertymapping_permissions"
}, },
"attrs": { "attrs": {
"$ref": "#/$defs/model_authentik_sources_plex.plexsourceconnection" "$ref": "#/$defs/model_authentik_sources_plex.plexsourcepropertymapping"
}, },
"identifiers": { "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.useroauthsourceconnection",
"authentik_sources_oauth.groupoauthsourceconnection", "authentik_sources_oauth.groupoauthsourceconnection",
"authentik_sources_plex.plexsource", "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.samlsource",
"authentik_sources_saml.samlsourcepropertymapping", "authentik_sources_saml.samlsourcepropertymapping",
"authentik_sources_saml.usersamlsourceconnection", "authentik_sources_saml.usersamlsourceconnection",
@ -5966,6 +6048,10 @@
"authentik_core.delete_group", "authentik_core.delete_group",
"authentik_core.remove_user_from_group", "authentik_core.remove_user_from_group",
"authentik_core.view_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.add_propertymapping",
"authentik_core.change_propertymapping", "authentik_core.change_propertymapping",
"authentik_core.delete_propertymapping", "authentik_core.delete_propertymapping",
@ -6235,6 +6321,22 @@
"authentik_rbac.edit_system_settings", "authentik_rbac.edit_system_settings",
"authentik_rbac.view_system_info", "authentik_rbac.view_system_info",
"authentik_rbac.view_system_settings", "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.add_ldapsource",
"authentik_sources_ldap.change_ldapsource", "authentik_sources_ldap.change_ldapsource",
"authentik_sources_ldap.delete_ldapsource", "authentik_sources_ldap.delete_ldapsource",
@ -6243,10 +6345,18 @@
"authentik_sources_ldap.change_ldapsourcepropertymapping", "authentik_sources_ldap.change_ldapsourcepropertymapping",
"authentik_sources_ldap.delete_ldapsourcepropertymapping", "authentik_sources_ldap.delete_ldapsourcepropertymapping",
"authentik_sources_ldap.view_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.add_oauthsource",
"authentik_sources_oauth.change_oauthsource", "authentik_sources_oauth.change_oauthsource",
"authentik_sources_oauth.delete_oauthsource", "authentik_sources_oauth.delete_oauthsource",
"authentik_sources_oauth.view_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.add_useroauthsourceconnection",
"authentik_sources_oauth.change_useroauthsourceconnection", "authentik_sources_oauth.change_useroauthsourceconnection",
"authentik_sources_oauth.delete_useroauthsourceconnection", "authentik_sources_oauth.delete_useroauthsourceconnection",
@ -6259,10 +6369,18 @@
"authentik_sources_plex.change_plexsourceconnection", "authentik_sources_plex.change_plexsourceconnection",
"authentik_sources_plex.delete_plexsourceconnection", "authentik_sources_plex.delete_plexsourceconnection",
"authentik_sources_plex.view_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.add_samlsource",
"authentik_sources_saml.change_samlsource", "authentik_sources_saml.change_samlsource",
"authentik_sources_saml.delete_samlsource", "authentik_sources_saml.delete_samlsource",
"authentik_sources_saml.view_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.add_usersamlsourceconnection",
"authentik_sources_saml.change_usersamlsourceconnection", "authentik_sources_saml.change_usersamlsourceconnection",
"authentik_sources_saml.delete_usersamlsourceconnection", "authentik_sources_saml.delete_usersamlsourceconnection",
@ -7118,6 +7236,16 @@
"minLength": 1, "minLength": 1,
"title": "Icon" "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": { "client_id": {
"type": "string", "type": "string",
"minLength": 1, "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", "type": "object",
"properties": { "properties": {
"identifier": { "identifier": {
@ -7195,7 +7374,7 @@
}, },
"required": [] "required": []
}, },
"model_authentik_sources_plex.plexsourceconnection_permissions": { "model_authentik_sources_plex.userplexsourceconnection_permissions": {
"type": "array", "type": "array",
"items": { "items": {
"type": "object", "type": "object",
@ -7206,10 +7385,47 @@
"permission": { "permission": {
"type": "string", "type": "string",
"enum": [ "enum": [
"add_plexsourceconnection", "add_userplexsourceconnection",
"change_plexsourceconnection", "change_userplexsourceconnection",
"delete_plexsourceconnection", "delete_userplexsourceconnection",
"view_plexsourceconnection" "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",
"required": [
"permission"
],
"properties": {
"permission": {
"type": "string",
"enum": [
"add_groupplexsourceconnection",
"change_groupplexsourceconnection",
"delete_groupplexsourceconnection",
"view_groupplexsourceconnection"
] ]
}, },
"user": { "user": {
@ -11495,6 +11711,10 @@
"authentik_core.delete_group", "authentik_core.delete_group",
"authentik_core.remove_user_from_group", "authentik_core.remove_user_from_group",
"authentik_core.view_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.add_propertymapping",
"authentik_core.change_propertymapping", "authentik_core.change_propertymapping",
"authentik_core.delete_propertymapping", "authentik_core.delete_propertymapping",
@ -11764,6 +11984,22 @@
"authentik_rbac.edit_system_settings", "authentik_rbac.edit_system_settings",
"authentik_rbac.view_system_info", "authentik_rbac.view_system_info",
"authentik_rbac.view_system_settings", "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.add_ldapsource",
"authentik_sources_ldap.change_ldapsource", "authentik_sources_ldap.change_ldapsource",
"authentik_sources_ldap.delete_ldapsource", "authentik_sources_ldap.delete_ldapsource",
@ -11772,10 +12008,18 @@
"authentik_sources_ldap.change_ldapsourcepropertymapping", "authentik_sources_ldap.change_ldapsourcepropertymapping",
"authentik_sources_ldap.delete_ldapsourcepropertymapping", "authentik_sources_ldap.delete_ldapsourcepropertymapping",
"authentik_sources_ldap.view_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.add_oauthsource",
"authentik_sources_oauth.change_oauthsource", "authentik_sources_oauth.change_oauthsource",
"authentik_sources_oauth.delete_oauthsource", "authentik_sources_oauth.delete_oauthsource",
"authentik_sources_oauth.view_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.add_useroauthsourceconnection",
"authentik_sources_oauth.change_useroauthsourceconnection", "authentik_sources_oauth.change_useroauthsourceconnection",
"authentik_sources_oauth.delete_useroauthsourceconnection", "authentik_sources_oauth.delete_useroauthsourceconnection",
@ -11788,10 +12032,18 @@
"authentik_sources_plex.change_plexsourceconnection", "authentik_sources_plex.change_plexsourceconnection",
"authentik_sources_plex.delete_plexsourceconnection", "authentik_sources_plex.delete_plexsourceconnection",
"authentik_sources_plex.view_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.add_samlsource",
"authentik_sources_saml.change_samlsource", "authentik_sources_saml.change_samlsource",
"authentik_sources_saml.delete_samlsource", "authentik_sources_saml.delete_samlsource",
"authentik_sources_saml.view_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.add_usersamlsourceconnection",
"authentik_sources_saml.change_usersamlsourceconnection", "authentik_sources_saml.change_usersamlsourceconnection",
"authentik_sources_saml.delete_usersamlsourceconnection", "authentik_sources_saml.delete_usersamlsourceconnection",

View File

@ -16540,6 +16540,287 @@ paths:
schema: schema:
$ref: '#/components/schemas/GenericError' $ref: '#/components/schemas/GenericError'
description: '' description: ''
/propertymappings/source/plex/:
get:
operationId: propertymappings_source_plex_list
description: PlexSourcePropertyMapping Viewset
parameters:
- in: query
name: managed
schema:
type: array
items:
type: string
explode: true
style: form
- in: query
name: managed__isnull
schema:
type: boolean
- in: query
name: name
schema:
type: string
- 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:
- propertymappings
security:
- authentik: []
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/PaginatedPlexSourcePropertyMappingList'
description: ''
'400':
content:
application/json:
schema:
$ref: '#/components/schemas/ValidationError'
description: ''
'403':
content:
application/json:
schema:
$ref: '#/components/schemas/GenericError'
description: ''
post:
operationId: propertymappings_source_plex_create
description: PlexSourcePropertyMapping Viewset
tags:
- propertymappings
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/PlexSourcePropertyMappingRequest'
required: true
security:
- authentik: []
responses:
'201':
content:
application/json:
schema:
$ref: '#/components/schemas/PlexSourcePropertyMapping'
description: ''
'400':
content:
application/json:
schema:
$ref: '#/components/schemas/ValidationError'
description: ''
'403':
content:
application/json:
schema:
$ref: '#/components/schemas/GenericError'
description: ''
/propertymappings/source/plex/{pm_uuid}/:
get:
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 Plex Source Property Mapping.
required: true
tags:
- propertymappings
security:
- authentik: []
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/PlexSourcePropertyMapping'
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_plex_update
description: PlexSourcePropertyMapping Viewset
parameters:
- in: path
name: pm_uuid
schema:
type: string
format: uuid
description: A UUID string identifying this Plex Source Property Mapping.
required: true
tags:
- propertymappings
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/PlexSourcePropertyMappingRequest'
required: true
security:
- authentik: []
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/PlexSourcePropertyMapping'
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_plex_partial_update
description: PlexSourcePropertyMapping Viewset
parameters:
- in: path
name: pm_uuid
schema:
type: string
format: uuid
description: A UUID string identifying this Plex Source Property Mapping.
required: true
tags:
- propertymappings
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/PatchedPlexSourcePropertyMappingRequest'
security:
- authentik: []
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/PlexSourcePropertyMapping'
description: ''
'400':
content:
application/json:
schema:
$ref: '#/components/schemas/ValidationError'
description: ''
'403':
content:
application/json:
schema:
$ref: '#/components/schemas/GenericError'
description: ''
delete:
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 Plex Source Property Mapping.
required: true
tags:
- propertymappings
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: ''
/propertymappings/source/plex/{pm_uuid}/used_by/:
get:
operationId: propertymappings_source_plex_used_by_list
description: Get a list of all objects that use this object
parameters:
- in: path
name: pm_uuid
schema:
type: string
format: uuid
description: A UUID string identifying this Plex Source Property Mapping.
required: true
tags:
- 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: ''
/propertymappings/source/saml/: /propertymappings/source/saml/:
get: get:
operationId: propertymappings_source_saml_list operationId: propertymappings_source_saml_list
@ -22175,8 +22456,10 @@ paths:
- authentik_sources_oauth.oauthsource - authentik_sources_oauth.oauthsource
- authentik_sources_oauth.oauthsourcepropertymapping - authentik_sources_oauth.oauthsourcepropertymapping
- authentik_sources_oauth.useroauthsourceconnection - authentik_sources_oauth.useroauthsourceconnection
- authentik_sources_plex.groupplexsourceconnection
- authentik_sources_plex.plexsource - authentik_sources_plex.plexsource
- authentik_sources_plex.plexsourceconnection - authentik_sources_plex.plexsourcepropertymapping
- authentik_sources_plex.userplexsourceconnection
- authentik_sources_saml.groupsamlsourceconnection - authentik_sources_saml.groupsamlsourceconnection
- authentik_sources_saml.samlsource - authentik_sources_saml.samlsource
- authentik_sources_saml.samlsourcepropertymapping - authentik_sources_saml.samlsourcepropertymapping
@ -22407,8 +22690,10 @@ paths:
- authentik_sources_oauth.oauthsource - authentik_sources_oauth.oauthsource
- authentik_sources_oauth.oauthsourcepropertymapping - authentik_sources_oauth.oauthsourcepropertymapping
- authentik_sources_oauth.useroauthsourceconnection - authentik_sources_oauth.useroauthsourceconnection
- authentik_sources_plex.groupplexsourceconnection
- authentik_sources_plex.plexsource - authentik_sources_plex.plexsource
- authentik_sources_plex.plexsourceconnection - authentik_sources_plex.plexsourcepropertymapping
- authentik_sources_plex.userplexsourceconnection
- authentik_sources_saml.groupsamlsourceconnection - authentik_sources_saml.groupsamlsourceconnection
- authentik_sources_saml.samlsource - authentik_sources_saml.samlsource
- authentik_sources_saml.samlsourcepropertymapping - authentik_sources_saml.samlsourcepropertymapping
@ -23958,6 +24243,258 @@ paths:
schema: schema:
$ref: '#/components/schemas/GenericError' $ref: '#/components/schemas/GenericError'
description: '' 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/: /sources/group_connections/saml/:
get: get:
operationId: sources_group_connections_saml_list operationId: sources_group_connections_saml_list
@ -25026,6 +25563,17 @@ paths:
schema: schema:
type: string type: string
format: uuid 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 - in: query
name: name name: name
schema: schema:
@ -27139,7 +27687,7 @@ paths:
content: content:
application/json: application/json:
schema: schema:
$ref: '#/components/schemas/PaginatedPlexSourceConnectionList' $ref: '#/components/schemas/PaginatedUserPlexSourceConnectionList'
description: '' description: ''
'400': '400':
content: content:
@ -27162,7 +27710,7 @@ paths:
content: content:
application/json: application/json:
schema: schema:
$ref: '#/components/schemas/PlexSourceConnectionRequest' $ref: '#/components/schemas/UserPlexSourceConnectionRequest'
required: true required: true
security: security:
- authentik: [] - authentik: []
@ -27171,7 +27719,7 @@ paths:
content: content:
application/json: application/json:
schema: schema:
$ref: '#/components/schemas/PlexSourceConnection' $ref: '#/components/schemas/UserPlexSourceConnection'
description: '' description: ''
'400': '400':
content: content:
@ -27205,7 +27753,7 @@ paths:
content: content:
application/json: application/json:
schema: schema:
$ref: '#/components/schemas/PlexSourceConnection' $ref: '#/components/schemas/UserPlexSourceConnection'
description: '' description: ''
'400': '400':
content: content:
@ -27235,7 +27783,7 @@ paths:
content: content:
application/json: application/json:
schema: schema:
$ref: '#/components/schemas/PlexSourceConnectionRequest' $ref: '#/components/schemas/UserPlexSourceConnectionRequest'
required: true required: true
security: security:
- authentik: [] - authentik: []
@ -27244,7 +27792,7 @@ paths:
content: content:
application/json: application/json:
schema: schema:
$ref: '#/components/schemas/PlexSourceConnection' $ref: '#/components/schemas/UserPlexSourceConnection'
description: '' description: ''
'400': '400':
content: content:
@ -27274,7 +27822,7 @@ paths:
content: content:
application/json: application/json:
schema: schema:
$ref: '#/components/schemas/PatchedPlexSourceConnectionRequest' $ref: '#/components/schemas/PatchedUserPlexSourceConnectionRequest'
security: security:
- authentik: [] - authentik: []
responses: responses:
@ -27282,7 +27830,7 @@ paths:
content: content:
application/json: application/json:
schema: schema:
$ref: '#/components/schemas/PlexSourceConnection' $ref: '#/components/schemas/UserPlexSourceConnection'
description: '' description: ''
'400': '400':
content: content:
@ -39635,6 +40183,35 @@ components:
- identifier - identifier
- pk - pk
- source - 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: GroupRequest:
type: object type: object
description: Group Serializer description: Group Serializer
@ -41235,7 +41812,9 @@ components:
- authentik_sources_oauth.useroauthsourceconnection - authentik_sources_oauth.useroauthsourceconnection
- authentik_sources_oauth.groupoauthsourceconnection - authentik_sources_oauth.groupoauthsourceconnection
- authentik_sources_plex.plexsource - 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.samlsource
- authentik_sources_saml.samlsourcepropertymapping - authentik_sources_saml.samlsourcepropertymapping
- authentik_sources_saml.usersamlsourceconnection - authentik_sources_saml.usersamlsourceconnection
@ -42764,6 +43343,18 @@ components:
required: required:
- pagination - pagination
- results - results
PaginatedGroupPlexSourceConnectionList:
type: object
properties:
pagination:
$ref: '#/components/schemas/Pagination'
results:
type: array
items:
$ref: '#/components/schemas/GroupPlexSourceConnection'
required:
- pagination
- results
PaginatedGroupSAMLSourceConnectionList: PaginatedGroupSAMLSourceConnectionList:
type: object type: object
properties: properties:
@ -43076,18 +43667,6 @@ components:
required: required:
- pagination - pagination
- results - results
PaginatedPlexSourceConnectionList:
type: object
properties:
pagination:
$ref: '#/components/schemas/Pagination'
results:
type: array
items:
$ref: '#/components/schemas/PlexSourceConnection'
required:
- pagination
- results
PaginatedPlexSourceList: PaginatedPlexSourceList:
type: object type: object
properties: properties:
@ -43100,6 +43679,18 @@ components:
required: required:
- pagination - pagination
- results - results
PaginatedPlexSourcePropertyMappingList:
type: object
properties:
pagination:
$ref: '#/components/schemas/Pagination'
results:
type: array
items:
$ref: '#/components/schemas/PlexSourcePropertyMapping'
required:
- pagination
- results
PaginatedPolicyBindingList: PaginatedPolicyBindingList:
type: object type: object
properties: properties:
@ -43676,6 +44267,18 @@ components:
required: required:
- pagination - pagination
- results - results
PaginatedUserPlexSourceConnectionList:
type: object
properties:
pagination:
$ref: '#/components/schemas/Pagination'
results:
type: array
items:
$ref: '#/components/schemas/UserPlexSourceConnection'
required:
- pagination
- results
PaginatedUserSAMLSourceConnectionList: PaginatedUserSAMLSourceConnectionList:
type: object type: object
properties: properties:
@ -45733,16 +46336,24 @@ components:
object_pk: object_pk:
type: string type: string
minLength: 1 minLength: 1
PatchedPlexSourceConnectionRequest: PatchedPlexSourcePropertyMappingRequest:
type: object type: object
description: Plex Source connection Serializer description: PlexSourcePropertyMapping Serializer
properties: properties:
identifier: managed:
type: string
nullable: true
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 type: string
minLength: 1 minLength: 1
plex_token: expression:
type: string type: string
writeOnly: true
minLength: 1 minLength: 1
PatchedPlexSourceRequest: PatchedPlexSourceRequest:
type: object type: object
@ -45790,6 +46401,11 @@ components:
user_path_template: user_path_template:
type: string type: string
minLength: 1 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: client_id:
type: string type: string
minLength: 1 minLength: 1
@ -46719,6 +47335,17 @@ components:
type: string type: string
writeOnly: true writeOnly: true
nullable: 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: PatchedUserRequest:
type: object type: object
description: User Serializer description: User Serializer
@ -46963,6 +47590,11 @@ components:
icon: icon:
type: string type: string
readOnly: true 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: client_id:
type: string type: string
description: Client identifier used to talk to Plex. description: Client identifier used to talk to Plex.
@ -46989,47 +47621,73 @@ components:
- slug - slug
- verbose_name - verbose_name
- verbose_name_plural - verbose_name_plural
PlexSourceConnection: PlexSourcePropertyMapping:
type: object type: object
description: Plex Source connection Serializer description: PlexSourcePropertyMapping Serializer
properties: properties:
pk: pk:
type: integer
readOnly: true
title: ID
user:
type: integer
readOnly: true
source:
allOf:
- $ref: '#/components/schemas/Source'
readOnly: true
created:
type: string type: string
format: date-time format: uuid
readOnly: true readOnly: true
identifier: title: Pm uuid
managed:
type: string 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
verbose_name:
type: string
description: Return object's verbose_name
readOnly: true
verbose_name_plural:
type: string
description: Return object's plural verbose_name
readOnly: true
meta_model_name:
type: string
description: Return internal model name
readOnly: true
required: required:
- created - component
- identifier - expression
- meta_model_name
- name
- pk - pk
- source - verbose_name
- user - verbose_name_plural
PlexSourceConnectionRequest: PlexSourcePropertyMappingRequest:
type: object type: object
description: Plex Source connection Serializer description: PlexSourcePropertyMapping Serializer
properties: properties:
identifier: managed:
type: string
nullable: true
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 type: string
minLength: 1 minLength: 1
plex_token: expression:
type: string type: string
writeOnly: true
minLength: 1 minLength: 1
required: required:
- identifier - expression
- plex_token - name
PlexSourceRequest: PlexSourceRequest:
type: object type: object
description: Plex Source Serializer description: Plex Source Serializer
@ -47076,6 +47734,11 @@ components:
user_path_template: user_path_template:
type: string type: string
minLength: 1 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: client_id:
type: string type: string
minLength: 1 minLength: 1
@ -51639,6 +52302,47 @@ components:
readOnly: true readOnly: true
required: required:
- paths - 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: UserRequest:
type: object type: object
description: User Serializer description: User Serializer

View File

@ -3,6 +3,7 @@ import "@goauthentik/admin/property-mappings/PropertyMappingLDAPSourceForm";
import "@goauthentik/admin/property-mappings/PropertyMappingMicrosoftEntraForm"; import "@goauthentik/admin/property-mappings/PropertyMappingMicrosoftEntraForm";
import "@goauthentik/admin/property-mappings/PropertyMappingNotification"; import "@goauthentik/admin/property-mappings/PropertyMappingNotification";
import "@goauthentik/admin/property-mappings/PropertyMappingOAuthSourceForm"; import "@goauthentik/admin/property-mappings/PropertyMappingOAuthSourceForm";
import "@goauthentik/admin/property-mappings/PropertyMappingPlexSourceForm";
import "@goauthentik/admin/property-mappings/PropertyMappingRACForm"; import "@goauthentik/admin/property-mappings/PropertyMappingRACForm";
import "@goauthentik/admin/property-mappings/PropertyMappingRadiusForm"; import "@goauthentik/admin/property-mappings/PropertyMappingRadiusForm";
import "@goauthentik/admin/property-mappings/PropertyMappingSAMLForm"; import "@goauthentik/admin/property-mappings/PropertyMappingSAMLForm";

View File

@ -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<PlexSourcePropertyMapping> {
docLink(): string {
return "/docs/sources/property-mappings/expression?utm_source=authentik";
}
loadInstance(pk: string): Promise<PlexSourcePropertyMapping> {
return new PropertymappingsApi(DEFAULT_CONFIG).propertymappingsSourcePlexRetrieve({
pmUuid: pk,
});
}
async send(data: PlexSourcePropertyMapping): Promise<PlexSourcePropertyMapping> {
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;
}
}

View File

@ -1,6 +1,7 @@
import "@goauthentik/admin/property-mappings/PropertyMappingLDAPSourceForm"; import "@goauthentik/admin/property-mappings/PropertyMappingLDAPSourceForm";
import "@goauthentik/admin/property-mappings/PropertyMappingNotification"; import "@goauthentik/admin/property-mappings/PropertyMappingNotification";
import "@goauthentik/admin/property-mappings/PropertyMappingOAuthSourceForm"; import "@goauthentik/admin/property-mappings/PropertyMappingOAuthSourceForm";
import "@goauthentik/admin/property-mappings/PropertyMappingPlexSourceForm";
import "@goauthentik/admin/property-mappings/PropertyMappingRACForm"; import "@goauthentik/admin/property-mappings/PropertyMappingRACForm";
import "@goauthentik/admin/property-mappings/PropertyMappingSAMLForm"; import "@goauthentik/admin/property-mappings/PropertyMappingSAMLForm";
import "@goauthentik/admin/property-mappings/PropertyMappingSAMLSourceForm"; import "@goauthentik/admin/property-mappings/PropertyMappingSAMLSourceForm";

View File

@ -1,7 +1,10 @@
import "@goauthentik/admin/common/ak-flow-search/ak-source-flow-search"; import "@goauthentik/admin/common/ak-flow-search/ak-source-flow-search";
import { iconHelperText, placeholderHelperText } from "@goauthentik/admin/helperText"; import { iconHelperText, placeholderHelperText } from "@goauthentik/admin/helperText";
import { BaseSourceForm } from "@goauthentik/admin/sources/BaseSourceForm"; 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 { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { PlexAPIClient, PlexResource, popupCenterScreen } from "@goauthentik/common/helpers/plex"; import { PlexAPIClient, PlexResource, popupCenterScreen } from "@goauthentik/common/helpers/plex";
import { ascii_letters, digits, first, randomString } from "@goauthentik/common/utils"; import { ascii_letters, digits, first, randomString } from "@goauthentik/common/utils";
@ -9,6 +12,8 @@ import {
CapabilitiesEnum, CapabilitiesEnum,
WithCapabilitiesConfig, WithCapabilitiesConfig,
} from "@goauthentik/elements/Interface/capabilitiesProvider"; } 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/FormGroup";
import "@goauthentik/elements/forms/HorizontalFormElement"; import "@goauthentik/elements/forms/HorizontalFormElement";
import "@goauthentik/elements/forms/SearchSelect"; import "@goauthentik/elements/forms/SearchSelect";
@ -20,11 +25,36 @@ import { ifDefined } from "lit/directives/if-defined.js";
import { import {
FlowsInstancesListDesignationEnum, FlowsInstancesListDesignationEnum,
GroupMatchingModeEnum,
PlexSource, PlexSource,
PlexSourcePropertyMapping,
PropertymappingsApi,
SourcesApi, SourcesApi,
UserMatchingModeEnum, UserMatchingModeEnum,
} from "@goauthentik/api"; } 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<PlexSourcePropertyMapping>) => false;
}
@customElement("ak-source-plex-form") @customElement("ak-source-plex-form")
export class PlexSourceForm extends WithCapabilitiesConfig(BaseSourceForm<PlexSource>) { export class PlexSourceForm extends WithCapabilitiesConfig(BaseSourceForm<PlexSource>) {
async loadInstance(pk: string): Promise<PlexSource> { async loadInstance(pk: string): Promise<PlexSource> {
@ -245,6 +275,35 @@ export class PlexSourceForm extends WithCapabilitiesConfig(BaseSourceForm<PlexSo
</option> </option>
</select> </select>
</ak-form-element-horizontal> </ak-form-element-horizontal>
<ak-form-element-horizontal
label=${msg("Group matching mode")}
?required=${true}
name="groupMatchingMode"
>
<select class="pf-c-form-control">
<option
value=${GroupMatchingModeEnum.Identifier}
?selected=${this.instance?.groupMatchingMode ===
GroupMatchingModeEnum.Identifier}
>
${UserMatchingModeToLabel(UserMatchingModeEnum.Identifier)}
</option>
<option
value=${GroupMatchingModeEnum.NameLink}
?selected=${this.instance?.groupMatchingMode ===
GroupMatchingModeEnum.NameLink}
>
${GroupMatchingModeToLabel(GroupMatchingModeEnum.NameLink)}
</option>
<option
value=${GroupMatchingModeEnum.NameDeny}
?selected=${this.instance?.groupMatchingMode ===
GroupMatchingModeEnum.NameDeny}
>
${GroupMatchingModeToLabel(GroupMatchingModeEnum.NameDeny)}
</option>
</select>
</ak-form-element-horizontal>
<ak-form-element-horizontal label=${msg("User path")} name="userPathTemplate"> <ak-form-element-horizontal label=${msg("User path")} name="userPathTemplate">
<input <input
type="text" type="text"
@ -354,6 +413,43 @@ export class PlexSourceForm extends WithCapabilitiesConfig(BaseSourceForm<PlexSo
</p> </p>
</ak-form-element-horizontal> </ak-form-element-horizontal>
</div> </div>
</ak-form-group>
<ak-form-group ?expanded=${true}>
<span slot="header"> ${msg("Plex Attribute mapping")} </span>
<div slot="body" class="pf-c-form">
<ak-form-element-horizontal
label=${msg("User Property Mappings")}
name="userPropertyMappings"
>
<ak-dual-select-dynamic-selected
.provider=${propertyMappingsProvider}
.selector=${makePropertyMappingsSelector(
this.instance?.userPropertyMappings,
)}
available-label="${msg("Available User Property Mappings")}"
selected-label="${msg("Selected User Property Mappings")}"
></ak-dual-select-dynamic-selected>
<p class="pf-c-form__helper-text">
${msg("Property mappings for user creation.")}
</p>
</ak-form-element-horizontal>
<ak-form-element-horizontal
label=${msg("Group Property Mappings")}
name="groupPropertyMappings"
>
<ak-dual-select-dynamic-selected
.provider=${propertyMappingsProvider}
.selector=${makePropertyMappingsSelector(
this.instance?.groupPropertyMappings,
)}
available-label="${msg("Available Group Property Mappings")}"
selected-label="${msg("Selected Group Property Mappings")}"
></ak-dual-select-dynamic-selected>
<p class="pf-c-form__helper-text">
${msg("Property mappings for group creation.")}
</p>
</ak-form-element-horizontal>
</div>
</ak-form-group>`; </ak-form-group>`;
} }
} }