Skip to content

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:

http://localhost:5173/login?method=saml

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

  1. Certificate issue:

    # Re-fetch certificate
    python setup_saml.py --keycloak-url http://localhost:8080
    

  2. Clock skew:

  3. Ensure server clocks are synchronized
  4. Check SAML assertion NotBefore/NotOnOrAfter times

  5. Signature verification:

  6. Verify IdP certificate in database matches Keycloak
  7. 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

  1. Use HTTPS everywhere

    SAML_SP_ENTITY_ID=https://yoursite.com/api/v1/auth/saml/metadata
    SAML_ACS_URL=https://yoursite.com/api/v1/auth/saml/acs
    

  2. Enable assertion encryption

  3. Keycloak client: Enable Encrypt Assertions
  4. Upload SP certificate

  5. Enable request signing

  6. Generate SP key/cert pair
  7. Configure in Keycloak
  8. Update backend settings

  9. Use persistent NameID

  10. Already configured: nameid_format: persistent
  11. Ensures stable user identity across systems

  12. Monitor SAML exchanges

  13. Enable debug logging in production carefully
  14. Use SAML tracer tools for troubleshooting
  15. 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:

User → Roles → Access Policies → Permissions
           → User can access X channel
           → User has Y actions

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

# Backend environment
LOGLEVEL=DEBUG
SQLALCHEMY_ECHO=1

Export SAML metadata for analysis

curl http://localhost:8000/api/v1/auth/saml/metadata > sp-metadata.xml

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

  1. ✓ Keycloak running
  2. ✓ Backend configured
  3. ✓ Test users working
  4. → Customize user attributes
  5. → Add more Keycloak users
  6. → Configure production IdP
  7. → Deploy to staging
  8. → Production rollout

References