Revert "feat(CIE): Implement OIDC RP Service with login, callback, and session management"

This reverts commit 5f81d2dcf7.
This commit is contained in:
gabdevele
2026-06-17 11:01:10 +00:00 Unverified
parent 75c57f9f69
commit 8a94f36015
30 changed files with 4 additions and 3217 deletions
-10
View File
@@ -35,16 +35,6 @@ Authorization: Bearer <token>
sends OTP through Mailpit
- `POST /auth/otp/verify`
consumes OTP, returns bearer token
- `POST /auth/cie/start`
starts local demo CIE OIDC RP login flow, returns provider `authorization_url`
current demo scope: `openid cie_demo`
- `GET /auth/cie/callback`
OIDC redirect URI for provider callback, backend completes token + userinfo flow then redirects frontend
- `GET /auth/cie/session/{state}`
frontend polling endpoint for OIDC login result
returns public `status` in `pending | authenticated | failed`
internal RP phase exposed separately as `phase`
`auth` payload is present only on success
- `GET /me`
current user profile, roles, permissions, points
- `PATCH /me`
-8
View File
@@ -25,9 +25,6 @@ generate public read-only intervention links.
## Runtime Model
- Auth uses bearer tokens from `api_tokens`.
- OTP login uses `otp_challenges` and Mailpit in local dev.
- CIE login uses OIDC RP state tables, public federation endpoints under
`/oidc/rp/*`, callback-side token exchange, encrypted/signed `userinfo`,
and frontend polling on `GET /api/v1/auth/cie/session/{state}`.
- DB access uses raw parameterized SQL through `drogon::orm::DbClient`.
- No Drogon generated ORM models. No `Mapper<T>`.
@@ -65,8 +62,6 @@ Effective permission helpers:
## Main Persistence Objects
- `users`, `roles`, `permissions`, `user_roles`, `role_permissions`
- `api_tokens`, `otp_challenges`
- `oidc_authentications`, `oidc_authentication_tokens`,
`oidc_federation_cache`, `user_external_identities`
- `report_categories`, `areas`, `team_categories`, `teams`
- `reports`, `report_status_history`, `assignments`, `report_photos`
- `messages`, `feedback`, `reward_events`, `notifications`
@@ -102,6 +97,3 @@ Output path:
still exposes citizen phone by design.
- Allowed-area containment for admin areas is vertex-based, simple not strict GIS-hard.
- No frontend doc set here beyond API/OpenAPI docs.
- OIDC federation trust validation/cache is still pragmatic: metadata comes from
trust-anchor `resolve`, but full trust-chain cryptographic validation is not
implemented yet.
-5
View File
@@ -31,11 +31,6 @@ public revocable link generated by operator/admin.
- Registration creates `citizen`.
- Login path:
- OTP email via Mailpit
- CIE OIDC RP demo flow implemented for local CIE provider:
start login, callback token exchange, encrypted/signed `userinfo`,
local user reunification, frontend polling result
- JWT/JWS/JWK operations use `jwt-cpp`.
- JWE decryption remains custom OpenSSL in `common/OidcCrypto.*`.
- Auth token: bearer token from `api_tokens`
- Banned users cannot authenticate.
-209
View File
@@ -1,209 +0,0 @@
# Visione CIE OIDC RP Technical Plan
## Goal
Implement Visione backend as SPID/CIE OIDC Federation Relying Party compatible
with local demo provider contained in `spid-cie-oidc-django/examples/provider`.
Scope target for first real implementation:
- compatibility with demo provider only
- CIE profile only
- Visione backend remains source of truth for application auth
- frontend drives browser redirect flow
## Local Reference Mapping
- Demo OP/federation behavior source:
- `spid-cie-oidc-django/examples/provider`
- `spid-cie-oidc-django/spid_cie_oidc/provider`
- `spid-cie-oidc-django/spid_cie_oidc/entity`
- Demo RP behavior to emulate in Drogon:
- `spid-cie-oidc-django/spid_cie_oidc/relying_party/views/rp_begin.py`
- `spid-cie-oidc-django/spid_cie_oidc/relying_party/views/rp_callback.py`
## Current Status
- `common/OidcJwt.*` now owns JWT/JWS/JWK work through `jwt-cpp`
- `common/OidcCrypto.*` isolates OpenSSL-only JWE compact parsing and decrypt
- `POST /api/v1/auth/cie/start` signs the request object with RP signing key
- callback exchanges code with `private_key_jwt`, verifies token JWS and `at_hash`
- `userinfo` GET supports plain JSON and demo-compatible nested JWE -> JWS
- merged OIDC claims persist through `user_external_identities`
- frontend polling contract is active through `GET /api/v1/auth/cie/session/{state}`
## Foundation Added In This Step
- config placeholders in `config.json`
- DB schema for OIDC auth sessions, tokens, federation cache, external identities
- Drogon controller skeleton in `controllers/OidcController.*`
- service skeleton in `services/OidcRpService.*`
- RP config helper in `common/OidcRpConfig.*`
- RP public endpoints reserved:
- `POST /api/v1/auth/cie/start`
- `GET /api/v1/auth/cie/callback`
- `GET /api/v1/auth/cie/session/{state}`
- `GET /oidc/rp/.well-known/openid-federation`
- `GET /oidc/rp/resolve`
- `GET /oidc/rp/jwks.json`
## Residual Backlog
### Phase 1: Dependencies and crypto plumbing
- Done for demo scope:
- `jwt-cpp` handles JWT parsing, signing and signature verification
- custom OpenSSL code remains only for JWE decryption in `OidcCrypto`
- focused unit tests cover JWT helpers and both supported JWE CBC/HMAC modes
### Phase 2: RP metadata and JWKS
- Done for demo flow.
- Residual gap:
- verify metadata fields against non-demo providers before reuse
### Phase 3: Federation trust resolution
- Current cut:
- fetches trust-anchor `resolve`
- extracts OP metadata/JWKS/endpoints
- Not done:
- full trust-chain signature validation
- federation cache population/reuse
- multi-provider or multi-anchor logic
### Phase 4: Authorization start
- Done.
- Demo scope now sent explicitly as `openid cie_demo`.
### Phase 5: Callback and token exchange
- Done for demo provider.
- Residual gap:
- explicit `exp` / `iat` skew checks still thin
- no refresh-token lifecycle use yet
### Phase 6: UserInfo and local account link
- Done for demo provider, including JWE decrypt + JWS verify + merged claims.
### Phase 7: Frontend completion contract
- Done.
- Session payload now exposes:
- public `status`
- internal `phase`
- `auth` payload only on success
### Phase 8: Tests and docs
- Unit tests added for:
- JWT parse/sign/verify
- `kid` lookup
- `at_hash` helper
- JWE decrypt for `A256CBC-HS512`
- JWE decrypt for `A128CBC-HS256`
- invalid JWE tag / unsupported enc
- merged claim precedence and fiscal code normalization
- Still missing:
- automated integration tests against live demo Django OP
## Data Model Notes
### `oidc_authentications`
Stores single login transaction state and provider snapshot.
### `oidc_authentication_tokens`
Stores authorization code and received tokens.
### `oidc_federation_cache`
Stores fetched federation docs with expiry.
### `user_external_identities`
Decouples local user from external subject identifiers.
## Current Decisions
- Keep OTP auth alive in parallel
- Use local `api_tokens` after OIDC success
- Use `fiscal_code` as strongest user reunification key
- Do not expose Visione token in query string
- Prefer external validated libs over handwritten JWT/JWK code
## Ready Criteria For Real Implementation
- foundation schema merged
- config keys finalized
- dependency choice finalized
- endpoint shapes stable enough for frontend
When these are acceptable, next step is real implementation of Phase 1-4.
## Demo CIE Runbook
### Prerequisites
- MySQL and Mailpit running locally through this repo `docker compose`
- RP keys available in `secrets/oidc/demo-rp-jwks.json`
- backend `config.json` aligned with:
- trust anchor `http://127.0.0.1:8000`
- provider issuer `http://127.0.0.1:8002/oidc/op`
- callback `http://127.0.0.1:5555/api/v1/auth/cie/callback`
### Bootstrap local dependencies
```bash
docker compose up -d
cmake -S . -B build_local -G Ninja -DCMAKE_BUILD_TYPE=Debug
cmake --build build_local
```
### Bootstrap demo federation authority
```bash
cd spid-cie-oidc-django/examples/federation_authority
cp federation_authority/settingslocal.py.example federation_authority/settingslocal.py
python3 -m pip install --upgrade pip
python3 -m pip install -e ../..
python3 -m pip install "design-django-theme==v1.4.8"
./manage.py migrate
./manage.py loaddata dumps/example.json
./manage.py runserver 0.0.0.0:8000
```
### Bootstrap demo provider
```bash
cd spid-cie-oidc-django/examples/provider
cp provider/settingslocal.py.example provider/settingslocal.py
./manage.py migrate
./manage.py loaddata dumps/example.json
./manage.py runserver 0.0.0.0:8002
```
### Start Visione backend
```bash
./build_local/visione-backend
```
### Start login
```bash
curl -sS -X POST http://127.0.0.1:5555/api/v1/auth/cie/start \
-H 'Content-Type: application/json' \
-d '{"provider":"cie_demo","frontend_redirect_uri":"http://localhost:3000/auth/cie/callback"}'
```
Expected result:
- `authorization_url` present
- `state` present
- one row in `oidc_authentications` with phase `AUTHORIZATION_REDIRECT_READY`
### Complete browser flow
1. Open returned `authorization_url`.
2. Authenticate with the demo CIE user configured by the Django fixtures.
3. Accept consent if requested.
4. Provider redirects to backend callback.
5. Backend redirects frontend to `frontend_redirect_uri?state=...`.
### Poll login result
```bash
curl -sS http://127.0.0.1:5555/api/v1/auth/cie/session/<state>
```
Expected success payload:
- `status = "authenticated"`
- `phase = "AUTHENTICATED"`
- `auth.token` present
### Minimal DB verification
```sql
SELECT state,status,authenticated_user_id FROM oidc_authentications ORDER BY id DESC LIMIT 3;
SELECT authentication_id,token_type,scope FROM oidc_authentication_tokens ORDER BY id DESC LIMIT 3;
SELECT user_id,provider,issuer,subject,fiscal_code FROM user_external_identities ORDER BY id DESC LIMIT 3;
SELECT user_id,expires_at FROM api_tokens ORDER BY id DESC LIMIT 3;
```
### Common failures
- `provider_metadata_missing`: federation authority not started or wrong trust anchor URL
- `token_exchange_failed`: provider callback reached but token endpoint unavailable or RP assertion invalid
- `invalid_userinfo_response`: JWE decryption key mismatch or unexpected provider response format
- `at_hash_mismatch`: provider tokens not aligned with received `access_token`