authentik.flows.tests.test_api

API flow tests

  1"""API flow tests"""
  2
  3from json import loads
  4
  5from django.urls import reverse
  6from rest_framework.test import APITestCase
  7
  8from authentik.core.tests.utils import create_test_admin_user, create_test_flow
  9from authentik.flows.api.stages import StageSerializer, StageViewSet
 10from authentik.flows.models import Flow, FlowDesignation, FlowStageBinding, Stage
 11from authentik.lib.generators import generate_id
 12from authentik.policies.dummy.models import DummyPolicy
 13from authentik.policies.models import PolicyBinding
 14from authentik.stages.dummy.models import DummyStage
 15
 16DIAGRAM_EXPECTED = """graph TD
 17flow_start[["Flow
 18test-default-context"]]
 19--> stage_0(["Stage (Dummy Stage)
 20dummy1"])
 21stage_1_policy_0 --Policy passed--> stage_1(["Stage (Dummy Stage)
 22dummy2"])
 23stage_0 --> stage_1_policy_0{{"Policy (Dummy Policy)
 24dummy2-policy"}}
 25stage_1 --> done[["End of the flow"]]"""
 26DIAGRAM_SHORT_EXPECTED = """graph TD
 27flow_start[["Flow
 28test-default-context"]]
 29flow_start --> done[["End of the flow"]]"""
 30
 31
 32class TestFlowsAPI(APITestCase):
 33    """API tests"""
 34
 35    def test_models(self):
 36        """Test that ui_user_settings returns none"""
 37        self.assertIsNone(Stage().ui_user_settings())
 38
 39    def test_api_serializer(self):
 40        """Test that stage serializer returns the correct type"""
 41        obj = DummyStage()
 42        self.assertEqual(StageSerializer().get_component(obj), "ak-stage-dummy-form")
 43        self.assertEqual(StageSerializer().get_verbose_name(obj), "Dummy Stage")
 44
 45    def test_api_viewset(self):
 46        """Test that stage serializer returns the correct type"""
 47        dummy = DummyStage.objects.create()
 48        self.assertIn(dummy, StageViewSet().get_queryset())
 49
 50    def test_api_diagram(self):
 51        """Test flow diagram."""
 52        user = create_test_admin_user()
 53        self.client.force_login(user)
 54
 55        flow = Flow.objects.create(
 56            name="test-default-context",
 57            slug="test-default-context",
 58            designation=FlowDesignation.AUTHENTICATION,
 59        )
 60        false_policy = DummyPolicy.objects.create(
 61            name="dummy2-policy", result=False, wait_min=1, wait_max=2
 62        )
 63
 64        FlowStageBinding.objects.create(
 65            target=flow, stage=DummyStage.objects.create(name="dummy1"), order=0
 66        )
 67        binding2 = FlowStageBinding.objects.create(
 68            target=flow,
 69            stage=DummyStage.objects.create(name="dummy2"),
 70            order=1,
 71            re_evaluate_policies=True,
 72        )
 73
 74        PolicyBinding.objects.create(policy=false_policy, target=binding2, order=0)
 75
 76        response = self.client.get(
 77            reverse("authentik_api:flow-diagram", kwargs={"slug": flow.slug})
 78        )
 79        self.assertEqual(response.status_code, 200)
 80        self.assertJSONEqual(response.content, {"diagram": DIAGRAM_EXPECTED})
 81
 82    def test_api_background(self):
 83        """Test custom background"""
 84        user = create_test_admin_user()
 85        self.client.force_login(user)
 86
 87        flow = create_test_flow()
 88        response = self.client.get(reverse("authentik_api:flow-detail", kwargs={"slug": flow.slug}))
 89        body = loads(response.content.decode())
 90        self.assertEqual(body["background_url"], "/static/dist/assets/images/flow_background.jpg")
 91
 92        flow.background = "https://goauthentik.io/img/icon.png"
 93        flow.save()
 94        response = self.client.get(reverse("authentik_api:flow-detail", kwargs={"slug": flow.slug}))
 95        body = loads(response.content.decode())
 96        self.assertEqual(body["background"], "https://goauthentik.io/img/icon.png")
 97
 98    def test_api_diagram_no_stages(self):
 99        """Test flow diagram with no stages."""
