From 75c7aad40eff9776451bd1364028c31679c104d4 Mon Sep 17 00:00:00 2001 From: Stavros Date: Fri, 21 Aug 2026 13:10:15 +0300 Subject: [PATCH] fix: don't depend on auth modules failing for spoofing decision --- internal/controller/proxy_controller.go | 63 ++++++++++++++------ internal/controller/proxy_controller_test.go | 2 +- 2 files changed, 47 insertions(+), 18 deletions(-) diff --git a/internal/controller/proxy_controller.go b/internal/controller/proxy_controller.go index 85f4fa92..57b56e4d 100644 --- a/internal/controller/proxy_controller.go +++ b/internal/controller/proxy_controller.go @@ -518,6 +518,39 @@ func (controller *ProxyController) getContextFromAuthModule(c *gin.Context, modu return ProxyContext{}, fmt.Errorf("unsupported auth module: %v", module) } +func (controller *ProxyController) authModuleIdentifiersPresent(c *gin.Context, module AuthModuleType) bool { + switch module { + case ForwardAuth: + _, host := controller.getHeader(c, "x-forwarded-host") + _, uri := controller.getHeader(c, "x-forwarded-uri") + return host || uri + case AuthRequest: + _, ok := controller.getHeader(c, "x-original-url") + return ok + case ExtAuthz: + return strings.TrimSpace(c.Query("path")) != "" + default: + return false + } +} + +func (controller *ProxyController) ensureNoMultipleAuthModules(c *gin.Context, authModules []AuthModuleType) error { + present := 0 + + for _, module := range authModules { + if controller.authModuleIdentifiersPresent(c, module) { + present++ + } + } + + if present > 1 { + controller.log.App.Warn().Msg("Request carries headers for multiple auth modules, possible spoofing attempt, denying") + return fmt.Errorf("conflicting auth module headers") + } + + return nil +} + func (controller *ProxyController) getProxyContext(c *gin.Context) (ProxyContext, error) { var req Proxy @@ -540,32 +573,28 @@ func (controller *ProxyController) getProxyContext(c *gin.Context) (ProxyContext return ProxyContext{}, fmt.Errorf("no auth modules supported for proxy: %v", req.Proxy) } - ctxs := make(map[AuthModuleType]ProxyContext) + err = controller.ensureNoMultipleAuthModules(c, authModules) + + if err != nil { + return ProxyContext{}, err + } + + var ctx *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) + authModuleCtx, 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("Successfully got context from auth module %v", module) - ctxs[module] = ctx + ctx = &authModuleCtx + break } - 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 + if ctx == nil { + return ProxyContext{}, fmt.Errorf("failed to get context from any auth module") } // Parse the raw path to populate the cleaned path used for ACLs @@ -593,5 +622,5 @@ func (controller *ProxyController) getProxyContext(c *gin.Context) (ProxyContext ctx.IsBrowser = isBrowser ctx.ProxyType = proxy - return ctx, nil + return *ctx, nil } diff --git a/internal/controller/proxy_controller_test.go b/internal/controller/proxy_controller_test.go index b63ced50..c7dee667 100644 --- a/internal/controller/proxy_controller_test.go +++ b/internal/controller/proxy_controller_test.go @@ -213,7 +213,7 @@ func TestProxyController(t *testing.T) { description: "Ensure forward auth fallback for envoy", 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.Host = "" req.Header.Set("x-forwarded-host", "test.example.com") req.Header.Set("x-forwarded-proto", "https")