fix(admin): omit unresolved tenant header
This commit is contained in:
parent
d6801f9de2
commit
e7389c1e74
@ -8,6 +8,8 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
adminmiddleware "hyapp-admin-server/internal/middleware"
|
||||||
|
|
||||||
"github.com/DATA-DOG/go-sqlmock"
|
"github.com/DATA-DOG/go-sqlmock"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"gorm.io/driver/mysql"
|
"gorm.io/driver/mysql"
|
||||||
@ -76,6 +78,9 @@ func TestLoginIgnoresLegacyRequestAppAndAuditsUnknownAccountWithoutTenant(t *tes
|
|||||||
|
|
||||||
gin.SetMode(gin.TestMode)
|
gin.SetMode(gin.TestMode)
|
||||||
engine := gin.New()
|
engine := gin.New()
|
||||||
|
// Production installs the global App middleware before external routes. Login
|
||||||
|
// must remove its fallback "lalu" response header until credentials resolve.
|
||||||
|
engine.Use(adminmiddleware.AppCode())
|
||||||
handler := New(adminDB, nil, Config{}, nil, WithLoginRateLimiter(allowFixedWindowLimiter{}))
|
handler := New(adminDB, nil, Config{}, nil, WithLoginRateLimiter(allowFixedWindowLimiter{}))
|
||||||
RegisterExternalRoutes(engine.Group("/api/v1"), handler, BusinessHandlers{})
|
RegisterExternalRoutes(engine.Group("/api/v1"), handler, BusinessHandlers{})
|
||||||
request := httptest.NewRequest(http.MethodPost, "/api/v1/external/auth/login", strings.NewReader(`{"appCode":"lalu","account":"missing-operator","password":"wrong-password"}`))
|
request := httptest.NewRequest(http.MethodPost, "/api/v1/external/auth/login", strings.NewReader(`{"appCode":"lalu","account":"missing-operator","password":"wrong-password"}`))
|
||||||
@ -86,6 +91,9 @@ func TestLoginIgnoresLegacyRequestAppAndAuditsUnknownAccountWithoutTenant(t *tes
|
|||||||
if responseRecorder.Code != http.StatusUnauthorized {
|
if responseRecorder.Code != http.StatusUnauthorized {
|
||||||
t.Fatalf("status=%d body=%s", responseRecorder.Code, responseRecorder.Body.String())
|
t.Fatalf("status=%d body=%s", responseRecorder.Code, responseRecorder.Body.String())
|
||||||
}
|
}
|
||||||
|
if got := responseRecorder.Header().Get("X-App-Code"); got != "" {
|
||||||
|
t.Fatalf("failed tenant-less login exposed default App header %q", got)
|
||||||
|
}
|
||||||
if !strings.Contains(responseRecorder.Body.String(), `"code":40100`) || strings.Contains(responseRecorder.Body.String(), "App") {
|
if !strings.Contains(responseRecorder.Body.String(), `"code":40100`) || strings.Contains(responseRecorder.Body.String(), "App") {
|
||||||
t.Fatalf("login response must expose only stable auth code and generic text: %s", responseRecorder.Body.String())
|
t.Fatalf("login response must expose only stable auth code and generic text: %s", responseRecorder.Body.String())
|
||||||
}
|
}
|
||||||
|
|||||||
@ -233,6 +233,10 @@ func (h *Handler) ListApps(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) Login(c *gin.Context) {
|
func (h *Handler) Login(c *gin.Context) {
|
||||||
|
// The global App middleware supplies the main-admin default before this anonymous
|
||||||
|
// route runs. No tenant is authoritative until a credential row resolves, so do
|
||||||
|
// not leak or imply that default on malformed, throttled or failed login responses.
|
||||||
|
c.Writer.Header().Del(appctx.HeaderAppCode)
|
||||||
// Limit parsing memory before decoding untrusted credentials. Binding tags are
|
// Limit parsing memory before decoding untrusted credentials. Binding tags are
|
||||||
// intentionally absent on loginRequest: every syntactically valid JSON attempt,
|
// intentionally absent on loginRequest: every syntactically valid JSON attempt,
|
||||||
// including missing fields, must reach the distributed limiter before rejection.
|
// including missing fields, must reach the distributed limiter before rejection.
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user