Skip to content

Commit e86686a

Browse files
authored
fix(http): well-known mitm propagates original headers (#406)
Signed-off-by: Marc Nuri <[email protected]>
1 parent 54f7e7f commit e86686a

File tree

2 files changed

+122
-1
lines changed

2 files changed

+122
-1
lines changed

pkg/http/http_test.go

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,122 @@ func TestWellKnownReverseProxy(t *testing.T) {
390390
})
391391
}
392392

393+
func TestWellKnownHeaderPropagation(t *testing.T) {
394+
cases := []string{
395+
".well-known/oauth-authorization-server",
396+
".well-known/oauth-protected-resource",
397+
".well-known/openid-configuration",
398+
}
399+
var receivedRequestHeaders http.Header
400+
testServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
401+
if !strings.HasPrefix(r.URL.EscapedPath(), "/.well-known/") {
402+
http.NotFound(w, r)
403+
return
404+
}
405+
// Capture headers received from the proxy
406+
receivedRequestHeaders = r.Header.Clone()
407+
// Set response headers that should be propagated back
408+
w.Header().Set("Content-Type", "application/json")
409+
w.Header().Set("Access-Control-Allow-Origin", "https://example.com")
410+
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, OPTIONS")
411+
w.Header().Set("Cache-Control", "no-cache")
412+
w.Header().Set("X-Custom-Backend-Header", "backend-value")
413+
_, _ = w.Write([]byte(`{"issuer": "https://example.com"}`))
414+
}))
415+
t.Cleanup(testServer.Close)
416+
staticConfig := &config.StaticConfig{
417+
AuthorizationURL: testServer.URL,
418+
RequireOAuth: true,
419+
ValidateToken: true,
420+
ClusterProviderStrategy: config.ClusterProviderKubeConfig,
421+
}
422+
testCaseWithContext(t, &httpContext{StaticConfig: staticConfig}, func(ctx *httpContext) {
423+
for _, path := range cases {
424+
receivedRequestHeaders = nil
425+
req, err := http.NewRequest("GET", fmt.Sprintf("http://%s/%s", ctx.HttpAddress, path), nil)
426+
if err != nil {
427+
t.Fatalf("Failed to create request: %v", err)
428+
}
429+
// Add various headers to test propagation
430+
req.Header.Set("Origin", "https://example.com")
431+
req.Header.Set("User-Agent", "Test-Agent/1.0")
432+
req.Header.Set("Accept", "application/json")
433+
req.Header.Set("Accept-Language", "en-US")
434+
req.Header.Set("X-Custom-Header", "custom-value")
435+
req.Header.Set("Referer", "https://example.com/page")
436+
437+
resp, err := http.DefaultClient.Do(req)
438+
if err != nil {
439+
t.Fatalf("Failed to get %s endpoint: %v", path, err)
440+
}
441+
t.Cleanup(func() { _ = resp.Body.Close() })
442+
443+
t.Run("Well-known proxy propagates Origin header to backend for "+path, func(t *testing.T) {
444+
if receivedRequestHeaders == nil {
445+
t.Fatal("Backend did not receive any headers")
446+
}
447+
if receivedRequestHeaders.Get("Origin") != "https://example.com" {
448+
t.Errorf("Expected Origin header 'https://example.com', got '%s'", receivedRequestHeaders.Get("Origin"))
449+
}
450+
})
451+
452+
t.Run("Well-known proxy propagates User-Agent header to backend for "+path, func(t *testing.T) {
453+
if receivedRequestHeaders.Get("User-Agent") != "Test-Agent/1.0" {
454+
t.Errorf("Expected User-Agent header 'Test-Agent/1.0', got '%s'", receivedRequestHeaders.Get("User-Agent"))
455+
}
456+
})
457+
458+
t.Run("Well-known proxy propagates Accept header to backend for "+path, func(t *testing.T) {
459+
if receivedRequestHeaders.Get("Accept") != "application/json" {
460+
t.Errorf("Expected Accept header 'application/json', got '%s'", receivedRequestHeaders.Get("Accept"))
461+
}
462+
})
463+
464+
t.Run("Well-known proxy propagates Accept-Language header to backend for "+path, func(t *testing.T) {
465+
if receivedRequestHeaders.Get("Accept-Language") != "en-US" {
466+
t.Errorf("Expected Accept-Language header 'en-US', got '%s'", receivedRequestHeaders.Get("Accept-Language"))
467+
}
468+
})
469+
470+
t.Run("Well-known proxy propagates custom headers to backend for "+path, func(t *testing.T) {
471+
if receivedRequestHeaders.Get("X-Custom-Header") != "custom-value" {
472+
t.Errorf("Expected X-Custom-Header 'custom-value', got '%s'", receivedRequestHeaders.Get("X-Custom-Header"))
473+
}
474+
})
475+
476+
t.Run("Well-known proxy propagates Referer header to backend for "+path, func(t *testing.T) {
477+
if receivedRequestHeaders.Get("Referer") != "https://example.com/page" {
478+
t.Errorf("Expected Referer header 'https://example.com/page', got '%s'", receivedRequestHeaders.Get("Referer"))
479+
}
480+
})
481+
482+
t.Run("Well-known proxy returns Access-Control-Allow-Origin from backend for "+path, func(t *testing.T) {
483+
if resp.Header.Get("Access-Control-Allow-Origin") != "https://example.com" {
484+
t.Errorf("Expected Access-Control-Allow-Origin header 'https://example.com', got '%s'", resp.Header.Get("Access-Control-Allow-Origin"))
485+
}
486+
})
487+
488+
t.Run("Well-known proxy returns Access-Control-Allow-Methods from backend for "+path, func(t *testing.T) {
489+
if resp.Header.Get("Access-Control-Allow-Methods") != "GET, POST, OPTIONS" {
490+
t.Errorf("Expected Access-Control-Allow-Methods header 'GET, POST, OPTIONS', got '%s'", resp.Header.Get("Access-Control-Allow-Methods"))
491+
}
492+
})
493+
494+
t.Run("Well-known proxy returns Cache-Control from backend for "+path, func(t *testing.T) {
495+
if resp.Header.Get("Cache-Control") != "no-cache" {
496+
t.Errorf("Expected Cache-Control header 'no-cache', got '%s'", resp.Header.Get("Cache-Control"))
497+
}
498+
})
499+
500+
t.Run("Well-known proxy returns custom response headers from backend for "+path, func(t *testing.T) {
501+
if resp.Header.Get("X-Custom-Backend-Header") != "backend-value" {
502+
t.Errorf("Expected X-Custom-Backend-Header 'backend-value', got '%s'", resp.Header.Get("X-Custom-Backend-Header"))
503+
}
504+
})
505+
}
506+
})
507+
}
508+
393509
func TestWellKnownOverrides(t *testing.T) {
394510
cases := []string{
395511
".well-known/oauth-authorization-server",

pkg/http/wellknown.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ var _ http.Handler = &WellKnown{}
3232

3333
func WellKnownHandler(staticConfig *config.StaticConfig, httpClient *http.Client) http.Handler {
3434
authorizationUrl := staticConfig.AuthorizationURL
35-
if authorizationUrl != "" && strings.HasSuffix("authorizationUrl", "/") {
35+
if authorizationUrl != "" && strings.HasSuffix(authorizationUrl, "/") {
3636
authorizationUrl = strings.TrimSuffix(authorizationUrl, "/")
3737
}
3838
if httpClient == nil {
@@ -56,6 +56,11 @@ func (w WellKnown) ServeHTTP(writer http.ResponseWriter, request *http.Request)
5656
http.Error(writer, "Failed to create request: "+err.Error(), http.StatusInternalServerError)
5757
return
5858
}
59+
for key, values := range request.Header {
60+
for _, value := range values {
61+
req.Header.Add(key, value)
62+
}
63+
}
5964
resp, err := w.httpClient.Do(req.WithContext(request.Context()))
6065
if err != nil {
6166
http.Error(writer, "Failed to perform request: "+err.Error(), http.StatusInternalServerError)

0 commit comments

Comments
 (0)