100        user = create_test_admin_user()
101        self.client.force_login(user)
102
103        flow = Flow.objects.create(
104            name="test-default-context",
105            slug="test-default-context",
106            designation=FlowDesignation.AUTHENTICATION,
107        )
108        response = self.client.get(
109            reverse("authentik_api:flow-diagram", kwargs={"slug": flow.slug})
110        )
111        self.assertEqual(response.status_code, 200)
112        self.assertJSONEqual(response.content, {"diagram": DIAGRAM_SHORT_EXPECTED})
113
114    def test_types(self):
115        """Test Stage's types endpoint"""
116        user = create_test_admin_user()
117        self.client.force_login(user)
118
119        response = self.client.get(
120            reverse("authentik_api:stage-types"),
121        )
122        self.assertEqual(response.status_code, 200)
123
124    def test_execute(self):
125        """Test execute endpoint"""
126        user = create_test_admin_user()
127        self.client.force_login(user)
128
129        flow = Flow.objects.create(
130            name=generate_id(),
131            slug=generate_id(),
132            designation=FlowDesignation.AUTHENTICATION,
133        )
134        FlowStageBinding.objects.create(
135            target=flow, stage=DummyStage.objects.create(name=generate_id()), order=0
136        )
137        response = self.client.get(
138            reverse("authentik_api:flow-execute", kwargs={"slug": flow.slug})
139        )
140        self.assertEqual(response.status_code, 200)
DIAGRAM_EXPECTED = 'graph TD\nflow_start[["Flow\ntest-default-context"]]\n--> stage_0(["Stage (Dummy Stage)\ndummy1"])\nstage_1_policy_0 --Policy passed--> stage_1(["Stage (Dummy Stage)\ndummy2"])\nstage_0 --> stage_1_policy_0{{"Policy (Dummy Policy)\ndummy2-policy"}}\nstage_1 --> done[["End of the flow"]]'
DIAGRAM_SHORT_EXPECTED = 'graph TD\nflow_start[["Flow\ntest-default-context"]]\nflow_start --> done[["End of the flow"]]'
class TestFlowsAPI(rest_framework.test.APITestCase):
 33class TestFlowsAPI(APITestCase):
 34    """API tests"""
 35
 36    def test_models(self):
 37        """Test that ui_user_settings returns none"""
 38        self.assertIsNone(Stage().ui_user_settings())
 39
 40    def test_api_serializer(self):
 41        """Test that stage serializer returns the correct type"""
 42        obj = DummyStage()
 43        self.assertEqual(StageSerializer().get_component(obj), "ak-stage-dummy-form")
 44        self.assertEqual(StageSerializer().get_verbose_name(obj), "Dummy Stage")
 45
 46    def test_api_viewset(self):
 47        """Test that stage serializer returns the correct type"""
 48        dummy = DummyStage.objects.create()
 49        self.assertIn(dummy, StageViewSet().get_queryset())
 50
 51    def test_api_diagram(self):
 52        """Test flow diagram."""
 53        user = create_test_admin_user()
 54        self.client.force_login(user)
 55
 56        flow = Flow.objects.create(
 57            name="test-default-context",
 58            slug="test-default-context",
 59            designation=FlowDesignation.AUTHENTICATION,
 60        )
 61        false_policy = DummyPolicy.objects.create(
 62            name="dummy2-policy", result=False, wait_min=1, wait_max=2
 63        )
 64
 65        FlowStageBinding.objects.create(
 66            target=flow, stage=DummyStage.objects.create(name="dummy1"), order=0
 67        )
 68        binding2 = FlowStageBinding.objects.create(
 69            target=flow,
 70            stage=DummyStage.objects.create(name="dummy2"),
 71            order=1,
 72            re_evaluate_policies=True,
 73        )
 74
 75        PolicyBinding.objects.create(policy=false_policy, target=binding2, order=0)
 76
 77        response = self.client.get(
 78            reverse("authentik_api:flow-diagram", kwargs={"slug": flow.slug})
 79        )
 80        self.assertEqual(response.status_code, 200)
 81        self.assertJSONEqual(response.content, {"diagram": DIAGRAM_EXPECTED})
 82
 83    def test_api_background(self):
 84        """Test custom background"""
 85        user = create_test_admin_user()
 86        self.client.force_login(user)
 87
 88        flow = create_test_flow()
 89        response = self.client.get(reverse("authentik_api:flow-detail", kwargs={"slug": flow.slug}))
 90        body = loads(response.content.decode())
 91        self.assertEqual(body["background_url"], "/static/dist/assets/images/flow_background.jpg")
 92
 93        flow.background = "https://goauthentik.io/img/icon.png"
 94        flow.save()
 95        response = self.client.get(reverse("authentik_api:flow-detail", kwargs={"slug": flow.slug}))
 96        body = loads(response.content.decode())
 97        self.assertEqual(body["background"], "https://goauthentik.io/img/icon.png")
 98
 99    def test_api_diagram_no_stages(self):
100        """Test flow diagram with no stages."""
101        user = create_test_admin_user()
102        self.client.force_login(user)
103
104        flow = Flow.objects.create(
105            name="test-default-context",
106            slug="test-default-context",
107            designation=FlowDesignation.AUTHENTICATION,
108        )
109        response = self.client.get(
110            reverse("authentik_api:flow-diagram", kwargs={"slug": flow.slug})
111        )
112        self.assertEqual(response.status_code, 200)
113        self.assertJSONEqual(response.content, {"diagram": DIAGRAM_SHORT_EXPECTED})
114
115    def test_types(self):
116        """Test Stage's types endpoint"""
117        user = create_test_admin_user()
118        self.client.force_login(user)
119
120        response = self.client.get(
121            reverse("authentik_api:stage-types"),
122        )
123        self.assertEqual(response.status_code, 200)
124
125    def test_execute(self):
126        """Test execute endpoint"""
127        user = create_test_admin_user()
128        self.client.force_login(user)
129
130        flow = Flow.objects.create(
131            name=generate_id(),
132            slug=generate_id(),
133            designation=FlowDesignation.AUTHENTICATION,
134        )
135        FlowStageBinding.objects.create(
136            target=flow, stage=DummyStage.objects.create(name=generate_id()), order=0
137        )
138        response = self.client.get(
139            reverse("authentik_api:flow-execute", kwargs={"slug": flow.slug})
140        )
141        self.assertEqual(response.status_code, 200)

