myxce/src/frontend/apiserver/controllers/rbac_abort_test.go
Rongsong Shen 42a402a5b4
fix(apiserver): abort the request on every middleware failure (bug-1949)
Cause: ReturnError only writes the response and never aborts the gin
chain; RequirePermission (token error) and WhitelistIPMiddleware (invalid
client IP) returned after ReturnError without ctx.Abort(), so the route
handler still ran after the rejection.

Fix: ctx.Abort() after ReturnError at both sites (and, for clarity, on the
ValidateHandler body-check path, which validateRequestBody already
aborted). RequirePermission now answers a bad token with 401 instead of
500. ReturnError stays non-aborting (documented): handlers such as
ControlHost call it from helpers and then test ctx.IsAborted(), so a
global abort would change handler flows, and it adds nothing in handlers.

Tests: TestRequirePermission_AbortsOnInvalidToken,
TestWhitelistIPMiddleware_AbortsOnFailure.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-10 08:58:19 +00:00

48 lines
1.3 KiB
Go

package controllers
import (
"apiserver/utils"
"net/http"
"net/http/httptest"
"testing"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
)
// bug-1949: a RequirePermission failure must stop the request before the
// handler runs.
func TestRequirePermission_AbortsOnInvalidToken(t *testing.T) {
resetRBACState()
prev := utils.AuthenticationYamlConfig
utils.AuthenticationYamlConfig = &utils.Authentication{
Token: utils.TokenConfig{Type: "jwt", SecretKey: "rbac-abort-test-secret", TokenExpireTime: 3600},
}
utils.Log = zap.NewNop()
t.Cleanup(func() { utils.AuthenticationYamlConfig = prev })
gin.SetMode(gin.TestMode)
r := gin.New()
handlerRan := false
r.GET("/protected", RequirePermission("host:view"), func(ctx *gin.Context) {
handlerRan = true
ReturnSuccess(ctx, http.StatusOK, "success", nil)
})
for _, header := range []string{"", "Bearer not-a-jwt"} {
handlerRan = false
req := httptest.NewRequest(http.MethodGet, "/protected", nil)
if header != "" {
req.Header.Set("Authorization", header)
}
w := httptest.NewRecorder()
r.ServeHTTP(w, req)
if handlerRan {
t.Errorf("Authorization %q: handler ran after RequirePermission failed (status %d)", header, w.Code)
}
if w.Code != http.StatusUnauthorized {
t.Errorf("Authorization %q: status = %d, want %d", header, w.Code, http.StatusUnauthorized)
}
}
}