authentik.providers.oauth2.tests.test_token_device

Test token view

  1"""Test token view"""
  2
  3from json import loads
  4
  5from django.test import RequestFactory
  6from django.urls import reverse
  7
  8from authentik.blueprints.tests import apply_blueprint
  9from authentik.common.oauth.constants import (
 10    GRANT_TYPE_DEVICE_CODE,
 11    SCOPE_OPENID,
 12    SCOPE_OPENID_EMAIL,
 13)
 14from authentik.core.models import Application
 15from authentik.core.tests.utils import create_test_admin_user, create_test_cert, create_test_flow
 16from authentik.lib.generators import generate_code_fixed_length, generate_id
 17from authentik.providers.oauth2.models import (
 18    AccessToken,
 19    DeviceToken,
 20    OAuth2Provider,
 21    RedirectURI,
 22    RedirectURIMatchingMode,
 23    ScopeMapping,
 24)
 25from authentik.providers.oauth2.tests.utils import OAuthTestCase
 26
 27
 28class TestTokenDeviceCode(OAuthTestCase):
 29    """Test token (device code) view"""
 30
 31    @apply_blueprint("system/providers-oauth2.yaml")
 32    def setUp(self) -> None:
 33        super().setUp()
 34        self.factory = RequestFactory()
 35        self.provider = OAuth2Provider.objects.create(
 36            name="test",
 37            authorization_flow=create_test_flow(),
 38            redirect_uris=[RedirectURI(RedirectURIMatchingMode.STRICT, "http://testserver")],
 39            signing_key=create_test_cert(),
 40        )
 41        self.provider.property_mappings.set(ScopeMapping.objects.all())
 42        self.app = Application.objects.create(name="test", slug="test", provider=self.provider)
 43        self.user = create_test_admin_user()
 44
 45    def test_code_no_code(self):
 46        """Test code without code"""
 47        res = self.client.post(
 48            reverse("authentik_providers_oauth2:token"),
 49            data={
 50                "client_id": self.provider.client_id,
 51                "grant_type": GRANT_TYPE_DEVICE_CODE,
 52            },
 53        )
 54        self.assertEqual(res.status_code, 400)
 55        body = loads(res.content.decode())
 56        self.assertEqual(body["error"], "invalid_grant")
 57
 58    def test_code_no_user(self):
 59        """Test code without user"""
 60        device_token = DeviceToken.objects.create(
 61            provider=self.provider,
 62            user_code=generate_code_fixed_length(),
 63            device_code=generate_id(),
 64        )
 65        res = self.client.post(
 66            reverse("authentik_providers_oauth2:token"),
 67            data={
 68                "client_id": self.provider.client_id,
 69                "grant_type": GRANT_TYPE_DEVICE_CODE,
 70                "device_code": device_token.device_code,
 71            },
 72        )
 73        self.assertEqual(res.status_code, 400)
 74        body = loads(res.content.decode())
 75        self.assertEqual(body["error"], "authorization_pending")
 76
 77    def test_code(self):
 78        """Test code with user"""
 79        device_token = DeviceToken.objects.create(
 80            provider=self.provider,
 81            user_code=generate_code_fixed_length(),
 82            device_code=generate_id(),
 83            user=self.user,
 84        )
 85        res = self.client.post(
 86            reverse("authentik_providers_oauth2:token"),
 87            data={
 88                "client_id": self.provider.client_id,
 89                "grant_type": GRANT_TYPE_DEVICE_CODE,
 90                "device_code": device_token.device_code,
 91            },
 92        )
 93        self.assertEqual(res.status_code, 200)
 94
 95    def test_code_mismatched_scope(self):
 96        """Test code with user (mismatched scopes)"""
 97        device_token = DeviceToken.objects.create(
 98            provider=self.provider,
 99            user_code=generate_code_fixed_length(),
100            device_code=generate_id(),
101            user=self.user,
102            scope=[SCOPE_OPENID, SCOPE_OPENID_EMAIL],
103        )
104        res = self.client.post(
105            reverse("authentik_providers_oauth2:token"),
106            data={
107                "client_id": self.provider.client_id,
108                "grant_type": GRANT_TYPE_DEVICE_CODE,
109                "device_code": device_token.device_code,
110                "scope": f"{SCOPE_OPENID} {SCOPE_OPENID_EMAIL} invalid",
111            },
112        )
113        self.assertEqual(res.status_code, 200)
114        body = loads(res.content)
115        token = AccessToken.objects.filter(
116            provider=self.provider, token=body["access_token"]
117        ).first()
118        self.assertSetEqual(set(token.scope), {SCOPE_OPENID, SCOPE_OPENID_EMAIL})
class TestTokenDeviceCode(authentik.providers.oauth2.tests.utils.OAuthTestCase):
 29class TestTokenDeviceCode(OAuthTestCase):
 30    """Test token (device code) view"""
 31
 32    @apply_blueprint("system/providers-oauth2.yaml")
 33    def setUp(self) -> None:
 34        super().setUp()
 35        self.factory = RequestFactory()
 36        self.provider = OAuth2Provider.objects.create(
 37            name="test",
 38            authorization_flow=create_test_flow(),
 39            redirect_uris=[RedirectURI(RedirectURIMatchingMode.STRICT, "http://testserver")],
 40            signing_key=create_test_cert(),
 41        )
 42        self.provider.property_mappings.set(ScopeMapping.objects.all())
 43        self.app = Application.objects.create(name="test", slug="test", provider=self.provider)
 44        self.user = create_test_admin_user()
 45
 46    def test_code_no_code(self):
 47        """Test code without code"""
 48        res = self.client.post(
 49            reverse("authentik_providers_oauth2:token"),
 50            data={
 51                "client_id": self.provider.client_id,
 52                "grant_type": GRANT_TYPE_DEVICE_CODE,
 53            },
 54        )
 55        self.assertEqual(res.status_code, 400)
 56        body = loads(res.content.decode())
 57        self.assertEqual(body["error"], "invalid_grant")
 58
 59    def test_code_no_user(self):
 60        """Test code without user"""
 61        device_token = DeviceToken.objects.create(
 62            provider=self.provider,
 63            user_code=generate_code_fixed_length(),
 64            device_code=generate_id(),
 65        )
 66        res = self.client.post(
 67            reverse("authentik_providers_oauth2:token"),
 68            data={
 69                "client_id": self.provider.client_id,
 70                "grant_type": GRANT_TYPE_DEVICE_CODE,
 71                "device_code": device_token.device_code,
 72            },
 73        )
 74        self.assertEqual(res.status_code, 400)
 75        body = loads(res.content.decode())
 76        self.assertEqual(body["error"], "authorization_pending")
 77
 78    def test_code(self):
 79        """Test code with user"""
 80        device_token = DeviceToken.objects.create(
 81            provider=self.provider,
 82            user_code=generate_code_fixed_length(),
 83            device_code=generate_id(),
 84            user=self.user,
 85        )
 86        res = self.client.post(
 87            reverse("authentik_providers_oauth2:token"),
 88            data={
 89                "client_id": self.provider.client_id,
 90                "grant_type": GRANT_TYPE_DEVICE_CODE,
 91                "device_code": device_token.device_code,
 92            },
 93        )
 94        self.assertEqual(res.status_code, 200)
 95
 96    def test_code_mismatched_scope(self):
 97        """Test code with user (mismatched scopes)"""
 98        device_token = DeviceToken.objects.create(
 99            provider=self.provider,
100            user_code=generate_code_fixed_length(),
101            device_code=generate_id(),
102            user=self.user,
103            scope=[SCOPE_OPENID, SCOPE_OPENID_EMAIL],
104        )
105        res = self.client.post(
106            reverse("authentik_providers_oauth2:token"),
107            data={
108                "client_id": self.provider.client_id,
109                "grant_type": GRANT_TYPE_DEVICE_CODE,
110                "device_code": device_token.device_code,
111                "scope": f"{SCOPE_OPENID} {SCOPE_OPENID_EMAIL} invalid",
112            },
113        )
114        self.assertEqual(res.status_code, 200)
115        body = loads(res.content)
116        token = AccessToken.objects.filter(
117            provider=self.provider, token=body["access_token"]
118        ).first()
119        self.assertSetEqual(set(token.scope), {SCOPE_OPENID, SCOPE_OPENID_EMAIL})

