mirror of
https://github.com/StarFleetCPTN/GoMFT.git
synced 2026-09-09 16:10:48 +02:00
- Added new routes and handlers for managing storage providers, including creation, editing, and deletion. - Introduced a new StorageProvider form component for user input. - Enhanced the database schema to support storage provider references in transfer configurations. - Implemented encryption for sensitive fields in storage provider data. - Added tests for storage provider API endpoints and integration with the database. - Updated frontend components to support storage provider selection and testing.
272 lines
7.5 KiB
Go
272 lines
7.5 KiB
Go
package audit
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
// SecurityMonitor provides aggregate monitoring, alerting, and reporting for security events
|
|
type SecurityMonitor struct {
|
|
auditor *SecurityAuditor
|
|
statsMutex sync.RWMutex
|
|
eventCounts map[EventType]int
|
|
errorCounts map[string]int
|
|
lastEventTime map[EventType]time.Time
|
|
alertThresholds map[EventType]int
|
|
alertHandler AlertHandler
|
|
}
|
|
|
|
// AlertLevel represents the severity of a security alert
|
|
type AlertLevel string
|
|
|
|
// Alert levels
|
|
const (
|
|
AlertLevelInfo AlertLevel = "info"
|
|
AlertLevelWarning AlertLevel = "warning"
|
|
AlertLevelCritical AlertLevel = "critical"
|
|
)
|
|
|
|
// SecurityAlert represents a security alert to be sent to handlers
|
|
type SecurityAlert struct {
|
|
Timestamp time.Time
|
|
Level AlertLevel
|
|
EventType EventType
|
|
Message string
|
|
Count int
|
|
Details map[string]interface{}
|
|
}
|
|
|
|
// AlertHandler is the interface for handling security alerts
|
|
type AlertHandler interface {
|
|
HandleAlert(alert SecurityAlert)
|
|
}
|
|
|
|
// DefaultAlertHandler is a basic implementation of AlertHandler that logs to a file
|
|
type DefaultAlertHandler struct {
|
|
logFile string
|
|
writer io.Writer
|
|
writerLock sync.Mutex
|
|
}
|
|
|
|
// NewDefaultAlertHandler creates a new default alert handler
|
|
func NewDefaultAlertHandler(logFile string) (*DefaultAlertHandler, error) {
|
|
var writer io.Writer
|
|
|
|
if logFile == "" {
|
|
writer = os.Stdout
|
|
} else {
|
|
file, err := os.OpenFile(logFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to open alert log file: %w", err)
|
|
}
|
|
writer = file
|
|
}
|
|
|
|
return &DefaultAlertHandler{
|
|
logFile: logFile,
|
|
writer: writer,
|
|
}, nil
|
|
}
|
|
|
|
// HandleAlert logs the alert to the configured output
|
|
func (h *DefaultAlertHandler) HandleAlert(alert SecurityAlert) {
|
|
h.writerLock.Lock()
|
|
defer h.writerLock.Unlock()
|
|
|
|
jsonData, err := json.Marshal(alert)
|
|
if err != nil {
|
|
fmt.Fprintf(h.writer, "Error marshaling alert: %v\n", err)
|
|
return
|
|
}
|
|
|
|
fmt.Fprintln(h.writer, string(jsonData))
|
|
}
|
|
|
|
// Close closes any open resources
|
|
func (h *DefaultAlertHandler) Close() error {
|
|
if h.logFile != "" {
|
|
if closer, ok := h.writer.(io.Closer); ok {
|
|
return closer.Close()
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// NewSecurityMonitor creates a new SecurityMonitor
|
|
func NewSecurityMonitor(auditor *SecurityAuditor) *SecurityMonitor {
|
|
// Use provided auditor or global one if nil
|
|
if auditor == nil {
|
|
auditor = GetGlobalAuditor()
|
|
}
|
|
|
|
defaultHandler, _ := NewDefaultAlertHandler("")
|
|
|
|
return &SecurityMonitor{
|
|
auditor: auditor,
|
|
eventCounts: make(map[EventType]int),
|
|
errorCounts: make(map[string]int),
|
|
lastEventTime: make(map[EventType]time.Time),
|
|
alertThresholds: make(map[EventType]int),
|
|
alertHandler: defaultHandler,
|
|
}
|
|
}
|
|
|
|
// SetAlertHandler sets a custom alert handler
|
|
func (m *SecurityMonitor) SetAlertHandler(handler AlertHandler) {
|
|
m.alertHandler = handler
|
|
}
|
|
|
|
// SetAlertThreshold sets the threshold for when to generate alerts for a specific event type
|
|
func (m *SecurityMonitor) SetAlertThreshold(eventType EventType, threshold int) {
|
|
m.statsMutex.Lock()
|
|
defer m.statsMutex.Unlock()
|
|
|
|
m.alertThresholds[eventType] = threshold
|
|
}
|
|
|
|
// ProcessEvent processes a security event for monitoring
|
|
func (m *SecurityMonitor) ProcessEvent(event AuditEvent) {
|
|
m.statsMutex.Lock()
|
|
defer m.statsMutex.Unlock()
|
|
|
|
// Update event statistics
|
|
m.eventCounts[event.EventType]++
|
|
m.lastEventTime[event.EventType] = event.Timestamp
|
|
|
|
// Track errors
|
|
if !event.Success && event.Error != "" {
|
|
errorType := classifyError(event.Error)
|
|
m.errorCounts[errorType]++
|
|
|
|
// Alert on specific error types
|
|
if strings.Contains(event.Error, "unauthorized") ||
|
|
strings.Contains(event.Error, "permission") ||
|
|
strings.Contains(event.Error, "access denied") {
|
|
m.generateAlert(AlertLevelCritical, event.EventType,
|
|
fmt.Sprintf("Possible security breach detected: %s", event.Error),
|
|
map[string]interface{}{
|
|
"operation": event.Operation,
|
|
"error": event.Error,
|
|
"keyVersion": event.KeyVersion,
|
|
"modelType": event.ModelType,
|
|
})
|
|
}
|
|
}
|
|
|
|
// Check thresholds for alerting
|
|
threshold, hasThreshold := m.alertThresholds[event.EventType]
|
|
if hasThreshold && m.eventCounts[event.EventType] >= threshold {
|
|
if event.EventType == EventDecryptionFailure || event.EventType == EventEncryptionFailure {
|
|
m.generateAlert(AlertLevelWarning, event.EventType,
|
|
fmt.Sprintf("High number of %s events detected (%d)", event.EventType, m.eventCounts[event.EventType]),
|
|
map[string]interface{}{
|
|
"count": m.eventCounts[event.EventType],
|
|
"threshold": threshold,
|
|
})
|
|
} else if event.EventType == EventKeyRotation {
|
|
m.generateAlert(AlertLevelInfo, event.EventType,
|
|
fmt.Sprintf("Key rotation threshold reached (%d operations)", m.eventCounts[event.EventType]),
|
|
map[string]interface{}{
|
|
"count": m.eventCounts[event.EventType],
|
|
"threshold": threshold,
|
|
})
|
|
}
|
|
|
|
// Reset counter after alerting
|
|
m.eventCounts[event.EventType] = 0
|
|
}
|
|
}
|
|
|
|
// GenerateReport generates a report of security events for a time period
|
|
func (m *SecurityMonitor) GenerateReport(startTime, endTime time.Time, writer io.Writer) error {
|
|
m.statsMutex.RLock()
|
|
defer m.statsMutex.RUnlock()
|
|
|
|
report := struct {
|
|
TimeRange struct {
|
|
Start time.Time `json:"start"`
|
|
End time.Time `json:"end"`
|
|
} `json:"time_range"`
|
|
EventCounts map[EventType]int `json:"event_counts"`
|
|
ErrorCounts map[string]int `json:"error_counts"`
|
|
LastEventTimes map[EventType]time.Time `json:"last_event_times"`
|
|
GeneratedAt time.Time `json:"generated_at"`
|
|
}{
|
|
TimeRange: struct {
|
|
Start time.Time `json:"start"`
|
|
End time.Time `json:"end"`
|
|
}{
|
|
Start: startTime,
|
|
End: endTime,
|
|
},
|
|
EventCounts: m.eventCounts,
|
|
ErrorCounts: m.errorCounts,
|
|
LastEventTimes: m.lastEventTime,
|
|
GeneratedAt: time.Now(),
|
|
}
|
|
|
|
jsonData, err := json.MarshalIndent(report, "", " ")
|
|
if err != nil {
|
|
return fmt.Errorf("failed to marshal report: %w", err)
|
|
}
|
|
|
|
_, err = writer.Write(jsonData)
|
|
return err
|
|
}
|
|
|
|
// generateAlert creates and sends a security alert
|
|
func (m *SecurityMonitor) generateAlert(level AlertLevel, eventType EventType, message string, details map[string]interface{}) {
|
|
if m.alertHandler == nil {
|
|
return
|
|
}
|
|
|
|
alert := SecurityAlert{
|
|
Timestamp: time.Now(),
|
|
Level: level,
|
|
EventType: eventType,
|
|
Message: message,
|
|
Count: m.eventCounts[eventType],
|
|
Details: details,
|
|
}
|
|
|
|
go m.alertHandler.HandleAlert(alert)
|
|
}
|
|
|
|
// classifyError examines an error string and categorizes it
|
|
func classifyError(errorStr string) string {
|
|
errorStr = strings.ToLower(errorStr)
|
|
|
|
if strings.Contains(errorStr, "decrypt") {
|
|
return "decryption_error"
|
|
} else if strings.Contains(errorStr, "encrypt") {
|
|
return "encryption_error"
|
|
} else if strings.Contains(errorStr, "key") {
|
|
return "key_error"
|
|
} else if strings.Contains(errorStr, "permission") || strings.Contains(errorStr, "unauthorized") {
|
|
return "permission_error"
|
|
} else {
|
|
return "other_error"
|
|
}
|
|
}
|
|
|
|
// AttachToAuditor creates a wrapper function for the auditor's LogEvent method
|
|
// that processes events through the monitor before passing them to the original function.
|
|
// Returns the wrapped function that should be set on the auditor.
|
|
func (m *SecurityMonitor) AttachToAuditor() func(AuditEvent) {
|
|
originalLogEvent := m.auditor.LogEvent
|
|
|
|
// Create a wrapper function that processes events and then calls the original
|
|
return func(event AuditEvent) {
|
|
// Process the event for monitoring
|
|
m.ProcessEvent(event)
|
|
|
|
// Call the original LogEvent function
|
|
originalLogEvent(event)
|
|
}
|
|
}
|