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    GrantType,
 21    OAuth2Provider,
 22    RedirectURI,
 23    RedirectURIMatchingMode,
 24    ScopeMapping,
 25)
 26from authentik.providers.oauth2.tests.utils import OAuthTestCase
 27
 28
 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            grant_types=[GrantType.DEVICE_CODE],
 42        )
 43        self.provider.property_mappings.set(ScopeMapping.objects.all())
 44        self.app = Application.objects.create(name="test", slug="test", provider=self.provider)
 45        self.user = create_test_admin_user()
 46
 47    def test_code_no_code(self):
 48        """Test code without code"""
 49        res = self.client.post(
 50            reverse("authentik_providers_oauth2:token"),
 51            data={
 52                "client_id": self.provider.client_id,
 53                "client_secret": self.provider.client_secret,
 54                "grant_type": GRANT_TYPE_DEVICE_CODE,
 55            },
 56        )
 57        self.assertEqual(res.status_code, 400)
 58        body = loads(res.content.decode())
 59        self.assertEqual(body["error"], "invalid_grant")
 60
 61    def test_code_no_user(self):
 62        """Test code without user"""
 63        device_token = DeviceToken.objects.create(
 64            provider=self.provider,
 65            user_code=generate_code_fixed_length(),
 66            device_code=generate_id(),
 67        )
 68        res = self.client.post(
 69            reverse("authentik_providers_oauth2:token"),
 70            data={
 71                "client_id": self.provider.client_id,
 72                "client_secret": self.provider.client_secret,
 73                "grant_type": GRANT_TYPE_DEVICE_CODE,
 74                "device_code": device_token.device_code,
 75            },
 76        )
 77        self.assertEqual(res.status_code, 400)
 78        body = loads(res.content.decode())
 79        self.assertEqual(body["error"], "authorization_pending")
 80
 81    def test_code_no_auth(self):
 82        """Test code with user"""
 83        device_token = DeviceToken.objects.create(
 84            provider=self.provider,
 85            user_code=generate_code_fixed_length(),
 86            device_code=generate_id(),
 87            user=self.user,
 88        )
 89        res = self.client.post(
 90            reverse("authentik_providers_oauth2:token"),
 91            data={
 92                "client_id": self.provider.client_id,
 93                "grant_type": GRANT_TYPE_DEVICE_CODE,
 94                "device_code": device_token.device_code,
 95            },
 96        )
 97        self.assertEqual(res.status_code, 400)
 98        body = loads(res.content.decode())
 99        self.assertEqual(body["error"], "invalid_client")
