Files
Charon/backend/internal/api/handlers/security_geoip_endpoints_test.go
T
GitHub Actions c156183666 fix: Enhance security handler tests and implement role-based access control
- Added role-based middleware to various security handler tests to ensure only admin users can access certain endpoints.
- Created a new test file for authorization checks on security mutators, verifying that non-admin users receive forbidden responses.
- Updated existing tests to include role setting for admin users, ensuring consistent access control during testing.
- Introduced sensitive data masking in settings handler responses, ensuring sensitive values are not exposed in API responses.
- Enhanced user handler responses to mask API keys and invite tokens, providing additional security for user-related endpoints.
- Refactored routes to group security admin endpoints under a dedicated route with role-based access control.
- Added tests for import handler routes to verify authorization guards, ensuring only admin users can access import functionalities.
2026-02-25 05:41:35 +00:00

139 lines
4.0 KiB
Go

package handlers
import (
"bytes"
"encoding/json"
"net/http"
"net/http/httptest"
"testing"
"github.com/Wikid82/charon/backend/internal/config"
"github.com/Wikid82/charon/backend/internal/services"
"github.com/gin-gonic/gin"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestSecurityHandler_GetGeoIPStatus_NotInitialized(t *testing.T) {
gin.SetMode(gin.TestMode)
h := NewSecurityHandler(config.SecurityConfig{}, nil, nil)
r := gin.New()
r.GET("/security/geoip/status", h.GetGeoIPStatus)
w := httptest.NewRecorder()
req := httptest.NewRequest(http.MethodGet, "/security/geoip/status", http.NoBody)
r.ServeHTTP(w, req)
assert.Equal(t, http.StatusOK, w.Code)
var body map[string]any
require.NoError(t, json.Unmarshal(w.Body.Bytes(), &body))
assert.Equal(t, false, body["loaded"])
assert.Equal(t, "GeoIP service not initialized", body["message"])
}
func TestSecurityHandler_GetGeoIPStatus_Initialized_NotLoaded(t *testing.T) {
gin.SetMode(gin.TestMode)
h := NewSecurityHandler(config.SecurityConfig{}, nil, nil)
h.SetGeoIPService(&services.GeoIPService{})
r := gin.New()
r.GET("/security/geoip/status", h.GetGeoIPStatus)
w := httptest.NewRecorder()
req := httptest.NewRequest(http.MethodGet, "/security/geoip/status", http.NoBody)
r.ServeHTTP(w, req)
assert.Equal(t, http.StatusOK, w.Code)
var body map[string]any
require.NoError(t, json.Unmarshal(w.Body.Bytes(), &body))
assert.Equal(t, false, body["loaded"])
assert.Equal(t, "GeoIP service available", body["message"])
}
func TestSecurityHandler_ReloadGeoIP_NotInitialized(t *testing.T) {
gin.SetMode(gin.TestMode)
h := NewSecurityHandler(config.SecurityConfig{}, nil, nil)
r := gin.New()
r.Use(func(c *gin.Context) {
c.Set("role", "admin")
c.Next()
})
r.POST("/security/geoip/reload", h.ReloadGeoIP)
w := httptest.NewRecorder()
req := httptest.NewRequest(http.MethodPost, "/security/geoip/reload", http.NoBody)
r.ServeHTTP(w, req)
assert.Equal(t, http.StatusServiceUnavailable, w.Code)
}
func TestSecurityHandler_ReloadGeoIP_LoadError(t *testing.T) {
gin.SetMode(gin.TestMode)
h := NewSecurityHandler(config.SecurityConfig{}, nil, nil)
h.SetGeoIPService(&services.GeoIPService{}) // dbPath empty => Load() will error
r := gin.New()
r.Use(func(c *gin.Context) {
c.Set("role", "admin")
c.Next()
})
r.POST("/security/geoip/reload", h.ReloadGeoIP)
w := httptest.NewRecorder()
req := httptest.NewRequest(http.MethodPost, "/security/geoip/reload", http.NoBody)
r.ServeHTTP(w, req)
assert.Equal(t, http.StatusInternalServerError, w.Code)
assert.Contains(t, w.Body.String(), "Failed to reload GeoIP database")
}
func TestSecurityHandler_LookupGeoIP_MissingIPAddress(t *testing.T) {
gin.SetMode(gin.TestMode)
h := NewSecurityHandler(config.SecurityConfig{}, nil, nil)
r := gin.New()
r.Use(func(c *gin.Context) {
c.Set("role", "admin")
c.Next()
})
r.POST("/security/geoip/lookup", h.LookupGeoIP)
payload := []byte(`{}`)
w := httptest.NewRecorder()
req := httptest.NewRequest(http.MethodPost, "/security/geoip/lookup", bytes.NewReader(payload))
req.Header.Set("Content-Type", "application/json")
r.ServeHTTP(w, req)
assert.Equal(t, http.StatusBadRequest, w.Code)
assert.Contains(t, w.Body.String(), "ip_address is required")
}
func TestSecurityHandler_LookupGeoIP_ServiceUnavailable(t *testing.T) {
gin.SetMode(gin.TestMode)
h := NewSecurityHandler(config.SecurityConfig{}, nil, nil)
h.SetGeoIPService(&services.GeoIPService{}) // present but not loaded
r := gin.New()
r.Use(func(c *gin.Context) {
c.Set("role", "admin")
c.Next()
})
r.POST("/security/geoip/lookup", h.LookupGeoIP)
payload, _ := json.Marshal(map[string]string{"ip_address": "8.8.8.8"})
w := httptest.NewRecorder()
req := httptest.NewRequest(http.MethodPost, "/security/geoip/lookup", bytes.NewReader(payload))
req.Header.Set("Content-Type", "application/json")
r.ServeHTTP(w, req)
assert.Equal(t, http.StatusServiceUnavailable, w.Code)
assert.Contains(t, w.Body.String(), "GeoIP service not available")
}