Add RBAC support with roles, permissions, and session management. Implement middleware for authentication and CSRF protection. Enhance audit logging with additional fields. Update HTTP handlers and routes for new features.
This commit is contained in:
@@ -2,7 +2,9 @@ package audit
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"database/sql"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"log"
|
||||
"time"
|
||||
@@ -19,6 +21,12 @@ type Event struct {
|
||||
ResourceID string
|
||||
Success bool
|
||||
Details map[string]any
|
||||
// Enhanced fields
|
||||
Actor string // Username or user identifier
|
||||
Resource string // Full resource identifier (e.g., "pool:my-pool")
|
||||
PayloadHash string // SHA256 hash of request payload
|
||||
Result string // Success/failure message or status
|
||||
ClientIP string // Client IP address
|
||||
}
|
||||
|
||||
type AuditLogger interface {
|
||||
@@ -40,12 +48,67 @@ func (l *SQLAuditLogger) Record(ctx context.Context, e Event) error {
|
||||
if e.Timestamp.IsZero() {
|
||||
e.Timestamp = time.Now()
|
||||
}
|
||||
detailsJSON, _ := json.Marshal(e.Details)
|
||||
_, err := l.DB.ExecContext(ctx, `INSERT INTO audit_events (id, ts, user_id, action, resource_type, resource_id, success, details) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, e.ID, e.Timestamp, e.UserID, e.Action, e.ResourceType, e.ResourceID, boolToInt(e.Success), string(detailsJSON))
|
||||
if err != nil {
|
||||
log.Printf("audit record failed: %v", err)
|
||||
|
||||
// Set actor from UserID if not provided
|
||||
if e.Actor == "" {
|
||||
e.Actor = e.UserID
|
||||
}
|
||||
return err
|
||||
|
||||
// Build resource string from ResourceType and ResourceID
|
||||
if e.Resource == "" {
|
||||
if e.ResourceID != "" {
|
||||
e.Resource = e.ResourceType + ":" + e.ResourceID
|
||||
} else {
|
||||
e.Resource = e.ResourceType
|
||||
}
|
||||
}
|
||||
|
||||
// Set result from Success if not provided
|
||||
if e.Result == "" {
|
||||
if e.Success {
|
||||
e.Result = "success"
|
||||
} else {
|
||||
e.Result = "failure"
|
||||
}
|
||||
}
|
||||
|
||||
detailsJSON, _ := json.Marshal(e.Details)
|
||||
|
||||
// Try to insert with all columns, fallback to basic columns if enhanced columns don't exist
|
||||
_, err := l.DB.ExecContext(ctx,
|
||||
`INSERT INTO audit_events (id, ts, user_id, action, resource_type, resource_id, success, details, actor, resource, payload_hash, result, client_ip)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||
e.ID, e.Timestamp, e.UserID, e.Action, e.ResourceType, e.ResourceID, boolToInt(e.Success), string(detailsJSON),
|
||||
e.Actor, e.Resource, e.PayloadHash, e.Result, e.ClientIP)
|
||||
if err != nil {
|
||||
// Fallback to basic insert if enhanced columns don't exist yet
|
||||
_, err2 := l.DB.ExecContext(ctx,
|
||||
`INSERT INTO audit_events (id, ts, user_id, action, resource_type, resource_id, success, details)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||
e.ID, e.Timestamp, e.UserID, e.Action, e.ResourceType, e.ResourceID, boolToInt(e.Success), string(detailsJSON))
|
||||
if err2 != nil {
|
||||
log.Printf("audit record failed: %v (fallback also failed: %v)", err, err2)
|
||||
return err2
|
||||
}
|
||||
log.Printf("audit record inserted with fallback (enhanced columns may not exist): %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// HashPayload computes SHA256 hash of a payload (JSON string or bytes)
|
||||
func HashPayload(payload interface{}) string {
|
||||
var data []byte
|
||||
switch v := payload.(type) {
|
||||
case []byte:
|
||||
data = v
|
||||
case string:
|
||||
data = []byte(v)
|
||||
default:
|
||||
jsonData, _ := json.Marshal(payload)
|
||||
data = jsonData
|
||||
}
|
||||
hash := sha256.Sum256(data)
|
||||
return hex.EncodeToString(hash[:])
|
||||
}
|
||||
|
||||
func boolToInt(b bool) int {
|
||||
|
||||
Reference in New Issue
Block a user