UNPKG

@clduab11/gemini-flow

Version:

Revolutionary AI agent swarm coordination platform with Google Services integration, multimedia processing, and production-ready monitoring. Features 8 Google AI services, quantum computing capabilities, and enterprise-grade security.

944 lines (830 loc) 25.1 kB
/** * Security Context Propagation System * * Manages security context propagation across the authentication system, * ensuring secure context sharing between components and maintaining security boundaries */ import { EventEmitter } from "events"; import { Logger } from "../../utils/logger.js"; import { SecurityContext, AuthContext, AuthCredentials, AuthError, } from "../../types/auth.js"; /** * Security context configuration */ export interface SecurityContextConfig { enableContextPropagation: boolean; maxContextAge: number; // milliseconds enableContextValidation: boolean; contextEncryptionEnabled: boolean; enableAuditTrail: boolean; trustedComponents: string[]; securityLevels: string[]; } /** * Context propagation entry */ interface ContextPropagationEntry { context: SecurityContext; createdAt: number; accessCount: number; lastAccessed: number; sourceComponent: string; propagatedTo: string[]; } /** * Context validation result */ interface ContextValidationResult { valid: boolean; expired: boolean; errors: string[]; warnings: string[]; } /** * Security audit entry */ interface SecurityAuditEntry { timestamp: number; eventType: | "context_created" | "context_propagated" | "context_validated" | "context_expired" | "security_violation"; contextId: string; component: string; details: Record<string, any>; securityLevel: string; } /** * Context access control */ interface ContextAccessControl { requiredPermissions: string[]; allowedComponents: string[]; securityLevel: string; expiration: number; } /** * Security Context Manager */ export class SecurityContextManager extends EventEmitter { private config: SecurityContextConfig; private logger: Logger; // Context storage and tracking private activeContexts = new Map<string, ContextPropagationEntry>(); private contextAccessControls = new Map<string, ContextAccessControl>(); private auditTrail: SecurityAuditEntry[] = []; // Component registry private trustedComponents = new Set<string>(); private componentSessions = new Map<string, Set<string>>(); // Security validation private contextValidationRules = new Map< string, (context: SecurityContext) => boolean >(); // Cleanup intervals private cleanupInterval?: ReturnType<typeof setInterval>; private auditCleanupInterval?: ReturnType<typeof setInterval>; constructor(config: Partial<SecurityContextConfig> = {}) { super(); this.config = { enableContextPropagation: config.enableContextPropagation ?? true, maxContextAge: config.maxContextAge || 24 * 60 * 60 * 1000, // 24 hours enableContextValidation: config.enableContextValidation ?? true, contextEncryptionEnabled: config.contextEncryptionEnabled ?? true, enableAuditTrail: config.enableAuditTrail ?? true, trustedComponents: config.trustedComponents || [], securityLevels: config.securityLevels || [ "public", "internal", "confidential", "secret", ], ...config, }; this.logger = new Logger("SecurityContextManager"); // Initialize trusted components this.config.trustedComponents.forEach((component) => { this.trustedComponents.add(component); }); // Set up default validation rules this.setupDefaultValidationRules(); // Start cleanup tasks this.startCleanupTasks(); this.logger.info("Security Context Manager initialized", { enablePropagation: this.config.enableContextPropagation, maxContextAge: this.config.maxContextAge, trustedComponents: this.config.trustedComponents.length, enableAuditTrail: this.config.enableAuditTrail, }); } /** * Create new security context */ async createSecurityContext( authContext: AuthContext, sourceComponent: string, options: { securityLevel?: string; requiredPermissions?: string[]; allowedComponents?: string[]; customData?: Record<string, any>; } = {}, ): Promise<SecurityContext> { try { if (!this.config.enableContextPropagation) { throw this.createSecurityError( "CONTEXT_DISABLED", "Context propagation is disabled", ); } // Validate source component this.validateSourceComponent(sourceComponent); // Generate context ID const contextId = this.generateContextId(); // Create security context const securityContext: SecurityContext = { authContext, requestId: contextId, sourceIp: options.customData?.sourceIp, userAgent: options.customData?.userAgent, timestamp: Date.now(), riskScore: this.calculateRiskScore(authContext, options), trustedDevice: this.isTrustedDevice(options.customData?.deviceInfo), }; // Create propagation entry const propagationEntry: ContextPropagationEntry = { context: securityContext, createdAt: Date.now(), accessCount: 0, lastAccessed: Date.now(), sourceComponent, propagatedTo: [], }; // Set up access control const accessControl: ContextAccessControl = { requiredPermissions: options.requiredPermissions || [], allowedComponents: options.allowedComponents || [], securityLevel: options.securityLevel || "internal", expiration: Date.now() + this.config.maxContextAge, }; // Store context this.activeContexts.set(contextId, propagationEntry); this.contextAccessControls.set(contextId, accessControl); // Add to component sessions if (!this.componentSessions.has(sourceComponent)) { this.componentSessions.set(sourceComponent, new Set()); } this.componentSessions.get(sourceComponent)!.add(contextId); // Log audit entry this.logSecurityAudit( "context_created", contextId, sourceComponent, { securityLevel: accessControl.securityLevel, permissions: authContext.permissions, userId: authContext.userId, }, accessControl.securityLevel, ); this.logger.info("Security context created", { contextId, sourceComponent, securityLevel: accessControl.securityLevel, permissions: authContext.permissions.length, }); this.emit("context_created", { contextId, securityContext, sourceComponent, }); return securityContext; } catch (error) { this.logger.error("Failed to create security context", { sourceComponent, error, }); throw error; } } /** * Propagate context to another component */ async propagateContext( contextId: string, targetComponent: string, requiredPermissions: string[] = [], ): Promise<SecurityContext> { try { if (!this.config.enableContextPropagation) { throw this.createSecurityError( "CONTEXT_DISABLED", "Context propagation is disabled", ); } // Get context entry const entry = this.activeContexts.get(contextId); if (!entry) { throw this.createSecurityError( "CONTEXT_NOT_FOUND", `Security context not found: ${contextId}`, ); } // Get access control const accessControl = this.contextAccessControls.get(contextId); if (!accessControl) { throw this.createSecurityError( "ACCESS_CONTROL_NOT_FOUND", `Access control not found: ${contextId}`, ); } // Validate context const validation = await this.validateContext(contextId); if (!validation.valid) { throw this.createSecurityError( "CONTEXT_INVALID", `Context validation failed: ${validation.errors.join(", ")}`, ); } // Check component authorization await this.checkComponentAuthorization( targetComponent, accessControl, requiredPermissions, ); // Update propagation tracking entry.accessCount++; entry.lastAccessed = Date.now(); if (!entry.propagatedTo.includes(targetComponent)) { entry.propagatedTo.push(targetComponent); } // Add to target component sessions if (!this.componentSessions.has(targetComponent)) { this.componentSessions.set(targetComponent, new Set()); } this.componentSessions.get(targetComponent)!.add(contextId); // Log audit entry this.logSecurityAudit( "context_propagated", contextId, targetComponent, { sourceComponent: entry.sourceComponent, requiredPermissions, accessCount: entry.accessCount, }, accessControl.securityLevel, ); this.logger.debug("Security context propagated", { contextId, sourceComponent: entry.sourceComponent, targetComponent, accessCount: entry.accessCount, }); this.emit("context_propagated", { contextId, sourceComponent: entry.sourceComponent, targetComponent, securityContext: entry.context, }); return entry.context; } catch (error) { this.logger.error("Failed to propagate security context", { contextId, targetComponent, error, }); throw error; } } /** * Validate security context */ async validateContext(contextId: string): Promise<ContextValidationResult> { try { const entry = this.activeContexts.get(contextId); const accessControl = this.contextAccessControls.get(contextId); const result: ContextValidationResult = { valid: true, expired: false, errors: [], warnings: [], }; // Check if context exists if (!entry || !accessControl) { result.valid = false; result.errors.push("Context not found"); return result; } // Check expiration const now = Date.now(); if (accessControl.expiration <= now) { result.valid = false; result.expired = true; result.errors.push("Context has expired"); } // Check context age const contextAge = now - entry.createdAt; if (contextAge > this.config.maxContextAge) { result.valid = false; result.expired = true; result.errors.push("Context exceeds maximum age"); } // Check auth context validity const authContext = entry.context.authContext; if (authContext.expiresAt && authContext.expiresAt <= now) { result.valid = false; result.expired = true; result.errors.push("Auth context has expired"); } // Run custom validation rules if (this.config.enableContextValidation) { for (const [ ruleName, ruleFunction, ] of this.contextValidationRules.entries()) { try { if (!ruleFunction(entry.context)) { result.warnings.push(`Validation rule failed: ${ruleName}`); } } catch (error) { result.warnings.push(`Validation rule error: ${ruleName}`); } } } // Log validation if there are issues if (!result.valid || result.warnings.length > 0) { this.logSecurityAudit( "context_validated", contextId, "security-manager", { valid: result.valid, expired: result.expired, errors: result.errors, warnings: result.warnings, }, accessControl.securityLevel, ); } return result; } catch (error) { this.logger.error("Context validation failed", { contextId, error }); return { valid: false, expired: false, errors: [ error instanceof Error ? error.message : "Unknown validation error", ], warnings: [], }; } } /** * Get security context */ async getSecurityContext( contextId: string, component: string, ): Promise<SecurityContext | null> { try { const entry = this.activeContexts.get(contextId); const accessControl = this.contextAccessControls.get(contextId); if (!entry || !accessControl) { return null; } // Validate context const validation = await this.validateContext(contextId); if (!validation.valid) { return null; } // Check component access if ( accessControl.allowedComponents.length > 0 && !accessControl.allowedComponents.includes(component) ) { throw this.createSecurityError( "ACCESS_DENIED", `Component not authorized: ${component}`, ); } // Update access tracking entry.accessCount++; entry.lastAccessed = Date.now(); return entry.context; } catch (error) { this.logger.error("Failed to get security context", { contextId, component, error, }); return null; } } /** * Revoke security context */ async revokeContext(contextId: string, component: string): Promise<boolean> { try { const entry = this.activeContexts.get(contextId); const accessControl = this.contextAccessControls.get(contextId); if (!entry || !accessControl) { return false; } // Check if component can revoke this context if ( entry.sourceComponent !== component && !this.trustedComponents.has(component) ) { throw this.createSecurityError( "ACCESS_DENIED", `Component not authorized to revoke context: ${component}`, ); } // Remove from all component sessions for (const [comp, sessions] of this.componentSessions.entries()) { sessions.delete(contextId); } // Remove context and access control this.activeContexts.delete(contextId); this.contextAccessControls.delete(contextId); // Log audit entry this.logSecurityAudit( "context_expired", contextId, component, { reason: "manual_revocation", originalSource: entry.sourceComponent, }, accessControl.securityLevel, ); this.logger.info("Security context revoked", { contextId, component }); this.emit("context_revoked", { contextId, component }); return true; } catch (error) { this.logger.error("Failed to revoke security context", { contextId, component, error, }); return false; } } /** * List active contexts for component */ getActiveContexts(component?: string): string[] { if (component) { const sessions = this.componentSessions.get(component); return sessions ? Array.from(sessions) : []; } return Array.from(this.activeContexts.keys()); } /** * Get security statistics */ getSecurityStats() { const now = Date.now(); const entries = Array.from(this.activeContexts.values()); return { totalContexts: this.activeContexts.size, activeComponents: this.componentSessions.size, trustedComponents: this.trustedComponents.size, totalAccesses: entries.reduce((sum, entry) => sum + entry.accessCount, 0), averageAge: entries.length > 0 ? entries.reduce((sum, entry) => sum + (now - entry.createdAt), 0) / entries.length : 0, auditEntries: this.auditTrail.length, securityViolations: this.auditTrail.filter( (entry) => entry.eventType === "security_violation", ).length, }; } /** * Get audit trail */ getAuditTrail(limit = 100, component?: string): SecurityAuditEntry[] { let entries = this.auditTrail; if (component) { entries = entries.filter((entry) => entry.component === component); } return entries.slice(-limit); } /** * Add custom validation rule */ addValidationRule( name: string, rule: (context: SecurityContext) => boolean, ): void { this.contextValidationRules.set(name, rule); this.logger.debug("Validation rule added", { name }); } /** * Remove validation rule */ removeValidationRule(name: string): boolean { const removed = this.contextValidationRules.delete(name); if (removed) { this.logger.debug("Validation rule removed", { name }); } return removed; } /** * Register trusted component */ registerTrustedComponent(component: string): void { this.trustedComponents.add(component); this.logger.info("Trusted component registered", { component }); } /** * Unregister trusted component */ unregisterTrustedComponent(component: string): void { this.trustedComponents.delete(component); this.logger.info("Trusted component unregistered", { component }); } /** * Shutdown and cleanup */ async shutdown(): Promise<void> { this.logger.info("Shutting down Security Context Manager"); // Clear cleanup intervals if (this.cleanupInterval) { clearInterval(this.cleanupInterval); } if (this.auditCleanupInterval) { clearInterval(this.auditCleanupInterval); } // Clear all contexts const contextIds = Array.from(this.activeContexts.keys()); for (const contextId of contextIds) { await this.revokeContext(contextId, "security-manager"); } this.logger.info("Security Context Manager shutdown complete"); } /** * Setup default validation rules */ private setupDefaultValidationRules(): void { // Rule: Check if auth context has required fields this.addValidationRule( "auth_context_complete", (context: SecurityContext) => { const authContext = context.authContext; return !!( authContext.sessionId && authContext.credentials && authContext.scopes ); }, ); // Rule: Check if credentials are not expired this.addValidationRule( "credentials_not_expired", (context: SecurityContext) => { const credentials = context.authContext.credentials; if (credentials.expiresAt) { return credentials.expiresAt > Date.now(); } return true; // No expiration set }, ); // Rule: Check risk score threshold this.addValidationRule( "risk_score_acceptable", (context: SecurityContext) => { return !context.riskScore || context.riskScore < 0.8; // 80% risk threshold }, ); } /** * Start cleanup tasks */ private startCleanupTasks(): void { // Context cleanup every 5 minutes this.cleanupInterval = setInterval( () => { this.cleanupExpiredContexts().catch((error) => { this.logger.error("Context cleanup failed", { error }); }); }, 5 * 60 * 1000, ); // Audit trail cleanup every hour this.auditCleanupInterval = setInterval( () => { this.cleanupAuditTrail(); }, 60 * 60 * 1000, ); } /** * Cleanup expired contexts */ private async cleanupExpiredContexts(): Promise<void> { const now = Date.now(); let cleanedCount = 0; for (const [contextId, entry] of this.activeContexts.entries()) { const accessControl = this.contextAccessControls.get(contextId); if (!accessControl) { // Remove context without access control this.activeContexts.delete(contextId); cleanedCount++; continue; } // Check if expired const contextAge = now - entry.createdAt; const isExpired = accessControl.expiration <= now || contextAge > this.config.maxContextAge; if (isExpired) { // Remove from component sessions for (const sessions of this.componentSessions.values()) { sessions.delete(contextId); } // Remove context this.activeContexts.delete(contextId); this.contextAccessControls.delete(contextId); // Log expiration this.logSecurityAudit( "context_expired", contextId, "security-manager", { reason: "automatic_cleanup", age: contextAge, }, accessControl.securityLevel, ); cleanedCount++; } } if (cleanedCount > 0) { this.logger.info("Expired contexts cleaned up", { count: cleanedCount }); this.emit("contexts_cleaned", { count: cleanedCount }); } } /** * Cleanup old audit trail entries */ private cleanupAuditTrail(): void { const maxEntries = 10000; const maxAge = 7 * 24 * 60 * 60 * 1000; // 7 days const now = Date.now(); // Remove old entries this.auditTrail = this.auditTrail.filter( (entry) => now - entry.timestamp <= maxAge, ); // Keep only latest entries if still too many if (this.auditTrail.length > maxEntries) { this.auditTrail = this.auditTrail.slice(-maxEntries); } } /** * Validate source component */ private validateSourceComponent(component: string): void { if (!component || typeof component !== "string") { throw this.createSecurityError( "INVALID_COMPONENT", "Invalid source component", ); } } /** * Check component authorization */ private async checkComponentAuthorization( component: string, accessControl: ContextAccessControl, requiredPermissions: string[], ): Promise<void> { // Check if component is allowed if ( accessControl.allowedComponents.length > 0 && !accessControl.allowedComponents.includes(component) ) { throw this.createSecurityError( "ACCESS_DENIED", `Component not in allowed list: ${component}`, ); } // Check if component is trusted for sensitive operations if ( accessControl.securityLevel === "secret" && !this.trustedComponents.has(component) ) { throw this.createSecurityError( "INSUFFICIENT_TRUST", `Component not trusted for secret level: ${component}`, ); } // Check required permissions for (const permission of requiredPermissions) { if (!accessControl.requiredPermissions.includes(permission)) { throw this.createSecurityError( "INSUFFICIENT_PERMISSIONS", `Missing required permission: ${permission}`, ); } } } /** * Calculate risk score */ private calculateRiskScore(authContext: AuthContext, options: any): number { let riskScore = 0; // Base risk from auth method if (authContext.credentials.type === "api_key") { riskScore += 0.2; } // Risk from unknown source IP if ( options.customData?.sourceIp && !this.isKnownIP(options.customData.sourceIp) ) { riskScore += 0.3; } // Risk from untrusted device if (!this.isTrustedDevice(options.customData?.deviceInfo)) { riskScore += 0.2; } // Risk from high privilege permissions const highPrivilegePerms = ["admin", "superuser", "root"]; if ( authContext.permissions.some((perm) => highPrivilegePerms.includes(perm)) ) { riskScore += 0.1; } return Math.min(riskScore, 1.0); } /** * Check if IP is known/trusted */ private isKnownIP(ip: string): boolean { // This would integrate with IP reputation services or allowlists // For now, return true for local IPs return ( ip.startsWith("127.") || ip.startsWith("192.168.") || ip.startsWith("10.") ); } /** * Check if device is trusted */ private isTrustedDevice(deviceInfo?: any): boolean { // This would check device fingerprints, certificates, etc. // For now, return false to be conservative return false; } /** * Generate unique context ID */ private generateContextId(): string { return `sec_ctx_${Date.now()}_${Math.random().toString(36).substring(2, 15)}`; } /** * Log security audit entry */ private logSecurityAudit( eventType: SecurityAuditEntry["eventType"], contextId: string, component: string, details: Record<string, any>, securityLevel: string, ): void { if (!this.config.enableAuditTrail) return; const entry: SecurityAuditEntry = { timestamp: Date.now(), eventType, contextId, component, details, securityLevel, }; this.auditTrail.push(entry); } /** * Create security error */ private createSecurityError(code: string, message: string): AuthError { const error = new Error(message) as AuthError; error.code = code; error.type = "authorization"; error.retryable = false; error.context = { manager: "security-context", timestamp: Date.now(), }; return error; } }