Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

outposts: fix Outpost reconcile not re-assigning managed attribute #8014

Merged
merged 2 commits into from
Dec 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion authentik/blueprints/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ def reconcile(self) -> None:
meth()
self._logger.debug("Successfully reconciled", name=name)
except (DatabaseError, ProgrammingError, InternalError) as exc:
self._logger.debug("Failed to run reconcile", name=name, exc=exc)
self._logger.warning("Failed to run reconcile", name=name, exc=exc)


class AuthentikBlueprintsConfig(ManagedAppConfig):
Expand Down
12 changes: 11 additions & 1 deletion authentik/outposts/api/outposts.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
from authentik.core.api.utils import JSONDictField, PassiveSerializer
from authentik.core.models import Provider
from authentik.outposts.api.service_connections import ServiceConnectionSerializer
from authentik.outposts.apps import MANAGED_OUTPOST
from authentik.outposts.apps import MANAGED_OUTPOST, MANAGED_OUTPOST_NAME
from authentik.outposts.models import (
Outpost,
OutpostConfig,
Expand Down Expand Up @@ -47,6 +47,16 @@
source="service_connection", read_only=True
)

def validate_name(self, name: str) -> str:
"""Validate name (especially for embedded outpost)"""
if not self.instance:
return name
if self.instance.managed == MANAGED_OUTPOST:
raise ValidationError("Embedded outpost's name cannot be changed")
if self.instance.name == MANAGED_OUTPOST_NAME:
self.instance.managed = MANAGED_OUTPOST
return name

Check warning on line 58 in authentik/outposts/api/outposts.py

View check run for this annotation

Codecov / codecov/patch

authentik/outposts/api/outposts.py#L52-L58

Added lines #L52 - L58 were not covered by tests

def validate_providers(self, providers: list[Provider]) -> list[Provider]:
"""Check that all providers match the type of the outpost"""
type_map = {
Expand Down
7 changes: 6 additions & 1 deletion authentik/outposts/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
["outpost", "uid", "version"],
)
MANAGED_OUTPOST = "goauthentik.io/outposts/embedded"
MANAGED_OUTPOST_NAME = "authentik Embedded Outpost"


class AuthentikOutpostConfig(ManagedAppConfig):
Expand All @@ -39,10 +40,14 @@ def reconcile_embedded_outpost(self):
OutpostType,
)

if outpost := Outpost.objects.filter(name=MANAGED_OUTPOST_NAME, managed="").first():
outpost.managed = MANAGED_OUTPOST
outpost.save()
return
outpost, updated = Outpost.objects.update_or_create(
defaults={
"name": "authentik Embedded Outpost",
"type": OutpostType.PROXY,
"name": MANAGED_OUTPOST_NAME,
},
managed=MANAGED_OUTPOST,
)
Expand Down
35 changes: 33 additions & 2 deletions authentik/outposts/tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@
from django.urls import reverse
from rest_framework.test import APITestCase

from authentik.blueprints.tests import reconcile_app

Check warning on line 5 in authentik/outposts/tests/test_api.py

View check run for this annotation

Codecov / codecov/patch

authentik/outposts/tests/test_api.py#L5

Added line #L5 was not covered by tests
from authentik.core.models import PropertyMapping
from authentik.core.tests.utils import create_test_admin_user, create_test_flow
from authentik.lib.generators import generate_id
from authentik.outposts.api.outposts import OutpostSerializer
from authentik.outposts.models import OutpostType, default_outpost_config
from authentik.outposts.apps import MANAGED_OUTPOST
from authentik.outposts.models import Outpost, OutpostType, default_outpost_config

Check warning on line 11 in authentik/outposts/tests/test_api.py

View check run for this annotation

Codecov / codecov/patch

authentik/outposts/tests/test_api.py#L10-L11

Added lines #L10 - L11 were not covered by tests
from authentik.providers.ldap.models import LDAPProvider
from authentik.providers.proxy.models import ProxyProvider

Expand All @@ -22,7 +24,36 @@
self.user = create_test_admin_user()
self.client.force_login(self.user)

def test_outpost_validaton(self):
@reconcile_app("authentik_outposts")
def test_managed_name_change(self):

Check warning on line 28 in authentik/outposts/tests/test_api.py

View check run for this annotation

Codecov / codecov/patch

authentik/outposts/tests/test_api.py#L27-L28

Added lines #L27 - L28 were not covered by tests
"""Test name change for embedded outpost"""
embedded_outpost = Outpost.objects.filter(managed=MANAGED_OUTPOST).first()
self.assertIsNotNone(embedded_outpost)
response = self.client.patch(

Check warning on line 32 in authentik/outposts/tests/test_api.py

View check run for this annotation

Codecov / codecov/patch

authentik/outposts/tests/test_api.py#L30-L32

Added lines #L30 - L32 were not covered by tests
reverse("authentik_api:outpost-detail", kwargs={"pk": embedded_outpost.pk}),
{"name": "foo"},
)
self.assertEqual(response.status_code, 400)
self.assertJSONEqual(

Check warning on line 37 in authentik/outposts/tests/test_api.py

View check run for this annotation

Codecov / codecov/patch

authentik/outposts/tests/test_api.py#L36-L37

Added lines #L36 - L37 were not covered by tests
response.content, {"name": ["Embedded outpost's name cannot be changed"]}
)

@reconcile_app("authentik_outposts")
def test_managed_without_managed(self):

Check warning on line 42 in authentik/outposts/tests/test_api.py

View check run for this annotation

Codecov / codecov/patch

authentik/outposts/tests/test_api.py#L41-L42

Added lines #L41 - L42 were not covered by tests
"""Test name change for embedded outpost"""
embedded_outpost = Outpost.objects.filter(managed=MANAGED_OUTPOST).first()
self.assertIsNotNone(embedded_outpost)
embedded_outpost.managed = ""
embedded_outpost.save()
response = self.client.patch(

Check warning on line 48 in authentik/outposts/tests/test_api.py

View check run for this annotation

Codecov / codecov/patch

authentik/outposts/tests/test_api.py#L44-L48

Added lines #L44 - L48 were not covered by tests
reverse("authentik_api:outpost-detail", kwargs={"pk": embedded_outpost.pk}),
{"name": "foo"},
)
self.assertEqual(response.status_code, 200)
embedded_outpost.refresh_from_db()
self.assertEqual(embedded_outpost.managed, MANAGED_OUTPOST)

Check warning on line 54 in authentik/outposts/tests/test_api.py

View check run for this annotation

Codecov / codecov/patch

authentik/outposts/tests/test_api.py#L52-L54

Added lines #L52 - L54 were not covered by tests

def test_outpost_validation(self):

Check warning on line 56 in authentik/outposts/tests/test_api.py

View check run for this annotation

Codecov / codecov/patch

authentik/outposts/tests/test_api.py#L56

Added line #L56 was not covered by tests
"""Test Outpost validation"""
valid = OutpostSerializer(
data={
Expand Down
Loading