apps/api: remove ldap module and replace with utils

This commit is contained in:
vchikalkin 2023-10-31 17:29:01 +03:00
parent a8179a324a
commit f1114cb703
16 changed files with 69 additions and 105 deletions

View File

@ -2,7 +2,6 @@ import { AppController } from './app.controller';
import { AppService } from './app.service';
import { AuthModule } from './auth/auth.module';
import { env } from './config/env';
import { LdapModule } from './ldap/ldap.module';
import { UsersModule } from './users/users.module';
import { Global, Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
@ -25,7 +24,6 @@ import { MongooseModule } from '@nestjs/mongoose';
}),
AuthModule,
UsersModule,
LdapModule,
MongooseModule.forRoot(`mongodb://${env.MONGO_HOST}`),
],
providers: [AppService],

View File

@ -2,7 +2,7 @@
/* eslint-disable class-methods-use-this */
/* eslint-disable import/no-extraneous-dependencies */
import { AuthService } from './auth.service';
import { Credentials } from './types/request';
import { Credentials } from './dto/credentials';
import type { CookieSerializeOptions } from '@fastify/cookie';
import { Body, Controller, Get, HttpException, HttpStatus, Post, Req, Res } from '@nestjs/common';
import { FastifyReply, FastifyRequest } from 'fastify';

View File

@ -1,4 +1,3 @@
import { LdapModule } from '../ldap/ldap.module';
import { UsersModule } from '../users/users.module';
import { AuthController } from './auth.controller';
import { AuthService } from './auth.service';
@ -6,7 +5,7 @@ import { Module } from '@nestjs/common';
@Module({
controllers: [AuthController],
imports: [UsersModule, LdapModule],
imports: [UsersModule],
providers: [AuthService],
})
// eslint-disable-next-line @typescript-eslint/no-extraneous-class

View File