100
101    def test_code(self):
102        """Test code with user"""
103        device_token = DeviceToken.objects.create(
104            provider=self.provider,
105            user_code=generate_code_fixed_length(),
106            device_code=generate_id(),
107            user=self.user,
108        )
109        res = self.client.post(
110            reverse("authentik_providers_oauth2:token"),
111            data={
112                "client_id": self.provider.client_id,
113                "client_secret": self.provider.client_secret,
114                "grant_type": GRANT_TYPE_DEVICE_CODE,
115                "device_code": device_token.device_code,
116            },
117        )
118        self.assertEqual(res.status_code, 200)
119
120    def test_code_mismatched_scope(self):
121        """Test code with user (mismatched scopes)"""
122        device_token = DeviceToken.objects.create(
123            provider=self.provider,
124            user_code=generate_code_fixed_length(),
125            device_code=generate_id(),
126            user=self.user,
127            scope=[SCOPE_OPENID, SCOPE_OPENID_EMAIL],
128        )
129        res = self.client.post(
130            reverse("authentik_providers_oauth2:token"),
131            data={
132                "client_id": self.provider.client_id,
133                "client_secret": self.provider.client_secret,
134                "grant_type": GRANT_TYPE_DEVICE_CODE,
135                "device_code": device_token.device_code,
136                "scope": f"{SCOPE_OPENID} {SCOPE_OPENID_EMAIL} invalid",
137            },
138        )
139        self.assertEqual(res.status_code, 200)
140        body = loads(res.content)
141        token = AccessToken.objects.filter(
142            provider=self.provider, token=body["access_token"]
143        ).first()
144        self.assertSetEqual(set(token.scope), {SCOPE_OPENID, SCOPE_OPENID_EMAIL})
class TestTokenDeviceCode(authentik.providers.oauth2.tests.utils.OAuthTestCase):
 30class TestTokenDeviceCode(OAuthTestCase):
 31    """Test token (device code) view"""
 32
 33    @apply_blueprint("system/providers-oauth2.yaml")
 34    def setUp(self) -> None:
 35        super().setUp()
 36        self.factory = RequestFactory()
 37        self.provider = OAuth2Provider.objects.create(
 38            name="test",
 39            authorization_flow=create_test_flow(),
 40            redirect_uris=[RedirectURI(RedirectURIMatchingMode.STRICT, "http://testserver")],
 41            signing_key=create_test_cert(),
 42            grant_types=[GrantType.DEVICE_CODE],
 43        )
 44        self.provider.property_mappings.set(ScopeMapping.objects.all())
 45        self.app = Application.objects.create(name="test", slug="test", provider=self.provider)
 46        self.user = create_test_admin_user()
 47
 48    def test_code_no_code(self):
 49        """Test code without code"""
 50        res = self.client.post(
 51            reverse("authentik_providers_oauth2:token"),
 52            data={
 53                "client_id": self.provider.client_id,
 54                "client_secret": self.provider.client_secret,
 55                "grant_type": GRANT_TYPE_DEVICE_CODE,
 56            },
 57        )
 58        self.assertEqual(res.status_code, 400)
 59        body = loads(res.content.decode())
 60        self.assertEqual(body["error"], "invalid_grant")
 61
 62    def test_code_no_user(self):
 63        """Test code without user"""
 64        device_token = DeviceToken.objects.create(
 65            provider=self.provider,
 66            user_code=generate_code_fixed_length(),
 67            device_code=generate_id(),
 68        )
 69        res = self.client.post(
 70            reverse("authentik_providers_oauth2:token"),
 71            data={
 72                "client_id": self.provider.client_id,
 73                "client_secret": self.provider.client_secret,
 74                "grant_type": GRANT_TYPE_DEVICE_CODE,
 75                "device_code": device_token.device_code,
 76            },
 77        )
 78        self.assertEqual(res.status_code, 400)
 79        body = loads(res.content.decode())
 80        self.assertEqual(body["error"], "authorization_pending")
 81
 82    def test_code_no_auth(self):
 83        """Test code with user"""
 84        device_token = DeviceToken.objects.create(
 85            provider=self.provider,
 86            user_code=generate_code_fixed_length(),
 87            device_code=generate_id(),
 88            user=self.user,
 89        )
 90        res = self.client.post(
 91            reverse("authentik_providers_oauth2:token"),
 92            data={
 93                "client_id": self.provider.client_id,
 94                "grant_type": GRANT_TYPE_DEVICE_CODE,
 95                "device_code": device_token.device_code,
 96            },
 97        )
 98        self.assertEqual(res.status_code, 400)
 99        body = loads(res.content.decode())
