#!/usr/bin/env python3 """Authentik OIDC integration test.""" import argparse import os import sys sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..', '..')) from utils.tests.helpers import ( http_get, http_post, load_toml_credentials, resolve_domain, _load_settings, ) def main(): if os.environ.get('SKIP_INTEGRATION') == '1': print("SKIP: OIDC integration test (SKIP_INTEGRATION=1)") return parser = argparse.ArgumentParser() parser.add_argument('--domain', default=os.environ.get('TEST_DOMAIN')) args = parser.parse_args() # Docs (ld2) domain — computed from settings settings = _load_settings() instance = settings["default_instance"] suffix = settings["instances"][instance]["domain_suffix"] docs_domain = f"ld2.{suffix}" docs_url = f"https://{docs_domain}" ak_domain = args.domain or resolve_domain('authentik') ak_url = f"https://{ak_domain}" recipe_dir = os.path.join(os.path.dirname(__file__), '..') creds = load_toml_credentials(recipe_dir, 'authentik') if creds is None: print("FAIL: Credentials file not found: authentik-test-credentials..toml") print("Run setup_docs_integration.py first.") sys.exit(1) print("=== Authentik OIDC Integration Test ===") print() # Step 1: Check lasuite-docs (ld2) is deployed print("Step 1: Checking lasuite-docs (ld2) is deployed ...") status, _ = http_get(docs_url) if status == 0: print(f" FAIL: lasuite-docs is not reachable at {docs_url}") sys.exit(1) elif status >= 500: print(f" FAIL: lasuite-docs returned HTTP {status}") sys.exit(1) print(f" OK: lasuite-docs (ld2) is reachable (HTTP {status})") # Step 2: Verify Authentik OIDC discovery print("Step 2: Checking Authentik OIDC discovery ...") discovery_url = creds["ak_discovery_endpoint"] status, _ = http_get(discovery_url) if status != 200: print(f" FAIL: OIDC discovery returned HTTP {status}") print(f" URL: {discovery_url}") sys.exit(1) print(f" PASS: OIDC discovery endpoint OK (app '{creds['ak_app_slug']}')") # Step 3: Obtain token from Authentik print("Step 3: Obtaining token from Authentik for test user ...") print(" Using APP_PASSWORD for password grant (authentik requirement)") status, data = http_post( creds["ak_token_endpoint"], data={ "grant_type": "password", "client_id": creds["ak_client_id"], "client_secret": creds["ak_client_secret"], "username": creds["ak_test_user"], "password": creds["ak_test_app_password"], "scope": "openid email profile", }, content_type="application/x-www-form-urlencoded", ) access_token = (data or {}).get("access_token", "") if not access_token: error = (data or {}).get("error_description", (data or {}).get("error", "unknown")) print(f" FAIL: Token request failed: {error}") sys.exit(1) print(f" PASS: Got access token ({len(access_token)} chars)") # Step 4: Authenticate against Docs API print("Step 4: Calling Docs API with Authentik token ...") status, body = http_get( f"{docs_url}/api/v1.0/users/me/", headers={"Authorization": f"Bearer {access_token}"}, timeout=30, ) if status != 200: print(f" FAIL: Docs API returned HTTP {status} (expected 200)") sys.exit(1) user_email = (body or {}).get("email", "") expected_email = creds["ak_test_email"] if user_email == expected_email: print(f" PASS: Docs returned authenticated user '{user_email}'") else: print(f" FAIL: Expected email '{expected_email}', got '{user_email}'") sys.exit(1) print() print("PASS: Authentik OIDC integration test passed") print(" Authentik issued a valid token, Docs (ld2) accepted it and returned the correct user.") if __name__ == '__main__': main()