Files
registry/ts/opsserver/handlers/admin.handler.ts

381 lines
14 KiB
TypeScript
Raw Normal View History

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<interfaces.requests.IReq_GetAdminProviders>(
'getAdminProviders',
async (dataArg) => {
await requireAdminIdentity(this.opsServerRef.authHandler, dataArg);
try {
const providers = await AuthProvider.getAllProviders();
return {
providers: providers.map((p) => p.toAdminInfo() as unknown as interfaces.data.IAuthProvider),
};
} 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<interfaces.requests.IReq_CreateAdminProvider>(
'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() as unknown as interfaces.data.IAuthProvider };
} 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<interfaces.requests.IReq_GetAdminProvider>(
'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() as unknown as interfaces.data.IAuthProvider };
} 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<interfaces.requests.IReq_UpdateAdminProvider>(
'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() as unknown as interfaces.data.IAuthProvider };
} 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<interfaces.requests.IReq_DeleteAdminProvider>(
'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<interfaces.requests.IReq_TestAdminProvider>(
'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<interfaces.requests.IReq_GetPlatformSettings>(
'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<interfaces.requests.IReq_UpdatePlatformSettings>(
'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');
}
},
),
);
}
}