import { Injectable, Logger } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; import { Client, Attribute, Change } from 'ldapts'; @Injectable() export class ActiveDirectoryService { private readonly logger = new Logger(ActiveDirectoryService.name); constructor(private configService: ConfigService) { } private createClient(): Client { return new Client({ url: this.configService.get('AD_URL')!, tlsOptions: { rejectUnauthorized: false }, }); } async createUser(cuenta: string): Promise { const client = this.createClient(); const bindDN = this.configService.get('AD_BIND_DN')!; const bindPass = this.configService.get('AD_BIND_PASS')!; const baseDN = this.configService.get('AD_BASE_DN')!; try { await client.bind(bindDN, bindPass); const userDN = `CN=${cuenta},${baseDN}`; await client.add(userDN, { objectClass: ['top', 'person', 'organizationalPerson', 'user'], sAMAccountName: cuenta, cn: cuenta, description: 'Creado desde el Sitio', userAccountControl: '32', }); const encodedPassword = Buffer.from(`"${cuenta}"`, 'utf16le'); await client.modify(userDN, [ new Change({ operation: 'replace', modification: new Attribute({ type: 'unicodePwd', values: [encodedPassword] }), }), ]); await client.modify(userDN, [ new Change({ operation: 'replace', modification: new Attribute({ type: 'pwdLastSet', values: ['0'] }), }), ]); await client.modify(userDN, [ new Change({ operation: 'replace', modification: new Attribute({ type: 'userAccountControl', values: ['512'] }), }), ]); this.logger.log(`Usuario ${cuenta} creado exitosamente en AD`); } catch (error) { this.logger.error(`Error al crear usuario ${cuenta} en AD`, error); throw error; } finally { await client.unbind(); } } async resetPassword(cuenta: string): Promise { const client = this.createClient(); const bindDN = this.configService.get('AD_BIND_DN')!; const bindPass = this.configService.get('AD_BIND_PASS')!; const baseDN = this.configService.get('AD_BASE_DN')!; try { await client.bind(bindDN, bindPass); const userDN = `CN=${cuenta},${baseDN}`; await client.del(userDN); this.logger.log(`Usuario ${cuenta} eliminado de AD`); } catch (error) { this.logger.warn(`No se pudo eliminar ${cuenta} de AD (puede no existir)`, error); } finally { await client.unbind(); } await this.createUser(cuenta); } async changePassword(cuenta: string, newPass?: string): Promise { const client = this.createClient(); const bindDN = this.configService.get('AD_BIND_DN')!; const bindPass = this.configService.get('AD_BIND_PASS')!; const baseDN = this.configService.get('AD_BASE_DN')!; const password = newPass ?? cuenta; try { await client.bind(bindDN, bindPass); const userDN = `CN=${cuenta},${baseDN}`; const encodedPassword = Buffer.from(`"${password}"`, 'utf16le'); await client.modify(userDN, [ new Change({ operation: 'replace', modification: new Attribute({ type: 'unicodePwd', values: [encodedPassword] }), }), ]); await client.modify(userDN, [ new Change({ operation: 'replace', modification: new Attribute({ type: 'pwdLastSet', values: ['0'] }), }), ]); this.logger.log(`ContraseƱa de ${cuenta} actualizada`); } catch (error) { this.logger.error(`Error al cambiar contraseƱa de ${cuenta}`, error); throw error; } finally { await client.unbind(); } } }