Skip to content

Commit

Permalink
sibling of c9036f8
Browse files Browse the repository at this point in the history
  • Loading branch information
BeryJu authored Nov 14, 2024
1 parent bcb91d2 commit 75ed417
Show file tree
Hide file tree
Showing 83 changed files with 4,445 additions and 19,180 deletions.
2 changes: 1 addition & 1 deletion .bumpversion.cfg
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[bumpversion]
current_version = 2024.10.1
current_version = 2024.10.2
tag = True
commit = True
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)(?:-(?P<rc_t>[a-zA-Z-]+)(?P<rc_n>[1-9]\\d*))?
Expand Down
2 changes: 1 addition & 1 deletion authentik/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from os import environ

__version__ = "2024.10.1"
__version__ = "2024.10.2"
ENV_GIT_HASH_KEY = "GIT_BUILD_HASH"


Expand Down
15 changes: 2 additions & 13 deletions authentik/core/api/users.py
Original file line number Diff line number Diff line change
Expand Up @@ -666,12 +666,7 @@ def recovery_email(self, request: Request, pk: int) -> Response:

@permission_required("authentik_core.impersonate")
@extend_schema(
request=inline_serializer(
"ImpersonationSerializer",
{
"reason": CharField(required=True),
},
),
request=OpenApiTypes.NONE,
responses={
"204": OpenApiResponse(description="Successfully started impersonation"),
"401": OpenApiResponse(description="Access denied"),
Expand All @@ -684,7 +679,6 @@ def impersonate(self, request: Request, pk: int) -> Response:
LOGGER.debug("User attempted to impersonate", user=request.user)
return Response(status=401)
user_to_be = self.get_object()
reason = request.data.get("reason", "")
# Check both object-level perms and global perms
if not request.user.has_perm(
"authentik_core.impersonate", user_to_be
Expand All @@ -694,16 +688,11 @@ def impersonate(self, request: Request, pk: int) -> Response:
if user_to_be.pk == self.request.user.pk:
LOGGER.debug("User attempted to impersonate themselves", user=request.user)
return Response(status=401)
if not reason and request.tenant.impersonation_require_reason:
LOGGER.debug(
"User attempted to impersonate without providing a reason", user=request.user
)
return Response(status=401)

request.session[SESSION_KEY_IMPERSONATE_ORIGINAL_USER] = request.user
request.session[SESSION_KEY_IMPERSONATE_USER] = user_to_be

Event.new(EventAction.IMPERSONATION_STARTED, reason=reason).from_http(request, user_to_be)
Event.new(EventAction.IMPERSONATION_STARTED).from_http(request, user_to_be)

return Response(status=201)

Expand Down
32 changes: 6 additions & 26 deletions authentik/core/tests/test_impersonation.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,7 @@ def test_impersonate_simple(self):
reverse(
"authentik_api:user-impersonate",
kwargs={"pk": self.other_user.pk},
),
data={"reason": "some reason"},
)
)

response = self.client.get(reverse("authentik_api:user-me"))
Expand All @@ -56,8 +55,7 @@ def test_impersonate_global(self):
reverse(
"authentik_api:user-impersonate",
kwargs={"pk": self.other_user.pk},
),
data={"reason": "some reason"},
)
)
self.assertEqual(response.status_code, 201)

Expand All @@ -77,8 +75,7 @@ def test_impersonate_scoped(self):
reverse(
"authentik_api:user-impersonate",
kwargs={"pk": self.other_user.pk},
),
data={"reason": "some reason"},
)
)
self.assertEqual(response.status_code, 201)

Expand All @@ -92,8 +89,7 @@ def test_impersonate_denied(self):
self.client.force_login(self.other_user)

response = self.client.post(
reverse("authentik_api:user-impersonate", kwargs={"pk": self.user.pk}),
data={"reason": "some reason"},
reverse("authentik_api:user-impersonate", kwargs={"pk": self.user.pk})
)
self.assertEqual(response.status_code, 403)

Expand All @@ -109,8 +105,7 @@ def test_impersonate_disabled(self):
self.client.force_login(self.user)

response = self.client.post(
reverse("authentik_api:user-impersonate", kwargs={"pk": self.other_user.pk}),
data={"reason": "some reason"},
reverse("authentik_api:user-impersonate", kwargs={"pk": self.other_user.pk})
)
self.assertEqual(response.status_code, 401)

Expand All @@ -123,22 +118,7 @@ def test_impersonate_self(self):
self.client.force_login(self.user)

