authentik.sources.oauth.tests.test_type_openid

OpenID Type tests

  1"""OpenID Type tests"""
  2
  3import time
  4
  5from django.test import RequestFactory, TestCase
  6from jwt import encode
  7from requests_mock import Mocker
  8
  9from authentik.core.tests.utils import create_test_cert
 10from authentik.lib.generators import generate_id
 11from authentik.providers.oauth2.views.jwks import JWKSView
 12from authentik.sources.oauth.models import OAuthSource
 13from authentik.sources.oauth.types.oidc import OpenIDConnectOAuth2Callback, OpenIDConnectType
 14
 15# https://connect2id.com/products/server/docs/api/userinfo
 16OPENID_USER = {
 17    "sub": "83692",
 18    "name": "Alice Adams",
 19    "email": "alice@example.com",
 20    "department": "Engineering",
 21    "birthdate": "1975-12-31",
 22    "nickname": "foo",
 23}
 24
 25
 26class TestTypeOpenID(TestCase):
 27    """OAuth Source tests"""
 28
 29    def setUp(self):
 30        self.source = OAuthSource.objects.create(
 31            name="test",
 32            slug="test",
 33            provider_type="openidconnect",
 34            authorization_url="",
 35            profile_url="http://localhost/userinfo",
 36            consumer_key="",
 37        )
 38        self.factory = RequestFactory()
 39
 40    def test_enroll_context(self):
 41        """Test OpenID Enrollment context"""
 42        ak_context = OpenIDConnectType().get_base_user_properties(
 43            source=self.source, info=OPENID_USER
 44        )
 45        self.assertEqual(ak_context["username"], OPENID_USER["nickname"])
 46        self.assertEqual(ak_context["email"], OPENID_USER["email"])
 47        self.assertEqual(ak_context["name"], OPENID_USER["name"])
 48
 49    @Mocker()
 50    def test_userinfo(self, mock: Mocker):
 51        """Test userinfo API call"""
 52        mock.get("http://localhost/userinfo", json=OPENID_USER)
 53        token = generate_id()
 54        OpenIDConnectOAuth2Callback(request=self.factory.get("/")).get_client(
 55            self.source
 56        ).get_profile_info(
 57            {
 58                "token_type": "foo",
 59                "access_token": token,
 60            }
 61        )
 62        self.assertEqual(mock.last_request.query, "")
 63        self.assertEqual(mock.last_request.headers["Authorization"], f"foo {token}")
 64
 65    @Mocker()
 66    def test_userinfo_jwt(self, mock: Mocker):
 67        """Test id_token fallback when profile_url is empty"""
 68        jwks_cert = create_test_cert()
 69        client_id = generate_id()
 70        self.source.profile_url = ""
 71        self.source.consumer_key = client_id
 72        self.source.oidc_jwks = {"keys": [JWKSView.get_jwk_for_key(jwks_cert, "sig")]}
 73        self.source.save()
 74        token = generate_id()
 75        now = int(time.time())
 76        id_token_payload = {
 77            "iss": "https://example.com",
 78            "sub": OPENID_USER["sub"],
 79            "aud": client_id,
 80            "exp": now + 3600,
 81            "iat": now,
 82            "name": OPENID_USER["name"],
 83            "email": OPENID_USER["email"],
 84            "nickname": OPENID_USER["nickname"],
 85        }
 86        profile = (
 87            OpenIDConnectOAuth2Callback(request=self.factory.get("/"))
 88            .get_client(self.source)
 89            .get_profile_info(
 90                {
 91                    "token_type": "Bearer",
 92                    "access_token": token,
 93                    "id_token": encode(
 94                        id_token_payload,
 95                        key=jwks_cert.private_key,
 96                        algorithm="RS256",
 97                        headers={"kid": self.source.oidc_jwks["keys"][0]["kid"]},
 98                    ),
 99                }
100            )
101        )
102        self.assertEqual(profile["sub"], OPENID_USER["sub"])
103        self.assertEqual(profile["name"], OPENID_USER["name"])
104        self.assertEqual(profile["email"], OPENID_USER["email"])
105        self.assertEqual(profile["aud"], client_id)
106        self.assertEqual(profile["iss"], "https://example.com")
OPENID_USER = {'sub': '83692', 'name': 'Alice Adams', 'email': 'alice@example.com', 'department': 'Engineering', 'birthdate': '1975-12-31', 'nickname': 'foo'}
class TestTypeOpenID(django.test.testcases.TestCase):
 27class TestTypeOpenID(TestCase):
 28    """OAuth Source tests"""
 29
 30    def setUp(self):
 31        self.source = OAuthSource.objects.create(
 32            name="test",
 33            slug="test",
 34            provider_type="openidconnect",
 35            authorization_url="",
 36            profile_url="http://localhost/userinfo",
 37            consumer_key="",
 38        )
 39        self.factory = RequestFactory()
 40
 41    def test_enroll_context(self):
 42        """Test OpenID Enrollment context"""
 43        ak_context = OpenIDConnectType().get_base_user_properties(
 44            source=self.source, info=OPENID_USER
 45        )
 46        self.assertEqual(ak_context["username"], OPENID_USER["nickname"])
 47        self.assertEqual(ak_context["email"], OPENID_USER["email"])
 48        self.assertEqual(ak_context["name"], OPENID_USER["name"])
 49
 50    @Mocker()
 51    def test_userinfo(self, mock: Mocker):
 52        """Test userinfo API call"""
 53        mock.get("http://localhost/userinfo", json=OPENID_USER)
 54        token = generate_id()
 55        OpenIDConnectOAuth2Callback(request=self.factory.get("/")).get_client(
 56            self.source
 57        ).get_profile_info(
 58            {
 59                "token_type": "foo",
 60                "access_token": token,
 61            }
 62        )
 63        self.assertEqual(mock.last_request.query, "")
 64        self.assertEqual(mock.last_request.headers["Authorization"], f"foo {token}")
 65
 66    @Mocker()
 67    def test_userinfo_jwt(self, mock: Mocker):
 68        """Test id_token fallback when profile_url is empty"""
 69        jwks_cert = create_test_cert()
 70        client_id = generate_id()
 71        self.source.profile_url = ""
 72        self.source.consumer_key = client_id
 73        self.source.oidc_jwks = {"keys": [JWKSView.get_jwk_for_key(jwks_cert, "sig")]}
 74        self.source.save()
 75        token = generate_id()
 76        now = int(time.time())
 77        id_token_payload = {
 78            "iss": "https://example.com",
 79            "sub": OPENID_USER["sub"],
 80            "aud": client_id,
 81            "exp": now + 3600,
 82            "iat": now,
 83            "name": OPENID_USER["name"],
 84            "email": OPENID_USER["email"],
 85            "nickname": OPENID_USER["nickname"],
 86        }
 87        profile = (
 88            OpenIDConnectOAuth2Callback(request=self.factory.get("/"))
 89            .get_client(self.source)
 90            .get_profile_info(
 91                {
 92                    "token_type": "Bearer",
 93                    "access_token": token,
 94                    "id_token": encode(
 95                        id_token_payload,
 96                        key=jwks_cert.private_key,
 97                        algorithm="RS256",
 98                        headers={"kid": self.source.oidc_jwks["keys"][0]["kid"]},
 99                    ),
100                }
101            )
102        )
103        self.assertEqual(profile["sub"], OPENID_USER["sub"])
104        self.assertEqual(profile["name"], OPENID_USER["name"])
105        self.assertEqual(profile["email"], OPENID_USER["email"])
106        self.assertEqual(profile["aud"], client_id)
107        self.assertEqual(profile["iss"], "https://example.com")

