created active-directory
This commit is contained in:
Generated
+364
-656
File diff suppressed because it is too large
Load Diff
@@ -30,6 +30,7 @@
|
||||
"@nestjs/typeorm": "^11.0.0",
|
||||
"class-transformer": "^0.5.1",
|
||||
"class-validator": "^0.14.2",
|
||||
"ldapts": "^8.1.7",
|
||||
"mysql2": "^3.14.4",
|
||||
"passport": "^0.7.0",
|
||||
"passport-jwt": "^4.0.1",
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { ActiveDirectoryController } from './active-directory.controller';
|
||||
import { ActiveDirectoryService } from './active-directory.service';
|
||||
|
||||
describe('ActiveDirectoryController', () => {
|
||||
let controller: ActiveDirectoryController;
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
controllers: [ActiveDirectoryController],
|
||||
providers: [ActiveDirectoryService],
|
||||
}).compile();
|
||||
|
||||
controller = module.get<ActiveDirectoryController>(ActiveDirectoryController);
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(controller).toBeDefined();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,28 @@
|
||||
import { Controller, Post, Body, Param } from '@nestjs/common';
|
||||
import { ActiveDirectoryService } from './active-directory.service';
|
||||
|
||||
@Controller('active-directory')
|
||||
export class ActiveDirectoryController {
|
||||
constructor(private readonly adService: ActiveDirectoryService) {}
|
||||
|
||||
@Post('crear/:cuenta')
|
||||
async crearUsuario(@Param('cuenta') cuenta: string) {
|
||||
await this.adService.createUser(cuenta);
|
||||
return { message: `Usuario ${cuenta} creado en AD` };
|
||||
}
|
||||
|
||||
@Post('reset/:cuenta')
|
||||
async resetPassword(@Param('cuenta') cuenta: string) {
|
||||
await this.adService.resetPassword(cuenta);
|
||||
return { message: `Contraseña de ${cuenta} reseteada` };
|
||||
}
|
||||
|
||||
@Post('cambiar-password/:cuenta')
|
||||
async cambiarPassword(
|
||||
@Param('cuenta') cuenta: string,
|
||||
@Body('password') password?: string,
|
||||
) {
|
||||
await this.adService.changePassword(cuenta, password);
|
||||
return { message: `Contraseña de ${cuenta} actualizada` };
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { ConfigModule } from '@nestjs/config';
|
||||
import { ActiveDirectoryService } from './active-directory.service';
|
||||
import { ActiveDirectoryController } from './active-directory.controller';
|
||||
|
||||
@Module({
|
||||
imports: [ConfigModule],
|
||||
providers: [ActiveDirectoryService],
|
||||
controllers: [ActiveDirectoryController],
|
||||
exports: [ActiveDirectoryService],
|
||||
})
|
||||
export class ActiveDirectoryModule {}
|
||||
@@ -0,0 +1,18 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { ActiveDirectoryService } from './active-directory.service';
|
||||
|
||||
describe('ActiveDirectoryService', () => {
|
||||
let service: ActiveDirectoryService;
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
providers: [ActiveDirectoryService],
|
||||
}).compile();
|
||||
|
||||
service = module.get<ActiveDirectoryService>(ActiveDirectoryService);
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(service).toBeDefined();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,124 @@
|
||||
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<string>('AD_URL')!,
|
||||
tlsOptions: { rejectUnauthorized: false },
|
||||
});
|
||||
}
|
||||
|
||||
async createUser(cuenta: string): Promise<void> {
|
||||
const client = this.createClient();
|
||||
const bindDN = this.configService.get<string>('AD_BIND_DN')!;
|
||||
const bindPass = this.configService.get<string>('AD_BIND_PASS')!;
|
||||
const baseDN = this.configService.get<string>('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<void> {
|
||||
const client = this.createClient();
|
||||
const bindDN = this.configService.get<string>('AD_BIND_DN')!;
|
||||
const bindPass = this.configService.get<string>('AD_BIND_PASS')!;
|
||||
const baseDN = this.configService.get<string>('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<void> {
|
||||
const client = this.createClient();
|
||||
const bindDN = this.configService.get<string>('AD_BIND_DN')!;
|
||||
const bindPass = this.configService.get<string>('AD_BIND_PASS')!;
|
||||
const baseDN = this.configService.get<string>('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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export class CreateActiveDirectoryDto {}
|
||||
@@ -0,0 +1,4 @@
|
||||
import { PartialType } from '@nestjs/mapped-types';
|
||||
import { CreateActiveDirectoryDto } from './create-active-directory.dto';
|
||||
|
||||
export class UpdateActiveDirectoryDto extends PartialType(CreateActiveDirectoryDto) {}
|
||||
@@ -0,0 +1 @@
|
||||
export class ActiveDirectory {}
|
||||
@@ -43,6 +43,7 @@ import { BitacoraModule } from './bitacora/bitacora.module';
|
||||
import { Bitacora } from './bitacora/entities/bitacora.entity';
|
||||
import { MensajeModule } from './mensaje/mensaje.module';
|
||||
import { Mensaje } from './mensaje/entities/mensaje.entity';
|
||||
import { ActiveDirectoryModule } from './active-directory/active-directory.module';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
@@ -103,6 +104,7 @@ import { Mensaje } from './mensaje/entities/mensaje.entity';
|
||||
BitacoraMesaModule,
|
||||
BitacoraModule,
|
||||
MensajeModule,
|
||||
ActiveDirectoryModule,
|
||||
],
|
||||
controllers: [AppController],
|
||||
providers: [AppService],
|
||||
|
||||
Reference in New Issue
Block a user