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
SAML Single Sign-On
This application now acts as a multi-tenant SAML 2.0 Service Provider (SP) using 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:
# 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
Create a tenant
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}'Create a SAML config
# 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:
{ "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" } }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
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.
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.
- ACS URL:
Upload metadata to Attestation Store
- Call
POST /api/saml/configs(above) using the downloaded metadata. - Set
attribute_mapping.emailtoemailorurn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress.
- Call
Assign users
In Google Admin, assign the SAML app to the users/groups who should access Attestation Store.Test
- Initiate login from Attestation Store:
/loginnow shows "Continue with " buttons. - Or IdP-initiated flows (if
allow_idp_initiatedistrue). - Watch the server logs for
saml_login_successevents; run through both ACS and SLO endpoints to confirm.
- Initiate login from Attestation Store:
Local development tip: When testing with Google, expose your dev server via
ngrokor run it in a public environment so Google can reachhttps://.../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 toemail,username,firstName,lastName.auto_provision_users: Whentrue, 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_usersisfalse, the assertion must match an existing user (byNameIDor mapped email); otherwise the login fails.
All SAML identities are stored in the external_identities table with the assertion attributes for auditability.
Testing & Troubleshooting
- Health check β
/healthzensures DB access before testing. - Metadata validation β hitting
/saml/<slug>/metadatashould return valid XML. Errors will appear insystem_logswithsaml_metadata_error. - ACS testing β use the IdP test button or tools like samltool.com to post assertions to
/saml/<slug>/acs. - SLO β ensure
/saml/<slug>/sloworks in both SP-initiated and IdP-initiated directions. - Logs β search
system_logsforsaml_*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_idis set to NULL)
Example:
# Delete tenant with ID 5
curl -X DELETE "$BASE_URL/api/saml/tenants/5" \
-H "Authorization: Bearer $JWT_TOKEN"
Response:
{
"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
# 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
# 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:
- Authenticate with the API
- Search for the tenant by name or slug (case-insensitive)
- Display tenant information
- Ask for confirmation before deletion
- 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:
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_KEYsecret; rotate SP certificates on a schedule. - Disable
allow_idp_initiatedif 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.