Skip to main content
Glama
orneryd

M.I.M.I.R - Multi-agent Intelligent Memory & Insight Repository

by orneryd
auth_adapter_test.go27.9 kB
package bolt import ( "strings" "testing" "time" "github.com/orneryd/nornicdb/pkg/auth" ) func TestAuthenticatorAdapter(t *testing.T) { // Create a real authenticator for testing config := auth.DefaultAuthConfig() config.JWTSecret = []byte("test-secret-key-for-jwt-signing!!") config.SecurityEnabled = true authenticator, err := auth.NewAuthenticator(config) if err != nil { t.Fatalf("Failed to create authenticator: %v", err) } // Create test users _, err = authenticator.CreateUser("admin", "admin-password", []auth.Role{auth.RoleAdmin}) if err != nil { t.Fatalf("Failed to create admin user: %v", err) } _, err = authenticator.CreateUser("editor", "editor-password", []auth.Role{auth.RoleEditor}) if err != nil { t.Fatalf("Failed to create editor user: %v", err) } _, err = authenticator.CreateUser("viewer", "viewer-password", []auth.Role{auth.RoleViewer}) if err != nil { t.Fatalf("Failed to create viewer user: %v", err) } // Create service account for clustering _, err = authenticator.CreateUser("cluster-node-1", "cluster-secret-123", []auth.Role{auth.RoleAdmin}) if err != nil { t.Fatalf("Failed to create cluster service account: %v", err) } t.Run("basic auth success - admin", func(t *testing.T) { adapter := NewAuthenticatorAdapter(authenticator) result, err := adapter.Authenticate("basic", "admin", "admin-password") if err != nil { t.Fatalf("Expected success, got error: %v", err) } if !result.Authenticated { t.Error("Expected Authenticated=true") } if result.Username != "admin" { t.Errorf("Expected username 'admin', got '%s'", result.Username) } if !result.HasRole("admin") { t.Error("Expected admin role") } if !result.HasPermission("write") { t.Error("Admin should have write permission") } if !result.HasPermission("schema") { t.Error("Admin should have schema permission") } }) t.Run("basic auth success - editor", func(t *testing.T) { adapter := NewAuthenticatorAdapter(authenticator) result, err := adapter.Authenticate("basic", "editor", "editor-password") if err != nil { t.Fatalf("Expected success, got error: %v", err) } if !result.HasRole("editor") { t.Error("Expected editor role") } if !result.HasPermission("write") { t.Error("Editor should have write permission") } if result.HasPermission("schema") { t.Error("Editor should NOT have schema permission") } }) t.Run("basic auth success - viewer", func(t *testing.T) { adapter := NewAuthenticatorAdapter(authenticator) result, err := adapter.Authenticate("basic", "viewer", "viewer-password") if err != nil { t.Fatalf("Expected success, got error: %v", err) } if !result.HasRole("viewer") { t.Error("Expected viewer role") } if !result.HasPermission("read") { t.Error("Viewer should have read permission") } if result.HasPermission("write") { t.Error("Viewer should NOT have write permission") } }) t.Run("service account auth for clustering", func(t *testing.T) { adapter := NewAuthenticatorAdapter(authenticator) // Service accounts use the same "basic" auth as regular users result, err := adapter.Authenticate("basic", "cluster-node-1", "cluster-secret-123") if err != nil { t.Fatalf("Expected success for service account, got error: %v", err) } if !result.Authenticated { t.Error("Expected Authenticated=true for service account") } if result.Username != "cluster-node-1" { t.Errorf("Expected username 'cluster-node-1', got '%s'", result.Username) } if !result.HasRole("admin") { t.Error("Service account should have admin role for clustering") } }) t.Run("basic auth failure - wrong password", func(t *testing.T) { adapter := NewAuthenticatorAdapter(authenticator) _, err := adapter.Authenticate("basic", "admin", "wrong-password") if err == nil { t.Error("Expected error for wrong password") } }) t.Run("basic auth failure - unknown user", func(t *testing.T) { adapter := NewAuthenticatorAdapter(authenticator) _, err := adapter.Authenticate("basic", "unknown-user", "any-password") if err == nil { t.Error("Expected error for unknown user") } }) t.Run("anonymous auth - disabled by default", func(t *testing.T) { adapter := NewAuthenticatorAdapter(authenticator) _, err := adapter.Authenticate("none", "", "") if err == nil { t.Error("Expected error for anonymous auth when disabled") } }) t.Run("anonymous auth - enabled", func(t *testing.T) { adapter := NewAuthenticatorAdapterWithAnonymous(authenticator) result, err := adapter.Authenticate("none", "", "") if err != nil { t.Fatalf("Expected success for anonymous auth when enabled, got: %v", err) } if result.Username != "anonymous" { t.Errorf("Expected username 'anonymous', got '%s'", result.Username) } if !result.HasRole("viewer") { t.Error("Anonymous should have viewer role") } if !result.HasPermission("read") { t.Error("Anonymous should have read permission") } if result.HasPermission("write") { t.Error("Anonymous should NOT have write permission") } }) t.Run("anonymous auth - empty scheme treated as none", func(t *testing.T) { adapter := NewAuthenticatorAdapterWithAnonymous(authenticator) result, err := adapter.Authenticate("", "", "") if err != nil { t.Fatalf("Expected success for empty scheme when anonymous enabled: %v", err) } if result.Username != "anonymous" { t.Errorf("Expected username 'anonymous', got '%s'", result.Username) } }) t.Run("unsupported auth scheme", func(t *testing.T) { adapter := NewAuthenticatorAdapter(authenticator) _, err := adapter.Authenticate("kerberos", "user", "ticket") if err == nil { t.Error("Expected error for unsupported auth scheme") } }) t.Run("SetAllowAnonymous toggle", func(t *testing.T) { adapter := NewAuthenticatorAdapter(authenticator) // Initially disabled _, err := adapter.Authenticate("none", "", "") if err == nil { t.Error("Expected error when anonymous disabled") } // Enable adapter.SetAllowAnonymous(true) result, err := adapter.Authenticate("none", "", "") if err != nil { t.Fatalf("Expected success when anonymous enabled: %v", err) } if result.Username != "anonymous" { t.Error("Expected anonymous user") } // Disable again adapter.SetAllowAnonymous(false) _, err = adapter.Authenticate("none", "", "") if err == nil { t.Error("Expected error after disabling anonymous") } }) } func TestAuthenticatorAdapterIntegrationWithBoltConfig(t *testing.T) { // This test verifies the adapter works correctly with Bolt Config config := auth.DefaultAuthConfig() config.JWTSecret = []byte("test-secret-key-for-jwt-signing!!") config.SecurityEnabled = true authenticator, err := auth.NewAuthenticator(config) if err != nil { t.Fatalf("Failed to create authenticator: %v", err) } _, err = authenticator.CreateUser("testuser", "testpass", []auth.Role{auth.RoleEditor}) if err != nil { t.Fatalf("Failed to create user: %v", err) } // Create Bolt config with the adapter boltConfig := DefaultConfig() boltConfig.Authenticator = NewAuthenticatorAdapter(authenticator) boltConfig.RequireAuth = true // Verify it's properly assigned if boltConfig.Authenticator == nil { t.Error("Authenticator should be set") } // Verify auth works through config result, err := boltConfig.Authenticator.Authenticate("basic", "testuser", "testpass") if err != nil { t.Fatalf("Auth through config failed: %v", err) } if !result.Authenticated { t.Error("Expected successful authentication") } } // TestBearerTokenAuthentication tests JWT bearer token authentication func TestBearerTokenAuthentication(t *testing.T) { config := auth.DefaultAuthConfig() config.JWTSecret = []byte("test-secret-key-for-jwt-signing!!") config.SecurityEnabled = true authenticator, err := auth.NewAuthenticator(config) if err != nil { t.Fatalf("Failed to create authenticator: %v", err) } adapter := NewAuthenticatorAdapter(authenticator) t.Run("bearer scheme with valid cluster token", func(t *testing.T) { // Generate a cluster token token, err := authenticator.GenerateClusterToken("node-1", auth.RoleAdmin) if err != nil { t.Fatalf("Failed to generate cluster token: %v", err) } // Authenticate with bearer scheme result, err := adapter.Authenticate("bearer", "", token) if err != nil { t.Fatalf("Bearer auth failed: %v", err) } if !result.Authenticated { t.Error("Expected Authenticated=true") } if result.Username != "node-1" { t.Errorf("Expected username 'node-1', got '%s'", result.Username) } if !result.HasRole("admin") { t.Error("Expected admin role") } if !result.HasPermission("write") { t.Error("Admin should have write permission") } if !result.HasPermission("schema") { t.Error("Admin should have schema permission") } }) t.Run("bearer scheme with viewer role token", func(t *testing.T) { token, err := authenticator.GenerateClusterToken("read-replica", auth.RoleViewer) if err != nil { t.Fatalf("Failed to generate cluster token: %v", err) } result, err := adapter.Authenticate("bearer", "", token) if err != nil { t.Fatalf("Bearer auth failed: %v", err) } if result.Username != "read-replica" { t.Errorf("Expected username 'read-replica', got '%s'", result.Username) } if !result.HasRole("viewer") { t.Error("Expected viewer role") } if !result.HasPermission("read") { t.Error("Viewer should have read permission") } if result.HasPermission("write") { t.Error("Viewer should NOT have write permission") } }) t.Run("bearer scheme with editor role token", func(t *testing.T) { token, err := authenticator.GenerateClusterToken("worker-node", auth.RoleEditor) if err != nil { t.Fatalf("Failed to generate cluster token: %v", err) } result, err := adapter.Authenticate("bearer", "", token) if err != nil { t.Fatalf("Bearer auth failed: %v", err) } if !result.HasRole("editor") { t.Error("Expected editor role") } if !result.HasPermission("write") { t.Error("Editor should have write permission") } if result.HasPermission("schema") { t.Error("Editor should NOT have schema permission") } }) t.Run("bearer scheme with empty token fails", func(t *testing.T) { _, err := adapter.Authenticate("bearer", "", "") if err == nil { t.Error("Expected error for empty bearer token") } if !strings.Contains(err.Error(), "bearer token required") { t.Errorf("Expected 'bearer token required' error, got: %v", err) } }) t.Run("bearer scheme with invalid token fails", func(t *testing.T) { _, err := adapter.Authenticate("bearer", "", "invalid.token.here") if err == nil { t.Error("Expected error for invalid bearer token") } if !strings.Contains(err.Error(), "invalid bearer token") { t.Errorf("Expected 'invalid bearer token' error, got: %v", err) } }) t.Run("bearer scheme with malformed JWT fails", func(t *testing.T) { _, err := adapter.Authenticate("bearer", "", "not-a-jwt-at-all") if err == nil { t.Error("Expected error for malformed JWT") } }) t.Run("bearer scheme with wrong signature fails", func(t *testing.T) { // Generate token with correct format but tampered signature token, _ := authenticator.GenerateClusterToken("node-1", auth.RoleAdmin) parts := strings.Split(token, ".") if len(parts) == 3 { // Tamper with signature tamperedToken := parts[0] + "." + parts[1] + ".tampered_signature" _, err := adapter.Authenticate("bearer", "", tamperedToken) if err == nil { t.Error("Expected error for tampered JWT signature") } } }) } // TestJWTAsBasicAuth tests JWT tokens passed via basic auth with empty username func TestJWTAsBasicAuth(t *testing.T) { config := auth.DefaultAuthConfig() config.JWTSecret = []byte("test-secret-key-for-jwt-signing!!") config.SecurityEnabled = true authenticator, err := auth.NewAuthenticator(config) if err != nil { t.Fatalf("Failed to create authenticator: %v", err) } adapter := NewAuthenticatorAdapter(authenticator) t.Run("JWT token with empty principal triggers bearer auth", func(t *testing.T) { // Generate a cluster token token, err := authenticator.GenerateClusterToken("cluster-west", auth.RoleAdmin) if err != nil { t.Fatalf("Failed to generate cluster token: %v", err) } // Pass JWT as credentials with empty principal (the Neo4j driver workaround) result, err := adapter.Authenticate("basic", "", token) if err != nil { t.Fatalf("JWT-as-basic auth failed: %v", err) } if !result.Authenticated { t.Error("Expected Authenticated=true") } if result.Username != "cluster-west" { t.Errorf("Expected username 'cluster-west', got '%s'", result.Username) } if !result.HasRole("admin") { t.Error("Expected admin role") } }) t.Run("empty principal with non-JWT password fails properly", func(t *testing.T) { // This should NOT be treated as JWT because it doesn't look like one _, err := adapter.Authenticate("basic", "", "regular-password") if err == nil { t.Error("Expected error for empty principal with non-JWT password") } }) t.Run("empty principal with invalid JWT fails", func(t *testing.T) { // Looks like JWT format but invalid _, err := adapter.Authenticate("basic", "", "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ0ZXN0In0.invalid_sig") if err == nil { t.Error("Expected error for invalid JWT") } }) } // TestGenerateClusterToken tests cluster token generation func TestGenerateClusterToken(t *testing.T) { config := auth.DefaultAuthConfig() config.JWTSecret = []byte("test-secret-key-for-jwt-signing!!") config.SecurityEnabled = true authenticator, err := auth.NewAuthenticator(config) if err != nil { t.Fatalf("Failed to create authenticator: %v", err) } t.Run("generates valid admin token", func(t *testing.T) { token, err := authenticator.GenerateClusterToken("node-east", auth.RoleAdmin) if err != nil { t.Fatalf("Failed to generate token: %v", err) } // Token should be in JWT format parts := strings.Split(token, ".") if len(parts) != 3 { t.Errorf("Expected JWT format (3 parts), got %d parts", len(parts)) } // Validate the token claims, err := authenticator.ValidateToken(token) if err != nil { t.Fatalf("Token validation failed: %v", err) } if claims.Username != "node-east" { t.Errorf("Expected username 'node-east', got '%s'", claims.Username) } if len(claims.Roles) != 1 || claims.Roles[0] != "admin" { t.Errorf("Expected roles ['admin'], got %v", claims.Roles) } if !strings.HasPrefix(claims.Sub, "cluster-") { t.Errorf("Expected Sub to start with 'cluster-', got '%s'", claims.Sub) } }) t.Run("generates valid viewer token", func(t *testing.T) { token, err := authenticator.GenerateClusterToken("replica-1", auth.RoleViewer) if err != nil { t.Fatalf("Failed to generate token: %v", err) } claims, err := authenticator.ValidateToken(token) if err != nil { t.Fatalf("Token validation failed: %v", err) } if len(claims.Roles) != 1 || claims.Roles[0] != "viewer" { t.Errorf("Expected roles ['viewer'], got %v", claims.Roles) } }) t.Run("different nodes get different tokens", func(t *testing.T) { token1, _ := authenticator.GenerateClusterToken("node-1", auth.RoleAdmin) token2, _ := authenticator.GenerateClusterToken("node-2", auth.RoleAdmin) if token1 == token2 { t.Error("Different nodes should get different tokens") } }) } // TestGenerateClusterTokenWithExpiry tests token generation with custom expiry func TestGenerateClusterTokenWithExpiry(t *testing.T) { config := auth.DefaultAuthConfig() config.JWTSecret = []byte("test-secret-key-for-jwt-signing!!") config.SecurityEnabled = true authenticator, err := auth.NewAuthenticator(config) if err != nil { t.Fatalf("Failed to create authenticator: %v", err) } t.Run("generates token with expiry", func(t *testing.T) { token, err := authenticator.GenerateClusterTokenWithExpiry("node-1", auth.RoleAdmin, 24*time.Hour) if err != nil { t.Fatalf("Failed to generate token: %v", err) } claims, err := authenticator.ValidateToken(token) if err != nil { t.Fatalf("Token validation failed: %v", err) } // Check expiry is set if claims.Exp == 0 { t.Error("Expected Exp to be set") } // Check expiry is approximately 24 hours from now expectedExp := time.Now().Add(24 * time.Hour).Unix() diff := claims.Exp - expectedExp if diff < -60 || diff > 60 { // Allow 60 second tolerance t.Errorf("Expected Exp around %d, got %d (diff: %d)", expectedExp, claims.Exp, diff) } }) t.Run("generates token without expiry when 0", func(t *testing.T) { token, err := authenticator.GenerateClusterTokenWithExpiry("node-1", auth.RoleAdmin, 0) if err != nil { t.Fatalf("Failed to generate token: %v", err) } claims, err := authenticator.ValidateToken(token) if err != nil { t.Fatalf("Token validation failed: %v", err) } if claims.Exp != 0 { t.Errorf("Expected Exp to be 0 (never expires), got %d", claims.Exp) } }) t.Run("short-lived token expires correctly", func(t *testing.T) { // Generate token that expires in 1 second token, err := authenticator.GenerateClusterTokenWithExpiry("node-1", auth.RoleAdmin, 1*time.Second) if err != nil { t.Fatalf("Failed to generate token: %v", err) } // Should be valid immediately _, err = authenticator.ValidateToken(token) if err != nil { t.Fatalf("Token should be valid immediately: %v", err) } // Wait for expiry time.Sleep(2 * time.Second) // Should be expired now _, err = authenticator.ValidateToken(token) if err == nil { t.Error("Expected expired token to fail validation") } }) } // TestLooksLikeJWT tests the JWT detection helper func TestLooksLikeJWT(t *testing.T) { tests := []struct { name string input string expected bool }{ {"valid JWT format", "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ0ZXN0In0.signature", true}, {"real JWT token", "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.dozjgNryP4J3jVmNHl0w5N_XgL0n3I9PlFUP0THsR8U", true}, {"short token two dots", "a.b.c", false}, // Too short {"empty string", "", false}, {"no dots", "nodots", false}, {"one dot", "one.dot", false}, {"two dots but short", "a.b.c", false}, {"three dots", "a.b.c.d", false}, {"regular password", "my-secure-password-123", false}, {"password with special chars", "P@ssw0rd!123#", false}, {"base64 without dots", "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9", false}, {"long string two dots", "aaaaaaaaaaaaaaaaaaaaa.bbbbbbbbbbbbbbbbbbb.cccccccccccccccc", true}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result := looksLikeJWT(tt.input) if result != tt.expected { t.Errorf("looksLikeJWT(%q) = %v, expected %v", tt.input, result, tt.expected) } }) } } // TestClusterAuthenticationE2E tests end-to-end cluster authentication flow func TestClusterAuthenticationE2E(t *testing.T) { // Simulate two nodes with the same JWT secret (shared secret cluster) sharedSecret := []byte("shared-cluster-secret-32-chars!!") // Node 1 (leader) config1 := auth.DefaultAuthConfig() config1.JWTSecret = sharedSecret config1.SecurityEnabled = true node1Auth, _ := auth.NewAuthenticator(config1) node1Adapter := NewAuthenticatorAdapter(node1Auth) // Node 2 (follower) config2 := auth.DefaultAuthConfig() config2.JWTSecret = sharedSecret config2.SecurityEnabled = true node2Auth, _ := auth.NewAuthenticator(config2) node2Adapter := NewAuthenticatorAdapter(node2Auth) t.Run("token generated on node1 works on node2", func(t *testing.T) { // Generate token on node1 token, err := node1Auth.GenerateClusterToken("follower-node-2", auth.RoleAdmin) if err != nil { t.Fatalf("Failed to generate token on node1: %v", err) } // Use token to authenticate on node2 (the leader) result, err := node2Adapter.Authenticate("bearer", "", token) if err != nil { t.Fatalf("Token from node1 failed on node2: %v", err) } if !result.Authenticated { t.Error("Expected successful authentication") } if result.Username != "follower-node-2" { t.Errorf("Expected username 'follower-node-2', got '%s'", result.Username) } }) t.Run("token generated on node2 works on node1", func(t *testing.T) { // Generate token on node2 token, err := node2Auth.GenerateClusterToken("leader-node-1", auth.RoleAdmin) if err != nil { t.Fatalf("Failed to generate token on node2: %v", err) } // Use token to authenticate on node1 result, err := node1Adapter.Authenticate("bearer", "", token) if err != nil { t.Fatalf("Token from node2 failed on node1: %v", err) } if !result.Authenticated { t.Error("Expected successful authentication") } }) t.Run("token with different secret fails", func(t *testing.T) { // Create a rogue node with different secret rogueConfig := auth.DefaultAuthConfig() rogueConfig.JWTSecret = []byte("different-secret-not-trusted!!!") rogueConfig.SecurityEnabled = true rogueAuth, _ := auth.NewAuthenticator(rogueConfig) // Generate token with rogue secret rogueToken, err := rogueAuth.GenerateClusterToken("rogue-node", auth.RoleAdmin) if err != nil { t.Fatalf("Failed to generate rogue token: %v", err) } // Try to use on node1 - should fail _, err = node1Adapter.Authenticate("bearer", "", rogueToken) if err == nil { t.Error("Expected rogue token to fail authentication") } }) t.Run("JWT via basic auth works across nodes", func(t *testing.T) { // This is the Neo4j driver workaround path token, _ := node1Auth.GenerateClusterToken("driver-client", auth.RoleEditor) // Authenticate using basic auth with empty principal result, err := node2Adapter.Authenticate("basic", "", token) if err != nil { t.Fatalf("JWT via basic auth failed: %v", err) } if result.Username != "driver-client" { t.Errorf("Expected username 'driver-client', got '%s'", result.Username) } if !result.HasRole("editor") { t.Error("Expected editor role") } }) } // TestBoltAuthResultPermissions tests all permission combinations func TestBoltAuthResultPermissions(t *testing.T) { tests := []struct { name string roles []string permission string shouldHave bool }{ // Admin role {"admin has read", []string{"admin"}, "read", true}, {"admin has write", []string{"admin"}, "write", true}, {"admin has create", []string{"admin"}, "create", true}, {"admin has delete", []string{"admin"}, "delete", true}, {"admin has admin", []string{"admin"}, "admin", true}, {"admin has schema", []string{"admin"}, "schema", true}, {"admin has user_manage", []string{"admin"}, "user_manage", true}, // Editor role {"editor has read", []string{"editor"}, "read", true}, {"editor has write", []string{"editor"}, "write", true}, {"editor has create", []string{"editor"}, "create", true}, {"editor has delete", []string{"editor"}, "delete", true}, {"editor no admin", []string{"editor"}, "admin", false}, {"editor no schema", []string{"editor"}, "schema", false}, {"editor no user_manage", []string{"editor"}, "user_manage", false}, // Viewer role {"viewer has read", []string{"viewer"}, "read", true}, {"viewer no write", []string{"viewer"}, "write", false}, {"viewer no create", []string{"viewer"}, "create", false}, {"viewer no delete", []string{"viewer"}, "delete", false}, {"viewer no admin", []string{"viewer"}, "admin", false}, {"viewer no schema", []string{"viewer"}, "schema", false}, // None role {"none no read", []string{"none"}, "read", false}, {"none no write", []string{"none"}, "write", false}, {"none no admin", []string{"none"}, "admin", false}, // Multiple roles {"viewer+editor has read", []string{"viewer", "editor"}, "read", true}, {"viewer+editor has write", []string{"viewer", "editor"}, "write", true}, {"viewer+editor no schema", []string{"viewer", "editor"}, "schema", false}, // Invalid/unknown role {"unknown role no perms", []string{"custom"}, "read", false}, {"unknown role no write", []string{"custom"}, "write", false}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result := &BoltAuthResult{ Authenticated: true, Username: "test", Roles: tt.roles, } has := result.HasPermission(tt.permission) if has != tt.shouldHave { t.Errorf("HasPermission(%q) = %v, expected %v for roles %v", tt.permission, has, tt.shouldHave, tt.roles) } }) } } // TestBoltAuthResultHasRole tests role checking func TestBoltAuthResultHasRole(t *testing.T) { tests := []struct { name string roles []string checkRole string shouldHave bool }{ {"has single role", []string{"admin"}, "admin", true}, {"missing single role", []string{"admin"}, "editor", false}, {"has in multiple roles", []string{"editor", "viewer"}, "viewer", true}, {"missing in multiple roles", []string{"editor", "viewer"}, "admin", false}, {"empty roles", []string{}, "admin", false}, {"nil treated as empty", nil, "admin", false}, {"case sensitive", []string{"Admin"}, "admin", false}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result := &BoltAuthResult{ Authenticated: true, Username: "test", Roles: tt.roles, } has := result.HasRole(tt.checkRole) if has != tt.shouldHave { t.Errorf("HasRole(%q) = %v, expected %v for roles %v", tt.checkRole, has, tt.shouldHave, tt.roles) } }) } } // TestAuthAdapterNilAuthenticator tests behavior with nil authenticator func TestAuthAdapterNilAuthenticator(t *testing.T) { // This is an edge case - what happens if someone passes nil? // The adapter should handle this gracefully t.Run("NewAuthenticatorAdapter with nil doesn't panic", func(t *testing.T) { defer func() { if r := recover(); r != nil { t.Errorf("NewAuthenticatorAdapter(nil) panicked: %v", r) } }() adapter := NewAuthenticatorAdapter(nil) if adapter == nil { t.Error("Expected non-nil adapter") } }) } // TestConcurrentAuthentication tests thread safety func TestConcurrentAuthentication(t *testing.T) { config := auth.DefaultAuthConfig() config.JWTSecret = []byte("test-secret-key-for-jwt-signing!!") config.SecurityEnabled = true authenticator, _ := auth.NewAuthenticator(config) authenticator.CreateUser("testuser", "testpass", []auth.Role{auth.RoleEditor}) adapter := NewAuthenticatorAdapter(authenticator) // Generate a token for concurrent testing token, _ := authenticator.GenerateClusterToken("concurrent-node", auth.RoleAdmin) t.Run("concurrent basic auth", func(t *testing.T) { done := make(chan bool, 100) for i := 0; i < 100; i++ { go func() { result, err := adapter.Authenticate("basic", "testuser", "testpass") if err != nil { t.Errorf("Concurrent auth failed: %v", err) } if !result.Authenticated { t.Error("Expected authenticated") } done <- true }() } // Wait for all goroutines for i := 0; i < 100; i++ { <-done } }) t.Run("concurrent bearer auth", func(t *testing.T) { done := make(chan bool, 100) for i := 0; i < 100; i++ { go func() { result, err := adapter.Authenticate("bearer", "", token) if err != nil { t.Errorf("Concurrent bearer auth failed: %v", err) } if !result.Authenticated { t.Error("Expected authenticated") } done <- true }() } // Wait for all goroutines for i := 0; i < 100; i++ { <-done } }) t.Run("concurrent SetAllowAnonymous toggle", func(t *testing.T) { done := make(chan bool, 100) for i := 0; i < 100; i++ { go func(idx int) { adapter.SetAllowAnonymous(idx%2 == 0) done <- true }(i) } // Wait for all goroutines for i := 0; i < 100; i++ { <-done } }) }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/orneryd/Mimir'

If you have feedback or need assistance with the MCP directory API, please join our Discord server