Skip to content

Commit

Permalink
Merge branch 'main' into web/maint/move-to-wireit
Browse files Browse the repository at this point in the history
* main: (25 commits)
  website/docs: add link from Install docs to Enterprise docs (#10827)
  website/docs: new upgrade page (#10742)
  stages/authenticator: actually update last_used (#10813)
  sources/ldap: Add enabled filter for ldap_password_validate signal (#10823)
  web: bump API Client version (#10821)
  sources/plex: add property mappings (#10772)
  core: bump goauthentik.io/api/v3 from 3.2024063.2 to 3.2024063.5 (#10817)
  web: bump the wdio group across 2 directories with 4 updates (#10818)
  web: bump chromedriver from 127.0.1 to 127.0.2 in /tests/wdio (#10819)
  web: update to ESLint 9 (#10812)
  website/docs: add source property mappings, rework provider property mappings (#10652)
  web/admin: refactor property mappings forms (#10810)
  web: bump API Client version (#10811)
  sources/saml: Basic support for EncryptedAssertion element. (#10099)
  web: bump API Client version (#10809)
  sources: add property mappings for all oauth and saml sources (#8771)
  web: bump API Client version (#10808)
  stages/authenticator: add created, last_updated and last_used metadata (#10636)
  providers/proxy: avoid erroring on logout with session_id is None (#9119)
  core: bump google-api-python-client from 2.139.0 to 2.140.0 (#10802)
  ...
  • Loading branch information
kensternberg-authentik committed Aug 8, 2024
2 parents 1078f1b + 911382f commit 9a57747
Show file tree
Hide file tree
Showing 173 changed files with 8,784 additions and 29,825 deletions.
2 changes: 2 additions & 0 deletions authentik/blueprints/v1/importer.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
from authentik.blueprints.v1.meta.registry import BaseMetaModel, registry
from authentik.core.models import (
AuthenticatedSession,
GroupSourceConnection,
PropertyMapping,
Provider,
Source,
Expand Down Expand Up @@ -91,6 +92,7 @@ def excluded_models() -> list[type[Model]]:
Source,
PropertyMapping,
UserSourceConnection,
GroupSourceConnection,
Stage,
OutpostServiceConnection,
Policy,
Expand Down
11 changes: 10 additions & 1 deletion authentik/core/api/devices.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,13 @@

from drf_spectacular.types import OpenApiTypes
from drf_spectacular.utils import OpenApiParameter, extend_schema
from rest_framework.fields import BooleanField, CharField, IntegerField, SerializerMethodField
from rest_framework.fields import (
BooleanField,
CharField,
DateTimeField,
IntegerField,
SerializerMethodField,
)
from rest_framework.permissions import IsAdminUser, IsAuthenticated
from rest_framework.request import Request
from rest_framework.response import Response
Expand All @@ -20,6 +26,9 @@ class DeviceSerializer(MetaNameSerializer):
name = CharField()
type = SerializerMethodField()
confirmed = BooleanField()
created = DateTimeField(read_only=True)
last_updated = DateTimeField(read_only=True)
last_used = DateTimeField(read_only=True, allow_null=True)

def get_type(self, instance: Device) -> str:
"""Get type of device"""
Expand Down
42 changes: 41 additions & 1 deletion authentik/core/api/sources.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
from authentik.core.api.object_types import TypesMixin
from authentik.core.api.used_by import UsedByMixin
from authentik.core.api.utils import MetaNameSerializer, ModelSerializer
from authentik.core.models import Source, UserSourceConnection
from authentik.core.models import GroupSourceConnection, Source, UserSourceConnection
from authentik.core.types import UserSettingSerializer
from authentik.lib.utils.file import (
FilePathSerializer,
Expand Down Expand Up @@ -194,3 +194,43 @@ class UserSourceConnectionViewSet(
search_fields = ["source__slug"]
filter_backends = [OwnerFilter, DjangoFilterBackend, OrderingFilter, SearchFilter]
ordering = ["source__slug", "pk"]


class GroupSourceConnectionSerializer(SourceSerializer):
"""Group Source Connection Serializer"""

source = SourceSerializer(read_only=True)

class Meta:
model = GroupSourceConnection
fields = [
"pk",
"group",
"source",
"identifier",
"created",
]
extra_kwargs = {
"group": {"read_only": True},
"identifier": {"read_only": True},
"created": {"read_only": True},
}


class GroupSourceConnectionViewSet(
mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
UsedByMixin,
mixins.ListModelMixin,
GenericViewSet,
):
"""Group-source connection Viewset"""

queryset = GroupSourceConnection.objects.all()
serializer_class = GroupSourceConnectionSerializer
permission_classes = [OwnerSuperuserPermissions]
filterset_fields = ["group", "source__slug"]
search_fields = ["source__slug"]
filter_backends = [OwnerFilter, DjangoFilterBackend, OrderingFilter, SearchFilter]
ordering = ["source__slug", "pk"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# Generated by Django 5.0.7 on 2024-08-01 18:52

import django.db.models.deletion
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("authentik_core", "0038_source_authentik_c_enabled_d72365_idx"),
]

operations = [
migrations.AddField(
model_name="source",
name="group_matching_mode",
field=models.TextField(
choices=[
("identifier", "Use the source-specific identifier"),
(
"name_link",
"Link to a group with identical name. Can have security implications when a group name is used with another source.",
),
(
"name_deny",
"Use the group name, but deny enrollment when the name already exists.",
),
],
default="identifier",
help_text="How the source determines if an existing group should be used or a new group created.",
),
),
migrations.AlterField(
model_name="group",
name="name",
field=models.TextField(verbose_name="name"),
),
migrations.CreateModel(
name="GroupSourceConnection",
fields=[
(
"id",
models.AutoField(
auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
),
),
("created", models.DateTimeField(auto_now_add=True)),
("last_updated", models.DateTimeField(auto_now=True)),
("identifier", models.TextField()),
(
"group",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE, to="authentik_core.group"
),
),
(
"source",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE, to="authentik_core.source"
),
),
],
options={
"unique_together": {("group", "source")},
},
),
]
44 changes: 43 additions & 1 deletion authentik/core/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ class Group(SerializerModel, AttributesMixin):

group_uuid = models.UUIDField(primary_key=True, editable=False, default=uuid4)

name = models.CharField(_("name"), max_length=80)
name = models.TextField(_("name"))
is_superuser = models.BooleanField(
default=False, help_text=_("Users added to this group will be superusers.")
)
Expand Down Expand Up @@ -583,6 +583,19 @@ class SourceUserMatchingModes(models.TextChoices):
)


class SourceGroupMatchingModes(models.TextChoices):
"""Different modes a source can handle new/returning groups"""

IDENTIFIER = "identifier", _("Use the source-specific identifier")
NAME_LINK = "name_link", _(
"Link to a group with identical name. Can have security implications "
"when a group name is used with another source."
)
NAME_DENY = "name_deny", _(
"Use the group name, but deny enrollment when the name already exists."
)


class Source(ManagedModel, SerializerModel, PolicyBindingModel):
"""Base Authentication source, i.e. an OAuth Provider, SAML Remote or LDAP Server"""

Expand Down Expand Up @@ -632,6 +645,14 @@ class Source(ManagedModel, SerializerModel, PolicyBindingModel):
"a new user enrolled."
),
)
group_matching_mode = models.TextField(
choices=SourceGroupMatchingModes.choices,
default=SourceGroupMatchingModes.IDENTIFIER,
help_text=_(
"How the source determines if an existing group should be used or "
"a new group created."
),
)

objects = InheritanceManager()

Expand Down Expand Up @@ -727,6 +748,27 @@ class Meta:
unique_together = (("user", "source"),)


class GroupSourceConnection(SerializerModel, CreatedUpdatedModel):
"""Connection between Group and Source."""

group = models.ForeignKey(Group, on_delete=models.CASCADE)
source = models.ForeignKey(Source, on_delete=models.CASCADE)
identifier = models.TextField()

objects = InheritanceManager()

@property
def serializer(self) -> type[Serializer]:
"""Get serializer for this model"""
raise NotImplementedError

def __str__(self) -> str:
return f"Group-source connection (group={self.group_id}, source={self.source_id})"

class Meta:
unique_together = (("group", "source"),)


class ExpiringModel(models.Model):
"""Base Model which can expire, and is automatically cleaned up."""

Expand Down
2 changes: 2 additions & 0 deletions authentik/core/signals.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ def user_logged_in_session(sender, request: HttpRequest, user: User, **_):
@receiver(user_logged_out)
def user_logged_out_session(sender, request: HttpRequest, user: User, **_):
"""Delete AuthenticatedSession if it exists"""
if not request.session or not request.session.session_key:
return
AuthenticatedSession.objects.filter(session_key=request.session.session_key).delete()


Expand Down
Loading

0 comments on commit 9a57747

Please sign in to comment.