diff --git a/docs/HORIZONTAL_SCALABILITY.md b/docs/HORIZONTAL_SCALABILITY.md deleted file mode 100644 index 3e9dd5e..0000000 --- a/docs/HORIZONTAL_SCALABILITY.md +++ /dev/null @@ -1,506 +0,0 @@ -# Horizontal Scalability Implementation - -## Overview - -Your authorization microservice is now **fully horizontally scalable** using Redis-based distributed caching. Multiple instances can run concurrently with shared state across all nodes. - -## Implementation Summary - -### What Was Changed - -#### 1. Distributed Caching (`services/cached_authorization.go`) - -- **Permission Cache**: Moved from local `sync.RWMutex` maps to Redis with key pattern `authz:perm:resource:action` -- **Policy Cache**: Stored in Redis with key pattern `authz:policy:permissionID` -- **User Attributes Cache**: Stored in Redis with key pattern `authz:userattr:userID` -- **Cache TTL**: 30 seconds for automatic expiration -- **Fallback Strategy**: Local cache maintained for backward compatibility and resilience - -#### 2. Cache Architecture - -```text -┌─────────────┐ ┌─────────────┐ ┌─────────────┐ -│ Instance 1 │ │ Instance 2 │ │ Instance 3 │ -└──────┬──────┘ └──────┬──────┘ └──────┬──────┘ - │ │ │ - └───────────────────┼───────────────────┘ - │ - ┌──────▼──────┐ - │ Redis │ - │ (Distributed)│ - │ Cache │ - └─────────────┘ - │ - ┌──────▼──────┐ - │ PostgreSQL │ - │ (Database) │ - └─────────────┘ -``` - -#### 3. Key Features - -#### Dual-Layer Caching - -- Primary: Redis (distributed, shared across instances) -- Secondary: Local in-memory (failover, performance boost) -- Automatic fallback when Redis unavailable - -#### Consistency Guarantees - -- All instances share the same Redis cache -- 30-second automatic cache refresh -- Manual invalidation via `InvalidateUserCache()` -- Force refresh via `RefreshCacheNow()` - -#### Performance Optimizations - -- JSON serialization for complex objects -- 100ms timeout for Redis operations -- Non-blocking Redis writes -- Concurrent-safe operations - -## Deployment Patterns - -### Kubernetes Deployment - -```yaml -apiVersion: apps/v1 -kind: Deployment -metadata: - name: authorization-service -spec: - replicas: 5 # Scale as needed - selector: - matchLabels: - app: authorization - template: - metadata: - labels: - app: authorization - spec: - containers: - - name: authorization - image: your-registry/authorization:latest - env: - - name: REDIS_HOST - value: "redis-cluster.default.svc.cluster.local" - - name: REDIS_PORT - value: "6379" - - name: REDIS_PASSWORD - valueFrom: - secretKeyRef: - name: redis-secret - key: password - - name: DB_HOST - value: "postgres.default.svc.cluster.local" - - name: DB_PORT - value: "5432" - resources: - requests: - memory: "256Mi" - cpu: "250m" - limits: - memory: "512Mi" - cpu: "500m" ---- -apiVersion: v1 -kind: Service -metadata: - name: authorization-service -spec: - type: LoadBalancer - selector: - app: authorization - ports: - - port: 80 - targetPort: 8080 -``` - -### Docker Compose - -```yaml -version: "3.8" - -services: - authorization-1: - image: authorization:latest - environment: - - REDIS_HOST=redis - - REDIS_PORT=6379 - - DB_HOST=postgres - - DB_PORT=5432 - depends_on: - - redis - - postgres - - authorization-2: - image: authorization:latest - environment: - - REDIS_HOST=redis - - REDIS_PORT=6379 - - DB_HOST=postgres - - DB_PORT=5432 - depends_on: - - redis - - postgres - - authorization-3: - image: authorization:latest - environment: - - REDIS_HOST=redis - - REDIS_PORT=6379 - - DB_HOST=postgres - - DB_PORT=5432 - depends_on: - - redis - - postgres - - redis: - image: redis:7-alpine - command: redis-server --requirepass yourpassword - ports: - - "6379:6379" - - postgres: - image: postgres:15-alpine - environment: - POSTGRES_DB: authorization - POSTGRES_USER: authuser - POSTGRES_PASSWORD: authpass - ports: - - "5432:5432" - - load-balancer: - image: nginx:alpine - ports: - - "80:80" - volumes: - - ./nginx.conf:/etc/nginx/nginx.conf:ro - depends_on: - - authorization-1 - - authorization-2 - - authorization-3 -``` - -### Nginx Load Balancer Config - -```nginx -upstream authorization { - least_conn; - server authorization-1:8080; - server authorization-2:8080; - server authorization-3:8080; -} - -server { - listen 80; - - location / { - proxy_pass http://authorization; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - } -} -``` - -## Redis Configuration - -### Production Redis Setup - -```bash -# redis.conf for production -maxmemory 2gb -maxmemory-policy allkeys-lru -requirepass your_strong_password_here -timeout 300 -tcp-keepalive 60 - -# Persistence (optional) -save 900 1 -save 300 10 -save 60 10000 -appendonly yes -appendfsync everysec -``` - -### Redis Cluster (High Availability) - -For production, consider Redis Cluster or Sentinel: - -```yaml -# Redis Cluster -apiVersion: v1 -kind: ConfigMap -metadata: - name: redis-cluster-config -data: - redis.conf: | - cluster-enabled yes - cluster-config-file nodes.conf - cluster-node-timeout 5000 - appendonly yes - maxmemory 2gb - maxmemory-policy allkeys-lru -``` - -## Monitoring and Observability - -### Key Metrics to Track - -1. **Cache Hit Rate** - - - Monitor via `GetCacheStats()` endpoint - - Target: >95% hit rate for permissions - - Alert if drops below 90% - -2. **Redis Availability** - - - Monitor `distributed_cache` and `redis_available` fields - - Alert if Redis becomes unavailable - - System continues working (fail-open) but performance degrades - -3. **Authorization Latency** - - - Target: <50ms per authorization check - - Logs "WARN: Slow cached authorization" if exceeds threshold - - Track P50, P95, P99 latencies - -4. **Instance Count** - - Monitor number of active instances - - Scale based on request rate - - Recommendation: 1 instance per 1000 req/s - -### Prometheus Metrics (Recommended) - -```go -// Add to your code -var ( - cacheHits = prometheus.NewCounterVec( - prometheus.CounterOpts{ - Name: "authz_cache_hits_total", - Help: "Total number of cache hits", - }, - []string{"cache_type"}, - ) - - cacheMisses = prometheus.NewCounterVec( - prometheus.CounterOpts{ - Name: "authz_cache_misses_total", - Help: "Total number of cache misses", - }, - []string{"cache_type"}, - ) - - authzLatency = prometheus.NewHistogram( - prometheus.HistogramOpts{ - Name: "authz_check_duration_seconds", - Help: "Authorization check latency", - Buckets: []float64{.001, .005, .01, .025, .05, .1, .25, .5, 1}, - }, - ) -) -``` - -## Performance Characteristics - -### Throughput - -| Setup | Instances | Expected RPS | Latency (P95) | -| --------------- | --------- | ------------ | ------------- | -| Single Instance | 1 | ~2,000 | <10ms | -| Small Cluster | 3 | ~6,000 | <15ms | -| Medium Cluster | 5 | ~10,000 | <20ms | -| Large Cluster | 10+ | ~20,000+ | <25ms | - -> **Note:** Assumes Redis on same network, PostgreSQL optimized - -### Cache Effectiveness - -- **Permission Cache**: 99%+ hit rate (permissions rarely change) -- **Policy Cache**: 99%+ hit rate (policies rarely change) -- **User Attributes Cache**: 85-95% hit rate (depends on user count) - -### Resource Requirements (Per Instance) - -- **Memory**: 256MB base + (1KB × cached_users) -- **CPU**: 0.1 core idle, 0.5 core at 1000 req/s -- **Network**: Minimal (<1MB/s per 1000 req/s) -- **Redis Memory**: ~10KB per user + ~100KB for permissions/policies - -## Scaling Guidelines - -### When to Scale Up - -1. **CPU utilization** consistently >70% -2. **Authorization latency** P95 >50ms -3. **Request rate** exceeds 2000 req/s per instance -4. **Memory usage** approaches 80% of limit - -### When to Scale Down - -1. **CPU utilization** consistently <20% -2. **Request rate** <500 req/s per instance -3. Cost optimization during off-peak hours - -### Auto-scaling Rules (Kubernetes HPA) - -```yaml -apiVersion: autoscaling/v2 -kind: HorizontalPodAutoscaler -metadata: - name: authorization-hpa -spec: - scaleTargetRef: - apiVersion: apps/v1 - kind: Deployment - name: authorization-service - minReplicas: 2 - maxReplicas: 10 - metrics: - - type: Resource - resource: - name: cpu - target: - type: Utilization - averageUtilization: 70 - - type: Resource - resource: - name: memory - target: - type: Utilization - averageUtilization: 80 - behavior: - scaleUp: - stabilizationWindowSeconds: 60 - policies: - - type: Percent - value: 50 - periodSeconds: 60 - scaleDown: - stabilizationWindowSeconds: 300 - policies: - - type: Percent - value: 25 - periodSeconds: 60 -``` - -## Testing Horizontal Scalability - -### Load Test with Multiple Instances - -```bash -# Start 3 instances locally -docker-compose up -d --scale authorization=3 - -# Run load test -ab -n 10000 -c 100 http://localhost/v1/auth/check - -# Monitor cache consistency -watch -n 1 'curl -s http://localhost/v1/cache/stats | jq' -``` - -### Verify Cache Consistency - -```bash -#!/bin/bash -# Test cache synchronization across instances - -INSTANCES=("http://instance1:8080" "http://instance2:8080" "http://instance3:8080") - -# Trigger cache refresh on instance 1 -curl -X POST ${INSTANCES[0]}/v1/admin/refresh-cache - -# Wait for sync -sleep 2 - -# Check all instances have same data -for instance in "${INSTANCES[@]}"; do - echo "=== $instance ===" - curl -s $instance/v1/cache/stats | jq '.permissions_cached, .last_refresh' -done -``` - -## Rollback Plan - -If issues occur, you can temporarily disable Redis: - -1. **Remove Redis environment variables**: - - ```bash - unset REDIS_HOST - unset REDIS_PASSWORD - ``` - -2. **Service automatically falls back** to local cache -3. **No code changes required** - graceful degradation -4. **Authorization still works**, but instances are independent - -## Migration Checklist - -- [ ] Redis deployed and accessible -- [ ] Redis password configured -- [ ] Environment variables set (REDIS_HOST, REDIS_PORT, REDIS_PASSWORD) -- [ ] All instances can connect to Redis -- [ ] Load balancer configured -- [ ] Health checks passing (`/health`, `/ready`) -- [ ] Monitoring configured -- [ ] Load testing completed -- [ ] Cache hit rate verified (>90%) -- [ ] Latency within acceptable range (<50ms P95) -- [ ] Rollback plan documented and tested - -## Troubleshooting - -### Issue: High Latency After Scaling - -**Cause**: Redis network latency or insufficient resources - -**Solution**: - -```bash -# Check Redis latency -redis-cli --latency -h redis-host -p 6379 - -# If high, check Redis resources -redis-cli INFO stats | grep -E "instantaneous_ops_per_sec|used_memory" -``` - -### Issue: Cache Misses on New Instances - -**Cause**: New instances start with empty local cache - -**Solution**: - -- Expected behavior, Redis cache is populated -- Local cache fills on first requests -- Monitor first 30 seconds after scaling - -### Issue: Redis Connection Failures - -**Cause**: Network issues, Redis overloaded, or password mismatch - -**Solution**: - -```bash -# Test Redis connectivity -redis-cli -h $REDIS_HOST -p $REDIS_PORT -a $REDIS_PASSWORD PING - -# Check service logs -kubectl logs -f deployment/authorization-service - -# Look for: "ERROR: Rate limiter: Redis not available" -``` - -## Summary - -Your authorization microservice now supports: - -✅ **Unlimited horizontal scaling** - Add instances without code changes -✅ **Shared cache state** - All instances see the same data -✅ **High availability** - Continues working if Redis fails -✅ **Low latency** - <50ms P95 authorization checks -✅ **Cost-effective** - Scale up/down based on demand -✅ **Production-ready** - Tested, monitored, and documented - -**Next Steps**: Deploy to production and configure auto-scaling based on your traffic patterns. diff --git a/docs/IMPLEMENTATION_SUMMARY.md b/docs/IMPLEMENTATION_SUMMARY.md deleted file mode 100644 index 9194863..0000000 --- a/docs/IMPLEMENTATION_SUMMARY.md +++ /dev/null @@ -1,290 +0,0 @@ -# RBAC + ABAC Implementation Summary - -## ✅ What Was Built - -A complete **Role-Based Access Control (RBAC)** and **Attribute-Based Access Control (ABAC)** authorization system with: - -### Core Components - -1. **Data Models** (`models/rbac.go`) - - - Permission, PolicyAttribute, UserAttribute, User - - AuthorizationContext, AuthorizationResult - -2. **Database Repository** (`repository/permission_repository.go`) - - - Permission lookup by resource + action - - Policy attributes retrieval - - User attributes retrieval - - Batch operations for caching - -3. **Policy Evaluator** (`services/policy_evaluator.go`) - - - ABAC policy evaluation engine - - 10 comparison operators (=, !=, >, <, >=, <=, IN, CONTAINS, etc.) - - Variable substitution (${resource.region}) - - Attribute validation - -4. **Authorization Service** (`services/authorize.go`) - - - Main authorization logic - - Integrates repository and evaluator - - Performance monitoring - -5. **Cached Service** (`services/cached_authorization.go`) - - - High-performance caching layer - - 5-minute cache for permissions/policies - - LRU cache for user attributes - - Background refresh - -6. **HTTP Handler** (`handlers/authorize.go`) - - REST API endpoint - - JWT integration - - Request validation - - Response formatting - -## 🎯 Key Features - -### RBAC - -- Database-driven permissions -- Resource + Action based -- 27 permissions defined - -### ABAC - -- User attributes (region, role, action_user_role, etc.) -- Resource attributes (passed in request) -- Environment attributes (time, location, etc.) -- Dynamic policy evaluation - -### Performance - -- **Without cache:** ~10-20ms per request -- **With cache:** ~0.5ms per request (200x faster) -- Cache hit rate: 98%+ -- Supports 10M+ cached tokens - -### Security - -- JWT authentication required -- User ID verification -- Audit trail ready -- Cache invalidation support - -## 📊 Database Schema - -```text -permissions (27 records) -├── id, permission_name, description -├── resource (users, cases, workload, etc.) -└── action (manage, view, encode, etc.) - -policy_attributes (16 records) -├── attribute_name (role, region, action_user_role) -├── attribute_type (user, resource, environment) -├── comparison (=, !=, IN, CONTAINS, etc.) -├── attribute_value (Admin, ${resource.region}, etc.) -└── permission_id → permissions.id - -user_attributes (14 records) -├── user_id → users.user_id -├── attribute_name (region, role, is_supervisor) -└── attribute_value (01, Admin, Y) - -users (4 records) -└── user_id, first_name, last_name, role_id, etc. -``` - -## 🔄 Authorization Flow - -```text -1. Client Request - ↓ -2. JWT Middleware (validates token) - ↓ -3. Authorization Handler - ↓ -4. Cached Authorization Service - ↓ - ├─→ [CACHE HIT] Return cached result (0.5ms) - └─→ [CACHE MISS] - ├─→ Get permission (resource + action) - ├─→ Get user attributes - ├─→ Get policy attributes - ├─→ Evaluate policies (ABAC) - ├─→ Cache result - └─→ Return decision (10-20ms) -``` - -## 🧪 Testing Examples - -### Example 1: Admin Access ✅ - -```json -POST /v1/auth/check -{ - "user_id": "U0000000001", - "resource": "users", - "action": "manage" -} -→ ALLOWED (user.role = Admin) -``` - -### Example 2: Regional Access ✅ - -```json -POST /v1/auth/check -{ - "user_id": "U0000000001", - "resource": "personnel", - "action": "assign_role", - "resource_data": {"region": "01"} -} -→ ALLOWED (user.region = resource.region) -``` - -### Example 3: Role Restriction ❌ - -```json -POST /v1/auth/check -{ - "user_id": "U0000000002", - "resource": "cases", - "action": "verify" -} -→ DENIED (Data Collector cannot verify) -``` - -### Example 4: Role Inclusion ✅ - -```json -POST /v1/auth/check -{ - "user_id": "U0000000003", - "resource": "data_processing", - "action": "certify" -} -→ ALLOWED (Provincial Focal Person in RFP,PFP) -``` - -## 📁 Files Created/Modified - -### New Files - -- `models/rbac.go` - RBAC/ABAC data models -- `repository/permission_repository.go` - Database layer -- `services/policy_evaluator.go` - ABAC engine -- `services/authorize.go` - Authorization service -- `services/cached_authorization.go` - Caching layer -- `docs/RBAC_ABAC_README.md` - Full documentation -- `docs/test_examples.txt` - Test cases -- `docs/database_schema.sql` - Schema reference - -### Modified Files - -- `handlers/authorize.go` - Updated handler -- `main.go` - Initialize auth service - -## 🚀 Deployment Checklist - -1. ✅ Database tables exist (permissions, policy_attributes, user_attributes, users) -2. ✅ Data populated in tables -3. ✅ JWT_KEY environment variable set -4. ✅ Database credentials configured -5. ✅ Go build successful -6. ✅ Test with sample requests - -## 🔧 Configuration - -### Environment Variables - -```bash -JWT_KEY=your_secret_key_here -DB_HOST=localhost -DB_PORT=3306 -DB_USER=your_db_user -DB_PASSWORD=your_db_password -DB_NAME=your_database_name -``` - -### Cache Settings (tunable in code) - -```go -cacheExpiry: 5 * time.Minute // Permission/policy cache -userAttrLimit: 10000 // User attribute cache size -``` - -## 📈 Performance Benchmarks - -| Operation | Without Cache | With Cache | -| ----------------- | ------------- | -------------- | -| Permission lookup | 5-10ms | 0.1ms | -| Policy fetch | 3-5ms | 0.1ms | -| User attributes | 2-4ms | 0.1ms (cached) | -| **Total** | **10-20ms** | **0.5ms** | - -### Load Testing Results - -- **1000 req/sec:** Avg 0.5ms response -- **10,000 req/sec:** Avg 2ms response -- **Cache hit rate:** 98.5% -- **Memory usage:** ~50MB (10k cached users) - -## 🛡️ Security Features - -1. **JWT Required** - All endpoints protected -2. **User Verification** - Request user_id must match JWT -3. **Attribute Validation** - Type-safe attribute evaluation -4. **SQL Injection Protection** - Parameterized queries -5. **Cache Poisoning Prevention** - Atomic cache updates - -## 📝 Adding New Permissions - -```sql --- Step 1: Add permission -INSERT INTO permissions (permission_name, description, resource, action) -VALUES ('New Permission', 'Description', 'resource_name', 'action_name'); - --- Step 2: Add policies (optional) -INSERT INTO policy_attributes -(attribute_name, attribute_type, comparison, attribute_value, permission_id) -VALUES -('role', 'user', '=', 'Admin', LAST_INSERT_ID()); - --- Step 3: Wait 5 minutes or restart service for cache refresh -``` - -## 🐛 Troubleshooting - -### Issue: Permission Not Found - -**Solution:** Check permissions table, verify resource/action spelling - -### Issue: Policy Fails - -**Solution:** Verify user has required attributes in user_attributes table - -### Issue: Slow Response - -**Solution:** Check database indexes, monitor cache hit rate - -### Issue: Cache Not Refreshing - -**Solution:** Cache refreshes every 5 minutes automatically - -## 🎓 Learning Resources - -- Read `docs/RBAC_ABAC_README.md` for detailed documentation -- Check `docs/test_examples.txt` for test scenarios -- Review `docs/database_schema.sql` for schema details - -## ✨ Next Steps - -1. **Add Audit Logging** - Log all authorization decisions -2. **Add Metrics Endpoint** - Expose cache statistics -3. **Add Admin UI** - Manage permissions via web interface -4. **Add Batch Authorization** - Check multiple permissions at once -5. **Add Time-based Policies** - Environment.time policies -6. **Add IP-based Policies** - Environment.ip_address policies diff --git a/docs/QUICK_START.md b/docs/QUICK_START.md deleted file mode 100644 index 2508a06..0000000 --- a/docs/QUICK_START.md +++ /dev/null @@ -1,264 +0,0 @@ -# Quick Start Guide - RBAC + ABAC Authorization - -## 🚀 Getting Started in 5 Minutes - -### Step 1: Verify Database Setup - -Your database already has the required tables and data: - -- ✅ `permissions` (27 permissions) -- ✅ `policy_attributes` (16 policies) -- ✅ `user_attributes` (14 attributes) -- ✅ `users` (4 users) - -### Step 2: Build & Run - -```bash -cd c:\Projects\UESS\Authorization -go build -o authorization.exe -./authorization.exe -``` - -### Step 3: Test Authorization - -#### Test 1: Admin Can Manage Users ✅ - -```bash -curl -X POST http://localhost:8080/v1/auth/check \ - -H "Authorization: Bearer YOUR_JWT_TOKEN" \ - -H "Content-Type: application/json" \ - -d "{\"user_id\":\"U0000000001\",\"resource\":\"users\",\"action\":\"manage\",\"resource_data\":{}}" -``` - -**Expected Response:** - -```json -{ - "allowed": true, - "reason": "All policies satisfied", - "permission_id": 1, - "evaluated_at": "2025-12-09T...", - "matched_policies": [1] -} -``` - -#### Test 2: Regional Access Control ✅ - -```bash -curl -X POST http://localhost:8080/v1/auth/check \ - -H "Authorization: Bearer YOUR_JWT_TOKEN" \ - -H "Content-Type: application/json" \ - -d "{\"user_id\":\"U0000000001\",\"resource\":\"personnel\",\"action\":\"assign_role\",\"resource_data\":{\"region\":\"01\"}}" -``` - -**Expected Response:** - -```json -{ - "allowed": true, - "reason": "All policies satisfied", - "permission_id": 3, - "evaluated_at": "2025-12-09T...", - "matched_policies": [8] -} -``` - -#### Test 3: Data Collector Cannot Verify ❌ - -```bash -curl -X POST http://localhost:8080/v1/auth/check \ - -H "Authorization: Bearer DATA_COLLECTOR_JWT_TOKEN" \ - -H "Content-Type: application/json" \ - -d "{\"user_id\":\"U0000000002\",\"resource\":\"cases\",\"action\":\"verify\",\"resource_data\":{}}" -``` - -**Expected Response:** - -```json -{ - "allowed": false, - "reason": "Policy failed: action_user_role != Data Collector...", - "permission_id": 14, - "evaluated_at": "2025-12-09T..." -} -``` - -## 📋 Common Use Cases - -### Check if User Can Perform Action - -```javascript -// JavaScript/Frontend Example -const checkPermission = async (resource, action, resourceData = {}) => { - const response = await fetch("/v1/auth/check", { - method: "POST", - headers: { - Authorization: `Bearer ${jwtToken}`, - "Content-Type": "application/json", - }, - body: JSON.stringify({ - user_id: currentUser.id, - resource: resource, - action: action, - resource_data: resourceData, - }), - }); - - const result = await response.json(); - return result.allowed; -}; - -// Usage -if (await checkPermission("users", "manage")) { - // Show admin interface -} - -if (await checkPermission("cases", "verify", { region: userRegion })) { - // Allow case verification -} -``` - -### Go Backend Integration - -```go -// In your service/handler -import "authorization/services" - -func (s *MyService) PerformAction(userID, resource, action string) error { - ctx := &models.AuthorizationContext{ - UserID: userID, - Resource: resource, - Action: action, - ResourceData: make(map[string]string), - } - - result, err := authService.Authorize(ctx) - if err != nil { - return fmt.Errorf("authorization failed: %w", err) - } - - if !result.Allowed { - return fmt.Errorf("access denied: %s", result.Reason) - } - - // Proceed with action - return nil -} -``` - -## 🔑 JWT Token Format - -Your JWT should include these claims: - -```json -{ - "user_id": "U0000000001", - "email_address": "darrel.israel@example.com", - "role_id": "SuperAdmin", - "exp": 1702123456 -} -``` - -## 📊 Permission Reference - -### Most Common Permissions - -| Resource | Action | Description | Policy | -| --------------- | -------------- | ------------------------- | ------------------ | -| users | manage | Create/edit user accounts | role = Admin | -| users | view | View user profiles | (no policy) | -| personnel | assign_role | Assign project roles | region match | -| personnel | assign_project | Grant project access | region match | -| workload | assign | Assign cases to staff | region match | -| workload | download | Download assigned cases | (no policy) | -| cases | encode | Create/update survey data | (no policy) | -| cases | verify | Review submitted data | NOT Data Collector | -| cases | return | Reject and return case | NOT Data Collector | -| data_processing | certify | Mark data as certified | RFP or PFP only | - -## 🎯 Policy Examples - -### Simple Role Check - -```text -Policy: user.role = Admin -→ Only users with role="Admin" allowed -``` - -### Regional Matching - -```text -Policy: user.region = ${resource.region} -→ User can only access resources in their region -``` - -### Role Exclusion - -```text -Policy: user.action_user_role != Data Collector -→ Everyone except Data Collectors allowed -``` - -### Multi-Role Inclusion - -```text -Policy: user.action_user_role IN RFP,PFP -→ Only RFP or PFP roles allowed -``` - -## 🔧 Troubleshooting - -### "Permission not found" - -- Check if permission exists in database -- Verify resource and action names match exactly -- Wait 5 minutes for cache refresh or restart service - -### "User attribute 'xxx' not found" - -- Check `user_attributes` table for the user -- Ensure attribute name matches policy requirement -- Add missing attribute to database - -### "Policy failed: region = 01 (actual: 03)" - -- User's region doesn't match resource region -- Check user_attributes.region for the user -- Verify resource_data.region in request - -## 📈 Performance Tips - -1. **Cache Hit Rate**: ~98% with default settings -2. **Response Time**: <1ms for cached requests -3. **Memory Usage**: ~50MB for 10k users -4. **Cache Refresh**: Every 5 minutes automatically - -## 🎓 Next Steps - -1. Read full documentation: `docs/RBAC_ABAC_README.md` -2. Review test examples: `docs/test_examples.txt` -3. Check implementation details: `docs/IMPLEMENTATION_SUMMARY.md` -4. View database schema: `docs/database_schema.sql` - -## 💡 Pro Tips - -- **Frontend**: Check permissions before rendering UI elements -- **Backend**: Always verify permissions in backend (don't trust frontend) -- **Caching**: Service caches permissions automatically -- **Invalidation**: Call `InvalidateUserCache(userID)` after updating user attributes -- **Monitoring**: Add performance logging for slow authorization checks (>50ms) - -## 🆘 Need Help? - -Common issues and solutions: - -1. **401 Unauthorized**: Check JWT token is valid and not expired -2. **403 Forbidden**: User lacks required permission or fails policy -3. **500 Internal Error**: Check database connection and logs -4. **Slow responses**: Check database indexes, cache hit rate - ---- - -**You're all set!** 🎉 - -The authorization service is production-ready with RBAC + ABAC, high-performance caching, and comprehensive policy evaluation. diff --git a/docs/RBAC_ABAC_README.md b/docs/RBAC_ABAC_README.md deleted file mode 100644 index d31d39b..0000000 --- a/docs/RBAC_ABAC_README.md +++ /dev/null @@ -1,278 +0,0 @@ -# RBAC + ABAC Authorization Service - -Complete Role-Based Access Control (RBAC) and Attribute-Based Access Control (ABAC) implementation for the UESS Authorization microservice. - -## Features - -- ✅ **Database-driven permissions** - Permissions stored in MySQL -- ✅ **Policy-based authorization** - ABAC policies with attribute constraints -- ✅ **High-performance caching** - 5-minute cache for permissions and policies -- ✅ **User attribute support** - Dynamic user attributes for fine-grained control -- ✅ **Variable substitution** - Dynamic policy values (e.g., `${resource.region}`) -- ✅ **Multiple comparison operators** - =, !=, >, <, >=, <=, IN, CONTAINS -- ✅ **JWT integration** - Works with existing JWT middleware - -## Database Schema - -### Tables Created - -1. **permissions** - System permissions (resource + action) -2. **policy_attributes** - ABAC policy constraints -3. **user_attributes** - User-specific attributes -4. **users** - User information - -## API Usage - -### Authorization Request - -**Endpoint:** `POST /v1/auth/check` - -**Headers:** - -```http -Authorization: Bearer -``` - -**Request Body:** - -```json -{ - "user_id": "U0000000001", - "resource": "users", - "action": "manage", - "resource_data": { - "region": "01" - } -} -``` - -**Success Response (200):** - -```json -{ - "allowed": true, - "reason": "All policies satisfied", - "permission_id": 1, - "evaluated_at": "2025-12-09T10:30:00Z", - "matched_policies": [1, 7] -} -``` - -**Denied Response (403):** - -```json -{ - "allowed": false, - "reason": "Policy failed: region = 01 (actual: 03)", - "permission_id": 1, - "evaluated_at": "2025-12-09T10:30:00Z" -} -``` - -## Authorization Flow - -1. **JWT Validation** - JWT middleware extracts user claims -2. **Permission Lookup** - Find permission by resource + action -3. **User Attributes** - Load user attributes from database (cached) -4. **Policy Evaluation** - Evaluate all ABAC policies -5. **Decision** - Return allowed/denied with reason - -## Examples - -### Example 1: Admin Access (Permission ID: 1) - -```text -Permission: users + manage -Policy: user.role = Admin -Result: Only users with role="Admin" can manage users -``` - -### Example 2: Regional Access (Permission ID: 3) - -```text -Permission: personnel + assign_role -Policy: user.region = ${resource.region} -Result: User can only assign roles in their own region -``` - -### Example 3: Role Exclusion (Permission ID: 14) - -```text -Permission: cases + verify -Policy: user.action_user_role != Data Collector -Result: Data Collectors cannot verify cases -``` - -### Example 4: Role Inclusion (Permission ID: 20) - -```text -Permission: data_processing + certify -Policy: user.action_user_role IN RFP,PFP -Result: Only RFP or PFP can certify data -``` - -## Policy Comparison Operators - -| Operator | Description | Example | -| ------------- | ------------------ | ------------------------------ | -| `=` | Equals | `user.role = Admin` | -| `!=` | Not equals | `user.role != Guest` | -| `>` | Greater than | `user.level > 5` | -| `<` | Less than | `user.age < 65` | -| `>=` | Greater or equal | `user.score >= 80` | -| `<=` | Less or equal | `user.attempts <= 3` | -| `IN` | In list | `user.role IN Admin,Moderator` | -| `CONTAINS` | Contains substring | `user.email CONTAINS @psa.gov` | -| `STARTS_WITH` | Starts with | `user.id STARTS_WITH U00` | -| `ENDS_WITH` | Ends with | `user.email ENDS_WITH .gov` | - -## Variable Substitution - -Policies support dynamic values using `${type.attribute}` syntax: - -```text -${user.region} → User's region attribute -${resource.region} → Resource region from request -${environment.time} → Current timestamp -``` - -**Example:** - -```text -Policy: user.region = ${resource.region} -Evaluates to: "01" = "01" ✓ -``` - -## Performance - -### Without Caching - -- Permission lookup: ~5-10ms -- Policy fetch: ~3-5ms -- **Total: ~10-20ms per request** - -### With Caching - -- Cache hit: ~0.1-0.5ms -- Cache miss: ~10-20ms (then cached) -- **Average: ~0.5ms per request** (98% cache hit rate) - -### Cache Settings - -- Permissions: Refreshed every 5 minutes -- Policies: Refreshed every 5 minutes -- User attributes: Cached indefinitely, LRU eviction at 10k entries - -## Testing - -### Test Admin Access - -```bash -curl -X POST http://localhost:8080/v1/auth/check \ - -H "Authorization: Bearer " \ - -H "Content-Type: application/json" \ - -d '{ - "user_id": "U0000000001", - "resource": "users", - "action": "manage", - "resource_data": {} - }' -``` - -### Test Regional Access - -```bash -curl -X POST http://localhost:8080/v1/auth/check \ - -H "Authorization: Bearer " \ - -H "Content-Type: application/json" \ - -d '{ - "user_id": "U0000000002", - "resource": "personnel", - "action": "assign_role", - "resource_data": { - "region": "01" - } - }' -``` - -## File Structure - -```text -authorization/ -├── models/ -│ ├── rbac.go # RBAC/ABAC data models -│ └── authorize.go # Request/Response models -├── repository/ -│ └── permission_repository.go # Database access layer -├── services/ -│ ├── authorize.go # Base authorization service -│ ├── policy_evaluator.go # ABAC policy evaluation engine -│ └── cached_authorization.go # Cached authorization service -├── handlers/ -│ └── authorize.go # HTTP handler -└── middleware/ - └── jwt.go # JWT authentication -``` - -## Adding New Permissions - -1. **Add permission to database:** - -```sql -INSERT INTO permissions (permission_name, description, resource, action) -VALUES ('Export Data', 'Export survey data to Excel', 'data', 'export'); -``` - -1. **Add policies (optional):** - -```sql -INSERT INTO policy_attributes (attribute_name, attribute_type, comparison, attribute_value, permission_id) -VALUES ('role', 'user', '=', 'Admin', 28); -``` - -1. **Cache updates automatically in 5 minutes** or restart service - -## Cache Statistics - -Get cache performance metrics (add this endpoint if needed): - -```go -// GET /v1/auth/cache-stats -{ - "permissions_cached": 27, - "policies_cached": 16, - "user_attributes_cached": 1523, - "last_refresh": "2025-12-09T10:25:00Z", - "cache_age_seconds": 245.3 -} -``` - -## Security Considerations - -1. **JWT Required** - All requests must have valid JWT -2. **User ID Verification** - Request user_id must match JWT user_id -3. **Secure Database** - Use read-only DB user for authorization service -4. **Audit Logging** - Log all authorization decisions (implement as needed) -5. **Cache Invalidation** - Invalidate user cache on attribute changes - -## Troubleshooting - -### Permission Not Found - -- Verify permission exists in database -- Check resource and action spelling -- Wait for cache refresh or restart service - -### Policy Fails Unexpectedly - -- Check user has required attributes in `user_attributes` table -- Verify attribute names match exactly -- Check comparison operator is correct -- Use variable substitution syntax correctly - -### Slow Performance - -- Check database indexes on permissions table -- Monitor cache hit rate -- Increase cache expiry if permissions change rarely -- Check database connection pool settings diff --git a/docs/test_examples.txt b/docs/test_examples.txt deleted file mode 100644 index 0512c2f..0000000 --- a/docs/test_examples.txt +++ /dev/null @@ -1,115 +0,0 @@ --- Example Authorization Requests for Testing - --- 1. Admin Managing Users (Should succeed for U0000000001) --- Permission: Manage User Accounts (ID: 1) --- Policy: user.role = Admin -{ - "user_id": "U0000000001", - "resource": "users", - "action": "manage", - "resource_data": {} -} --- Expected: ALLOWED (user has role="Super Admin") - --- 2. Regional Permission Assignment (Should succeed for same region) --- Permission: Assign Project Roles (ID: 3) --- Policy: user.region = ${resource.region} -{ - "user_id": "U0000000001", - "resource": "personnel", - "action": "assign_role", - "resource_data": { - "region": "01" - } -} --- Expected: ALLOWED (user region "01" matches resource region "01") - --- 3. Regional Permission Assignment (Should fail for different region) --- Permission: Assign Project Roles (ID: 3) --- Policy: user.region = ${resource.region} -{ - "user_id": "U0000000003", - "resource": "personnel", - "action": "assign_role", - "resource_data": { - "region": "01" - } -} --- Expected: DENIED (user region "03" doesn't match resource region "01") - --- 4. Data Collector Cannot Verify Cases --- Permission: Verify Case (ID: 14) --- Policy: user.action_user_role != Data Collector -{ - "user_id": "U0000000002", - "resource": "cases", - "action": "verify", - "resource_data": {} -} --- Expected: DENIED (user is Data Collector) - --- 5. Certify Data (RFP/PFP only) --- Permission: Certify Data (ID: 20) --- Policy: user.action_user_role IN RFP,PFP -{ - "user_id": "U0000000003", - "resource": "data_processing", - "action": "certify", - "resource_data": {} -} --- Expected: ALLOWED (user is Provincial Focal Person) - --- 6. Certify Data (Should fail for non-RFP/PFP) --- Permission: Certify Data (ID: 20) --- Policy: user.action_user_role IN RFP,PFP -{ - "user_id": "U0000000002", - "resource": "data_processing", - "action": "certify", - "resource_data": {} -} --- Expected: DENIED (user is Data Collector, not RFP/PFP) - --- 7. View User Profiles (No policies - should succeed) --- Permission: View User Profiles (ID: 2) --- No policies defined -{ - "user_id": "U0000000002", - "resource": "users", - "action": "view", - "resource_data": {} -} --- Expected: ALLOWED (no policies to fail) - --- 8. DPS Role Validation --- Permission: Validate Data (ID: 18) --- Policy: user.role_dps = 1 -{ - "user_id": "U0000000001", - "resource": "data_processing", - "action": "validate", - "resource_data": {} -} --- Expected: ALLOWED (user has role_dps=1) - --- 9. Multiple Policies - Regional Workload Assignment --- Permission: Assign Workload (ID: 9) --- Policy: user.region = ${resource.region} -{ - "user_id": "U0000000001", - "resource": "workload", - "action": "assign", - "resource_data": { - "region": "01" - } -} --- Expected: ALLOWED (user in region 01, resource in region 01) - --- 10. Permission Not Found (Should return appropriate error) -{ - "user_id": "U0000000001", - "resource": "nonexistent", - "action": "delete", - "resource_data": {} -} --- Expected: DENIED with "Permission not found" reason