authentik.providers.oauth2.tests.test_jwks

JWKS tests

  1"""JWKS tests"""
  2
  3import base64
  4import json
  5
  6from cryptography.hazmat.backends import default_backend
  7from cryptography.x509 import load_der_x509_certificate
  8from django.urls.base import reverse
  9from jwt import PyJWKSet
 10
 11from authentik.core.models import Application
 12from authentik.core.tests.utils import create_test_cert, create_test_flow
 13from authentik.crypto.builder import PrivateKeyAlg
 14from authentik.crypto.models import CertificateKeyPair
 15from authentik.lib.generators import generate_id
 16from authentik.providers.oauth2.models import OAuth2Provider, RedirectURI, RedirectURIMatchingMode
 17from authentik.providers.oauth2.tests.utils import OAuthTestCase
 18
 19TEST_CORDS_CERT = """
 20-----BEGIN CERTIFICATE-----
 21MIIB6jCCAZCgAwIBAgIRAOsdE3N7zETzs+7shTXGj5wwCgYIKoZIzj0EAwIwHjEc
 22MBoGA1UEAwwTYXV0aGVudGlrIDIwMjIuMTIuMjAeFw0yMzAxMTYyMjU2MjVaFw0y
 23NDAxMTIyMjU2MjVaMHgxTDBKBgNVBAMMQ0NsbDR2TzFJSGxvdFFhTGwwMHpES2tM
 24WENYdzRPUFF2eEtZN1NrczAuc2VsZi1zaWduZWQuZ29hdXRoZW50aWsuaW8xEjAQ
 25BgNVBAoMCWF1dGhlbnRpazEUMBIGA1UECwwLU2VsZi1zaWduZWQwWTATBgcqhkjO
 26PQIBBggqhkjOPQMBBwNCAAQAwOGam7AKOi5LKmb9lK1rAzA2JTppqrFiIaUdjqmH
 27ZICJP00Wt0dfqOtEjgMEv1Hhu1DmKZn2ehvpxwPSzBr5o1UwUzBRBgNVHREBAf8E
 28RzBFgkNCNkw4YlI0UldJRU42NUZLamdUTzV1YmRvNUZWdkpNS2lxdjFZeTRULnNl
 29bGYtc2lnbmVkLmdvYXV0aGVudGlrLmlvMAoGCCqGSM49BAMCA0gAMEUCIC/JAfnl
 30uC30ihqepbiMCaTaPMbL8Ka2Lk92IYfMhf46AiEAz9Kmv6HF2D4MK54iwhz2WqvF
 318vo+OiGdTQ1Qoj7fgYU=
 32-----END CERTIFICATE-----
 33"""
 34TEST_CORDS_KEY = """
 35-----BEGIN EC PRIVATE KEY-----
 36MHcCAQEEIKy6mPLJc5v71InMMvYaxyXI3xXpwQTPLyAYWVFnZHVioAoGCCqGSM49
 37AwEHoUQDQgAEAMDhmpuwCjouSypm/ZStawMwNiU6aaqxYiGlHY6ph2SAiT9NFrdH
 38X6jrRI4DBL9R4btQ5imZ9nob6ccD0swa+Q==
 39-----END EC PRIVATE KEY-----
 40"""
 41
 42
 43class TestJWKS(OAuthTestCase):
 44    """Test JWKS view"""
 45
 46    def test_rs256(self):
 47        """Test JWKS request with RS256"""
 48        provider = OAuth2Provider.objects.create(
 49            name="test",
 50            client_id="test",
 51            authorization_flow=create_test_flow(),
 52            redirect_uris=[RedirectURI(RedirectURIMatchingMode.STRICT, "http://local.invalid")],
 53            signing_key=create_test_cert(),
 54        )
 55        app = Application.objects.create(name="test", slug="test", provider=provider)
 56        response = self.client.get(
 57            reverse("authentik_providers_oauth2:jwks", kwargs={"application_slug": app.slug})
 58        )
 59        body = json.loads(response.content.decode())
 60        self.assertEqual(len(body["keys"]), 1)
 61        PyJWKSet.from_dict(body)
 62        key = body["keys"][0]
 63        load_der_x509_certificate(base64.b64decode(key["x5c"][0]), default_backend()).public_key()
 64
 65    def test_hs256(self):
 66        """Test JWKS request with HS256"""
 67        provider = OAuth2Provider.objects.create(
 68            name="test",
 69            client_id="test",
 70            authorization_flow=create_test_flow(),
 71            redirect_uris=[RedirectURI(RedirectURIMatchingMode.STRICT, "http://local.invalid")],
 72        )
 73        app = Application.objects.create(name="test", slug="test", provider=provider)
 74        response = self.client.get(
 75            reverse("authentik_providers_oauth2:jwks", kwargs={"application_slug": app.slug})
 76        )
 77        self.assertJSONEqual(response.content.decode(), {})
 78
 79    def test_es256(self):
 80        """Test JWKS request with ES256"""
 81        provider = OAuth2Provider.objects.create(
 82            name="test",
 83            client_id="test",
 84            authorization_flow=create_test_flow(),
 85            redirect_uris=[RedirectURI(RedirectURIMatchingMode.STRICT, "http://local.invalid")],
 86            signing_key=create_test_cert(PrivateKeyAlg.ECDSA),
 87        )
 88        app = Application.objects.create(name="test", slug="test", provider=provider)
 89        response = self.client.get(
 90            reverse("authentik_providers_oauth2:jwks", kwargs={"application_slug": app.slug})
 91        )
 92        body = json.loads(response.content.decode())
 93        self.assertEqual(len(body["keys"]), 1)
 94        PyJWKSet.from_dict(body)
 95
 96    def test_enc(self):
 97        """Test with JWE"""
 98        provider = OAuth2Provider.objects.create(
 99            name="test",
100            client_id="test",
101            authorization_flow=create_test_flow(),
102            redirect_uris=[RedirectURI(RedirectURIMatchingMode.STRICT, "http://local.invalid")],
103            signing_key=create_test_cert(PrivateKeyAlg.ECDSA),
104            encryption_key=create_test_cert(PrivateKeyAlg.ECDSA),
105        )
106        app = Application.objects.create(name="test", slug="test", provider=provider)
107        response = self.client.get(
108            reverse("authentik_providers_oauth2:jwks", kwargs={"application_slug": app.slug})
109        )
110        body = json.loads(response.content.decode())
111        self.assertEqual(len(body["keys"]), 2)
112        PyJWKSet.from_dict(body)
113
114    def test_ecdsa_coords_mismatched(self):
115        """Test JWKS request with ES256"""
116        cert = CertificateKeyPair.objects.create(
117            name=generate_id(),
118            key_data=TEST_CORDS_KEY,
119            certificate_data=TEST_CORDS_CERT,
120        )
121        provider = OAuth2Provider.objects.create(
122            name="test",
123            client_id="test",
124            authorization_flow=create_test_flow(),
125            redirect_uris=[RedirectURI(RedirectURIMatchingMode.STRICT, "http://local.invalid")],
126            signing_key=cert,
127        )
128        app = Application.objects.create(name="test", slug="test", provider=provider)
129        response = self.client.get(
130            reverse("authentik_providers_oauth2:jwks", kwargs={"application_slug": app.slug})
131        )
132        body = json.loads(response.content.decode())
133        self.assertEqual(len(body["keys"]), 1)
134        PyJWKSet.from_dict(body)
TEST_CORDS_CERT = '\n-----BEGIN CERTIFICATE-----\nMIIB6jCCAZCgAwIBAgIRAOsdE3N7zETzs+7shTXGj5wwCgYIKoZIzj0EAwIwHjEc\nMBoGA1UEAwwTYXV0aGVudGlrIDIwMjIuMTIuMjAeFw0yMzAxMTYyMjU2MjVaFw0y\nNDAxMTIyMjU2MjVaMHgxTDBKBgNVBAMMQ0NsbDR2TzFJSGxvdFFhTGwwMHpES2tM\nWENYdzRPUFF2eEtZN1NrczAuc2VsZi1zaWduZWQuZ29hdXRoZW50aWsuaW8xEjAQ\nBgNVBAoMCWF1dGhlbnRpazEUMBIGA1UECwwLU2VsZi1zaWduZWQwWTATBgcqhkjO\nPQIBBggqhkjOPQMBBwNCAAQAwOGam7AKOi5LKmb9lK1rAzA2JTppqrFiIaUdjqmH\nZICJP00Wt0dfqOtEjgMEv1Hhu1DmKZn2ehvpxwPSzBr5o1UwUzBRBgNVHREBAf8E\nRzBFgkNCNkw4YlI0UldJRU42NUZLamdUTzV1YmRvNUZWdkpNS2lxdjFZeTRULnNl\nbGYtc2lnbmVkLmdvYXV0aGVudGlrLmlvMAoGCCqGSM49BAMCA0gAMEUCIC/JAfnl\nuC30ihqepbiMCaTaPMbL8Ka2Lk92IYfMhf46AiEAz9Kmv6HF2D4MK54iwhz2WqvF\n8vo+OiGdTQ1Qoj7fgYU=\n-----END CERTIFICATE-----\n'
TEST_CORDS_KEY = '\n-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIKy6mPLJc5v71InMMvYaxyXI3xXpwQTPLyAYWVFnZHVioAoGCCqGSM49\nAwEHoUQDQgAEAMDhmpuwCjouSypm/ZStawMwNiU6aaqxYiGlHY6ph2SAiT9NFrdH\nX6jrRI4DBL9R4btQ5imZ9nob6ccD0swa+Q==\n-----END EC PRIVATE KEY-----\n'
 44class TestJWKS(OAuthTestCase):
 45    """Test JWKS view"""
 46
 47    def test_rs256(self):
 48        """Test JWKS request with RS256"""
 49        provider = OAuth2Provider.objects.create(
 50            name="test",
 51            client_id="test",
 52            authorization_flow=create_test_flow(),
 53            redirect_uris=[RedirectURI(RedirectURIMatchingMode.STRICT, "http://local.invalid")],
 54            signing_key=create_test_cert(),
 55        )
 56        app = Application.objects.create(name="test", slug="test", provider=provider)
 57        response = self.client.get(
 58            reverse("authentik_providers_oauth2:jwks", kwargs={"application_slug": app.slug})
 59        )
 60        body = json.loads(response.content.decode())
 61        self.assertEqual(len(body["keys"]), 1)
 62        PyJWKSet.from_dict(body)
 63        key = body["keys"][0]
 64        load_der_x509_certificate(base64.b64decode(key["x5c"][0]), default_backend()).public_key()
 65
 66    def test_hs256(self):
 67        """Test JWKS request with HS256"""
 68        provider = OAuth2Provider.objects.create(
 69            name="test",
 70            client_id="test",
 71            authorization_flow=create_test_flow(),
 72            redirect_uris=[RedirectURI(RedirectURIMatchingMode.STRICT, "http://local.invalid")],
 73        )
 74        app = Application.objects.create(name="test", slug="test", provider=provider)
 75        response = self.client.get(
 76            reverse("authentik_providers_oauth2:jwks", kwargs={"application_slug": app.slug})
 77        )
 78        self.assertJSONEqual(response.content.decode(), {})
 79
 80    def test_es256(self):
 81        """Test JWKS request with ES256"""
 82        provider = OAuth2Provider.objects.create(
 83            name="test",
 84            client_id="test",
 85            authorization_flow=create_test_flow(),
 86            redirect_uris=[RedirectURI(RedirectURIMatchingMode.STRICT, "http://local.invalid")],
 87            signing_key=create_test_cert(PrivateKeyAlg.ECDSA),
 88        )
 89        app = Application.objects.create(name="test", slug="test", provider=provider)
 90        response = self.client.get(
 91            reverse("authentik_providers_oauth2:jwks", kwargs={"application_slug": app.slug})
 92        )
 93        body = json.loads(response.content.decode())
 94        self.assertEqual(len(body["keys"]), 1)
 95        PyJWKSet.from_dict(body)
 96
 97    def test_enc(self):
 98        """Test with JWE"""
 99        provider = OAuth2Provider.objects.create(
100            name="test",
101            client_id="test",
102            authorization_flow=create_test_flow(),
103            redirect_uris=[RedirectURI(RedirectURIMatchingMode.STRICT, "http://local.invalid")],
104            signing_key=create_test_cert(PrivateKeyAlg.ECDSA),
105            encryption_key=create_test_cert(PrivateKeyAlg.ECDSA),
106        )
107        app = Application.objects.create(name="test", slug="test", provider=provider)
108        response = self.client.get(
109            reverse("authentik_providers_oauth2:jwks", kwargs={"application_slug": app.slug})
110        )
111        body = json.loads(response.content.decode())
112        self.assertEqual(len(body["keys"]), 2)
113        PyJWKSet.from_dict(body)
114
115    def test_ecdsa_coords_mismatched(self):
116        """Test JWKS request with ES256"""
117        cert = CertificateKeyPair.objects.create(
118            name=generate_id(),
119            key_data=TEST_CORDS_KEY,
120            certificate_data=TEST_CORDS_CERT,
121        )
122        provider = OAuth2Provider.objects.create(
123            name="test",
124            client_id="test",
125            authorization_flow=create_test_flow(),
126            redirect_uris=[RedirectURI(RedirectURIMatchingMode.STRICT, "http://local.invalid")],
127            signing_key=cert,
128        )
129        app = Application.objects.create(name="test", slug="test", provider=provider)
130        response = self.client.get(
131            reverse("authentik_providers_oauth2:jwks", kwargs={"application_slug": app.slug})
132        )
133        body = json.loads(response.content.decode())
134        self.assertEqual(len(body["keys"]), 1)
135        PyJWKSet.from_dict(body)

