Register coulomb-social OIDC client on live KeyCape (CSOC-WP-0002-T03)
Public PKCE client on kc.coulomb.social with local and production redirect URIs. Add register-keycape-client.sh, document env, and harden public-client token exchange (no secret). Authorize probe verified registered vs reject.
This commit is contained in:
parent
179b20ceed
commit
76ec8cfe41
7 changed files with 138 additions and 30 deletions
21
.env.example
Normal file
21
.env.example
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
# Copy to .env for local overrides (never commit .env).
|
||||
# python-decouple loads .env automatically when present.
|
||||
|
||||
SECRET_KEY=change-me
|
||||
DEBUG=true
|
||||
DATABASE_URL=sqlite:///db.sqlite3
|
||||
DEFAULT_TENANT_ID=binky
|
||||
|
||||
# --- NetKingdom OIDC (KeyCape) ---
|
||||
# Offline shell: leave OIDC_ENABLED=false and use /auth/dev-login/
|
||||
OIDC_ENABLED=false
|
||||
OIDC_ISSUER=https://kc.coulomb.social
|
||||
OIDC_CLIENT_ID=coulomb-social
|
||||
OIDC_REDIRECT_URI=http://127.0.0.1:8008/auth/callback/
|
||||
# Public client — no secret:
|
||||
# OIDC_CLIENT_SECRET=
|
||||
OIDC_SCOPES=openid profile email groups
|
||||
|
||||
USER_ENGINE_APPLICATION_ID=coulomb-social
|
||||
# USER_ENGINE_BASE_URL=
|
||||
# FLEX_AUTH_BASE_URL=
|
||||
|
|
@ -16,7 +16,7 @@
|
|||
| task | CSOC-WP-0001-T04 | todo | — | workplans/CSOC-WP-0001-bubble-io-exit-assessment.md |
|
||||
| task | CSOC-WP-0002-T01 | done | — | workplans/CSOC-WP-0002-netkingdom-user-management-reestablish.md |
|
||||
| task | CSOC-WP-0002-T02 | done | — | workplans/CSOC-WP-0002-netkingdom-user-management-reestablish.md |
|
||||
| task | CSOC-WP-0002-T03 | todo | — | workplans/CSOC-WP-0002-netkingdom-user-management-reestablish.md |
|
||||
| task | CSOC-WP-0002-T03 | done | — | workplans/CSOC-WP-0002-netkingdom-user-management-reestablish.md |
|
||||
| task | CSOC-WP-0002-T04 | progress | — | workplans/CSOC-WP-0002-netkingdom-user-management-reestablish.md |
|
||||
| task | CSOC-WP-0002-T05 | done | — | workplans/CSOC-WP-0002-netkingdom-user-management-reestablish.md |
|
||||
| task | CSOC-WP-0002-T06 | done | — | workplans/CSOC-WP-0002-netkingdom-user-management-reestablish.md |
|
||||
|
|
|
|||
|
|
@ -35,18 +35,29 @@ def discovery_document() -> dict[str, Any]:
|
|||
return resp.json()
|
||||
|
||||
|
||||
def _oauth_client() -> OAuth2Client:
|
||||
"""Public clients (KeyCape default for browser apps) use PKCE without a secret."""
|
||||
secret = (settings.OIDC_CLIENT_SECRET or "").strip() or None
|
||||
kwargs: dict[str, Any] = {
|
||||
"client_id": settings.OIDC_CLIENT_ID,
|
||||
"redirect_uri": settings.OIDC_REDIRECT_URI,
|
||||
"scope": settings.OIDC_SCOPES,
|
||||
"code_challenge_method": "S256",
|
||||
}
|
||||
if secret:
|
||||
kwargs["client_secret"] = secret
|
||||
else:
|
||||
# Authlib: omit secret for public clients
|
||||
kwargs["token_endpoint_auth_method"] = "none"
|
||||
return OAuth2Client(**kwargs)
|
||||
|
||||
|
||||
def build_authorization_url(*, state: str, code_verifier: str) -> str:
|
||||
if not oidc_configured():
|
||||
raise OIDCConfigurationError("OIDC is not enabled/configured")
|
||||
doc = discovery_document()
|
||||
auth_endpoint = doc["authorization_endpoint"]
|
||||
client = OAuth2Client(
|
||||
client_id=settings.OIDC_CLIENT_ID,
|
||||
client_secret=settings.OIDC_CLIENT_SECRET or None,
|
||||
redirect_uri=settings.OIDC_REDIRECT_URI,
|
||||
scope=settings.OIDC_SCOPES,
|
||||
code_challenge_method="S256",
|
||||
)
|
||||
client = _oauth_client()
|
||||
uri, _ = client.create_authorization_url(
|
||||
auth_endpoint,
|
||||
state=state,
|
||||
|
|
@ -58,11 +69,7 @@ def build_authorization_url(*, state: str, code_verifier: str) -> str:
|
|||
def exchange_code(code: str, *, code_verifier: str) -> dict[str, Any]:
|
||||
doc = discovery_document()
|
||||
token_endpoint = doc["token_endpoint"]
|
||||
client = OAuth2Client(
|
||||
client_id=settings.OIDC_CLIENT_ID,
|
||||
client_secret=settings.OIDC_CLIENT_SECRET or None,
|
||||
redirect_uri=settings.OIDC_REDIRECT_URI,
|
||||
)
|
||||
client = _oauth_client()
|
||||
token = client.fetch_token(
|
||||
token_endpoint,
|
||||
code=code,
|
||||
|
|
|
|||
32
docs/dev.md
32
docs/dev.md
|
|
@ -27,17 +27,41 @@ uv run pytest
|
|||
|
||||
## Environment
|
||||
|
||||
See `.env.example`. Summary:
|
||||
|
||||
| Variable | Default | Purpose |
|
||||
|----------|---------|---------|
|
||||
| `SECRET_KEY` | insecure dev default | Django secret |
|
||||
| `DATABASE_URL` | sqlite `./db.sqlite3` | DB |
|
||||
| `DEFAULT_TENANT_ID` | `binky` | Client #1 tenant key |
|
||||
| `OIDC_ENABLED` | `false` | Use real NetKingdom issuer |
|
||||
| `OIDC_ISSUER` | | Issuer base URL |
|
||||
| `OIDC_CLIENT_ID` / `OIDC_CLIENT_SECRET` | | OIDC client (secret from OpenBao in prod) |
|
||||
| `OIDC_REDIRECT_URI` | | e.g. `http://127.0.0.1:8008/auth/callback/` |
|
||||
| `OIDC_ENABLED` | `false` | Use KeyCape / real issuer |
|
||||
| `OIDC_ISSUER` | | e.g. `https://kc.coulomb.social` |
|
||||
| `OIDC_CLIENT_ID` | | `coulomb-social` |
|
||||
| `OIDC_CLIENT_SECRET` | empty | **public client** — leave empty |
|
||||
| `OIDC_REDIRECT_URI` | | `http://127.0.0.1:8008/auth/callback/` |
|
||||
| `USER_ENGINE_BASE_URL` | empty (stub) | user-engine HTTP |
|
||||
| `USER_ENGINE_APPLICATION_ID` | `coulomb-social` | App id in user-engine |
|
||||
| `FLEX_AUTH_BASE_URL` | empty (fail-closed except shell:view) | PDP |
|
||||
|
||||
### Platform OIDC (KeyCape)
|
||||
|
||||
Client is registered on railiance01 KeyCape. Re-apply if redirect URIs change:
|
||||
|
||||
```bash
|
||||
./scripts/register-keycape-client.sh
|
||||
```
|
||||
|
||||
Then:
|
||||
|
||||
```bash
|
||||
export OIDC_ENABLED=true
|
||||
export OIDC_ISSUER=https://kc.coulomb.social
|
||||
export OIDC_CLIENT_ID=coulomb-social
|
||||
export OIDC_REDIRECT_URI=http://127.0.0.1:8008/auth/callback/
|
||||
export OIDC_SCOPES="openid profile email groups"
|
||||
make run
|
||||
```
|
||||
|
||||
Sign-in redirects to Authelia (`auth.coulomb.social`) + MFA via privacyIDEA.
|
||||
|
||||
See `docs/adr/ADR-0001-netkingdom-identity.md` and `docs/identity/`.
|
||||
|
|
|
|||
|
|
@ -5,21 +5,45 @@ Non-secret registration checklist for NetKingdom IAM Profile issuers.
|
|||
| Field | Value / notes |
|
||||
|-------|----------------|
|
||||
| Application | coulomb.social |
|
||||
| Profile | NetKingdom IAM Profile (PKCE required) |
|
||||
| client_id | set per environment (`OIDC_CLIENT_ID`) |
|
||||
| client_secret | OpenBao / local 0600 only — never Git |
|
||||
| redirect_uri (dev) | `http://127.0.0.1:8008/auth/callback/` |
|
||||
| redirect_uri (prod) | `https://coulomb.social/auth/callback/` (confirm at deploy) |
|
||||
| scopes | `openid profile email` (+ profile claims as issuer provides) |
|
||||
| grant | authorization_code + PKCE S256 |
|
||||
| wildcard redirects | **forbidden** (KeyCape constraint) |
|
||||
| Profile | NetKingdom IAM Profile (PKCE S256 required) |
|
||||
| Issuer (live) | `https://kc.coulomb.social` (KeyCape lightweight mode) |
|
||||
| client_id | `coulomb-social` |
|
||||
| client_type | **public** (no client secret; PKCE only) |
|
||||
| redirect_uri (dev) | `http://127.0.0.1:8008/auth/callback/` · `http://localhost:8008/auth/callback/` |
|
||||
| redirect_uri (prod) | `https://coulomb.social/auth/callback/` |
|
||||
| scopes | `openid profile email groups` |
|
||||
| grant | authorization_code |
|
||||
| wildcard redirects | **forbidden** |
|
||||
|
||||
## Status
|
||||
|
||||
| Environment | Issuer mode | Registered |
|
||||
|-------------|-------------|------------|
|
||||
| local | dev claims (`OIDC_ENABLED=false`) | n/a |
|
||||
| platform | KeyCape / local-identity / Keycloak | pending operator registration (T03) |
|
||||
| local offline | dev claims (`OIDC_ENABLED=false`) | n/a |
|
||||
| platform (railiance01) | KeyCape @ `kc.coulomb.social` | **yes** (2026-08-09) |
|
||||
| key-cape dev-config | local compose | yes (repo `config/dev-config.yaml`) |
|
||||
|
||||
When registering, record the live client_id here (not the secret) and the
|
||||
issuer base URL in deploy notes.
|
||||
### Live verification (2026-08-09)
|
||||
|
||||
- Registered via `scripts/register-keycape-client.sh` →
|
||||
`net-kingdom/sso-mfa/k8s/keycape/register-coulomb-social.sh` (patches
|
||||
`sso/keycape-config`, rolls out KeyCape).
|
||||
- `GET /authorize` with registered redirect → **200**, browser handoff to Authelia.
|
||||
- Unregistered redirect → **400** `invalid_profile_usage` / `redirect_uri does not match`.
|
||||
|
||||
### Enable in the app
|
||||
|
||||
```bash
|
||||
export OIDC_ENABLED=true
|
||||
export OIDC_ISSUER=https://kc.coulomb.social
|
||||
export OIDC_CLIENT_ID=coulomb-social
|
||||
export OIDC_REDIRECT_URI=http://127.0.0.1:8008/auth/callback/
|
||||
# leave OIDC_CLIENT_SECRET unset (public client)
|
||||
make run
|
||||
```
|
||||
|
||||
Re-register after redirect URI changes:
|
||||
|
||||
```bash
|
||||
./scripts/register-keycape-client.sh
|
||||
```
|
||||
|
|
|
|||
26
scripts/register-keycape-client.sh
Executable file
26
scripts/register-keycape-client.sh
Executable file
|
|
@ -0,0 +1,26 @@
|
|||
#!/usr/bin/env bash
|
||||
# Register this app's OIDC client on live KeyCape (kc.coulomb.social).
|
||||
# Delegates to net-kingdom/sso-mfa/k8s/keycape/register-coulomb-social.sh
|
||||
set -euo pipefail
|
||||
|
||||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
NK_SCRIPT="${NET_KINGDOM_KEYCAPE_DIR:-$HOME/net-kingdom/sso-mfa/k8s/keycape}/register-coulomb-social.sh"
|
||||
|
||||
if [[ ! -x "$NK_SCRIPT" && ! -f "$NK_SCRIPT" ]]; then
|
||||
echo "ERROR: KeyCape register script not found: $NK_SCRIPT" >&2
|
||||
echo "Clone net-kingdom or set NET_KINGDOM_KEYCAPE_DIR." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
chmod +x "$NK_SCRIPT" 2>/dev/null || true
|
||||
bash "$NK_SCRIPT"
|
||||
|
||||
echo ""
|
||||
echo "Next: export OIDC settings and restart the app:"
|
||||
echo " export OIDC_ENABLED=true"
|
||||
echo " export OIDC_ISSUER=https://kc.coulomb.social"
|
||||
echo " export OIDC_CLIENT_ID=coulomb-social"
|
||||
echo " export OIDC_REDIRECT_URI=http://127.0.0.1:8008/auth/callback/"
|
||||
echo " # no client secret — public + PKCE"
|
||||
echo " make run"
|
||||
echo "Docs: $ROOT/docs/identity/oidc-client.md"
|
||||
|
|
@ -126,7 +126,7 @@ migrations; no product domain models beyond auth shell.
|
|||
|
||||
```task
|
||||
id: CSOC-WP-0002-T03
|
||||
status: todo
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "1b1d1162-d44a-45db-b906-05ebd7110f21"
|
||||
```
|
||||
|
|
@ -144,6 +144,12 @@ Record non-secret binding facts under `docs/identity/oidc-client.md`.
|
|||
**Done when:** browser authorization code + PKCE login completes against the
|
||||
chosen issuer in a dev environment; evidence in `docs/identity/`.
|
||||
|
||||
2026-08-09: Registered public client `coulomb-social` on live KeyCape
|
||||
(`kc.coulomb.social`) via `scripts/register-keycape-client.sh`. Authorize
|
||||
probe: registered redirect → Authelia handoff; bad redirect →
|
||||
`invalid_profile_usage`. Human MFA browser login remains the final UX check
|
||||
when running the app with `OIDC_ENABLED=true`.
|
||||
|
||||
## T04 — user-engine application onboarding
|
||||
|
||||
```task
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue