Compare commits

..

2 Commits

Author SHA1 Message Date
b0679bb0fa website/docs: Break line. 2025-04-14 17:16:15 +02:00
153fc7cc3b website/docs: Add whitespace. 2025-04-14 17:07:23 +02:00
119 changed files with 8572 additions and 9345 deletions

View File

@ -7,7 +7,7 @@ from rest_framework.exceptions import ValidationError
from rest_framework.fields import CharField, DateTimeField from rest_framework.fields import CharField, DateTimeField
from rest_framework.request import Request from rest_framework.request import Request
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework.serializers import ListSerializer from rest_framework.serializers import ListSerializer, ModelSerializer
from rest_framework.viewsets import ModelViewSet from rest_framework.viewsets import ModelViewSet
from authentik.blueprints.models import BlueprintInstance from authentik.blueprints.models import BlueprintInstance
@ -15,7 +15,7 @@ from authentik.blueprints.v1.importer import Importer
from authentik.blueprints.v1.oci import OCI_PREFIX from authentik.blueprints.v1.oci import OCI_PREFIX
from authentik.blueprints.v1.tasks import apply_blueprint, blueprints_find_dict from authentik.blueprints.v1.tasks import apply_blueprint, blueprints_find_dict
from authentik.core.api.used_by import UsedByMixin from authentik.core.api.used_by import UsedByMixin
from authentik.core.api.utils import JSONDictField, ModelSerializer, PassiveSerializer from authentik.core.api.utils import JSONDictField, PassiveSerializer
from authentik.rbac.decorators import permission_required from authentik.rbac.decorators import permission_required

View File

@ -20,8 +20,6 @@ from rest_framework.serializers import (
raise_errors_on_nested_writes, raise_errors_on_nested_writes,
) )
from authentik.rbac.permissions import assign_initial_permissions
def is_dict(value: Any): def is_dict(value: Any):
"""Ensure a value is a dictionary, useful for JSONFields""" """Ensure a value is a dictionary, useful for JSONFields"""
@ -31,14 +29,6 @@ def is_dict(value: Any):
class ModelSerializer(BaseModelSerializer): class ModelSerializer(BaseModelSerializer):
def create(self, validated_data):
instance = super().create(validated_data)
request = self.context.get("request")
if request and hasattr(request, "user") and not request.user.is_anonymous:
assign_initial_permissions(request.user, instance)
return instance
def update(self, instance: Model, validated_data): def update(self, instance: Model, validated_data):
raise_errors_on_nested_writes("update", self, validated_data) raise_errors_on_nested_writes("update", self, validated_data)

View File

@ -1,17 +1,9 @@
"""Test API Utils""" """Test API Utils"""
from rest_framework.exceptions import ValidationError from rest_framework.exceptions import ValidationError
from rest_framework.serializers import (
HyperlinkedModelSerializer,
)
from rest_framework.serializers import (
ModelSerializer as BaseModelSerializer,
)
from rest_framework.test import APITestCase from rest_framework.test import APITestCase
from authentik.core.api.utils import ModelSerializer as CustomModelSerializer
from authentik.core.api.utils import is_dict from authentik.core.api.utils import is_dict
from authentik.lib.utils.reflection import all_subclasses
class TestAPIUtils(APITestCase): class TestAPIUtils(APITestCase):
@ -22,14 +14,3 @@ class TestAPIUtils(APITestCase):
self.assertIsNone(is_dict({})) self.assertIsNone(is_dict({}))
with self.assertRaises(ValidationError): with self.assertRaises(ValidationError):
is_dict("foo") is_dict("foo")
def test_all_serializers_descend_from_custom(self):
"""Test that every serializer we define descends from our own ModelSerializer"""
# Weirdly, there's only one serializer in `rest_framework` which descends from
# ModelSerializer: HyperlinkedModelSerializer
expected = {CustomModelSerializer, HyperlinkedModelSerializer}
actual = set(all_subclasses(BaseModelSerializer)) - set(
all_subclasses(CustomModelSerializer)
)
self.assertEqual(expected, actual)

View File

