From e28968c8962428e95edba0255402a0d80b5b3b6f Mon Sep 17 00:00:00 2001 From: Jens Langhammer Date: Sat, 10 May 2025 17:11:01 +0200 Subject: [PATCH] move more Signed-off-by: Jens Langhammer --- .../expression/tests.py} | 0 authentik/core/api/users.py | 2 +- authentik/{lib => core}/avatars.py | 0 authentik/core/models.py | 2 +- authentik/flows/stage.py | 2 +- authentik/lib/tests/test_http.py | 82 ------------------- authentik/lib/tests/test_sentry.py | 3 +- authentik/lib/tests/test_views.py | 19 +++++ authentik/root/celery.py | 4 +- authentik/root/tests.py | 64 +++++++++++++++ authentik/stages/identification/stage.py | 2 +- 11 files changed, 91 insertions(+), 89 deletions(-) rename authentik/{lib/tests/test_evaluator.py => common/expression/tests.py} (100%) rename authentik/{lib => core}/avatars.py (100%) delete mode 100644 authentik/lib/tests/test_http.py create mode 100644 authentik/lib/tests/test_views.py diff --git a/authentik/lib/tests/test_evaluator.py b/authentik/common/expression/tests.py similarity index 100% rename from authentik/lib/tests/test_evaluator.py rename to authentik/common/expression/tests.py diff --git a/authentik/core/api/users.py b/authentik/core/api/users.py index 6378965bf2..d54cf4268b 100644 --- a/authentik/core/api/users.py +++ b/authentik/core/api/users.py @@ -62,6 +62,7 @@ from authentik.core.api.utils import ( ModelSerializer, PassiveSerializer, ) +from authentik.core.avatars import get_avatar from authentik.core.middleware import ( SESSION_KEY_IMPERSONATE_ORIGINAL_USER, SESSION_KEY_IMPERSONATE_USER, @@ -81,7 +82,6 @@ from authentik.flows.exceptions import FlowNonApplicableException from authentik.flows.models import FlowToken from authentik.flows.planner import PLAN_CONTEXT_PENDING_USER, FlowPlanner from authentik.flows.views.executor import QS_KEY_TOKEN -from authentik.lib.avatars import get_avatar from authentik.rbac.decorators import permission_required from authentik.rbac.models import get_permission_choices from authentik.stages.email.models import EmailStage diff --git a/authentik/lib/avatars.py b/authentik/core/avatars.py similarity index 100% rename from authentik/lib/avatars.py rename to authentik/core/avatars.py diff --git a/authentik/core/models.py b/authentik/core/models.py index 04fbb297fe..aa153f88f3 100644 --- a/authentik/core/models.py +++ b/authentik/core/models.py @@ -27,10 +27,10 @@ from structlog.stdlib import get_logger from authentik.blueprints.models import ManagedModel from authentik.common.expression.exceptions import ControlFlowException +from authentik.core.avatars import get_avatar from authentik.core.expression.exceptions import PropertyMappingExpressionException from authentik.core.types import UILoginButton, UserSettingSerializer from authentik.crypto.generators import generate_id -from authentik.lib.avatars import get_avatar from authentik.lib.merge import MERGE_LIST_UNIQUE from authentik.lib.models import ( CreatedUpdatedModel, diff --git a/authentik/flows/stage.py b/authentik/flows/stage.py index 715a2aa52a..6c93836bc1 100644 --- a/authentik/flows/stage.py +++ b/authentik/flows/stage.py @@ -14,6 +14,7 @@ from rest_framework.request import Request from sentry_sdk import start_span from structlog.stdlib import BoundLogger, get_logger +from authentik.core.avatars import DEFAULT_AVATAR, get_avatar from authentik.core.models import Application, User from authentik.flows.challenge import ( AccessDeniedChallenge, @@ -28,7 +29,6 @@ from authentik.flows.challenge import ( from authentik.flows.exceptions import StageInvalidException from authentik.flows.models import InvalidResponseAction from authentik.flows.planner import PLAN_CONTEXT_APPLICATION, PLAN_CONTEXT_PENDING_USER -from authentik.lib.avatars import DEFAULT_AVATAR, get_avatar from authentik.lib.utils.reflection import class_to_path if TYPE_CHECKING: diff --git a/authentik/lib/tests/test_http.py b/authentik/lib/tests/test_http.py deleted file mode 100644 index 910993db49..0000000000 --- a/authentik/lib/tests/test_http.py +++ /dev/null @@ -1,82 +0,0 @@ -"""Test HTTP Helpers""" - -from django.test import RequestFactory, TestCase - -from authentik.core.models import Token, TokenIntents, UserTypes -from authentik.core.tests.utils import create_test_admin_user -from authentik.lib.views import bad_request_message -from authentik.root.middleware import ClientIPMiddleware - - -class TestHTTP(TestCase): - """Test HTTP Helpers""" - - def setUp(self) -> None: - self.user = create_test_admin_user() - self.factory = RequestFactory() - - def test_bad_request_message(self): - """test bad_request_message""" - request = self.factory.get("/") - self.assertEqual(bad_request_message(request, "foo").status_code, 400) - - def test_normal(self): - """Test normal request""" - request = self.factory.get("/") - self.assertEqual(ClientIPMiddleware.get_client_ip(request), "127.0.0.1") - - def test_forward_for(self): - """Test x-forwarded-for request""" - request = self.factory.get("/", HTTP_X_FORWARDED_FOR="127.0.0.2") - self.assertEqual(ClientIPMiddleware.get_client_ip(request), "127.0.0.2") - - def test_forward_for_invalid(self): - """Test invalid forward for""" - request = self.factory.get("/", HTTP_X_FORWARDED_FOR="foobar") - self.assertEqual(ClientIPMiddleware.get_client_ip(request), ClientIPMiddleware.default_ip) - - def test_fake_outpost(self): - """Test faked IP which is overridden by an outpost""" - token = Token.objects.create( - identifier="test", user=self.user, intent=TokenIntents.INTENT_API - ) - # Invalid, non-existent token - request = self.factory.get( - "/", - **{ - ClientIPMiddleware.outpost_remote_ip_header: "1.2.3.4", - ClientIPMiddleware.outpost_token_header: "abc", - }, - ) - self.assertEqual(ClientIPMiddleware.get_client_ip(request), "127.0.0.1") - # Invalid, user doesn't have permissions - request = self.factory.get( - "/", - **{ - ClientIPMiddleware.outpost_remote_ip_header: "1.2.3.4", - ClientIPMiddleware.outpost_token_header: token.key, - }, - ) - self.assertEqual(ClientIPMiddleware.get_client_ip(request), "127.0.0.1") - # Invalid, not a real IP - self.user.type = UserTypes.INTERNAL_SERVICE_ACCOUNT - self.user.save() - request = self.factory.get( - "/", - **{ - ClientIPMiddleware.outpost_remote_ip_header: "foobar", - ClientIPMiddleware.outpost_token_header: token.key, - }, - ) - self.assertEqual(ClientIPMiddleware.get_client_ip(request), "127.0.0.1") - # Valid - self.user.type = UserTypes.INTERNAL_SERVICE_ACCOUNT - self.user.save() - request = self.factory.get( - "/", - **{ - ClientIPMiddleware.outpost_remote_ip_header: "1.2.3.4", - ClientIPMiddleware.outpost_token_header: token.key, - }, - ) - self.assertEqual(ClientIPMiddleware.get_client_ip(request), "1.2.3.4") diff --git a/authentik/lib/tests/test_sentry.py b/authentik/lib/tests/test_sentry.py index 5822efad8c..a05abba0fd 100644 --- a/authentik/lib/tests/test_sentry.py +++ b/authentik/lib/tests/test_sentry.py @@ -2,7 +2,8 @@ from django.test import TestCase -from authentik.common.exceptions import NotReportedException, before_send +from authentik.common.exceptions import NotReportedException +from authentik.root.sentry import before_send class TestSentry(TestCase): diff --git a/authentik/lib/tests/test_views.py b/authentik/lib/tests/test_views.py new file mode 100644 index 0000000000..73b06c1fd3 --- /dev/null +++ b/authentik/lib/tests/test_views.py @@ -0,0 +1,19 @@ +"""Test HTTP Helpers""" + +from django.test import RequestFactory, TestCase + +from authentik.core.tests.utils import create_test_admin_user +from authentik.lib.views import bad_request_message + + +class TestViews(TestCase): + """Test Views Helpers""" + + def setUp(self) -> None: + self.user = create_test_admin_user() + self.factory = RequestFactory() + + def test_bad_request_message(self): + """test bad_request_message""" + request = self.factory.get("/") + self.assertEqual(bad_request_message(request, "foo").status_code, 400) diff --git a/authentik/root/celery.py b/authentik/root/celery.py index b1d4699807..25e17a5b83 100644 --- a/authentik/root/celery.py +++ b/authentik/root/celery.py @@ -30,7 +30,7 @@ from tenant_schemas_celery.app import CeleryApp as TenantAwareCeleryApp from authentik import get_full_version from authentik.lib.utils.errors import exception_to_string -from authentik.root.sentry import before_send +from authentik.root.sentry import should_ignore_exception # set the default Django settings module for the 'celery' program. os.environ.setdefault("DJANGO_SETTINGS_MODULE", "authentik.root.settings") @@ -83,7 +83,7 @@ def task_error_hook(task_id: str, exception: Exception, traceback, *args, **kwar LOGGER.warning("Task failure", task_id=task_id.replace("-", ""), exc=exception) CTX_TASK_ID.set(...) - if before_send({}, {"exc_info": (None, exception, None)}) is not None: + if not should_ignore_exception(exception): Event.new( EventAction.SYSTEM_EXCEPTION, message=exception_to_string(exception), task_id=task_id ).save() diff --git a/authentik/root/tests.py b/authentik/root/tests.py index 175caa8d99..984edff36c 100644 --- a/authentik/root/tests.py +++ b/authentik/root/tests.py @@ -7,6 +7,9 @@ from tempfile import gettempdir from django.test import TestCase from django.urls import reverse +from authentik.core.models import Token, TokenIntents, UserTypes +from authentik.root.middleware import ClientIPMiddleware + class TestRoot(TestCase): """Test root application""" @@ -39,3 +42,64 @@ class TestRoot(TestCase): def test_monitoring_ready(self): """Test ReadyView""" self.assertEqual(self.client.get(reverse("health-ready")).status_code, 200) + + def test_normal(self): + """Test normal request""" + request = self.factory.get("/") + self.assertEqual(ClientIPMiddleware.get_client_ip(request), "127.0.0.1") + + def test_forward_for(self): + """Test x-forwarded-for request""" + request = self.factory.get("/", HTTP_X_FORWARDED_FOR="127.0.0.2") + self.assertEqual(ClientIPMiddleware.get_client_ip(request), "127.0.0.2") + + def test_forward_for_invalid(self): + """Test invalid forward for""" + request = self.factory.get("/", HTTP_X_FORWARDED_FOR="foobar") + self.assertEqual(ClientIPMiddleware.get_client_ip(request), ClientIPMiddleware.default_ip) + + def test_fake_outpost(self): + """Test faked IP which is overridden by an outpost""" + token = Token.objects.create( + identifier="test", user=self.user, intent=TokenIntents.INTENT_API + ) + # Invalid, non-existent token + request = self.factory.get( + "/", + **{ + ClientIPMiddleware.outpost_remote_ip_header: "1.2.3.4", + ClientIPMiddleware.outpost_token_header: "abc", + }, + ) + self.assertEqual(ClientIPMiddleware.get_client_ip(request), "127.0.0.1") + # Invalid, user doesn't have permissions + request = self.factory.get( + "/", + **{ + ClientIPMiddleware.outpost_remote_ip_header: "1.2.3.4", + ClientIPMiddleware.outpost_token_header: token.key, + }, + ) + self.assertEqual(ClientIPMiddleware.get_client_ip(request), "127.0.0.1") + # Invalid, not a real IP + self.user.type = UserTypes.INTERNAL_SERVICE_ACCOUNT + self.user.save() + request = self.factory.get( + "/", + **{ + ClientIPMiddleware.outpost_remote_ip_header: "foobar", + ClientIPMiddleware.outpost_token_header: token.key, + }, + ) + self.assertEqual(ClientIPMiddleware.get_client_ip(request), "127.0.0.1") + # Valid + self.user.type = UserTypes.INTERNAL_SERVICE_ACCOUNT + self.user.save() + request = self.factory.get( + "/", + **{ + ClientIPMiddleware.outpost_remote_ip_header: "1.2.3.4", + ClientIPMiddleware.outpost_token_header: token.key, + }, + ) + self.assertEqual(ClientIPMiddleware.get_client_ip(request), "1.2.3.4") diff --git a/authentik/stages/identification/stage.py b/authentik/stages/identification/stage.py index 8e2ea8a596..9e3a58c8fb 100644 --- a/authentik/stages/identification/stage.py +++ b/authentik/stages/identification/stage.py @@ -15,6 +15,7 @@ from rest_framework.serializers import ValidationError from sentry_sdk import start_span from authentik.core.api.utils import PassiveSerializer +from authentik.core.avatars import DEFAULT_AVATAR from authentik.core.models import Application, Source, User from authentik.events.utils import sanitize_item from authentik.flows.challenge import ( @@ -26,7 +27,6 @@ from authentik.flows.models import FlowDesignation from authentik.flows.planner import PLAN_CONTEXT_PENDING_USER from authentik.flows.stage import PLAN_CONTEXT_PENDING_USER_IDENTIFIER, ChallengeStageView from authentik.flows.views.executor import SESSION_KEY_APPLICATION_PRE, SESSION_KEY_GET -from authentik.lib.avatars import DEFAULT_AVATAR from authentik.lib.utils.reflection import all_subclasses from authentik.lib.utils.urls import reverse_with_qs from authentik.root.middleware import ClientIPMiddleware