response = self.client.post(
reverse("authentik_api:user-impersonate", kwargs={"pk": self.user.pk}),
data={"reason": "some reason"},
)
self.assertEqual(response.status_code, 401)

response = self.client.get(reverse("authentik_api:user-me"))
response_body = loads(response.content.decode())
self.assertEqual(response_body["user"]["username"], self.user.username)

def test_impersonate_reason_required(self):
"""test impersonation that user must provide reason"""
self.client.force_login(self.user)

response = self.client.post(
reverse("authentik_api:user-impersonate", kwargs={"pk": self.user.pk}),
data={"reason": ""},
reverse("authentik_api:user-impersonate", kwargs={"pk": self.user.pk})
)
self.assertEqual(response.status_code, 401)

Expand Down
2 changes: 1 addition & 1 deletion authentik/events/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ def default_event_duration():
"""Default duration an Event is saved.
This is used as a fallback when no brand is available"""
try:
tenant = get_current_tenant(only=["event_retention"])
tenant = get_current_tenant()
return now() + timedelta_from_string(tenant.event_retention)
except Tenant.DoesNotExist:
return now() + timedelta(days=365)
Expand Down
20 changes: 10 additions & 10 deletions authentik/sources/kerberos/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,14 @@
from typing import Any

import gssapi
import kadmin
import pglock
from django.db import connection, models
from django.db.models.fields import b64decode
from django.http import HttpRequest
from django.shortcuts import reverse
from django.templatetags.static import static
from django.utils.translation import gettext_lazy as _
from kadmin import KAdmin
from kadmin.exceptions import PyKAdminException
from rest_framework.serializers import Serializer
from structlog.stdlib import get_logger

Expand All @@ -31,8 +30,9 @@
LOGGER = get_logger()


# Creating kadmin connections is expensive. As such, this global is used to reuse
# existing kadmin connections instead of creating new ones
# python-kadmin leaks file descriptors. As such, this global is used to reuse
# existing kadmin connections instead of creating new ones, which results in less to no file
# descriptors leaks
_kadmin_connections: dict[str, Any] = {}


Expand Down Expand Up @@ -198,13 +198,13 @@ def krb5_conf_path(self) -> str | None:
conf_path.write_text(self.krb5_conf)
return str(conf_path)

