mirror of
https://github.com/lukaszraczylo/traefikoidc.git
synced 2026-11-03 07:44:13 +00:00
A templated header skipped its Set when the render failed, came out empty or failed sanitising. The client's own value of that header then reached the backend. A client could forge a header such as X-Tenant by using a token that lacks the claim. The middleware now removes the inbound value first. Identity headers and Authorization are left alone.
55 lines
2.0 KiB
Go
55 lines
2.0 KiB
Go
package traefikoidc
|
|
|
|
import (
|
|
"net/http/httptest"
|
|
"testing"
|
|
"text/template"
|
|
)
|
|
|
|
func ownedHeaderOIDC(t *testing.T, names ...string) *TraefikOidc {
|
|
t.Helper()
|
|
m := map[string]*template.Template{}
|
|
for _, n := range names {
|
|
m[n] = template.Must(template.New(n).Option("missingkey=zero").Parse("{{.Claims.tenant}}"))
|
|
}
|
|
return &TraefikOidc{logger: NewLogger("error"), headerTemplates: m}
|
|
}
|
|
|
|
// A templated header the middleware owns must never carry a client value:
|
|
// an optional claim that renders empty must leave the header absent.
|
|
func TestTemplatedHeaderDropsClientSpoof(t *testing.T) {
|
|
o := ownedHeaderOIDC(t, "X-Tenant")
|
|
req := httptest.NewRequest("GET", "/", nil)
|
|
req.Header.Set("X-Tenant", "admin-corp")
|
|
o.applyHeaderTemplates(req, &principal{Claims: map[string]interface{}{"sub": "u"}})
|
|
if got := req.Header.Get("X-Tenant"); got != "" {
|
|
t.Fatalf("client-supplied X-Tenant reached the backend: %q", got)
|
|
}
|
|
}
|
|
|
|
func TestTemplatedHeaderRenderedValueWins(t *testing.T) {
|
|
o := ownedHeaderOIDC(t, "X-Tenant")
|
|
req := httptest.NewRequest("GET", "/", nil)
|
|
req.Header.Set("X-Tenant", "evil")
|
|
o.applyHeaderTemplates(req, &principal{Claims: map[string]interface{}{"tenant": "acme"}})
|
|
if got := req.Header.Get("X-Tenant"); got != "acme" {
|
|
t.Fatalf("X-Tenant = %q, want acme", got)
|
|
}
|
|
}
|
|
|
|
// Identity headers are injected before templates run; an empty render must
|
|
// not clobber them, and Authorization stays as received.
|
|
func TestTemplatedHeaderKeepsIdentityAndAuthorization(t *testing.T) {
|
|
o := ownedHeaderOIDC(t, "X-Forwarded-User", "Authorization")
|
|
req := httptest.NewRequest("GET", "/", nil)
|
|
req.Header.Set("X-Forwarded-User", "alice")
|
|
req.Header.Set("Authorization", "Bearer abc")
|
|
o.applyHeaderTemplates(req, &principal{Claims: map[string]interface{}{"sub": "u"}})
|
|
if got := req.Header.Get("X-Forwarded-User"); got != "alice" {
|
|
t.Fatalf("identity header clobbered: %q", got)
|
|
}
|
|
if got := req.Header.Get("Authorization"); got != "Bearer abc" {
|
|
t.Fatalf("Authorization changed: %q", got)
|
|
}
|
|
}
|