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
|
### Configuration Architecture
|
||||||
|
|
||||||
The system uses feature toggles extensively (`types/Config:271-276`):
|
The system uses feature toggles extensively (`types/Config:271-280`):
|
||||||
```yaml
|
```yaml
|
||||||
auth_enabled: true # JWT authentication system
|
auth_enabled: true # JWT authentication system
|
||||||
tamper_logging_enabled: true # Cryptographic audit trail
|
tamper_logging_enabled: true # Cryptographic audit trail
|
||||||
clustering_enabled: true # Gossip protocol and sync
|
clustering_enabled: true # Gossip protocol and sync
|
||||||
rate_limiting_enabled: true # Per-client rate limiting
|
rate_limiting_enabled: true # Per-client rate limiting
|
||||||
revision_history_enabled: true # Automatic versioning
|
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
|
### Testing Strategy
|
||||||
|
|
||||||
#### Integration Test Suite (`integration_test.sh`)
|
#### Integration Test Suite (`integration_test.sh`)
|
||||||
@@ -115,6 +121,11 @@ revision_history_enabled: true # Automatic versioning
|
|||||||
- **Basic functionality** - Single-node CRUD operations
|
- **Basic functionality** - Single-node CRUD operations
|
||||||
- **Cluster formation** - 2-node gossip protocol and data replication
|
- **Cluster formation** - 2-node gossip protocol and data replication
|
||||||
- **Conflict resolution** - Automated conflict detection and resolution using `test_conflict.go`
|
- **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.
|
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
|
rate_limiting_enabled: true # Rate limiting
|
||||||
revision_history_enabled: true # Automatic versioning
|
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 configuration
|
||||||
backup_enabled: true # Automated backups
|
backup_enabled: true # Automated backups
|
||||||
backup_schedule: "0 0 * * *" # Daily at midnight (cron format)
|
backup_schedule: "0 0 * * *" # Daily at midnight (cron format)
|
||||||
@@ -134,7 +138,7 @@ backup_retention: 7 # Days to keep backups
|
|||||||
```bash
|
```bash
|
||||||
PUT /kv/{path}
|
PUT /kv/{path}
|
||||||
Content-Type: application/json
|
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
|
# Basic storage
|
||||||
curl -X PUT http://localhost:8080/kv/users/john/profile \
|
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
|
#### Retrieve Data
|
||||||
```bash
|
```bash
|
||||||
GET /kv/{path}
|
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
|
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
|
#### Delete Data
|
||||||
```bash
|
```bash
|
||||||
DELETE /kv/{path}
|
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
|
curl -X DELETE -H "Authorization: Bearer eyJ..." http://localhost:8080/kv/users/john/profile
|
||||||
# Returns: 204 No Content
|
# 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 |
|
| `bootstrap_max_age_hours` | Max historical data to sync | 720 hours | 30 days default |
|
||||||
| **Feature Toggles** |
|
| **Feature Toggles** |
|
||||||
| `auth_enabled` | JWT authentication system | true | Complete auth/authz system |
|
| `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 |
|
| `clustering_enabled` | Gossip protocol and sync | true | Distributed mode |
|
||||||
| `compression_enabled` | ZSTD compression | true | Reduces storage size |
|
| `compression_enabled` | ZSTD compression | true | Reduces storage size |
|
||||||
| `rate_limiting_enabled` | Rate limiting | true | Per-client limits |
|
| `rate_limiting_enabled` | Rate limiting | true | Per-client limits |
|
||||||
|
@@ -361,6 +361,79 @@ EOF
|
|||||||
fi
|
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 test execution
|
||||||
main() {
|
main() {
|
||||||
echo "=================================================="
|
echo "=================================================="
|
||||||
@@ -378,6 +451,7 @@ main() {
|
|||||||
test_basic_functionality
|
test_basic_functionality
|
||||||
test_cluster_formation
|
test_cluster_formation
|
||||||
test_conflict_resolution
|
test_conflict_resolution
|
||||||
|
test_authentication_middleware
|
||||||
|
|
||||||
# Results
|
# Results
|
||||||
echo "=================================================="
|
echo "=================================================="
|
||||||
|
Reference in New Issue
Block a user