@ -4,9 +4,10 @@ from rest_framework.exceptions import PermissionDenied, ValidationError
from rest_framework.fields import CharField, ChoiceField, ListField, SerializerMethodField from rest_framework.fields import CharField, ChoiceField, ListField, SerializerMethodField
from rest_framework.request import Request from rest_framework.request import Request
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework.serializers import ModelSerializer
from structlog.stdlib import get_logger from structlog.stdlib import get_logger
from authentik.core.api.utils import ModelSerializer, PassiveSerializer from authentik.core.api.utils import PassiveSerializer
from authentik.enterprise.providers.ssf.models import ( from authentik.enterprise.providers.ssf.models import (
DeliveryMethods, DeliveryMethods,
EventTypes, EventTypes,

View File

@ -2,11 +2,11 @@
from rest_framework import mixins from rest_framework import mixins
from rest_framework.permissions import IsAdminUser from rest_framework.permissions import IsAdminUser
from rest_framework.serializers import ModelSerializer
from rest_framework.viewsets import GenericViewSet, ModelViewSet from rest_framework.viewsets import GenericViewSet, ModelViewSet
from structlog.stdlib import get_logger from structlog.stdlib import get_logger
from authentik.core.api.used_by import UsedByMixin from authentik.core.api.used_by import UsedByMixin
from authentik.core.api.utils import ModelSerializer
from authentik.enterprise.api import EnterpriseRequiredMixin from authentik.enterprise.api import EnterpriseRequiredMixin
from authentik.enterprise.stages.authenticator_endpoint_gdtc.models import ( from authentik.enterprise.stages.authenticator_endpoint_gdtc.models import (
AuthenticatorEndpointGDTCStage, AuthenticatorEndpointGDTCStage,

View File

@ -48,7 +48,6 @@ class TestFlowInspector(APITestCase):
"allow_show_password": False, "allow_show_password": False,
"captcha_stage": None, "captcha_stage": None,
"component": "ak-stage-identification", "component": "ak-stage-identification",
"enable_remember_me": False,
"flow_info": { "flow_info": {
"background": "/static/dist/assets/images/flow_background.jpg", "background": "/static/dist/assets/images/flow_background.jpg",
"cancel_url": reverse("authentik_flows:cancel"), "cancel_url": reverse("authentik_flows:cancel"),

View File

@ -356,14 +356,6 @@ def redis_url(db: int) -> str:
def django_db_config(config: ConfigLoader | None = None) -> dict: def django_db_config(config: ConfigLoader | None = None) -> dict:
if not config: if not config:
config = CONFIG config = CONFIG
pool_options = False
use_pool = config.get_bool("postgresql.use_pool", False)
if use_pool:
pool_options = config.get_dict_from_b64_json("postgresql.pool_options", True)
if not pool_options:
pool_options = True
db = { db = {
"default": { "default": {
"ENGINE": "authentik.root.db", "ENGINE": "authentik.root.db",
@ -377,7 +369,6 @@ def django_db_config(config: ConfigLoader | None = None) -> dict:
"sslrootcert": config.get("postgresql.sslrootcert"), "sslrootcert": config.get("postgresql.sslrootcert"),
"sslcert": config.get("postgresql.sslcert"), "sslcert": config.get("postgresql.sslcert"),
"sslkey": config.get("postgresql.sslkey"), "sslkey": config.get("postgresql.sslkey"),
"pool": pool_options,
}, },
"CONN_MAX_AGE": config.get_optional_int("postgresql.conn_max_age", 0), "CONN_MAX_AGE": config.get_optional_int("postgresql.conn_max_age", 0),
"CONN_HEALTH_CHECKS": config.get_bool("postgresql.conn_health_checks", False), "CONN_HEALTH_CHECKS": config.get_bool("postgresql.conn_health_checks", False),

View File

@ -21,7 +21,6 @@ postgresql:
user: authentik user: authentik
port: 5432 port: 5432
password: "env://POSTGRES_PASSWORD" password: "env://POSTGRES_PASSWORD"
use_pool: False
test: test:
name: test_authentik name: test_authentik
default_schema: public default_schema: public

View File

@ -217,7 +217,6 @@ class TestConfig(TestCase):
"HOST": "foo", "HOST": "foo",
"NAME": "foo", "NAME": "foo",
"OPTIONS": { "OPTIONS": {
"pool": False,
"sslcert": "foo", "sslcert": "foo",
"sslkey": "foo", "sslkey": "foo",
"sslmode": "foo", "sslmode": "foo",
@ -268,7 +267,6 @@ class TestConfig(TestCase):
"HOST": "foo", "HOST": "foo",
"NAME": "foo", "NAME": "foo",
"OPTIONS": { "OPTIONS": {
"pool": False,
"sslcert": "foo", "sslcert": "foo",
"sslkey": "foo", "sslkey": "foo",
"sslmode": "foo", "sslmode": "foo",
@ -287,7 +285,6 @@ class TestConfig(TestCase):
"HOST": "bar", "HOST": "bar",
"NAME": "foo", "NAME": "foo",
"OPTIONS": { "OPTIONS": {
"pool": False,
"sslcert": "foo", "sslcert": "foo",
"sslkey": "foo", "sslkey": "foo",
"sslmode": "foo", "sslmode": "foo",
@ -336,7 +333,6 @@ class TestConfig(TestCase):
"HOST": "foo", "HOST": "foo",
"NAME": "foo", "NAME": "foo",
"OPTIONS": { "OPTIONS": {
"pool": False,
"sslcert": "foo", "sslcert": "foo",
"sslkey": "foo", "sslkey": "foo",
"sslmode": "foo", "sslmode": "foo",
@ -355,7 +351,6 @@ class TestConfig(TestCase):
"HOST": "bar", "HOST": "bar",
"NAME": "foo", "NAME": "foo",
"OPTIONS": { "OPTIONS": {
"pool": False,
"sslcert": "foo", "sslcert": "foo",
"sslkey": "foo", "sslkey": "foo",
"sslmode": "foo", "sslmode": "foo",
@ -399,7 +394,6 @@ class TestConfig(TestCase):
"HOST": "foo", "HOST": "foo",
"NAME": "foo", "NAME": "foo",
"OPTIONS": { "OPTIONS": {
"pool": False,
"sslcert": "foo", "sslcert": "foo",
"sslkey": "foo", "sslkey": "foo",
"sslmode": "foo", "sslmode": "foo",
@ -418,7 +412,6 @@ class TestConfig(TestCase):
"HOST": "bar", "HOST": "bar",
"NAME": "foo", "NAME": "foo",
"OPTIONS": { "OPTIONS": {
"pool": False,
"sslcert": "foo", "sslcert": "foo",
"sslkey": "foo", "sslkey": "foo",
"sslmode": "foo", "sslmode": "foo",
@ -458,7 +451,6 @@ class TestConfig(TestCase):
"HOST": "foo", "HOST": "foo",
"NAME": "foo", "NAME": "foo",
"OPTIONS": { "OPTIONS": {
"pool": False,
"sslcert": "foo", "sslcert": "foo",
"sslkey": "foo", "sslkey": "foo",
"sslmode": "foo", "sslmode": "foo",
@ -477,7 +469,6 @@ class TestConfig(TestCase):
"HOST": "bar", "HOST": "bar",
"NAME": "foo", "NAME": "foo",
"OPTIONS": { "OPTIONS": {
"pool": False,
"sslcert": "bar", "sslcert": "bar",
"sslkey": "foo", "sslkey": "foo",
"sslmode": "foo", "sslmode": "foo",
@ -493,87 +484,3 @@ class TestConfig(TestCase):
}, },
}, },
) )
def test_db_pool(self):
"""Test DB Config with pool"""
config = ConfigLoader()
config.set("postgresql.host", "foo")
config.set("postgresql.name", "foo")
config.set("postgresql.user", "foo")
config.set("postgresql.password", "foo")
config.set("postgresql.port", "foo")
config.set("postgresql.test.name", "foo")
config.set("postgresql.use_pool", True)
conf = django_db_config(config)
self.assertEqual(
conf,
{
"default": {
"ENGINE": "authentik.root.db",
"HOST": "foo",
"NAME": "foo",
"OPTIONS": {
"pool": True,
"sslcert": None,
"sslkey": None,
"sslmode": None,
"sslrootcert": None,
},
"PASSWORD": "foo",
"PORT": "foo",
"TEST": {"NAME": "foo"},
"USER": "foo",
"CONN_MAX_AGE": 0,
"CONN_HEALTH_CHECKS": False,
"DISABLE_SERVER_SIDE_CURSORS": False,
}
},
)
def test_db_pool_options(self):
"""Test DB Config with pool"""
config = ConfigLoader()
config.set("postgresql.host", "foo")
config.set("postgresql.name", "foo")
config.set("postgresql.user", "foo")
config.set("postgresql.password", "foo")
config.set("postgresql.port", "foo")
config.set("postgresql.test.name", "foo")
config.set("postgresql.use_pool", True)
config.set(
"postgresql.pool_options",
base64.b64encode(
dumps(
{
"max_size": 15,
}
).encode()
).decode(),
)
conf = django_db_config(config)
self.assertEqual(
conf,
{
"default": {
"ENGINE": "authentik.root.db",
"HOST": "foo",
"NAME": "foo",
"OPTIONS": {
"pool": {
"max_size": 15,
},
"sslcert": None,
"sslkey": None,
"sslmode": None,
"sslrootcert": None,
},
"PASSWORD": "foo",
"PORT": "foo",
"TEST": {"NAME": "foo"},
"USER": "foo",
"CONN_MAX_AGE": 0,
"CONN_HEALTH_CHECKS": False,
"DISABLE_SERVER_SIDE_CURSORS": False,
}
},
)

View File

@ -108,9 +108,6 @@ class PolicyEngine:
self.__cached_policies.append(cached_policy) self.__cached_policies.append(cached_policy)
return True return True
def _should_fork(self, binding: PolicyBinding) -> bool:
return binding.policy is not None
def build(self) -> "PolicyEngine": def build(self) -> "PolicyEngine":
"""Build wrapper which monitors performance""" """Build wrapper which monitors performance"""
with ( with (
@ -137,7 +134,7 @@ class PolicyEngine:
task = PolicyProcess(binding, self.request, task_end) task = PolicyProcess(binding, self.request, task_end)
task.daemon = False task.daemon = False
self.logger.debug("P_ENG: Starting Process", binding=binding, request=self.request) self.logger.debug("P_ENG: Starting Process", binding=binding, request=self.request)
if not CURRENT_PROCESS._config.get("daemon") or not self._should_fork(binding): if not CURRENT_PROCESS._config.get("daemon"):
task.run() task.run()
else: else:
task.start() task.start()

View File

@ -66,9 +66,7 @@ class GeoIPPolicy(Policy):
if not static_results and not dynamic_results: if not static_results and not dynamic_results:
return PolicyResult(True) return PolicyResult(True)
static_passing = any(r.passing for r in static_results) if static_results else True passing = any(r.passing for r in static_results) and all(r.passing for r in dynamic_results)
dynamic_passing = all(r.passing for r in dynamic_results)
passing = static_passing and dynamic_passing
messages = chain( messages = chain(
*[r.messages for r in static_results], *[r.messages for r in dynamic_results] *[r.messages for r in static_results], *[r.messages for r in dynamic_results]
) )
@ -115,19 +113,13 @@ class GeoIPPolicy(Policy):
to previous authentication requests""" to previous authentication requests"""
# Get previous login event and GeoIP data # Get previous login event and GeoIP data
previous_logins = Event.objects.filter( previous_logins = Event.objects.filter(
action=EventAction.LOGIN, action=EventAction.LOGIN, user__pk=request.user.pk, context__geo__isnull=False
user__pk=request.user.pk, # context__geo__isnull=False
).order_by("-created")[: self.history_login_count] ).order_by("-created")[: self.history_login_count]
_now = now() _now = now()
geoip_data: GeoIPDict | None = request.context.get("geoip") geoip_data: GeoIPDict | None = request.context.get("geoip")
if not geoip_data: if not geoip_data:
return PolicyResult(False) return PolicyResult(False)
if not previous_logins.exists():
return PolicyResult(True)
result = False
for previous_login in previous_logins: for previous_login in previous_logins:
if "geo" not in previous_login.context:
continue
previous_login_geoip: GeoIPDict = previous_login.context["geo"] previous_login_geoip: GeoIPDict = previous_login.context["geo"]
# Figure out distance # Figure out distance
@ -150,8 +142,7 @@ class GeoIPPolicy(Policy):
(MAX_DISTANCE_HOUR_KM * rel_time_hours) + self.distance_tolerance_km (MAX_DISTANCE_HOUR_KM * rel_time_hours) + self.distance_tolerance_km
): ):
return PolicyResult(False, _("Distance is further than possible.")) return PolicyResult(False, _("Distance is further than possible."))
result = True return PolicyResult(True)
return PolicyResult(result)
class Meta(Policy.PolicyMeta): class Meta(Policy.PolicyMeta):
verbose_name = _("GeoIP Policy") verbose_name = _("GeoIP Policy")

View File

@ -163,7 +163,7 @@ class TestGeoIPPolicy(TestCase):
result: PolicyResult = policy.passes(self.request) result: PolicyResult = policy.passes(self.request)
self.assertFalse(result.passing) self.assertFalse(result.passing)
def test_history_impossible_travel_failing(self): def test_history_impossible_travel(self):
"""Test history checks""" """Test history checks"""
Event.objects.create( Event.objects.create(
action=EventAction.LOGIN, action=EventAction.LOGIN,
@ -181,24 +181,6 @@ class TestGeoIPPolicy(TestCase):
result: PolicyResult = policy.passes(self.request) result: PolicyResult = policy.passes(self.request)
self.assertFalse(result.passing) self.assertFalse(result.passing)
def test_history_impossible_travel_passing(self):
"""Test history checks"""
Event.objects.create(
action=EventAction.LOGIN,
user=get_user(self.user),
context={
# Random location in Canada
"geo": {"lat": 55.868351, "long": -104.441011},
},
)
# Same location
self.request.context["geoip"] = {"lat": 55.868351, "long": -104.441011}
policy = GeoIPPolicy.objects.create(check_impossible_travel=True)
result: PolicyResult = policy.passes(self.request)
self.assertTrue(result.passing)
def test_history_no_geoip(self): def test_history_no_geoip(self):
"""Test history checks (previous login with no geoip data)""" """Test history checks (previous login with no geoip data)"""
Event.objects.create( Event.objects.create(
@ -213,18 +195,3 @@ class TestGeoIPPolicy(TestCase):
result: PolicyResult = policy.passes(self.request) result: PolicyResult = policy.passes(self.request)
self.assertFalse(result.passing) self.assertFalse(result.passing)
def test_impossible_travel_no_geoip(self):
"""Test impossible travel checks (previous login with no geoip data)"""
Event.objects.create(
action=EventAction.LOGIN,
user=get_user(self.user),
context={},
)
# Random location in Poland
self.request.context["geoip"] = {"lat": 50.950613, "long": 20.363679}
policy = GeoIPPolicy.objects.create(check_impossible_travel=True)
result: PolicyResult = policy.passes(self.request)
self.assertFalse(result.passing)

View File

@ -1,41 +0,0 @@
"""RBAC Initial Permissions"""
from rest_framework.serializers import ListSerializer
from rest_framework.viewsets import ModelViewSet
from authentik.core.api.used_by import UsedByMixin
from authentik.core.api.utils import ModelSerializer
from authentik.rbac.api.rbac import PermissionSerializer
from authentik.rbac.models import InitialPermissions
class InitialPermissionsSerializer(ModelSerializer):
"""InitialPermissions serializer"""
permissions_obj = ListSerializer(
child=PermissionSerializer(),
read_only=True,
source="permissions",
required=False,
)
class Meta:
model = InitialPermissions
fields = [
"pk",
"name",
"mode",
"role",
"permissions",
"permissions_obj",
]
class InitialPermissionsViewSet(UsedByMixin, ModelViewSet):
"""InitialPermissions viewset"""
queryset = InitialPermissions.objects.all()
serializer_class = InitialPermissionsSerializer
search_fields = ["name"]
ordering = ["name"]
filterset_fields = ["name"]

View File

@ -1,39 +0,0 @@
# Generated by Django 5.0.13 on 2025-04-07 13:05
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("auth", "0012_alter_user_first_name_max_length"),
("authentik_rbac", "0004_alter_systempermission_options"),
]
operations = [
migrations.CreateModel(
name="InitialPermissions",
fields=[
(
"id",
models.AutoField(
auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
),
),
("name", models.TextField(max_length=150, unique=True)),
("mode", models.CharField(choices=[("user", "User"), ("role", "Role")])),
("permissions", models.ManyToManyField(blank=True, to="auth.permission")),
(
"role",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE, to="authentik_rbac.role"
),
),
],
options={
"verbose_name": "Initial Permissions",
"verbose_name_plural": "Initial Permissions",
},
),
]

View File

@ -3,7 +3,6 @@
from uuid import uuid4 from uuid import uuid4
from django.contrib.auth.management import _get_all_permissions from django.contrib.auth.management import _get_all_permissions
from django.contrib.auth.models import Permission
from django.db import models from django.db import models
from django.db.transaction import atomic from django.db.transaction import atomic
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
@ -76,35 +75,6 @@ class Role(SerializerModel):
] ]
class InitialPermissionsMode(models.TextChoices):
"""Determines which entity the initial permissions are assigned to."""
USER = "user", _("User")
ROLE = "role", _("Role")
class InitialPermissions(SerializerModel):
"""Assigns permissions for newly created objects."""
name = models.TextField(max_length=150, unique=True)
mode = models.CharField(choices=InitialPermissionsMode.choices)
role = models.ForeignKey(Role, on_delete=models.CASCADE)
permissions = models.ManyToManyField(Permission, blank=True)
@property
def serializer(self) -> type[BaseSerializer]:
from authentik.rbac.api.initial_permissions import InitialPermissionsSerializer
return InitialPermissionsSerializer
def __str__(self) -> str:
return f"Initial Permissions for Role #{self.role_id}, applying to #{self.mode}"
class Meta:
verbose_name = _("Initial Permissions")
verbose_name_plural = _("Initial Permissions")
class SystemPermission(models.Model): class SystemPermission(models.Model):
"""System-wide permissions that are not related to any direct """System-wide permissions that are not related to any direct
database model""" database model"""

View File

@ -1,13 +1,9 @@
"""RBAC Permissions""" """RBAC Permissions"""
from django.contrib.contenttypes.models import ContentType
from django.db.models import Model from django.db.models import Model
from guardian.shortcuts import assign_perm
from rest_framework.permissions import BasePermission, DjangoObjectPermissions from rest_framework.permissions import BasePermission, DjangoObjectPermissions
from rest_framework.request import Request from rest_framework.request import Request
from authentik.rbac.models import InitialPermissions, InitialPermissionsMode
class ObjectPermissions(DjangoObjectPermissions): class ObjectPermissions(DjangoObjectPermissions):
"""RBAC Permissions""" """RBAC Permissions"""
@ -55,20 +51,3 @@ def HasPermission(*perm: str) -> type[BasePermission]:
return bool(request.user and request.user.has_perms(perm)) return bool(request.user and request.user.has_perms(perm))
return checker return checker
# TODO: add `user: User` type annotation without circular dependencies.
# The author of this function isn't proficient/patient enough to do it.
def assign_initial_permissions(user, instance: Model):
# Performance here should not be an issue, but if needed, there are many optimization routes
initial_permissions_list = InitialPermissions.objects.filter(role__group__in=user.groups.all())
for initial_permissions in initial_permissions_list:
for permission in initial_permissions.permissions.all():
if permission.content_type != ContentType.objects.get_for_model(instance):
continue
assign_to = (
user
if initial_permissions.mode == InitialPermissionsMode.USER
else initial_permissions.role.group
)
assign_perm(permission, assign_to, instance)

View File

@ -1,116 +0,0 @@
"""Test InitialPermissions"""
from django.contrib.auth.models import Permission
from guardian.shortcuts import assign_perm
from rest_framework.reverse import reverse
from rest_framework.test import APITestCase
from authentik.core.models import Group
from authentik.core.tests.utils import create_test_user
from authentik.lib.generators import generate_id
from authentik.rbac.models import InitialPermissions, InitialPermissionsMode, Role
from authentik.stages.dummy.models import DummyStage
class TestInitialPermissions(APITestCase):
"""Test InitialPermissions"""
def setUp(self) -> None:
self.user = create_test_user()
self.same_role_user = create_test_user()
self.different_role_user = create_test_user()
self.role = Role.objects.create(name=generate_id())
self.different_role = Role.objects.create(name=generate_id())
self.group = Group.objects.create(name=generate_id())
self.different_group = Group.objects.create(name=generate_id())
self.group.roles.add(self.role)
self.group.users.add(self.user, self.same_role_user)
self.different_group.roles.add(self.different_role)
self.different_group.users.add(self.different_role_user)
self.ip = InitialPermissions.objects.create(
name=generate_id(), mode=InitialPermissionsMode.USER, role=self.role
)
self.view_role = Permission.objects.filter(codename="view_role").first()
self.ip.permissions.add(self.view_role)
assign_perm("authentik_rbac.add_role", self.user)
self.client.force_login(self.user)
def test_different_role(self):
"""InitialPermissions for different role does nothing"""
self.ip.role = self.different_role
self.ip.save()
self.client.post(reverse("authentik_api:roles-list"), {"name": "test-role"})
role = Role.objects.filter(name="test-role").first()
self.assertFalse(self.user.has_perm("authentik_rbac.view_role", role))
def test_different_model(self):
"""InitialPermissions for different model does nothing"""
assign_perm("authentik_stages_dummy.add_dummystage", self.user)
self.client.post(
reverse("authentik_api:stages-dummy-list"), {"name": "test-stage", "throw-error": False}
)
role = Role.objects.filter(name="test-role").first()
self.assertFalse(self.user.has_perm("authentik_rbac.view_role", role))
stage = DummyStage.objects.filter(name="test-stage").first()
self.assertFalse(self.user.has_perm("authentik_stages_dummy.view_dummystage", stage))
def test_mode_user(self):
"""InitialPermissions adds user permission in user mode"""
self.client.post(reverse("authentik_api:roles-list"), {"name": "test-role"})
role = Role.objects.filter(name="test-role").first()
self.assertTrue(self.user.has_perm("authentik_rbac.view_role", role))
self.assertFalse(self.same_role_user.has_perm("authentik_rbac.view_role", role))
def test_mode_role(self):
"""InitialPermissions adds role permission in role mode"""
self.ip.mode = InitialPermissionsMode.ROLE
self.ip.save()
self.client.post(reverse("authentik_api:roles-list"), {"name": "test-role"})
role = Role.objects.filter(name="test-role").first()
self.assertTrue(self.user.has_perm("authentik_rbac.view_role", role))
self.assertTrue(self.same_role_user.has_perm("authentik_rbac.view_role", role))
def test_many_permissions(self):
"""InitialPermissions can add multiple permissions"""
change_role = Permission.objects.filter(codename="change_role").first()
self.ip.permissions.add(change_role)
self.client.post(reverse("authentik_api:roles-list"), {"name": "test-role"})
role = Role.objects.filter(name="test-role").first()
self.assertTrue(self.user.has_perm("authentik_rbac.view_role", role))
self.assertTrue(self.user.has_perm("authentik_rbac.change_role", role))
def test_permissions_separated_by_role(self):
"""When the triggering user is part of two different roles with InitialPermissions in role
mode, it only adds permissions to the relevant role."""
self.ip.mode = InitialPermissionsMode.ROLE
self.ip.save()
different_ip = InitialPermissions.objects.create(
name=generate_id(), mode=InitialPermissionsMode.ROLE, role=self.different_role
)
change_role = Permission.objects.filter(codename="change_role").first()
different_ip.permissions.add(change_role)
self.different_group.users.add(self.user)
self.client.post(reverse("authentik_api:roles-list"), {"name": "test-role"})
role = Role.objects.filter(name="test-role").first()
self.assertTrue(self.user.has_perm("authentik_rbac.view_role", role))
self.assertTrue(self.same_role_user.has_perm("authentik_rbac.view_role", role))
self.assertFalse(self.different_role_user.has_perm("authentik_rbac.view_role", role))
self.assertTrue(self.user.has_perm("authentik_rbac.change_role", role))
self.assertFalse(self.same_role_user.has_perm("authentik_rbac.change_role", role))
self.assertTrue(self.different_role_user.has_perm("authentik_rbac.change_role", role))

View File

@ -1,6 +1,5 @@
"""RBAC API urls""" """RBAC API urls"""
from authentik.rbac.api.initial_permissions import InitialPermissionsViewSet
from authentik.rbac.api.rbac import RBACPermissionViewSet from authentik.rbac.api.rbac import RBACPermissionViewSet
from authentik.rbac.api.rbac_assigned_by_roles import RoleAssignedPermissionViewSet from authentik.rbac.api.rbac_assigned_by_roles import RoleAssignedPermissionViewSet
from authentik.rbac.api.rbac_assigned_by_users import UserAssignedPermissionViewSet from authentik.rbac.api.rbac_assigned_by_users import UserAssignedPermissionViewSet
@ -22,6 +21,5 @@ api_urlpatterns = [
("rbac/permissions/users", UserPermissionViewSet, "permissions-users"), ("rbac/permissions/users", UserPermissionViewSet, "permissions-users"),
("rbac/permissions/roles", RolePermissionViewSet, "permissions-roles"), ("rbac/permissions/roles", RolePermissionViewSet, "permissions-roles"),
("rbac/permissions", RBACPermissionViewSet), ("rbac/permissions", RBACPermissionViewSet),
("rbac/roles", RoleViewSet, "roles"), ("rbac/roles", RoleViewSet),
("rbac/initial_permissions", InitialPermissionsViewSet, "initial-permissions"),
] ]

View File

@ -130,7 +130,6 @@ class OAuthSourceSerializer(SourceSerializer):
"oidc_well_known_url", "oidc_well_known_url",
"oidc_jwks_url", "oidc_jwks_url",
"oidc_jwks", "oidc_jwks",
"authorization_code_auth_method",
] ]
extra_kwargs = { extra_kwargs = {
"consumer_secret": {"write_only": True}, "consumer_secret": {"write_only": True},

View File

@ -6,15 +6,11 @@ from urllib.parse import parse_qsl
from django.utils.crypto import constant_time_compare, get_random_string from django.utils.crypto import constant_time_compare, get_random_string
from django.utils.translation import gettext as _ from django.utils.translation import gettext as _
from requests.auth import AuthBase, HTTPBasicAuth
from requests.exceptions import RequestException from requests.exceptions import RequestException
from requests.models import Response from requests.models import Response
from structlog.stdlib import get_logger from structlog.stdlib import get_logger
from authentik.sources.oauth.clients.base import BaseOAuthClient from authentik.sources.oauth.clients.base import BaseOAuthClient
from authentik.sources.oauth.models import (
AuthorizationCodeAuthMethod,
)
LOGGER = get_logger() LOGGER = get_logger()
SESSION_KEY_OAUTH_PKCE = "authentik/sources/oauth/pkce" SESSION_KEY_OAUTH_PKCE = "authentik/sources/oauth/pkce"
@ -59,30 +55,6 @@ class OAuth2Client(BaseOAuthClient):
"""Get client secret""" """Get client secret"""
return self.source.consumer_secret return self.source.consumer_secret
def get_access_token_args(self, callback: str, code: str) -> dict[str, Any]:
args = {
"redirect_uri": callback,
"code": code,
"grant_type": "authorization_code",
}
if SESSION_KEY_OAUTH_PKCE in self.request.session:
args["code_verifier"] = self.request.session[SESSION_KEY_OAUTH_PKCE]
if (
self.source.source_type.authorization_code_auth_method
== AuthorizationCodeAuthMethod.POST_BODY
):
args["client_id"] = self.get_client_id()
args["client_secret"] = self.get_client_secret()
return args
def get_access_token_auth(self) -> AuthBase | None:
if (
self.source.source_type.authorization_code_auth_method
== AuthorizationCodeAuthMethod.BASIC_AUTH
):
return HTTPBasicAuth(self.get_client_id(), self.get_client_secret())
return None
def get_access_token(self, **request_kwargs) -> dict[str, Any] | None: def get_access_token(self, **request_kwargs) -> dict[str, Any] | None:
"""Fetch access token from callback request.""" """Fetch access token from callback request."""
callback = self.request.build_absolute_uri(self.callback or self.request.path) callback = self.request.build_absolute_uri(self.callback or self.request.path)
@ -95,6 +67,13 @@ class OAuth2Client(BaseOAuthClient):
error = self.get_request_arg("error", None) error = self.get_request_arg("error", None)
error_desc = self.get_request_arg("error_description", None) error_desc = self.get_request_arg("error_description", None)
return {"error": error_desc or error or _("No token received.")} return {"error": error_desc or error or _("No token received.")}
args = {
"redirect_uri": callback,
"code": code,
"grant_type": "authorization_code",
}
if SESSION_KEY_OAUTH_PKCE in self.request.session:
args["code_verifier"] = self.request.session[SESSION_KEY_OAUTH_PKCE]
try: try:
access_token_url = self.source.source_type.access_token_url or "" access_token_url = self.source.source_type.access_token_url or ""
if self.source.source_type.urls_customizable and self.source.access_token_url: if self.source.source_type.urls_customizable and self.source.access_token_url:
@ -102,8 +81,8 @@ class OAuth2Client(BaseOAuthClient):
response = self.do_request( response = self.do_request(
"post", "post",
access_token_url, access_token_url,
auth=self.get_access_token_auth(), auth=(self.get_client_id(), self.get_client_secret()),
data=self.get_access_token_args(callback, code), data=args,
headers=self._default_headers, headers=self._default_headers,
**request_kwargs, **request_kwargs,
) )

View File

@ -1,25 +0,0 @@
# Generated by Django 5.0.14 on 2025-04-11 18:09
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("authentik_sources_oauth", "0009_migrate_useroauthsourceconnection_identifier"),
]
operations = [
migrations.AddField(
model_name="oauthsource",
name="authorization_code_auth_method",
field=models.TextField(
choices=[
("basic_auth", "HTTP Basic Authentication"),
("post_body", "Include the client ID and secret as request parameters"),
],
default="basic_auth",
help_text="How to perform authentication during an authorization_code token request flow",
),
),
]

View File

@ -21,11 +21,6 @@ if TYPE_CHECKING:
from authentik.sources.oauth.types.registry import SourceType from authentik.sources.oauth.types.registry import SourceType
class AuthorizationCodeAuthMethod(models.TextChoices):
BASIC_AUTH = "basic_auth", _("HTTP Basic Authentication")
POST_BODY = "post_body", _("Include the client ID and secret as request parameters")
class OAuthSource(NonCreatableType, Source): class OAuthSource(NonCreatableType, Source):
"""Login using a Generic OAuth provider.""" """Login using a Generic OAuth provider."""
@ -66,14 +61,6 @@ class OAuthSource(NonCreatableType, Source):
oidc_jwks_url = models.TextField(default="", blank=True) oidc_jwks_url = models.TextField(default="", blank=True)
oidc_jwks = models.JSONField(default=dict, blank=True) oidc_jwks = models.JSONField(default=dict, blank=True)
authorization_code_auth_method = models.TextField(
choices=AuthorizationCodeAuthMethod.choices,
default=AuthorizationCodeAuthMethod.BASIC_AUTH,
help_text=_(
"How to perform authentication during an authorization_code token request flow"
),
)
@property @property
def source_type(self) -> type["SourceType"]: def source_type(self) -> type["SourceType"]:
"""Return the provider instance for this source""" """Return the provider instance for this source"""

View File

@ -1,69 +0,0 @@
from django.test import RequestFactory, TestCase
from guardian.shortcuts import get_anonymous_user
from authentik.lib.generators import generate_id
from authentik.sources.oauth.clients.oauth2 import OAuth2Client
from authentik.sources.oauth.models import AuthorizationCodeAuthMethod, OAuthSource
from authentik.sources.oauth.types.oidc import OpenIDConnectClient
class TestOAuthClient(TestCase):
"""OAuth Source tests"""
def setUp(self):
self.source = OAuthSource.objects.create(
name="test",
slug="test",
provider_type="openidconnect",
authorization_url="",
profile_url="",
consumer_key=generate_id(),
)
self.factory = RequestFactory()
def test_client_post_body_auth(self):
"""Test login_challenge"""
self.source.provider_type = "apple"
self.source.save()
request = self.factory.get("/")
request.session = {}
request.user = get_anonymous_user()
client = OAuth2Client(self.source, request)
self.assertIsNone(client.get_access_token_auth())
args = client.get_access_token_args("", "")
self.assertIn("client_id", args)
self.assertIn("client_secret", args)
def test_client_basic_auth(self):
"""Test login_challenge"""
self.source.provider_type = "reddit"
self.source.save()
request = self.factory.get("/")
request.session = {}
request.user = get_anonymous_user()
client = OAuth2Client(self.source, request)
self.assertIsNotNone(client.get_access_token_auth())
args = client.get_access_token_args("", "")
self.assertNotIn("client_id", args)
self.assertNotIn("client_secret", args)
def test_client_openid_auth(self):
"""Test login_challenge"""
request = self.factory.get("/")
request.session = {}
request.user = get_anonymous_user()
client = OpenIDConnectClient(self.source, request)
self.assertIsNotNone(client.get_access_token_auth())
args = client.get_access_token_args("", "")
self.assertNotIn("client_id", args)
self.assertNotIn("client_secret", args)
self.source.authorization_code_auth_method = AuthorizationCodeAuthMethod.POST_BODY
self.source.save()
client = OpenIDConnectClient(self.source, request)
self.assertIsNone(client.get_access_token_auth())
args = client.get_access_token_args("", "")
self.assertIn("client_id", args)
self.assertIn("client_secret", args)

View File

@ -11,7 +11,7 @@ from structlog.stdlib import get_logger
from authentik.flows.challenge import Challenge, ChallengeResponse from authentik.flows.challenge import Challenge, ChallengeResponse
from authentik.sources.oauth.clients.oauth2 import OAuth2Client from authentik.sources.oauth.clients.oauth2 import OAuth2Client
from authentik.sources.oauth.models import AuthorizationCodeAuthMethod, OAuthSource from authentik.sources.oauth.models import OAuthSource
from authentik.sources.oauth.types.registry import SourceType, registry from authentik.sources.oauth.types.registry import SourceType, registry
from authentik.sources.oauth.views.callback import OAuthCallback from authentik.sources.oauth.views.callback import OAuthCallback
from authentik.sources.oauth.views.redirect import OAuthRedirect from authentik.sources.oauth.views.redirect import OAuthRedirect
@ -105,8 +105,6 @@ class AppleType(SourceType):
access_token_url = "https://appleid.apple.com/auth/token" # nosec access_token_url = "https://appleid.apple.com/auth/token" # nosec
profile_url = "" profile_url = ""
authorization_code_auth_method = AuthorizationCodeAuthMethod.POST_BODY
def login_challenge(self, source: OAuthSource, request: HttpRequest) -> Challenge: def login_challenge(self, source: OAuthSource, request: HttpRequest) -> Challenge:
"""Pre-general all the things required for the JS SDK""" """Pre-general all the things required for the JS SDK"""
apple_client = AppleOAuthClient( apple_client = AppleOAuthClient(

View File

@ -6,7 +6,6 @@ from requests import RequestException
from structlog.stdlib import get_logger from structlog.stdlib import get_logger
from authentik.sources.oauth.clients.oauth2 import UserprofileHeaderAuthClient from authentik.sources.oauth.clients.oauth2 import UserprofileHeaderAuthClient
from authentik.sources.oauth.models import AuthorizationCodeAuthMethod
from authentik.sources.oauth.types.oidc import OpenIDConnectOAuth2Callback from authentik.sources.oauth.types.oidc import OpenIDConnectOAuth2Callback
from authentik.sources.oauth.types.registry import SourceType, registry from authentik.sources.oauth.types.registry import SourceType, registry
from authentik.sources.oauth.views.redirect import OAuthRedirect from authentik.sources.oauth.views.redirect import OAuthRedirect
@ -78,8 +77,6 @@ class AzureADType(SourceType):
) )
oidc_jwks_url = "https://login.microsoftonline.com/common/discovery/keys" oidc_jwks_url = "https://login.microsoftonline.com/common/discovery/keys"
authorization_code_auth_method = AuthorizationCodeAuthMethod.POST_BODY
def get_base_user_properties(self, info: dict[str, Any], **kwargs) -> dict[str, Any]: def get_base_user_properties(self, info: dict[str, Any], **kwargs) -> dict[str, Any]:
mail = info.get("mail", None) or info.get("otherMails", [None])[0] mail = info.get("mail", None) or info.get("otherMails", [None])[0]
# Format group info # Format group info

View File

@ -2,8 +2,8 @@
from typing import Any from typing import Any
from authentik.sources.oauth.models import AuthorizationCodeAuthMethod
from authentik.sources.oauth.types.registry import SourceType, registry from authentik.sources.oauth.types.registry import SourceType, registry
from authentik.sources.oauth.views.callback import OAuthCallback
from authentik.sources.oauth.views.redirect import OAuthRedirect from authentik.sources.oauth.views.redirect import OAuthRedirect
@ -16,10 +16,15 @@ class FacebookOAuthRedirect(OAuthRedirect):
} }
class FacebookOAuth2Callback(OAuthCallback):
"""Facebook OAuth2 Callback"""
@registry.register() @registry.register()
class FacebookType(SourceType): class FacebookType(SourceType):
"""Facebook Type definition""" """Facebook Type definition"""
callback_view = FacebookOAuth2Callback
redirect_view = FacebookOAuthRedirect redirect_view = FacebookOAuthRedirect
verbose_name = "Facebook" verbose_name = "Facebook"
name = "facebook" name = "facebook"
@ -28,8 +33,6 @@ class FacebookType(SourceType):
access_token_url = "https://graph.facebook.com/v7.0/oauth/access_token" # nosec access_token_url = "https://graph.facebook.com/v7.0/oauth/access_token" # nosec
profile_url = "https://graph.facebook.com/v7.0/me?fields=id,name,email" profile_url = "https://graph.facebook.com/v7.0/me?fields=id,name,email"
authorization_code_auth_method = AuthorizationCodeAuthMethod.POST_BODY
def get_base_user_properties(self, info: dict[str, Any], **kwargs) -> dict[str, Any]: def get_base_user_properties(self, info: dict[str, Any], **kwargs) -> dict[str, Any]:
return { return {
"username": info.get("name"), "username": info.get("name"),

View File

@ -5,7 +5,7 @@ from typing import Any
from requests.exceptions import RequestException from requests.exceptions import RequestException
from authentik.sources.oauth.clients.oauth2 import OAuth2Client from authentik.sources.oauth.clients.oauth2 import OAuth2Client
from authentik.sources.oauth.models import AuthorizationCodeAuthMethod, OAuthSource from authentik.sources.oauth.models import OAuthSource
from authentik.sources.oauth.types.registry import SourceType, registry from authentik.sources.oauth.types.registry import SourceType, registry
from authentik.sources.oauth.views.callback import OAuthCallback from authentik.sources.oauth.views.callback import OAuthCallback
from authentik.sources.oauth.views.redirect import OAuthRedirect from authentik.sources.oauth.views.redirect import OAuthRedirect
@ -63,8 +63,6 @@ class GitHubType(SourceType):
) )
oidc_jwks_url = "https://token.actions.githubusercontent.com/.well-known/jwks" oidc_jwks_url = "https://token.actions.githubusercontent.com/.well-known/jwks"
authorization_code_auth_method = AuthorizationCodeAuthMethod.POST_BODY
def get_base_user_properties( def get_base_user_properties(
self, self,
source: OAuthSource, source: OAuthSource,

View File

@ -7,8 +7,9 @@ and https://docs.gitlab.com/ee/integration/openid_connect_provider.html
from typing import Any from typing import Any
from authentik.sources.oauth.models import AuthorizationCodeAuthMethod, OAuthSource from authentik.sources.oauth.models import OAuthSource
from authentik.sources.oauth.types.registry import SourceType, registry from authentik.sources.oauth.types.registry import SourceType, registry
from authentik.sources.oauth.views.callback import OAuthCallback
from authentik.sources.oauth.views.redirect import OAuthRedirect from authentik.sources.oauth.views.redirect import OAuthRedirect
@ -21,10 +22,15 @@ class GitLabOAuthRedirect(OAuthRedirect):
} }
class GitLabOAuthCallback(OAuthCallback):
"""GitLab OAuth2 Callback"""
@registry.register() @registry.register()
class GitLabType(SourceType): class GitLabType(SourceType):
"""GitLab Type definition""" """GitLab Type definition"""
callback_view = GitLabOAuthCallback
redirect_view = GitLabOAuthRedirect redirect_view = GitLabOAuthRedirect
verbose_name = "GitLab" verbose_name = "GitLab"
name = "gitlab" name = "gitlab"
@ -37,8 +43,6 @@ class GitLabType(SourceType):
oidc_well_known_url = "https://gitlab.com/.well-known/openid-configuration" oidc_well_known_url = "https://gitlab.com/.well-known/openid-configuration"
oidc_jwks_url = "https://gitlab.com/oauth/discovery/keys" oidc_jwks_url = "https://gitlab.com/oauth/discovery/keys"
authorization_code_auth_method = AuthorizationCodeAuthMethod.POST_BODY
def get_base_user_properties(self, info: dict[str, Any], **kwargs) -> dict[str, Any]: def get_base_user_properties(self, info: dict[str, Any], **kwargs) -> dict[str, Any]:
return { return {
"username": info.get("preferred_username"), "username": info.get("preferred_username"),

View File

@ -2,8 +2,8 @@
from typing import Any from typing import Any
from authentik.sources.oauth.models import AuthorizationCodeAuthMethod
from authentik.sources.oauth.types.registry import SourceType, registry from authentik.sources.oauth.types.registry import SourceType, registry
from authentik.sources.oauth.views.callback import OAuthCallback
from authentik.sources.oauth.views.redirect import OAuthRedirect from authentik.sources.oauth.views.redirect import OAuthRedirect
@ -16,10 +16,15 @@ class GoogleOAuthRedirect(OAuthRedirect):
} }
class GoogleOAuth2Callback(OAuthCallback):
"""Google OAuth2 Callback"""
@registry.register() @registry.register()
class GoogleType(SourceType): class GoogleType(SourceType):
"""Google Type definition""" """Google Type definition"""
callback_view = GoogleOAuth2Callback
redirect_view = GoogleOAuthRedirect redirect_view = GoogleOAuthRedirect
verbose_name = "Google" verbose_name = "Google"
name = "google" name = "google"
@ -30,8 +35,6 @@ class GoogleType(SourceType):
oidc_well_known_url = "https://accounts.google.com/.well-known/openid-configuration" oidc_well_known_url = "https://accounts.google.com/.well-known/openid-configuration"
oidc_jwks_url = "https://www.googleapis.com/oauth2/v3/certs" oidc_jwks_url = "https://www.googleapis.com/oauth2/v3/certs"
authorization_code_auth_method = AuthorizationCodeAuthMethod.POST_BODY
def get_base_user_properties(self, info: dict[str, Any], **kwargs) -> dict[str, Any]: def get_base_user_properties(self, info: dict[str, Any], **kwargs) -> dict[str, Any]:
return { return {
"email": info.get("email"), "email": info.get("email"),

View File

@ -6,7 +6,6 @@ from requests.exceptions import RequestException
from structlog.stdlib import get_logger from structlog.stdlib import get_logger
from authentik.sources.oauth.clients.oauth2 import OAuth2Client from authentik.sources.oauth.clients.oauth2 import OAuth2Client
from authentik.sources.oauth.models import AuthorizationCodeAuthMethod
from authentik.sources.oauth.types.registry import SourceType, registry from authentik.sources.oauth.types.registry import SourceType, registry
from authentik.sources.oauth.views.callback import OAuthCallback from authentik.sources.oauth.views.callback import OAuthCallback
from authentik.sources.oauth.views.redirect import OAuthRedirect from authentik.sources.oauth.views.redirect import OAuthRedirect
@ -60,8 +59,6 @@ class MailcowType(SourceType):
urls_customizable = True urls_customizable = True
authorization_code_auth_method = AuthorizationCodeAuthMethod.POST_BODY
def get_base_user_properties(self, info: dict[str, Any], **kwargs) -> dict[str, Any]: def get_base_user_properties(self, info: dict[str, Any], **kwargs) -> dict[str, Any]:
return { return {
"username": info.get("full_name"), "username": info.get("full_name"),

View File

@ -2,10 +2,8 @@
from typing import Any from typing import Any
from requests.auth import AuthBase, HTTPBasicAuth
from authentik.sources.oauth.clients.oauth2 import UserprofileHeaderAuthClient from authentik.sources.oauth.clients.oauth2 import UserprofileHeaderAuthClient
from authentik.sources.oauth.models import AuthorizationCodeAuthMethod, OAuthSource from authentik.sources.oauth.models import OAuthSource
from authentik.sources.oauth.types.registry import SourceType, registry from authentik.sources.oauth.types.registry import SourceType, registry
from authentik.sources.oauth.views.callback import OAuthCallback from authentik.sources.oauth.views.callback import OAuthCallback
from authentik.sources.oauth.views.redirect import OAuthRedirect from authentik.sources.oauth.views.redirect import OAuthRedirect
@ -20,27 +18,10 @@ class OpenIDConnectOAuthRedirect(OAuthRedirect):
} }
class OpenIDConnectClient(UserprofileHeaderAuthClient):
def get_access_token_args(self, callback: str, code: str) -> dict[str, Any]:
args = super().get_access_token_args(callback, code)
if self.source.authorization_code_auth_method == AuthorizationCodeAuthMethod.POST_BODY:
args["client_id"] = self.get_client_id()
args["client_secret"] = self.get_client_secret()
else:
args.pop("client_id", None)
args.pop("client_secret", None)
return args
def get_access_token_auth(self) -> AuthBase | None:
if self.source.authorization_code_auth_method == AuthorizationCodeAuthMethod.BASIC_AUTH:
return HTTPBasicAuth(self.get_client_id(), self.get_client_secret())
return None
class OpenIDConnectOAuth2Callback(OAuthCallback): class OpenIDConnectOAuth2Callback(OAuthCallback):
"""OpenIDConnect OAuth2 Callback""" """OpenIDConnect OAuth2 Callback"""
client_class = OpenIDConnectClient client_class = UserprofileHeaderAuthClient
def get_user_id(self, info: dict[str, str]) -> str: def get_user_id(self, info: dict[str, str]) -> str:
return info.get("sub", None) return info.get("sub", None)

View File

@ -2,6 +2,7 @@
from typing import Any from typing import Any
from authentik.sources.oauth.clients.oauth2 import UserprofileHeaderAuthClient
from authentik.sources.oauth.models import OAuthSource from authentik.sources.oauth.models import OAuthSource
from authentik.sources.oauth.types.oidc import OpenIDConnectOAuth2Callback from authentik.sources.oauth.types.oidc import OpenIDConnectOAuth2Callback
from authentik.sources.oauth.types.registry import SourceType, registry from authentik.sources.oauth.types.registry import SourceType, registry
@ -17,11 +18,20 @@ class OktaOAuthRedirect(OAuthRedirect):
} }
class OktaOAuth2Callback(OpenIDConnectOAuth2Callback):
"""Okta OAuth2 Callback"""
# Okta has the same quirk as azure and throws an error if the access token
# is set via query parameter, so we reuse the azure client
# see https://github.com/goauthentik/authentik/issues/1910
client_class = UserprofileHeaderAuthClient
@registry.register() @registry.register()
class OktaType(SourceType): class OktaType(SourceType):
"""Okta Type definition""" """Okta Type definition"""
callback_view = OpenIDConnectOAuth2Callback callback_view = OktaOAuth2Callback
redirect_view = OktaOAuthRedirect redirect_view = OktaOAuthRedirect
verbose_name = "Okta" verbose_name = "Okta"
name = "okta" name = "okta"

View File

@ -3,7 +3,7 @@
from typing import Any from typing import Any
from authentik.sources.oauth.clients.oauth2 import UserprofileHeaderAuthClient from authentik.sources.oauth.clients.oauth2 import UserprofileHeaderAuthClient
from authentik.sources.oauth.models import AuthorizationCodeAuthMethod, OAuthSource from authentik.sources.oauth.models import OAuthSource
from authentik.sources.oauth.types.registry import SourceType, registry from authentik.sources.oauth.types.registry import SourceType, registry
from authentik.sources.oauth.views.callback import OAuthCallback from authentik.sources.oauth.views.callback import OAuthCallback
from authentik.sources.oauth.views.redirect import OAuthRedirect from authentik.sources.oauth.views.redirect import OAuthRedirect
@ -41,8 +41,6 @@ class PatreonType(SourceType):
access_token_url = "https://www.patreon.com/api/oauth2/token" # nosec access_token_url = "https://www.patreon.com/api/oauth2/token" # nosec
profile_url = "https://www.patreon.com/api/oauth2/api/current_user" profile_url = "https://www.patreon.com/api/oauth2/api/current_user"
authorization_code_auth_method = AuthorizationCodeAuthMethod.POST_BODY
def get_base_user_properties(self, info: dict[str, Any], **kwargs) -> dict[str, Any]: def get_base_user_properties(self, info: dict[str, Any], **kwargs) -> dict[str, Any]:
return { return {
"username": info.get("data", {}).get("attributes", {}).get("vanity"), "username": info.get("data", {}).get("attributes", {}).get("vanity"),

View File

@ -2,6 +2,8 @@
from typing import Any from typing import Any
from requests.auth import HTTPBasicAuth
from authentik.sources.oauth.clients.oauth2 import UserprofileHeaderAuthClient from authentik.sources.oauth.clients.oauth2 import UserprofileHeaderAuthClient
from authentik.sources.oauth.types.registry import SourceType, registry from authentik.sources.oauth.types.registry import SourceType, registry
from authentik.sources.oauth.views.callback import OAuthCallback from authentik.sources.oauth.views.callback import OAuthCallback
@ -18,10 +20,21 @@ class RedditOAuthRedirect(OAuthRedirect):
} }
class RedditOAuth2Client(UserprofileHeaderAuthClient):
"""Reddit OAuth2 Client"""
def get_access_token(self, **request_kwargs):
"Fetch access token from callback request."
request_kwargs["auth"] = HTTPBasicAuth(
self.source.consumer_key, self.source.consumer_secret
)
return super().get_access_token(**request_kwargs)
class RedditOAuth2Callback(OAuthCallback): class RedditOAuth2Callback(OAuthCallback):
"""Reddit OAuth2 Callback""" """Reddit OAuth2 Callback"""
client_class = UserprofileHeaderAuthClient client_class = RedditOAuth2Client
@registry.register() @registry.register()

View File

@ -10,7 +10,7 @@ from django.urls.base import reverse
from structlog.stdlib import get_logger from structlog.stdlib import get_logger
from authentik.flows.challenge import Challenge, RedirectChallenge from authentik.flows.challenge import Challenge, RedirectChallenge
from authentik.sources.oauth.models import AuthorizationCodeAuthMethod, OAuthSource from authentik.sources.oauth.models import OAuthSource
from authentik.sources.oauth.views.callback import OAuthCallback from authentik.sources.oauth.views.callback import OAuthCallback
from authentik.sources.oauth.views.redirect import OAuthRedirect from authentik.sources.oauth.views.redirect import OAuthRedirect
@ -41,10 +41,6 @@ class SourceType:
oidc_well_known_url: str | None = None oidc_well_known_url: str | None = None
oidc_jwks_url: str | None = None oidc_jwks_url: str | None = None
authorization_code_auth_method: AuthorizationCodeAuthMethod = (
AuthorizationCodeAuthMethod.BASIC_AUTH
)
def icon_url(self) -> str: def icon_url(self) -> str:
"""Get Icon URL for login""" """Get Icon URL for login"""
return static(f"authentik/sources/{self.name}.svg") return static(f"authentik/sources/{self.name}.svg")

View File

@ -4,7 +4,6 @@ from json import dumps
from typing import Any from typing import Any
from authentik.sources.oauth.clients.oauth2 import UserprofileHeaderAuthClient from authentik.sources.oauth.clients.oauth2 import UserprofileHeaderAuthClient
from authentik.sources.oauth.models import AuthorizationCodeAuthMethod
from authentik.sources.oauth.types.oidc import OpenIDConnectOAuth2Callback from authentik.sources.oauth.types.oidc import OpenIDConnectOAuth2Callback
from authentik.sources.oauth.types.registry import SourceType, registry from authentik.sources.oauth.types.registry import SourceType, registry
from authentik.sources.oauth.views.redirect import OAuthRedirect from authentik.sources.oauth.views.redirect import OAuthRedirect
@ -48,8 +47,6 @@ class TwitchType(SourceType):
access_token_url = "https://id.twitch.tv/oauth2/token" # nosec access_token_url = "https://id.twitch.tv/oauth2/token" # nosec
profile_url = "https://id.twitch.tv/oauth2/userinfo" profile_url = "https://id.twitch.tv/oauth2/userinfo"
authorization_code_auth_method = AuthorizationCodeAuthMethod.POST_BODY
def get_base_user_properties(self, info: dict[str, Any], **kwargs) -> dict[str, Any]: def get_base_user_properties(self, info: dict[str, Any], **kwargs) -> dict[str, Any]:
return { return {
"username": info.get("preferred_username"), "username": info.get("preferred_username"),

View File

@ -12,6 +12,23 @@ from authentik.sources.oauth.views.callback import OAuthCallback
from authentik.sources.oauth.views.redirect import OAuthRedirect from authentik.sources.oauth.views.redirect import OAuthRedirect
class TwitterClient(UserprofileHeaderAuthClient):
"""Twitter has similar quirks to Azure AD, and additionally requires Basic auth on
the access token endpoint for some reason."""
# Twitter has the same quirk as azure and throws an error if the access token
# is set via query parameter, so we reuse the azure client
# see https://github.com/goauthentik/authentik/issues/1910
def get_access_token(self, **request_kwargs) -> dict[str, Any] | None:
return super().get_access_token(
auth=(
self.source.consumer_key,
self.source.consumer_secret,
)
)
class TwitterOAuthRedirect(OAuthRedirect): class TwitterOAuthRedirect(OAuthRedirect):
"""Twitter OAuth2 Redirect""" """Twitter OAuth2 Redirect"""
@ -27,7 +44,7 @@ class TwitterOAuthRedirect(OAuthRedirect):
class TwitterOAuthCallback(OAuthCallback): class TwitterOAuthCallback(OAuthCallback):
"""Twitter OAuth2 Callback""" """Twitter OAuth2 Callback"""
client_class = UserprofileHeaderAuthClient client_class = TwitterClient
def get_user_id(self, info: dict[str, str]) -> str: def get_user_id(self, info: dict[str, str]) -> str:
return info.get("data", {}).get("id", "") return info.get("data", {}).get("id", "")

File diff suppressed because one or more lines are too long

View File

@ -2,4 +2,4 @@
from authentik.stages.dummy.api import DummyStageViewSet from authentik.stages.dummy.api import DummyStageViewSet
api_urlpatterns = [("stages/dummy", DummyStageViewSet, "stages-dummy")] api_urlpatterns = [("stages/dummy", DummyStageViewSet)]

View File

@ -36,7 +36,6 @@ class IdentificationStageSerializer(StageSerializer):
"sources", "sources",
"show_source_labels", "show_source_labels",
"pretend_user_exists", "pretend_user_exists",
"enable_remember_me",
] ]

View File

@ -1,21 +0,0 @@
# Generated by Django 5.1.8 on 2025-04-16 17:14
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("authentik_stages_identification", "0015_identificationstage_captcha_stage"),
]
operations = [
migrations.AddField(
model_name="identificationstage",
name="enable_remember_me",
field=models.BooleanField(
default=False,
help_text="Show the user the 'Remember me on this device' toggle, allowing repeat users to skip straight to entering their password.",
),
),
]

View File

@ -76,13 +76,7 @@ class IdentificationStage(Stage):
"is entered." "is entered."
), ),
) )
enable_remember_me = models.BooleanField(
default=False,
help_text=_(
"Show the user the 'Remember me on this device' toggle, allowing repeat "
"users to skip straight to entering their password."
),
)
enrollment_flow = models.ForeignKey( enrollment_flow = models.ForeignKey(
Flow, Flow,
on_delete=models.SET_DEFAULT, on_delete=models.SET_DEFAULT,

View File

@ -85,7 +85,6 @@ class IdentificationChallenge(Challenge):
primary_action = CharField() primary_action = CharField()
sources = LoginSourceSerializer(many=True, required=False) sources = LoginSourceSerializer(many=True, required=False)
show_source_labels = BooleanField() show_source_labels = BooleanField()
enable_remember_me = BooleanField(required=False, default=True)
component = CharField(default="ak-stage-identification") component = CharField(default="ak-stage-identification")
@ -236,7 +235,6 @@ class IdentificationStageView(ChallengeStageView):
and current_stage.password_stage.allow_show_password, and current_stage.password_stage.allow_show_password,
"show_source_labels": current_stage.show_source_labels, "show_source_labels": current_stage.show_source_labels,
"flow_designation": self.executor.flow.designation, "flow_designation": self.executor.flow.designation,
"enable_remember_me": current_stage.enable_remember_me,
} }
) )
# If the user has been redirected to us whilst trying to access an # If the user has been redirected to us whilst trying to access an

View File

@ -4,12 +4,11 @@ from drf_spectacular.utils import extend_schema
from rest_framework.decorators import action from rest_framework.decorators import action
from rest_framework.request import Request from rest_framework.request import Request
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework.serializers import CharField from rest_framework.serializers import CharField, ModelSerializer
from rest_framework.validators import UniqueValidator from rest_framework.validators import UniqueValidator
from rest_framework.viewsets import ModelViewSet from rest_framework.viewsets import ModelViewSet
from authentik.core.api.used_by import UsedByMixin from authentik.core.api.used_by import UsedByMixin
from authentik.core.api.utils import ModelSerializer
from authentik.core.expression.exceptions import PropertyMappingExpressionException from authentik.core.expression.exceptions import PropertyMappingExpressionException
from authentik.flows.api.stages import StageSerializer from authentik.flows.api.stages import StageSerializer
from authentik.flows.challenge import HttpChallengeResponse from authentik.flows.challenge import HttpChallengeResponse

View File

@ -15,12 +15,12 @@ from rest_framework.filters import OrderingFilter, SearchFilter
from rest_framework.permissions import BasePermission from rest_framework.permissions import BasePermission
from rest_framework.request import Request from rest_framework.request import Request
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework.serializers import DateTimeField from rest_framework.serializers import DateTimeField, ModelSerializer
from rest_framework.views import View from rest_framework.views import View
from rest_framework.viewsets import ModelViewSet from rest_framework.viewsets import ModelViewSet
from authentik.api.authentication import validate_auth from authentik.api.authentication import validate_auth
from authentik.core.api.utils import ModelSerializer, PassiveSerializer from authentik.core.api.utils import PassiveSerializer
from authentik.core.models import User from authentik.core.models import User
from authentik.lib.config import CONFIG from authentik.lib.config import CONFIG
from authentik.recovery.lib import create_admin_group, create_recovery_token from authentik.recovery.lib import create_admin_group, create_recovery_token

View File

@ -1201,46 +1201,6 @@
} }
} }
}, },
{
"type": "object",
"required": [
"model",
"identifiers"
],
"properties": {
"model": {
"const": "authentik_rbac.initialpermissions"
},
"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_rbac.initialpermissions_permissions"
},
"attrs": {
"$ref": "#/$defs/model_authentik_rbac.initialpermissions"
},
"identifiers": {
"$ref": "#/$defs/model_authentik_rbac.initialpermissions"
}
}
},
{ {
"type": "object", "type": "object",
"required": [ "required": [
@ -4868,7 +4828,6 @@
"authentik_providers_scim.scimprovider", "authentik_providers_scim.scimprovider",
"authentik_providers_scim.scimmapping", "authentik_providers_scim.scimmapping",
"authentik_rbac.role", "authentik_rbac.role",
"authentik_rbac.initialpermissions",
"authentik_sources_kerberos.kerberossource", "authentik_sources_kerberos.kerberossource",
"authentik_sources_kerberos.kerberossourcepropertymapping", "authentik_sources_kerberos.kerberossourcepropertymapping",
"authentik_sources_kerberos.userkerberossourceconnection", "authentik_sources_kerberos.userkerberossourceconnection",
@ -7210,16 +7169,12 @@
"authentik_providers_ssf.view_stream", "authentik_providers_ssf.view_stream",
"authentik_providers_ssf.view_streamevent", "authentik_providers_ssf.view_streamevent",
"authentik_rbac.access_admin_interface", "authentik_rbac.access_admin_interface",
"authentik_rbac.add_initialpermissions",
"authentik_rbac.add_role", "authentik_rbac.add_role",
"authentik_rbac.assign_role_permissions", "authentik_rbac.assign_role_permissions",
"authentik_rbac.change_initialpermissions",
"authentik_rbac.change_role", "authentik_rbac.change_role",
"authentik_rbac.delete_initialpermissions",
"authentik_rbac.delete_role", "authentik_rbac.delete_role",
"authentik_rbac.edit_system_settings", "authentik_rbac.edit_system_settings",
"authentik_rbac.unassign_role_permissions", "authentik_rbac.unassign_role_permissions",
"authentik_rbac.view_initialpermissions",
"authentik_rbac.view_role", "authentik_rbac.view_role",
"authentik_rbac.view_system_info", "authentik_rbac.view_system_info",
"authentik_rbac.view_system_settings", "authentik_rbac.view_system_settings",
@ -7506,64 +7461,6 @@
} }
} }
}, },
"model_authentik_rbac.initialpermissions": {
"type": "object",
"properties": {
"name": {
"type": "string",
"maxLength": 150,
"minLength": 1,
"title": "Name"
},
"mode": {
"type": "string",
"enum": [
"user",
"role"
],
"title": "Mode"
},
"role": {
"type": "string",
"format": "uuid",
"title": "Role"
},
"permissions": {
"type": "array",
"items": {
"type": "integer"
},
"title": "Permissions"
}
},
"required": []
},
"model_authentik_rbac.initialpermissions_permissions": {
"type": "array",
"items": {
"type": "object",
"required": [
"permission"
],
"properties": {
"permission": {
"type": "string",
"enum": [
"add_initialpermissions",
"change_initialpermissions",
"delete_initialpermissions",
"view_initialpermissions"
]
},
"user": {
"type": "integer"
},
"role": {
"type": "string"
}
}
}
},
"model_authentik_sources_kerberos.kerberossource": { "model_authentik_sources_kerberos.kerberossource": {
"type": "object", "type": "object",
"properties": { "properties": {
@ -8436,15 +8333,6 @@
"type": "object", "type": "object",
"additionalProperties": true, "additionalProperties": true,
"title": "Oidc jwks" "title": "Oidc jwks"
},
"authorization_code_auth_method": {
"type": "string",
"enum": [
"basic_auth",
"post_body"
],
"title": "Authorization code auth method",
"description": "How to perform authentication during an authorization_code token request flow"
} }
}, },
"required": [] "required": []
@ -11893,11 +11781,6 @@
"type": "boolean", "type": "boolean",
"title": "Pretend user exists", "title": "Pretend user exists",
"description": "When enabled, the stage will succeed and continue even when incorrect user info is entered." "description": "When enabled, the stage will succeed and continue even when incorrect user info is entered."
},
"enable_remember_me": {
"type": "boolean",
"title": "Enable remember me",
"description": "Show the user the 'Remember me on this device' toggle, allowing repeat users to skip straight to entering their password."
} }
}, },
"required": [] "required": []
@ -13910,16 +13793,12 @@
"authentik_providers_ssf.view_stream", "authentik_providers_ssf.view_stream",
"authentik_providers_ssf.view_streamevent", "authentik_providers_ssf.view_streamevent",
"authentik_rbac.access_admin_interface", "authentik_rbac.access_admin_interface",
"authentik_rbac.add_initialpermissions",
"authentik_rbac.add_role", "authentik_rbac.add_role",
"authentik_rbac.assign_role_permissions", "authentik_rbac.assign_role_permissions",
"authentik_rbac.change_initialpermissions",
"authentik_rbac.change_role", "authentik_rbac.change_role",
"authentik_rbac.delete_initialpermissions",
"authentik_rbac.delete_role", "authentik_rbac.delete_role",
"authentik_rbac.edit_system_settings", "authentik_rbac.edit_system_settings",
"authentik_rbac.unassign_role_permissions", "authentik_rbac.unassign_role_permissions",
"authentik_rbac.view_initialpermissions",
"authentik_rbac.view_role", "authentik_rbac.view_role",
"authentik_rbac.view_system_info", "authentik_rbac.view_system_info",
"authentik_rbac.view_system_settings", "authentik_rbac.view_system_settings",

