Initial commit: Open sourcing all of the Maple Open Technologies code.
This commit is contained in:
commit
755d54a99d
2010 changed files with 448675 additions and 0 deletions
182
cloud/maplefile-backend/pkg/auditlog/auditlog.go
Normal file
182
cloud/maplefile-backend/pkg/auditlog/auditlog.go
Normal file
|
|
@ -0,0 +1,182 @@
|
|||
// Package auditlog provides security audit logging for compliance and security monitoring.
|
||||
// Audit logs are separate from application logs and capture security-relevant events
|
||||
// with consistent structure for analysis and alerting.
|
||||
package auditlog
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/gocql/gocql"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/config/constants"
|
||||
"codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/pkg/validation"
|
||||
)
|
||||
|
||||
// EventType represents the type of security event
|
||||
type EventType string
|
||||
|
||||
const (
|
||||
// Authentication events
|
||||
EventTypeLoginAttempt EventType = "login_attempt"
|
||||
EventTypeLoginSuccess EventType = "login_success"
|
||||
EventTypeLoginFailure EventType = "login_failure"
|
||||
EventTypeLogout EventType = "logout"
|
||||
EventTypeTokenRefresh EventType = "token_refresh"
|
||||
EventTypeTokenRevoked EventType = "token_revoked"
|
||||
|
||||
// Account events
|
||||
EventTypeAccountCreated EventType = "account_created"
|
||||
EventTypeAccountDeleted EventType = "account_deleted"
|
||||
EventTypeAccountLocked EventType = "account_locked"
|
||||
EventTypeAccountUnlocked EventType = "account_unlocked"
|
||||
EventTypeEmailVerified EventType = "email_verified"
|
||||
|
||||
// Recovery events
|
||||
EventTypeRecoveryInitiated EventType = "recovery_initiated"
|
||||
EventTypeRecoveryCompleted EventType = "recovery_completed"
|
||||
EventTypeRecoveryFailed EventType = "recovery_failed"
|
||||
|
||||
// Access control events
|
||||
EventTypeAccessDenied EventType = "access_denied"
|
||||
EventTypePermissionChanged EventType = "permission_changed"
|
||||
|
||||
// Sharing events
|
||||
EventTypeCollectionShared EventType = "collection_shared"
|
||||
EventTypeCollectionUnshared EventType = "collection_unshared"
|
||||
EventTypeSharingBlocked EventType = "sharing_blocked"
|
||||
)
|
||||
|
||||
// Outcome represents the result of the audited action
|
||||
type Outcome string
|
||||
|
||||
const (
|
||||
OutcomeSuccess Outcome = "success"
|
||||
OutcomeFailure Outcome = "failure"
|
||||
OutcomeBlocked Outcome = "blocked"
|
||||
)
|
||||
|
||||
// AuditEvent represents a security audit event
|
||||
type AuditEvent struct {
|
||||
Timestamp time.Time `json:"timestamp"`
|
||||
EventType EventType `json:"event_type"`
|
||||
Outcome Outcome `json:"outcome"`
|
||||
UserID string `json:"user_id,omitempty"`
|
||||
Email string `json:"email,omitempty"` // Always masked
|
||||
ClientIP string `json:"client_ip,omitempty"`
|
||||
UserAgent string `json:"user_agent,omitempty"`
|
||||
Resource string `json:"resource,omitempty"`
|
||||
Action string `json:"action,omitempty"`
|
||||
Details map[string]string `json:"details,omitempty"`
|
||||
FailReason string `json:"fail_reason,omitempty"`
|
||||
}
|
||||
|
||||
// AuditLogger provides security audit logging functionality
|
||||
type AuditLogger interface {
|
||||
// Log records a security audit event
|
||||
Log(ctx context.Context, event AuditEvent)
|
||||
|
||||
// LogAuth logs an authentication event with common fields
|
||||
LogAuth(ctx context.Context, eventType EventType, outcome Outcome, email string, clientIP string, details map[string]string)
|
||||
|
||||
// LogAccess logs an access control event
|
||||
LogAccess(ctx context.Context, eventType EventType, outcome Outcome, userID string, resource string, action string, details map[string]string)
|
||||
}
|
||||
|
||||
type auditLoggerImpl struct {
|
||||
logger *zap.Logger
|
||||
}
|
||||
|
||||
// NewAuditLogger creates a new audit logger
|
||||
func NewAuditLogger(logger *zap.Logger) AuditLogger {
|
||||
// Create a named logger specifically for audit events
|
||||
// This allows filtering audit logs separately from application logs
|
||||
auditLogger := logger.Named("AUDIT")
|
||||
|
||||
return &auditLoggerImpl{
|
||||
logger: auditLogger,
|
||||
}
|
||||
}
|
||||
|
||||
// Log records a security audit event
|
||||
func (a *auditLoggerImpl) Log(ctx context.Context, event AuditEvent) {
|
||||
// Set timestamp if not provided
|
||||
if event.Timestamp.IsZero() {
|
||||
event.Timestamp = time.Now().UTC()
|
||||
}
|
||||
|
||||
// Build zap fields
|
||||
fields := []zap.Field{
|
||||
zap.String("audit_event", string(event.EventType)),
|
||||
zap.String("outcome", string(event.Outcome)),
|
||||
zap.Time("event_time", event.Timestamp),
|
||||
}
|
||||
|
||||
if event.UserID != "" {
|
||||
fields = append(fields, zap.String("user_id", event.UserID))
|
||||
}
|
||||
if event.Email != "" {
|
||||
fields = append(fields, zap.String("email", validation.MaskEmail(event.Email))) // Always mask for safety
|
||||
}
|
||||
if event.ClientIP != "" {
|
||||
fields = append(fields, zap.String("client_ip", validation.MaskIP(event.ClientIP))) // Always mask for safety
|
||||
}
|
||||
if event.UserAgent != "" {
|
||||
fields = append(fields, zap.String("user_agent", event.UserAgent))
|
||||
}
|
||||
if event.Resource != "" {
|
||||
fields = append(fields, zap.String("resource", event.Resource))
|
||||
}
|
||||
if event.Action != "" {
|
||||
fields = append(fields, zap.String("action", event.Action))
|
||||
}
|
||||
if event.FailReason != "" {
|
||||
fields = append(fields, zap.String("fail_reason", event.FailReason))
|
||||
}
|
||||
if len(event.Details) > 0 {
|
||||
fields = append(fields, zap.Any("details", event.Details))
|
||||
}
|
||||
|
||||
// Try to get request ID from context
|
||||
if requestID, ok := ctx.Value(constants.SessionID).(string); ok && requestID != "" {
|
||||
fields = append(fields, zap.String("request_id", requestID))
|
||||
}
|
||||
|
||||
// Log at INFO level - audit events are always important
|
||||
a.logger.Info("security_audit", fields...)
|
||||
}
|
||||
|
||||
// LogAuth logs an authentication event with common fields
|
||||
func (a *auditLoggerImpl) LogAuth(ctx context.Context, eventType EventType, outcome Outcome, email string, clientIP string, details map[string]string) {
|
||||
event := AuditEvent{
|
||||
Timestamp: time.Now().UTC(),
|
||||
EventType: eventType,
|
||||
Outcome: outcome,
|
||||
Email: email, // Should be pre-masked by caller
|
||||
ClientIP: clientIP,
|
||||
Details: details,
|
||||
}
|
||||
|
||||
// Extract user ID from context if available
|
||||
if userID, ok := ctx.Value(constants.SessionUserID).(gocql.UUID); ok {
|
||||
event.UserID = userID.String()
|
||||
}
|
||||
|
||||
a.Log(ctx, event)
|
||||
}
|
||||
|
||||
// LogAccess logs an access control event
|
||||
func (a *auditLoggerImpl) LogAccess(ctx context.Context, eventType EventType, outcome Outcome, userID string, resource string, action string, details map[string]string) {
|
||||
event := AuditEvent{
|
||||
Timestamp: time.Now().UTC(),
|
||||
EventType: eventType,
|
||||
Outcome: outcome,
|
||||
UserID: userID,
|
||||
Resource: resource,
|
||||
Action: action,
|
||||
Details: details,
|
||||
}
|
||||
|
||||
a.Log(ctx, event)
|
||||
}
|
||||
8
cloud/maplefile-backend/pkg/auditlog/provider.go
Normal file
8
cloud/maplefile-backend/pkg/auditlog/provider.go
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
package auditlog
|
||||
|
||||
import "go.uber.org/zap"
|
||||
|
||||
// ProvideAuditLogger provides an audit logger for Wire dependency injection
|
||||
func ProvideAuditLogger(logger *zap.Logger) AuditLogger {
|
||||
return NewAuditLogger(logger)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue