forked from ryyst/kalzu-value-store
		
	feat: add anonymous access configuration for KV endpoints (issue #5)
- Add AllowAnonymousRead and AllowAnonymousWrite config parameters - Set both to false by default for security - Apply conditional authentication middleware to KV endpoints: - GET requires auth if AllowAnonymousRead is false - PUT requires auth if AllowAnonymousWrite is false - DELETE always requires authentication (no anonymous delete) - Update integration tests to enable anonymous access for testing - Maintain backward compatibility when AuthEnabled is false 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
		@@ -55,6 +55,10 @@ func Default() *types.Config {
 | 
			
		||||
		ClusteringEnabled:      true,
 | 
			
		||||
		RateLimitingEnabled:    true,
 | 
			
		||||
		RevisionHistoryEnabled: true,
 | 
			
		||||
		
 | 
			
		||||
		// Default anonymous access settings (both disabled by default for security)
 | 
			
		||||
		AllowAnonymousRead:     false,
 | 
			
		||||
		AllowAnonymousWrite:    false,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -91,6 +91,8 @@ port: 8090
 | 
			
		||||
data_dir: "./basic_data"
 | 
			
		||||
seed_nodes: []
 | 
			
		||||
log_level: "error"
 | 
			
		||||
allow_anonymous_read: true
 | 
			
		||||
allow_anonymous_write: true
 | 
			
		||||
EOF
 | 
			
		||||
    
 | 
			
		||||
    # Start node
 | 
			
		||||
@@ -134,6 +136,8 @@ log_level: "error"
 | 
			
		||||
gossip_interval_min: 5
 | 
			
		||||
gossip_interval_max: 10
 | 
			
		||||
sync_interval: 10
 | 
			
		||||
allow_anonymous_read: true
 | 
			
		||||
allow_anonymous_write: true
 | 
			
		||||
EOF
 | 
			
		||||
    
 | 
			
		||||
    # Node 2 config
 | 
			
		||||
@@ -147,6 +151,8 @@ log_level: "error"
 | 
			
		||||
gossip_interval_min: 5
 | 
			
		||||
gossip_interval_max: 10
 | 
			
		||||
sync_interval: 10
 | 
			
		||||
allow_anonymous_read: true
 | 
			
		||||
allow_anonymous_write: true
 | 
			
		||||
EOF
 | 
			
		||||
    
 | 
			
		||||
    # Start nodes
 | 
			
		||||
@@ -242,6 +248,8 @@ data_dir: "./conflict1_data"
 | 
			
		||||
seed_nodes: []
 | 
			
		||||
log_level: "info"
 | 
			
		||||
sync_interval: 3
 | 
			
		||||
allow_anonymous_read: true
 | 
			
		||||
allow_anonymous_write: true
 | 
			
		||||
EOF
 | 
			
		||||
        
 | 
			
		||||
        cat > conflict2.yaml <<EOF
 | 
			
		||||
@@ -252,6 +260,8 @@ data_dir: "./conflict2_data"
 | 
			
		||||
seed_nodes: ["127.0.0.1:8111"]
 | 
			
		||||
log_level: "info"
 | 
			
		||||
sync_interval: 3
 | 
			
		||||
allow_anonymous_read: true
 | 
			
		||||
allow_anonymous_write: true
 | 
			
		||||
EOF
 | 
			
		||||
        
 | 
			
		||||
        # Start nodes
 | 
			
		||||
 
 | 
			
		||||
@@ -11,10 +11,33 @@ func (s *Server) setupRoutes() *mux.Router {
 | 
			
		||||
	// Health endpoint (always available)
 | 
			
		||||
	router.HandleFunc("/health", s.healthHandler).Methods("GET")
 | 
			
		||||
 | 
			
		||||
	// KV endpoints (always available - see issue #5 for anonymous access control)
 | 
			
		||||
	router.HandleFunc("/kv/{path:.+}", s.getKVHandler).Methods("GET")
 | 
			
		||||
	router.HandleFunc("/kv/{path:.+}", s.putKVHandler).Methods("PUT")
 | 
			
		||||
	router.HandleFunc("/kv/{path:.+}", s.deleteKVHandler).Methods("DELETE")
 | 
			
		||||
	// KV endpoints (with conditional authentication based on anonymous access settings)
 | 
			
		||||
	// GET endpoint - require auth if anonymous read is disabled
 | 
			
		||||
	if s.config.AuthEnabled && !s.config.AllowAnonymousRead {
 | 
			
		||||
		router.Handle("/kv/{path:.+}", s.authService.Middleware(
 | 
			
		||||
			[]string{"read"}, nil, "",
 | 
			
		||||
		)(s.getKVHandler)).Methods("GET")
 | 
			
		||||
	} else {
 | 
			
		||||
		router.HandleFunc("/kv/{path:.+}", s.getKVHandler).Methods("GET")
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	// PUT endpoint - require auth if anonymous write is disabled
 | 
			
		||||
	if s.config.AuthEnabled && !s.config.AllowAnonymousWrite {
 | 
			
		||||
		router.Handle("/kv/{path:.+}", s.authService.Middleware(
 | 
			
		||||
			[]string{"write"}, nil, "",
 | 
			
		||||
		)(s.putKVHandler)).Methods("PUT")
 | 
			
		||||
	} else {
 | 
			
		||||
		router.HandleFunc("/kv/{path:.+}", s.putKVHandler).Methods("PUT")
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	// DELETE endpoint - always require authentication (no anonymous delete)
 | 
			
		||||
	if s.config.AuthEnabled {
 | 
			
		||||
		router.Handle("/kv/{path:.+}", s.authService.Middleware(
 | 
			
		||||
			[]string{"delete"}, nil, "",
 | 
			
		||||
		)(s.deleteKVHandler)).Methods("DELETE")
 | 
			
		||||
	} else {
 | 
			
		||||
		router.HandleFunc("/kv/{path:.+}", s.deleteKVHandler).Methods("DELETE")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Member endpoints (available when clustering is enabled)
 | 
			
		||||
	if s.config.ClusteringEnabled {
 | 
			
		||||
 
 | 
			
		||||
@@ -273,4 +273,8 @@ type Config struct {
 | 
			
		||||
	ClusteringEnabled      bool `yaml:"clustering_enabled"`       // Enable/disable clustering/gossip
 | 
			
		||||
	RateLimitingEnabled    bool `yaml:"rate_limiting_enabled"`    // Enable/disable rate limiting
 | 
			
		||||
	RevisionHistoryEnabled bool `yaml:"revision_history_enabled"` // Enable/disable revision history
 | 
			
		||||
	
 | 
			
		||||
	// Anonymous access control (Issue #5)
 | 
			
		||||
	AllowAnonymousRead     bool `yaml:"allow_anonymous_read"`     // Allow unauthenticated read access to KV endpoints
 | 
			
		||||
	AllowAnonymousWrite    bool `yaml:"allow_anonymous_write"`    // Allow unauthenticated write access to KV endpoints
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user