authentik.providers.oauth2.tests.test_api

Test OAuth2 API

  1"""Test OAuth2 API"""
  2
  3from json import loads
  4from sys import version_info
  5from unittest import skipUnless
  6
  7from django.urls import reverse
  8from rest_framework.test import APITestCase
  9
 10from authentik.blueprints.tests import apply_blueprint
 11from authentik.core.models import Application
 12from authentik.core.tests.utils import create_test_admin_user, create_test_flow
 13from authentik.lib.generators import generate_id
 14from authentik.providers.oauth2.models import (
 15    OAuth2Provider,
 16    RedirectURI,
 17    RedirectURIMatchingMode,
 18    ScopeMapping,
 19)
 20
 21
 22class TestAPI(APITestCase):
 23    """Test api view"""
 24
 25    @apply_blueprint("system/providers-oauth2.yaml")
 26    def setUp(self) -> None:
 27        self.provider: OAuth2Provider = OAuth2Provider.objects.create(
 28            name="test",
 29            authorization_flow=create_test_flow(),
 30            redirect_uris=[RedirectURI(RedirectURIMatchingMode.STRICT, "http://testserver")],
 31        )
 32        self.provider.property_mappings.set(ScopeMapping.objects.all())
 33        self.app = Application.objects.create(name="test", slug="test", provider=self.provider)
 34        self.user = create_test_admin_user()
 35        self.client.force_login(self.user)
 36
 37    def test_preview(self):
 38        """Test Preview API Endpoint"""
 39        response = self.client.get(
 40            reverse("authentik_api:oauth2provider-preview-user", kwargs={"pk": self.provider.pk})
 41        )
 42        self.assertEqual(response.status_code, 200)
 43        body = loads(response.content.decode())["preview"]
 44        self.assertEqual(body["iss"], "http://testserver/application/o/test/")
 45
 46    def test_setup_urls(self):
 47        """Test Setup URLs API Endpoint"""
 48        response = self.client.get(
 49            reverse("authentik_api:oauth2provider-setup-urls", kwargs={"pk": self.provider.pk})
 50        )
 51        self.assertEqual(response.status_code, 200)
 52        body = loads(response.content.decode())
 53        self.assertEqual(body["issuer"], "http://testserver/application/o/test/")
 54
 55    # https://github.com/goauthentik/authentik/pull/5918
 56    @skipUnless(version_info >= (3, 11, 4), "This behaviour is only Python 3.11.4 and up")
 57    def test_launch_url(self):
 58        """Test launch_url"""
 59        self.provider.redirect_uris = [
 60            RedirectURI(
 61                RedirectURIMatchingMode.REGEX,
 62                "https://[\\d\\w]+.pr.test.goauthentik.io/source/oauth/callback/authentik/",
 63            ),
 64        ]
 65        self.provider.save()
 66        self.provider.refresh_from_db()
 67        self.assertIsNone(self.provider.launch_url)
 68
 69    def test_validate_redirect_uris(self):
 70        """Test redirect_uris API"""
 71        response = self.client.post(
 72            reverse("authentik_api:oauth2provider-list"),
 73            data={
 74                "name": generate_id(),
 75                "authorization_flow": create_test_flow().pk,
 76                "invalidation_flow": create_test_flow().pk,
 77                "redirect_uris": [
 78                    {"matching_mode": "strict", "url": "http://goauthentik.io"},
 79                    {"matching_mode": "regex", "url": "**"},
 80                ],
 81            },
 82        )
 83        self.assertJSONEqual(response.content, {"redirect_uris": ["Invalid Regex Pattern: **"]})
 84
 85    def test_logout_uri_validation(self):
 86        """Test logout_uri API validation"""
 87        response = self.client.post(
 88            reverse("authentik_api:oauth2provider-list"),
 89            data={
 90                "name": generate_id(),
 91                "authorization_flow": create_test_flow().pk,
 92                "invalidation_flow": create_test_flow().pk,
 93                "redirect_uris": [
 94                    {"matching_mode": "strict", "url": "http://goauthentik.io"},
 95                ],
 96                "logout_uri": "invalid-url",
 97                "logout_method": "backchannel",
 98            },
 99        )