2
go.mod
View File

@ -27,7 +27,7 @@ require (
github.com/spf13/cobra v1.9.1 github.com/spf13/cobra v1.9.1
github.com/stretchr/testify v1.10.0 github.com/stretchr/testify v1.10.0
github.com/wwt/guac v1.3.2 github.com/wwt/guac v1.3.2
goauthentik.io/api/v3 v3.2025024.7 goauthentik.io/api/v3 v3.2025024.4
golang.org/x/exp v0.0.0-20230210204819-062eb4c674ab golang.org/x/exp v0.0.0-20230210204819-062eb4c674ab
golang.org/x/oauth2 v0.29.0 golang.org/x/oauth2 v0.29.0
golang.org/x/sync v0.13.0 golang.org/x/sync v0.13.0

4
go.sum
View File

@ -300,8 +300,8 @@ go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y
go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
goauthentik.io/api/v3 v3.2025024.7 h1:OOBuyLzv+l5rtvrOYzoDs6Hy9cIfkE5sewRqR5ThSRc= goauthentik.io/api/v3 v3.2025024.4 h1:fD4K6YcCTdwtkqKbYBdJk3POHVzw+LDdJdZSbOAKbX4=
goauthentik.io/api/v3 v3.2025024.7/go.mod h1:zz+mEZg8rY/7eEjkMGWJ2DnGqk+zqxuybGCGrR2O4Kw= goauthentik.io/api/v3 v3.2025024.4/go.mod h1:zz+mEZg8rY/7eEjkMGWJ2DnGqk+zqxuybGCGrR2O4Kw=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=

View File

@ -9,7 +9,7 @@
"version": "0.0.0", "version": "0.0.0",
"license": "MIT", "license": "MIT",
"devDependencies": { "devDependencies": {
"aws-cdk": "^2.1010.0", "aws-cdk": "^2.1007.0",
"cross-env": "^7.0.3" "cross-env": "^7.0.3"
}, },
"engines": { "engines": {
@ -17,9 +17,9 @@
} }
}, },
"node_modules/aws-cdk": { "node_modules/aws-cdk": {
"version": "2.1010.0", "version": "2.1007.0",
"resolved": "https://registry.npmjs.org/aws-cdk/-/aws-cdk-2.1010.0.tgz", "resolved": "https://registry.npmjs.org/aws-cdk/-/aws-cdk-2.1007.0.tgz",
"integrity": "sha512-kYNzBXVUZoRrTuYxRRA2Loz/Uvay0MqHobg8KPZaWylIbw/meUDgtoATRNt+stOdJ9PHODTjWmlDKI+2/KoF+w==", "integrity": "sha512-/UOYOTGWUm+pP9qxg03tID5tL6euC+pb+xo0RBue+xhnUWwj/Bbsw6DbqbpOPMrNzTUxmM723/uMEQmM6S26dw==",
"dev": true, "dev": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"bin": { "bin": {

View File

@ -10,7 +10,7 @@
"node": ">=20" "node": ">=20"
}, },
"devDependencies": { "devDependencies": {
"aws-cdk": "^2.1010.0", "aws-cdk": "^2.1007.0",
"cross-env": "^7.0.3" "cross-env": "^7.0.3"
} }
} }

View File

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-04-17 00:09+0000\n" "POT-Creation-Date: 2025-04-14 00:11+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@ -169,7 +169,6 @@ msgid "User's display name."
msgstr "" msgstr ""
#: authentik/core/models.py authentik/providers/oauth2/models.py #: authentik/core/models.py authentik/providers/oauth2/models.py
#: authentik/rbac/models.py
msgid "User" msgid "User"
msgstr "" msgstr ""
@ -1985,10 +1984,6 @@ msgstr ""
msgid "Roles" msgid "Roles"
msgstr "" msgstr ""
#: authentik/rbac/models.py
msgid "Initial Permissions"
msgstr ""
#: authentik/rbac/models.py #: authentik/rbac/models.py
msgid "System permission" msgid "System permission"
msgstr "" msgstr ""
@ -2254,14 +2249,6 @@ msgstr ""
msgid "No token received." msgid "No token received."
msgstr "" msgstr ""
#: authentik/sources/oauth/models.py
msgid "HTTP Basic Authentication"
msgstr ""
#: authentik/sources/oauth/models.py
msgid "Include the client ID and secret as request parameters"
msgstr ""
#: authentik/sources/oauth/models.py #: authentik/sources/oauth/models.py
msgid "Request Token URL" msgid "Request Token URL"
msgstr "" msgstr ""
@ -2299,11 +2286,6 @@ msgstr ""
msgid "Additional Scopes" msgid "Additional Scopes"
msgstr "" msgstr ""
#: authentik/sources/oauth/models.py
msgid ""
"How to perform authentication during an authorization_code token request flow"
msgstr ""
#: authentik/sources/oauth/models.py #: authentik/sources/oauth/models.py
msgid "OAuth Source" msgid "OAuth Source"
msgstr "" msgstr ""
@ -3486,14 +3468,6 @@ msgid ""
"seconds=2)." "seconds=2)."
msgstr "" msgstr ""
#: authentik/tenants/models.py
msgid "Reputation cannot decrease lower than this value. Zero or negative."
msgstr ""
#: authentik/tenants/models.py
msgid "Reputation cannot increase higher than this value. Zero or positive."
msgstr ""
#: authentik/tenants/models.py #: authentik/tenants/models.py
msgid "The option configures the footer links on the flow executor pages." msgid "The option configures the footer links on the flow executor pages."
msgstr "" msgstr ""

View File

@ -9,9 +9,9 @@
# Kyllian Delaye-Maillot, 2023 # Kyllian Delaye-Maillot, 2023
# Manuel Viens, 2023 # Manuel Viens, 2023
# Mordecai, 2023 # Mordecai, 2023
# nerdinator <florian.dupret@gmail.com>, 2024
# Charles Leclerc, 2025 # Charles Leclerc, 2025
# Tina, 2025 # Tina, 2025
# nerdinator <florian.dupret@gmail.com>, 2025
# Marc Schmitt, 2025 # Marc Schmitt, 2025
# #
#, fuzzy #, fuzzy
@ -19,7 +19,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-04-15 00:11+0000\n" "POT-Creation-Date: 2025-04-11 00:10+0000\n"
"PO-Revision-Date: 2022-09-26 16:47+0000\n" "PO-Revision-Date: 2022-09-26 16:47+0000\n"
"Last-Translator: Marc Schmitt, 2025\n" "Last-Translator: Marc Schmitt, 2025\n"
"Language-Team: French (https://app.transifex.com/authentik/teams/119923/fr/)\n" "Language-Team: French (https://app.transifex.com/authentik/teams/119923/fr/)\n"
@ -194,7 +194,6 @@ msgid "User's display name."
msgstr "Nom d'affichage de l'utilisateur" msgstr "Nom d'affichage de l'utilisateur"
#: authentik/core/models.py authentik/providers/oauth2/models.py #: authentik/core/models.py authentik/providers/oauth2/models.py
#: authentik/rbac/models.py
msgid "User" msgid "User"
msgstr "Utilisateur" msgstr "Utilisateur"
@ -383,18 +382,6 @@ msgstr "Mappage de propriété"
msgid "Property Mappings" msgid "Property Mappings"
msgstr "Mappages de propriété" msgstr "Mappages de propriété"
#: authentik/core/models.py
msgid "session data"
msgstr "Données de session"
#: authentik/core/models.py
msgid "Session"
msgstr "Session"
#: authentik/core/models.py
msgid "Sessions"
msgstr "Sessions"
#: authentik/core/models.py #: authentik/core/models.py
msgid "Authenticated Session" msgid "Authenticated Session"
msgstr "Session Authentifiée" msgstr "Session Authentifiée"
@ -2210,10 +2197,6 @@ msgstr "Rôle"
msgid "Roles" msgid "Roles"
msgstr "Rôles" msgstr "Rôles"
#: authentik/rbac/models.py
msgid "Initial Permissions"
msgstr "Permissions initiales"
#: authentik/rbac/models.py #: authentik/rbac/models.py
msgid "System permission" msgid "System permission"
msgstr "Permission système" msgstr "Permission système"
@ -2464,9 +2447,6 @@ msgid ""
"attribute. This allows nested group resolution on systems like FreeIPA and " "attribute. This allows nested group resolution on systems like FreeIPA and "
"Active Directory" "Active Directory"
msgstr "" msgstr ""
"Recherche de l'appartenance aux groupes basée sur un attribut utilisateur "
"plutôt que sur un attribut de groupe. Cela permet la résolution des groupes "
"imbriqués sur des systèmes tels que FreeIPA et Active Directory."
#: authentik/sources/ldap/models.py #: authentik/sources/ldap/models.py
msgid "LDAP Source" msgid "LDAP Source"
@ -2484,22 +2464,6 @@ msgstr "Mappage de propriété source LDAP"
msgid "LDAP Source Property Mappings" msgid "LDAP Source Property Mappings"
msgstr "Mappages de propriété source LDAP" msgstr "Mappages de propriété source LDAP"
#: authentik/sources/ldap/models.py
msgid "User LDAP Source Connection"
msgstr "Connexion de l'utilisateur à la source LDAP"
#: authentik/sources/ldap/models.py
msgid "User LDAP Source Connections"
msgstr "Connexions de l'utilisateur à la source LDAP"
#: authentik/sources/ldap/models.py
msgid "Group LDAP Source Connection"
msgstr "Connexion du groupe à la source LDAP"
#: authentik/sources/ldap/models.py
msgid "Group LDAP Source Connections"
msgstr "Connexions du groupe à la source LDAP"
#: authentik/sources/ldap/signals.py #: authentik/sources/ldap/signals.py
msgid "Password does not match Active Directory Complexity." msgid "Password does not match Active Directory Complexity."
msgstr "Le mot de passe ne correspond pas à la complexité d'Active Directory." msgstr "Le mot de passe ne correspond pas à la complexité d'Active Directory."
@ -3853,17 +3817,6 @@ msgstr ""
"Les évènements seront supprimés après cet interval. (Format : " "Les évènements seront supprimés après cet interval. (Format : "
"weeks=3;days=2;hours=3,seconds=2)" "weeks=3;days=2;hours=3,seconds=2)"
#: authentik/tenants/models.py
msgid "Reputation cannot decrease lower than this value. Zero or negative."
msgstr ""
"La réputation ne peut pas descendre en dessous de cette valeur. Zéro ou "
"négatif."
#: authentik/tenants/models.py
msgid "Reputation cannot increase higher than this value. Zero or positive."
msgstr ""
"La réputation ne peut pas monter au dessus de cette valeur. Zéro ou positif."
#: authentik/tenants/models.py #: authentik/tenants/models.py
msgid "The option configures the footer links on the flow executor pages." msgid "The option configures the footer links on the flow executor pages."
msgstr "" msgstr ""

Binary file not shown.

Binary file not shown.

View File

@ -15,7 +15,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-04-15 00:11+0000\n" "POT-Creation-Date: 2025-04-11 00:10+0000\n"
"PO-Revision-Date: 2022-09-26 16:47+0000\n" "PO-Revision-Date: 2022-09-26 16:47+0000\n"
"Last-Translator: deluxghost, 2025\n" "Last-Translator: deluxghost, 2025\n"
"Language-Team: Chinese Simplified (https://app.transifex.com/authentik/teams/119923/zh-Hans/)\n" "Language-Team: Chinese Simplified (https://app.transifex.com/authentik/teams/119923/zh-Hans/)\n"
@ -179,7 +179,6 @@ msgid "User's display name."
msgstr "用户的显示名称。" msgstr "用户的显示名称。"
#: authentik/core/models.py authentik/providers/oauth2/models.py #: authentik/core/models.py authentik/providers/oauth2/models.py
#: authentik/rbac/models.py
msgid "User" msgid "User"
msgstr "用户" msgstr "用户"
@ -346,18 +345,6 @@ msgstr "属性映射"
msgid "Property Mappings" msgid "Property Mappings"
msgstr "属性映射" msgstr "属性映射"
#: authentik/core/models.py
msgid "session data"
msgstr "会话数据"
#: authentik/core/models.py
msgid "Session"
msgstr "会话"
#: authentik/core/models.py
msgid "Sessions"
msgstr "会话"
#: authentik/core/models.py #: authentik/core/models.py
msgid "Authenticated Session" msgid "Authenticated Session"
msgstr "已认证会话" msgstr "已认证会话"
@ -1256,11 +1243,11 @@ msgstr "正在等待身份验证…"
msgid "" msgid ""
"You're already authenticating in another tab. This page will refresh once " "You're already authenticating in another tab. This page will refresh once "
"authentication is completed." "authentication is completed."
msgstr "您正在另一个标签页中验证身份。身份验证完成后,此页面会刷新。" msgstr ""
#: authentik/policies/templates/policies/buffer.html #: authentik/policies/templates/policies/buffer.html
msgid "Authenticate in this tab" msgid "Authenticate in this tab"
msgstr "在此标签页中验证身份" msgstr ""
#: authentik/policies/templates/policies/denied.html #: authentik/policies/templates/policies/denied.html
msgid "Permission denied" msgid "Permission denied"
@ -2012,10 +1999,6 @@ msgstr "角色"
msgid "Roles" msgid "Roles"
msgstr "角色" msgstr "角色"
#: authentik/rbac/models.py
msgid "Initial Permissions"
msgstr "初始权限"
#: authentik/rbac/models.py #: authentik/rbac/models.py
msgid "System permission" msgid "System permission"
msgstr "系统权限" msgstr "系统权限"
@ -2244,7 +2227,7 @@ msgid ""
"Lookup group membership based on a user attribute instead of a group " "Lookup group membership based on a user attribute instead of a group "
"attribute. This allows nested group resolution on systems like FreeIPA and " "attribute. This allows nested group resolution on systems like FreeIPA and "
"Active Directory" "Active Directory"
msgstr "基于用户属性而非组属性查询组成员身份。这允许在 FreeIPA 或 Active Directory 等系统上支持嵌套组决策" msgstr ""
#: authentik/sources/ldap/models.py #: authentik/sources/ldap/models.py
msgid "LDAP Source" msgid "LDAP Source"
@ -2262,22 +2245,6 @@ msgstr "LDAP 源属性映射"
msgid "LDAP Source Property Mappings" msgid "LDAP Source Property Mappings"
msgstr "LDAP 源属性映射" msgstr "LDAP 源属性映射"
#: authentik/sources/ldap/models.py
msgid "User LDAP Source Connection"
msgstr "用户 LDAP 源连接"
#: authentik/sources/ldap/models.py
msgid "User LDAP Source Connections"
msgstr "用户 LDAP 源连接"
#: authentik/sources/ldap/models.py
msgid "Group LDAP Source Connection"
msgstr "组 LDAP 源连接"
#: authentik/sources/ldap/models.py
msgid "Group LDAP Source Connections"
msgstr "组 LDAP 源连接"
#: authentik/sources/ldap/signals.py #: authentik/sources/ldap/signals.py
msgid "Password does not match Active Directory Complexity." msgid "Password does not match Active Directory Complexity."
msgstr "密码与 Active Directory 复杂度不匹配。" msgstr "密码与 Active Directory 复杂度不匹配。"
@ -3538,14 +3505,6 @@ msgid ""
"weeks=3;days=2;hours=3,seconds=2)." "weeks=3;days=2;hours=3,seconds=2)."
msgstr "事件会在多久后被删除。格式weeks=3;days=2;hours=3,seconds=2。" msgstr "事件会在多久后被删除。格式weeks=3;days=2;hours=3,seconds=2。"
#: authentik/tenants/models.py
msgid "Reputation cannot decrease lower than this value. Zero or negative."
msgstr "信誉无法降低到此值以下。可为零或负数。"
#: authentik/tenants/models.py
msgid "Reputation cannot increase higher than this value. Zero or positive."
msgstr "信誉无法提高到此值以上。可为零或正数。"
#: authentik/tenants/models.py #: authentik/tenants/models.py
msgid "The option configures the footer links on the flow executor pages." msgid "The option configures the footer links on the flow executor pages."
msgstr "此选项配置流程执行器页面上的页脚链接。" msgstr "此选项配置流程执行器页面上的页脚链接。"

View File

@ -14,7 +14,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-04-15 00:11+0000\n" "POT-Creation-Date: 2025-04-11 00:10+0000\n"
"PO-Revision-Date: 2022-09-26 16:47+0000\n" "PO-Revision-Date: 2022-09-26 16:47+0000\n"
"Last-Translator: deluxghost, 2025\n" "Last-Translator: deluxghost, 2025\n"
"Language-Team: Chinese (China) (https://app.transifex.com/authentik/teams/119923/zh_CN/)\n" "Language-Team: Chinese (China) (https://app.transifex.com/authentik/teams/119923/zh_CN/)\n"
@ -178,7 +178,6 @@ msgid "User's display name."
msgstr "用户的显示名称。" msgstr "用户的显示名称。"
#: authentik/core/models.py authentik/providers/oauth2/models.py #: authentik/core/models.py authentik/providers/oauth2/models.py
#: authentik/rbac/models.py
msgid "User" msgid "User"
msgstr "用户" msgstr "用户"
@ -345,18 +344,6 @@ msgstr "属性映射"
msgid "Property Mappings" msgid "Property Mappings"
msgstr "属性映射" msgstr "属性映射"
#: authentik/core/models.py
msgid "session data"
msgstr "会话数据"
#: authentik/core/models.py
msgid "Session"
msgstr "会话"
#: authentik/core/models.py
msgid "Sessions"
msgstr "会话"
#: authentik/core/models.py #: authentik/core/models.py
msgid "Authenticated Session" msgid "Authenticated Session"
msgstr "已认证会话" msgstr "已认证会话"
@ -2011,10 +1998,6 @@ msgstr "角色"
msgid "Roles" msgid "Roles"
msgstr "角色" msgstr "角色"
#: authentik/rbac/models.py
msgid "Initial Permissions"
msgstr "初始权限"
#: authentik/rbac/models.py #: authentik/rbac/models.py
msgid "System permission" msgid "System permission"
msgstr "系统权限" msgstr "系统权限"
@ -2243,7 +2226,7 @@ msgid ""
"Lookup group membership based on a user attribute instead of a group " "Lookup group membership based on a user attribute instead of a group "
"attribute. This allows nested group resolution on systems like FreeIPA and " "attribute. This allows nested group resolution on systems like FreeIPA and "
"Active Directory" "Active Directory"
msgstr "基于用户属性而非组属性查询组成员身份。这允许在 FreeIPA 或 Active Directory 等系统上支持嵌套组决策" msgstr ""
#: authentik/sources/ldap/models.py #: authentik/sources/ldap/models.py
msgid "LDAP Source" msgid "LDAP Source"
@ -2261,22 +2244,6 @@ msgstr "LDAP 源属性映射"
msgid "LDAP Source Property Mappings" msgid "LDAP Source Property Mappings"
msgstr "LDAP 源属性映射" msgstr "LDAP 源属性映射"
#: authentik/sources/ldap/models.py
msgid "User LDAP Source Connection"
msgstr "用户 LDAP 源连接"
#: authentik/sources/ldap/models.py
msgid "User LDAP Source Connections"
msgstr "用户 LDAP 源连接"
#: authentik/sources/ldap/models.py
msgid "Group LDAP Source Connection"
msgstr "组 LDAP 源连接"
#: authentik/sources/ldap/models.py
msgid "Group LDAP Source Connections"
msgstr "组 LDAP 源连接"
#: authentik/sources/ldap/signals.py #: authentik/sources/ldap/signals.py
msgid "Password does not match Active Directory Complexity." msgid "Password does not match Active Directory Complexity."
msgstr "密码与 Active Directory 复杂度不匹配。" msgstr "密码与 Active Directory 复杂度不匹配。"
@ -3537,14 +3504,6 @@ msgid ""
"weeks=3;days=2;hours=3,seconds=2)." "weeks=3;days=2;hours=3,seconds=2)."
msgstr "事件会在多久后被删除。格式weeks=3;days=2;hours=3,seconds=2。" msgstr "事件会在多久后被删除。格式weeks=3;days=2;hours=3,seconds=2。"
#: authentik/tenants/models.py
msgid "Reputation cannot decrease lower than this value. Zero or negative."
msgstr "信誉无法降低到此值以下。可为零或负数。"
#: authentik/tenants/models.py
msgid "Reputation cannot increase higher than this value. Zero or positive."
msgstr "信誉无法提高到此值以上。可为零或正数。"
#: authentik/tenants/models.py #: authentik/tenants/models.py
msgid "The option configures the footer links on the flow executor pages." msgid "The option configures the footer links on the flow executor pages."
msgstr "此选项配置流程执行器页面上的页脚链接。" msgstr "此选项配置流程执行器页面上的页脚链接。"

View File

