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).
160 lines
6.3 KiB
Python
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()
|