100        self.assertEqual(response.status_code, 400)
101
102    def test_logout_uri_create_and_retrieve(self):
103        """Test creating and retrieving logout URI with method"""
104        response = self.client.post(
105            reverse("authentik_api:oauth2provider-list"),
106            data={
107                "name": generate_id(),
108                "authorization_flow": create_test_flow().pk,
109                "invalidation_flow": create_test_flow().pk,
110                "redirect_uris": [
111                    {"matching_mode": "strict", "url": "http://goauthentik.io"},
112                ],
113                "logout_uri": "http://goauthentik.io/logout",
114                "logout_method": "backchannel",
115            },
116        )
117        self.assertEqual(response.status_code, 201)
118        provider_data = response.json()
119        self.assertEqual(provider_data["logout_uri"], "http://goauthentik.io/logout")
120        self.assertEqual(provider_data["logout_method"], "backchannel")
121
122        # Test retrieving the provider
123        provider_pk = provider_data["pk"]
124        response = self.client.get(
125            reverse("authentik_api:oauth2provider-detail", kwargs={"pk": provider_pk})
126        )
127        self.assertEqual(response.status_code, 200)
128        retrieved_data = response.json()
129        self.assertEqual(retrieved_data["logout_uri"], "http://goauthentik.io/logout")
130        self.assertEqual(retrieved_data["logout_method"], "backchannel")
class TestAPI(rest_framework.test.APITestCase):
 23class TestAPI(APITestCase):
 24    """Test api view"""
 25
 26    @apply_blueprint("system/providers-oauth2.yaml")
 27    def setUp(self) -> None:
 28        self.provider: OAuth2Provider = OAuth2Provider.objects.create(
 29            name="test",
 30            authorization_flow=create_test_flow(),
 31            redirect_uris=[RedirectURI(RedirectURIMatchingMode.STRICT, "http://testserver")],
 32        )
 33        self.provider.property_mappings.set(ScopeMapping.objects.all())
 34        self.app = Application.objects.create(name="test", slug="test", provider=self.provider)
 35        self.user = create_test_admin_user()
 36        self.client.force_login(self.user)
 37
 38    def test_preview(self):
 39        """Test Preview API Endpoint"""
 40        response = self.client.get(
 41            reverse("authentik_api:oauth2provider-preview-user", kwargs={"pk": self.provider.pk})
 42        )
 43        self.assertEqual(response.status_code, 200)
 44        body = loads(response.content.decode())["preview"]
 45        self.assertEqual(body["iss"], "http://testserver/application/o/test/")
 46
 47    def test_setup_urls(self):
 48        """Test Setup URLs API Endpoint"""
 49        response = self.client.get(
 50            reverse("authentik_api:oauth2provider-setup-urls", kwargs={"pk": self.provider.pk})
 51        )
 52        self.assertEqual(response.status_code, 200)
 53        body = loads(response.content.decode())
 54        self.assertEqual(body["issuer"], "http://testserver/application/o/test/")
 55
 56    # https://github.com/goauthentik/authentik/pull/5918
 57    @skipUnless(version_info >= (3, 11, 4), "This behaviour is only Python 3.11.4 and up")
 58    def test_launch_url(self):
 59        """Test launch_url"""
 60        self.provider.redirect_uris = [
 61            RedirectURI(
 62                RedirectURIMatchingMode.REGEX,
 63                "https://[\\d\\w]+.pr.test.goauthentik.io/source/oauth/callback/authentik/",
 64            ),
 65        ]
 66        self.provider.save()
 67        self.provider.refresh_from_db()
 68        self.assertIsNone(self.provider.launch_url)
 69
 70    def test_validate_redirect_uris(self):
 71        """Test redirect_uris API"""
 72        response = self.client.post(
 73            reverse("authentik_api:oauth2provider-list"),
 74            data={
 75                "name": generate_id(),
 76                "authorization_flow": create_test_flow().pk,
 77                "invalidation_flow": create_test_flow().pk,
 78                "redirect_uris": [
 79                    {"matching_mode": "strict", "url": "http://goauthentik.io"},
 80                    {"matching_mode": "regex", "url": "**"},
 81                ],
 82            },
 83        )
 84        self.assertJSONEqual(response.content, {"redirect_uris": ["Invalid Regex Pattern: **"]})
 85
 86    def test_logout_uri_validation(self):
 87        """Test logout_uri API validation"""
 88        response = self.client.post(
 89            reverse("authentik_api:oauth2provider-list"),
 90            data={
 91                "name": generate_id(),
 92                "authorization_flow": create_test_flow().pk,
 93                "invalidation_flow": create_test_flow().pk,
 94                "redirect_uris": [
 95                    {"matching_mode": "strict", "url": "http://goauthentik.io"},
 96                ],
 97                "logout_uri": "invalid-url",
 98                "logout_method": "backchannel",
 99            },
100        )
101        self.assertEqual(response.status_code, 400)
102
103    def test_logout_uri_create_and_retrieve(self):
104        """Test creating and retrieving logout URI with method"""
105        response = self.client.post(
106            reverse("authentik_api:oauth2provider-list"),
107            data={
108                "name": generate_id(),
109                "authorization_flow": create_test_flow().pk,
110                "invalidation_flow": create_test_flow().pk,
111                "redirect_uris": [
112                    {"matching_mode": "strict", "url": "http://goauthentik.io"},
113                ],
114                "logout_uri": "http://goauthentik.io/logout",
115                "logout_method": "backchannel",
116            },
117        )
118        self.assertEqual(response.status_code, 201)
119        provider_data = response.json()
120        self.assertEqual(provider_data["logout_uri"], "http://goauthentik.io/logout")
121        self.assertEqual(provider_data["logout_method"], "backchannel")
122
123        # Test retrieving the provider
124        provider_pk = provider_data["pk"]
125        response = self.client.get(
126            reverse("authentik_api:oauth2provider-detail", kwargs={"pk": provider_pk})
127        )
128        self.assertEqual(response.status_code, 200)
129        retrieved_data = response.json()
130        self.assertEqual(retrieved_data["logout_uri"], "http://goauthentik.io/logout")
131        self.assertEqual(retrieved_data["logout_method"], "backchannel")

Test api view

@apply_blueprint('system/providers-oauth2.yaml')
def setUp(self) -> None:
26    @apply_blueprint("system/providers-oauth2.yaml")
27    def setUp(self) -> None:
28        self.provider: OAuth2Provider = OAuth2Provider.objects.create(
29            name="test",
30            authorization_flow=create_test_flow(),
31            redirect_uris=[RedirectURI(RedirectURIMatchingMode.STRICT, "http://testserver")],
32        )
33        self.provider.property_mappings.set(ScopeMapping.objects.all())
34        self.app = Application.objects.create(name="test", slug="test", provider=self.provider)
35        self.user = create_test_admin_user()
36        self.client.force_login(self.user)

Hook method for setting up the test fixture before exercising it.

def test_preview(self):
38    def test_preview(self):
39        """Test Preview API Endpoint"""
40        response = self.client.get(
41            reverse("authentik_api:oauth2provider-preview-user", kwargs={"pk": self.provider.pk})
42        )
43        self.assertEqual(response.status_code, 200)
44        body = loads(response.content.decode())["preview"]
45        self.assertEqual(body["iss"], "http://testserver/application/o/test/")

Test Preview API Endpoint

def test_setup_urls(self):
47    def test_setup_urls(self):
48        """Test Setup URLs API Endpoint"""
49        response = self.client.get(
50            reverse("authentik_api:oauth2provider-setup-urls", kwargs={"pk": self.provider.pk})
51        )
52        self.assertEqual(response.status_code, 200)
53        body = loads(response.content.decode())
54        self.assertEqual(body["issuer"], "http://testserver/application/o/test/")