@ -47,7 +47,7 @@ dependencies = [
"opencontainers", "opencontainers",
"packaging", "packaging",
"paramiko", "paramiko",
"psycopg[c, pool]", "psycopg[c]",
"pydantic", "pydantic",
"pydantic-scim", "pydantic-scim",
"pyjwt", "pyjwt",

View File

@ -24209,270 +24209,6 @@ paths:
schema: schema:
$ref: '#/components/schemas/GenericError' $ref: '#/components/schemas/GenericError'
description: '' description: ''
/rbac/initial_permissions/:
get:
operationId: rbac_initial_permissions_list
description: InitialPermissions viewset
parameters:
- 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:
- rbac
security:
- authentik: []
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/PaginatedInitialPermissionsList'
description: ''
'400':
content:
application/json:
schema:
$ref: '#/components/schemas/ValidationError'
description: ''
'403':
content:
application/json:
schema:
$ref: '#/components/schemas/GenericError'
description: ''
post:
operationId: rbac_initial_permissions_create
description: InitialPermissions viewset
tags:
- rbac
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/InitialPermissionsRequest'
required: true
security:
- authentik: []
responses:
'201':
content:
application/json:
schema:
$ref: '#/components/schemas/InitialPermissions'
description: ''
'400':
content:
application/json:
schema:
$ref: '#/components/schemas/ValidationError'
description: ''
'403':
content:
application/json:
schema:
$ref: '#/components/schemas/GenericError'
description: ''
/rbac/initial_permissions/{id}/:
get:
operationId: rbac_initial_permissions_retrieve
description: InitialPermissions viewset
parameters:
- in: path
name: id
schema:
type: integer
description: A unique integer value identifying this Initial Permissions.
required: true
tags:
- rbac
security:
- authentik: []
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/InitialPermissions'
description: ''
'400':
content:
application/json:
schema:
$ref: '#/components/schemas/ValidationError'
description: ''
'403':
content:
application/json:
schema:
$ref: '#/components/schemas/GenericError'
description: ''
put:
operationId: rbac_initial_permissions_update
description: InitialPermissions viewset
parameters:
- in: path
name: id
schema:
type: integer
description: A unique integer value identifying this Initial Permissions.
required: true
tags:
- rbac
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/InitialPermissionsRequest'
required: true
security:
- authentik: []
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/InitialPermissions'
description: ''
'400':
content:
application/json:
schema:
$ref: '#/components/schemas/ValidationError'
description: ''
'403':
content:
application/json:
schema:
$ref: '#/components/schemas/GenericError'
description: ''
patch:
operationId: rbac_initial_permissions_partial_update
description: InitialPermissions viewset
parameters:
- in: path
name: id
schema:
type: integer
description: A unique integer value identifying this Initial Permissions.
required: true
tags:
- rbac
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/PatchedInitialPermissionsRequest'
security:
- authentik: []
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/InitialPermissions'
description: ''
'400':
content:
application/json:
schema:
$ref: '#/components/schemas/ValidationError'
description: ''
'403':
content:
application/json:
schema:
$ref: '#/components/schemas/GenericError'
description: ''
delete:
operationId: rbac_initial_permissions_destroy
description: InitialPermissions viewset
parameters:
- in: path
name: id
schema:
type: integer
description: A unique integer value identifying this Initial Permissions.
required: true
tags:
- rbac
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: ''
/rbac/initial_permissions/{id}/used_by/:
get:
operationId: rbac_initial_permissions_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 Initial Permissions.
required: true
tags:
- rbac
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: ''
/rbac/permissions/: /rbac/permissions/:
get: get:
operationId: rbac_permissions_list operationId: rbac_permissions_list
@ -24634,7 +24370,6 @@ paths:
- authentik_providers_scim.scimmapping - authentik_providers_scim.scimmapping
- authentik_providers_scim.scimprovider - authentik_providers_scim.scimprovider
- authentik_providers_ssf.ssfprovider - authentik_providers_ssf.ssfprovider
- authentik_rbac.initialpermissions
- authentik_rbac.role - authentik_rbac.role
- authentik_sources_kerberos.groupkerberossourceconnection - authentik_sources_kerberos.groupkerberossourceconnection
- authentik_sources_kerberos.kerberossource - authentik_sources_kerberos.kerberossource
@ -24881,7 +24616,6 @@ paths:
- authentik_providers_scim.scimmapping - authentik_providers_scim.scimmapping
- authentik_providers_scim.scimprovider - authentik_providers_scim.scimprovider
- authentik_providers_ssf.ssfprovider - authentik_providers_ssf.ssfprovider
- authentik_rbac.initialpermissions
- authentik_rbac.role - authentik_rbac.role
- authentik_sources_kerberos.groupkerberossourceconnection - authentik_sources_kerberos.groupkerberossourceconnection
- authentik_sources_kerberos.kerberossource - authentik_sources_kerberos.kerberossource
@ -42110,11 +41844,6 @@ components:
format: uuid format: uuid
required: required:
- name - name
AuthorizationCodeAuthMethodEnum:
enum:
- basic_auth
- post_body
type: string
AutoSubmitChallengeResponseRequest: AutoSubmitChallengeResponseRequest:
type: object type: object
description: Pseudo class for autosubmit response description: Pseudo class for autosubmit response
@ -46049,9 +45778,6 @@ components:
$ref: '#/components/schemas/LoginSource' $ref: '#/components/schemas/LoginSource'
show_source_labels: show_source_labels:
type: boolean type: boolean
enable_remember_me:
type: boolean
default: true
required: required:
- flow_designation - flow_designation
- password_fields - password_fields
@ -46164,10 +45890,6 @@ components:
type: boolean type: boolean
description: When enabled, the stage will succeed and continue even when description: When enabled, the stage will succeed and continue even when
incorrect user info is entered. incorrect user info is entered.
enable_remember_me:
type: boolean
description: Show the user the 'Remember me on this device' toggle, allowing
repeat users to skip straight to entering their password.
required: required:
- component - component
- meta_model_name - meta_model_name
@ -46242,10 +45964,6 @@ components:
type: boolean type: boolean
description: When enabled, the stage will succeed and continue even when description: When enabled, the stage will succeed and continue even when
incorrect user info is entered. incorrect user info is entered.
enable_remember_me:
type: boolean
description: Show the user the 'Remember me on this device' toggle, allowing
repeat users to skip straight to entering their password.
required: required:
- name - name
ImpersonationRequest: ImpersonationRequest:
@ -46256,63 +45974,6 @@ components:
minLength: 1 minLength: 1
required: required:
- reason - reason
InitialPermissions:
type: object
description: InitialPermissions serializer
properties:
pk:
type: integer
readOnly: true
title: ID
name:
type: string
maxLength: 150
mode:
$ref: '#/components/schemas/InitialPermissionsModeEnum'
role:
type: string
format: uuid
permissions:
type: array
items:
type: integer
permissions_obj:
type: array
items:
$ref: '#/components/schemas/Permission'
readOnly: true
required:
- mode
- name
- permissions_obj
- pk
- role
InitialPermissionsModeEnum:
enum:
- user
- role
type: string
InitialPermissionsRequest:
type: object
description: InitialPermissions serializer
properties:
name:
type: string
minLength: 1
maxLength: 150
mode:
$ref: '#/components/schemas/InitialPermissionsModeEnum'
role:
type: string
format: uuid
permissions:
type: array
items:
type: integer
required:
- mode
- name
- role
InstallID: InstallID:
type: object type: object
properties: properties:
@ -48001,7 +47662,6 @@ components:
- authentik_providers_scim.scimprovider - authentik_providers_scim.scimprovider
- authentik_providers_scim.scimmapping - authentik_providers_scim.scimmapping
- authentik_rbac.role - authentik_rbac.role
- authentik_rbac.initialpermissions
- authentik_sources_kerberos.kerberossource - authentik_sources_kerberos.kerberossource
- authentik_sources_kerberos.kerberossourcepropertymapping - authentik_sources_kerberos.kerberossourcepropertymapping
- authentik_sources_kerberos.userkerberossourceconnection - authentik_sources_kerberos.userkerberossourceconnection
@ -48758,11 +48418,6 @@ components:
oidc_jwks_url: oidc_jwks_url:
type: string type: string
oidc_jwks: {} oidc_jwks: {}
authorization_code_auth_method:
allOf:
- $ref: '#/components/schemas/AuthorizationCodeAuthMethodEnum'
description: How to perform authentication during an authorization_code
token request flow
required: required:
- callback_url - callback_url
- component - component
@ -48932,11 +48587,6 @@ components:
oidc_jwks_url: oidc_jwks_url:
type: string type: string
oidc_jwks: {} oidc_jwks: {}
authorization_code_auth_method:
allOf:
- $ref: '#/components/schemas/AuthorizationCodeAuthMethodEnum'
description: How to perform authentication during an authorization_code
token request flow
required: required:
- consumer_key - consumer_key
- consumer_secret - consumer_secret
@ -49740,18 +49390,6 @@ components:
required: required:
- pagination - pagination
- results - results
PaginatedInitialPermissionsList:
type: object
properties:
pagination:
$ref: '#/components/schemas/Pagination'
results:
type: array
items:
$ref: '#/components/schemas/InitialPermissions'
required:
- pagination
- results
PaginatedInvitationList: PaginatedInvitationList:
type: object type: object
properties: properties:
@ -52301,27 +51939,6 @@ components:
type: boolean type: boolean
description: When enabled, the stage will succeed and continue even when description: When enabled, the stage will succeed and continue even when
incorrect user info is entered. incorrect user info is entered.
enable_remember_me:
type: boolean
description: Show the user the 'Remember me on this device' toggle, allowing
repeat users to skip straight to entering their password.
PatchedInitialPermissionsRequest:
type: object
description: InitialPermissions serializer
properties:
name:
type: string
minLength: 1
maxLength: 150
mode:
$ref: '#/components/schemas/InitialPermissionsModeEnum'
role:
type: string
format: uuid
permissions:
type: array
items:
type: integer
PatchedInvitationRequest: PatchedInvitationRequest:
type: object type: object
description: Invitation Serializer description: Invitation Serializer
@ -53039,11 +52656,6 @@ components:
oidc_jwks_url: oidc_jwks_url:
type: string type: string
oidc_jwks: {} oidc_jwks: {}
authorization_code_auth_method:
allOf:
- $ref: '#/components/schemas/AuthorizationCodeAuthMethodEnum'
description: How to perform authentication during an authorization_code
token request flow
PatchedOutpostRequest: PatchedOutpostRequest:
type: object type: object
description: Outpost Serializer description: Outpost Serializer
@ -54492,21 +54104,6 @@ components:
type: string type: string
required: required:
- id - id
PermissionRequest:
type: object
description: Global permission
properties:
name:
type: string
minLength: 1
maxLength: 255
codename:
type: string
minLength: 1
maxLength: 100
required:
- codename
- name
PlexAuthenticationChallenge: PlexAuthenticationChallenge:
type: object type: object
description: Challenge shown to the user in identification stage description: Challenge shown to the user in identification stage

79
uv.lock generated
View File

@ -210,7 +210,7 @@ dependencies = [
{ name = "opencontainers" }, { name = "opencontainers" },
{ name = "packaging" }, { name = "packaging" },
{ name = "paramiko" }, { name = "paramiko" },
{ name = "psycopg", extra = ["c", "pool"] }, { name = "psycopg", extra = ["c"] },
{ name = "pydantic" }, { name = "pydantic" },
{ name = "pydantic-scim" }, { name = "pydantic-scim" },
{ name = "pyjwt" }, { name = "pyjwt" },
@ -308,7 +308,7 @@ requires-dist = [
{ name = "opencontainers", git = "https://github.com/BeryJu/oci-python?rev=c791b19056769cd67957322806809ab70f5bead8" }, { name = "opencontainers", git = "https://github.com/BeryJu/oci-python?rev=c791b19056769cd67957322806809ab70f5bead8" },
{ name = "packaging" }, { name = "packaging" },
{ name = "paramiko" }, { name = "paramiko" },
{ name = "psycopg", extras = ["c", "pool"] }, { name = "psycopg", extras = ["c"] },
{ name = "pydantic" }, { name = "pydantic" },
{ name = "pydantic-scim" }, { name = "pydantic-scim" },
{ name = "pyjwt" }, { name = "pyjwt" },
@ -558,30 +558,30 @@ wheels = [
[[package]] [[package]]
name = "boto3" name = "boto3"
version = "1.37.34" version = "1.37.33"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "botocore" }, { name = "botocore" },
{ name = "jmespath" }, { name = "jmespath" },
{ name = "s3transfer" }, { name = "s3transfer" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/39/5d/6b1ca20ba4da350799509a69f2d295ae11d5ec08a98e82f74b5708a8180c/boto3-1.37.34.tar.gz", hash = "sha256:94ca07328474db3fa605eb99b011512caa73f7161740d365a1f00cfebfb6dd90", size = 111701 } sdist = { url = "https://files.pythonhosted.org/packages/89/74/001695948752bc1b5357677eb2635e059f464b22c3eb5f9411ec4e8c48a3/boto3-1.37.33.tar.gz", hash = "sha256:4390317a1578af73f1514651bd180ba25802dcbe0a23deafa13851d54d3c3203", size = 111676 }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/cb/2e/ad43d1e87d46d11dcf4104f97b9a7f6beb38a52a0e752edfadf3eb8b6e38/boto3-1.37.34-py3-none-any.whl", hash = "sha256:586bfa72a00601c04067f9adcbb08ecaf63b05b7d731103f33cb2ce0d6950b1b", size = 139920 }, { url = "https://files.pythonhosted.org/packages/1f/e7/e660fac728570c926c4a12fa1ae8bffde7300d4817942bbd7871a6ebd4e2/boto3-1.37.33-py3-none-any.whl", hash = "sha256:7b1b1bc69762975824e5a5d570880abebf634f7594f88b3dc175e8800f35be1a", size = 139920 },
] ]
[[package]] [[package]]
name = "botocore" name = "botocore"
version = "1.37.34" version = "1.37.33"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "jmespath" }, { name = "jmespath" },
{ name = "python-dateutil" }, { name = "python-dateutil" },
{ name = "urllib3" }, { name = "urllib3" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/ca/60/9ec251a0e2d3994f3eac8bd9741576757c3aad189abbdec8fab6011f5a1a/botocore-1.37.34.tar.gz", hash = "sha256:2909b6dbf9c90347c71a6fa0364acee522d6a7664f13d6f7996c9dd1b1f46fac", size = 13817141 } sdist = { url = "https://files.pythonhosted.org/packages/f4/1d/0c539ae261d2f8fe8b47c358b369ec58645bf0ea96b78825365e48675b67/botocore-1.37.33.tar.gz", hash = "sha256:09b213b0d0500040f85c7daee912ea767c724e43ed61909e624c803ff6925222", size = 13817305 }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/e8/51/19fff717cc5000708c4ce3d081bb0e63ca117c6823975b33101d52fdd9f5/botocore-1.37.34-py3-none-any.whl", hash = "sha256:bd9af0db1097befd2028ba8525e32cacc04f26ccb9dbd5d48d6ecd05bc16c27a", size = 13483679 }, { url = "https://files.pythonhosted.org/packages/21/93/425fb149fb969f07804f60cb1931d8aab197eb5f45dce821cbbbffc49207/botocore-1.37.33-py3-none-any.whl", hash = "sha256:4a167dfecae51e9140de24067de1c339acde5ade3dad524a4600ac2c72055e23", size = 13482312 },
] ]
[[package]] [[package]]
@ -1370,16 +1370,16 @@ wheels = [
[[package]] [[package]]
name = "google-auth" name = "google-auth"
version = "2.39.0" version = "2.38.0"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "cachetools" }, { name = "cachetools" },
{ name = "pyasn1-modules" }, { name = "pyasn1-modules" },
{ name = "rsa" }, { name = "rsa" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/cb/8e/8f45c9a32f73e786e954b8f9761c61422955d23c45d1e8c347f9b4b59e8e/google_auth-2.39.0.tar.gz", hash = "sha256:73222d43cdc35a3aeacbfdcaf73142a97839f10de930550d89ebfe1d0a00cde7", size = 274834 } sdist = { url = "https://files.pythonhosted.org/packages/c6/eb/d504ba1daf190af6b204a9d4714d457462b486043744901a6eeea711f913/google_auth-2.38.0.tar.gz", hash = "sha256:8285113607d3b80a3f1543b75962447ba8a09fe85783432a784fdeef6ac094c4", size = 270866 }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/ce/12/ad37a1ef86006d0a0117fc06a4a00bd461c775356b534b425f00dde208ea/google_auth-2.39.0-py2.py3-none-any.whl", hash = "sha256:0150b6711e97fb9f52fe599f55648950cc4540015565d8fbb31be2ad6e1548a2", size = 212319 }, { url = "https://files.pythonhosted.org/packages/9d/47/603554949a37bca5b7f894d51896a9c534b9eab808e2520a748e081669d0/google_auth-2.38.0-py2.py3-none-any.whl", hash = "sha256:e7dae6694313f434a2727bf2906f27ad259bae090d7aa896590d86feec3d9d4a", size = 210770 },
] ]
[[package]] [[package]]
@ -2009,7 +2009,7 @@ wheels = [
[[package]] [[package]]
name = "msgraph-sdk" name = "msgraph-sdk"
version = "1.28.0" version = "1.27.0"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "azure-identity" }, { name = "azure-identity" },
@ -2019,9 +2019,9 @@ dependencies = [
{ name = "microsoft-kiota-serialization-text" }, { name = "microsoft-kiota-serialization-text" },
{ name = "msgraph-core" }, { name = "msgraph-core" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/b9/41/40bb3c630ca026182aefd79a9862ef4a1917b1161c83690c858d714788f5/msgraph_sdk-1.28.0.tar.gz", hash = "sha256:b2d64b7bd711ad285fc2c090dd524853a026848732e1c83874fe34561805350d", size = 6121069 } sdist = { url = "https://files.pythonhosted.org/packages/a5/5d/678e6e95151ebc012a8e00164ea85c3c638c3e9d42baf76bb0efbde4fce2/msgraph_sdk-1.27.0.tar.gz", hash = "sha256:92c3d168a2842eec631c772c2825864aa53ca54ea417935a6a9d2d1e50ede6f5", size = 6121021 }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/a8/58/d8e9593ea81779d503831b5b06c8d9881d5affefe3df99ca20112c969e6f/msgraph_sdk-1.28.0-py3-none-any.whl", hash = "sha256:bd33b186371dfa8ed6375dfda92eef0931485633e69b06c001ce3c2fd3658f18", size = 25091309 }, { url = "https://files.pythonhosted.org/packages/0b/ec/a2a7bda2e5828b16cc561aee996b2ee28724e5921bf571ae1846bafde805/msgraph_sdk-1.27.0-py3-none-any.whl", hash = "sha256:d5e91ef46fc7b95ae8e003cc3a27793075f4efeabd65611ccb9dad6976f76e99", size = 25091359 },
] ]
[[package]] [[package]]
@ -2084,42 +2084,42 @@ source = { git = "https://github.com/BeryJu/oci-python?rev=c791b19056769cd679573
[[package]] [[package]]
name = "opentelemetry-api" name = "opentelemetry-api"
version = "1.32.1" version = "1.32.0"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "deprecated" }, { name = "deprecated" },
{ name = "importlib-metadata" }, { name = "importlib-metadata" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/42/40/2359245cd33641c2736a0136a50813352d72f3fc209de28fb226950db4a1/opentelemetry_api-1.32.1.tar.gz", hash = "sha256:a5be71591694a4d9195caf6776b055aa702e964d961051a0715d05f8632c32fb", size = 64138 } sdist = { url = "https://files.pythonhosted.org/packages/7b/34/e701d77900123af17a11dbaf0c9f527fa7ef94b8f02b2c55bed94477890a/opentelemetry_api-1.32.0.tar.gz", hash = "sha256:2623280c916f9b19cad0aa4280cb171265f19fd2909b0d47e4f06f7c83b02cb5", size = 64134 }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/12/f2/89ea3361a305466bc6460a532188830351220b5f0851a5fa133155c16eca/opentelemetry_api-1.32.1-py3-none-any.whl", hash = "sha256:bbd19f14ab9f15f0e85e43e6a958aa4cb1f36870ee62b7fd205783a112012724", size = 65287 }, { url = "https://files.pythonhosted.org/packages/fe/e8/d05fd19c1c7e7e230ab44c366791179fd64c843bc587c257a56e853893c5/opentelemetry_api-1.32.0-py3-none-any.whl", hash = "sha256:15df743c765078611f376037b0d9111ec5c1febf2ec9440cdd919370faa1ce55", size = 65285 },
] ]
[[package]] [[package]]
name = "opentelemetry-sdk" name = "opentelemetry-sdk"
version = "1.32.1" version = "1.32.0"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "opentelemetry-api" }, { name = "opentelemetry-api" },
{ name = "opentelemetry-semantic-conventions" }, { name = "opentelemetry-semantic-conventions" },
{ name = "typing-extensions" }, { name = "typing-extensions" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/a3/65/2069caef9257fae234ca0040d945c741aa7afbd83a7298ee70fc0bc6b6f4/opentelemetry_sdk-1.32.1.tar.gz", hash = "sha256:8ef373d490961848f525255a42b193430a0637e064dd132fd2a014d94792a092", size = 161044 } sdist = { url = "https://files.pythonhosted.org/packages/e8/0c/842aed73035cab0302ec70057f3180f4f023974d74bd9764ef3046f358fb/opentelemetry_sdk-1.32.0.tar.gz", hash = "sha256:5ff07fb371d1ab1189fa7047702e2e888b5403c5efcbb18083cae0d5aa5f58d2", size = 161043 }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/dc/00/d3976cdcb98027aaf16f1e980e54935eb820872792f0eaedd4fd7abb5964/opentelemetry_sdk-1.32.1-py3-none-any.whl", hash = "sha256:bba37b70a08038613247bc42beee5a81b0ddca422c7d7f1b097b32bf1c7e2f17", size = 118989 }, { url = "https://files.pythonhosted.org/packages/ee/6a/b8cb562234bd94bcf12ad3058ef7f31319b94a8df65130ce9cc2ff3c8d55/opentelemetry_sdk-1.32.0-py3-none-any.whl", hash = "sha256:ed252d035c22a15536c1f603ca089298daab60850fc2f5ddfa95d95cc1c043ea", size = 118990 },
] ]
[[package]] [[package]]
name = "opentelemetry-semantic-conventions" name = "opentelemetry-semantic-conventions"
version = "0.53b1" version = "0.53b0"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "deprecated" }, { name = "deprecated" },
{ name = "opentelemetry-api" }, { name = "opentelemetry-api" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/5e/b6/3c56e22e9b51bcb89edab30d54830958f049760bbd9ab0a759cece7bca88/opentelemetry_semantic_conventions-0.53b1.tar.gz", hash = "sha256:4c5a6fede9de61211b2e9fc1e02e8acacce882204cd770177342b6a3be682992", size = 114350 } sdist = { url = "https://files.pythonhosted.org/packages/c2/c4/213d23239df175b420b74c6e25899c482701e6614822dc51f8c20dae7e2d/opentelemetry_semantic_conventions-0.53b0.tar.gz", hash = "sha256:05b7908e1da62d72f9bf717ed25c72f566fe005a2dd260c61b11e025f2552cf6", size = 114343 }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/27/6b/a8fb94760ef8da5ec283e488eb43235eac3ae7514385a51b6accf881e671/opentelemetry_semantic_conventions-0.53b1-py3-none-any.whl", hash = "sha256:21df3ed13f035f8f3ea42d07cbebae37020367a53b47f1ebee3b10a381a00208", size = 188443 }, { url = "https://files.pythonhosted.org/packages/7c/23/0bef11f394f828f910f32567d057f097dbaba23edf33114018a380a0d0bf/opentelemetry_semantic_conventions-0.53b0-py3-none-any.whl", hash = "sha256:561da89f766ab51615c0e72b12329e0a1bc16945dbd62c8646ffc74e36a1edff", size = 188441 },
] ]
[[package]] [[package]]
@ -2243,14 +2243,14 @@ wheels = [
[[package]] [[package]]
name = "prompt-toolkit" name = "prompt-toolkit"
version = "3.0.51" version = "3.0.50"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "wcwidth" }, { name = "wcwidth" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/bb/6e/9d084c929dfe9e3bfe0c6a47e31f78a25c54627d64a66e884a8bf5474f1c/prompt_toolkit-3.0.51.tar.gz", hash = "sha256:931a162e3b27fc90c86f1b48bb1fb2c528c2761475e57c9c06de13311c7b54ed", size = 428940 } sdist = { url = "https://files.pythonhosted.org/packages/a1/e1/bd15cb8ffdcfeeb2bdc215de3c3cffca11408d829e4b8416dcfe71ba8854/prompt_toolkit-3.0.50.tar.gz", hash = "sha256:544748f3860a2623ca5cd6d2795e7a14f3d0e1c3c9728359013f79877fc89bab", size = 429087 }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/ce/4f/5249960887b1fbe561d9ff265496d170b55a735b76724f10ef19f9e40716/prompt_toolkit-3.0.51-py3-none-any.whl", hash = "sha256:52742911fde84e2d423e2f9a4cf1de7d7ac4e51958f648d9540e0fb8db077b07", size = 387810 }, { url = "https://files.pythonhosted.org/packages/e4/ea/d836f008d33151c7a1f62caf3d8dd782e4d15f6a43897f64480c2b8de2ad/prompt_toolkit-3.0.50-py3-none-any.whl", hash = "sha256:9b6427eb19e479d98acff65196a307c555eb567989e6d88ebbb1b509d9779198", size = 387816 },
] ]
[[package]] [[package]]
@ -2321,9 +2321,6 @@ wheels = [
c = [ c = [
{ name = "psycopg-c", marker = "implementation_name != 'pypy'" }, { name = "psycopg-c", marker = "implementation_name != 'pypy'" },
] ]
pool = [
{ name = "psycopg-pool" },
]
[[package]] [[package]]
name = "psycopg-c" name = "psycopg-c"
@ -2331,18 +2328,6 @@ version = "3.2.6"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/2f/f1/367a2429af2b97f6a46dc116206cd3b1cf668fca7ff3c22b979ea0686427/psycopg_c-3.2.6.tar.gz", hash = "sha256:b5fd4ce70f82766a122ca5076a36c4d5818eaa9df9bf76870bc83a064ffaed3a", size = 609304 } sdist = { url = "https://files.pythonhosted.org/packages/2f/f1/367a2429af2b97f6a46dc116206cd3b1cf668fca7ff3c22b979ea0686427/psycopg_c-3.2.6.tar.gz", hash = "sha256:b5fd4ce70f82766a122ca5076a36c4d5818eaa9df9bf76870bc83a064ffaed3a", size = 609304 }
[[package]]
name = "psycopg-pool"
version = "3.2.6"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "typing-extensions" },
]
sdist = { url = "https://files.pythonhosted.org/packages/cf/13/1e7850bb2c69a63267c3dbf37387d3f71a00fd0e2fa55c5db14d64ba1af4/psycopg_pool-3.2.6.tar.gz", hash = "sha256:0f92a7817719517212fbfe2fd58b8c35c1850cdd2a80d36b581ba2085d9148e5", size = 29770 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/47/fd/4feb52a55c1a4bd748f2acaed1903ab54a723c47f6d0242780f4d97104d4/psycopg_pool-3.2.6-py3-none-any.whl", hash = "sha256:5887318a9f6af906d041a0b1dc1c60f8f0dda8340c2572b74e10907b51ed5da7", size = 38252 },
]
[[package]] [[package]]
name = "publication" name = "publication"
version = "0.0.3" version = "0.0.3"
@ -2759,14 +2744,14 @@ wheels = [
[[package]] [[package]]
name = "rsa" name = "rsa"
version = "4.9.1" version = "4.9"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "pyasn1" }, { name = "pyasn1" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/da/8a/22b7beea3ee0d44b1916c0c1cb0ee3af23b700b6da9f04991899d0c555d4/rsa-4.9.1.tar.gz", hash = "sha256:e7bdbfdb5497da4c07dfd35530e1a902659db6ff241e39d9953cad06ebd0ae75", size = 29034 } sdist = { url = "https://files.pythonhosted.org/packages/aa/65/7d973b89c4d2351d7fb232c2e452547ddfa243e93131e7cfa766da627b52/rsa-4.9.tar.gz", hash = "sha256:e38464a49c6c85d7f1351b0126661487a7e0a14a50f1675ec50eb34d4f20ef21", size = 29711 }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/64/8d/0133e4eb4beed9e425d9a98ed6e081a55d195481b7632472be1af08d2f6b/rsa-4.9.1-py3-none-any.whl", hash = "sha256:68635866661c6836b8d39430f97a996acbd61bfa49406748ea243539fe239762", size = 34696 }, { url = "https://files.pythonhosted.org/packages/49/97/fa78e3d2f65c02c8e1268b9aba606569fe97f6c8f7c2d74394553347c145/rsa-4.9-py3-none-any.whl", hash = "sha256:90260d9058e514786967344d0ef75fa8727eed8a7d2e43ce9f4bcf1b536174f7", size = 34315 },
] ]
[[package]] [[package]]
@ -2837,15 +2822,15 @@ wheels = [
[[package]] [[package]]
name = "sentry-sdk" name = "sentry-sdk"
version = "2.26.1" version = "2.25.1"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "certifi" }, { name = "certifi" },
{ name = "urllib3" }, { name = "urllib3" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/85/26/099631caa51abffb1fd9e08c2138bc6681d3f288a5936c2fc4e054729611/sentry_sdk-2.26.1.tar.gz", hash = "sha256:759e019c41551a21519a95e6cef6d91fb4af1054761923dadaee2e6eca9c02c7", size = 323099 } sdist = { url = "https://files.pythonhosted.org/packages/85/2f/a0f732270cc7c1834f5ec45539aec87c360d5483a8bd788217a9102ccfbd/sentry_sdk-2.25.1.tar.gz", hash = "sha256:f9041b7054a7cf12d41eadabe6458ce7c6d6eea7a97cfe1b760b6692e9562cf0", size = 322190 }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/23/32/0a30b4fafdb3d26d133f99bb566aaa6000004ee7f2c4b72aafea9237ab7e/sentry_sdk-2.26.1-py2.py3-none-any.whl", hash = "sha256:e99390e3f217d13ddcbaeaed08789f1ca614d663b345b9da42e35ad6b60d696a", size = 340558 }, { url = "https://files.pythonhosted.org/packages/96/b6/84049ab0967affbc7cc7590d86ae0170c1b494edb69df8786707100420e5/sentry_sdk-2.25.1-py2.py3-none-any.whl", hash = "sha256:60b016d0772789454dc55a284a6a44212044d4a16d9f8448725effee97aaf7f6", size = 339851 },
] ]
[[package]] [[package]]

View File

