import datetime import os import uuid import pytest from authlib.oidc.core.grants.util import generate_id_token from canaille.oidc.models import AuthorizationCode from canaille.oidc.models import Client from canaille.oidc.models import Consent from canaille.oidc.models import Token from canaille.oidc.oauth import generate_user_info from canaille.oidc.oauth import get_jwt_config from cryptography.hazmat.backends import default_backend as crypto_default_backend from cryptography.hazmat.primitives import serialization as crypto_serialization from cryptography.hazmat.primitives.asymmetric import rsa from werkzeug.security import gen_salt @pytest.fixture def app(app): os.environ["AUTHLIB_INSECURE_TRANSPORT"] = "true" yield app @pytest.fixture(scope="session") def keypair(): key = rsa.generate_private_key( backend=crypto_default_backend(), public_exponent=65537, key_size=2048 ) private_key = key.private_bytes( crypto_serialization.Encoding.PEM, crypto_serialization.PrivateFormat.PKCS8, crypto_serialization.NoEncryption(), ) public_key = key.public_key().public_bytes( crypto_serialization.Encoding.OpenSSH, crypto_serialization.PublicFormat.OpenSSH ) return private_key, public_key @pytest.fixture def keypair_path(keypair, tmp_path): private_key, public_key = keypair private_key_path = os.path.join(tmp_path, "private.pem") with open(private_key_path, "wb") as fd: fd.write(private_key) public_key_path = os.path.join(tmp_path, "public.pem") with open(public_key_path, "wb") as fd: fd.write(public_key) return private_key_path, public_key_path @pytest.fixture def configuration(configuration, keypair_path): private_key_path, public_key_path = keypair_path conf = { **configuration, "OIDC": { "JWT": { "PUBLIC_KEY": public_key_path, "PRIVATE_KEY": private_key_path, "ISS": "https://auth.mydomain.tld", } }, } return conf @pytest.fixture def client(testclient, other_client, slapd_connection): c = Client( client_id=gen_salt(24), client_name="Some client", contacts="contact@mydomain.tld", client_uri="https://mydomain.tld", redirect_uris=[ "https://mydomain.tld/redirect1", "https://mydomain.tld/redirect2", ], logo_uri="https://mydomain.tld/logo.png", client_id_issued_at=datetime.datetime.now(datetime.timezone.utc), client_secret=gen_salt(48), grant_types=[ "password", "authorization_code", "implicit", "hybrid", "refresh_token", ], response_types=["code", "token", "id_token"], scope=["openid", "email", "profile", "groups", "address", "phone"], tos_uri="https://mydomain.tld/tos", policy_uri="https://mydomain.tld/policy", jwks_uri="https://mydomain.tld/jwk", token_endpoint_auth_method="client_secret_basic", post_logout_redirect_uris=["https://mydomain.tld/disconnected"], ) c.audience = [c, other_client] c.save() yield c c.delete() @pytest.fixture def other_client(testclient, slapd_connection): c = Client( client_id=gen_salt(24), client_name="Some other client", contacts="contact@myotherdomain.tld", client_uri="https://myotherdomain.tld", redirect_uris=[ "https://myotherdomain.tld/redirect1", "https://myotherdomain.tld/redirect2", ], logo_uri="https://myotherdomain.tld/logo.png", client_id_issued_at=datetime.datetime.now(datetime.timezone.utc), client_secret=gen_salt(48), grant_types=[ "password", "authorization_code", "implicit", "hybrid", "refresh_token", ], response_types=["code", "token", "id_token"], scope=["openid", "profile", "groups"], tos_uri="https://myotherdomain.tld/tos", policy_uri="https://myotherdomain.tld/policy", jwks_uri="https://myotherdomain.tld/jwk", token_endpoint_auth_method="client_secret_basic", post_logout_redirect_uris=["https://myotherdomain.tld/disconnected"], ) c.audience = [c] c.save() yield c c.delete() @pytest.fixture def authorization(testclient, user, client, slapd_connection): a = AuthorizationCode( authorization_code_id=gen_salt(48), code="my-code", client=client, subject=user, redirect_uri="https://foo.bar/callback", response_type="code", scope="openid profile", nonce="nonce", issue_date=datetime.datetime(2020, 1, 1, tzinfo=datetime.timezone.utc), lifetime=3600, challenge="challenge", challenge_method="method", revokation="", ) a.save() yield a a.delete() @pytest.fixture def token(testclient, client, user, slapd_connection): t = Token( token_id=gen_salt(48), access_token=gen_salt(48), audience=[client], client=client, subject=user, token_type=None, refresh_token=gen_salt(48), scope="openid profile", issue_date=datetime.datetime.now(datetime.timezone.utc), lifetime=3600, ) t.save() yield t t.delete() @pytest.fixture def id_token(testclient, client, user, slapd_connection): return generate_id_token( {}, generate_user_info(user, client.scope), aud=client.client_id, **get_jwt_config(None) ) @pytest.fixture def consent(testclient, client, user, slapd_connection): t = Consent( consent_id=str(uuid.uuid4()), client=client, subject=user, scope=["openid", "profile"], issue_date=datetime.datetime.now(datetime.timezone.utc), ) t.save() yield t t.delete()