Test token (device code) view

@apply_blueprint('system/providers-oauth2.yaml')
def setUp(self) -> None:
32    @apply_blueprint("system/providers-oauth2.yaml")
33    def setUp(self) -> None:
34        super().setUp()
35        self.factory = RequestFactory()
36        self.provider = OAuth2Provider.objects.create(
37            name="test",
38            authorization_flow=create_test_flow(),
39            redirect_uris=[RedirectURI(RedirectURIMatchingMode.STRICT, "http://testserver")],
40            signing_key=create_test_cert(),
41        )
42        self.provider.property_mappings.set(ScopeMapping.objects.all())
43        self.app = Application.objects.create(name="test", slug="test", provider=self.provider)
44        self.user = create_test_admin_user()

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

def test_code_no_code(self):
46    def test_code_no_code(self):
47        """Test code without code"""
48        res = self.client.post(
49            reverse("authentik_providers_oauth2:token"),
50            data={
51                "client_id": self.provider.client_id,
52                "grant_type": GRANT_TYPE_DEVICE_CODE,
53            },
54        )
55        self.assertEqual(res.status_code, 400)
56        body = loads(res.content.decode())
57        self.assertEqual(body["error"], "invalid_grant")

Test code without code

def test_code_no_user(self):
59    def test_code_no_user(self):
60        """Test code without user"""
61        device_token = DeviceToken.objects.create(
62            provider=self.provider,
63            user_code=generate_code_fixed_length(),
64            device_code=generate_id(),
65        )
66        res = self.client.post(
67            reverse("authentik_providers_oauth2:token"),
68            data={
69                "client_id": self.provider.client_id,
70                "grant_type": GRANT_TYPE_DEVICE_CODE,
71                "device_code": device_token.device_code,
72            },
73        )
74        self.assertEqual(res.status_code, 400)
75        body = loads(res.content.decode())
76        self.assertEqual(body["error"], "authorization_pending")

