From d210966dc3a7501483cf985de3c7b58c24f07220 Mon Sep 17 00:00:00 2001 From: pushpinderbal Date: Tue, 30 Dec 2025 23:47:20 -0500 Subject: [PATCH 1/2] feat: allow any HTTP method for /api/auth/envoy and restrict methods for non-envoy proxies --- internal/controller/proxy_controller.go | 16 +++++++++++++-- internal/controller/proxy_controller_test.go | 21 +++++++++++++++++++- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/internal/controller/proxy_controller.go b/internal/controller/proxy_controller.go index 40f83748..6c1b3347 100644 --- a/internal/controller/proxy_controller.go +++ b/internal/controller/proxy_controller.go @@ -43,8 +43,8 @@ func NewProxyController(config ProxyControllerConfig, router *gin.RouterGroup, a func (controller *ProxyController) SetupRoutes() { proxyGroup := controller.router.Group("/auth") - proxyGroup.GET("/:proxy", controller.proxyHandler) - proxyGroup.POST("/:proxy", controller.proxyHandler) + // There is a later check to control allowed methods per proxy + proxyGroup.Any("/:proxy", controller.proxyHandler) } func (controller *ProxyController) proxyHandler(c *gin.Context) { @@ -69,6 +69,18 @@ func (controller *ProxyController) proxyHandler(c *gin.Context) { return } + // Only allow GET for non-envoy proxies. + // Envoy uses the original client method for the external auth request + // so we allow Any standard HTTP method for /api/auth/envoy + if req.Proxy != "envoy" && c.Request.Method != http.MethodGet { + log.Warn().Str("method", c.Request.Method).Msg("Invalid method for proxy") + c.JSON(405, gin.H{ + "status": 405, + "message": "Method Not Allowed", + }) + return + } + isBrowser := strings.Contains(c.Request.Header.Get("Accept"), "text/html") if isBrowser { diff --git a/internal/controller/proxy_controller_test.go b/internal/controller/proxy_controller_test.go index 54bb8882..7f3c826a 100644 --- a/internal/controller/proxy_controller_test.go +++ b/internal/controller/proxy_controller_test.go @@ -81,6 +81,13 @@ func TestProxyHandler(t *testing.T) { assert.Equal(t, 400, recorder.Code) + // Test invalid method for non-envoy proxy + recorder = httptest.NewRecorder() + req = httptest.NewRequest("POST", "/api/auth/traefik", nil) + router.ServeHTTP(recorder, req) + + assert.Equal(t, 405, recorder.Code) + // Test logged out user (traefik/caddy) recorder = httptest.NewRecorder() req = httptest.NewRequest("GET", "/api/auth/traefik", nil) @@ -93,7 +100,7 @@ func TestProxyHandler(t *testing.T) { assert.Equal(t, 307, recorder.Code) assert.Equal(t, "http://localhost:8080/login?redirect_uri=https%3A%2F%2Fexample.com%2Fsomepath", recorder.Header().Get("Location")) - // Test logged out user (envoy) + // Test logged out user (envoy - POST method) recorder = httptest.NewRecorder() req = httptest.NewRequest("POST", "/api/auth/envoy", nil) req.Header.Set("X-Forwarded-Proto", "https") @@ -105,6 +112,18 @@ func TestProxyHandler(t *testing.T) { assert.Equal(t, 307, recorder.Code) assert.Equal(t, "http://localhost:8080/login?redirect_uri=https%3A%2F%2Fexample.com%2Fsomepath", recorder.Header().Get("Location")) + // Test logged out user (envoy - DELETE method) + recorder = httptest.NewRecorder() + req = httptest.NewRequest("DELETE", "/api/auth/envoy", nil) + req.Header.Set("X-Forwarded-Proto", "https") + req.Header.Set("X-Forwarded-Host", "example.com") + req.Header.Set("X-Forwarded-Uri", "/somepath") + req.Header.Set("Accept", "text/html") + router.ServeHTTP(recorder, req) + + assert.Equal(t, 307, recorder.Code) + assert.Equal(t, "http://localhost:8080/login?redirect_uri=https%3A%2F%2Fexample.com%2Fsomepath", recorder.Header().Get("Location")) + // Test logged out user (nginx) recorder = httptest.NewRecorder() req = httptest.NewRequest("GET", "/api/auth/nginx", nil) From 80dee3d12b6efff46d673462802042ef4df8df5f Mon Sep 17 00:00:00 2001 From: pushpinderbal Date: Wed, 31 Dec 2025 00:01:54 -0500 Subject: [PATCH 2/2] feat: add Allow header for invalid methods in proxyHandler --- internal/controller/proxy_controller.go | 1 + internal/controller/proxy_controller_test.go | 1 + 2 files changed, 2 insertions(+) diff --git a/internal/controller/proxy_controller.go b/internal/controller/proxy_controller.go index 6c1b3347..d6c8bebc 100644 --- a/internal/controller/proxy_controller.go +++ b/internal/controller/proxy_controller.go @@ -74,6 +74,7 @@ func (controller *ProxyController) proxyHandler(c *gin.Context) { // so we allow Any standard HTTP method for /api/auth/envoy if req.Proxy != "envoy" && c.Request.Method != http.MethodGet { log.Warn().Str("method", c.Request.Method).Msg("Invalid method for proxy") + c.Header("Allow", "GET") c.JSON(405, gin.H{ "status": 405, "message": "Method Not Allowed", diff --git a/internal/controller/proxy_controller_test.go b/internal/controller/proxy_controller_test.go index 7f3c826a..4d409a8c 100644 --- a/internal/controller/proxy_controller_test.go +++ b/internal/controller/proxy_controller_test.go @@ -87,6 +87,7 @@ func TestProxyHandler(t *testing.T) { router.ServeHTTP(recorder, req) assert.Equal(t, 405, recorder.Code) + assert.Equal(t, "GET", recorder.Header().Get("Allow")) // Test logged out user (traefik/caddy) recorder = httptest.NewRecorder()