Test JWKS view

def test_rs256(self):
47    def test_rs256(self):
48        """Test JWKS request with RS256"""
49        provider = OAuth2Provider.objects.create(
50            name="test",
51            client_id="test",
52            authorization_flow=create_test_flow(),
53            redirect_uris=[RedirectURI(RedirectURIMatchingMode.STRICT, "http://local.invalid")],
54            signing_key=create_test_cert(),
55        )
56        app = Application.objects.create(name="test", slug="test", provider=provider)
57        response = self.client.get(
58            reverse("authentik_providers_oauth2:jwks", kwargs={"application_slug": app.slug})
59        )
60        body = json.loads(response.content.decode())
61        self.assertEqual(len(body["keys"]), 1)
62        PyJWKSet.from_dict(body)
63        key = body["keys"][0]
64        load_der_x509_certificate(base64.b64decode(key["x5c"][0]), default_backend()).public_key()

Test JWKS request with RS256

def test_hs256(self):
66    def test_hs256(self):
67        """Test JWKS request with HS256"""
68        provider = OAuth2Provider.objects.create(
69            name="test",
70            client_id="test",
71            authorization_flow=create_test_flow(),
72            redirect_uris=[RedirectURI(RedirectURIMatchingMode.STRICT, "http://local.invalid")],
73        )
74        app = Application.objects.create(name="test", slug="test", provider=provider)
75        response = self.client.get(
76            reverse("authentik_providers_oauth2:jwks", kwargs={"application_slug": app.slug})
77        )
78        self.assertJSONEqual(response.content.decode(), {})