Test code without user

def test_code(self):
78    def test_code(self):
79        """Test code with user"""
80        device_token = DeviceToken.objects.create(
81            provider=self.provider,
82            user_code=generate_code_fixed_length(),
83            device_code=generate_id(),
84            user=self.user,
85        )
86        res = self.client.post(
87            reverse("authentik_providers_oauth2:token"),
88            data={
89                "client_id": self.provider.client_id,
90                "grant_type": GRANT_TYPE_DEVICE_CODE,
91                "device_code": device_token.device_code,
92            },
93        )
94        self.assertEqual(res.status_code, 200)

Test code with user

def test_code_mismatched_scope(self):
 96    def test_code_mismatched_scope(self):
 97        """Test code with user (mismatched scopes)"""
 98        device_token = DeviceToken.objects.create(
 99            provider=self.provider,
100            user_code=generate_code_fixed_length(),
101            device_code=generate_id(),
102            user=self.user,
103            scope=[SCOPE_OPENID, SCOPE_OPENID_EMAIL],
104        )
105        res = self.client.post(
106            reverse("authentik_providers_oauth2:token"),
107            data={
108                "client_id": self.provider.client_id,
109                "grant_type": GRANT_TYPE_DEVICE_CODE,
110                "device_code": device_token.device_code,
111                "scope": f"{SCOPE_OPENID} {SCOPE_OPENID_EMAIL} invalid",
112            },
113        )
114        self.assertEqual(res.status_code, 200)
115        body = loads(res.content)
116        token = AccessToken.objects.filter(
117            provider=self.provider, token=body["access_token"]
118        ).first()
119        self.assertSetEqual(set(token.scope), {SCOPE_OPENID, SCOPE_OPENID_EMAIL})

Test code with user (mismatched scopes)