Files
recipe-maintainer/recipe-info/cryptpad/setup_authentik_integration.py
autonomic-bot f283a371bb recipe-maintainer: public snapshot (secrets + deployment plans removed, single commit)
Sanitized single-commit public mirror of recipe-maintainer.
- Removed test-ssh/.testenv (live creds); added test-ssh/.testenv.example placeholders.
- Removed plans/ and planned-updates/ (deployment-planning docs) so no client/
  deployment domains appear in the public repo.
- All other secret stores were already gitignored.
- docs.coopcloud.tech retained as a submodule (public upstream).
2026-06-16 20:18:24 +00:00

160 lines
6.3 KiB
Python

#!/usr/bin/env python3
"""Setup Authentik OIDC integration for CryptPad SSO.
Creates an OAuth2 provider, application, and test user in Authentik,
then updates the CryptPad env file with SSO settings and inserts
the client secret as a Docker secret.
"""
import os
import sys
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", ".."))
from lib.abra import app_secret_insert
from lib.authentik import AuthentikAdmin
from lib.env import apply_env_overrides, get_abra_env_path, read_env_file
from lib.models import load_default_instance
from lib.secrets import load_secrets
# Configuration
PROVIDER_NAME = "cryptpad"
APP_SLUG = "cryptpad"
CLIENT_ID = "cryptpad"
TEST_USER = "testuser"
TEST_PASS = "testpass123"
TEST_EMAIL = f"{TEST_USER}@test.example.com"
def main():
inst = load_default_instance()
cpad_domain = inst.default_domain("cryptpad")
ak_domain = inst.default_domain("authentik")
ak_url = f"https://{ak_domain}"
# Get Authentik admin token from synced secrets
ak_secrets = load_secrets(ak_domain)
ak_token = ak_secrets["admin_token"]
ak = AuthentikAdmin(ak_url, ak_token)
# Resolve Authentik UUIDs
uuids = ak.resolve_uuids()
# Step 1: Create OAuth2 provider
provider_pk, client_secret = ak.ensure_provider(
PROVIDER_NAME, CLIENT_ID,
redirect_uris=[{
"matching_mode": "strict",
"url": f"https://{cpad_domain}/ssoauth",
}],
uuids=uuids,
)
# Step 2: Create application
ak.ensure_application("CryptPad", APP_SLUG, provider_pk,
f"https://{cpad_domain}")
# Step 3: Ensure test user with APP_PASSWORD
user_pk = ak.ensure_user(TEST_USER, TEST_EMAIL, TEST_PASS)
app_password = ak.ensure_app_password(user_pk)
# Step 4: Update CryptPad env with SSO settings
print("=== Update CryptPad SSO settings in env file ===", flush=True)
env_path = get_abra_env_path(inst.server, cpad_domain)
if not env_path.exists():
print(f" WARNING: CryptPad env file not found at {env_path}", flush=True)
print(f" Create the app first: abra app new cryptpad --server {inst.server} --domain {cpad_domain} --no-input", flush=True)
print(" Skipping env update", flush=True)
else:
oidc_url = f"{ak_url}/application/o/{APP_SLUG}"
overrides = {
"SSO_ENABLED": "true",
"SSO_PROVIDER_NAME": "Authentik",
"SSO_OIDC_URL": oidc_url,
"SSO_CLIENT_ID": CLIENT_ID,
}
# Remove old SSO_CLIENT_SECRET env var if present (now a Docker secret)
env_data = read_env_file(env_path)
if "SSO_CLIENT_SECRET" in env_data:
print(" Removing old SSO_CLIENT_SECRET env var (now a Docker secret)", flush=True)
# Read file lines and filter out SSO_CLIENT_SECRET
with open(env_path) as f:
lines = f.readlines()
with open(env_path, "w") as f:
for line in lines:
if not line.strip().startswith("SSO_CLIENT_SECRET="):
f.write(line)
apply_env_overrides(env_path, overrides)
# Ensure SSO_CLIENT_SECRET_VERSION exists
env_data = read_env_file(env_path)
if "SSO_CLIENT_SECRET_VERSION" not in env_data:
with open(env_path, "a") as f:
f.write("SSO_CLIENT_SECRET_VERSION=v1\n")
# Insert client secret as Docker secret if not already present
try:
existing = load_secrets(cpad_domain).get("sso_client_s")
except Exception:
existing = None
if existing:
print(" Secret sso_client_s already exists in local testsecrets, skipping insert", flush=True)
else:
env_data = read_env_file(env_path)
current_version = env_data.get("SSO_CLIENT_SECRET_VERSION", "v1")
print(f" Inserting sso_client_s {current_version} ...", flush=True)
app_secret_insert(cpad_domain, "sso_client_s", current_version,
client_secret)
print(f" Inserted sso_client_s {current_version}", flush=True)
# Step 5: Write credentials file
script_dir = os.path.dirname(os.path.abspath(__file__))
creds_file = os.path.join(script_dir, f"authentik-test-credentials.{inst.domain_suffix}.toml")
print(f"=== Write credentials to {creds_file} ===", flush=True)
with open(creds_file, "w") as f:
f.write(f'# Authentik OIDC credentials for CryptPad SSO test instance\n')
f.write(f'#\n')
f.write(f'# Authentik instance: {ak_domain}\n')
f.write(f'# Application slug: {APP_SLUG}\n')
f.write(f'# Created by: setup_authentik_integration.py\n')
f.write(f'\n')
f.write(f'# Authentik admin\n')
f.write(f'ak_token = "{ak_token}"\n')
f.write(f'\n')
f.write(f'# OIDC provider\n')
f.write(f'ak_app_slug = "{APP_SLUG}"\n')
f.write(f'ak_client_id = "{CLIENT_ID}"\n')
f.write(f'ak_client_secret = "{client_secret}"\n')
f.write(f'\n')
f.write(f'# Authentik OIDC endpoints\n')
f.write(f'ak_token_endpoint = "https://{ak_domain}/application/o/token/"\n')
f.write(f'ak_userinfo_endpoint = "https://{ak_domain}/application/o/userinfo/"\n')
f.write(f'ak_discovery_endpoint = "https://{ak_domain}/application/o/{APP_SLUG}/.well-known/openid-configuration"\n')
f.write(f'\n')
f.write(f'# Test user (password for browser login, app_password for password grant)\n')
f.write(f'ak_test_user = "{TEST_USER}"\n')
f.write(f'ak_test_pass = "{TEST_PASS}"\n')
f.write(f'ak_test_app_password = "{app_password}"\n')
f.write(f'ak_test_email = "{TEST_EMAIL}"\n')
f.write(f'\n')
f.write(f'# CryptPad instance\n')
f.write(f'cpad_domain = "{cpad_domain}"\n')
print(f" Written to {creds_file}", flush=True)
print("", flush=True)
print("=== Authentik OIDC integration setup for CryptPad complete ===", flush=True)
print("", flush=True)
print("Next steps:", flush=True)
print(f" 1. Redeploy CryptPad: abra app deploy {cpad_domain} --chaos --force --no-input", flush=True)
print(f" 2. Wait ~2min for SSO plugin to install and CryptPad to rebuild", flush=True)
print(f" 3. Run OIDC test: python3 recipe-info/cryptpad/tests/oidc_login.py", flush=True)
if __name__ == "__main__":
main()