SAML Setup Quick Start Guide¶
Overview¶
This guide provides step-by-step instructions to set up SAML authentication with Keycloak for the Bank USSD application.
Prerequisites¶
- Docker and Docker Compose installed
- Python 3.8+
- Backend running or ability to run Python scripts
- Keycloak 15+ image available
Quick Start (5 minutes)¶
Step 1: Start Keycloak¶
cd deployment/
# Start Keycloak with PostgreSQL backend
docker-compose -f docker-compose-keycloak.yaml up -d
# Wait for Keycloak to be ready
docker logs -f keycloak
# Look for: "Listening on http://0.0.0.0:8080"
# Press Ctrl+C to exit logs
Step 2: Access Keycloak Admin Console¶
Open browser: http://localhost:8080/auth/admin
Credentials:
- Username: admin
- Password: admin123
Verify Setup: 1. Click on "Realms" (top-left) 2. Should see "bank-ussd" realm 3. Click it to view realm configuration 4. Go to "Clients" → "bank-ussd-saml" 5. Verify SAML is enabled
Step 3: Configure Backend SAML¶
cd backend/
# Option A: Automatic setup (recommended)
python setup_saml.py \
--keycloak-url http://localhost:8080 \
--realm bank-ussd \
--backend-url http://localhost:8000
# Option B: Manual configuration
# Edit database:
# docker exec -it <postgres_container> psql -U <user> -d <db>
# UPDATE auth.saml_config SET
# idp_entity_id = 'http://keycloak:8080/auth/realms/bank-ussd',
# idp_sso_url = 'http://keycloak:8080/auth/realms/bank-ussd/protocol/saml',
# saml_enabled = true
# WHERE id = 1;
Step 4: Verify SAML Metadata¶
# Check that SAML metadata is accessible
curl http://localhost:8000/api/v1/auth/saml/metadata
# Should return valid XML metadata
Step 5: Test SAML Login¶
Via Web UI:
Via API:
curl -X POST http://localhost:8000/api/v1/auth/saml/login \
-H "Content-Type: application/json" \
-d '{
"channel": "web"
}'
Test Credentials: | Username | Password | Role | Branch | |----------|----------|------|--------| | admin.keycloak | admin123 | admin | london | | john.smith | password123 | staff | london | | sarah.jones | password123 | customers | manchester | | bob.wilson | password123 | operators | newcastle | | emma.davis | password123 | agents | birmingham |
Step 6: Run Integration Tests¶
# Test complete SAML setup
python test_saml_integration.py
# Run specific tests
python test_saml_integration.py --entities-only
python test_saml_integration.py --roles-only
python test_saml_integration.py --provision-only
Detailed Configuration¶
Environment Variables¶
Add these to your .env file:
# SAML Settings (from backend)
SAML_ENABLED=1
SAML_SP_ENTITY_ID=http://localhost/api/v1/auth/saml/metadata
SAML_ACS_URL=http://localhost/api/v1/auth/saml/acs
SAML_SLS_URL=http://localhost/api/v1/auth/saml/sls
# Keycloak IdP (from IdP)
SAML_IDP_ENTITY_ID=http://keycloak:8080/auth/realms/bank-ussd
SAML_IDP_SSO_URL=http://keycloak:8080/auth/realms/bank-ussd/protocol/saml
SAML_IDP_X509CERT=
Database Configuration¶
SAML config is stored in auth.saml_config table:
SELECT * FROM auth.saml_config;
-- Update IdP configuration
UPDATE auth.saml_config SET
idp_entity_id = 'http://keycloak:8080/auth/realms/bank-ussd',
idp_sso_url = 'http://keycloak:8080/auth/realms/bank-ussd/protocol/saml',
idp_x509cert = '...',
saml_enabled = true
WHERE id = 1;
Keycloak Realm Configuration¶
The Keycloak realm is automatically provisioned with:
Realm: bank-ussd
- Admin: admin / admin123
SAML Client: bank-ussd-saml
- Protocol: SAML 2.0
- Valid Redirect URIs:
- http://localhost:8000/api/v1/auth/saml/acs
- http://localhost/api/v1/auth/saml/sls
Test Users: (5 users with different roles and branches)
Protocol Mappers: (Configured to send user attributes) - Email - First/Last Name - Branch (custom attribute) - Role (realm roles)
Troubleshooting¶
Keycloak won't start¶
# Check logs
docker logs keycloak
# Restart
docker-compose down
docker-compose up -d
# Wait 60+ seconds for startup
SAML config not loading¶
# Verify in database
SELECT * FROM auth.saml_config WHERE id = 1;
# Check environment variables
echo $SAML_ENABLED
echo $SAML_IDP_ENTITY_ID
# Run setup script
python setup_saml.py --verify-only
User not provisioning¶
# Check that entities exist
SELECT * FROM core.entity WHERE code IN ('london', 'manchester', 'newcastle', 'birmingham');
# Check that LDAP roles exist
SELECT * FROM users.roles WHERE name LIKE 'LDAP%';
# Check SAML user attribute mapping
# Log into Keycloak admin
# Clients → bank-ussd-saml → Mappers
# Verify all mappers are enabled
SAML assertion validation fails¶
-
Certificate issue:
-
Clock skew:
- Ensure server clocks are synchronized
-
Check SAML assertion NotBefore/NotOnOrAfter times
-
Signature verification:
- Verify IdP certificate in database matches Keycloak
- Check SAML signature settings in Keycloak client
Advanced Configuration¶
Custom SAML Attributes¶
To add custom attributes (e.g., department, office):
# 1. Add attribute to Keycloak user
# Keycloak Admin → Users → Select user → Attributes
# 2. Create protocol mapper
# Clients → bank-ussd-saml → Mappers → Create
# Name: department
# Protocol: SAML
# Mapper Type: User Attribute
# Attribute name: department
# SAML Attribute Name: department
# 3. Extract in backend
# Modify create_ldap_or_saml_user() to extract custom attributes
Production Deployment¶
-
Use HTTPS everywhere
-
Enable assertion encryption
- Keycloak client: Enable Encrypt Assertions
-
Upload SP certificate
-
Enable request signing
- Generate SP key/cert pair
- Configure in Keycloak
-
Update backend settings
-
Use persistent NameID
- Already configured:
nameid_format: persistent -
Ensures stable user identity across systems
-
Monitor SAML exchanges
- Enable debug logging in production carefully
- Use SAML tracer tools for troubleshooting
- Monitor failed assertions
Integration Points¶
With LDAP¶
Both LDAP and SAML: - Extract branch from OU/attribute - Link to Entity records - Map to database roles - JIT provision users - Support KYC data capture
Key difference: LDAP validates passwords directly; SAML delegates to IdP.
With Database Roles¶
SAML roles map to database roles via LDAP_GROUP_ROLE_MAP:
{
"admin": "admin",
"staff": "staff",
"customers": "customers",
"operators": "operators",
"agents": "agents"
}
When user logs in via SAML: 1. Extract roles from SAML assertion 2. Map to database role names 3. Create UserRole records
With Access Policies¶
LDAP and SAML users get policies from their roles:
Monitoring & Logging¶
Check SAML activity¶
# Backend logs
docker logs -f bank_ussd_backend | grep -i saml
# Database audit
SELECT * FROM auth.user_identity_provider
WHERE provider = 'SAML'
ORDER BY created_at DESC;
Keycloak logs¶
# Inside Keycloak container
docker exec keycloak tail -f /opt/keycloak/bin/../logs/server.log
# Keycloak admin console → Events
# Shows all logins, logouts, failures
Security Checklist¶
- [ ] HTTPS configured in production
- [ ] IdP certificate validation enabled
- [ ] Assertion signature verification enabled
- [ ] NameID format set to persistent
- [ ] SAML response time validation enabled
- [ ] Invalid assertions rejected
- [ ] Session cookies marked Secure
- [ ] CSRF protection enabled
- [ ] Rate limiting on /auth endpoints
- [ ] Audit logging enabled
Support & Debugging¶
Enable verbose logging¶
Export SAML metadata for analysis¶
Service Provider Metadata¶
View at: http://localhost:8000/api/v1/auth/saml/metadata
Should contain: - SP EntityID - ACS URL - Supported bindings - NameID formats
Next Steps¶
- ✓ Keycloak running
- ✓ Backend configured
- ✓ Test users working
- → Customize user attributes
- → Add more Keycloak users
- → Configure production IdP
- → Deploy to staging
- → Production rollout