100        self.assertEqual(body["error"], "invalid_client")
101
102    def test_code(self):
103        """Test code with user"""
104        device_token = DeviceToken.objects.create(
105            provider=self.provider,
106            user_code=generate_code_fixed_length(),
107            device_code=generate_id(),
108            user=self.user,
109        )
110        res = self.client.post(
111            reverse("authentik_providers_oauth2:token"),
112            data={
113                "client_id": self.provider.client_id,
114                "client_secret": self.provider.client_secret,
115                "grant_type": GRANT_TYPE_DEVICE_CODE,
116                "device_code": device_token.device_code,
117            },
118        )
119        self.assertEqual(res.status_code, 200)
120
121    def test_code_mismatched_scope(self):
122        """Test code with user (mismatched scopes)"""
123        device_token = DeviceToken.objects.create(
124            provider=self.provider,
125            user_code=generate_code_fixed_length(),
126            device_code=generate_id(),
127            user=self.user,
128            scope=[SCOPE_OPENID, SCOPE_OPENID_EMAIL],
129        )
130        res = self.client.post(
131            reverse("authentik_providers_oauth2:token"),
132            data={
133                "client_id": self.provider.client_id,
134                "client_secret": self.provider.client_secret,
135                "grant_type": GRANT_TYPE_DEVICE_CODE,
136                "device_code": device_token.device_code,
137                "scope": f"{SCOPE_OPENID} {SCOPE_OPENID_EMAIL} invalid",
138            },
139        )
140        self.assertEqual(res.status_code, 200)
141        body = loads(res.content)
142        token = AccessToken.objects.filter(
143            provider=self.provider, token=body["access_token"]
144        ).first()
145        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:
33    @apply_blueprint("system/providers-oauth2.yaml")
34    def setUp(self) -> None:
35        super().setUp()
36        self.factory = RequestFactory()
37        self.provider = OAuth2Provider.objects.create(
38            name="test",
39            authorization_flow=create_test_flow(),
40            redirect_uris=[RedirectURI(RedirectURIMatchingMode.STRICT, "http://testserver")],
41            signing_key=create_test_cert(),
42            grant_types=[GrantType.DEVICE_CODE],
43        )
44        self.provider.property_mappings.set(ScopeMapping.objects.all())
45        self.app = Application.objects.create(name="test", slug="test", provider=self.provider)
46        self.user = create_test_admin_user()

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

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

Test code without code

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

Test code without user

def test_code_no_auth(self):
 82    def test_code_no_auth(self):
 83        """Test code with user"""
 84        device_token = DeviceToken.objects.create(
 85            provider=self.provider,
 86            user_code=generate_code_fixed_length(),
 87            device_code=generate_id(),
 88            user=self.user,
 89        )
 90        res = self.client.post(
 91            reverse("authentik_providers_oauth2:token"),
 92            data={
 93                "client_id": self.provider.client_id,
 94                "grant_type": GRANT_TYPE_DEVICE_CODE,
 95                "device_code": device_token.device_code,
 96            },
 97        )
 98        self.assertEqual(res.status_code, 400)
 99        body = loads(res.content.decode())
100        self.assertEqual(body["error"], "invalid_client")

Test code with user

def test_code(self):
102    def test_code(self):
103        """Test code with user"""
104        device_token = DeviceToken.objects.create(
105            provider=self.provider,
106            user_code=generate_code_fixed_length(),
107            device_code=generate_id(),
108            user=self.user,
109        )
110        res = self.client.post(
111            reverse("authentik_providers_oauth2:token"),
112            data={
113                "client_id": self.provider.client_id,
114                "client_secret": self.provider.client_secret,
115                "grant_type": GRANT_TYPE_DEVICE_CODE,
116                "device_code": device_token.device_code,
117            },
118        )
119        self.assertEqual(res.status_code, 200)

Test code with user

def test_code_mismatched_scope(self):
121    def test_code_mismatched_scope(self):
122        """Test code with user (mismatched scopes)"""
123        device_token = DeviceToken.objects.create(
124            provider=self.provider,
125            user_code=generate_code_fixed_length(),
126            device_code=generate_id(),
127            user=self.user,
128            scope=[SCOPE_OPENID, SCOPE_OPENID_EMAIL],
129        )
130        res = self.client.post(
131            reverse("authentik_providers_oauth2:token"),
132            data={
133                "client_id": self.provider.client_id,
134                "client_secret": self.provider.client_secret,
135                "grant_type": GRANT_TYPE_DEVICE_CODE,
136                "device_code": device_token.device_code,
137                "scope": f"{SCOPE_OPENID} {SCOPE_OPENID_EMAIL} invalid",
138            },
139        )
140        self.assertEqual(res.status_code, 200)
141        body = loads(res.content)
142        token = AccessToken.objects.filter(
143            provider=self.provider, token=body["access_token"]
144        ).first()
145        self.assertSetEqual(set(token.scope), {SCOPE_OPENID, SCOPE_OPENID_EMAIL})

Test code with user (mismatched scopes)