@ -16,16 +16,16 @@ three contexts in which to run.
The three contexts corresponds to objects in the API's `model` section, so let's use those names. The three contexts corresponds to objects in the API's `model` section, so let's use those names.
- The root `Config`. The root configuration object of the server, containing mostly caching and - The root `Config`. The root configuration object of the server, containing mostly caching and
error reporting information. This is misleading, however; the `Config` object contains some user error reporting information. This is misleading, however; the `Config` object contains some user
information, specifically a list of permissions the current user (or "no user") has. information, specifically a list of permissions the current user (or "no user") has.
- The root `CurrentTenant`. This describes the `Brand` information UIs should use, such as themes, - The root `CurrentTenant`. This describes the `Brand` information UIs should use, such as themes,
logos, favicon, and specific default flows for logging in, logging out, and recovering a user logos, favicon, and specific default flows for logging in, logging out, and recovering a user
password. password.
- The current `SessionUser`, the person logged in: username, display name, and various states. - The current `SessionUser`, the person logged in: username, display name, and various states.
(Note: the authentik server permits administrators to "impersonate" any other user in order to (Note: the authentik server permits administrators to "impersonate" any other user in order to
debug their authentikation experience. If impersonation is active, the `user` field reflects that debug their authentikation experience. If impersonation is active, the `user` field reflects that
user, but it also includes a field, `original`, with the administrator's information.) user, but it also includes a field, `original`, with the administrator's information.)
(There is a fourth context object, Version, but its use is limited to displaying version information (There is a fourth context object, Version, but its use is limited to displaying version information
and checking for upgrades. Just be aware that you will see it, but you will probably never interact and checking for upgrades. Just be aware that you will see it, but you will probably never interact
@ -36,55 +36,55 @@ insides are provided by third-party libraries (Patternfly and Rapidoc, respectiv
three are actual applications. The descriptions below are wholly from the view of the user's three are actual applications. The descriptions below are wholly from the view of the user's
experience: experience:
- `Flow`: From a given URL, displays a form that requests information from the user to accomplish a - `Flow`: From a given URL, displays a form that requests information from the user to accomplish a
task. Some tasks require the user to be logged in, but many (such as logging in itself!) task. Some tasks require the user to be logged in, but many (such as logging in itself!)
obviously do not. obviously do not.
- `User`: Provides the user with access to the applications they can access, plus a few user - `User`: Provides the user with access to the applications they can access, plus a few user
settings. settings.
- `Admin`: Provides someone with super-user permissions access to the administrative functions of - `Admin`: Provides someone with super-user permissions access to the administrative functions of
the authentik server. the authentik server.
**Mental Model** **Mental Model**
- Upon initialization, _every_ authentik UI application fetches `Config` and `CurrentTenant`. `User` - Upon initialization, _every_ authentik UI application fetches `Config` and `CurrentTenant`. `User`
and `Admin` will also attempt to load the `SessionUser`; if there is none, the user is kicked out and `Admin` will also attempt to load the `SessionUser`; if there is none, the user is kicked out
to the `Flow` for logging into authentik itself. to the `Flow` for logging into authentik itself.
- `Config`, `CurrentTenant`, and `SessionUser`, are provided by the `@goauthentik/api` application, - `Config`, `CurrentTenant`, and `SessionUser`, are provided by the `@goauthentik/api` application,
not by the codebase under `./web`. (Where you are now). not by the codebase under `./web`. (Where you are now).
- `Flow`, `User`, and `Admin` are all called `Interfaces` and are found in - `Flow`, `User`, and `Admin` are all called `Interfaces` and are found in
`./web/src/flow/FlowInterface`, `./web/src/user/UserInterface`, `./web/src/admin/AdminInterface`, `./web/src/flow/FlowInterface`, `./web/src/user/UserInterface`, `./web/src/admin/AdminInterface`,
respectively. respectively.
Inside each of these you will find, in a hierarchal order: Inside each of these you will find, in a hierarchal order:
- The context layer described above - The context layer described above
- A theme managing layer - A theme managing layer
- The orchestration layer: - The orchestration layer:
- web socket handler for server-generated events - web socket handler for server-generated events
- The router - The router
- Individual routes for each vertical slice and its relationship to other objects: - Individual routes for each vertical slice and its relationship to other objects:
Each slice corresponds to an object table on the server, and each slice _usually_ consists of the Each slice corresponds to an object table on the server, and each slice _usually_ consists of the
following: following:
- A paginated collection display, usually using the `Table` foundation (found in - A paginated collection display, usually using the `Table` foundation (found in
`./web/src/elements/Table`) `./web/src/elements/Table`)
- The ability to view an individual object from the collection, which you may be able to: - The ability to view an individual object from the collection, which you may be able to:
- Edit - Edit
- Delete - Delete
- A form for creating a new object - A form for creating a new object
- Tabs showing that object's relationship to other objects - Tabs showing that object's relationship to other objects
- Interactive elements for changing or deleting those relationships, or creating new ones. - Interactive elements for changing or deleting those relationships, or creating new ones.
- The ability to create new objects with which to have that relationship, if they're not part of - The ability to create new objects with which to have that relationship, if they're not part of
the core objects (such as User->MFA authenticator apps, since the latter is not a "core" object the core objects (such as User->MFA authenticator apps, since the latter is not a "core" object
and has no tab of its own). and has no tab of its own).
We are still a bit "all over the place" with respect to sub-units and common units; there are We are still a bit "all over the place" with respect to sub-units and common units; there are
folders `common`, `elements`, and `components`, and ideally they would be: folders `common`, `elements`, and `components`, and ideally they would be:
- `common`: non-UI related libraries all of our applications need - `common`: non-UI related libraries all of our applications need
- `elements`: UI elements shared among multiple applications that do not need context - `elements`: UI elements shared among multiple applications that do not need context
- `components`: UI elements shared among multiple that use one or more context - `components`: UI elements shared among multiple that use one or more context
... but at the moment there are some context-sensitive elements, and some UI-related stuff in ... but at the moment there are some context-sensitive elements, and some UI-related stuff in
`common`. `common`.
@ -95,18 +95,18 @@ folders `common`, `elements`, and `components`, and ideally they would be:
reliably documented any other way. For the most part, they contain comments related to custom reliably documented any other way. For the most part, they contain comments related to custom
settings in JSON files, which do not support comments. settings in JSON files, which do not support comments.
- `tsconfig.json`: - `tsconfig.json`:
- `compilerOptions.useDefineForClassFields: false` is required to make TSC use the "classic" form - `compilerOptions.useDefineForClassFields: false` is required to make TSC use the "classic" form
of field definition when compiling class definitions. Storybook does not handle the ESNext of field definition when compiling class definitions. Storybook does not handle the ESNext
proposed definition mechanism (yet). proposed definition mechanism (yet).
- `compilerOptions.plugins.ts-lit-plugin.rules.no-unknown-tag-name: "off"`: required to support - `compilerOptions.plugins.ts-lit-plugin.rules.no-unknown-tag-name: "off"`: required to support
rapidoc, which exports its tag late. rapidoc, which exports its tag late.
- `compilerOptions.plugins.ts-lit-plugin.rules.no-missing-import: "off"`: lit-analyzer currently - `compilerOptions.plugins.ts-lit-plugin.rules.no-missing-import: "off"`: lit-analyzer currently
does not support path aliases very well, and cannot find the definition files associated with does not support path aliases very well, and cannot find the definition files associated with
imports using them. imports using them.
- `compilerOptions.plugins.ts-lit-plugin.rules.no-incompatible-type-binding: "warn"`: lit-analyzer - `compilerOptions.plugins.ts-lit-plugin.rules.no-incompatible-type-binding: "warn"`: lit-analyzer
does not support generics well when parsing a subtype of `HTMLElement`. As a result, this threw does not support generics well when parsing a subtype of `HTMLElement`. As a result, this threw
too many errors to be supportable. too many errors to be supportable.
### License ### License

13262
web/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -12,7 +12,7 @@
"@floating-ui/dom": "^1.6.11", "@floating-ui/dom": "^1.6.11",
"@formatjs/intl-listformat": "^7.5.7", "@formatjs/intl-listformat": "^7.5.7",
"@fortawesome/fontawesome-free": "^6.6.0", "@fortawesome/fontawesome-free": "^6.6.0",
"@goauthentik/api": "^2025.2.4-1744640358", "@goauthentik/api": "^2025.2.4-1744288676",
"@lit-labs/ssr": "^3.2.2", "@lit-labs/ssr": "^3.2.2",
"@lit/context": "^1.1.2", "@lit/context": "^1.1.2",
"@lit/localize": "^0.12.2", "@lit/localize": "^0.12.2",
@ -42,7 +42,7 @@
"lit": "^3.2.0", "lit": "^3.2.0",
"md-front-matter": "^1.0.4", "md-front-matter": "^1.0.4",
"mermaid": "^11.4.1", "mermaid": "^11.4.1",
"rapidoc": "^9.3.8", "rapidoc": "^9.3.7",
"react": "^18.3.1", "react": "^18.3.1",
"react-dom": "^18.3.1", "react-dom": "^18.3.1",
"rehype-highlight": "^7.0.2", "rehype-highlight": "^7.0.2",
@ -128,14 +128,6 @@
"@rollup/rollup-linux-arm64-gnu": "4.23.0", "@rollup/rollup-linux-arm64-gnu": "4.23.0",
"@rollup/rollup-linux-x64-gnu": "4.23.0" "@rollup/rollup-linux-x64-gnu": "4.23.0"
}, },
"overrides": {
"rapidoc": {
"@apitools/openapi-parser@": "0.0.37"
},
"chromedriver": {
"axios": "^1.8.4"
}
},
"private": true, "private": true,
"scripts": { "scripts": {
"build": "wireit", "build": "wireit",

View File

@ -9,11 +9,11 @@ It exists primarily to support late versions of Microsoft Office365 and Microsof
software that still uses the MSEdge-18 and IE-11 _Trident_ web engine for web-based log-ins. It has software that still uses the MSEdge-18 and IE-11 _Trident_ web engine for web-based log-ins. It has
limited support for the full language, supporting only the following stages: limited support for the full language, supporting only the following stages:
- identification - identification
- password - password
- redirect - redirect
- autosubmit - autosubmit
- authenticator validation (both code and WebAuthn) - authenticator validation (both code and WebAuthn)
### License ### License

View File

@ -22,7 +22,6 @@ export default [
"coverage/", "coverage/",
"src/locale-codes.ts", "src/locale-codes.ts",
"storybook-static/", "storybook-static/",
"scripts/esbuild",
"src/locales/", "src/locales/",
], ],
}, },

View File

@ -131,7 +131,6 @@ export class AkAdminSidebar extends WithCapabilitiesConfig(WithVersion(AKElement
["/identity/users", msg("Users"), [`^/identity/users/(?<id>${ID_REGEX})$`]], ["/identity/users", msg("Users"), [`^/identity/users/(?<id>${ID_REGEX})$`]],
["/identity/groups", msg("Groups"), [`^/identity/groups/(?<id>${UUID_REGEX})$`]], ["/identity/groups", msg("Groups"), [`^/identity/groups/(?<id>${UUID_REGEX})$`]],
["/identity/roles", msg("Roles"), [`^/identity/roles/(?<id>${UUID_REGEX})$`]], ["/identity/roles", msg("Roles"), [`^/identity/roles/(?<id>${UUID_REGEX})$`]],
["/identity/initial-permissions", msg("Initial Permissions"), [`^/identity/initial-permissions/(?<id>${ID_REGEX})$`]],
["/core/sources", msg("Federation and Social login"), [`^/core/sources/(?<slug>${SLUG_REGEX})$`]], ["/core/sources", msg("Federation and Social login"), [`^/core/sources/(?<slug>${SLUG_REGEX})$`]],
["/core/tokens", msg("Tokens and App passwords")], ["/core/tokens", msg("Tokens and App passwords")],
["/flow/stages/invitations", msg("Invitations")]]], ["/flow/stages/invitations", msg("Invitations")]]],

View File

