|
Download docs/SAML_SETUP.md from dn-scribe/attstore: direct link, hf CLI and curl.
- Browser
- Download file 9.27 kB
-
https://huggingface.co/spaces/dn-scribe/attstore/resolve/main/docs/SAML_SETUP.md
- Command line
-
hf download hf://spaces/dn-scribe/attstore/docs/SAML_SETUP.md
-
curl -L -o SAML_SETUP.md https://huggingface.co/spaces/dn-scribe/attstore/resolve/main/docs/SAML_SETUP.md
9.27 kB
| # SAML Single Sign-On | |
| This application now acts as a multi-tenant SAML 2.0 Service Provider (SP) using [`python3-saml`](https://github.com/onelogin/python3-saml). Each customer/tenant can upload their Identity Provider (IdP) metadata and control how SAML attributes map to local users. SAML logins reuse the same session/JWT creation flow as password-based logins. | |
| ## Components | |
| - **Tenants (`/api/saml/tenants`)** β logical customers. Tenants can allow/disallow password auth and host one or more SAML configs. | |
| - **SAML configurations (`/api/saml/configs`)** β derived from IdP metadata. Store IdP entity ID, SSO/SLO endpoints, certificates, attribute mappings, and SP overrides (ACS URL, entity ID, etc.). | |
| - **External identities** β map SAML `NameID`/email values to local users and keep a copy of the attributes returned by the IdP. | |
| > **Migrations:** After pulling this change, run `flask db migrate && flask db upgrade` (or the equivalent for your environment) to create the new tables/columns. | |
| ## Required Environment Variables | |
| | Variable | Purpose | | |
| | --- | --- | | |
| | `PUBLIC_BASE_URL` | Public HTTPS base URL that IdPs can reach (e.g., `https://attstore.example.com`). Used to calculate ACS/SLO endpoints inside the generated metadata. | | |
| | `SAML_SP_CERTIFICATE` | Optional PEM certificate if you need to sign Authn/SLO requests. Leave unset for unsigned requests. | | |
| | `SAML_SP_PRIVATE_KEY` | Private key that matches `SAML_SP_CERTIFICATE`. | | |
| The legacy `FILE_STORAGE_BASE_URL` is still used for file downloads; it is **not** used for SAML. | |
| ## Authenticating Admin API Calls | |
| The `/api/saml/*` endpoints require a JWT (same as the rest of the admin API surface). Use an API token from **Settings β API Tokens** to mint a short-lived JWT and export both values for reuse: | |
| ```bash | |
| # Base URL (should match PUBLIC_BASE_URL) | |
| export BASE_URL="https://attstore.example.com" | |
| # 1. Paste the API token generated in the UI | |
| export TOKEN="dXNlcm5hbWU6c2VjcmV0Cg==" | |
| # 2. Exchange it for a JWT (requires jq) | |
| export JWT_TOKEN=$(curl -s -X POST "$BASE_URL/v1/login" \ | |
| -H 'Content-Type: application/json' \ | |
| -d "{\"api_token\":\"$TOKEN\"}" | jq -r '.access_token') | |
| # 3. Use the JWT for all privileged calls | |
| curl -H "Authorization: Bearer $JWT_TOKEN" "$BASE_URL/api/saml/tenants" | |
| ``` | |
| This keeps API tokens long-lived while every admin request runs with the scoped JWT. | |
| ## Provisioning a Tenant & IdP Metadata | |
| 1. **Create a tenant** | |
| ```bash | |
| curl -X POST "$BASE_URL/api/saml/tenants" \ | |
| -H "Authorization: Bearer $JWT_TOKEN" \ | |
| -H "Content-Type: application/json" \ | |
| -d '{"name": "Acme Corp", "slug": "acme", "allow_password_auth": false}' | |
| ``` | |
| 2. **Create a SAML config** | |
| ```bash | |
| # Convert your IdP metadata into JSON-safe form (example path: tmp/GoogleIDPMetadata.xml) | |
| export METADATA=$(jq -Rs . tmp/GoogleIDPMetadata.xml) | |
| curl -X POST "$BASE_URL/api/saml/configs" \ | |
| -H "Authorization: Bearer $JWT_TOKEN" \ | |
| -H "Content-Type: application/json" \ | |
| -d "{ | |
| \"tenant_id\": 1, | |
| \"name\": \"Acme SSO\", | |
| \"slug\": \"acme-sso\", | |
| \"metadata_xml\": $METADATA, | |
| \"attribute_mapping\": { | |
| \"email\": \"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress\", | |
| \"username\": \"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name\" | |
| }, | |
| \"auto_provision_users\": true | |
| }" | |
| ``` | |
| The server parses the metadata, stores the IdP certificate and endpoints, and responds with derived SP URLs: | |
| ```json | |
| { | |
| "id": 4, | |
| "slug": "acme-sso", | |
| "service_urls": { | |
| "acs": "https://attstore.example.com/saml/acme-sso/acs", | |
| "entity_id": "https://attstore.example.com/saml/acme-sso/metadata", | |
| "slo": "https://attstore.example.com/saml/acme-sso/slo" | |
| } | |
| } | |
| ``` | |
| 3. **Hand the SP metadata to the IdP**\ | |
| Each SAML config exposes SP metadata at `/saml/<slug>/metadata`. Provide this URL to the IdP (or download the XML and upload it manually). | |
| ## Google Workspace Example | |
| 1. **Create the custom SAML app** | |
| - Google Admin Console β *Apps β Web and mobile apps β Add custom SAML app*. | |
| - Download the IdP metadata XML provided during the wizard. | |
| 2. **Configure URLs** | |
| - **ACS URL**: `https://<your-domain>/saml/<slug>/acs` | |
| - **Entity ID**: `https://<your-domain>/saml/<slug>/metadata` | |
| - **Name ID**: `Email` (default) or whichever attribute you plan to map. | |
| 3. **Upload metadata to Attestation Store** | |
| - Call `POST /api/saml/configs` (above) using the downloaded metadata. | |
| - Set `attribute_mapping.email` to `email` or `urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress`. | |
| 4. **Assign users**\ | |
| In Google Admin, assign the SAML app to the users/groups who should access Attestation Store. | |
| 5. **Test** | |
| - Initiate login from Attestation Store: `/login` now shows "Continue with <Tenant>" buttons. | |
| - Or IdP-initiated flows (if `allow_idp_initiated` is `true`). | |
| - Watch the server logs for `saml_login_success` events; run through both ACS and SLO endpoints to confirm. | |
| > **Local development tip:** When testing with Google, expose your dev server via `ngrok` or run it in a public environment so Google can reach `https://.../saml/<slug>/acs`. | |
| ## Attribute Mapping & Auto-Provisioning | |
| - `attribute_mapping`: JSON object mapping logical fields (`email`, `username`, `first_name`, `last_name`) to the IdP attribute names. Defaults to `email`, `username`, `firstName`, `lastName`. | |
| - `auto_provision_users`: When `true`, the server creates a local user the first time it sees a new SAML identity. The user is placed in the tenant and assigned a random password (unused). | |
| - When `auto_provision_users` is `false`, the assertion must match an existing user (by `NameID` or mapped email); otherwise the login fails. | |
| All SAML identities are stored in the `external_identities` table with the assertion attributes for auditability. | |
| ## Testing & Troubleshooting | |
| 1. **Health check** β `/healthz` ensures DB access before testing. | |
| 2. **Metadata validation** β hitting `/saml/<slug>/metadata` should return valid XML. Errors will appear in `system_logs` with `saml_metadata_error`. | |
| 3. **ACS testing** β use the IdP test button or tools like [samltool.com](https://www.samltool.com/) to post assertions to `/saml/<slug>/acs`. | |
| 4. **SLO** β ensure `/saml/<slug>/slo` works in both SP-initiated and IdP-initiated directions. | |
| 5. **Logs** β search `system_logs` for `saml_*` events to trace configuration or login issues. | |
| ## Tenant Management | |
| ### API Endpoints | |
| The following tenant management endpoints are available: | |
| | Method | Endpoint | Description | | |
| | --- | --- | --- | | |
| | GET | `/api/saml/tenants` | List all tenants | | |
| | POST | `/api/saml/tenants` | Create a new tenant | | |
| | PATCH | `/api/saml/tenants/<id>` | Update a tenant | | |
| | DELETE | `/api/saml/tenants/<id>` | Delete a tenant | | |
| ### Deleting a Tenant | |
| When you delete a tenant via `DELETE /api/saml/tenants/<tenant_id>`, the following actions occur: | |
| - β Tenant record is deleted | |
| - β All SAML configurations for the tenant are deleted | |
| - β All external identity records are deleted | |
| - β οΈ Users are preserved but unlinked from the tenant (their `tenant_id` is set to NULL) | |
| **Example:** | |
| ```bash | |
| # Delete tenant with ID 5 | |
| curl -X DELETE "$BASE_URL/api/saml/tenants/5" \ | |
| -H "Authorization: Bearer $JWT_TOKEN" | |
| ``` | |
| **Response:** | |
| ```json | |
| { | |
| "message": "Tenant acme-corp deleted successfully", | |
| "users_affected": 5, | |
| "saml_configs_deleted": 2 | |
| } | |
| ``` | |
| ### Shell Scripts | |
| Two convenience scripts are provided in the `scripts/` directory: | |
| #### List Tenants | |
| ```bash | |
| # Make executable first | |
| chmod +x scripts/list_tenants.sh | |
| # Usage | |
| ./scripts/list_tenants.sh [API_URL] [USERNAME] [PASSWORD] | |
| # Examples | |
| ./scripts/list_tenants.sh | |
| ./scripts/list_tenants.sh http://localhost:5555 admin mypassword | |
| ``` | |
| The script displays a formatted table with tenant details and full JSON output. | |
| #### Delete Tenant | |
| ```bash | |
| # Make executable first | |
| chmod +x scripts/delete_tenant.sh | |
| # Usage | |
| ./scripts/delete_tenant.sh <tenant_name_or_slug> [API_URL] [USERNAME] [PASSWORD] | |
| # Examples | |
| ./scripts/delete_tenant.sh acme-corp | |
| ./scripts/delete_tenant.sh "Acme Corporation" http://localhost:5555 admin mypassword | |
| ``` | |
| The script will: | |
| 1. Authenticate with the API | |
| 2. Search for the tenant by name or slug (case-insensitive) | |
| 3. Display tenant information | |
| 4. Ask for confirmation before deletion | |
| 5. Delete the tenant and display the results | |
| **Important:** Deletion is permanent and cannot be undone. Users are NOT deleted, only their tenant association is removed. | |
| ### Testing Tenant Management | |
| Run the automated test script to verify tenant management functionality: | |
| ```bash | |
| python3 scripts/test_tenant_management.py | |
| ``` | |
| This will test creating, listing, and deleting tenants, ensuring all operations work correctly. | |
| ## Security Notes | |
| - Always run the public endpoints over HTTPS. | |
| - Keep `SAML_SP_PRIVATE_KEY` secret; rotate SP certificates on a schedule. | |
| - Disable `allow_idp_initiated` if you require SP-initiated flows only. | |
| - When deactivating accounts, set `User.is_active = False`; SAML logins will honor the flag. | |
| - All tenant management operations require admin privileges and are logged for audit purposes. | |