From 3052cc0da32bdd816425fc501036c77c82e32999 Mon Sep 17 00:00:00 2001 From: Stavros Date: Tue, 18 Aug 2026 20:55:05 +0300 Subject: [PATCH] fix: only allow one auth module to succeed per request --- internal/controller/proxy_controller.go | 32 +++++++++++++++----- internal/controller/proxy_controller_test.go | 28 ++++++++++++++++- 2 files changed, 51 insertions(+), 9 deletions(-) diff --git a/internal/controller/proxy_controller.go b/internal/controller/proxy_controller.go index c239e29f..85f4fa92 100644 --- a/internal/controller/proxy_controller.go +++ b/internal/controller/proxy_controller.go @@ -465,6 +465,10 @@ func (controller *ProxyController) getExtAuthzContext(c *gin.Context) (ProxyCont // We get the path from the query string path := c.Query("path") + if strings.TrimSpace(path) == "" { + return ProxyContext{}, errors.New("path not found") + } + // For envoy we need to support every method method := c.Request.Method @@ -536,20 +540,32 @@ func (controller *ProxyController) getProxyContext(c *gin.Context) (ProxyContext return ProxyContext{}, fmt.Errorf("no auth modules supported for proxy: %v", req.Proxy) } - var ctx ProxyContext + ctxs := make(map[AuthModuleType]ProxyContext) for _, module := range authModules { controller.log.App.Debug().Msgf("Trying to get context from auth module %v", module) - ctx, err = controller.getContextFromAuthModule(c, module) - if err == nil { - controller.log.App.Debug().Msgf("Successfully got context from auth module %v", module) - break + ctx, err := controller.getContextFromAuthModule(c, module) + if err != nil { + controller.log.App.Debug().Msgf("Failed to get context from auth module %v: %v", module, err) + continue } - controller.log.App.Debug().Msgf("Failed to get context from auth module %v: %v", module, err) + controller.log.App.Debug().Msgf("Successfully got context from auth module %v", module) + ctxs[module] = ctx } - if err != nil { - return ProxyContext{}, err + if len(ctxs) == 0 { + return ProxyContext{}, fmt.Errorf("no auth module context found") + } + + if len(ctxs) > 1 { + controller.log.App.Warn().Msg("Multiple auth module contexts found, something is wrong in your proxy config or someone is trying to spoof the request, denying") + return ProxyContext{}, fmt.Errorf("multiple auth module contexts found") + } + + var ctx ProxyContext + + for _, c := range ctxs { + ctx = c } // Parse the raw path to populate the cleaned path used for ACLs diff --git a/internal/controller/proxy_controller_test.go b/internal/controller/proxy_controller_test.go index 4d2e23a3..b63ced50 100644 --- a/internal/controller/proxy_controller_test.go +++ b/internal/controller/proxy_controller_test.go @@ -261,7 +261,7 @@ func TestProxyController(t *testing.T) { description: "Ensure extauthz with envoy non browser returns json", middlewares: []gin.HandlerFunc{}, run: func(t *testing.T, router *gin.Engine, recorder *httptest.ResponseRecorder) { - req := httptest.NewRequest("HEAD", "/api/auth/envoy?path=/hello", nil) + req := httptest.NewRequest("HEAD", "/api/auth/envoy", nil) req.Header.Set("x-forwarded-host", "test.example.com") req.Header.Set("x-forwarded-proto", "https") req.Header.Set("x-forwarded-uri", "/hello") @@ -877,6 +877,32 @@ func TestProxyController(t *testing.T) { assert.Equal(t, "bar", recorder.Header().Get("x-foo")) }, }, + { + description: "Forward auth and auth request headers should fail for nginx", + run: func(t *testing.T, router *gin.Engine, recorder *httptest.ResponseRecorder) { + req := httptest.NewRequest("GET", "/api/auth/nginx", nil) + req.Header.Set("x-forwarded-host", "foo.example.com") + req.Header.Set("x-forwarded-proto", "https") + req.Header.Set("x-forwarded-uri", "/foo?bar=foo") + req.Header.Set("x-original-url", "https://foo.example.com/foo?bar=foo") + router.ServeHTTP(recorder, req) + + assert.Equal(t, http.StatusBadRequest, recorder.Code) + }, + }, + { + description: "Forward auth and ext authz headers should fail for envoy", + run: func(t *testing.T, router *gin.Engine, recorder *httptest.ResponseRecorder) { + req := httptest.NewRequest("HEAD", "/api/auth/envoy?path=/hello", nil) + req.Host = "foo.example.com" + req.Header.Set("x-forwarded-host", "foo.example.com") + req.Header.Set("x-forwarded-proto", "https") + req.Header.Set("x-forwarded-uri", "/foo?bar=foo") + router.ServeHTTP(recorder, req) + + assert.Equal(t, http.StatusBadRequest, recorder.Code) + }, + }, } store := memory.New()