Test Setup URLs API Endpoint

@skipUnless(version_info >= (3, 11, 4), 'This behaviour is only Python 3.11.4 and up')
def test_launch_url(self):
57    @skipUnless(version_info >= (3, 11, 4), "This behaviour is only Python 3.11.4 and up")
58    def test_launch_url(self):
59        """Test launch_url"""
60        self.provider.redirect_uris = [
61            RedirectURI(
62                RedirectURIMatchingMode.REGEX,
63                "https://[\\d\\w]+.pr.test.goauthentik.io/source/oauth/callback/authentik/",
64            ),
65        ]
66        self.provider.save()
67        self.provider.refresh_from_db()
68        self.assertIsNone(self.provider.launch_url)

Test launch_url

def test_validate_redirect_uris(self):
70    def test_validate_redirect_uris(self):
71        """Test redirect_uris API"""
72        response = self.client.post(
73            reverse("authentik_api:oauth2provider-list"),
74            data={
75                "name": generate_id(),
76                "authorization_flow": create_test_flow().pk,
77                "invalidation_flow": create_test_flow().pk,
78                "redirect_uris": [
79                    {"matching_mode": "strict", "url": "http://goauthentik.io"},
80                    {"matching_mode": "regex", "url": "**"},
81                ],
82            },
83        )
84        self.assertJSONEqual(response.content, {"redirect_uris": ["Invalid Regex Pattern: **"]})

Test redirect_uris API

def test_logout_uri_validation(self):
 86    def test_logout_uri_validation(self):
 87        """Test logout_uri API validation"""
 88        response = self.client.post(
 89            reverse("authentik_api:oauth2provider-list"),
 90            data={
 91                "name": generate_id(),
 92                "authorization_flow": create_test_flow().pk,
 93                "invalidation_flow": create_test_flow().pk,
 94                "redirect_uris": [
 95                    {"matching_mode": "strict", "url": "http://goauthentik.io"},
 96                ],
 97                "logout_uri": "invalid-url",
 98                "logout_method": "backchannel",
 99            },
100        )
101        self.assertEqual(response.status_code, 400)

Test logout_uri API validation

def test_logout_uri_create_and_retrieve(self):
103    def test_logout_uri_create_and_retrieve(self):
104        """Test creating and retrieving logout URI with method"""
105        response = self.client.post(
106            reverse("authentik_api:oauth2provider-list"),
107            data={
108                "name": generate_id(),
109                "authorization_flow": create_test_flow().pk,
110                "invalidation_flow": create_test_flow().pk,
111                "redirect_uris": [
112                    {"matching_mode": "strict", "url": "http://goauthentik.io"},
113                ],
114                "logout_uri": "http://goauthentik.io/logout",
115                "logout_method": "backchannel",
116            },
117        )
118        self.assertEqual(response.status_code, 201)
119        provider_data = response.json()
120        self.assertEqual(provider_data["logout_uri"], "http://goauthentik.io/logout")
121        self.assertEqual(provider_data["logout_method"], "backchannel")
122
123        # Test retrieving the provider
124        provider_pk = provider_data["pk"]
125        response = self.client.get(
126            reverse("authentik_api:oauth2provider-detail", kwargs={"pk": provider_pk})
127        )
128        self.assertEqual(response.status_code, 200)
129        retrieved_data = response.json()
130        self.assertEqual(retrieved_data["logout_uri"], "http://goauthentik.io/logout")
131        self.assertEqual(retrieved_data["logout_method"], "backchannel")

Test creating and retrieving logout URI with method