forked from ryyst/kalzu-value-store
		
	test: add comprehensive authentication middleware test (issue #4)
- Add Test 5 to integration_test.sh for authentication verification - Test admin endpoints reject unauthorized requests properly - Test admin endpoints work with valid JWT tokens - Test KV endpoints respect anonymous access configuration - Extract and use auto-generated root account tokens docs: update README and CLAUDE.md for recent security features - Document allow_anonymous_read and allow_anonymous_write config options - Update API documentation with authentication requirements - Add security notes about DELETE operations always requiring auth - Update configuration table with new anonymous access settings - Document new authentication test coverage in CLAUDE.md 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
		
							
								
								
									
										13
									
								
								CLAUDE.md
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								CLAUDE.md
									
									
									
									
									
								
							@@ -99,15 +99,21 @@ type StoredValue struct {
 | 
			
		||||
 | 
			
		||||
### Configuration Architecture
 | 
			
		||||
 | 
			
		||||
The system uses feature toggles extensively (`types/Config:271-276`):
 | 
			
		||||
The system uses feature toggles extensively (`types/Config:271-280`):
 | 
			
		||||
```yaml
 | 
			
		||||
auth_enabled: true              # JWT authentication system
 | 
			
		||||
tamper_logging_enabled: true    # Cryptographic audit trail  
 | 
			
		||||
clustering_enabled: true        # Gossip protocol and sync
 | 
			
		||||
rate_limiting_enabled: true     # Per-client rate limiting
 | 
			
		||||
revision_history_enabled: true  # Automatic versioning
 | 
			
		||||
 | 
			
		||||
# Anonymous access control (Issue #5 - when auth_enabled: true)
 | 
			
		||||
allow_anonymous_read: false     # Allow unauthenticated read access to KV endpoints
 | 
			
		||||
allow_anonymous_write: false    # Allow unauthenticated write access to KV endpoints
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
**Security Note**: DELETE operations always require authentication when `auth_enabled: true`, regardless of anonymous access settings.
 | 
			
		||||
 | 
			
		||||
### Testing Strategy
 | 
			
		||||
 | 
			
		||||
#### Integration Test Suite (`integration_test.sh`)
 | 
			
		||||
@@ -115,6 +121,11 @@ revision_history_enabled: true  # Automatic versioning
 | 
			
		||||
- **Basic functionality** - Single-node CRUD operations  
 | 
			
		||||
- **Cluster formation** - 2-node gossip protocol and data replication
 | 
			
		||||
- **Conflict resolution** - Automated conflict detection and resolution using `test_conflict.go`
 | 
			
		||||
- **Authentication middleware** - Comprehensive security testing (Issue #4):
 | 
			
		||||
  - Admin endpoints properly reject unauthenticated requests
 | 
			
		||||
  - Admin endpoints work with valid JWT tokens
 | 
			
		||||
  - KV endpoints respect anonymous access configuration
 | 
			
		||||
  - Automatic root account creation and token extraction
 | 
			
		||||
 | 
			
		||||
The test suite uses sophisticated retry logic and timing to handle the eventually consistent nature of the system.
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										12
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								README.md
									
									
									
									
									
								
							@@ -113,6 +113,10 @@ clustering_enabled: true               # Gossip protocol and sync
 | 
			
		||||
rate_limiting_enabled: true            # Rate limiting
 | 
			
		||||
revision_history_enabled: true         # Automatic versioning
 | 
			
		||||
 | 
			
		||||
# Anonymous access control (when auth_enabled: true)
 | 
			
		||||
allow_anonymous_read: false            # Allow unauthenticated read access to KV endpoints
 | 
			
		||||
allow_anonymous_write: false           # Allow unauthenticated write access to KV endpoints
 | 
			
		||||
 | 
			
		||||
# Backup configuration
 | 
			
		||||
backup_enabled: true                   # Automated backups
 | 
			
		||||
backup_schedule: "0 0 * * *"           # Daily at midnight (cron format)
 | 
			
		||||
@@ -134,7 +138,7 @@ backup_retention: 7                    # Days to keep backups
 | 
			
		||||
```bash
 | 
			
		||||
PUT /kv/{path}
 | 
			
		||||
Content-Type: application/json
 | 
			
		||||
Authorization: Bearer <jwt-token>  # Required if auth_enabled
 | 
			
		||||
Authorization: Bearer <jwt-token>  # Required if auth_enabled && !allow_anonymous_write
 | 
			
		||||
 | 
			
		||||
# Basic storage
 | 
			
		||||
curl -X PUT http://localhost:8080/kv/users/john/profile \
 | 
			
		||||
@@ -158,7 +162,7 @@ curl -X PUT http://localhost:8080/kv/cache/session/abc123 \
 | 
			
		||||
#### Retrieve Data
 | 
			
		||||
```bash
 | 
			
		||||
GET /kv/{path}
 | 
			
		||||
Authorization: Bearer <jwt-token>  # Required if auth_enabled
 | 
			
		||||
Authorization: Bearer <jwt-token>  # Required if auth_enabled && !allow_anonymous_read
 | 
			
		||||
 | 
			
		||||
curl -H "Authorization: Bearer eyJ..." http://localhost:8080/kv/users/john/profile
 | 
			
		||||
 | 
			
		||||
@@ -177,7 +181,7 @@ curl -H "Authorization: Bearer eyJ..." http://localhost:8080/kv/users/john/profi
 | 
			
		||||
#### Delete Data
 | 
			
		||||
```bash
 | 
			
		||||
DELETE /kv/{path}
 | 
			
		||||
Authorization: Bearer <jwt-token>  # Required if auth_enabled
 | 
			
		||||
Authorization: Bearer <jwt-token>  # Always required when auth_enabled (no anonymous delete)
 | 
			
		||||
 | 
			
		||||
curl -X DELETE -H "Authorization: Bearer eyJ..." http://localhost:8080/kv/users/john/profile
 | 
			
		||||
# Returns: 204 No Content
 | 
			
		||||
@@ -532,6 +536,8 @@ type StoredValue struct {
 | 
			
		||||
| `bootstrap_max_age_hours` | Max historical data to sync | 720 hours | 30 days default |
 | 
			
		||||
| **Feature Toggles** |
 | 
			
		||||
| `auth_enabled` | JWT authentication system | true | Complete auth/authz system |
 | 
			
		||||
| `allow_anonymous_read` | Allow unauthenticated read access | false | When auth_enabled, controls KV GET endpoints |
 | 
			
		||||
| `allow_anonymous_write` | Allow unauthenticated write access | false | When auth_enabled, controls KV PUT endpoints |
 | 
			
		||||
| `clustering_enabled` | Gossip protocol and sync | true | Distributed mode |
 | 
			
		||||
| `compression_enabled` | ZSTD compression | true | Reduces storage size |
 | 
			
		||||
| `rate_limiting_enabled` | Rate limiting | true | Per-client limits |
 | 
			
		||||
 
 | 
			
		||||
@@ -361,6 +361,79 @@ EOF
 | 
			
		||||
    fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Test 5: Authentication middleware (Issue #4)
 | 
			
		||||
test_authentication_middleware() {
 | 
			
		||||
    test_start "Authentication middleware test (Issue #4)"
 | 
			
		||||
    
 | 
			
		||||
    # Create auth test config
 | 
			
		||||
    cat > auth_test.yaml <<EOF
 | 
			
		||||
node_id: "auth-test"
 | 
			
		||||
bind_address: "127.0.0.1"
 | 
			
		||||
port: 8095
 | 
			
		||||
data_dir: "./auth_test_data"
 | 
			
		||||
seed_nodes: []
 | 
			
		||||
log_level: "error"
 | 
			
		||||
auth_enabled: true
 | 
			
		||||
allow_anonymous_read: false
 | 
			
		||||
allow_anonymous_write: false
 | 
			
		||||
EOF
 | 
			
		||||
    
 | 
			
		||||
    # Start node
 | 
			
		||||
    $BINARY auth_test.yaml >auth_test.log 2>&1 &
 | 
			
		||||
    local pid=$!
 | 
			
		||||
    
 | 
			
		||||
    if wait_for_service 8095; then
 | 
			
		||||
        sleep 2  # Allow root account creation
 | 
			
		||||
        
 | 
			
		||||
        # Extract the token from logs
 | 
			
		||||
        local token=$(grep "Token:" auth_test.log | sed 's/.*Token: //' | tr -d '\n\r')
 | 
			
		||||
        
 | 
			
		||||
        if [ -z "$token" ]; then
 | 
			
		||||
            log_error "Failed to extract authentication token from logs"
 | 
			
		||||
            kill $pid 2>/dev/null || true
 | 
			
		||||
            return
 | 
			
		||||
        fi
 | 
			
		||||
        
 | 
			
		||||
        # Test 1: Admin endpoints should fail without authentication
 | 
			
		||||
        local no_auth_response=$(curl -s -X POST http://localhost:8095/api/users -H "Content-Type: application/json" -d '{"nickname":"test","password":"test"}')
 | 
			
		||||
        if echo "$no_auth_response" | grep -q "Unauthorized"; then
 | 
			
		||||
            log_success "Admin endpoints properly reject unauthenticated requests"
 | 
			
		||||
        else
 | 
			
		||||
            log_error "Admin endpoints should reject unauthenticated requests, got: $no_auth_response"
 | 
			
		||||
        fi
 | 
			
		||||
        
 | 
			
		||||
        # Test 2: Admin endpoints should work with valid authentication
 | 
			
		||||
        local auth_response=$(curl -s -X POST http://localhost:8095/api/users -H "Content-Type: application/json" -H "Authorization: Bearer $token" -d '{"nickname":"authtest","password":"authtest"}')
 | 
			
		||||
        if echo "$auth_response" | grep -q "uuid"; then
 | 
			
		||||
            log_success "Admin endpoints work with valid authentication"
 | 
			
		||||
        else
 | 
			
		||||
            log_error "Admin endpoints should work with authentication, got: $auth_response"
 | 
			
		||||
        fi
 | 
			
		||||
        
 | 
			
		||||
        # Test 3: KV endpoints should require auth when anonymous access is disabled
 | 
			
		||||
        local kv_no_auth=$(curl -s -X PUT http://localhost:8095/kv/test/auth -H "Content-Type: application/json" -d '{"test":"auth"}')
 | 
			
		||||
        if echo "$kv_no_auth" | grep -q "Unauthorized"; then
 | 
			
		||||
            log_success "KV endpoints properly require authentication when anonymous access disabled"
 | 
			
		||||
        else
 | 
			
		||||
            log_error "KV endpoints should require auth when anonymous access disabled, got: $kv_no_auth"
 | 
			
		||||
        fi
 | 
			
		||||
        
 | 
			
		||||
        # Test 4: KV endpoints should work with valid authentication
 | 
			
		||||
        local kv_auth=$(curl -s -X PUT http://localhost:8095/kv/test/auth -H "Content-Type: application/json" -H "Authorization: Bearer $token" -d '{"test":"auth"}')
 | 
			
		||||
        if echo "$kv_auth" | grep -q "uuid\|timestamp" || [ -z "$kv_auth" ]; then
 | 
			
		||||
            log_success "KV endpoints work with valid authentication"
 | 
			
		||||
        else
 | 
			
		||||
            log_error "KV endpoints should work with authentication, got: $kv_auth"
 | 
			
		||||
        fi
 | 
			
		||||
        
 | 
			
		||||
        kill $pid 2>/dev/null || true
 | 
			
		||||
        sleep 2
 | 
			
		||||
    else
 | 
			
		||||
        log_error "Auth test node failed to start"
 | 
			
		||||
        kill $pid 2>/dev/null || true
 | 
			
		||||
    fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Main test execution
 | 
			
		||||
main() {
 | 
			
		||||
    echo "=================================================="
 | 
			
		||||
@@ -378,6 +451,7 @@ main() {
 | 
			
		||||
    test_basic_functionality
 | 
			
		||||
    test_cluster_formation
 | 
			
		||||
    test_conflict_resolution
 | 
			
		||||
    test_authentication_middleware
 | 
			
		||||
    
 | 
			
		||||
    # Results
 | 
			
		||||
    echo "=================================================="
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user