From bd54d034e1c48dcb8f2b01bf2221d3faeff0810e Mon Sep 17 00:00:00 2001 From: Jens Langhammer Date: Thu, 1 Jun 2023 13:12:02 +0200 Subject: [PATCH] ATH-01-001: resolve path and check start before loading blueprints This is even less of an issue since 411ef239f63e4d3beacd8297d4be54b29fb30127, since with that commit we only allow files that the listing returns Signed-off-by: Jens Langhammer --- authentik/blueprints/models.py | 4 ++- authentik/blueprints/tests/test_models.py | 33 ++++-------------- .../tests/test_serializer_models.py | 34 +++++++++++++++++++ 3 files changed, 44 insertions(+), 27 deletions(-) create mode 100644 authentik/blueprints/tests/test_serializer_models.py diff --git a/authentik/blueprints/models.py b/authentik/blueprints/models.py index 130b13264..cea1c0966 100644 --- a/authentik/blueprints/models.py +++ b/authentik/blueprints/models.py @@ -82,7 +82,9 @@ class BlueprintInstance(SerializerModel, ManagedModel, CreatedUpdatedModel): def retrieve_file(self) -> str: """Get blueprint from path""" try: - full_path = Path(CONFIG.y("blueprints_dir")).joinpath(Path(self.path)) + full_path = Path(CONFIG.y("blueprints_dir")).joinpath(Path(self.path)).resolve() + if not str(full_path).startswith(CONFIG.y("blueprints_dir")): + raise BlueprintRetrievalFailed("Invalid blueprint path") with full_path.open("r", encoding="utf-8") as _file: return _file.read() except (IOError, OSError) as exc: diff --git a/authentik/blueprints/tests/test_models.py b/authentik/blueprints/tests/test_models.py index 718caa502..2c04b64ef 100644 --- a/authentik/blueprints/tests/test_models.py +++ b/authentik/blueprints/tests/test_models.py @@ -1,34 +1,15 @@ """authentik managed models tests""" -from typing import Callable, Type - -from django.apps import apps from django.test import TestCase -from authentik.blueprints.v1.importer import is_model_allowed -from authentik.lib.models import SerializerModel +from authentik.blueprints.models import BlueprintInstance, BlueprintRetrievalFailed +from authentik.lib.generators import generate_id class TestModels(TestCase): """Test Models""" - -def serializer_tester_factory(test_model: Type[SerializerModel]) -> Callable: - """Test serializer""" - - def tester(self: TestModels): - if test_model._meta.abstract: # pragma: no cover - return - model_class = test_model() - self.assertTrue(isinstance(model_class, SerializerModel)) - self.assertIsNotNone(model_class.serializer) - - return tester - - -for app in apps.get_app_configs(): - if not app.label.startswith("authentik"): - continue - for model in app.get_models(): - if not is_model_allowed(model): - continue - setattr(TestModels, f"test_{app.label}_{model.__name__}", serializer_tester_factory(model)) + def test_retrieve_file(self): + """Test retrieve_file""" + instance = BlueprintInstance.objects.create(name=generate_id(), path="../etc/hosts") + with self.assertRaises(BlueprintRetrievalFailed): + instance.retrieve() diff --git a/authentik/blueprints/tests/test_serializer_models.py b/authentik/blueprints/tests/test_serializer_models.py new file mode 100644 index 000000000..718caa502 --- /dev/null +++ b/authentik/blueprints/tests/test_serializer_models.py @@ -0,0 +1,34 @@ +"""authentik managed models tests""" +from typing import Callable, Type + +from django.apps import apps +from django.test import TestCase + +from authentik.blueprints.v1.importer import is_model_allowed +from authentik.lib.models import SerializerModel + + +class TestModels(TestCase): + """Test Models""" + + +def serializer_tester_factory(test_model: Type[SerializerModel]) -> Callable: + """Test serializer""" + + def tester(self: TestModels): + if test_model._meta.abstract: # pragma: no cover + return + model_class = test_model() + self.assertTrue(isinstance(model_class, SerializerModel)) + self.assertIsNotNone(model_class.serializer) + + return tester + + +for app in apps.get_app_configs(): + if not app.label.startswith("authentik"): + continue + for model in app.get_models(): + if not is_model_allowed(model): + continue + setattr(TestModels, f"test_{app.label}_{model.__name__}", serializer_tester_factory(model))