OAuth Source tests

def setUp(self):
30    def setUp(self):
31        self.source = OAuthSource.objects.create(
32            name="test",
33            slug="test",
34            provider_type="openidconnect",
35            authorization_url="",
36            profile_url="http://localhost/userinfo",
37            consumer_key="",
38        )
39        self.factory = RequestFactory()

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

def test_enroll_context(self):
41    def test_enroll_context(self):
42        """Test OpenID Enrollment context"""
43        ak_context = OpenIDConnectType().get_base_user_properties(
44            source=self.source, info=OPENID_USER
45        )
46        self.assertEqual(ak_context["username"], OPENID_USER["nickname"])
47        self.assertEqual(ak_context["email"], OPENID_USER["email"])
48        self.assertEqual(ak_context["name"], OPENID_USER["name"])

Test OpenID Enrollment context

@Mocker()
def test_userinfo(self, mock: requests_mock.mocker.Mocker):
50    @Mocker()
51    def test_userinfo(self, mock: Mocker):
52        """Test userinfo API call"""
53        mock.get("http://localhost/userinfo", json=OPENID_USER)
54        token = generate_id()
55        OpenIDConnectOAuth2Callback(request=self.factory.get("/")).get_client(
56            self.source
57        ).get_profile_info(
58            {
59                "token_type": "foo",
60                "access_token": token,
61            }
62        )
63        self.assertEqual(mock.last_request.query, "")
64        self.assertEqual(mock.last_request.headers["Authorization"], f"foo {token}")

Test userinfo API call

@Mocker()
def test_userinfo_jwt(self, mock: requests_mock.mocker.Mocker):
 66    @Mocker()
 67    def test_userinfo_jwt(self, mock: Mocker):
 68        """Test id_token fallback when profile_url is empty"""
 69        jwks_cert = create_test_cert()
 70        client_id = generate_id()
 71        self.source.profile_url = ""
 72        self.source.consumer_key = client_id
 73        self.source.oidc_jwks = {"keys": [JWKSView.get_jwk_for_key(jwks_cert, "sig")]}
 74        self.source.save()
 75        token = generate_id()
 76        now = int(time.time())
 77        id_token_payload = {
 78            "iss": "https://example.com",
 79            "sub": OPENID_USER["sub"],
 80            "aud": client_id,
 81            "exp": now + 3600,
 82            "iat": now,
 83            "name": OPENID_USER["name"],
 84            "email": OPENID_USER["email"],
 85            "nickname": OPENID_USER["nickname"],
 86        }
 87        profile = (
 88            OpenIDConnectOAuth2Callback(request=self.factory.get("/"))
 89            .get_client(self.source)
 90            .get_profile_info(
 91                {
 92                    "token_type": "Bearer",
 93                    "access_token": token,
 94                    "id_token": encode(
 95                        id_token_payload,
 96                        key=jwks_cert.private_key,
 97                        algorithm="RS256",
 98                        headers={"kid": self.source.oidc_jwks["keys"][0]["kid"]},
 99                    ),
100                }
101            )
102        )
103        self.assertEqual(profile["sub"], OPENID_USER["sub"])
104        self.assertEqual(profile["name"], OPENID_USER["name"])
105        self.assertEqual(profile["email"], OPENID_USER["email"])
106        self.assertEqual(profile["aud"], client_id)
107        self.assertEqual(profile["iss"], "https://example.com")

Test id_token fallback when profile_url is empty