package httpserver import ( "net/http" "net/http/httptest" "testing" ) func TestRBAC_Disabled_PassesThrough(t *testing.T) { rbac := NewRBACMiddleware(RBACConfig{Enabled: false}) handler := rbac.Require(RoleAdmin, func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) w.Write([]byte("ok")) }) req := httptest.NewRequest("GET", "/test", nil) rec := httptest.NewRecorder() handler(rec, req) if rec.Code != http.StatusOK { t.Fatalf("expected 200, got %d", rec.Code) } } func TestRBAC_Enabled_NoKey_Returns401(t *testing.T) { rbac := NewRBACMiddleware(RBACConfig{Enabled: true}) handler := rbac.Require(RoleViewer, func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) }) req := httptest.NewRequest("GET", "/test", nil) rec := httptest.NewRecorder() handler(rec, req) if rec.Code != http.StatusUnauthorized { t.Fatalf("expected 401, got %d", rec.Code) } } func TestRBAC_Enabled_ValidKey_AdminAccess(t *testing.T) { rbac := NewRBACMiddleware(RBACConfig{Enabled: true}) rbac.RegisterKey("admin-key", "sk-admin-123", RoleAdmin) handler := rbac.Require(RoleAdmin, func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) w.Write([]byte("admin")) }) req := httptest.NewRequest("GET", "/test", nil) req.Header.Set("Authorization", "Bearer sk-admin-123") rec := httptest.NewRecorder() handler(rec, req) if rec.Code != http.StatusOK { t.Fatalf("expected 200, got %d", rec.Code) } } func TestRBAC_Enabled_InsufficientRole_Returns403(t *testing.T) { rbac := NewRBACMiddleware(RBACConfig{Enabled: true}) rbac.RegisterKey("viewer-key", "sk-viewer-456", RoleViewer) handler := rbac.Require(RoleAdmin, func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) }) req := httptest.NewRequest("GET", "/test", nil) req.Header.Set("Authorization", "Bearer sk-viewer-456") rec := httptest.NewRecorder() handler(rec, req) if rec.Code != http.StatusForbidden { t.Fatalf("expected 403, got %d", rec.Code) } } func TestRBAC_XAPIKeyHeader(t *testing.T) { rbac := NewRBACMiddleware(RBACConfig{Enabled: true}) rbac.RegisterKey("sensor", "sk-sensor-789", RoleSensor) handler := rbac.Require(RoleSensor, func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) }) req := httptest.NewRequest("POST", "/ingest", nil) req.Header.Set("X-API-Key", "sk-sensor-789") rec := httptest.NewRecorder() handler(rec, req) if rec.Code != http.StatusOK { t.Fatalf("expected 200, got %d", rec.Code) } } func TestRBAC_RevokedKey_Returns401(t *testing.T) { rbac := NewRBACMiddleware(RBACConfig{Enabled: true}) rbac.RegisterKey("temp-key", "sk-temp-000", RoleAdmin) rbac.RevokeKey("sk-temp-000") handler := rbac.Require(RoleViewer, func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) }) req := httptest.NewRequest("GET", "/test", nil) req.Header.Set("Authorization", "Bearer sk-temp-000") rec := httptest.NewRecorder() handler(rec, req) if rec.Code != http.StatusUnauthorized { t.Fatalf("expected 401, got %d", rec.Code) } } func TestRBAC_ListKeys_MasksKeys(t *testing.T) { rbac := NewRBACMiddleware(RBACConfig{Enabled: true}) rbac.RegisterKey("admin", "sk-admin-very-long-key-12345", RoleAdmin) keys := rbac.ListKeys() if len(keys) != 1 { t.Fatalf("expected 1 key, got %d", len(keys)) } if keys[0].Key == "sk-admin-very-long-key-12345" { t.Fatal("key should be masked") } if keys[0].Name != "admin" { t.Fatalf("expected name='admin', got %q", keys[0].Name) } t.Logf("masked key: %s", keys[0].Key) } func TestRBAC_RoleHierarchy(t *testing.T) { tests := []struct { userRole Role minRole Role allowed bool }{ {RoleAdmin, RoleAdmin, true}, {RoleAdmin, RoleSensor, true}, {RoleAnalyst, RoleViewer, true}, {RoleViewer, RoleAnalyst, false}, {RoleSensor, RoleViewer, false}, {RoleExternal, RoleAdmin, false}, {RoleSensor, RoleSensor, true}, } for _, tt := range tests { got := hasPermission(tt.userRole, tt.minRole) if got != tt.allowed { t.Errorf("hasPermission(%s, %s) = %v, want %v", tt.userRole, tt.minRole, got, tt.allowed) } } }