feat(api): add support for local management password validation and spoofed IP rejection
- Introduced `newTestServerWithOptions` to customize server initialization in tests. - Added `TestManagementLocalPasswordRejectsSpoofedForwardedFor` to validate security against spoofed `X-Forwarded-For` headers. - Enabled default WebSocket authentication (`ws-auth`) in `config.example.yaml`. - Disabled trusted proxy headers in Gin engine with appropriate logging to enhance security.
This commit is contained in:
+1
-1
@@ -143,7 +143,7 @@ routing:
|
|||||||
session-affinity-ttl: "1h"
|
session-affinity-ttl: "1h"
|
||||||
|
|
||||||
# When true, enable authentication for the WebSocket API (/v1/ws).
|
# When true, enable authentication for the WebSocket API (/v1/ws).
|
||||||
ws-auth: false
|
ws-auth: true
|
||||||
|
|
||||||
# When true, enable Gemini CLI internal endpoints (/v1internal:*).
|
# When true, enable Gemini CLI internal endpoints (/v1internal:*).
|
||||||
# Default is false for safety.
|
# Default is false for safety.
|
||||||
|
|||||||
@@ -217,6 +217,9 @@ func NewServer(cfg *config.Config, authManager *auth.Manager, accessManager *sdk
|
|||||||
|
|
||||||
// Create gin engine
|
// Create gin engine
|
||||||
engine := gin.New()
|
engine := gin.New()
|
||||||
|
if errSetTrustedProxies := engine.SetTrustedProxies(nil); errSetTrustedProxies != nil {
|
||||||
|
log.Warnf("failed to disable trusted proxy headers: %v", errSetTrustedProxies)
|
||||||
|
}
|
||||||
if optionState.engineConfigurator != nil {
|
if optionState.engineConfigurator != nil {
|
||||||
optionState.engineConfigurator(engine)
|
optionState.engineConfigurator(engine)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,10 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func newTestServer(t *testing.T) *Server {
|
func newTestServer(t *testing.T) *Server {
|
||||||
|
return newTestServerWithOptions(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newTestServerWithOptions(t *testing.T, opts ...ServerOption) *Server {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
gin.SetMode(gin.TestMode)
|
gin.SetMode(gin.TestMode)
|
||||||
@@ -46,7 +50,7 @@ func newTestServer(t *testing.T) *Server {
|
|||||||
accessManager := sdkaccess.NewManager()
|
accessManager := sdkaccess.NewManager()
|
||||||
|
|
||||||
configPath := filepath.Join(tmpDir, "config.yaml")
|
configPath := filepath.Join(tmpDir, "config.yaml")
|
||||||
return NewServer(cfg, authManager, accessManager, configPath)
|
return NewServer(cfg, authManager, accessManager, configPath, opts...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestHealthz(t *testing.T) {
|
func TestHealthz(t *testing.T) {
|
||||||
@@ -148,6 +152,26 @@ func TestManagementUsageRequiresManagementAuthAndPopsArray(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestManagementLocalPasswordRejectsSpoofedForwardedFor(t *testing.T) {
|
||||||
|
t.Setenv("MANAGEMENT_PASSWORD", "")
|
||||||
|
|
||||||
|
server := newTestServerWithOptions(t, WithLocalManagementPassword("test-local-key"))
|
||||||
|
|
||||||
|
req := httptest.NewRequest(http.MethodGet, "/v0/management/config", nil)
|
||||||
|
req.RemoteAddr = "203.0.113.10:45678"
|
||||||
|
req.Header.Set("X-Forwarded-For", "127.0.0.1")
|
||||||
|
req.Header.Set("Authorization", "Bearer test-local-key")
|
||||||
|
|
||||||
|
rr := httptest.NewRecorder()
|
||||||
|
server.engine.ServeHTTP(rr, req)
|
||||||
|
if rr.Code != http.StatusForbidden {
|
||||||
|
t.Fatalf("status = %d, want %d body=%s", rr.Code, http.StatusForbidden, rr.Body.String())
|
||||||
|
}
|
||||||
|
if body := rr.Body.String(); !strings.Contains(body, "remote management disabled") {
|
||||||
|
t.Fatalf("body = %q, want remote management disabled", body)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestHomeEnabledHidesManagementEndpointsAndControlPanel(t *testing.T) {
|
func TestHomeEnabledHidesManagementEndpointsAndControlPanel(t *testing.T) {
|
||||||
t.Setenv("MANAGEMENT_PASSWORD", "test-management-key")
|
t.Setenv("MANAGEMENT_PASSWORD", "test-management-key")
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user