fix: allow any HTTP method for /api/auth/envoy (#551)

* feat: allow any HTTP method for /api/auth/envoy and restrict methods for non-envoy proxies

* feat: add Allow header for invalid methods in proxyHandler
This commit is contained in:
Pushpinder Singh
2025-12-31 04:34:25 -05:00
committed by GitHub
parent 3c6bd44906
commit 974f2a67f0
2 changed files with 36 additions and 3 deletions

View File

@@ -43,8 +43,8 @@ func NewProxyController(config ProxyControllerConfig, router *gin.RouterGroup, a
func (controller *ProxyController) SetupRoutes() { func (controller *ProxyController) SetupRoutes() {
proxyGroup := controller.router.Group("/auth") proxyGroup := controller.router.Group("/auth")
proxyGroup.GET("/:proxy", controller.proxyHandler) // There is a later check to control allowed methods per proxy
proxyGroup.POST("/:proxy", controller.proxyHandler) proxyGroup.Any("/:proxy", controller.proxyHandler)
} }
func (controller *ProxyController) proxyHandler(c *gin.Context) { func (controller *ProxyController) proxyHandler(c *gin.Context) {
@@ -69,6 +69,19 @@ func (controller *ProxyController) proxyHandler(c *gin.Context) {
return 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.Header("Allow", "GET")
c.JSON(405, gin.H{
"status": 405,
"message": "Method Not Allowed",
})
return
}
isBrowser := strings.Contains(c.Request.Header.Get("Accept"), "text/html") isBrowser := strings.Contains(c.Request.Header.Get("Accept"), "text/html")
if isBrowser { if isBrowser {

View File

@@ -81,6 +81,14 @@ func TestProxyHandler(t *testing.T) {
assert.Equal(t, 400, recorder.Code) 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)
assert.Equal(t, "GET", recorder.Header().Get("Allow"))
// Test logged out user (traefik/caddy) // Test logged out user (traefik/caddy)
recorder = httptest.NewRecorder() recorder = httptest.NewRecorder()
req = httptest.NewRequest("GET", "/api/auth/traefik", nil) req = httptest.NewRequest("GET", "/api/auth/traefik", nil)
@@ -93,7 +101,7 @@ func TestProxyHandler(t *testing.T) {
assert.Equal(t, 307, recorder.Code) 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")) 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() recorder = httptest.NewRecorder()
req = httptest.NewRequest("POST", "/api/auth/envoy", nil) req = httptest.NewRequest("POST", "/api/auth/envoy", nil)
req.Header.Set("X-Forwarded-Proto", "https") req.Header.Set("X-Forwarded-Proto", "https")
@@ -105,6 +113,18 @@ func TestProxyHandler(t *testing.T) {
assert.Equal(t, 307, recorder.Code) 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")) 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) // Test logged out user (nginx)
recorder = httptest.NewRecorder() recorder = httptest.NewRecorder()
req = httptest.NewRequest("GET", "/api/auth/nginx", nil) req = httptest.NewRequest("GET", "/api/auth/nginx", nil)