API tests

def test_models(self):
36    def test_models(self):
37        """Test that ui_user_settings returns none"""
38        self.assertIsNone(Stage().ui_user_settings())

Test that ui_user_settings returns none

def test_api_serializer(self):
40    def test_api_serializer(self):
41        """Test that stage serializer returns the correct type"""
42        obj = DummyStage()
43        self.assertEqual(StageSerializer().get_component(obj), "ak-stage-dummy-form")
44        self.assertEqual(StageSerializer().get_verbose_name(obj), "Dummy Stage")

Test that stage serializer returns the correct type

def test_api_viewset(self):
46    def test_api_viewset(self):
47        """Test that stage serializer returns the correct type"""
48        dummy = DummyStage.objects.create()
49        self.assertIn(dummy, StageViewSet().get_queryset())

Test that stage serializer returns the correct type

def test_api_diagram(self):
51    def test_api_diagram(self):
52        """Test flow diagram."""
53        user = create_test_admin_user()
54        self.client.force_login(user)
55
56        flow = Flow.objects.create(
57            name="test-default-context",
58            slug="test-default-context",
59            designation=FlowDesignation.AUTHENTICATION,
60        )
61        false_policy = DummyPolicy.objects.create(
62            name="dummy2-policy", result=False, wait_min=1, wait_max=2
63        )
64
65        FlowStageBinding.objects.create(
66            target=flow, stage=DummyStage.objects.create(name="dummy1"), order=0
67        )
68        binding2 = FlowStageBinding.objects.create(
69            target=flow,
70            stage=DummyStage.objects.create(name="dummy2"),
71            order=1,
72            re_evaluate_policies=True,
73        )
74
75        PolicyBinding.objects.create(policy=false_policy, target=binding2, order=0)
76
77        response = self.client.get(
78            reverse("authentik_api:flow-diagram", kwargs={"slug": flow.slug})
79        )
80        self.assertEqual(response.status_code, 200)
81        self.assertJSONEqual(response.content, {"diagram": DIAGRAM_EXPECTED})

Test flow diagram.

def test_api_background(self):
83    def test_api_background(self):
84        """Test custom background"""
85        user = create_test_admin_user()
86        self.client.force_login(user)
87
88        flow = create_test_flow()
89        response = self.client.get(reverse("authentik_api:flow-detail", kwargs={"slug": flow.slug}))
90        body = loads(response.content.decode())
91        self.assertEqual(body["background_url"], "/static/dist/assets/images/flow_background.jpg")
92
93        flow.background = "https://goauthentik.io/img/icon.png"
94        flow.save()
95        response = self.client.get(reverse("authentik_api:flow-detail", kwargs={"slug": flow.slug}))
96        body = loads(response.content.decode())
97        self.assertEqual(body["background"], "https://goauthentik.io/img/icon.png")

Test custom background

def test_api_diagram_no_stages(self):
 99    def test_api_diagram_no_stages(self):
100        """Test flow diagram with no stages."""
101        user = create_test_admin_user()
102        self.client.force_login(user)
103
104        flow = Flow.objects.create(
105            name="test-default-context",
106            slug="test-default-context",
107            designation=FlowDesignation.AUTHENTICATION,
108        )
109        response = self.client.get(
110            reverse("authentik_api:flow-diagram", kwargs={"slug": flow.slug})
111        )
112        self.assertEqual(response.status_code, 200)
113        self.assertJSONEqual(response.content, {"diagram": DIAGRAM_SHORT_EXPECTED})

Test flow diagram with no stages.

def test_types(self):
115    def test_types(self):
116        """Test Stage's types endpoint"""
117        user = create_test_admin_user()
118        self.client.force_login(user)
119
120        response = self.client.get(
121            reverse("authentik_api:stage-types"),
122        )
123        self.assertEqual(response.status_code, 200)

Test Stage's types endpoint

def test_execute(self):
125    def test_execute(self):
126        """Test execute endpoint"""
127        user = create_test_admin_user()
128        self.client.force_login(user)
129
130        flow = Flow.objects.create(
131            name=generate_id(),
132            slug=generate_id(),
133            designation=FlowDesignation.AUTHENTICATION,
134        )
135        FlowStageBinding.objects.create(
136            target=flow, stage=DummyStage.objects.create(name=generate_id()), order=0
137        )
138        response = self.client.get(
139            reverse("authentik_api:flow-execute", kwargs={"slug": flow.slug})
140        )
141        self.assertEqual(response.status_code, 200)

Test execute endpoint