A Traefik middleware plugin that bridges legacy SSO systems to modern applications combining legacy DES with a secure internal AES-256-GCM cookie architecture and robust SOAP validation.
Code Quality: Cyclomatic complexity < 10 for all functions ✅
- ✅ Hybrid Cryptography - Retains backward-compatible DES-CBC decryption for legacy SSO tokens while securing internal session state with industrial-grade AES-256-GCM.
- ✅ CST Token Handling - Extract and validate Service Tickets from CST tokens
- ✅ Secure SOAP Validation - Validate tickets via SOAP web service using native XML marshaling preventing injections.
- ✅ High Performance - Implements Keep-Alive Connection Pooling and AES pre-computations for minimal overhead.
- ✅ Cookie Management - Auto-generate secure cookies after ticket validation.
- ✅ Triple Validation Strategy - Cookie → CST Token → Login redirect.
- ✅ Header Injection - Inject configurable user identification headers for downstream apps.
Add to your traefik.yml:
experimental:
plugins:
sso-bridge:
moduleName: "github.com/Ariesly/traefik-plugin-sso-bridge"
version: "v1.3.0"Configure the middleware in dynamic.yml:
http:
middlewares:
my-sso-bridge:
plugin:
sso-bridge:
secretKey: "YourKey8" # Must be 8 characters
cookieName: "SSO_AUTH_TICKET"
cstTokenName: "cst" # URL parameter name (default: "cst")
ssoLoginUrl: "http://sso.example.com/Login.aspx"
ticketServiceUrl: "http://sso.example.com/Ticket.asmx"
serviceId: "your_service_id"
cookieDomain: ".example.com" # Optional
cookieSecure: true # Use true for HTTPS
cookieMaxAge: 28800 # Expiration in seconds (8 hours)
soapAction: "http://sso.indigox.net/ValidateServiceTicket" # Optional
soapNamespace: "http://sso.indigox.net/" # Optional
authHeaders:
- "X-Auth-User"
- "X-Auth-ID"http:
routers:
my-app:
rule: "Host(`app.example.com`)"
service: my-service
middlewares:
- my-sso-bridge@file| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
secretKey |
string | ✅ Yes | - | 8-character DES key (Used to derive AES key internally) |
cookieSecret |
string | ❌ No | - | Optional 32-character key for independent internal AES-256 Cookie Encryption |
cookieName |
string | ❌ No | SSO_AUTH_TICKET |
Cookie name |
cstTokenName |
string | ❌ No | cst |
URL parameter name for CST token |
ssoLoginUrl |
string | ✅ Yes | - | SSO login page URL |
ticketServiceUrl |
string | ✅ Yes | - | SOAP validation endpoint |
serviceId |
string | ✅ Yes | - | Service ID in SSO system |
cookieDomain |
string | ❌ No | - | Cookie domain (e.g., .example.com) |
cookieSecure |
bool | ❌ No | false |
Enable secure flag (HTTPS) |
cookieMaxAge |
int | ❌ No | 28800 |
Optional cookie expiration in seconds (default is 8 hours) |
soapAction |
string | ❌ No | http://sso.indigox.net/ValidateServiceTicket |
XML SOAPAction Header |
soapNamespace |
string | ❌ No | http://sso.indigox.net/ |
The namespace payload attribute prefix |
authHeaders |
[]string | ❌ No | ["X-Auth-User", "X-Auth-ID"] |
Request headers dynamically injected downstream |
1. User accesses https://app.example.com/dashboard
↓
2. Traefik intercepts request
↓
3. SSO Bridge Plugin checks:
├─ A. Valid cookie? → Pass to app
├─ B. Valid CST token (e.g., ?cst=xxx)? → Decrypt → Extract ST → Validate → Set cookie → Redirect
└─ C. Neither? → Redirect to SSO login
↓
4. App receives X-Auth-User header
URL: ?cst=<encrypted_token>
↓
Step 1: Decrypt CST token
Result: {ID: "123", UserName: "john", ServiceTicket: "ST-12345"}
↓
Step 2: Extract ServiceTicket
ServiceTicket: "ST-12345"
↓
Step 3: Validate via SOAP
POST /Ticket.asmx
<ValidateServiceTicket>
<ticketToken>ST-12345</ticketToken>
<serviceID>your_service_id</serviceID>
</ValidateServiceTicket>
↓
Step 4: Set cookie and redirect to clean URL
Set-Cookie: SSO_AUTH_TICKET=<encrypted_user_data>
Location: https://app.example.com/dashboard
version: '3.8'
services:
traefik:
image: traefik:v3.0
command:
- "--experimental.plugins.sso-bridge.moduleName=github.com/Ariesly/traefik-plugin-sso-bridge"
- "--experimental.plugins.sso-bridge.version=v1.3.0"
ports:
- "80:80"
volumes:
- ./dynamic.yml:/etc/traefik/dynamic.yml
gitea:
image: gitea/gitea:latest
environment:
- GITEA__service__ENABLE_REVERSE_PROXY_AUTHENTICATION=true
- GITEA__service__REVERSE_PROXY_AUTHENTICATION_USER=X-Auth-User
labels:
- "traefik.enable=true"
- "traefik.http.routers.gitea.rule=Host(`git.localhost`)"
- "traefik.http.routers.gitea.middlewares=my-sso-bridge@file"make fmt: Format code withgofmt.make lint: Rungolangci-lint.make test: Run all unit tests.
go test -v ./...go build ./...Check the cstTokenName configuration matches your URL parameter:
# URL: ?cst=xxx
cstTokenName: "cst" # ✅ Correct
# URL: ?token=xxx
cstTokenName: "token" # ✅ Must matchEnsure proper domain and secure settings:
# HTTPS environment
cookieSecure: true
cookieDomain: ".example.com"
# HTTP development
cookieSecure: false
cookieDomain: ""MIT License
Created to bridge legacy SSO systems with modern microservices architecture.
Repository: https://github.com/Ariesly/traefik-plugin-sso-bridge