mirror of
https://github.com/lukaszraczylo/traefikoidc.git
synced 2026-10-19 04:47:48 +00:00
Add templated headers sent to the downstream service. (#40)
This commit is contained in:
@@ -0,0 +1,197 @@
|
||||
package traefikoidc
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
func TestTemplatedHeaderValidation(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
header TemplatedHeader
|
||||
expectedError string
|
||||
}{
|
||||
{
|
||||
name: "Empty Name",
|
||||
header: TemplatedHeader{Name: "", Value: "{{.Claims.email}}"},
|
||||
expectedError: "header name cannot be empty",
|
||||
},
|
||||
{
|
||||
name: "Empty Value",
|
||||
header: TemplatedHeader{Name: "X-Email", Value: ""},
|
||||
expectedError: "header value template cannot be empty",
|
||||
},
|
||||
{
|
||||
name: "Not a Template",
|
||||
header: TemplatedHeader{Name: "X-Email", Value: "static-value"},
|
||||
expectedError: "header value 'static-value' does not appear to be a valid template (missing {{ }})",
|
||||
},
|
||||
{
|
||||
name: "Lowercase claims",
|
||||
header: TemplatedHeader{Name: "X-Email", Value: "{{.claims.email}}"},
|
||||
expectedError: "header template '{{.claims.email}}' appears to use lowercase 'claims' - use '{{.Claims...' instead (case sensitive)",
|
||||
},
|
||||
{
|
||||
name: "Lowercase accessToken",
|
||||
header: TemplatedHeader{Name: "X-Token", Value: "Bearer {{.accessToken}}"},
|
||||
expectedError: "header template 'Bearer {{.accessToken}}' appears to use lowercase 'accessToken' - use '{{.AccessToken...' instead (case sensitive)",
|
||||
},
|
||||
{
|
||||
name: "Lowercase idToken",
|
||||
header: TemplatedHeader{Name: "X-Token", Value: "Bearer {{.idToken}}"},
|
||||
expectedError: "header template 'Bearer {{.idToken}}' appears to use lowercase 'idToken' - use '{{.IdToken...' instead (case sensitive)",
|
||||
},
|
||||
{
|
||||
name: "Lowercase refreshToken",
|
||||
header: TemplatedHeader{Name: "X-Refresh", Value: "Bearer {{.refreshToken}}"},
|
||||
expectedError: "header template 'Bearer {{.refreshToken}}' appears to use lowercase 'refreshToken' - use '{{.RefreshToken...' instead (case sensitive)",
|
||||
},
|
||||
{
|
||||
name: "Valid Template",
|
||||
header: TemplatedHeader{Name: "X-Email", Value: "{{.Claims.email}}"},
|
||||
expectedError: "",
|
||||
},
|
||||
{
|
||||
name: "Valid Bearer Token Template",
|
||||
header: TemplatedHeader{Name: "Authorization", Value: "Bearer {{.AccessToken}}"},
|
||||
expectedError: "",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
config := &Config{
|
||||
ProviderURL: "https://provider.com",
|
||||
CallbackURL: "/callback",
|
||||
ClientID: "client-id",
|
||||
ClientSecret: "client-secret",
|
||||
SessionEncryptionKey: "this-is-a-long-enough-encryption-key",
|
||||
RateLimit: 10, // Adding minimum required rate limit
|
||||
Headers: []TemplatedHeader{tc.header},
|
||||
}
|
||||
|
||||
err := config.Validate()
|
||||
if tc.expectedError == "" {
|
||||
if err != nil {
|
||||
t.Errorf("Expected no error, got: %v", err)
|
||||
}
|
||||
} else {
|
||||
if err == nil {
|
||||
t.Errorf("Expected error: %s, got nil", tc.expectedError)
|
||||
} else if err.Error() != tc.expectedError {
|
||||
t.Errorf("Expected error: %s, got: %s", tc.expectedError, err.Error())
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestTemplateParsingInNew(t *testing.T) {
|
||||
// Test successful parsing of templates during middleware creation
|
||||
tests := []struct {
|
||||
name string
|
||||
headers []TemplatedHeader
|
||||
expectedTemplates int
|
||||
expectError bool
|
||||
}{
|
||||
{
|
||||
name: "Single Valid Template",
|
||||
headers: []TemplatedHeader{
|
||||
{Name: "X-Email", Value: "{{.Claims.email}}"},
|
||||
},
|
||||
expectedTemplates: 1,
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "Multiple Valid Templates",
|
||||
headers: []TemplatedHeader{
|
||||
{Name: "X-Email", Value: "{{.Claims.email}}"},
|
||||
{Name: "X-User-ID", Value: "{{.Claims.sub}}"},
|
||||
{Name: "Authorization", Value: "Bearer {{.AccessToken}}"},
|
||||
},
|
||||
expectedTemplates: 3,
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "Invalid Template",
|
||||
headers: []TemplatedHeader{
|
||||
{Name: "X-Email", Value: "{{.Claims.email"}, // Missing closing braces
|
||||
},
|
||||
expectedTemplates: 0,
|
||||
expectError: true,
|
||||
},
|
||||
{
|
||||
name: "Mix of Valid and Invalid Templates",
|
||||
headers: []TemplatedHeader{
|
||||
{Name: "X-Email", Value: "{{.Claims.email}}"},
|
||||
{Name: "X-Invalid", Value: "{{if .Claims.admin}}Admin{{end"}, // Invalid template
|
||||
},
|
||||
expectedTemplates: 1, // Only the valid template should be parsed
|
||||
expectError: true, // We expect an error for the invalid template, but we'll handle it
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
// For testing template parsing, we'll directly try to parse the templates instead of using New()
|
||||
// This avoids the provider discovery that would fail in tests
|
||||
headerTemplates := make(map[string]*template.Template)
|
||||
|
||||
// Special handling for the mixed valid/invalid templates case
|
||||
if tc.name == "Mix of Valid and Invalid Templates" {
|
||||
// Process templates one at a time so we can still have valid templates
|
||||
for _, header := range tc.headers {
|
||||
tmpl, err := template.New(header.Name).Parse(header.Value)
|
||||
if err != nil {
|
||||
// We expect an error for the invalid template
|
||||
if !tc.expectError {
|
||||
t.Errorf("Unexpected error parsing template %s: %v", header.Name, err)
|
||||
}
|
||||
// Skip this template but continue processing others
|
||||
continue
|
||||
}
|
||||
headerTemplates[header.Name] = tmpl
|
||||
}
|
||||
} else {
|
||||
// Normal handling for other test cases
|
||||
var parseErr error
|
||||
for _, header := range tc.headers {
|
||||
tmpl, err := template.New(header.Name).Parse(header.Value)
|
||||
if err != nil {
|
||||
parseErr = err
|
||||
break
|
||||
}
|
||||
headerTemplates[header.Name] = tmpl
|
||||
}
|
||||
|
||||
if tc.expectError {
|
||||
if parseErr == nil {
|
||||
t.Error("Expected error parsing templates but got nil")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if parseErr != nil {
|
||||
t.Fatalf("Unexpected error: %v", parseErr)
|
||||
}
|
||||
}
|
||||
|
||||
// Check the number of parsed templates
|
||||
if len(headerTemplates) != tc.expectedTemplates {
|
||||
t.Errorf("Expected %d parsed templates, got %d", tc.expectedTemplates, len(headerTemplates))
|
||||
}
|
||||
|
||||
// Check each template was parsed
|
||||
for _, header := range tc.headers {
|
||||
// Skip the known invalid templates
|
||||
if header.Value == "{{.Claims.email" || header.Value == "{{if .Claims.admin}}Admin{{end" {
|
||||
continue
|
||||
}
|
||||
|
||||
if _, ok := headerTemplates[header.Name]; !ok {
|
||||
t.Errorf("Template for header %s was not parsed", header.Name)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user