Test JWKS request with HS256

def test_es256(self):
80    def test_es256(self):
81        """Test JWKS request with ES256"""
82        provider = OAuth2Provider.objects.create(
83            name="test",
84            client_id="test",
85            authorization_flow=create_test_flow(),
86            redirect_uris=[RedirectURI(RedirectURIMatchingMode.STRICT, "http://local.invalid")],
87            signing_key=create_test_cert(PrivateKeyAlg.ECDSA),
88        )
89        app = Application.objects.create(name="test", slug="test", provider=provider)
90        response = self.client.get(
91            reverse("authentik_providers_oauth2:jwks", kwargs={"application_slug": app.slug})
92        )
93        body = json.loads(response.content.decode())
94        self.assertEqual(len(body["keys"]), 1)
95        PyJWKSet.from_dict(body)

Test JWKS request with ES256

def test_enc(self):
 97    def test_enc(self):
 98        """Test with JWE"""
 99        provider = OAuth2Provider.objects.create(
100            name="test",
101            client_id="test",
102            authorization_flow=create_test_flow(),
103            redirect_uris=[RedirectURI(RedirectURIMatchingMode.STRICT, "http://local.invalid")],
104            signing_key=create_test_cert(PrivateKeyAlg.ECDSA),
105            encryption_key=create_test_cert(PrivateKeyAlg.ECDSA),
106        )
107        app = Application.objects.create(name="test", slug="test", provider=provider)
108        response = self.client.get(
109            reverse("authentik_providers_oauth2:jwks", kwargs={"application_slug": app.slug})
110        )
111        body = json.loads(response.content.decode())
112        self.assertEqual(len(body["keys"]), 2)
113        PyJWKSet.from_dict(body)

Test with JWE

def test_ecdsa_coords_mismatched(self):
115    def test_ecdsa_coords_mismatched(self):
116        """Test JWKS request with ES256"""
117        cert = CertificateKeyPair.objects.create(
118            name=generate_id(),
119            key_data=TEST_CORDS_KEY,
120            certificate_data=TEST_CORDS_CERT,
121        )
122        provider = OAuth2Provider.objects.create(
123            name="test",
124            client_id="test",
125            authorization_flow=create_test_flow(),
126            redirect_uris=[RedirectURI(RedirectURIMatchingMode.STRICT, "http://local.invalid")],
127            signing_key=cert,
128        )
129        app = Application.objects.create(name="test", slug="test", provider=provider)
130        response = self.client.get(
131            reverse("authentik_providers_oauth2:jwks", kwargs={"application_slug": app.slug})
132        )
133        body = json.loads(response.content.decode())
134        self.assertEqual(len(body["keys"]), 1)
135        PyJWKSet.from_dict(body)

Test JWKS request with ES256