def _kadmin_init(self) -> KAdmin | None:
def _kadmin_init(self) -> "kadmin.KAdmin | None":
# kadmin doesn't use a ccache for its connection
# as such, we don't need to create a separate ccache for each source
if not self.sync_principal:
return None
if self.sync_password:
return KAdmin.with_password(
return kadmin.init_with_password(
self.sync_principal,
self.sync_password,
)
Expand All @@ -215,18 +215,18 @@ def _kadmin_init(self) -> KAdmin | None:
keytab_path.touch(mode=0o600)
keytab_path.write_bytes(b64decode(self.sync_keytab))
keytab = f"FILE:{keytab_path}"
return KAdmin.with_keytab(
return kadmin.init_with_keytab(
self.sync_principal,
keytab,
)
if self.sync_ccache:
return KAdmin.with_ccache(
return kadmin.init_with_ccache(
self.sync_principal,
self.sync_ccache,
)
return None

def connection(self) -> KAdmin | None:
def connection(self) -> "kadmin.KAdmin | None":
"""Get kadmin connection"""
if str(self.pk) not in _kadmin_connections:
kadm = self._kadmin_init()
Expand All @@ -246,7 +246,7 @@ def check_connection(self) -> dict[str, str]:
status["status"] = "no connection"
return status
status["principal_exists"] = kadm.principal_exists(self.sync_principal)
except PyKAdminException as exc:
except kadmin.KAdminError as exc:
status["status"] = str(exc)
return status

Expand Down
4 changes: 2 additions & 2 deletions authentik/sources/kerberos/signals.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
"""authentik kerberos source signals"""

import kadmin
from django.db.models.signals import post_save
from django.dispatch import receiver
from kadmin.exceptions import PyKAdminException
from rest_framework.serializers import ValidationError
from structlog.stdlib import get_logger

Expand Down Expand Up @@ -48,7 +48,7 @@ def kerberos_sync_password(sender, user: User, password: str, **_):
source.connection().getprinc(user_source_connection.identifier).change_password(
password
)
except PyKAdminException as exc:
except kadmin.KAdminError as exc:
LOGGER.warning("failed to set Kerberos password", exc=exc, source=source)
Event.new(
EventAction.CONFIGURATION_ERROR,
Expand Down
6 changes: 3 additions & 3 deletions authentik/sources/kerberos/sync.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

from typing import Any

import kadmin
from django.core.exceptions import FieldError
from django.db import IntegrityError, transaction
from kadmin import KAdmin
from structlog.stdlib import BoundLogger, get_logger

from authentik.core.expression.exceptions import (
Expand All @@ -30,7 +30,7 @@ class KerberosSync:

_source: KerberosSource
_logger: BoundLogger
_connection: KAdmin
_connection: "kadmin.KAdmin"
mapper: SourceMapper
user_manager: PropertyMappingManager
group_manager: PropertyMappingManager
Expand Down Expand Up @@ -161,7 +161,7 @@ def sync(self) -> int:

user_count = 0
with Krb5ConfContext(self._source):
for principal in self._connection.list_principals(None):
for principal in self._connection.principals():
if self._handle_principal(principal):
user_count += 1
return user_count
1 change: 0 additions & 1 deletion authentik/sources/kerberos/tests/test_auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ def setUp(self):
)
self.user = User.objects.create(username=generate_id())
self.user.set_unusable_password()
self.user.save()
UserKerberosSourceConnection.objects.create(
source=self.source, user=self.user, identifier=self.realm.user_princ
)
Expand Down
3 changes: 0 additions & 3 deletions authentik/sources/kerberos/tests/test_spnego.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@

from base64 import b64decode, b64encode
from pathlib import Path
from sys import platform
from unittest import skipUnless

import gssapi
from django.urls import reverse
Expand Down Expand Up @@ -38,7 +36,6 @@ def test_api_read(self):
)
self.assertEqual(response.status_code, 200)

@skipUnless(platform.startswith("linux"), "Requires compatible GSSAPI implementation")
def test_source_login(self):
"""test login view"""
response = self.client.get(
Expand Down
2 changes: 1 addition & 1 deletion authentik/stages/authenticator_webauthn/mds/blob.jwt

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion authentik/tenants/api/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ class Meta:
"footer_links",
"gdpr_compliance",
"impersonation",
"impersonation_require_reason",
"default_token_duration",
"default_token_length",
]
Expand Down

This file was deleted.

4 changes: 0 additions & 4 deletions authentik/tenants/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,10 +85,6 @@ class Tenant(TenantMixin, SerializerModel):
impersonation = models.BooleanField(
help_text=_("Globally enable/disable impersonation."), default=True
)
impersonation_require_reason = models.BooleanField(
help_text=_("Require administrators to provide a reason for impersonating a user."),
default=True,
)
default_token_duration = models.TextField(
help_text=_("Default token duration"),
default=DEFAULT_TOKEN_DURATION,
Expand Down
6 changes: 2 additions & 4 deletions authentik/tenants/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,9 @@
from authentik.tenants.models import Tenant


def get_current_tenant(only: list[str] | None = None) -> Tenant:
def get_current_tenant() -> Tenant:
"""Get tenant for current request"""
if only is None:
only = []
return Tenant.objects.only(*only).get(schema_name=connection.schema_name)
return Tenant.objects.get(schema_name=connection.schema_name)


def get_unique_identifier() -> str:
Expand Down
2 changes: 1 addition & 1 deletion blueprints/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"$schema": "http://json-schema.org/draft-07/schema",
"$id": "https://goauthentik.io/blueprints/schema.json",
"type": "object",
"title": "authentik 2024.10.1 Blueprint schema",
"title": "authentik 2024.10.2 Blueprint schema",
"required": [
"version",
"entries"
Expand Down
4 changes: 2 additions & 2 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ services:
volumes:
- redis:/data
server:
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2024.10.1}
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2024.10.2}
restart: unless-stopped
command: server
environment:
Expand All @@ -52,7 +52,7 @@ services:
- postgresql
- redis
worker:
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2024.10.1}
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2024.10.2}
restart: unless-stopped
command: worker
environment:
Expand Down
6 changes: 3 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,10 @@ require (
github.com/spf13/cobra v1.8.1
github.com/stretchr/testify v1.9.0
github.com/wwt/guac v1.3.2
goauthentik.io/api/v3 v3.2024100.2
goauthentik.io/api/v3 v3.2024083.13
golang.org/x/exp v0.0.0-20230210204819-062eb4c674ab
golang.org/x/oauth2 v0.24.0
golang.org/x/sync v0.9.0
golang.org/x/oauth2 v0.23.0
golang.org/x/sync v0.8.0
gopkg.in/yaml.v2 v2.4.0
layeh.com/radius v0.0.0-20210819152912-ad72663a72ab
)
Expand Down
Loading

0 comments on commit 75ed417

Please sign in to comment.