Skip to main content
Glama
SecurityConfigManager.ts22.4 kB
/** * Security Configuration Management System * Provides centralized security policy and configuration management */ import * as fs from "fs/promises"; import * as path from "path"; import { z } from "zod"; import { SecurityUtils } from "./SecurityConfig.js"; import { SecurityValidationError } from "./InputValidator.js"; import { LoggerFactory } from "@/utils/logger.js"; const logger = LoggerFactory.security(); interface SecurityPolicy { id: string; name: string; version: string; description: string; enabled: boolean; scope: "global" | "environment" | "application" | "endpoint"; rules: SecurityPolicyRule[]; compliance: { frameworks: string[]; // OWASP, CWE, GDPR, etc. requirements: string[]; }; metadata: { created: Date; updated: Date; author: string; approved: boolean; }; } interface SecurityPolicyRule { id: string; name: string; type: "authentication" | "authorization" | "input-validation" | "crypto" | "session" | "logging" | "monitoring"; action: "enforce" | "warn" | "log" | "block"; conditions: { environments?: string[]; methods?: string[]; paths?: string[]; userRoles?: string[]; }; parameters: Record<string, unknown>; exceptions: string[]; } interface SecurityConfiguration { configId: string; version: string; environment: string; policies: SecurityPolicy[]; settings: { authentication: AuthenticationSettings; authorization: AuthorizationSettings; inputValidation: InputValidationSettings; cryptography: CryptographySettings; session: SessionSettings; logging: LoggingSettings; monitoring: MonitoringSettings; }; overrides: Record<string, unknown>; metadata: { lastUpdated: Date; checksum: string; }; } interface AuthenticationSettings { methods: ("password" | "jwt" | "oauth" | "api-key")[]; passwordPolicy: { minLength: number; requireUppercase: boolean; requireLowercase: boolean; requireNumbers: boolean; requireSpecialChars: boolean; maxAge: number; preventReuse: number; }; jwtSettings: { algorithm: string; expiresIn: string; issuer: string; audience: string; }; rateLimiting: { maxAttempts: number; windowMs: number; blockDuration: number; }; mfa: { enabled: boolean; methods: string[]; required: boolean; }; } interface AuthorizationSettings { rbac: { enabled: boolean; defaultRole: string; roleHierarchy: Record<string, string[]>; }; permissions: { strict: boolean; defaultDeny: boolean; inheritance: boolean; }; sessionTimeout: number; resourceAccess: { checkOrigin: boolean; allowedOrigins: string[]; csrfProtection: boolean; }; } interface InputValidationSettings { sanitization: { enabled: boolean; htmlStripping: boolean; sqlEscaping: boolean; jsEscaping: boolean; }; validation: { strict: boolean; maxStringLength: number; maxFileSize: number; allowedFileTypes: string[]; blockedPatterns: string[]; }; xssProtection: { enabled: boolean; mode: "filter" | "block"; reportUri: string; }; } interface CryptographySettings { encryption: { algorithm: "AES-256-GCM" | "AES-256-CBC" | "ChaCha20-Poly1305"; keyDerivation: "PBKDF2" | "scrypt" | "Argon2"; keyRotation: { enabled: boolean; intervalDays: number; }; }; hashing: { algorithm: "bcrypt" | "scrypt" | "Argon2"; saltRounds: number; }; tls: { minVersion: string; cipherSuites: string[]; hsts: { enabled: boolean; maxAge: number; includeSubDomains: boolean; }; }; } interface SessionSettings { storage: "memory" | "redis" | "database"; security: { httpOnly: boolean; secure: boolean; sameSite: "strict" | "lax" | "none"; }; timeout: { idle: number; absolute: number; }; regeneration: { onLogin: boolean; onPrivilegeChange: boolean; interval: number; }; } interface LoggingSettings { level: "error" | "warn" | "info" | "debug"; security: { logFailedAuth: boolean; logPrivilegeEscalation: boolean; logDataAccess: boolean; logConfigChanges: boolean; }; retention: { days: number; compression: boolean; encryption: boolean; }; alerting: { enabled: boolean; thresholds: Record<string, number>; channels: string[]; }; } interface MonitoringSettings { realTime: { enabled: boolean; metrics: string[]; alertThresholds: Record<string, number>; }; anomalyDetection: { enabled: boolean; sensitivity: "low" | "medium" | "high"; models: string[]; }; compliance: { enabled: boolean; frameworks: string[]; reportingSchedule: string; }; } /** * Security Configuration Schema Validation */ const SecurityPolicySchema = z.object({ id: z.string().min(1), name: z.string().min(1), version: z.string().regex(/^\d+\.\d+\.\d+$/), description: z.string().min(1), enabled: z.boolean(), scope: z.enum(["global", "environment", "application", "endpoint"]), rules: z.array( z.object({ id: z.string().min(1), name: z.string().min(1), type: z.enum([ "authentication", "authorization", "input-validation", "crypto", "session", "logging", "monitoring", ]), action: z.enum(["enforce", "warn", "log", "block"]), conditions: z.object({ environments: z.array(z.string()).optional(), methods: z.array(z.string()).optional(), paths: z.array(z.string()).optional(), userRoles: z.array(z.string()).optional(), }), parameters: z.record(z.string(), z.unknown()), exceptions: z.array(z.string()), }), ), compliance: z.object({ frameworks: z.array(z.string()), requirements: z.array(z.string()), }), metadata: z.object({ created: z.date(), updated: z.date(), author: z.string(), approved: z.boolean(), }), }); /** * Security Configuration Manager */ export class SecurityConfigManager { private configurations: Map<string, SecurityConfiguration> = new Map(); private policies: Map<string, SecurityPolicy> = new Map(); private configPath: string; constructor(configPath: string = "security-config") { this.configPath = configPath; } /** * Initialize security configuration manager */ async initialize(): Promise<void> { logger.info("Initializing security configuration manager"); await this.ensureConfigDirectory(); await this.loadConfigurations(); await this.loadPolicies(); logger.info("Loaded configurations and policies", { configurationCount: this.configurations.size, policyCount: this.policies.size, }); } /** * Create a new security policy */ async createPolicy(policyData: Omit<SecurityPolicy, "id" | "metadata">): Promise<SecurityPolicy> { const policy: SecurityPolicy = { ...policyData, id: SecurityUtils.generateSecureToken(16), metadata: { created: new Date(), updated: new Date(), author: "system", approved: false, }, }; // Validate policy try { SecurityPolicySchema.parse(policy); } catch (_error) { throw new SecurityValidationError("Invalid security policy", [{ message: String(_error) }]); } this.policies.set(policy.id, policy); await this.savePolicyToFile(policy); logger.info(`Created policy: ${policy.name}`, { policyId: policy.id }); return policy; } /** * Update an existing security policy */ async updatePolicy(policyId: string, updates: Partial<SecurityPolicy>): Promise<SecurityPolicy> { const existingPolicy = this.policies.get(policyId); if (!existingPolicy) { throw new SecurityValidationError("Policy not found", [{ message: `Policy ${policyId} not found` }]); } const updatedPolicy: SecurityPolicy = { ...existingPolicy, ...updates, id: policyId, // Ensure ID doesn't change metadata: { ...existingPolicy.metadata, updated: new Date(), }, }; // Validate updated policy try { SecurityPolicySchema.parse(updatedPolicy); } catch (_error) { throw new SecurityValidationError("Invalid policy update", [{ message: String(_error) }]); } this.policies.set(policyId, updatedPolicy); await this.savePolicyToFile(updatedPolicy); logger.info(`Updated policy: ${updatedPolicy.name}`, { policyId }); return updatedPolicy; } /** * Create a new security configuration */ async createConfiguration( environment: string, configData: Partial<SecurityConfiguration>, ): Promise<SecurityConfiguration> { const config: SecurityConfiguration = { configId: SecurityUtils.generateSecureToken(16), version: "1.0.0", environment, policies: [], settings: configData.settings || this.getDefaultSettings(), overrides: configData.overrides || {}, metadata: { lastUpdated: new Date(), checksum: "", }, }; // Calculate checksum config.metadata.checksum = await this.calculateChecksum(config); this.configurations.set(environment, config); await this.saveConfigurationToFile(config); logger.info(`Created configuration for environment: ${environment}`, { environment }); return config; } /** * Get configuration for environment */ getConfiguration(environment: string): SecurityConfiguration | null { return this.configurations.get(environment) || null; } /** * Get all configurations */ getAllConfigurations(): SecurityConfiguration[] { return Array.from(this.configurations.values()); } /** * Apply policies to configuration */ async applyPoliciesToConfiguration(environment: string, policyIds: string[]): Promise<SecurityConfiguration> { const config = this.configurations.get(environment); if (!config) { throw new SecurityValidationError("Configuration not found", [ { message: `Environment ${environment} not found` }, ]); } const policies: SecurityPolicy[] = []; for (const policyId of policyIds) { const policy = this.policies.get(policyId); if (!policy) { throw new SecurityValidationError("Policy not found", [{ message: `Policy ${policyId} not found` }]); } if (!policy.enabled) { logger.warn(`Skipping disabled policy: ${policy.name}`, { policyName: policy.name }); continue; } policies.push(policy); } config.policies = policies; config.metadata.lastUpdated = new Date(); config.metadata.checksum = await this.calculateChecksum(config); this.configurations.set(environment, config); await this.saveConfigurationToFile(config); logger.info(`Applied policies to ${environment}`, { policyCount: policies.length, environment }); return config; } /** * Validate configuration compliance */ async validateCompliance(environment: string): Promise<{ compliant: boolean; violations: string[]; recommendations: string[]; }> { const config = this.configurations.get(environment); if (!config) { throw new SecurityValidationError("Configuration not found", [ { message: `Environment ${environment} not found` }, ]); } const violations: string[] = []; const recommendations: string[] = []; // Check password policy compliance if (config.settings.authentication.passwordPolicy.minLength < 8) { violations.push("Password minimum length below recommended 8 characters"); } // Check encryption compliance if (!["AES-256-GCM", "ChaCha20-Poly1305"].includes(config.settings.cryptography.encryption.algorithm)) { violations.push("Weak encryption algorithm detected"); } // Check session security if (!config.settings.session.security.httpOnly || !config.settings.session.security.secure) { violations.push("Insecure session configuration"); } // Check HTTPS enforcement if (!config.settings.cryptography.tls.hsts.enabled) { recommendations.push("Enable HSTS for enhanced security"); } // Check MFA configuration if (!config.settings.authentication.mfa.enabled) { recommendations.push("Consider enabling multi-factor authentication"); } // Check compliance frameworks const requiredFrameworks = ["OWASP", "CWE"]; const configuredFrameworks = config.policies.flatMap((p) => p.compliance.frameworks); for (const framework of requiredFrameworks) { if (!configuredFrameworks.includes(framework)) { recommendations.push(`Add ${framework} compliance policies`); } } return { compliant: violations.length === 0, violations, recommendations, }; } /** * Generate default security settings */ private getDefaultSettings(): SecurityConfiguration["settings"] { return { authentication: { methods: ["password", "jwt"], passwordPolicy: { minLength: 8, requireUppercase: true, requireLowercase: true, requireNumbers: true, requireSpecialChars: true, maxAge: 90, preventReuse: 5, }, jwtSettings: { algorithm: "HS256", expiresIn: "1h", issuer: "mcp-wordpress", audience: "mcp-wordpress-users", }, rateLimiting: { maxAttempts: 5, windowMs: 900000, // 15 minutes blockDuration: 3600000, // 1 hour }, mfa: { enabled: false, methods: ["totp", "sms"], required: false, }, }, authorization: { rbac: { enabled: true, defaultRole: "user", roleHierarchy: { admin: ["editor", "user"], editor: ["user"], user: [], }, }, permissions: { strict: true, defaultDeny: true, inheritance: true, }, sessionTimeout: 3600, // 1 hour resourceAccess: { checkOrigin: true, allowedOrigins: [], csrfProtection: true, }, }, inputValidation: { sanitization: { enabled: true, htmlStripping: true, sqlEscaping: true, jsEscaping: true, }, validation: { strict: true, maxStringLength: 10000, maxFileSize: 10485760, // 10MB allowedFileTypes: ["image/jpeg", "image/png", "application/pdf"], blockedPatterns: ["<script>", "javascript:", "vbscript:"], }, xssProtection: { enabled: true, mode: "block", reportUri: "/security/xss-report", }, }, cryptography: { encryption: { algorithm: "AES-256-GCM", keyDerivation: "PBKDF2", keyRotation: { enabled: true, intervalDays: 90, }, }, hashing: { algorithm: "bcrypt", saltRounds: 12, }, tls: { minVersion: "1.2", cipherSuites: ["ECDHE-RSA-AES256-GCM-SHA384", "ECDHE-RSA-AES128-GCM-SHA256", "ECDHE-RSA-AES256-SHA384"], hsts: { enabled: true, maxAge: 31536000, // 1 year includeSubDomains: true, }, }, }, session: { storage: "memory", security: { httpOnly: true, secure: true, sameSite: "strict", }, timeout: { idle: 1800, // 30 minutes absolute: 28800, // 8 hours }, regeneration: { onLogin: true, onPrivilegeChange: true, interval: 3600, // 1 hour }, }, logging: { level: "info", security: { logFailedAuth: true, logPrivilegeEscalation: true, logDataAccess: true, logConfigChanges: true, }, retention: { days: 90, compression: true, encryption: true, }, alerting: { enabled: true, thresholds: { failedLogins: 10, privilegeEscalation: 1, dataAccess: 100, }, channels: ["email", "webhook"], }, }, monitoring: { realTime: { enabled: true, metrics: ["requests", "errors", "latency", "security_events"], alertThresholds: { errorRate: 0.05, latencyP99: 1000, securityEvents: 10, }, }, anomalyDetection: { enabled: true, sensitivity: "medium", models: ["statistical", "ml"], }, compliance: { enabled: true, frameworks: ["OWASP", "CWE"], reportingSchedule: "daily", }, }, }; } /** * Load configurations from files */ private async loadConfigurations(): Promise<void> { try { const configDir = path.join(this.configPath, "configurations"); await fs.access(configDir); const files = await fs.readdir(configDir); for (const file of files) { if (file.endsWith(".json")) { const filePath = path.join(configDir, file); const content = await fs.readFile(filePath, "utf-8"); const config: SecurityConfiguration = JSON.parse(content); // Convert date strings back to Date objects config.metadata.lastUpdated = new Date(config.metadata.lastUpdated); this.configurations.set(config.environment, config); } } } catch (_error) { logger.info("No existing configurations found, will create new ones"); } } /** * Load policies from files */ private async loadPolicies(): Promise<void> { try { const policiesDir = path.join(this.configPath, "policies"); await fs.access(policiesDir); const files = await fs.readdir(policiesDir); for (const file of files) { if (file.endsWith(".json")) { const filePath = path.join(policiesDir, file); const content = await fs.readFile(filePath, "utf-8"); const policy: SecurityPolicy = JSON.parse(content); // Convert date strings back to Date objects policy.metadata.created = new Date(policy.metadata.created); policy.metadata.updated = new Date(policy.metadata.updated); this.policies.set(policy.id, policy); } } } catch (_error) { logger.info("No existing policies found"); } } /** * Save configuration to file */ private async saveConfigurationToFile(config: SecurityConfiguration): Promise<void> { const configDir = path.join(this.configPath, "configurations"); await fs.mkdir(configDir, { recursive: true }); const filePath = path.join(configDir, `${config.environment}.json`); await fs.writeFile(filePath, JSON.stringify(config, null, 2), "utf-8"); } /** * Save policy to file */ private async savePolicyToFile(policy: SecurityPolicy): Promise<void> { const policiesDir = path.join(this.configPath, "policies"); await fs.mkdir(policiesDir, { recursive: true }); const filePath = path.join(policiesDir, `${policy.id}.json`); await fs.writeFile(filePath, JSON.stringify(policy, null, 2), "utf-8"); } /** * Ensure config directory exists */ private async ensureConfigDirectory(): Promise<void> { await fs.mkdir(this.configPath, { recursive: true }); await fs.mkdir(path.join(this.configPath, "configurations"), { recursive: true }); await fs.mkdir(path.join(this.configPath, "policies"), { recursive: true }); } /** * Calculate configuration checksum */ private async calculateChecksum(config: SecurityConfiguration): Promise<string> { const configForHash = { ...config, metadata: { ...config.metadata, checksum: "", // Exclude checksum from hash calculation }, }; const _configString = JSON.stringify(configForHash, Object.keys(configForHash).sort()); return SecurityUtils.generateSecureToken(32); } /** * Get all policies */ getAllPolicies(): SecurityPolicy[] { return Array.from(this.policies.values()); } /** * Get policy by ID */ getPolicy(policyId: string): SecurityPolicy | null { return this.policies.get(policyId) || null; } /** * Delete policy */ async deletePolicy(policyId: string): Promise<boolean> { const policy = this.policies.get(policyId); if (!policy) { return false; } this.policies.delete(policyId); try { const filePath = path.join(this.configPath, "policies", `${policyId}.json`); await fs.unlink(filePath); logger.info(`Deleted policy: ${policy.name}`, { policyId }); return true; } catch (_error) { logger.warn("Failed to delete policy file", { _error }); return false; } } /** * Export configuration */ async exportConfiguration(environment: string): Promise<string> { const config = this.configurations.get(environment); if (!config) { throw new SecurityValidationError("Configuration not found", [ { message: `Environment ${environment} not found` }, ]); } return JSON.stringify(config, null, 2); } /** * Import configuration */ async importConfiguration(configData: string): Promise<SecurityConfiguration> { try { const config: SecurityConfiguration = JSON.parse(configData); // Validate configuration structure if (!config.configId || !config.environment) { throw new Error("Invalid configuration format"); } // Convert date strings to Date objects config.metadata.lastUpdated = new Date(config.metadata.lastUpdated); this.configurations.set(config.environment, config); await this.saveConfigurationToFile(config); logger.info(`Imported configuration for environment: ${config.environment}`, { environment: config.environment }); return config; } catch (_error) { throw new SecurityValidationError("Failed to import configuration", [{ message: String(_error) }]); } } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/docdyhr/mcp-wordpress'

If you have feedback or need assistance with the MCP directory API, please join our Discord server