diff --git a/src/domain/usecases/user-monitoring/two-factor-monitoring/RunTwoFactorReportUseCase.ts b/src/domain/usecases/user-monitoring/two-factor-monitoring/RunTwoFactorReportUseCase.ts index 7346cc3..c629e37 100644 --- a/src/domain/usecases/user-monitoring/two-factor-monitoring/RunTwoFactorReportUseCase.ts +++ b/src/domain/usecases/user-monitoring/two-factor-monitoring/RunTwoFactorReportUseCase.ts @@ -3,11 +3,12 @@ import { TwoFactorUserD2Repository } from "data/user-monitoring/two-factor-monit import { TwoFactorConfigD2Repository } from "data/user-monitoring/two-factor-monitoring/TwoFactorConfigD2Repository"; import { UserMonitoringProgramD2Repository } from "data/user-monitoring/common/UserMonitoringProgramD2Repository"; import { TwoFactorReportD2Repository } from "data/user-monitoring/two-factor-monitoring/TwoFactorReportD2Repository"; -import log from "utils/log"; import { TwoFactorUserReport } from "domain/entities/user-monitoring/two-factor-monitoring/TwoFactorUserReport"; import { Async } from "domain/entities/Async"; import { NonUsersException } from "domain/entities/user-monitoring/two-factor-monitoring/exception/NonUsersException"; +type TwoFactorReportResponse = { message: string; report: TwoFactorUserReport }; + export class RunTwoFactorReportUseCase { constructor( private userRepository: TwoFactorUserD2Repository, @@ -16,10 +17,10 @@ export class RunTwoFactorReportUseCase { private programRepository: UserMonitoringProgramD2Repository ) {} - async execute(): Async { + async execute(): Async { const options = await this.configRepository.get(); - const twoFactorGroupUsers = await this.userRepository.getUsersByGroupId([options.twoFactorGroup.id]); + if (!twoFactorGroupUsers) { throw new NonUsersException( "Users not found in the group. Check the group id. " + options.twoFactorGroup.id @@ -32,13 +33,12 @@ export class RunTwoFactorReportUseCase { const userItems = usersWithoutTwoFactor.map(user => { return { id: user.id, name: user.username }; }); - const response: TwoFactorUserReport = { + const report: TwoFactorUserReport = { invalidUsersCount: userItems.length, listOfAffectedUsers: userItems, }; - log.info("Users without two factor: " + userItems.length); const programMetadata = await this.programRepository.get(options.pushProgram.id); - const saveResponse = await this.reportRepository.save(programMetadata, response); - return saveResponse; + const saveResponse = await this.reportRepository.save(programMetadata, report); + return { message: saveResponse, report }; } } diff --git a/src/domain/usecases/user-monitoring/two-factor-monitoring/__tests__/TwoFactorReportUseCase.specs.ts b/src/domain/usecases/user-monitoring/two-factor-monitoring/__tests__/TwoFactorReportUseCase.specs.ts new file mode 100644 index 0000000..c98cc1e --- /dev/null +++ b/src/domain/usecases/user-monitoring/two-factor-monitoring/__tests__/TwoFactorReportUseCase.specs.ts @@ -0,0 +1,139 @@ +import { describe, it, expect } from "vitest"; + +import { RunTwoFactorReportUseCase } from "../RunTwoFactorReportUseCase"; +import { TwoFactorConfigD2Repository } from "data/user-monitoring/two-factor-monitoring/TwoFactorConfigD2Repository"; +import { anything, deepEqual, instance, mock, when } from "ts-mockito"; +import { + config, + listOfUsers, + listOfUsersWithTwoInvalid, + listOfUsersWithTwoValid, + userWithoutTwoFA, + userWithTwoFA, +} from "./TwoFactorTest.data"; +import { TwoFactorUserD2Repository } from "data/user-monitoring/two-factor-monitoring/TwoFactorUserD2Repository"; +import { TwoFactorReportD2Repository } from "data/user-monitoring/two-factor-monitoring/TwoFactorReportD2Repository"; +import { UserMonitoringProgramD2Repository } from "data/user-monitoring/common/UserMonitoringProgramD2Repository"; +import { TwoFactorUser } from "domain/entities/user-monitoring/two-factor-monitoring/TwoFactorUser"; +import { NonUsersException } from "domain/entities/user-monitoring/two-factor-monitoring/exception/NonUsersException"; + +describe("TwoFactorReportUseCase", () => { + it("Should push report with 0 affected users and empty affected user list if one user has two factor activated", async () => { + const useCase = givenUsers([userWithTwoFA]); + + const result = await useCase.execute(); + + expect(result.report.invalidUsersCount).toEqual(0); + expect(result.report.listOfAffectedUsers).toEqual([]); + expect(result.message).toEqual("OK"); + }); + + it("Should push report with 0 affected users and empty affected user list if all the users has two factor activated", async () => { + const useCase = givenUsers([userWithTwoFA, userWithTwoFA]); + + const result = await useCase.execute(); + + expect(result.report.invalidUsersCount).toEqual(0); + expect(result.report.listOfAffectedUsers).toEqual([]); + expect(result.message).toEqual("OK"); + }); + + it("Should push report with 1 affected users and 1 affected user list if 1 user has two factor deactivated", async () => { + const useCase = givenUsers([userWithoutTwoFA]); + + const result = await useCase.execute(); + + const expectedReport = { id: userWithoutTwoFA.id, name: userWithoutTwoFA.username }; + expect(result.report.invalidUsersCount).toEqual(1); + expect(result.report.listOfAffectedUsers).toEqual([expectedReport]); + expect(result.message).toEqual("OK"); + }); + + it("Should push report 1 affected user if we provide a list with two users, and only one has two-factor authentication disabled.", async () => { + const useCase = givenUsers(listOfUsers); + + const result = await useCase.execute(); + + const expectedReport = { id: userWithoutTwoFA.id, name: userWithoutTwoFA.username }; + expect(result.report.invalidUsersCount).toEqual(1); + expect(result.report.listOfAffectedUsers).toEqual([expectedReport]); + expect(result.message).toEqual("OK"); + }); + + it("Should push report 2 affected users and a list of 2 affected user if 2 user has two factor deactivate and 1 activated", async () => { + const useCase = givenUsers(listOfUsersWithTwoInvalid); + + const result = await useCase.execute(); + + const expectedReport = [ + { id: userWithoutTwoFA.id, name: userWithoutTwoFA.username }, + { id: userWithoutTwoFA.id, name: userWithoutTwoFA.username }, + ]; + expect(result.report.invalidUsersCount).toEqual(2); + expect(result.report.listOfAffectedUsers).toEqual(expectedReport); + expect(result.message).toEqual("OK"); + }); + + it("Should push report 1 affected users and a list of 1 affected user if 1 user has two factor deactivate and 2 activated", async () => { + const useCase = givenUsers(listOfUsersWithTwoValid); + + const result = await useCase.execute(); + + const expectedReport = [{ id: userWithoutTwoFA.id, name: userWithoutTwoFA.username }]; + expect(result.report.invalidUsersCount).toEqual(1); + expect(result.report.listOfAffectedUsers).toEqual(expectedReport); + expect(result.message).toEqual("OK"); + }); + + it("Should throw exception if no users in the given usergroup", async () => { + const useCase = givenInvalidUserGroupId(); + + await expect(async () => { + await useCase.execute(); + }).rejects.toThrow(NonUsersException); + }); +}); + +function givenUsers(users: TwoFactorUser[]) { + const useCase = new RunTwoFactorReportUseCase( + givenUserRepository(users, config.twoFactorGroup.id), + givenTwoFactorReportD2Repository(), + givenConfigRepository(), + givenUserMonitoringProgramD2Repository() + ); + return useCase; +} +function givenInvalidUserGroupId() { + const useCase = new RunTwoFactorReportUseCase( + givenUserRepository([], "invalidGroupId"), + givenTwoFactorReportD2Repository(), + givenConfigRepository(), + givenUserMonitoringProgramD2Repository() + ); + return useCase; +} + +function givenUserRepository(users: TwoFactorUser[], groupId = config.twoFactorGroup.id) { + const mockedRepository = mock(TwoFactorUserD2Repository); + when(mockedRepository.getUsersByGroupId(deepEqual([groupId]))).thenReturn(Promise.resolve(users)); + const configRepository = instance(mockedRepository); + return configRepository; +} +function givenTwoFactorReportD2Repository() { + const mockedRepository = mock(TwoFactorReportD2Repository); + when(mockedRepository.save(anything(), anything())).thenReturn(Promise.resolve("OK")); + const reportRepository = instance(mockedRepository); + return reportRepository; +} +function givenUserMonitoringProgramD2Repository() { + const mockedRepository = mock(UserMonitoringProgramD2Repository); + const reportRepository = instance(mockedRepository); + return reportRepository; +} + +function givenConfigRepository() { + const mockedRepository = mock(TwoFactorConfigD2Repository); + when(mockedRepository.get()).thenReturn(Promise.resolve(config)); + const configRepository = instance(mockedRepository); + return configRepository; +} diff --git a/src/domain/usecases/user-monitoring/two-factor-monitoring/__tests__/TwoFactorTest.data.ts b/src/domain/usecases/user-monitoring/two-factor-monitoring/__tests__/TwoFactorTest.data.ts new file mode 100644 index 0000000..45ef694 --- /dev/null +++ b/src/domain/usecases/user-monitoring/two-factor-monitoring/__tests__/TwoFactorTest.data.ts @@ -0,0 +1,35 @@ +import { UserMonitoringProgramMetadata } from "domain/entities/user-monitoring/common/UserMonitoringProgramMetadata"; +import { TwoFactorUser } from "domain/entities/user-monitoring/two-factor-monitoring/TwoFactorUser"; +import { TwoFactorUserOptions } from "domain/entities/user-monitoring/two-factor-monitoring/TwoFactorUserOptions"; + +export const config: TwoFactorUserOptions = { + pushProgram: { + id: "IKpEgoQ4S0r", + name: "Event program uid", + }, + twoFactorGroup: { + id: "MkELexlZOj9", + name: "TwoFactor usergroup", + }, +}; + +export const NoUsersReport = { + invalidUsersCount: 0, + listOfAffectedUsers: [], +}; + +export const userWithTwoFA: TwoFactorUser = { + id: "userUid", + twoFA: true, + username: "username", +}; + +export const userWithoutTwoFA: TwoFactorUser = { + id: "userUid2", + twoFA: false, + username: "username2", +}; + +export const listOfUsers: TwoFactorUser[] = [userWithTwoFA, userWithoutTwoFA]; +export const listOfUsersWithTwoInvalid: TwoFactorUser[] = [userWithTwoFA, userWithoutTwoFA, userWithoutTwoFA]; +export const listOfUsersWithTwoValid: TwoFactorUser[] = [userWithTwoFA, userWithTwoFA, userWithoutTwoFA]; diff --git a/src/scripts/commands/userMonitoring.ts b/src/scripts/commands/userMonitoring.ts index d038704..0715a40 100644 --- a/src/scripts/commands/userMonitoring.ts +++ b/src/scripts/commands/userMonitoring.ts @@ -64,12 +64,14 @@ const run2FAReporterCmd = command({ const userMonitoringReportRepository = new TwoFactorReportD2Repository(api); const programRepository = new UserMonitoringProgramD2Repository(api); log.info(`Run Report users without 2FA`); - await new RunTwoFactorReportUseCase( + const response = await new RunTwoFactorReportUseCase( usersRepository, userMonitoringReportRepository, externalConfigRepository, programRepository ).execute(); + + log.info(JSON.stringify(response)); }, });