import * as plugins from '../../plugins.ts'; import * as interfaces from '../../../ts_interfaces/index.ts'; import type { OpsServer } from '../classes.opsserver.ts'; import { requireAdminIdentity } from '../helpers/guards.ts'; import { AuthProvider, PlatformSettings } from '../../models/index.ts'; import { cryptoService } from '../../services/crypto.service.ts'; import { externalAuthService } from '../../services/external.auth.service.ts'; import { AuditService } from '../../services/audit.service.ts'; export class AdminHandler { public typedrouter = new plugins.typedrequest.TypedRouter(); constructor(private opsServerRef: OpsServer) { this.opsServerRef.typedrouter.addTypedRouter(this.typedrouter); this.registerHandlers(); } private registerHandlers(): void { // Get Admin Providers this.typedrouter.addTypedHandler( new plugins.typedrequest.TypedHandler( 'getAdminProviders', async (dataArg) => { await requireAdminIdentity(this.opsServerRef.authHandler, dataArg); try { const providers = await AuthProvider.getAllProviders(); return { providers: providers.map((p) => p.toAdminInfo()), }; } catch (error) { if (error instanceof plugins.typedrequest.TypedResponseError) throw error; throw new plugins.typedrequest.TypedResponseError('Failed to list providers'); } }, ), ); // Create Admin Provider this.typedrouter.addTypedHandler( new plugins.typedrequest.TypedHandler( 'createAdminProvider', async (dataArg) => { await requireAdminIdentity(this.opsServerRef.authHandler, dataArg); try { const { name, displayName, type, oauthConfig, ldapConfig, attributeMapping, provisioning } = dataArg; // Validate required fields if (!name || !displayName || !type) { throw new plugins.typedrequest.TypedResponseError( 'name, displayName, and type are required', ); } // Check name uniqueness const existing = await AuthProvider.findByName(name); if (existing) { throw new plugins.typedrequest.TypedResponseError('Provider name already exists'); } // Validate type-specific config if (type === 'oidc' && !oauthConfig) { throw new plugins.typedrequest.TypedResponseError( 'oauthConfig is required for OIDC provider', ); } if (type === 'ldap' && !ldapConfig) { throw new plugins.typedrequest.TypedResponseError( 'ldapConfig is required for LDAP provider', ); } let provider: AuthProvider; if (type === 'oidc' && oauthConfig) { // Encrypt client secret const encryptedSecret = await cryptoService.encrypt( oauthConfig.clientSecretEncrypted, ); provider = await AuthProvider.createOAuthProvider({ name, displayName, oauthConfig: { ...oauthConfig, clientSecretEncrypted: encryptedSecret, }, attributeMapping, provisioning, createdById: dataArg.identity.userId, }); } else if (type === 'ldap' && ldapConfig) { // Encrypt bind password const encryptedPassword = await cryptoService.encrypt( ldapConfig.bindPasswordEncrypted, ); provider = await AuthProvider.createLdapProvider({ name, displayName, ldapConfig: { ...ldapConfig, bindPasswordEncrypted: encryptedPassword, }, attributeMapping, provisioning, createdById: dataArg.identity.userId, }); } else { throw new plugins.typedrequest.TypedResponseError('Invalid provider type'); } // Audit log await AuditService.withContext({ actorId: dataArg.identity.userId, actorType: 'user', }).log('AUTH_PROVIDER_CREATED', 'auth_provider', { resourceId: provider.id, success: true, metadata: { providerName: provider.name, providerType: provider.type, }, }); return { provider: provider.toAdminInfo() }; } catch (error) { if (error instanceof plugins.typedrequest.TypedResponseError) throw error; throw new plugins.typedrequest.TypedResponseError('Failed to create provider'); } }, ), ); // Get Admin Provider this.typedrouter.addTypedHandler( new plugins.typedrequest.TypedHandler( 'getAdminProvider', async (dataArg) => { await requireAdminIdentity(this.opsServerRef.authHandler, dataArg); try { const provider = await AuthProvider.findById(dataArg.providerId); if (!provider) { throw new plugins.typedrequest.TypedResponseError('Provider not found'); } return { provider: provider.toAdminInfo() }; } catch (error) { if (error instanceof plugins.typedrequest.TypedResponseError) throw error; throw new plugins.typedrequest.TypedResponseError('Failed to get provider'); } }, ), ); // Update Admin Provider this.typedrouter.addTypedHandler( new plugins.typedrequest.TypedHandler( 'updateAdminProvider', async (dataArg) => { await requireAdminIdentity(this.opsServerRef.authHandler, dataArg); try { const provider = await AuthProvider.findById(dataArg.providerId); if (!provider) { throw new plugins.typedrequest.TypedResponseError('Provider not found'); } // Update basic fields if (dataArg.displayName !== undefined) provider.displayName = dataArg.displayName; if (dataArg.status !== undefined) provider.status = dataArg.status as any; if (dataArg.priority !== undefined) provider.priority = dataArg.priority; // Update OAuth config if (dataArg.oauthConfig && provider.oauthConfig) { const newOAuthConfig = { ...provider.oauthConfig, ...dataArg.oauthConfig }; // Encrypt new client secret if provided and not already encrypted if ( dataArg.oauthConfig.clientSecretEncrypted && !cryptoService.isEncrypted(dataArg.oauthConfig.clientSecretEncrypted) ) { newOAuthConfig.clientSecretEncrypted = await cryptoService.encrypt( dataArg.oauthConfig.clientSecretEncrypted, ); } provider.oauthConfig = newOAuthConfig; } // Update LDAP config if (dataArg.ldapConfig && provider.ldapConfig) { const newLdapConfig = { ...provider.ldapConfig, ...dataArg.ldapConfig }; // Encrypt new bind password if provided and not already encrypted if ( dataArg.ldapConfig.bindPasswordEncrypted && !cryptoService.isEncrypted(dataArg.ldapConfig.bindPasswordEncrypted) ) { newLdapConfig.bindPasswordEncrypted = await cryptoService.encrypt( dataArg.ldapConfig.bindPasswordEncrypted, ); } provider.ldapConfig = newLdapConfig; } // Update attribute mapping if (dataArg.attributeMapping) { provider.attributeMapping = { ...provider.attributeMapping, ...dataArg.attributeMapping, } as any; } // Update provisioning settings if (dataArg.provisioning) { provider.provisioning = { ...provider.provisioning, ...dataArg.provisioning, } as any; } await provider.save(); // Audit log await AuditService.withContext({ actorId: dataArg.identity.userId, actorType: 'user', }).log('AUTH_PROVIDER_UPDATED', 'auth_provider', { resourceId: provider.id, success: true, metadata: { providerName: provider.name }, }); return { provider: provider.toAdminInfo() }; } catch (error) { if (error instanceof plugins.typedrequest.TypedResponseError) throw error; throw new plugins.typedrequest.TypedResponseError('Failed to update provider'); } }, ), ); // Delete Admin Provider this.typedrouter.addTypedHandler( new plugins.typedrequest.TypedHandler( 'deleteAdminProvider', async (dataArg) => { await requireAdminIdentity(this.opsServerRef.authHandler, dataArg); try { const provider = await AuthProvider.findById(dataArg.providerId); if (!provider) { throw new plugins.typedrequest.TypedResponseError('Provider not found'); } // Soft delete - disable instead of removing provider.status = 'disabled'; await provider.save(); // Audit log await AuditService.withContext({ actorId: dataArg.identity.userId, actorType: 'user', }).log('AUTH_PROVIDER_DELETED', 'auth_provider', { resourceId: provider.id, success: true, metadata: { providerName: provider.name }, }); return { message: 'Provider disabled' }; } catch (error) { if (error instanceof plugins.typedrequest.TypedResponseError) throw error; throw new plugins.typedrequest.TypedResponseError('Failed to delete provider'); } }, ), ); // Test Admin Provider this.typedrouter.addTypedHandler( new plugins.typedrequest.TypedHandler( 'testAdminProvider', async (dataArg) => { await requireAdminIdentity(this.opsServerRef.authHandler, dataArg); try { const result = await externalAuthService.testConnection(dataArg.providerId); // Audit log await AuditService.withContext({ actorId: dataArg.identity.userId, actorType: 'user', }).log('AUTH_PROVIDER_TESTED', 'auth_provider', { resourceId: dataArg.providerId, success: result.success, metadata: { result: result.success ? 'success' : 'failure', latencyMs: result.latencyMs, error: result.error, }, }); return { result }; } catch (error) { if (error instanceof plugins.typedrequest.TypedResponseError) throw error; throw new plugins.typedrequest.TypedResponseError('Failed to test provider'); } }, ), ); // Get Platform Settings this.typedrouter.addTypedHandler( new plugins.typedrequest.TypedHandler( 'getPlatformSettings', async (dataArg) => { await requireAdminIdentity(this.opsServerRef.authHandler, dataArg); try { const settings = await PlatformSettings.get(); return { settings: { id: settings.id, auth: settings.auth, updatedAt: settings.updatedAt instanceof Date ? settings.updatedAt.toISOString() : String(settings.updatedAt), updatedById: settings.updatedById, }, }; } catch (error) { if (error instanceof plugins.typedrequest.TypedResponseError) throw error; throw new plugins.typedrequest.TypedResponseError('Failed to get settings'); } }, ), ); // Update Platform Settings this.typedrouter.addTypedHandler( new plugins.typedrequest.TypedHandler( 'updatePlatformSettings', async (dataArg) => { await requireAdminIdentity(this.opsServerRef.authHandler, dataArg); try { const settings = await PlatformSettings.get(); if (dataArg.auth) { await settings.updateAuthSettings(dataArg.auth as any, dataArg.identity.userId); } // Audit log await AuditService.withContext({ actorId: dataArg.identity.userId, actorType: 'user', }).log('PLATFORM_SETTINGS_UPDATED', 'platform_settings', { resourceId: 'platform-settings', success: true, }); return { settings: { id: settings.id, auth: settings.auth, updatedAt: settings.updatedAt instanceof Date ? settings.updatedAt.toISOString() : String(settings.updatedAt), updatedById: settings.updatedById, }, }; } catch (error) { if (error instanceof plugins.typedrequest.TypedResponseError) throw error; throw new plugins.typedrequest.TypedResponseError('Failed to update settings'); } }, ), ); } }