From 73d7b5f110caab64a896ca8a322933d51153072b Mon Sep 17 00:00:00 2001
From: Jens L
Date: Tue, 14 Mar 2023 17:13:03 +0100
Subject: [PATCH] root: add common fixture loader (#4946)
Signed-off-by: Jens Langhammer
---
.editorconfig | 4 +-
authentik/blueprints/tests/__init__.py | 11 ---
authentik/blueprints/tests/test_v1.py | 8 +--
.../blueprints/tests/test_v1_conditions.py | 6 +-
authentik/blueprints/tests/test_v1_state.py | 10 +--
authentik/lib/tests/utils.py | 18 +++++
authentik/lib/utils/http.py | 12 ++--
authentik/providers/saml/tests/test_api.py | 2 +-
.../providers/saml/tests/test_metadata.py | 9 +--
.../saml/tests/fixtures/response_error.xml | 10 +++
.../saml/tests/fixtures/response_success.xml | 40 +++++++++++
authentik/sources/saml/tests/test_response.py | 70 ++++---------------
web/src/admin/users/UserForm.ts | 16 ++---
13 files changed, 113 insertions(+), 103 deletions(-)
create mode 100644 authentik/sources/saml/tests/fixtures/response_error.xml
create mode 100644 authentik/sources/saml/tests/fixtures/response_success.xml
diff --git a/.editorconfig b/.editorconfig
index e12dc6e50..2a5b1f870 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -7,8 +7,8 @@ charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
-[html]
+[*.html]
indent_size = 2
-[yaml]
+[*.{yaml,yml}]
indent_size = 2
diff --git a/authentik/blueprints/tests/__init__.py b/authentik/blueprints/tests/__init__.py
index 4f62d668b..8b39ca6dd 100644
--- a/authentik/blueprints/tests/__init__.py
+++ b/authentik/blueprints/tests/__init__.py
@@ -1,6 +1,5 @@
"""Blueprint helpers"""
from functools import wraps
-from pathlib import Path
from typing import Callable
from django.apps import apps
@@ -45,13 +44,3 @@ def reconcile_app(app_name: str):
return wrapper
return wrapper_outer
-
-
-def load_yaml_fixture(path: str, **kwargs) -> str:
- """Load yaml fixture, optionally formatting it with kwargs"""
- with open(Path(__file__).resolve().parent / Path(path), "r", encoding="utf-8") as _fixture:
- fixture = _fixture.read()
- try:
- return fixture % kwargs
- except TypeError:
- return fixture
diff --git a/authentik/blueprints/tests/test_v1.py b/authentik/blueprints/tests/test_v1.py
index b5f6a252a..4679de909 100644
--- a/authentik/blueprints/tests/test_v1.py
+++ b/authentik/blueprints/tests/test_v1.py
@@ -3,12 +3,12 @@ from os import environ
from django.test import TransactionTestCase
-from authentik.blueprints.tests import load_yaml_fixture
from authentik.blueprints.v1.exporter import FlowExporter
from authentik.blueprints.v1.importer import Importer, transaction_rollback
from authentik.core.models import Group
from authentik.flows.models import Flow, FlowDesignation, FlowStageBinding
from authentik.lib.generators import generate_id
+from authentik.lib.tests.utils import load_fixture
from authentik.policies.expression.models import ExpressionPolicy
from authentik.policies.models import PolicyBinding
from authentik.sources.oauth.models import OAuthSource
@@ -113,14 +113,14 @@ class TestBlueprintsV1(TransactionTestCase):
"""Test export and import it twice"""
count_initial = Prompt.objects.filter(field_key="username").count()
- importer = Importer(load_yaml_fixture("fixtures/static_prompt_export.yaml"))
+ importer = Importer(load_fixture("fixtures/static_prompt_export.yaml"))
self.assertTrue(importer.validate()[0])
self.assertTrue(importer.apply())
count_before = Prompt.objects.filter(field_key="username").count()
self.assertEqual(count_initial + 1, count_before)
- importer = Importer(load_yaml_fixture("fixtures/static_prompt_export.yaml"))
+ importer = Importer(load_fixture("fixtures/static_prompt_export.yaml"))
self.assertTrue(importer.apply())
self.assertEqual(Prompt.objects.filter(field_key="username").count(), count_before)
@@ -130,7 +130,7 @@ class TestBlueprintsV1(TransactionTestCase):
ExpressionPolicy.objects.filter(name="foo-bar-baz-qux").delete()
Group.objects.filter(name="test").delete()
environ["foo"] = generate_id()
- importer = Importer(load_yaml_fixture("fixtures/tags.yaml"), {"bar": "baz"})
+ importer = Importer(load_fixture("fixtures/tags.yaml"), {"bar": "baz"})
self.assertTrue(importer.validate()[0])
self.assertTrue(importer.apply())
policy = ExpressionPolicy.objects.filter(name="foo-bar-baz-qux").first()
diff --git a/authentik/blueprints/tests/test_v1_conditions.py b/authentik/blueprints/tests/test_v1_conditions.py
index 02d657303..3914e19dd 100644
--- a/authentik/blueprints/tests/test_v1_conditions.py
+++ b/authentik/blueprints/tests/test_v1_conditions.py
@@ -1,10 +1,10 @@
"""Test blueprints v1"""
from django.test import TransactionTestCase
-from authentik.blueprints.tests import load_yaml_fixture
from authentik.blueprints.v1.importer import Importer
from authentik.flows.models import Flow
from authentik.lib.generators import generate_id
+from authentik.lib.tests.utils import load_fixture
class TestBlueprintsV1Conditions(TransactionTestCase):
@@ -14,7 +14,7 @@ class TestBlueprintsV1Conditions(TransactionTestCase):
"""Test conditions fulfilled"""
flow_slug1 = generate_id()
flow_slug2 = generate_id()
- import_yaml = load_yaml_fixture(
+ import_yaml = load_fixture(
"fixtures/conditions_fulfilled.yaml", id1=flow_slug1, id2=flow_slug2
)
@@ -31,7 +31,7 @@ class TestBlueprintsV1Conditions(TransactionTestCase):
"""Test conditions not fulfilled"""
flow_slug1 = generate_id()
flow_slug2 = generate_id()
- import_yaml = load_yaml_fixture(
+ import_yaml = load_fixture(
"fixtures/conditions_not_fulfilled.yaml", id1=flow_slug1, id2=flow_slug2
)
diff --git a/authentik/blueprints/tests/test_v1_state.py b/authentik/blueprints/tests/test_v1_state.py
index 02ddfcb50..e0bf4c13a 100644
--- a/authentik/blueprints/tests/test_v1_state.py
+++ b/authentik/blueprints/tests/test_v1_state.py
@@ -1,10 +1,10 @@
"""Test blueprints v1"""
from django.test import TransactionTestCase
-from authentik.blueprints.tests import load_yaml_fixture
from authentik.blueprints.v1.importer import Importer
from authentik.flows.models import Flow
from authentik.lib.generators import generate_id
+from authentik.lib.tests.utils import load_fixture
class TestBlueprintsV1State(TransactionTestCase):
@@ -13,7 +13,7 @@ class TestBlueprintsV1State(TransactionTestCase):
def test_state_present(self):
"""Test state present"""
flow_slug = generate_id()
- import_yaml = load_yaml_fixture("fixtures/state_present.yaml", id=flow_slug)
+ import_yaml = load_fixture("fixtures/state_present.yaml", id=flow_slug)
importer = Importer(import_yaml)
self.assertTrue(importer.validate()[0])
@@ -39,7 +39,7 @@ class TestBlueprintsV1State(TransactionTestCase):
def test_state_created(self):
"""Test state created"""
flow_slug = generate_id()
- import_yaml = load_yaml_fixture("fixtures/state_created.yaml", id=flow_slug)
+ import_yaml = load_fixture("fixtures/state_created.yaml", id=flow_slug)
importer = Importer(import_yaml)
self.assertTrue(importer.validate()[0])
@@ -65,7 +65,7 @@ class TestBlueprintsV1State(TransactionTestCase):
def test_state_absent(self):
"""Test state absent"""
flow_slug = generate_id()
- import_yaml = load_yaml_fixture("fixtures/state_created.yaml", id=flow_slug)
+ import_yaml = load_fixture("fixtures/state_created.yaml", id=flow_slug)
importer = Importer(import_yaml)
self.assertTrue(importer.validate()[0])
@@ -74,7 +74,7 @@ class TestBlueprintsV1State(TransactionTestCase):
flow: Flow = Flow.objects.filter(slug=flow_slug).first()
self.assertEqual(flow.slug, flow_slug)
- import_yaml = load_yaml_fixture("fixtures/state_absent.yaml", id=flow_slug)
+ import_yaml = load_fixture("fixtures/state_absent.yaml", id=flow_slug)
importer = Importer(import_yaml)
self.assertTrue(importer.validate()[0])
self.assertTrue(importer.apply())
diff --git a/authentik/lib/tests/utils.py b/authentik/lib/tests/utils.py
index 35ec8391d..6e15fe61b 100644
--- a/authentik/lib/tests/utils.py
+++ b/authentik/lib/tests/utils.py
@@ -1,4 +1,7 @@
"""Test utils"""
+from inspect import currentframe
+from pathlib import Path
+
from django.contrib.messages.middleware import MessageMiddleware
from django.contrib.sessions.middleware import SessionMiddleware
from django.http import HttpRequest
@@ -11,6 +14,21 @@ def dummy_get_response(request: HttpRequest): # pragma: no cover
return None
+def load_fixture(path: str, **kwargs) -> str:
+ """Load fixture, optionally formatting it with kwargs"""
+ current = currentframe()
+ parent = current.f_back
+ calling_file_path = parent.f_globals["__file__"]
+ with open(
+ Path(calling_file_path).resolve().parent / Path(path), "r", encoding="utf-8"
+ ) as _fixture:
+ fixture = _fixture.read()
+ try:
+ return fixture % kwargs
+ except TypeError:
+ return fixture
+
+
def get_request(*args, user=None, **kwargs):
"""Get a request with usable session"""
request = RequestFactory().get(*args, **kwargs)
diff --git a/authentik/lib/utils/http.py b/authentik/lib/utils/http.py
index 94c01c9b7..d20ad29eb 100644
--- a/authentik/lib/utils/http.py
+++ b/authentik/lib/utils/http.py
@@ -38,13 +38,17 @@ def _get_outpost_override_ip(request: HttpRequest) -> Optional[str]:
if OUTPOST_REMOTE_IP_HEADER not in request.META or OUTPOST_TOKEN_HEADER not in request.META:
return None
fake_ip = request.META[OUTPOST_REMOTE_IP_HEADER]
- tokens = Token.filter_not_expired(
- key=request.META.get(OUTPOST_TOKEN_HEADER), intent=TokenIntents.INTENT_API
+ token = (
+ Token.filter_not_expired(
+ key=request.META.get(OUTPOST_TOKEN_HEADER), intent=TokenIntents.INTENT_API
+ )
+ .select_related("user")
+ .first()
)
- if not tokens.exists():
+ if not token:
LOGGER.warning("Attempted remote-ip override without token", fake_ip=fake_ip)
return None
- user = tokens.first().user
+ user = token.user
if not user.group_attributes(request).get(USER_ATTRIBUTE_CAN_OVERRIDE_IP, False):
LOGGER.warning(
"Remote-IP override: user doesn't have permission",
diff --git a/authentik/providers/saml/tests/test_api.py b/authentik/providers/saml/tests/test_api.py
index af103d8a3..f0c878e5a 100644
--- a/authentik/providers/saml/tests/test_api.py
+++ b/authentik/providers/saml/tests/test_api.py
@@ -10,8 +10,8 @@ from authentik.core.models import Application
from authentik.core.tests.utils import create_test_admin_user, create_test_flow
from authentik.flows.models import FlowDesignation
from authentik.lib.generators import generate_id
+from authentik.lib.tests.utils import load_fixture
from authentik.providers.saml.models import SAMLPropertyMapping, SAMLProvider
-from authentik.providers.saml.tests.test_metadata import load_fixture
class TestSAMLProviderAPI(APITestCase):
diff --git a/authentik/providers/saml/tests/test_metadata.py b/authentik/providers/saml/tests/test_metadata.py
index 07fc6ad0e..ffe1b2a4a 100644
--- a/authentik/providers/saml/tests/test_metadata.py
+++ b/authentik/providers/saml/tests/test_metadata.py
@@ -1,6 +1,4 @@
"""Test Service-Provider Metadata Parser"""
-from pathlib import Path
-
import xmlsec
from defusedxml.lxml import fromstring
from django.test import RequestFactory, TestCase
@@ -9,6 +7,7 @@ from lxml import etree # nosec
from authentik.core.models import Application
from authentik.core.tests.utils import create_test_cert, create_test_flow
from authentik.lib.generators import generate_id
+from authentik.lib.tests.utils import load_fixture
from authentik.lib.xml import lxml_from_string
from authentik.providers.saml.models import SAMLBindings, SAMLPropertyMapping, SAMLProvider
from authentik.providers.saml.processors.metadata import MetadataProcessor
@@ -16,12 +15,6 @@ from authentik.providers.saml.processors.metadata_parser import ServiceProviderM
from authentik.sources.saml.processors.constants import NS_MAP
-def load_fixture(path: str, **kwargs) -> str:
- """Load fixture"""
- with open(Path(__file__).resolve().parent / Path(path), "r", encoding="utf-8") as _fixture:
- return _fixture.read()
-
-
class TestServiceProviderMetadataParser(TestCase):
"""Test ServiceProviderMetadataParser parsing and creation of SAML Provider"""
diff --git a/authentik/sources/saml/tests/fixtures/response_error.xml b/authentik/sources/saml/tests/fixtures/response_error.xml
new file mode 100644
index 000000000..e0bf15cf2
--- /dev/null
+++ b/authentik/sources/saml/tests/fixtures/response_error.xml
@@ -0,0 +1,10 @@
+
+
+ https://accounts.google.com/o/saml2?idpid=
+
+
+
+
+ Invalid request, ACS Url in request http://localhost:9000/source/saml/google/acs/ doesn't match configured ACS Url https://127.0.0.1:9443/source/saml/google/acs/.
+
+
diff --git a/authentik/sources/saml/tests/fixtures/response_success.xml b/authentik/sources/saml/tests/fixtures/response_success.xml
new file mode 100644
index 000000000..979c2e2aa
--- /dev/null
+++ b/authentik/sources/saml/tests/fixtures/response_success.xml
@@ -0,0 +1,40 @@
+
+
+ https://accounts.google.com/o/saml2?idpid=
+
+
+
+
+ https://accounts.google.com/o/saml2?idpid=
+
+ jens@goauthentik.io
+
+
+
+
+
+
+ https://accounts.google.com/o/saml2?idpid=
+
+
+
+
+ foo
+
+
+ bar
+
+
+ foo@bar.baz
+
+
+
+
+ urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified
+
+
+
+
diff --git a/authentik/sources/saml/tests/test_response.py b/authentik/sources/saml/tests/test_response.py
index 2ab1c6486..f66a28b23 100644
--- a/authentik/sources/saml/tests/test_response.py
+++ b/authentik/sources/saml/tests/test_response.py
@@ -6,64 +6,10 @@ from django.test import RequestFactory, TestCase
from authentik.core.tests.utils import create_test_flow
from authentik.lib.generators import generate_id
-from authentik.lib.tests.utils import dummy_get_response
+from authentik.lib.tests.utils import dummy_get_response, load_fixture
from authentik.sources.saml.models import SAMLSource
from authentik.sources.saml.processors.response import ResponseProcessor
-RESPONSE_ERROR = """
-
- https://accounts.google.com/o/saml2?idpid=
-
-
-
-
- Invalid request, ACS Url in request http://localhost:9000/source/saml/google/acs/ doesn't match configured ACS Url https://127.0.0.1:9443/source/saml/google/acs/.
-
-
-"""
-
-RESPONSE_SUCCESS = """
-
- https://accounts.google.com/o/saml2?idpid=
-
-
-
-
- https://accounts.google.com/o/saml2?idpid=
-
- jens@goauthentik.io
-
-
-
-
-
-
- https://accounts.google.com/o/saml2?idpid=
-
-
-
-
- foo
-
-
- bar
-
-
- foo@bar.baz
-
-
-
-
- urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified
-
-
-
-
-"""
-
class TestResponseProcessor(TestCase):
"""Test ResponseProcessor"""
@@ -80,7 +26,12 @@ class TestResponseProcessor(TestCase):
def test_status_error(self):
"""Test error status"""
request = self.factory.post(
- "/", data={"SAMLResponse": b64encode(RESPONSE_ERROR.encode()).decode()}
+ "/",
+ data={
+ "SAMLResponse": b64encode(
+ load_fixture("fixtures/response_error.xml").encode()
+ ).decode()
+ },
)
middleware = SessionMiddleware(dummy_get_response)
@@ -99,7 +50,12 @@ class TestResponseProcessor(TestCase):
def test_success(self):
"""Test success"""
request = self.factory.post(
- "/", data={"SAMLResponse": b64encode(RESPONSE_SUCCESS.encode()).decode()}
+ "/",
+ data={
+ "SAMLResponse": b64encode(
+ load_fixture("fixtures/response_success.xml").encode()
+ ).decode()
+ },
)
middleware = SessionMiddleware(dummy_get_response)
diff --git a/web/src/admin/users/UserForm.ts b/web/src/admin/users/UserForm.ts
index ec657cfa4..46188dff9 100644
--- a/web/src/admin/users/UserForm.ts
+++ b/web/src/admin/users/UserForm.ts
@@ -68,14 +68,6 @@ export class UserForm extends ModelForm {
${t`User's primary identifier. 150 characters or fewer.`}
-
-
-
{
${t`Designates whether this user should be treated as active. Unselect this instead of deleting accounts.`}
+
+
+