From 4a070de160d32b0f77b5832e298497a97953c220 Mon Sep 17 00:00:00 2001 From: Alexander Ungefug <82446024+AlexanderUngefug@users.noreply.github.com> Date: Fri, 13 Dec 2024 09:19:36 +0100 Subject: [PATCH] refactor LDAP client service and event handler for improved organization and member checks --- src/core/ldap/domain/ldap-client.service.ts | 68 ++++++++++++++++----- src/core/ldap/domain/ldap-event-handler.ts | 18 +++++- 2 files changed, 68 insertions(+), 18 deletions(-) diff --git a/src/core/ldap/domain/ldap-client.service.ts b/src/core/ldap/domain/ldap-client.service.ts index b3bbc6993..f4eb75622 100644 --- a/src/core/ldap/domain/ldap-client.service.ts +++ b/src/core/ldap/domain/ldap-client.service.ts @@ -469,13 +469,10 @@ export class LdapClientService { await client.add(orgUnitDn, newOrgUnit); } - const orgRoleDn: string = `cn=${LdapClientService.GROUPS},ou=${schoolReferrer},${LdapClientService.DC_SCHULE_SH_DC_DE}`; - const searchResultOrgRole: SearchResult = await client.search( - `ou=${schoolReferrer},${LdapClientService.DC_SCHULE_SH_DC_DE}`, - { - filter: `(cn=${LdapClientService.GROUPS})`, - }, - ); + const orgRoleDn: string = `cn=${LdapClientService.GROUPS},${orgUnitDn}`; + const searchResultOrgRole: SearchResult = await client.search(orgUnitDn, { + filter: `(cn=${LdapClientService.GROUPS})`, + }); if (!searchResultOrgRole.searchEntries[0]) { const newOrgRole: { cn: string; objectClass: string } = { cn: LdapClientService.GROUPS, @@ -484,13 +481,10 @@ export class LdapClientService { await client.add(orgRoleDn, newOrgRole); } - const lehrerDn: string = `cn=${groupId},cn=${LdapClientService.GROUPS},ou=${schoolReferrer},${LdapClientService.DC_SCHULE_SH_DC_DE}`; - const searchResultGroupOfNames: SearchResult = await client.search( - `cn=${LdapClientService.GROUPS},ou=${schoolReferrer},${LdapClientService.DC_SCHULE_SH_DC_DE}`, - { - filter: `(cn=${groupId})`, - }, - ); + const lehrerDn: string = `cn=${groupId},${orgRoleDn}`; + const searchResultGroupOfNames: SearchResult = await client.search(orgRoleDn, { + filter: `(cn=${groupId})`, + }); if (!searchResultGroupOfNames.searchEntries[0]) { const newLehrerGroup: { cn: string; objectclass: string[]; member: string[] } = { cn: groupId, @@ -508,6 +502,11 @@ export class LdapClientService { } } + if (this.isPersonInSearchResult(searchResultGroupOfNames, personUid)) { + this.logger.info(`LDAP: Person ${personUid} is already in group ${groupId}`); + return { ok: true, value: false }; + } + try { await client.modify(lehrerDn, [ new Change({ @@ -533,8 +532,17 @@ export class LdapClientService { const client: Client = this.ldapClient.getClient(); const bindResult: Result = await this.bind(); if (!bindResult.ok) return bindResult; - const dn: string = `cn=${groupId},cn=${LdapClientService.GROUPS},ou=${schoolReferrer},${LdapClientService.DC_SCHULE_SH_DC_DE}`; - const searchResultOrgUnit: SearchResult = await client.search(dn, { scope: 'base' }); + const searchResultOrgUnit: SearchResult = await client.search( + `cn=${LdapClientService.GROUPS},ou=${schoolReferrer},${LdapClientService.DC_SCHULE_SH_DC_DE}`, + { + filter: `(cn=${groupId})`, + }, + ); + + if (!this.isPersonInSearchResult(searchResultOrgUnit, personUid)) { + this.logger.info(`LDAP: Person ${personUid} is not in group ${groupId}`); + return { ok: true, value: false }; + } if (!searchResultOrgUnit.searchEntries[0]) { const errMsg: string = `LDAP: Group ${groupId} not found`; @@ -566,4 +574,32 @@ export class LdapClientService { return { ok: false, error: new LdapRemovePersonFromGroupError() }; } } + + private isPersonInSearchResult(searchResult: SearchResult, personUid: string): boolean | undefined { + if (!searchResult.searchEntries[0]) return; + const member: string | string[] | Buffer | Buffer[] | undefined = searchResult.searchEntries[0]['member']; + const lehrerUid: string = this.getLehrerUid(personUid, 'users'); + + if (typeof member === 'string') { + return member === lehrerUid; + } + + if (Buffer.isBuffer(member)) { + return member.toString() === lehrerUid; + } + + if (Array.isArray(member)) { + return member.some((entry: string | Buffer) => { + if (typeof entry === 'string') { + return entry === lehrerUid; + } + if (Buffer.isBuffer(entry)) { + return entry.toString() === lehrerUid; + } + return false; + }); + } + + return false; + } } diff --git a/src/core/ldap/domain/ldap-event-handler.ts b/src/core/ldap/domain/ldap-event-handler.ts index 2eebcadf9..ab7b4d9c5 100644 --- a/src/core/ldap/domain/ldap-event-handler.ts +++ b/src/core/ldap/domain/ldap-event-handler.ts @@ -155,7 +155,10 @@ export class LdapEventHandler { await Promise.allSettled( event.removedKontexte - .filter((pk: PersonenkontextEventKontextData) => pk.rolle === RollenArt.LEHR) + .filter( + (pk: PersonenkontextEventKontextData) => + pk.rolle === RollenArt.LEHR && !this.hatZuordnungZuOrganisationNachLoeschen(event, pk), + ) .map((pk: PersonenkontextEventKontextData) => { if (!pk.orgaKennung) { return Promise.reject(new Error('Organisation has no Kennung')); @@ -207,7 +210,7 @@ export class LdapEventHandler { .then((emailDomain: Result) => { if (emailDomain.ok) { return this.ldapClientService - .createLehrer(event.person, emailDomain.value, pk.orgaKennung!, undefined) + .createLehrer(event.person, emailDomain.value, pk.orgaKennung!) .then((creationResult: Result) => { if (!creationResult.ok) { this.logger.error(creationResult.error.message); @@ -246,4 +249,15 @@ export class LdapEventHandler { await this.ldapClientService.changeEmailAddressByPersonId(event.personId, event.newAddress); } + + public hatZuordnungZuOrganisationNachLoeschen( + personenkontextUpdatedEvent: PersonenkontextUpdatedEvent, + personenkontextEventKontextData: PersonenkontextEventKontextData, + ): boolean { + const orgaId: OrganisationID = personenkontextEventKontextData.orgaId; + const currentOrgaIds: OrganisationID[] = personenkontextUpdatedEvent.currentKontexte.map( + (pk: PersonenkontextEventKontextData) => pk.orgaId, + ); + return currentOrgaIds.includes(orgaId); + } }