| @ -62,6 +62,7 @@ from authentik.core.api.utils import ( | |||||||
|     ModelSerializer, |     ModelSerializer, | ||||||
|     PassiveSerializer, |     PassiveSerializer, | ||||||
| ) | ) | ||||||
|  | from authentik.core.avatars import get_avatar | ||||||
| from authentik.core.middleware import ( | from authentik.core.middleware import ( | ||||||
|     SESSION_KEY_IMPERSONATE_ORIGINAL_USER, |     SESSION_KEY_IMPERSONATE_ORIGINAL_USER, | ||||||
|     SESSION_KEY_IMPERSONATE_USER, |     SESSION_KEY_IMPERSONATE_USER, | ||||||
| @ -81,7 +82,6 @@ from authentik.flows.exceptions import FlowNonApplicableException | |||||||
| from authentik.flows.models import FlowToken | from authentik.flows.models import FlowToken | ||||||
| from authentik.flows.planner import PLAN_CONTEXT_PENDING_USER, FlowPlanner | from authentik.flows.planner import PLAN_CONTEXT_PENDING_USER, FlowPlanner | ||||||
| from authentik.flows.views.executor import QS_KEY_TOKEN | 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.decorators import permission_required | ||||||
| from authentik.rbac.models import get_permission_choices | from authentik.rbac.models import get_permission_choices | ||||||
| from authentik.stages.email.models import EmailStage | from authentik.stages.email.models import EmailStage | ||||||
|  | |||||||
| @ -27,10 +27,10 @@ from structlog.stdlib import get_logger | |||||||
|  |  | ||||||
| from authentik.blueprints.models import ManagedModel | from authentik.blueprints.models import ManagedModel | ||||||
| from authentik.common.expression.exceptions import ControlFlowException | from authentik.common.expression.exceptions import ControlFlowException | ||||||
|  | from authentik.core.avatars import get_avatar | ||||||
| from authentik.core.expression.exceptions import PropertyMappingExpressionException | from authentik.core.expression.exceptions import PropertyMappingExpressionException | ||||||
| from authentik.core.types import UILoginButton, UserSettingSerializer | from authentik.core.types import UILoginButton, UserSettingSerializer | ||||||
| from authentik.crypto.generators import generate_id | 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.merge import MERGE_LIST_UNIQUE | ||||||
| from authentik.lib.models import ( | from authentik.lib.models import ( | ||||||
|     CreatedUpdatedModel, |     CreatedUpdatedModel, | ||||||
|  | |||||||
| @ -14,6 +14,7 @@ from rest_framework.request import Request | |||||||
| from sentry_sdk import start_span | from sentry_sdk import start_span | ||||||
| from structlog.stdlib import BoundLogger, get_logger | 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.core.models import Application, User | ||||||
| from authentik.flows.challenge import ( | from authentik.flows.challenge import ( | ||||||
|     AccessDeniedChallenge, |     AccessDeniedChallenge, | ||||||
| @ -28,7 +29,6 @@ from authentik.flows.challenge import ( | |||||||
| from authentik.flows.exceptions import StageInvalidException | from authentik.flows.exceptions import StageInvalidException | ||||||
| from authentik.flows.models import InvalidResponseAction | from authentik.flows.models import InvalidResponseAction | ||||||
| from authentik.flows.planner import PLAN_CONTEXT_APPLICATION, PLAN_CONTEXT_PENDING_USER | 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 | from authentik.lib.utils.reflection import class_to_path | ||||||
|  |  | ||||||
| if TYPE_CHECKING: | if TYPE_CHECKING: | ||||||
|  | |||||||
| @ -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") |  | ||||||
| @ -2,7 +2,8 @@ | |||||||
|  |  | ||||||
| from django.test import TestCase | 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): | class TestSentry(TestCase): | ||||||
|  | |||||||
							
								
								
									
										19
									
								
								authentik/lib/tests/test_views.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								authentik/lib/tests/test_views.py
									
									
									
									
									
										Normal file
									
								
							| @ -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) | ||||||
| @ -30,7 +30,7 @@ from tenant_schemas_celery.app import CeleryApp as TenantAwareCeleryApp | |||||||
|  |  | ||||||
| from authentik import get_full_version | from authentik import get_full_version | ||||||
| from authentik.lib.utils.errors import exception_to_string | 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. | # set the default Django settings module for the 'celery' program. | ||||||
| os.environ.setdefault("DJANGO_SETTINGS_MODULE", "authentik.root.settings") | 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) |     LOGGER.warning("Task failure", task_id=task_id.replace("-", ""), exc=exception) | ||||||
|     CTX_TASK_ID.set(...) |     CTX_TASK_ID.set(...) | ||||||
|     if before_send({}, {"exc_info": (None, exception, None)}) is not None: |     if not should_ignore_exception(exception): | ||||||
|         Event.new( |         Event.new( | ||||||
|             EventAction.SYSTEM_EXCEPTION, message=exception_to_string(exception), task_id=task_id |             EventAction.SYSTEM_EXCEPTION, message=exception_to_string(exception), task_id=task_id | ||||||
|         ).save() |         ).save() | ||||||
|  | |||||||
| @ -7,6 +7,9 @@ from tempfile import gettempdir | |||||||
| from django.test import TestCase | from django.test import TestCase | ||||||
| from django.urls import reverse | from django.urls import reverse | ||||||
|  |  | ||||||
|  | from authentik.core.models import Token, TokenIntents, UserTypes | ||||||
|  | from authentik.root.middleware import ClientIPMiddleware | ||||||
|  |  | ||||||
|  |  | ||||||
| class TestRoot(TestCase): | class TestRoot(TestCase): | ||||||
|     """Test root application""" |     """Test root application""" | ||||||
| @ -39,3 +42,64 @@ class TestRoot(TestCase): | |||||||
|     def test_monitoring_ready(self): |     def test_monitoring_ready(self): | ||||||
|         """Test ReadyView""" |         """Test ReadyView""" | ||||||
|         self.assertEqual(self.client.get(reverse("health-ready")).status_code, 200) |         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") | ||||||
|  | |||||||
| @ -15,6 +15,7 @@ from rest_framework.serializers import ValidationError | |||||||
| from sentry_sdk import start_span | from sentry_sdk import start_span | ||||||
|  |  | ||||||
| from authentik.core.api.utils import PassiveSerializer | from authentik.core.api.utils import PassiveSerializer | ||||||
|  | from authentik.core.avatars import DEFAULT_AVATAR | ||||||
| from authentik.core.models import Application, Source, User | from authentik.core.models import Application, Source, User | ||||||
| from authentik.events.utils import sanitize_item | from authentik.events.utils import sanitize_item | ||||||
| from authentik.flows.challenge import ( | 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.planner import PLAN_CONTEXT_PENDING_USER | ||||||
| from authentik.flows.stage import PLAN_CONTEXT_PENDING_USER_IDENTIFIER, ChallengeStageView | 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.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.reflection import all_subclasses | ||||||
| from authentik.lib.utils.urls import reverse_with_qs | from authentik.lib.utils.urls import reverse_with_qs | ||||||
| from authentik.root.middleware import ClientIPMiddleware | from authentik.root.middleware import ClientIPMiddleware | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user
	 Jens Langhammer
					Jens Langhammer