@ -84,10 +84,6 @@ export const ROUTES: Route[] = [
await import("@goauthentik/admin/roles/RoleListPage"); await import("@goauthentik/admin/roles/RoleListPage");
return html`<ak-role-list></ak-role-list>`; return html`<ak-role-list></ak-role-list>`;
}), }),
new Route(new RegExp("^/identity/initial-permissions$"), async () => {
await import("@goauthentik/admin/rbac/InitialPermissionsListPage");
return html`<ak-initial-permissions-list></ak-initial-permissions-list>`;
}),
new Route(new RegExp(`^/identity/roles/(?<id>${UUID_REGEX})$`), async (args) => { new Route(new RegExp(`^/identity/roles/(?<id>${UUID_REGEX})$`), async (args) => {
await import("@goauthentik/admin/roles/RoleViewPage"); await import("@goauthentik/admin/roles/RoleViewPage");
return html`<ak-role-view roleId=${args.id}></ak-role-view>`; return html`<ak-role-view roleId=${args.id}></ak-role-view>`;

View File

@ -15,7 +15,9 @@ export const bindModeOptions = [
{ {
label: msg("Direct binding"), label: msg("Direct binding"),
value: LDAPAPIAccessMode.Direct, value: LDAPAPIAccessMode.Direct,
description: html`${msg("Always execute the configured bind flow to authenticate the user")}`, description: html`${msg(
"Always execute the configured bind flow to authenticate the user",
)}`,
}, },
]; ];
@ -31,7 +33,9 @@ export const searchModeOptions = [
{ {
label: msg("Direct querying"), label: msg("Direct querying"),
value: LDAPAPIAccessMode.Direct, value: LDAPAPIAccessMode.Direct,
description: html`${msg("Always returns the latest data, but slower than cached querying")}`, description: html`${msg(
"Always returns the latest data, but slower than cached querying",
)}`,
}, },
]; ];

View File

@ -1,150 +0,0 @@
import { InitialPermissionsModeToLabel } from "@goauthentik/admin/rbac/utils";
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import "@goauthentik/elements/ak-dual-select/ak-dual-select-provider";
import { DataProvision, DualSelectPair } from "@goauthentik/elements/ak-dual-select/types";
import "@goauthentik/elements/chips/Chip";
import "@goauthentik/elements/chips/ChipGroup";
import "@goauthentik/elements/forms/HorizontalFormElement";
import { ModelForm } from "@goauthentik/elements/forms/ModelForm";
import "@goauthentik/elements/forms/SearchSelect";
import { msg } from "@lit/localize";
import { TemplateResult, html } from "lit";
import { customElement } from "lit/decorators.js";
import { ifDefined } from "lit/directives/if-defined.js";
import {
InitialPermissions,
InitialPermissionsModeEnum,
Permission,
RbacApi,
RbacRolesListRequest,
Role,
} from "@goauthentik/api";
export function rbacPermissionPair(item: Permission): DualSelectPair {
return [item.id.toString(), html`<div class="selection-main">${item.name}</div>`, item.name];
}
@customElement("ak-initial-permissions-form")
export class InitialPermissionsForm extends ModelForm<InitialPermissions, string> {
loadInstance(pk: string): Promise<InitialPermissions> {
return new RbacApi(DEFAULT_CONFIG).rbacInitialPermissionsRetrieve({
id: Number(pk),
});
}
getSuccessMessage(): string {
return this.instance
? msg("Successfully updated initial permissions.")
: msg("Successfully created initial permissions.");
}
async send(data: InitialPermissions): Promise<InitialPermissions> {
if (this.instance?.pk) {
return new RbacApi(DEFAULT_CONFIG).rbacInitialPermissionsPartialUpdate({
id: this.instance.pk,
patchedInitialPermissionsRequest: data,
});
} else {
return new RbacApi(DEFAULT_CONFIG).rbacInitialPermissionsCreate({
initialPermissionsRequest: data,
});
}
}
renderForm(): TemplateResult {
return html`<form class="pf-c-form pf-m-horizontal">
<ak-form-element-horizontal label=${msg("Name")} required name="name">
<input
type="text"
value="${ifDefined(this.instance?.name)}"
class="pf-c-form-control"
required
/>
</ak-form-element-horizontal>
<ak-form-element-horizontal label=${msg("Role")} required name="role">
<ak-search-select
.fetchObjects=${async (query?: string): Promise<Role[]> => {
const args: RbacRolesListRequest = {
ordering: "name",
};
if (query !== undefined) {
args.search = query;
}
const users = await new RbacApi(DEFAULT_CONFIG).rbacRolesList(args);
return users.results;
}}
.renderElement=${(role: Role): string => {
return role.name;
}}
.renderDescription=${(role: Role): TemplateResult => {
return html`${role.name}`;
}}
.value=${(role: Role | undefined): string | undefined => {
return role?.pk;
}}
.selected=${(role: Role): boolean => {
return this.instance?.role === role.pk;
}}
>
</ak-search-select>
<p class="pf-c-form__helper-text">
${msg(
"When a user with the selected Role creates an object, the Initial Permissions will be applied to that object.",
)}
</p>
</ak-form-element-horizontal>
<ak-form-element-horizontal label=${msg("Mode")} required name="mode">
<select class="pf-c-form-control">
<option
value=${InitialPermissionsModeEnum.User}
?selected=${this.instance?.mode === InitialPermissionsModeEnum.User}
>
${InitialPermissionsModeToLabel(InitialPermissionsModeEnum.User)}
</option>
<option
value=${InitialPermissionsModeEnum.Role}
?selected=${this.instance?.mode === InitialPermissionsModeEnum.Role}
>
${InitialPermissionsModeToLabel(InitialPermissionsModeEnum.Role)}
</option>
</select>
<p class="pf-c-form__helper-text">
${msg(
"The Initial Permissions can either be placed on the User creating the object, or the Role selected in the previous field.",
)}
</p>
</ak-form-element-horizontal>
<ak-form-element-horizontal label=${msg("Permissions")} name="permissions">
<ak-dual-select-provider
.provider=${(page: number, search?: string): Promise<DataProvision> => {
return new RbacApi(DEFAULT_CONFIG)
.rbacPermissionsList({
page: page,
search: search,
})
.then((results) => {
return {
pagination: results.pagination,
options: results.results.map(rbacPermissionPair),
};
});
}}
.selected=${(this.instance?.permissionsObj ?? []).map(rbacPermissionPair)}
available-label="${msg("Available Permissions")}"
selected-label="${msg("Selected Permissions")}"
></ak-dual-select-provider>
<p class="pf-c-form__helper-text">
${msg("Permissions to grant when a new object is created.")}
</p>
</ak-form-element-horizontal>
</form>`;
}
}
declare global {
interface HTMLElementTagNameMap {
"ak-initial-permissions-form": InitialPermissionsForm;
}
}

View File

@ -1,115 +0,0 @@
import "@goauthentik/admin/rbac/InitialPermissionsForm";
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import "@goauthentik/elements/buttons/SpinnerButton";
import "@goauthentik/elements/forms/DeleteBulkForm";
import "@goauthentik/elements/forms/ModalForm";
import { PaginatedResponse } from "@goauthentik/elements/table/Table";
import { TableColumn } from "@goauthentik/elements/table/Table";
import { TablePage } from "@goauthentik/elements/table/TablePage";
import "@patternfly/elements/pf-tooltip/pf-tooltip.js";
import { msg } from "@lit/localize";
import { TemplateResult, html } from "lit";
import { customElement, property } from "lit/decorators.js";
import { ifDefined } from "lit/directives/if-defined.js";
import { InitialPermissions, RbacApi } from "@goauthentik/api";
@customElement("ak-initial-permissions-list")
export class InitialPermissionsListPage extends TablePage<InitialPermissions> {
checkbox = true;
clearOnRefresh = true;
searchEnabled(): boolean {
return true;
}
pageTitle(): string {
return msg("Initial Permissions");
}
pageDescription(): string {
return msg("Set initial permissions for newly created objects.");
}
pageIcon(): string {
return "fa fa-lock";
}
@property()
order = "name";
async apiEndpoint(): Promise<PaginatedResponse<InitialPermissions>> {
return new RbacApi(DEFAULT_CONFIG).rbacInitialPermissionsList(
await this.defaultEndpointConfig(),
);
}
columns(): TableColumn[] {
return [new TableColumn(msg("Name"), "name"), new TableColumn(msg("Actions"))];
}
renderToolbarSelected(): TemplateResult {
const disabled = this.selectedElements.length < 1;
return html`<ak-forms-delete-bulk
objectLabel=${msg("Initial Permissions")}
.objects=${this.selectedElements}
.usedBy=${(item: InitialPermissions) => {
return new RbacApi(DEFAULT_CONFIG).rbacInitialPermissionsUsedByList({
id: item.pk,
});
}}
.delete=${(item: InitialPermissions) => {
return new RbacApi(DEFAULT_CONFIG).rbacInitialPermissionsDestroy({
id: item.pk,
});
}}
>
<button ?disabled=${disabled} slot="trigger" class="pf-c-button pf-m-danger">
${msg("Delete")}
</button>
</ak-forms-delete-bulk>`;
}
render(): TemplateResult {
return html`<ak-page-header
icon=${this.pageIcon()}
header=${this.pageTitle()}
description=${ifDefined(this.pageDescription())}
>
</ak-page-header>
<section class="pf-c-page__main-section pf-m-no-padding-mobile">
<div class="pf-c-card">${this.renderTable()}</div>
</section>`;
}
row(item: InitialPermissions): TemplateResult[] {
return [
html`${item.name}`,
html`<ak-forms-modal>
<span slot="submit"> ${msg("Update")} </span>
<span slot="header"> ${msg("Update Initial Permissions")} </span>
<ak-initial-permissions-form slot="form" .instancePk=${item.pk}>
</ak-initial-permissions-form>
<button slot="trigger" class="pf-c-button pf-m-plain">
<pf-tooltip position="top" content=${msg("Edit")}>
<i class="fas fa-edit"></i>
</pf-tooltip>
</button>
</ak-forms-modal>`,
];
}
renderObjectCreate(): TemplateResult {
return html`
<ak-forms-modal>
<span slot="submit"> ${msg("Create")} </span>
<span slot="header"> ${msg("Create Initial Permissions")} </span>
<ak-initial-permissions-form slot="form"> </ak-initial-permissions-form>
<button slot="trigger" class="pf-c-button pf-m-primary">${msg("Create")}</button>
</ak-forms-modal>
`;
}
}
declare global {
interface HTMLElementTagNameMap {
"initial-permissions-list": InitialPermissionsListPage;
}
}

View File

@ -1,14 +0,0 @@
import { msg } from "@lit/localize";
import { InitialPermissionsModeEnum } from "@goauthentik/api";
export function InitialPermissionsModeToLabel(mode: InitialPermissionsModeEnum): string {
switch (mode) {
case InitialPermissionsModeEnum.User:
return msg("User");
case InitialPermissionsModeEnum.Role:
return msg("Role");
case InitialPermissionsModeEnum.UnknownDefaultOpenApi:
return msg("Unknown Initial Permissions mode");
}
}

View File

@ -7,7 +7,6 @@ import {
} from "@goauthentik/admin/sources/oauth/utils"; } from "@goauthentik/admin/sources/oauth/utils";
import { DEFAULT_CONFIG, config } from "@goauthentik/common/api/config"; import { DEFAULT_CONFIG, config } from "@goauthentik/common/api/config";
import { first } from "@goauthentik/common/utils"; import { first } from "@goauthentik/common/utils";
import "@goauthentik/components/ak-radio-input";
import "@goauthentik/elements/CodeMirror"; import "@goauthentik/elements/CodeMirror";
import { CodeMirrorMode } from "@goauthentik/elements/CodeMirror"; import { CodeMirrorMode } from "@goauthentik/elements/CodeMirror";
import { import {
@ -17,7 +16,6 @@ import {
import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js"; import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.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/Radio";
import "@goauthentik/elements/forms/SearchSelect"; import "@goauthentik/elements/forms/SearchSelect";
import { msg } from "@lit/localize"; import { msg } from "@lit/localize";
@ -26,7 +24,6 @@ import { customElement, property, state } from "lit/decorators.js";
import { ifDefined } from "lit/directives/if-defined.js"; import { ifDefined } from "lit/directives/if-defined.js";
import { import {
AuthorizationCodeAuthMethodEnum,
FlowsInstancesListDesignationEnum, FlowsInstancesListDesignationEnum,
GroupMatchingModeEnum, GroupMatchingModeEnum,
OAuthSource, OAuthSource,
@ -39,18 +36,6 @@ import {
import { propertyMappingsProvider, propertyMappingsSelector } from "./OAuthSourceFormHelpers.js"; import { propertyMappingsProvider, propertyMappingsSelector } from "./OAuthSourceFormHelpers.js";
const authorizationCodeAuthMethodOptions = [
{
label: msg("HTTP Basic Auth"),
value: AuthorizationCodeAuthMethodEnum.BasicAuth,
default: true,
},
{
label: msg("Include the client ID and secret as request parameters"),
value: AuthorizationCodeAuthMethodEnum.PostBody,
},
];
@customElement("ak-source-oauth-form") @customElement("ak-source-oauth-form")
export class OAuthSourceForm extends WithCapabilitiesConfig(BaseSourceForm<OAuthSource>) { export class OAuthSourceForm extends WithCapabilitiesConfig(BaseSourceForm<OAuthSource>) {
async loadInstance(pk: string): Promise<OAuthSource> { async loadInstance(pk: string): Promise<OAuthSource> {
@ -255,19 +240,6 @@ export class OAuthSourceForm extends WithCapabilitiesConfig(BaseSourceForm<OAuth
<p class="pf-c-form__helper-text">${msg("Raw JWKS data.")}</p> <p class="pf-c-form__helper-text">${msg("Raw JWKS data.")}</p>
</ak-form-element-horizontal>` </ak-form-element-horizontal>`
: html``} : html``}
${this.providerType.name === ProviderTypeEnum.Openidconnect
? html`<ak-radio-input
label=${msg("Authorization code authentication method")}
name="authorizationCodeAuthMethod"
required
.options=${authorizationCodeAuthMethodOptions}
.value=${this.instance?.authorizationCodeAuthMethod}
help=${msg(
"How to perform authentication during an authorization_code token request flow",
)}
>
</ak-radio-input>`
: html``}
</div> </div>
</ak-form-group>`; </ak-form-group>`;
} }

View File

@ -2,7 +2,6 @@ import "@goauthentik/admin/common/ak-flow-search/ak-flow-search";
import { BaseStageForm } from "@goauthentik/admin/stages/BaseStageForm"; import { BaseStageForm } from "@goauthentik/admin/stages/BaseStageForm";
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { first, groupBy } from "@goauthentik/common/utils"; import { first, groupBy } from "@goauthentik/common/utils";
import "@goauthentik/components/ak-switch-input.js";
import "@goauthentik/elements/ak-checkbox-group/ak-checkbox-group.js"; import "@goauthentik/elements/ak-checkbox-group/ak-checkbox-group.js";
import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js"; import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js";
import "@goauthentik/elements/forms/FormGroup"; import "@goauthentik/elements/forms/FormGroup";
@ -159,38 +158,68 @@ export class IdentificationStageForm extends BaseStageForm<IdentificationStage>
)} )}
</p> </p>
</ak-form-element-horizontal> </ak-form-element-horizontal>
<ak-switch-input <ak-form-element-horizontal name="caseInsensitiveMatching">
name="caseInsensitiveMatching" <label class="pf-c-switch">
label=${msg("Case insensitive matching")} <input
?checked=${first(this.instance?.caseInsensitiveMatching, true)} class="pf-c-switch__input"
help=${msg( type="checkbox"
"When enabled, user fields are matched regardless of their casing.", ?checked=${first(this.instance?.caseInsensitiveMatching, true)}
)} />
></ak-switch-input> <span class="pf-c-switch__toggle">
<ak-switch-input <span class="pf-c-switch__toggle-icon">
name="pretendUserExists" <i class="fas fa-check" aria-hidden="true"></i>
label=${msg("Pretend user exists")} </span>
?checked=${first(this.instance?.pretendUserExists, true)} </span>
help=${msg( <span class="pf-c-switch__label"
"When enabled, the stage will always accept the given user identifier and continue.", >${msg("Case insensitive matching")}</span
)} >
></ak-switch-input> </label>
<ak-switch-input <p class="pf-c-form__helper-text">
name="showMatchedUser" ${msg(
label=${msg("Show matched user")} "When enabled, user fields are matched regardless of their casing.",
?checked=${first(this.instance?.showMatchedUser, true)} )}
help=${msg( </p>
"When a valid username/email has been entered, and this option is enabled, the user's username and avatar will be shown. Otherwise, the text that the user entered will be shown.", </ak-form-element-horizontal>
)} <ak-form-element-horizontal name="pretendUserExists">
></ak-switch-input> <label class="pf-c-switch">
<ak-switch-input <input
name="enableRememberMe" class="pf-c-switch__input"
label=${msg('Enable "Remember me on this device"')} type="checkbox"
?checked=${this.instance?.enableRememberMe} ?checked=${first(this.instance?.pretendUserExists, true)}
help=${msg( />
"When enabled, the user can save their username in a cookie, allowing them to skip directly to entering their password.", <span class="pf-c-switch__toggle">
)} <span class="pf-c-switch__toggle-icon">
></ak-switch-input> <i class="fas fa-check" aria-hidden="true"></i>
</span>
</span>
<span class="pf-c-switch__label">${msg("Pretend user exists")}</span>
</label>
<p class="pf-c-form__helper-text">
${msg(
"When enabled, the stage will always accept the given user identifier and continue.",
)}
</p>
</ak-form-element-horizontal>
<ak-form-element-horizontal name="showMatchedUser">
<label class="pf-c-switch">
<input
class="pf-c-switch__input"
type="checkbox"
?checked=${first(this.instance?.showMatchedUser, true)}
/>
<span class="pf-c-switch__toggle">
<span class="pf-c-switch__toggle-icon">
<i class="fas fa-check" aria-hidden="true"></i>
</span>
</span>
<span class="pf-c-switch__label">${msg("Show matched user")}</span>
</label>
<p class="pf-c-form__helper-text">
${msg(
"When a valid username/email has been entered, and this option is enabled, the user's username and avatar will be shown. Otherwise, the text that the user entered will be shown.",
)}
</p>
</ak-form-element-horizontal>
</div> </div>
</ak-form-group> </ak-form-group>
<ak-form-group> <ak-form-group>

View File

@ -1,5 +1,4 @@
import { import {
CSRFHeaderName,
CSRFMiddleware, CSRFMiddleware,
EventMiddleware, EventMiddleware,
LoggingMiddleware, LoggingMiddleware,
@ -9,10 +8,6 @@ import { globalAK } from "@goauthentik/common/global";
import { Config, Configuration, CoreApi, CurrentBrand, RootApi } from "@goauthentik/api"; import { Config, Configuration, CoreApi, CurrentBrand, RootApi } from "@goauthentik/api";
// HACK: Workaround for ESBuild not being able to hoist import statement across entrypoints.
// This can be removed after ESBuild uses a single build context for all entrypoints.
export { CSRFHeaderName };
let globalConfigPromise: Promise<Config> | undefined = Promise.resolve(globalAK().config); let globalConfigPromise: Promise<Config> | undefined = Promise.resolve(globalAK().config);
export function config(): Promise<Config> { export function config(): Promise<Config> {
if (!globalConfigPromise) { if (!globalConfigPromise) {

View File

@ -5,7 +5,6 @@ import "@goauthentik/elements/forms/FormElement";
import "@goauthentik/flow/components/ak-flow-password-input.js"; import "@goauthentik/flow/components/ak-flow-password-input.js";
import { BaseStage } from "@goauthentik/flow/stages/base"; import { BaseStage } from "@goauthentik/flow/stages/base";
import "@goauthentik/flow/stages/captcha/CaptchaStage"; import "@goauthentik/flow/stages/captcha/CaptchaStage";
import { AkRememberMeController } from "@goauthentik/flow/stages/identification/RememberMeController.js";
import { msg, str } from "@lit/localize"; import { msg, str } from "@lit/localize";
import { CSSResult, PropertyValues, TemplateResult, css, html, nothing } from "lit"; import { CSSResult, PropertyValues, TemplateResult, css, html, nothing } from "lit";
@ -48,8 +47,6 @@ export class IdentificationStage extends BaseStage<
> { > {
form?: HTMLFormElement; form?: HTMLFormElement;
rememberMe: AkRememberMeController;
@state() @state()
captchaToken = ""; captchaToken = "";
@state() @state()
@ -65,9 +62,8 @@ export class IdentificationStage extends BaseStage<
PFFormControl, PFFormControl,
PFTitle, PFTitle,
PFButton, PFButton,
AkRememberMeController.styles, /* login page's icons */
css` css`
/* login page's icons */
.pf-c-login__main-footer-links-item button { .pf-c-login__main-footer-links-item button {
background-color: transparent; background-color: transparent;
border: 0; border: 0;
@ -85,11 +81,6 @@ export class IdentificationStage extends BaseStage<
]; ];
} }
constructor() {
super();
this.rememberMe = new AkRememberMeController(this);
}
updated(changedProperties: PropertyValues<this>) { updated(changedProperties: PropertyValues<this>) {
if (changedProperties.has("challenge") && this.challenge !== undefined) { if (changedProperties.has("challenge") && this.challenge !== undefined) {
this.autoRedirect(); this.autoRedirect();
@ -277,10 +268,8 @@ export class IdentificationStage extends BaseStage<
autocomplete="username" autocomplete="username"
spellcheck="false" spellcheck="false"
class="pf-c-form-control" class="pf-c-form-control"
value=${this.rememberMe?.username ?? ""}
required required
/> />
${this.rememberMe.render()}
</ak-form-element> </ak-form-element>
${this.challenge.passwordFields ${this.challenge.passwordFields
? html` ? html`

View File

@ -1,156 +0,0 @@
import { getCookie } from "@goauthentik/common/utils.js";
import { msg } from "@lit/localize";
import { css, html, nothing } from "lit";
import { ReactiveController, ReactiveControllerHost } from "lit";
import type { IdentificationStage } from "./IdentificationStage.js";
type RememberMeHost = ReactiveControllerHost & IdentificationStage;
export class AkRememberMeController implements ReactiveController {
static get styles() {
return css`
.remember-me-switch {
display: inline-block;
padding-top: 0.25rem;
}
`;
}
username?: string;
rememberingUsername: boolean = false;
constructor(private host: RememberMeHost) {
this.trackRememberMe = this.trackRememberMe.bind(this);
this.toggleRememberMe = this.toggleRememberMe.bind(this);
this.host.addController(this);
}
// Record a stable token that we can use between requests to track if we've
// been here before. If we can't, clear out the username.
hostConnected() {
try {
const sessionId = localStorage.getItem("authentik-remember-me-session");
if (!!this.localSession && sessionId === this.localSession) {
this.username = undefined;
localStorage?.removeItem("authentik-remember-me-user");
}
localStorage?.setItem("authentik-remember-me-session", this.localSession);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (_e: any) {
this.username = undefined;
}
}
get localSession() {
return (getCookie("authentik_csrf") ?? "").substring(0, 8);
}
get usernameField() {
return this.host.renderRoot.querySelector(
'input[name="uidField"]',
) as HTMLInputElement | null;
}
get rememberMeToggle() {
return this.host.renderRoot.querySelector(
"#authentik-remember-me",
) as HTMLInputElement | null;
}
get isValidChallenge() {
return !(
this.host.challenge.responseErrors &&
this.host.challenge.responseErrors.non_field_errors &&
this.host.challenge.responseErrors.non_field_errors.find(
(cre) => cre.code === "invalid",
)
);
}
get submitButton() {
return this.host.renderRoot.querySelector('button[type="submit"]') as HTMLButtonElement;
}
get isEnabled() {
return (
this.host.challenge !== undefined &&
this.host.challenge.enableRememberMe &&
typeof localStorage !== "undefined"
);
}
get canAutoSubmit() {
return (
!!this.host.challenge &&
!!this.username &&
!!this.usernameField?.value &&
!this.host.challenge.passwordFields &&
!this.host.challenge.passwordlessUrl
);
}
// Before the page is updated, try to extract the username from localstorage.
hostUpdate() {
if (!this.isEnabled) {
return;
}
try {
this.username = localStorage.getItem("authentik-remember-me-user") || undefined;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (_e: any) {
this.username = undefined;
}
}
// After the page is updated, if everything is ready to go, do the autosubmit.
hostUpdated() {
if (this.isEnabled && this.canAutoSubmit) {
this.submitButton?.click();
}
}
trackRememberMe() {
if (!this.usernameField || this.usernameField.value === undefined) {
return;
}
this.username = this.usernameField.value;
localStorage?.setItem("authentik-remember-me-user", this.username);
}
// When active, save current details and record every keystroke to the username.
// When inactive, clear all fields and remove keystroke recorder.
toggleRememberMe() {
if (!this.rememberMeToggle || !this.rememberMeToggle.checked) {
localStorage?.removeItem("authentik-remember-me-user");
localStorage?.removeItem("authentik-remember-me-session");
this.username = undefined;
this.usernameField?.removeEventListener("keyup", this.trackRememberMe);
return;
}
if (!this.usernameField) {
return;
}
localStorage?.setItem("authentik-remember-me-user", this.usernameField.value);
localStorage?.setItem("authentik-remember-me-session", this.localSession);
this.usernameField.addEventListener("keyup", this.trackRememberMe);
}
render() {
return this.isEnabled
? html` <label class="pf-c-switch remember-me-switch">
<input
class="pf-c-switch__input"
id="authentik-remember-me"
@click=${this.toggleRememberMe}
type="checkbox"
?checked=${!!this.username}
/>
<span class="pf-c-form__label">${msg("Remember me on this device")}</span>
</label>`
: nothing;
}
}

View File

@ -1,7 +1,4 @@
// sort-imports-ignore import { CSRFHeaderName } from "@goauthentik/common/api/middleware";
import "rapidoc";
import { CSRFHeaderName } from "@goauthentik/common/api/config";
import { EVENT_THEME_CHANGE } from "@goauthentik/common/constants"; import { EVENT_THEME_CHANGE } from "@goauthentik/common/constants";
import { globalAK } from "@goauthentik/common/global"; import { globalAK } from "@goauthentik/common/global";
import { first, getCookie } from "@goauthentik/common/utils"; import { first, getCookie } from "@goauthentik/common/utils";
@ -9,6 +6,7 @@ import { Interface } from "@goauthentik/elements/Interface";
import "@goauthentik/elements/ak-locale-context"; import "@goauthentik/elements/ak-locale-context";
import { DefaultBrand } from "@goauthentik/elements/sidebar/SidebarBrand"; import { DefaultBrand } from "@goauthentik/elements/sidebar/SidebarBrand";
import { themeImage } from "@goauthentik/elements/utils/images"; import { themeImage } from "@goauthentik/elements/utils/images";
import "rapidoc";
import { msg } from "@lit/localize"; import { msg } from "@lit/localize";
import { CSSResult, TemplateResult, css, html } from "lit"; import { CSSResult, TemplateResult, css, html } from "lit";

View File

@ -9086,66 +9086,6 @@ Bindings to groups/users are checked against the user of the event.</source>
</trans-unit> </trans-unit>
<trans-unit id="s17359123e1f24504"> <trans-unit id="s17359123e1f24504">
<source>Field which contains DNs of groups the user is a member of. This field is used to lookup groups from users, e.g. 'memberOf'. To lookup nested groups in an Active Directory environment use 'memberOf:1.2.840.113556.1.4.1941:'.</source> <source>Field which contains DNs of groups the user is a member of. This field is used to lookup groups from users, e.g. 'memberOf'. To lookup nested groups in an Active Directory environment use 'memberOf:1.2.840.113556.1.4.1941:'.</source>
</trans-unit>
<trans-unit id="s891cd64acabf23bf">
<source>Initial Permissions</source>
</trans-unit>
<trans-unit id="sedb57bf4b42a8e40">
<source>Unknown Initial Permissions mode</source>
</trans-unit>
<trans-unit id="s6ea6a64acb45dfdf">
<source>Successfully updated initial permissions.</source>
</trans-unit>
<trans-unit id="sfddf7896ab5938b6">
<source>Successfully created initial permissions.</source>
</trans-unit>
<trans-unit id="s5c5f240cbb6d0bae">
<source>When a user with the selected Role creates an object, the Initial Permissions will be applied to that object.</source>
</trans-unit>
<trans-unit id="sbf27294eef56ac81">
<source>The Initial Permissions can either be placed on the User creating the object, or the Role selected in the previous field.</source>
</trans-unit>
<trans-unit id="s93f04537efda1b24">
<source>Available Permissions</source>
</trans-unit>
<trans-unit id="s297bc57f9e494470">
<source>Selected Permissions</source>
</trans-unit>
<trans-unit id="s0ea71d53764d781c">
<source>Permissions to grant when a new object is created.</source>
</trans-unit>
<trans-unit id="s06fc21a40f5d7de1">
<source>Set initial permissions for newly created objects.</source>
</trans-unit>
<trans-unit id="sc7104a4d0fc35c7c">
<source>Update Initial Permissions</source>
</trans-unit>
<trans-unit id="s83fa005829a65be9">
<source>Create Initial Permissions</source>
</trans-unit>
<trans-unit id="se37ac6cf9c72f21a">
<source>Reputation: lower limit</source>
</trans-unit>
<trans-unit id="sa634ffa797037aac">
<source>Reputation cannot decrease lower than this value. Zero or negative.</source>
</trans-unit>
<trans-unit id="s862986ce8e70edd7">
<source>Reputation: upper limit</source>
</trans-unit>
<trans-unit id="sdd04913b3b46cf30">
<source>Reputation cannot increase higher than this value. Zero or positive.</source>
</trans-unit>
<trans-unit id="s4d5cb134999b50df">
<source>HTTP Basic Auth</source>
</trans-unit>
<trans-unit id="s6927635d1c339cfc">
<source>Include the client ID and secret as request parameters</source>
</trans-unit>
<trans-unit id="s4fca384c634e1a92">
<source>Authorization code authentication method</source>
</trans-unit>
<trans-unit id="sdc02c276ed429008">
<source>How to perform authentication during an authorization_code token request flow</source>
</trans-unit> </trans-unit>
</body> </body>
</file> </file>

View File

@ -7619,66 +7619,6 @@ Bindings to groups/users are checked against the user of the event.</source>
</trans-unit> </trans-unit>
<trans-unit id="s17359123e1f24504"> <trans-unit id="s17359123e1f24504">
<source>Field which contains DNs of groups the user is a member of. This field is used to lookup groups from users, e.g. 'memberOf'. To lookup nested groups in an Active Directory environment use 'memberOf:1.2.840.113556.1.4.1941:'.</source> <source>Field which contains DNs of groups the user is a member of. This field is used to lookup groups from users, e.g. 'memberOf'. To lookup nested groups in an Active Directory environment use 'memberOf:1.2.840.113556.1.4.1941:'.</source>
</trans-unit>
<trans-unit id="s891cd64acabf23bf">
<source>Initial Permissions</source>
</trans-unit>
<trans-unit id="sedb57bf4b42a8e40">
<source>Unknown Initial Permissions mode</source>
</trans-unit>
<trans-unit id="s6ea6a64acb45dfdf">
<source>Successfully updated initial permissions.</source>
</trans-unit>
<trans-unit id="sfddf7896ab5938b6">
<source>Successfully created initial permissions.</source>
</trans-unit>
<trans-unit id="s5c5f240cbb6d0bae">
<source>When a user with the selected Role creates an object, the Initial Permissions will be applied to that object.</source>
</trans-unit>
<trans-unit id="sbf27294eef56ac81">
<source>The Initial Permissions can either be placed on the User creating the object, or the Role selected in the previous field.</source>
</trans-unit>
<trans-unit id="s93f04537efda1b24">
<source>Available Permissions</source>
</trans-unit>
<trans-unit id="s297bc57f9e494470">
<source>Selected Permissions</source>
</trans-unit>
<trans-unit id="s0ea71d53764d781c">
<source>Permissions to grant when a new object is created.</source>
</trans-unit>
<trans-unit id="s06fc21a40f5d7de1">
<source>Set initial permissions for newly created objects.</source>
</trans-unit>
<trans-unit id="sc7104a4d0fc35c7c">
<source>Update Initial Permissions</source>
</trans-unit>
<trans-unit id="s83fa005829a65be9">
<source>Create Initial Permissions</source>
</trans-unit>
<trans-unit id="se37ac6cf9c72f21a">
<source>Reputation: lower limit</source>
</trans-unit>
<trans-unit id="sa634ffa797037aac">
<source>Reputation cannot decrease lower than this value. Zero or negative.</source>
</trans-unit>
<trans-unit id="s862986ce8e70edd7">
<source>Reputation: upper limit</source>
</trans-unit>
<trans-unit id="sdd04913b3b46cf30">
<source>Reputation cannot increase higher than this value. Zero or positive.</source>
</trans-unit>
<trans-unit id="s4d5cb134999b50df">
<source>HTTP Basic Auth</source>
</trans-unit>
<trans-unit id="s6927635d1c339cfc">
<source>Include the client ID and secret as request parameters</source>
</trans-unit>
<trans-unit id="s4fca384c634e1a92">
<source>Authorization code authentication method</source>
</trans-unit>
<trans-unit id="sdc02c276ed429008">
<source>How to perform authentication during an authorization_code token request flow</source>
</trans-unit> </trans-unit>
</body> </body>
</file> </file>

View File

@ -9178,66 +9178,6 @@ Las vinculaciones a grupos o usuarios se comparan con el usuario del evento.</ta
</trans-unit> </trans-unit>
<trans-unit id="s17359123e1f24504"> <trans-unit id="s17359123e1f24504">
<source>Field which contains DNs of groups the user is a member of. This field is used to lookup groups from users, e.g. 'memberOf'. To lookup nested groups in an Active Directory environment use 'memberOf:1.2.840.113556.1.4.1941:'.</source> <source>Field which contains DNs of groups the user is a member of. This field is used to lookup groups from users, e.g. 'memberOf'. To lookup nested groups in an Active Directory environment use 'memberOf:1.2.840.113556.1.4.1941:'.</source>
</trans-unit>
<trans-unit id="s891cd64acabf23bf">
<source>Initial Permissions</source>
</trans-unit>
<trans-unit id="sedb57bf4b42a8e40">
<source>Unknown Initial Permissions mode</source>
</trans-unit>
<trans-unit id="s6ea6a64acb45dfdf">
<source>Successfully updated initial permissions.</source>
</trans-unit>
<trans-unit id="sfddf7896ab5938b6">
<source>Successfully created initial permissions.</source>
</trans-unit>
<trans-unit id="s5c5f240cbb6d0bae">
<source>When a user with the selected Role creates an object, the Initial Permissions will be applied to that object.</source>
</trans-unit>
<trans-unit id="sbf27294eef56ac81">
<source>The Initial Permissions can either be placed on the User creating the object, or the Role selected in the previous field.</source>
</trans-unit>
<trans-unit id="s93f04537efda1b24">
<source>Available Permissions</source>
</trans-unit>
<trans-unit id="s297bc57f9e494470">
<source>Selected Permissions</source>
</trans-unit>
<trans-unit id="s0ea71d53764d781c">
<source>Permissions to grant when a new object is created.</source>
</trans-unit>
<trans-unit id="s06fc21a40f5d7de1">
<source>Set initial permissions for newly created objects.</source>
</trans-unit>
<trans-unit id="sc7104a4d0fc35c7c">
<source>Update Initial Permissions</source>
</trans-unit>
<trans-unit id="s83fa005829a65be9">
<source>Create Initial Permissions</source>
</trans-unit>
<trans-unit id="se37ac6cf9c72f21a">
<source>Reputation: lower limit</source>
</trans-unit>
<trans-unit id="sa634ffa797037aac">
<source>Reputation cannot decrease lower than this value. Zero or negative.</source>
</trans-unit>
<trans-unit id="s862986ce8e70edd7">
<source>Reputation: upper limit</source>
</trans-unit>
<trans-unit id="sdd04913b3b46cf30">
<source>Reputation cannot increase higher than this value. Zero or positive.</source>
</trans-unit>
<trans-unit id="s4d5cb134999b50df">
<source>HTTP Basic Auth</source>
</trans-unit>
<trans-unit id="s6927635d1c339cfc">
<source>Include the client ID and secret as request parameters</source>
</trans-unit>
<trans-unit id="s4fca384c634e1a92">
<source>Authorization code authentication method</source>
</trans-unit>
<trans-unit id="sdc02c276ed429008">
<source>How to perform authentication during an authorization_code token request flow</source>
</trans-unit> </trans-unit>
</body> </body>
</file> </file>

View File

@ -9696,91 +9696,12 @@ Les liaisons avec les groupes/utilisateurs sont vérifiées par rapport à l'uti
</trans-unit> </trans-unit>
<trans-unit id="s783964a224796865"> <trans-unit id="s783964a224796865">
<source>Field which contains members of a group. Note that if using the "memberUid" field, the value is assumed to contain a relative distinguished name. e.g. 'memberUid=some-user' instead of 'memberUid=cn=some-user,ou=groups,...'. When selecting 'Lookup using a user attribute', this should be a user attribute, otherwise a group attribute.</source> <source>Field which contains members of a group. Note that if using the "memberUid" field, the value is assumed to contain a relative distinguished name. e.g. 'memberUid=some-user' instead of 'memberUid=cn=some-user,ou=groups,...'. When selecting 'Lookup using a user attribute', this should be a user attribute, otherwise a group attribute.</source>
<target>Champ qui contient les membres d'un groupe. Si vous utilisez le champ "memberUid", la valeur est censée contenir un nom distinctif relatif, par exemple 'memberUid=un-utilisateur' au lieu de 'memberUid=cn=un-utilisateur,ou=groups,...'. Lorsque "Recherche avec un attribut utilisateur" est sélectionné, cet attribut doit être un attribut utilisateur, sinon un attribut de groupe.</target>
</trans-unit> </trans-unit>
<trans-unit id="s1d47b4f61ca53e8e"> <trans-unit id="s1d47b4f61ca53e8e">
<source>Lookup using user attribute</source> <source>Lookup using user attribute</source>
<target>Recherche avec un attribut utilisateur</target>
</trans-unit> </trans-unit>
<trans-unit id="s17359123e1f24504"> <trans-unit id="s17359123e1f24504">
<source>Field which contains DNs of groups the user is a member of. This field is used to lookup groups from users, e.g. 'memberOf'. To lookup nested groups in an Active Directory environment use 'memberOf:1.2.840.113556.1.4.1941:'.</source> <source>Field which contains DNs of groups the user is a member of. This field is used to lookup groups from users, e.g. 'memberOf'. To lookup nested groups in an Active Directory environment use 'memberOf:1.2.840.113556.1.4.1941:'.</source>
<target>Champ contenant les DN des groupes dont l'utilisateur est membre. Ce champ est utilisé pour rechercher les groupes d'un utilisateur, par exemple 'memberOf'. Pour rechercher les groupes imbriqués dans un environnement Active Directory, utilisez 'memberOf:1.2.840.113556.1.4.1941:'.</target>
</trans-unit>
<trans-unit id="s891cd64acabf23bf">
<source>Initial Permissions</source>
<target>Permissions initiales</target>
</trans-unit>
<trans-unit id="sedb57bf4b42a8e40">
<source>Unknown Initial Permissions mode</source>
<target>Mode de permissions initiales inconnu</target>
</trans-unit>
<trans-unit id="s6ea6a64acb45dfdf">
<source>Successfully updated initial permissions.</source>
<target>Permissions initiales mises à jour avec succès.</target>
</trans-unit>
<trans-unit id="sfddf7896ab5938b6">
<source>Successfully created initial permissions.</source>
<target>Permissions initiales créées avec succès.</target>
</trans-unit>
<trans-unit id="s5c5f240cbb6d0bae">
<source>When a user with the selected Role creates an object, the Initial Permissions will be applied to that object.</source>
<target>Lorsqu'un utilisateur avec le rôle sélectionné crée un objet, les permissions initiales seront appliquées à cet objet,</target>
</trans-unit>
<trans-unit id="sbf27294eef56ac81">
<source>The Initial Permissions can either be placed on the User creating the object, or the Role selected in the previous field.</source>
<target>Les permissions initiales peuvent soit être placées sur l'utilisateur créant l'objet, ou sur le rôle sélectionné au champ précédent.</target>
</trans-unit>
<trans-unit id="s93f04537efda1b24">
<source>Available Permissions</source>
<target>Permissions disponibles</target>
</trans-unit>
<trans-unit id="s297bc57f9e494470">
<source>Selected Permissions</source>
<target>Permissions sélectionnées</target>
</trans-unit>
<trans-unit id="s0ea71d53764d781c">
<source>Permissions to grant when a new object is created.</source>
<target>Permissions à attribuer lorsqu'un nouvel objet est créé.</target>
</trans-unit>
<trans-unit id="s06fc21a40f5d7de1">
<source>Set initial permissions for newly created objects.</source>
<target>Définir des permissions initiales pour les objets nouvellement créés.</target>
</trans-unit>
<trans-unit id="sc7104a4d0fc35c7c">
<source>Update Initial Permissions</source>
<target>Mettre à jour les permissions initiales</target>
</trans-unit>
<trans-unit id="s83fa005829a65be9">
<source>Create Initial Permissions</source>
<target>Créer des permissions initiales</target>
</trans-unit>
<trans-unit id="se37ac6cf9c72f21a">
<source>Reputation: lower limit</source>
<target>Réputation : limite inférieure</target>
</trans-unit>
<trans-unit id="sa634ffa797037aac">
<source>Reputation cannot decrease lower than this value. Zero or negative.</source>
<target>La réputation ne peut pas descendre en dessous de cette valeur. Zéro ou négatif.</target>
</trans-unit>
<trans-unit id="s862986ce8e70edd7">
<source>Reputation: upper limit</source>
<target>Réputation : limite supérieure</target>
</trans-unit>
<trans-unit id="sdd04913b3b46cf30">
<source>Reputation cannot increase higher than this value. Zero or positive.</source>
<target>La réputation ne peut pas monter au dessus de cette valeur. Zéro ou positif.</target>
</trans-unit>
<trans-unit id="s4d5cb134999b50df">
<source>HTTP Basic Auth</source>
</trans-unit>
<trans-unit id="s6927635d1c339cfc">
<source>Include the client ID and secret as request parameters</source>
</trans-unit>
<trans-unit id="s4fca384c634e1a92">
<source>Authorization code authentication method</source>
</trans-unit>
<trans-unit id="sdc02c276ed429008">
<source>How to perform authentication during an authorization_code token request flow</source>
</trans-unit> </trans-unit>
</body> </body>
</file> </file>

View File

@ -9703,66 +9703,6 @@ Bindings to groups/users are checked against the user of the event.</source>
</trans-unit> </trans-unit>
<trans-unit id="s17359123e1f24504"> <trans-unit id="s17359123e1f24504">
<source>Field which contains DNs of groups the user is a member of. This field is used to lookup groups from users, e.g. 'memberOf'. To lookup nested groups in an Active Directory environment use 'memberOf:1.2.840.113556.1.4.1941:'.</source> <source>Field which contains DNs of groups the user is a member of. This field is used to lookup groups from users, e.g. 'memberOf'. To lookup nested groups in an Active Directory environment use 'memberOf:1.2.840.113556.1.4.1941:'.</source>
</trans-unit>
<trans-unit id="s891cd64acabf23bf">
<source>Initial Permissions</source>
</trans-unit>
<trans-unit id="sedb57bf4b42a8e40">
<source>Unknown Initial Permissions mode</source>
</trans-unit>
<trans-unit id="s6ea6a64acb45dfdf">
<source>Successfully updated initial permissions.</source>
</trans-unit>
<trans-unit id="sfddf7896ab5938b6">
<source>Successfully created initial permissions.</source>
</trans-unit>
<trans-unit id="s5c5f240cbb6d0bae">
<source>When a user with the selected Role creates an object, the Initial Permissions will be applied to that object.</source>
</trans-unit>
<trans-unit id="sbf27294eef56ac81">
<source>The Initial Permissions can either be placed on the User creating the object, or the Role selected in the previous field.</source>
</trans-unit>
<trans-unit id="s93f04537efda1b24">
<source>Available Permissions</source>
</trans-unit>
<trans-unit id="s297bc57f9e494470">
<source>Selected Permissions</source>
</trans-unit>
<trans-unit id="s0ea71d53764d781c">
<source>Permissions to grant when a new object is created.</source>
</trans-unit>
<trans-unit id="s06fc21a40f5d7de1">
<source>Set initial permissions for newly created objects.</source>
</trans-unit>
<trans-unit id="sc7104a4d0fc35c7c">
<source>Update Initial Permissions</source>
</trans-unit>
<trans-unit id="s83fa005829a65be9">
<source>Create Initial Permissions</source>
</trans-unit>
<trans-unit id="se37ac6cf9c72f21a">
<source>Reputation: lower limit</source>
</trans-unit>
<trans-unit id="sa634ffa797037aac">
<source>Reputation cannot decrease lower than this value. Zero or negative.</source>
</trans-unit>
<trans-unit id="s862986ce8e70edd7">
<source>Reputation: upper limit</source>
</trans-unit>
<trans-unit id="sdd04913b3b46cf30">
<source>Reputation cannot increase higher than this value. Zero or positive.</source>
</trans-unit>
<trans-unit id="s4d5cb134999b50df">
<source>HTTP Basic Auth</source>
</trans-unit>
<trans-unit id="s6927635d1c339cfc">
<source>Include the client ID and secret as request parameters</source>
</trans-unit>
<trans-unit id="s4fca384c634e1a92">
<source>Authorization code authentication method</source>
</trans-unit>
<trans-unit id="sdc02c276ed429008">
<source>How to perform authentication during an authorization_code token request flow</source>
</trans-unit> </trans-unit>
</body> </body>
</file> </file>

View File

@ -9086,66 +9086,6 @@ Bindings to groups/users are checked against the user of the event.</source>
</trans-unit> </trans-unit>
<trans-unit id="s17359123e1f24504"> <trans-unit id="s17359123e1f24504">
<source>Field which contains DNs of groups the user is a member of. This field is used to lookup groups from users, e.g. 'memberOf'. To lookup nested groups in an Active Directory environment use 'memberOf:1.2.840.113556.1.4.1941:'.</source> <source>Field which contains DNs of groups the user is a member of. This field is used to lookup groups from users, e.g. 'memberOf'. To lookup nested groups in an Active Directory environment use 'memberOf:1.2.840.113556.1.4.1941:'.</source>
</trans-unit>
<trans-unit id="s891cd64acabf23bf">
<source>Initial Permissions</source>
</trans-unit>
<trans-unit id="sedb57bf4b42a8e40">
<source>Unknown Initial Permissions mode</source>
</trans-unit>
<trans-unit id="s6ea6a64acb45dfdf">
<source>Successfully updated initial permissions.</source>
</trans-unit>
<trans-unit id="sfddf7896ab5938b6">
<source>Successfully created initial permissions.</source>
</trans-unit>
<trans-unit id="s5c5f240cbb6d0bae">
<source>When a user with the selected Role creates an object, the Initial Permissions will be applied to that object.</source>
</trans-unit>
<trans-unit id="sbf27294eef56ac81">
<source>The Initial Permissions can either be placed on the User creating the object, or the Role selected in the previous field.</source>
</trans-unit>
<trans-unit id="s93f04537efda1b24">
<source>Available Permissions</source>
</trans-unit>
<trans-unit id="s297bc57f9e494470">
<source>Selected Permissions</source>
</trans-unit>
<trans-unit id="s0ea71d53764d781c">
<source>Permissions to grant when a new object is created.</source>
</trans-unit>
<trans-unit id="s06fc21a40f5d7de1">
<source>Set initial permissions for newly created objects.</source>
</trans-unit>
<trans-unit id="sc7104a4d0fc35c7c">
<source>Update Initial Permissions</source>
</trans-unit>
<trans-unit id="s83fa005829a65be9">
<source>Create Initial Permissions</source>
</trans-unit>
<trans-unit id="se37ac6cf9c72f21a">
<source>Reputation: lower limit</source>
</trans-unit>
<trans-unit id="sa634ffa797037aac">
<source>Reputation cannot decrease lower than this value. Zero or negative.</source>
</trans-unit>
<trans-unit id="s862986ce8e70edd7">
<source>Reputation: upper limit</source>
</trans-unit>
<trans-unit id="sdd04913b3b46cf30">
<source>Reputation cannot increase higher than this value. Zero or positive.</source>
</trans-unit>
<trans-unit id="s4d5cb134999b50df">
<source>HTTP Basic Auth</source>
</trans-unit>
<trans-unit id="s6927635d1c339cfc">
<source>Include the client ID and secret as request parameters</source>
</trans-unit>
<trans-unit id="s4fca384c634e1a92">
<source>Authorization code authentication method</source>
</trans-unit>
<trans-unit id="sdc02c276ed429008">
<source>How to perform authentication during an authorization_code token request flow</source>
</trans-unit> </trans-unit>
</body> </body>
</file> </file>

View File

@ -8988,66 +8988,6 @@ Bindingen naar groepen/gebruikers worden gecontroleerd tegen de gebruiker van de
</trans-unit> </trans-unit>
<trans-unit id="s17359123e1f24504"> <trans-unit id="s17359123e1f24504">
<source>Field which contains DNs of groups the user is a member of. This field is used to lookup groups from users, e.g. 'memberOf'. To lookup nested groups in an Active Directory environment use 'memberOf:1.2.840.113556.1.4.1941:'.</source> <source>Field which contains DNs of groups the user is a member of. This field is used to lookup groups from users, e.g. 'memberOf'. To lookup nested groups in an Active Directory environment use 'memberOf:1.2.840.113556.1.4.1941:'.</source>
</trans-unit>
<trans-unit id="s891cd64acabf23bf">
<source>Initial Permissions</source>
</trans-unit>
<trans-unit id="sedb57bf4b42a8e40">
<source>Unknown Initial Permissions mode</source>
</trans-unit>
<trans-unit id="s6ea6a64acb45dfdf">
<source>Successfully updated initial permissions.</source>
</trans-unit>
<trans-unit id="sfddf7896ab5938b6">
<source>Successfully created initial permissions.</source>
</trans-unit>
<trans-unit id="s5c5f240cbb6d0bae">
<source>When a user with the selected Role creates an object, the Initial Permissions will be applied to that object.</source>
</trans-unit>
<trans-unit id="sbf27294eef56ac81">
<source>The Initial Permissions can either be placed on the User creating the object, or the Role selected in the previous field.</source>
</trans-unit>
<trans-unit id="s93f04537efda1b24">
<source>Available Permissions</source>
</trans-unit>
<trans-unit id="s297bc57f9e494470">
<source>Selected Permissions</source>
</trans-unit>
<trans-unit id="s0ea71d53764d781c">
<source>Permissions to grant when a new object is created.</source>
</trans-unit>
<trans-unit id="s06fc21a40f5d7de1">
<source>Set initial permissions for newly created objects.</source>
</trans-unit>
<trans-unit id="sc7104a4d0fc35c7c">
<source>Update Initial Permissions</source>
</trans-unit>
<trans-unit id="s83fa005829a65be9">
<source>Create Initial Permissions</source>
</trans-unit>
<trans-unit id="se37ac6cf9c72f21a">
<source>Reputation: lower limit</source>
</trans-unit>
<trans-unit id="sa634ffa797037aac">
<source>Reputation cannot decrease lower than this value. Zero or negative.</source>
</trans-unit>
<trans-unit id="s862986ce8e70edd7">
<source>Reputation: upper limit</source>
</trans-unit>
<trans-unit id="sdd04913b3b46cf30">
<source>Reputation cannot increase higher than this value. Zero or positive.</source>
</trans-unit>
<trans-unit id="s4d5cb134999b50df">
<source>HTTP Basic Auth</source>
</trans-unit>
<trans-unit id="s6927635d1c339cfc">
<source>Include the client ID and secret as request parameters</source>
</trans-unit>
<trans-unit id="s4fca384c634e1a92">
<source>Authorization code authentication method</source>
</trans-unit>
<trans-unit id="sdc02c276ed429008">
<source>How to perform authentication during an authorization_code token request flow</source>
</trans-unit> </trans-unit>
</body> </body>
</file> </file>

View File

@ -9413,66 +9413,6 @@ Powiązania z grupami/użytkownikami są sprawdzane względem użytkownika zdarz
</trans-unit> </trans-unit>
<trans-unit id="s17359123e1f24504"> <trans-unit id="s17359123e1f24504">
<source>Field which contains DNs of groups the user is a member of. This field is used to lookup groups from users, e.g. 'memberOf'. To lookup nested groups in an Active Directory environment use 'memberOf:1.2.840.113556.1.4.1941:'.</source> <source>Field which contains DNs of groups the user is a member of. This field is used to lookup groups from users, e.g. 'memberOf'. To lookup nested groups in an Active Directory environment use 'memberOf:1.2.840.113556.1.4.1941:'.</source>
</trans-unit>
<trans-unit id="s891cd64acabf23bf">
<source>Initial Permissions</source>
</trans-unit>
<trans-unit id="sedb57bf4b42a8e40">
<source>Unknown Initial Permissions mode</source>
</trans-unit>
<trans-unit id="s6ea6a64acb45dfdf">
<source>Successfully updated initial permissions.</source>
</trans-unit>
<trans-unit id="sfddf7896ab5938b6">
<source>Successfully created initial permissions.</source>
</trans-unit>
<trans-unit id="s5c5f240cbb6d0bae">
<source>When a user with the selected Role creates an object, the Initial Permissions will be applied to that object.</source>
</trans-unit>
<trans-unit id="sbf27294eef56ac81">
<source>The Initial Permissions can either be placed on the User creating the object, or the Role selected in the previous field.</source>
</trans-unit>
<trans-unit id="s93f04537efda1b24">
<source>Available Permissions</source>
</trans-unit>
<trans-unit id="s297bc57f9e494470">
<source>Selected Permissions</source>
</trans-unit>
<trans-unit id="s0ea71d53764d781c">
<source>Permissions to grant when a new object is created.</source>
</trans-unit>
<trans-unit id="s06fc21a40f5d7de1">
<source>Set initial permissions for newly created objects.</source>
</trans-unit>
<trans-unit id="sc7104a4d0fc35c7c">
<source>Update Initial Permissions</source>
</trans-unit>
<trans-unit id="s83fa005829a65be9">
<source>Create Initial Permissions</source>
</trans-unit>
<trans-unit id="se37ac6cf9c72f21a">
<source>Reputation: lower limit</source>
</trans-unit>
<trans-unit id="sa634ffa797037aac">
<source>Reputation cannot decrease lower than this value. Zero or negative.</source>
</trans-unit>
<trans-unit id="s862986ce8e70edd7">
<source>Reputation: upper limit</source>
</trans-unit>
<trans-unit id="sdd04913b3b46cf30">
<source>Reputation cannot increase higher than this value. Zero or positive.</source>
</trans-unit>
<trans-unit id="s4d5cb134999b50df">
<source>HTTP Basic Auth</source>
</trans-unit>
<trans-unit id="s6927635d1c339cfc">
<source>Include the client ID and secret as request parameters</source>
</trans-unit>
<trans-unit id="s4fca384c634e1a92">
<source>Authorization code authentication method</source>
</trans-unit>
<trans-unit id="sdc02c276ed429008">
<source>How to perform authentication during an authorization_code token request flow</source>
</trans-unit> </trans-unit>
</body> </body>
</file> </file>

View File

@ -9421,64 +9421,4 @@ Bindings to groups/users are checked against the user of the event.</source>
<trans-unit id="s17359123e1f24504"> <trans-unit id="s17359123e1f24504">
<source>Field which contains DNs of groups the user is a member of. This field is used to lookup groups from users, e.g. 'memberOf'. To lookup nested groups in an Active Directory environment use 'memberOf:1.2.840.113556.1.4.1941:'.</source> <source>Field which contains DNs of groups the user is a member of. This field is used to lookup groups from users, e.g. 'memberOf'. To lookup nested groups in an Active Directory environment use 'memberOf:1.2.840.113556.1.4.1941:'.</source>
</trans-unit> </trans-unit>
<trans-unit id="s891cd64acabf23bf">
<source>Initial Permissions</source>
</trans-unit>
<trans-unit id="sedb57bf4b42a8e40">
<source>Unknown Initial Permissions mode</source>
</trans-unit>
<trans-unit id="s6ea6a64acb45dfdf">
<source>Successfully updated initial permissions.</source>
</trans-unit>
<trans-unit id="sfddf7896ab5938b6">
<source>Successfully created initial permissions.</source>
</trans-unit>
<trans-unit id="s5c5f240cbb6d0bae">
<source>When a user with the selected Role creates an object, the Initial Permissions will be applied to that object.</source>
</trans-unit>
<trans-unit id="sbf27294eef56ac81">
<source>The Initial Permissions can either be placed on the User creating the object, or the Role selected in the previous field.</source>
</trans-unit>
<trans-unit id="s93f04537efda1b24">
<source>Available Permissions</source>
</trans-unit>
<trans-unit id="s297bc57f9e494470">
<source>Selected Permissions</source>
</trans-unit>
<trans-unit id="s0ea71d53764d781c">
<source>Permissions to grant when a new object is created.</source>
</trans-unit>
<trans-unit id="s06fc21a40f5d7de1">
<source>Set initial permissions for newly created objects.</source>
</trans-unit>
<trans-unit id="sc7104a4d0fc35c7c">
<source>Update Initial Permissions</source>
</trans-unit>
<trans-unit id="s83fa005829a65be9">
<source>Create Initial Permissions</source>
</trans-unit>
<trans-unit id="se37ac6cf9c72f21a">
<source>Reputation: lower limit</source>
</trans-unit>
<trans-unit id="sa634ffa797037aac">
<source>Reputation cannot decrease lower than this value. Zero or negative.</source>
</trans-unit>
<trans-unit id="s862986ce8e70edd7">
<source>Reputation: upper limit</source>
</trans-unit>
<trans-unit id="sdd04913b3b46cf30">
<source>Reputation cannot increase higher than this value. Zero or positive.</source>
</trans-unit>
<trans-unit id="s4d5cb134999b50df">
<source>HTTP Basic Auth</source>
</trans-unit>
<trans-unit id="s6927635d1c339cfc">
<source>Include the client ID and secret as request parameters</source>
</trans-unit>
<trans-unit id="s4fca384c634e1a92">
<source>Authorization code authentication method</source>
</trans-unit>
<trans-unit id="sdc02c276ed429008">
<source>How to perform authentication during an authorization_code token request flow</source>
</trans-unit>
</body></file></xliff> </body></file></xliff>

View File

@ -9506,66 +9506,6 @@ Bindings to groups/users are checked against the user of the event.</source>
</trans-unit> </trans-unit>
<trans-unit id="s17359123e1f24504"> <trans-unit id="s17359123e1f24504">
<source>Field which contains DNs of groups the user is a member of. This field is used to lookup groups from users, e.g. 'memberOf'. To lookup nested groups in an Active Directory environment use 'memberOf:1.2.840.113556.1.4.1941:'.</source> <source>Field which contains DNs of groups the user is a member of. This field is used to lookup groups from users, e.g. 'memberOf'. To lookup nested groups in an Active Directory environment use 'memberOf:1.2.840.113556.1.4.1941:'.</source>
</trans-unit>
<trans-unit id="s891cd64acabf23bf">
<source>Initial Permissions</source>
</trans-unit>
<trans-unit id="sedb57bf4b42a8e40">
<source>Unknown Initial Permissions mode</source>
</trans-unit>
<trans-unit id="s6ea6a64acb45dfdf">
<source>Successfully updated initial permissions.</source>
</trans-unit>
<trans-unit id="sfddf7896ab5938b6">
<source>Successfully created initial permissions.</source>
</trans-unit>
<trans-unit id="s5c5f240cbb6d0bae">
<source>When a user with the selected Role creates an object, the Initial Permissions will be applied to that object.</source>
</trans-unit>
<trans-unit id="sbf27294eef56ac81">
<source>The Initial Permissions can either be placed on the User creating the object, or the Role selected in the previous field.</source>
</trans-unit>
<trans-unit id="s93f04537efda1b24">
<source>Available Permissions</source>
</trans-unit>
<trans-unit id="s297bc57f9e494470">
<source>Selected Permissions</source>
</trans-unit>
<trans-unit id="s0ea71d53764d781c">
<source>Permissions to grant when a new object is created.</source>
</trans-unit>
<trans-unit id="s06fc21a40f5d7de1">
<source>Set initial permissions for newly created objects.</source>
</trans-unit>
<trans-unit id="sc7104a4d0fc35c7c">
<source>Update Initial Permissions</source>
</trans-unit>
<trans-unit id="s83fa005829a65be9">
<source>Create Initial Permissions</source>
</trans-unit>
<trans-unit id="se37ac6cf9c72f21a">
<source>Reputation: lower limit</source>
</trans-unit>
<trans-unit id="sa634ffa797037aac">
<source>Reputation cannot decrease lower than this value. Zero or negative.</source>
</trans-unit>
<trans-unit id="s862986ce8e70edd7">
<source>Reputation: upper limit</source>
</trans-unit>
<trans-unit id="sdd04913b3b46cf30">
<source>Reputation cannot increase higher than this value. Zero or positive.</source>
</trans-unit>
<trans-unit id="s4d5cb134999b50df">
<source>HTTP Basic Auth</source>
</trans-unit>
<trans-unit id="s6927635d1c339cfc">
<source>Include the client ID and secret as request parameters</source>
</trans-unit>
<trans-unit id="s4fca384c634e1a92">
<source>Authorization code authentication method</source>
</trans-unit>
<trans-unit id="sdc02c276ed429008">
<source>How to perform authentication during an authorization_code token request flow</source>
</trans-unit> </trans-unit>
</body> </body>
</file> </file>

View File

@ -9477,66 +9477,6 @@ Gruplara/kullanıcılara yapılan bağlamalar, etkinliğin kullanıcısına kar
</trans-unit> </trans-unit>
<trans-unit id="s17359123e1f24504"> <trans-unit id="s17359123e1f24504">
<source>Field which contains DNs of groups the user is a member of. This field is used to lookup groups from users, e.g. 'memberOf'. To lookup nested groups in an Active Directory environment use 'memberOf:1.2.840.113556.1.4.1941:'.</source> <source>Field which contains DNs of groups the user is a member of. This field is used to lookup groups from users, e.g. 'memberOf'. To lookup nested groups in an Active Directory environment use 'memberOf:1.2.840.113556.1.4.1941:'.</source>
</trans-unit>
<trans-unit id="s891cd64acabf23bf">
<source>Initial Permissions</source>
</trans-unit>
<trans-unit id="sedb57bf4b42a8e40">
<source>Unknown Initial Permissions mode</source>
</trans-unit>
<trans-unit id="s6ea6a64acb45dfdf">
<source>Successfully updated initial permissions.</source>
</trans-unit>
<trans-unit id="sfddf7896ab5938b6">
<source>Successfully created initial permissions.</source>
</trans-unit>
<trans-unit id="s5c5f240cbb6d0bae">
<source>When a user with the selected Role creates an object, the Initial Permissions will be applied to that object.</source>
</trans-unit>
<trans-unit id="sbf27294eef56ac81">
<source>The Initial Permissions can either be placed on the User creating the object, or the Role selected in the previous field.</source>
</trans-unit>
<trans-unit id="s93f04537efda1b24">
<source>Available Permissions</source>
</trans-unit>
<trans-unit id="s297bc57f9e494470">
<source>Selected Permissions</source>
</trans-unit>
<trans-unit id="s0ea71d53764d781c">
<source>Permissions to grant when a new object is created.</source>
</trans-unit>
<trans-unit id="s06fc21a40f5d7de1">
<source>Set initial permissions for newly created objects.</source>
</trans-unit>
<trans-unit id="sc7104a4d0fc35c7c">
<source>Update Initial Permissions</source>
</trans-unit>
<trans-unit id="s83fa005829a65be9">
<source>Create Initial Permissions</source>
</trans-unit>
<trans-unit id="se37ac6cf9c72f21a">
<source>Reputation: lower limit</source>
</trans-unit>
<trans-unit id="sa634ffa797037aac">
<source>Reputation cannot decrease lower than this value. Zero or negative.</source>
</trans-unit>
<trans-unit id="s862986ce8e70edd7">
<source>Reputation: upper limit</source>
</trans-unit>
<trans-unit id="sdd04913b3b46cf30">
<source>Reputation cannot increase higher than this value. Zero or positive.</source>
</trans-unit>
<trans-unit id="s4d5cb134999b50df">
<source>HTTP Basic Auth</source>
</trans-unit>
<trans-unit id="s6927635d1c339cfc">
<source>Include the client ID and secret as request parameters</source>
</trans-unit>
<trans-unit id="s4fca384c634e1a92">
<source>Authorization code authentication method</source>
</trans-unit>
<trans-unit id="sdc02c276ed429008">
<source>How to perform authentication during an authorization_code token request flow</source>
</trans-unit> </trans-unit>
</body> </body>
</file> </file>

View File

@ -6227,66 +6227,6 @@ Bindings to groups/users are checked against the user of the event.</source>
<trans-unit id="s17359123e1f24504"> <trans-unit id="s17359123e1f24504">
<source>Field which contains DNs of groups the user is a member of. This field is used to lookup groups from users, e.g. 'memberOf'. To lookup nested groups in an Active Directory environment use 'memberOf:1.2.840.113556.1.4.1941:'.</source> <source>Field which contains DNs of groups the user is a member of. This field is used to lookup groups from users, e.g. 'memberOf'. To lookup nested groups in an Active Directory environment use 'memberOf:1.2.840.113556.1.4.1941:'.</source>
</trans-unit> </trans-unit>
<trans-unit id="s891cd64acabf23bf">
<source>Initial Permissions</source>
</trans-unit>
<trans-unit id="sedb57bf4b42a8e40">
<source>Unknown Initial Permissions mode</source>
</trans-unit>
<trans-unit id="s6ea6a64acb45dfdf">
<source>Successfully updated initial permissions.</source>
</trans-unit>
<trans-unit id="sfddf7896ab5938b6">
<source>Successfully created initial permissions.</source>
</trans-unit>
<trans-unit id="s5c5f240cbb6d0bae">
<source>When a user with the selected Role creates an object, the Initial Permissions will be applied to that object.</source>
</trans-unit>
<trans-unit id="sbf27294eef56ac81">
<source>The Initial Permissions can either be placed on the User creating the object, or the Role selected in the previous field.</source>
</trans-unit>
<trans-unit id="s93f04537efda1b24">
<source>Available Permissions</source>
</trans-unit>
<trans-unit id="s297bc57f9e494470">
<source>Selected Permissions</source>
</trans-unit>
<trans-unit id="s0ea71d53764d781c">
<source>Permissions to grant when a new object is created.</source>
</trans-unit>
<trans-unit id="s06fc21a40f5d7de1">
<source>Set initial permissions for newly created objects.</source>
</trans-unit>
<trans-unit id="sc7104a4d0fc35c7c">
<source>Update Initial Permissions</source>
</trans-unit>
<trans-unit id="s83fa005829a65be9">
<source>Create Initial Permissions</source>
</trans-unit>
<trans-unit id="se37ac6cf9c72f21a">
<source>Reputation: lower limit</source>
</trans-unit>
<trans-unit id="sa634ffa797037aac">
<source>Reputation cannot decrease lower than this value. Zero or negative.</source>
</trans-unit>
<trans-unit id="s862986ce8e70edd7">
<source>Reputation: upper limit</source>
</trans-unit>
<trans-unit id="sdd04913b3b46cf30">
<source>Reputation cannot increase higher than this value. Zero or positive.</source>
</trans-unit>
<trans-unit id="s4d5cb134999b50df">
<source>HTTP Basic Auth</source>
</trans-unit>
<trans-unit id="s6927635d1c339cfc">
<source>Include the client ID and secret as request parameters</source>
</trans-unit>
<trans-unit id="s4fca384c634e1a92">
<source>Authorization code authentication method</source>
</trans-unit>
<trans-unit id="sdc02c276ed429008">
<source>How to perform authentication during an authorization_code token request flow</source>
</trans-unit>
</body> </body>
</file> </file>
</xliff> </xliff>

View File

@ -9697,91 +9697,12 @@ Bindings to groups/users are checked against the user of the event.</source>
</trans-unit> </trans-unit>
<trans-unit id="s783964a224796865"> <trans-unit id="s783964a224796865">
<source>Field which contains members of a group. Note that if using the "memberUid" field, the value is assumed to contain a relative distinguished name. e.g. 'memberUid=some-user' instead of 'memberUid=cn=some-user,ou=groups,...'. When selecting 'Lookup using a user attribute', this should be a user attribute, otherwise a group attribute.</source> <source>Field which contains members of a group. Note that if using the "memberUid" field, the value is assumed to contain a relative distinguished name. e.g. 'memberUid=some-user' instead of 'memberUid=cn=some-user,ou=groups,...'. When selecting 'Lookup using a user attribute', this should be a user attribute, otherwise a group attribute.</source>
<target>包含组成员的字段。请注意,如果使用 "memberUid" 字段,则假定该值包含相对可分辨名称。例如,'memberUid=some-user' 而不是 'memberUid=cn=some-user,ou=groups,...'。当选中“使用用户属性查询”时,此配置应该为用户属性,否则为组属性。</target>
</trans-unit> </trans-unit>
<trans-unit id="s1d47b4f61ca53e8e"> <trans-unit id="s1d47b4f61ca53e8e">
<source>Lookup using user attribute</source> <source>Lookup using user attribute</source>
<target>使用用户属性查询</target>
</trans-unit> </trans-unit>
<trans-unit id="s17359123e1f24504"> <trans-unit id="s17359123e1f24504">
<source>Field which contains DNs of groups the user is a member of. This field is used to lookup groups from users, e.g. 'memberOf'. To lookup nested groups in an Active Directory environment use 'memberOf:1.2.840.113556.1.4.1941:'.</source> <source>Field which contains DNs of groups the user is a member of. This field is used to lookup groups from users, e.g. 'memberOf'. To lookup nested groups in an Active Directory environment use 'memberOf:1.2.840.113556.1.4.1941:'.</source>
<target>包含用户所属组 DN 的字段。此字段用于从用户查询组,例如 'memberOf'。要在 Active Directory 环境中查询嵌套组,则使用 'memberOf:1.2.840.113556.1.4.1941:'。</target>
</trans-unit>
<trans-unit id="s891cd64acabf23bf">
<source>Initial Permissions</source>
<target>初始权限</target>
</trans-unit>
<trans-unit id="sedb57bf4b42a8e40">
<source>Unknown Initial Permissions mode</source>
<target>未知初始权限模式</target>
</trans-unit>
<trans-unit id="s6ea6a64acb45dfdf">
<source>Successfully updated initial permissions.</source>
<target>已成功更新初始权限。</target>
</trans-unit>
<trans-unit id="sfddf7896ab5938b6">
<source>Successfully created initial permissions.</source>
<target>已成功创建初始权限。</target>
</trans-unit>
<trans-unit id="s5c5f240cbb6d0bae">
<source>When a user with the selected Role creates an object, the Initial Permissions will be applied to that object.</source>
<target>当所选角色的用户创建对象时,初始权限会应用于该对象。</target>
</trans-unit>
<trans-unit id="sbf27294eef56ac81">
<source>The Initial Permissions can either be placed on the User creating the object, or the Role selected in the previous field.</source>
<target>初始权限既可以属于创建对象的用户,又可以属于上一个字段中设置的角色。</target>
</trans-unit>
<trans-unit id="s93f04537efda1b24">
<source>Available Permissions</source>
<target>可用权限</target>
</trans-unit>
<trans-unit id="s297bc57f9e494470">
<source>Selected Permissions</source>
<target>已选权限</target>
</trans-unit>
<trans-unit id="s0ea71d53764d781c">
<source>Permissions to grant when a new object is created.</source>
<target>创建新对象时授予的权限。</target>
</trans-unit>
<trans-unit id="s06fc21a40f5d7de1">
<source>Set initial permissions for newly created objects.</source>
<target>为新创建的对象设置初始权限。</target>
</trans-unit>
<trans-unit id="sc7104a4d0fc35c7c">
<source>Update Initial Permissions</source>
<target>更新初始权限</target>
</trans-unit>
<trans-unit id="s83fa005829a65be9">
<source>Create Initial Permissions</source>
<target>创建初始权限</target>
</trans-unit>
<trans-unit id="se37ac6cf9c72f21a">
<source>Reputation: lower limit</source>
<target>信誉:下限值</target>
</trans-unit>
<trans-unit id="sa634ffa797037aac">
<source>Reputation cannot decrease lower than this value. Zero or negative.</source>
<target>信誉无法降低到此值以下。可为零或负数。</target>
</trans-unit>
<trans-unit id="s862986ce8e70edd7">
<source>Reputation: upper limit</source>
<target>信誉:上限值</target>
</trans-unit>
<trans-unit id="sdd04913b3b46cf30">
<source>Reputation cannot increase higher than this value. Zero or positive.</source>
<target>信誉无法提高到此值以上。可为零或正数。</target>
</trans-unit>
<trans-unit id="s4d5cb134999b50df">
<source>HTTP Basic Auth</source>
</trans-unit>
<trans-unit id="s6927635d1c339cfc">
<source>Include the client ID and secret as request parameters</source>
</trans-unit>
<trans-unit id="s4fca384c634e1a92">
<source>Authorization code authentication method</source>
</trans-unit>
<trans-unit id="sdc02c276ed429008">
<source>How to perform authentication during an authorization_code token request flow</source>
</trans-unit> </trans-unit>
</body> </body>
</file> </file>

View File

@ -7319,66 +7319,6 @@ Bindings to groups/users are checked against the user of the event.</source>
</trans-unit> </trans-unit>
<trans-unit id="s17359123e1f24504"> <trans-unit id="s17359123e1f24504">
<source>Field which contains DNs of groups the user is a member of. This field is used to lookup groups from users, e.g. 'memberOf'. To lookup nested groups in an Active Directory environment use 'memberOf:1.2.840.113556.1.4.1941:'.</source> <source>Field which contains DNs of groups the user is a member of. This field is used to lookup groups from users, e.g. 'memberOf'. To lookup nested groups in an Active Directory environment use 'memberOf:1.2.840.113556.1.4.1941:'.</source>
</trans-unit>
<trans-unit id="s891cd64acabf23bf">
<source>Initial Permissions</source>
</trans-unit>
<trans-unit id="sedb57bf4b42a8e40">
<source>Unknown Initial Permissions mode</source>
</trans-unit>
<trans-unit id="s6ea6a64acb45dfdf">
<source>Successfully updated initial permissions.</source>
</trans-unit>
<trans-unit id="sfddf7896ab5938b6">
<source>Successfully created initial permissions.</source>
</trans-unit>
<trans-unit id="s5c5f240cbb6d0bae">
<source>When a user with the selected Role creates an object, the Initial Permissions will be applied to that object.</source>
</trans-unit>
<trans-unit id="sbf27294eef56ac81">
<source>The Initial Permissions can either be placed on the User creating the object, or the Role selected in the previous field.</source>
</trans-unit>
<trans-unit id="s93f04537efda1b24">
<source>Available Permissions</source>
</trans-unit>
<trans-unit id="s297bc57f9e494470">
<source>Selected Permissions</source>
</trans-unit>
<trans-unit id="s0ea71d53764d781c">
<source>Permissions to grant when a new object is created.</source>
</trans-unit>
<trans-unit id="s06fc21a40f5d7de1">
<source>Set initial permissions for newly created objects.</source>
</trans-unit>
<trans-unit id="sc7104a4d0fc35c7c">
<source>Update Initial Permissions</source>
</trans-unit>
<trans-unit id="s83fa005829a65be9">
<source>Create Initial Permissions</source>
</trans-unit>
<trans-unit id="se37ac6cf9c72f21a">
<source>Reputation: lower limit</source>
</trans-unit>
<trans-unit id="sa634ffa797037aac">
<source>Reputation cannot decrease lower than this value. Zero or negative.</source>
</trans-unit>
<trans-unit id="s862986ce8e70edd7">
<source>Reputation: upper limit</source>
</trans-unit>
<trans-unit id="sdd04913b3b46cf30">
<source>Reputation cannot increase higher than this value. Zero or positive.</source>
</trans-unit>
<trans-unit id="s4d5cb134999b50df">
<source>HTTP Basic Auth</source>
</trans-unit>
<trans-unit id="s6927635d1c339cfc">
<source>Include the client ID and secret as request parameters</source>
</trans-unit>
<trans-unit id="s4fca384c634e1a92">
<source>Authorization code authentication method</source>
</trans-unit>
<trans-unit id="sdc02c276ed429008">
<source>How to perform authentication during an authorization_code token request flow</source>
</trans-unit> </trans-unit>
</body> </body>
</file> </file>

View File

@ -9697,79 +9697,12 @@ Bindings to groups/users are checked against the user of the event.</source>
</trans-unit> </trans-unit>
<trans-unit id="s783964a224796865"> <trans-unit id="s783964a224796865">
<source>Field which contains members of a group. Note that if using the &quot;memberUid&quot; field, the value is assumed to contain a relative distinguished name. e.g. 'memberUid=some-user' instead of 'memberUid=cn=some-user,ou=groups,...'. When selecting 'Lookup using a user attribute', this should be a user attribute, otherwise a group attribute.</source> <source>Field which contains members of a group. Note that if using the &quot;memberUid&quot; field, the value is assumed to contain a relative distinguished name. e.g. 'memberUid=some-user' instead of 'memberUid=cn=some-user,ou=groups,...'. When selecting 'Lookup using a user attribute', this should be a user attribute, otherwise a group attribute.</source>
<target>包含组成员的字段。请注意,如果使用 &quot;memberUid&quot; 字段,则假定该值包含相对可分辨名称。例如,'memberUid=some-user' 而不是 'memberUid=cn=some-user,ou=groups,...'。当选中“使用用户属性查询”时,此配置应该为用户属性,否则为组属性。</target>
</trans-unit> </trans-unit>
<trans-unit id="s1d47b4f61ca53e8e"> <trans-unit id="s1d47b4f61ca53e8e">
<source>Lookup using user attribute</source> <source>Lookup using user attribute</source>
<target>使用用户属性查询</target>
</trans-unit> </trans-unit>
<trans-unit id="s17359123e1f24504"> <trans-unit id="s17359123e1f24504">
<source>Field which contains DNs of groups the user is a member of. This field is used to lookup groups from users, e.g. 'memberOf'. To lookup nested groups in an Active Directory environment use 'memberOf:1.2.840.113556.1.4.1941:'.</source> <source>Field which contains DNs of groups the user is a member of. This field is used to lookup groups from users, e.g. 'memberOf'. To lookup nested groups in an Active Directory environment use 'memberOf:1.2.840.113556.1.4.1941:'.</source>
<target>包含用户所属组 DN 的字段。此字段用于从用户查询组,例如 'memberOf'。要在 Active Directory 环境中查询嵌套组,则使用 'memberOf:1.2.840.113556.1.4.1941:'。</target>
</trans-unit>
<trans-unit id="s891cd64acabf23bf">
<source>Initial Permissions</source>
<target>初始权限</target>
</trans-unit>
<trans-unit id="sedb57bf4b42a8e40">
<source>Unknown Initial Permissions mode</source>
<target>未知初始权限模式</target>
</trans-unit>
<trans-unit id="s6ea6a64acb45dfdf">
<source>Successfully updated initial permissions.</source>
<target>已成功更新初始权限。</target>
</trans-unit>
<trans-unit id="sfddf7896ab5938b6">
<source>Successfully created initial permissions.</source>
<target>已成功创建初始权限。</target>
</trans-unit>
<trans-unit id="s5c5f240cbb6d0bae">
<source>When a user with the selected Role creates an object, the Initial Permissions will be applied to that object.</source>
<target>当所选角色的用户创建对象时,初始权限会应用于该对象。</target>
</trans-unit>
<trans-unit id="sbf27294eef56ac81">
<source>The Initial Permissions can either be placed on the User creating the object, or the Role selected in the previous field.</source>
<target>初始权限既可以属于创建对象的用户,又可以属于上一个字段中设置的角色。</target>
</trans-unit>
<trans-unit id="s93f04537efda1b24">
<source>Available Permissions</source>
<target>可用权限</target>
</trans-unit>
<trans-unit id="s297bc57f9e494470">
<source>Selected Permissions</source>
<target>已选权限</target>
</trans-unit>
<trans-unit id="s0ea71d53764d781c">
<source>Permissions to grant when a new object is created.</source>
<target>创建新对象时授予的权限。</target>
</trans-unit>
<trans-unit id="s06fc21a40f5d7de1">
<source>Set initial permissions for newly created objects.</source>
<target>为新创建的对象设置初始权限。</target>
</trans-unit>
<trans-unit id="sc7104a4d0fc35c7c">
<source>Update Initial Permissions</source>
<target>更新初始权限</target>
</trans-unit>
<trans-unit id="s83fa005829a65be9">
<source>Create Initial Permissions</source>
<target>创建初始权限</target>
</trans-unit>
<trans-unit id="se37ac6cf9c72f21a">
<source>Reputation: lower limit</source>
<target>信誉:下限值</target>
</trans-unit>
<trans-unit id="sa634ffa797037aac">
<source>Reputation cannot decrease lower than this value. Zero or negative.</source>
<target>信誉无法降低到此值以下。可为零或负数。</target>
</trans-unit>
<trans-unit id="s862986ce8e70edd7">
<source>Reputation: upper limit</source>
<target>信誉:上限值</target>
</trans-unit>
<trans-unit id="sdd04913b3b46cf30">
<source>Reputation cannot increase higher than this value. Zero or positive.</source>
<target>信誉无法提高到此值以上。可为零或正数。</target>
</trans-unit> </trans-unit>
</body> </body>
</file> </file>

View File

@ -9063,66 +9063,6 @@ Bindings to groups/users are checked against the user of the event.</source>
</trans-unit> </trans-unit>
<trans-unit id="s17359123e1f24504"> <trans-unit id="s17359123e1f24504">
<source>Field which contains DNs of groups the user is a member of. This field is used to lookup groups from users, e.g. 'memberOf'. To lookup nested groups in an Active Directory environment use 'memberOf:1.2.840.113556.1.4.1941:'.</source> <source>Field which contains DNs of groups the user is a member of. This field is used to lookup groups from users, e.g. 'memberOf'. To lookup nested groups in an Active Directory environment use 'memberOf:1.2.840.113556.1.4.1941:'.</source>
</trans-unit>
<trans-unit id="s891cd64acabf23bf">
<source>Initial Permissions</source>
</trans-unit>
<trans-unit id="sedb57bf4b42a8e40">
<source>Unknown Initial Permissions mode</source>
</trans-unit>
<trans-unit id="s6ea6a64acb45dfdf">
<source>Successfully updated initial permissions.</source>
</trans-unit>
<trans-unit id="sfddf7896ab5938b6">
<source>Successfully created initial permissions.</source>
</trans-unit>
<trans-unit id="s5c5f240cbb6d0bae">
<source>When a user with the selected Role creates an object, the Initial Permissions will be applied to that object.</source>
</trans-unit>
<trans-unit id="sbf27294eef56ac81">
<source>The Initial Permissions can either be placed on the User creating the object, or the Role selected in the previous field.</source>
</trans-unit>
<trans-unit id="s93f04537efda1b24">
<source>Available Permissions</source>
</trans-unit>
<trans-unit id="s297bc57f9e494470">
<source>Selected Permissions</source>
</trans-unit>
<trans-unit id="s0ea71d53764d781c">
<source>Permissions to grant when a new object is created.</source>
</trans-unit>
<trans-unit id="s06fc21a40f5d7de1">
<source>Set initial permissions for newly created objects.</source>
</trans-unit>
<trans-unit id="sc7104a4d0fc35c7c">
<source>Update Initial Permissions</source>
</trans-unit>
<trans-unit id="s83fa005829a65be9">
<source>Create Initial Permissions</source>
</trans-unit>
<trans-unit id="se37ac6cf9c72f21a">
<source>Reputation: lower limit</source>
</trans-unit>
<trans-unit id="sa634ffa797037aac">
<source>Reputation cannot decrease lower than this value. Zero or negative.</source>
</trans-unit>
<trans-unit id="s862986ce8e70edd7">
<source>Reputation: upper limit</source>
</trans-unit>
<trans-unit id="sdd04913b3b46cf30">
<source>Reputation cannot increase higher than this value. Zero or positive.</source>
</trans-unit>
<trans-unit id="s4d5cb134999b50df">
<source>HTTP Basic Auth</source>
</trans-unit>
<trans-unit id="s6927635d1c339cfc">
<source>Include the client ID and secret as request parameters</source>
</trans-unit>
<trans-unit id="s4fca384c634e1a92">
<source>Authorization code authentication method</source>
</trans-unit>
<trans-unit id="sdc02c276ed429008">
<source>How to perform authentication during an authorization_code token request flow</source>
</trans-unit> </trans-unit>
</body> </body>
</file> </file>

View File

@ -34,10 +34,6 @@ These fields specify if and which flows are linked on the form. The enrollment f
When enabled, any user identifier will be accepted as valid (as long as they match the correct format, i.e. when [User fields](#user-fields) is set to only allow Emails, then the identifier still needs to be an Email). The stage will succeed and the flow will continue to the next stage. Stages like the [Password stage](../password/index.md) and [Email stage](../email/index.mdx) are aware of this "pretend" user and will behave the same as if the user would exist. When enabled, any user identifier will be accepted as valid (as long as they match the correct format, i.e. when [User fields](#user-fields) is set to only allow Emails, then the identifier still needs to be an Email). The stage will succeed and the flow will continue to the next stage. Stages like the [Password stage](../password/index.md) and [Email stage](../email/index.mdx) are aware of this "pretend" user and will behave the same as if the user would exist.
## Enable "Remember me on this device":ak-version[2025.4]
When enabled, users will be given the option at login of having their username stored on the device. If selected, on future logins this stage will automatically fill in the username and fast-forward to the password field. Users will still have the options of clicking "Not you?" and going back to provide a different username or disable this feature.
## Source settings ## Source settings
Some sources (like the [OAuth Source](../../../../users-sources/sources/protocols/oauth/index.mdx) and [SAML Source](../../../../users-sources/sources/protocols/saml/index.md)) require user interaction. To make these sources available to users, they can be selected in the Identification stage settings, which will show them below the selected [user field](#user-fields). Some sources (like the [OAuth Source](../../../../users-sources/sources/protocols/oauth/index.mdx) and [SAML Source](../../../../users-sources/sources/protocols/saml/index.md)) require user interaction. To make these sources available to users, they can be selected in the Identification stage settings, which will show them below the selected [user field](#user-fields).

View File

@ -8,7 +8,7 @@ authentik provides several [standard policy types](./index.md#standard-policies)
We also document how to use a policy to [whitelist email domains](./expression/whitelist_email.md) and to [ensure unique email addresses](./expression/unique_email.md). We also document how to use a policy to [whitelist email domains](./expression/whitelist_email.md) and to [ensure unique email addresses](./expression/unique_email.md).
To learn more see also [bindings](../../add-secure-apps/flows-stages/bindings/index.md) and how to [bind policy bindings to a new application when the application is created](../../add-secure-apps/applications/manage_apps.mdx#instructions) (for example, to configure application-specific access). To learn more see also [bindings](../../add-secure-apps/flows-stages/bindings/index.md) and how to [bind policy bindings to a new application when yo create the application](../../add-secure-apps/applications/manage_apps.mdx#instructions) (for example, to configure application-specific access).
## Create a policy ## Create a policy

View File

@ -19,8 +19,6 @@ Previously, sessions were stored by default in the cache. Now, they are stored i
## New features ## New features
### Postgres pool
## Upgrading ## Upgrading
This release does not introduce any new requirements. You can follow the upgrade instructions below; for more detailed information about upgrading authentik, refer to our [Upgrade documentation](../../install-config/upgrade.mdx). This release does not introduce any new requirements. You can follow the upgrade instructions below; for more detailed information about upgrading authentik, refer to our [Upgrade documentation](../../install-config/upgrade.mdx).

View File

@ -4,14 +4,14 @@ sidebar_label: Actual Budget
support_level: community support_level: community
--- ---
import Tabs from "@theme/Tabs";
import TabItem from "@theme/TabItem";
## What is Actual Budget ## What is Actual Budget
> Actual Budget is a web-based financial management software. It helps users track and manage their income, expenses, and budgets in real time. The software compares actual spending with planned budgets to improve financial decisions. > Actual Budget is a web-based financial management software. It helps users track and manage their income, expenses, and budgets in real time.
> The software compares actual spending with planned budgets to improve financial decisions.
> >
> -- https://actualbudget.org/ > -- https://actualbudget.org/
>
> This guide explains how to configure Actual Budget to use authentik as the OAuth provider for logging in to the Web GUI.
## Preparation ## Preparation
@ -37,7 +37,7 @@ To support the integration of Actual Budget with authentik, you need to create a
- **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type. - **Choose a Provider type**: select **OAuth2/OpenID Connect** as the provider type.
- **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations. - **Configure the Provider**: provide a name (or accept the auto-provided name), the authorization flow to use for this provider, and the following required configurations.
- Note the **Client ID**,**Client Secret**, and **slug** values because they will be required later. - Note the **Client ID**,**Client Secret**, and **slug** values because they will be required later.
- Set a `Strict` redirect URI to <kbd>https://<em>actual.company</em>/openid/callback</kbd>. - Set a `Strict` redirect URI to <kbd>https://<em>actual.company</em>/openid/callback/</kbd>.
- Select any available signing key. Actual Budget only supports the RS256 algorithm. Be aware of this when choosing a signing key. - Select any available signing key. Actual Budget only supports the RS256 algorithm. Be aware of this when choosing a signing key.
- **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/flows-stages/bindings/) (policy, group, or user) to manage the listing and access to applications on a user's **My applications** page. - **Configure Bindings** _(optional)_: you can create a [binding](/docs/add-secure-apps/flows-stages/bindings/) (policy, group, or user) to manage the listing and access to applications on a user's **My applications** page.
@ -45,67 +45,33 @@ To support the integration of Actual Budget with authentik, you need to create a
## Actual Budget configuration ## Actual Budget configuration
<Tabs 1. Sign in to Actual Budget with a browser of your choice and access your budget by clicking on its name.
defaultValue="env"
values={[
{ label: 'With Environment Variables', value: 'env' },
{ label: 'By editing the JSON file', value: 'json' },
{ label: 'Using the UI', value: 'ui' },
]}>
<TabItem value="env">
You can configure OpenID Connect with Actual Budget by adding the following variables to your `.env` file.
```yaml showLineNumbers 2. Click your budget in the top-left corner to open the dropdown menu and select **Settings**.
ACTUAL_OPENID_DISCOVERY_URL=https://authentik.company/application/o/<your-application-slug>/
ACTUAL_OPENID_CLIENT_ID=Your Client ID from authentik
ACTUAL_OPENID_CLIENT_SECRET=Your Client Secret from authentik
ACTUAL_OPENID_SERVER_HOSTNAME=https://actual.company
```
</TabItem> 3. Scroll to the bottom and select **Show advanced settings**. Scroll again and select **I understand the risks, show experimental features**.
<TabItem value="json">
You can configure Actual Budget to authenticate users with OpenID Connect by modifying the `/data/config.json` file or it's equivalent specified by the `ACTUAL_DATA_DIR` environment variable. 4. To enable the option **OpenID authentication method** select the checkbox next to it.
```json showLineNumbers title="/data/config.json" 5. Scroll up to the new option **Authentication method...** and click **Start using OpenID**.
"openId": {
"issuer": "https://authentik.company/application/o/<your-application-slug>/",
"client_id": "<Client ID from authentik>",
"client_secret": "<Client Secret from authentik>",
"server_hostname": "https://actual.company",
"authMethod": "openid"
}
```
</TabItem> 6. Set the following values from the authentik provider:
<TabItem value="ui"> - Set **OpenID Provider** to **authentik**
- Set **OpenID provider URL** to https://_authentik.company_/application/o/_actual_/
Alternatively, it is possible to configure OpenID Connect via the UI. - Set **Client ID** to _client-id_
- Set **Client secret** to _client-secret_
1. Sign in to Actual Budget and select your budget by clicing its name.
2. In the top-left corner, click your budget name to open the dropdown and choose **Settings**.
3. Scroll down and select **Show advanced settings**, then enable **I understand the risks, show experimental features**.
4. Enable **OpenID authentication method**.
5. Scroll up and click **Start using OpenID** under the **Authentication method** section.
6. Fill in the following values:
- **OpenID Provider**: authentik
- **OpenID provider URL**: <kbd>https://<em>authentik.company</em>/application/o/<em>your-application-slug</em>/</kbd>
- **Client ID**: Enter the **Client ID** from authentik
- **Client Secret**: Enter the **Client Secret** from authentik
</TabItem>
</Tabs>
:::warning :::warning
The first user to log into Actual Budget via OpenID will become the owner and administrator with the highest privileges for the budget. You should also note that users are not created automatically in Actual Budget. The owner must manually add users. The first user to log into Actual Budget via OpenID will become the owner and administrator with the highest privileges for the budget. For more information on how to create additional users, see the Note below.
To do so, navigate to **Server online** > **User Directory**, and create users matching exiting authentik usernames. Then, grant access to the budget via the **User Access** tab.
::: :::
## Resources ## Test the login
- [Official Actual Budget documentation on OpenID Connect integration](https://actualbudget.org/docs/experimental/oauth-auth/) - Open a browser of your choice and navigate to https://_actual.company_.
- Select the OpenID login method in the dropdown menu and click **Sign in with OpenID**.
- You should be redirected to authentik (with the login flows you created), and then authentik will redirect you back to the https://_actual.company_ URL.
- If you are redirected back to the https://_actual.company_ URL and can see the budget file selection page, the setup was successful.
## Configuration verification :::info
Users are not automatically created when logging in with authentik. The owner must manually create each user in Actual Budget. To do so, click **Server online** at the top next to your name and select **User Directory**. Add a new user. The `Username` must match the one in authentik. You can now grant the new user access to your budget by clicking **Server online** next to your name at the top and selecting **User Access**.
To confirm that authentik is properly configured with Actual Budget, visit your Actual Budget installation, select the OpenID login method from the dropdown menu, and click **Sign in with OpenID**. :::

View File

@ -23,7 +23,7 @@ This documentation lists only the settings that you need to change from their de
## authentik configuration ## authentik configuration
To support the integration of AdventureLog with authentik, you need to create an application/provider pair in authentik. To support the integration of Adventure Log with authentik, you need to create an application/provider pair in authentik.
### Create an application and provider in authentik ### Create an application and provider in authentik
@ -42,22 +42,41 @@ To support the integration of AdventureLog with authentik, you need to create an
## AdventureLog configuration ## AdventureLog configuration
:::info AdventureLog documentation can be found here: https://adventurelog.app/docs/configuration/social_auth/authentik.html
`localhost` is unlikely to be a valid `server_url` because it refers to the server hosting AdventureLog, not authentik. Instead, use the IP address of the server running authentik or a domain name if available.
This configuration is done in the Admin Panel. Launch the panel by clicking your user avatar in the navbar, selecting **Settings**, and then clicking **Launch Admin Panel**. Make sure you are logged in as an administrator for this to work.
Alternatively, navigate to `/admin` on your AdventureLog server.
1. In the admin panel, scroll down to the **Social Accounts** section and click **Add** next to **Social applications**. Fill in the following fields:
- Provider: OpenID Connect
- Provider ID: authentik Client ID
- Name: authentik
- Client ID: authentik Client ID
- Secret Key: authentik Client Secret
- Key: _should be left blank_
- Settings: (make sure http/https is set correctly)
```json
{
"server_url": "https://authentik.company/application/o/[YOUR_SLUG]/"
}
```
- Sites: move over the sites you want to enable authentik on, usually `example.com` and `www.example.com` unless you renamed your sites.
:::warning
`localhost` is most likely not a valid `server_url` for authentik in this instance because `localhost` is the server running AdventureLog, not authentik. You should use the IP address of the server running authentik or the domain name if you have one.
::: :::
1. Log in to your AdventureLog installation as an administrator and launch the Admin Panel. To do so, click your **user avatar** in the navigation bar, select **Settings**, then click **Launch Admin Panel**. Alternatively, visit <kbd>https://<em>adventurelog.company</em>/admin</kbd>. 2. Save the configuration.
2. Scroll down to **Social Accounts** and click **Add**. Fill in the following fields:
- **Provider**: OpenID Connect Ensure that the authentik server is running and accessible by AdventureLog. Users should now be able to log in to AdventureLog using their authentik account.
- **Provider ID**: Enter the Client ID from authentik
- **Name**: `authentik` ## Configuration validation
- **Client ID**: Enter the Client ID from authentik
- **Secret Key**: Enter the Client Secret from authentik To validate the configuration, either link to an existing account as described below or naviage to the AdventureLog login page and click the **authentik** button to log in. You should be redirected to the authentik login page. After logging in, you should be redirected back to AdventureLog.
- **Key**: Leave this line blank
- Under **Settings**:
- **server_url**: <kbd><em>https://authentik.company</em>/application/o/<em>your-application-slug</em>/</kbd>
- **Sites**: move over the sites you want to enable authentik on, usually `example.com` and `www.example.com` unless you renamed your sites.
### Linking to Existing Account ### Linking to Existing Account
@ -72,11 +91,3 @@ Ensure the `https://adventurelog.company/accounts` path is routed to the backend
### authentik - No Permission ### authentik - No Permission
Launch your authentik dashboard as an admin and find the AdventureLog app. Click **More details** then **Edit**. In the admin interface, click **Test** under **Check Access**. If you get a 403 error, you need to grant the user the correct permissions. This can be done by going to the user's profile and adding the correct permissions. Launch your authentik dashboard as an admin and find the AdventureLog app. Click **More details** then **Edit**. In the admin interface, click **Test** under **Check Access**. If you get a 403 error, you need to grant the user the correct permissions. This can be done by going to the user's profile and adding the correct permissions.
## Resources
- [AdventureLog's official documentation](https://adventurelog.app/docs/configuration/social_auth/authentik.html)
## Configuration verification
To confirm authentik is correctly integrated with AdventureLog, log out and attempt to log back in using OpenID Connect by clicking the **authentik** button on the AdventureLog login page.

View File

@ -4,9 +4,6 @@ sidebar_label: Apache Guacamole™
support_level: authentik support_level: authentik
--- ---
import Tabs from "@theme/Tabs";
import TabItem from "@theme/TabItem";
## What is Apache Guacamole™ ## What is Apache Guacamole™
> Apache Guacamole is a clientless remote desktop gateway. It supports standard protocols like VNC, RDP, and SSH. > Apache Guacamole is a clientless remote desktop gateway. It supports standard protocols like VNC, RDP, and SSH.
@ -44,13 +41,12 @@ To support the integration of Apache Guacamole with authentik, you need to creat
3. Click **Submit** to save the new application and provider. 3. Click **Submit** to save the new application and provider.
## Apache Guacamole Configuration ## Guacamole configuration
It is recommended to create an admin account in Guacamole before configuring Single Sign-On to simplify the process. Create a user in Guacamole using the same username as in authentik and grant them admin permissions. This step is important to avoid losing access to the Guacamole admin settings, as you may need to revert your changes without it. It is recommended you configure an admin account in Guacamole before setting up SSO to make things easier. Create a user in Guacamole using the username of your user in authentik and give them admin permissions. Without this, you might lose access to the Guacamole admin settings and have to revert the settings below.
:::warning import Tabs from "@theme/Tabs";
You can configure Apache Guacamole to use either the `sub` or `preferred_username` as the UID field under `user-name-attribute`. When using `preferred_username` as the user identifier, ensure that the [**Allow users to change username** setting](https://docs.goauthentik.io/docs/sys-mgmt/settings#allow-users-to-change-username) is disabled to prevent authentication issues. The `sub` option uses a unique, stable identifier for the user, while `preferred_username` uses the username configured in authentik. import TabItem from "@theme/TabItem";
:::
<Tabs <Tabs
defaultValue="docker" defaultValue="docker"
@ -59,35 +55,29 @@ You can configure Apache Guacamole to use either the `sub` or `preferred_usernam
{ label: 'Standalone', value: 'standalone' }, { label: 'Standalone', value: 'standalone' },
]}> ]}>
<TabItem value="docker"> <TabItem value="docker">
Docker containers are typically configured using environment variables. To ensure proper integration, add the following variables to your `.env` file: The Docker containers are configured via environment variables. The following variables are required:
```yaml showLineNumbers ```yaml
OPENID_AUTHORIZATION_ENDPOINT=https://authentik.company/application/o/authorize/ OPENID_AUTHORIZATION_ENDPOINT: https://authentik.company/application/o/authorize/
OPENID_CLIENT_ID=<Client ID from authentik> OPENID_CLIENT_ID: # client ID from above
OPENID_ISSUER=https://authentik.company/application/o/<your-slug>/ OPENID_ISSUER: https://authentik.company/application/o/*Slug of the application from above*/
OPENID_JWKS_ENDPOINT=https://authentik.company/application/o/<your-slug>/jwks/ OPENID_JWKS_ENDPOINT: https://authentik.company/application/o/*Slug of the application from above*/jwks/
OPENID_REDIRECT_URI=https://guacamole.company/ # Must match Redirect URI in authentik OPENID_REDIRECT_URI: https://guacamole.company/ # This must match the redirect URI above
OPENID_USERNAME_CLAIM_TYPE=preferred_username OPENID_USERNAME_CLAIM_TYPE: preferred_username
``` ```
Additionally, ensure your `guacamole.properties` file (typically located in `/etc/guacamole/`) includes the following line. This setting allows environment variables to be evaluated before static configuration files:
```yaml
enable-environment-properties: true
```
</TabItem> </TabItem>
<TabItem value="standalone"> <TabItem value="standalone">
To set up Apache Guacamole in a standalone environment, you'll need to adjust the settings in the `guacamole.properties` file, usually found in the `/etc/guacamole/` directory. Add the following settings: Standalone Guacamole is configured using the `guacamole.properties` file. Add the following settings:
```yaml showLineNumbers title="/etc/guacamole/guacamole.properties" ```
openid-authorization-endpoint=https://authentik.company/application/o/authorize/ openid-authorization-endpoint=https://authentik.company/application/o/authorize/
openid-client-id=<Client ID from authentik> openid-client-id=# client ID from above
openid-issuer=https://authentik.company/application/o/<your-slug>/ openid-issuer=https://authentik.company/application/o/*Slug of the application from above*/
openid-jwks-endpoint=https://authentik.company/application/o/<your-slug>/jwks/ openid-jwks-endpoint=https://authentik.company/application/o/*Slug of the application from above*/jwks/
openid-redirect-uri=https://guacamole.company/ # This must match the Redirect URI set in authentik (Including trailing slash). openid-redirect-uri=https://guacamole.company/ # This must match the redirect URI above
openid-username-claim-type=preferred_username openid-username-claim-type=preferred_username
``` ```
</TabItem> </TabItem>
</Tabs> </Tabs>
@ -108,9 +98,9 @@ This section depends on the operating system hosting Apache Guacamole.
2. To add the certificate as trusted in `/etc/ssl/certs/ca-certificates.crt`, use the following command: 2. To add the certificate as trusted in `/etc/ssl/certs/ca-certificates.crt`, use the following command:
```shell ```shell
update-ca-certificates update-ca-certificates
``` ```
##### For _Synology_ systems: ##### For _Synology_ systems:
@ -118,80 +108,24 @@ This section depends on the operating system hosting Apache Guacamole.
2. To add the certificate as trusted in `/etc/ssl/certs/ca-certificates.crt`, use the following command: 2. To add the certificate as trusted in `/etc/ssl/certs/ca-certificates.crt`, use the following command:
```shell ```shell
update-ca-certificates.sh update-ca-certificates.sh
``` ```
#### Adding Certificate Authority certificate to `/opt/java/openjkd/jre/lib/security/cacerts` #### Adding Certificate Authority certificate to `/opt/java/openjkd/jre/lib/security/cacerts`
1. To export the certificate of the Certificate Authority, use the following command on the Certificate Authority host: 1. To export the certificate of the Certificate Authority, use the following command on the Certificate Authority host:
```shell ```shell
openssl pkcs12 -export -in <CA_certificate>.crt -inkey <CA_certificate>.key -out <CA_certificate>.p12 -passout pass:<password> openssl pkcs12 -export -in <CA_certificate>.crt -inkey <CA_certificate>.key -out <CA_certificate>.p12 -passout pass:<password>
``` ```
2. To import the certificate to the `/opt/java/openjdk/jre/lib/security/cacerts` keystore on the Apache Guacamole host, use the following command: 2. To import the certificate to the `/opt/java/openjdk/jre/lib/security/cacerts` keystore on the Apache Guacamole host, use the following command:
```shell ```shell
keytool -importkeystore -srckeystore <CA_certificate>.p12 -srcstoretype PKCS12 -keystore /opt/java/openjdk/jre/lib/security/cacerts -deststorepass <destination_store_password> -nopromt -srcstorepass <password> keytool -importkeystore -srckeystore <CA_certificate>.p12 -srcstoretype PKCS12 -keystore /opt/java/openjdk/jre/lib/security/cacerts -deststorepass <destination_store_password> -nopromt -srcstorepass <password>
``` ```
:::note :::note
More information on the keytool command can be found in the [Oracle documentation.](https://docs.oracle.com/en/java/javase/21/docs/specs/man/keytool.html) More information on the keytool command can be found in the [Oracle documentation.](https://docs.oracle.com/en/java/javase/21/docs/specs/man/keytool.html)
::: :::
### Self Signed Certificates
When using a self-signed certificate, it is necessary to incorporate the certificate of the corresponding Certificate Authority into both the `/etc/ssl/certs/ca-certificates.crt` file and the `/opt/java/openjkd/jre/lib/security/cacerts` keystore on your Apache Guacamole host. This ensures that the self-signed certificate is trusted by both the system and the Java runtime environment used by Guacamole.
#### Adding Certificate Authority certificate as trusted in `/etc/ssl/certs/ca-certificates.crt`
:::note
This section depends on the operating system hosting Apache Guacamole.
:::
##### For _Debian_ based operating systems:
1. Copy the certificate of the Certificate Authority (e.g. `<CA_certificate>.crt`) to the `/usr/local/share/ca-certificates/` directory on the Apache Guacamole host. Ensure that the file extension is `.crt`.
2. To add the certificate as trusted in `/etc/ssl/certs/ca-certificates.crt`, use the following command:
```shell
update-ca-certificates
```
##### For _Synology_ systems:
1. Copy the certificate of the Certificate Authority (e.g. `<CA_certificate>.crt`) to the `/usr/syno/etc/security-profile/ca-bundle-profile/ca-certificates/` directory on the Synology host. Ensure that the filetype is `.crt`.
2. To add the certificate as trusted in `/etc/ssl/certs/ca-certificates.crt`, use the following command:
```shell
update-ca-certificates.sh
```
#### Adding Certificate Authority certificate to `/opt/java/openjkd/jre/lib/security/cacerts`
1. To export the certificate of the Certificate Authority, use the following command on the Certificate Authority host:
```shell
openssl pkcs12 -export -in <CA_certificate>.crt -inkey <CA_certificate>.key -out <CA_certificate>.p12 -passout pass:<password>
```
2. To import the certificate to the `/opt/java/openjdk/jre/lib/security/cacerts` keystore on the Apache Guacamole host, use the following command:
```shell
keytool -importkeystore -srckeystore <CA_certificate>.p12 -srcstoretype PKCS12 -keystore /opt/java/openjdk/jre/lib/security/cacerts -deststorepass <destination_store_password> -nopromt -srcstorepass <password>
```
:::note
More information on the keytool command can be found in the [Oracle documentation.](https://docs.oracle.com/en/java/javase/21/docs/specs/man/keytool.html)
:::
## Resources
- [Apache Guacamole official documentation on OpenID Connect integrations](https://guacamole.apache.org/doc/gug/openid-auth.html#configuring-guacamole-for-single-sign-on-with-openid-connect)
## Configuration verification
To verify that authentik is correctly configured with Apache Guacamole, log out and log back in through authentik. You should notice a new button appearing at the bottom left of the login page.

View File

@ -46,6 +46,80 @@ Using the authentik Admin interface, navigate to **Directory** -> **Groups** and
After creating the groups, select a group, navigate to the **Users** tab, and manage its members by using the **Add existing user** and **Create user** buttons as needed. After creating the groups, select a group, navigate to the **Users** tab, and manage its members by using the **Add existing user** and **Create user** buttons as needed.
## Terraform provider
```hcl
data "authentik_flow" "default-provider-authorization-implicit-consent" {
slug = "default-provider-authorization-implicit-consent"
}
data "authentik_flow" "default-provider-invalidation" {
slug = "default-invalidation-flow"
}
data "authentik_property_mapping_provider_scope" "scope-email" {
name = "authentik default OAuth Mapping: OpenID 'email'"
}
data "authentik_property_mapping_provider_scope" "scope-profile" {
name = "authentik default OAuth Mapping: OpenID 'profile'"
}
data "authentik_property_mapping_provider_scope" "scope-openid" {
name = "authentik default OAuth Mapping: OpenID 'openid'"
}
data "authentik_certificate_key_pair" "generated" {
name = "authentik Self-signed Certificate"
}
resource "authentik_provider_oauth2" "argocd" {
name = "ArgoCD"
# Required. You can use the output of:
# $ openssl rand -hex 16
client_id = "my_client_id"
# Optional: will be generated if not provided
# client_secret = "my_client_secret"
authorization_flow = data.authentik_flow.default-provider-authorization-implicit_consent.id
invalidation_flow = data.authentik_flow.default-provider-invalidation.id
signing_key = data.authentik_certificate_key_pair.generated.id
allowed_redirect_uris = [
{
matching_mode = "strict",
url = "https://argocd.company/api/dex/callback",
},
{
matching_mode = "strict",
url = "http://localhost:8085/auth/callback",
}
]
property_mappings = [
data.authentik_property_mapping_provider_scope.scope-email.id,
data.authentik_property_mapping_provider_scope.scope-profile.id,
data.authentik_property_mapping_provider_scope.scope-openid.id,
]
}
resource "authentik_application" "argocd" {
name = "ArgoCD"
slug = "argocd"
protocol_provider = authentik_provider_oauth2.argocd.id
}
resource "authentik_group" "argocd_admins" {
name = "ArgoCD Admins"
}
resource "authentik_group" "argocd_viewers" {
name = "ArgoCD Viewers"
}
```
## ArgoCD Configuration ## ArgoCD Configuration
:::note :::note

View File

@ -16,6 +16,7 @@ The following placeholders are used in this guide:
- `arubaorchestrator.company` is the FQDN of the Aruba Orchestrator installation. - `arubaorchestrator.company` is the FQDN of the Aruba Orchestrator installation.
- `authentik.company` is the FQDN of the authentik installation. - `authentik.company` is the FQDN of the authentik installation.
- `SSL Certificate` is the name of the SSL certificate used to sign outgoing responses.
:::note :::note
This documentation lists only the settings that you need to change from their default values. Be aware that any changes other than those explicitly mentioned in this guide could cause issues accessing your application. This documentation lists only the settings that you need to change from their default values. Be aware that any changes other than those explicitly mentioned in this guide could cause issues accessing your application.

Some files were not shown because too many files have changed in this diff Show More