@ -1,20 +1,19 @@
import { LdapService } from '../ldap/ldap.service';
import { UsersCache } from '../users/users.cache';
import type { DecodedToken, TokenPayload } from './types/jwt';
import { Injectable } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { env } from 'src/config/env';
import * as ldap from 'src/utils/ldap';
@Injectable()
export class AuthService {
constructor(
private readonly ldapService: LdapService,
private readonly usersCache: UsersCache,
private readonly jwtService: JwtService
) {}
public async login(login: string, password: string) {
const user = await this.ldapService.authenticate(login, password);
const user = await ldap.authenticate(login, password);
const { username } = user;
await this.usersCache.addUser(username, user);

View File

@ -0,0 +1,4 @@
export class Credentials {
readonly login: string;
readonly password: string;
}

View File

@ -1,6 +1,6 @@
export type TokenPayload = {
username: string;
domain: string;
username: string;
};
export type DecodedToken = {

View File

@ -1,4 +0,0 @@
export type Credentials = {
login: string;
password: string;
};

View File

@ -1,9 +0,0 @@
import { LdapService } from './ldap.service';
import { Module } from '@nestjs/common';
@Module({
exports: [LdapService],
providers: [LdapService],
})
// eslint-disable-next-line @typescript-eslint/no-extraneous-class
export class LdapModule {}

View File

@ -1,19 +0,0 @@
import { LdapService } from './ldap.service';
import type { TestingModule } from '@nestjs/testing';
import { Test } from '@nestjs/testing';
describe('LdapService', () => {
let service: LdapService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [LdapService],
}).compile();
service = module.get<LdapService>(LdapService);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
});

View File

@ -1,44 +0,0 @@
import { env } from '../config/env';
import type { User } from '../types/user';
import type { LdapUser } from './types/user';
import { Injectable } from '@nestjs/common';
import type { AuthenticationOptions } from 'ldap-authentication';
import { authenticate } from 'ldap-authentication';
@Injectable()
export class LdapService {
public async authenticate(login: string, password?: string) {
const options: AuthenticationOptions = {
adminDn: env.LDAP_BIND_DN,
adminPassword: env.LDAP_BIND_CREDENTIALS,
ldapOpts: {
url: env.LDAP_URL,
},
userPassword: password,
userSearchBase: env.LDAP_BASE,
username: login,
usernameAttribute: env.LDAP_ATTRIBUTE,
verifyUserExists: password === undefined,
};
const {
displayName,
department,
title,
mail,
sAMAccountName: username,
}: LdapUser = await authenticate(options);
const user: User = {
department,
displayName,
domain: env.LDAP_DOMAIN,
domainName: `${env.LDAP_DOMAIN}\\${username}`,
mail,
position: title,
username,
};
return user;
}
}

View File

@ -1,9 +0,0 @@
export type User = {
department: string;
displayName: string;
domain: string;
domainName: string;
mail: string;
position: string;
username: string;
};

View File

@ -1,4 +1,3 @@
import type { User } from '../types/user';
import { CACHE_MANAGER } from '@nestjs/cache-manager';
import { Inject, Injectable } from '@nestjs/common';
import { Cache } from 'cache-manager';
@ -6,15 +5,15 @@ import { Cache } from 'cache-manager';
@Injectable()
export class UsersCache {
constructor(@Inject(CACHE_MANAGER) private readonly cacheManager: Cache) {}
async getUser(username: string) {
return (await this.cacheManager.get(username)) as User;
public async getUser<T extends object>(username: string) {
return (await this.cacheManager.get(username)) as T;
}
async addUser(username: string, user: User) {
public async addUser<T extends object>(username: string, user: T) {
await this.cacheManager.set(username, user);
}
async deleteUser(username: string) {
public async deleteUser(username: string) {
if (this.cacheManager.get(username)) {
await this.cacheManager.del(username);
}

View File

@ -1,4 +1,3 @@
import { LdapModule } from '../ldap/ldap.module';
import { UsersCache } from './users.cache';
import { UsersController } from './users.controller';
import { UsersService } from './users.service';
@ -20,7 +19,6 @@ import { User, UserSchema } from 'src/schemas/user.schema';
store: redisStore,
ttl: env.API_CACHE_TTL,
}),
LdapModule,
MongooseModule.forFeature([{ name: User.name, schema: UserSchema }]),
],
providers: [UsersService, UsersCache],

View File

@ -1,5 +1,4 @@
import type { DecodedToken } from '../auth/types/jwt';
import { LdapService } from '../ldap/ldap.service';
import type { CreateUserDto } from './dto/create-user.dto';
import { UsersCache } from './users.cache';
import { Injectable, NotFoundException, UnauthorizedException } from '@nestjs/common';
@ -8,14 +7,14 @@ import { InjectModel } from '@nestjs/mongoose';
import * as bcrypt from 'bcrypt';
import { Model } from 'mongoose';
import { User } from 'src/schemas/user.schema';
import { generatePassword } from 'utils/password';
import * as ldap from 'src/utils/ldap';
import { generatePassword } from 'src/utils/password';
@Injectable()
export class UsersService {
constructor(
private readonly usersCache: UsersCache,
private readonly jwtService: JwtService,
private readonly ldapService: LdapService,
@InjectModel(User.name)
private userModel: Model<User>
) {}
@ -26,7 +25,7 @@ export class UsersService {
const cachedUser = await this.usersCache.getUser(username);
if (!cachedUser) {
const user = await this.ldapService.authenticate(username);
const user = await ldap.authenticate(username);
await this.usersCache.addUser(username, user);

View File

@ -1,3 +1,17 @@
import type { AuthenticationOptions } from 'ldap-authentication';
import * as ldap from 'ldap-authentication';
import { env } from 'src/config/env';
export type User = {
department: string;
displayName: string;
domain: string;
domainName: string;
mail: string;
position: string;
username: string;
};
export type LdapUser = {
accountExpires: string;
badPasswordTime: string;
@ -61,3 +75,42 @@ export type LdapUser = {
whenChanged: string;
whenCreated: string;
};
const BASE_OPTIONS: AuthenticationOptions = {
adminDn: env.LDAP_BIND_DN,
adminPassword: env.LDAP_BIND_CREDENTIALS,
ldapOpts: {
url: env.LDAP_URL,
},
userSearchBase: env.LDAP_BASE,
usernameAttribute: env.LDAP_ATTRIBUTE,
};
export async function authenticate(login: string, password?: string) {
const options: AuthenticationOptions = {
...BASE_OPTIONS,
userPassword: password,
username: login,
verifyUserExists: password === undefined,
};
const {
displayName,
department,
title,
mail,
sAMAccountName: username,
}: LdapUser = await ldap.authenticate(options);
const user: User = {
department,
displayName,
domain: env.LDAP_DOMAIN,
domainName: `${env.LDAP_DOMAIN}\\${username}`,
mail,
position: title,
username,
};
return user;
}