diff --git a/README.md b/README.md index 371553e..1a478dd 100644 --- a/README.md +++ b/README.md @@ -142,6 +142,10 @@ The pivot used for the synchronization in the LSC connector is the email address The destination attributes for the LSC aliases connector are named `firstname` and `surname`. +For the domain synchronization, you can specify the wished domain list to be synchronized by specify the dedicated ENV variable with key `DOMAIN_LIST_TO_SYNCHRONIZE` and DELIMITER `,`. The synchronization for other domain contacts will be ignored (no create, update, delete operation). For example: `DOMAIN_LIST_TO_SYNCHRONIZE=james.org,linagora.com`. + +If you omit this environment variable setting, all domains contact will be synchronized from LDAP. + ### Address Mappings Synchronization For example, it can be used to synchronize the address mappings stored in the LDAP server to the TMail Server(s) of a TMail deployment. @@ -326,7 +330,8 @@ The values to configure are: The domains used in the aliases must have been previously created in TMail. Otherwise, if a user have a single alias pointing to an unknown domain, none of her aliases will be added. -For the domain synchronization, you can specify the wished domain list to be synchronized by specify the dedicated ENV variable with key `DOMAIN_LIST_TO_SYNCHRONIZE` and DELIMITER `,`. +For the domain synchronization, you can specify the wished domain list to be synchronized by specify the dedicated ENV variable with key `DOMAIN_LIST_TO_SYNCHRONIZE` and DELIMITER `,`. The synchronization for other domain contacts will be ignored (no create, update, delete operation). For example: `DOMAIN_LIST_TO_SYNCHRONIZE=linagora.com` or `DOMAIN_LIST_TO_SYNCHRONIZE=lists.linagora.com`. + If you omit this environment variable setting, all domains contact will be synchronized from LDAP. The jar of the TMail LSC plugin (`target/lsc-tmail-plugin-1.0-distribution.jar`) must be copied in the `lib` directory of your LSC installation. diff --git a/sample/ldap-to-tmail-contact/lsc.xml b/sample/ldap-to-tmail-contact/lsc.xml index 6cf9781..b732e22 100644 --- a/sample/ldap-to-tmail-contact/lsc.xml +++ b/sample/ldap-to-tmail-contact/lsc.xml @@ -62,7 +62,7 @@ true true - false + true false diff --git a/src/main/java/org/lsc/plugins/connectors/james/TMailContactDstService.java b/src/main/java/org/lsc/plugins/connectors/james/TMailContactDstService.java index a4b3486..44872d9 100644 --- a/src/main/java/org/lsc/plugins/connectors/james/TMailContactDstService.java +++ b/src/main/java/org/lsc/plugins/connectors/james/TMailContactDstService.java @@ -78,6 +78,9 @@ public boolean apply(LscModifications lscModifications) throws LscServiceExcepti } else { return false; } + case DELETE_OBJECT: + LOGGER.debug("Domain contact {} exists on TMail but not in LDAP. Deleting this domain contact.", email); + return jamesDao.removeDomainContact(email); default: LOGGER.debug("{} operation, ignored.", lscModifications.getOperation()); return false; diff --git a/src/test/java/org/lsc/plugins/connectors/james/TMailContactDstServiceTest.java b/src/test/java/org/lsc/plugins/connectors/james/TMailContactDstServiceTest.java index 8871027..79df37a 100644 --- a/src/test/java/org/lsc/plugins/connectors/james/TMailContactDstServiceTest.java +++ b/src/test/java/org/lsc/plugins/connectors/james/TMailContactDstServiceTest.java @@ -4,6 +4,7 @@ import static io.restassured.config.EncoderConfig.encoderConfig; import static io.restassured.config.RestAssuredConfig.newConfig; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.assertj.core.api.SoftAssertions.assertSoftly; import static org.hamcrest.Matchers.hasSize; import static org.lsc.plugins.connectors.james.TMailContactDstService.EMAIL_KEY; @@ -27,6 +28,8 @@ import java.util.Map; import java.util.Optional; +import javax.ws.rs.NotFoundException; + import org.apache.http.HttpStatus; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.openssl.PEMReader; @@ -307,6 +310,78 @@ void shouldSupportPartialUpdate() throws Exception { CONTACT_RENE.getFirstname(), Optional.of("Surname"))); } + @Test + void deleteOperationShouldDeleteDomainContactWhenUserDoesNotExistAnymoreOnLDAP() throws Exception { + createContact(CONTACT_RENE); + + LscModifications modifications = new LscModifications(LscModificationType.DELETE_OBJECT); + modifications.setMainIdentifer(CONTACT_RENE.getEmailAddress()); + modifications.setLscAttributeModifications(ImmutableList.of()); + + boolean applied = testee.apply(modifications); + + assertThat(applied).isTrue(); + assertNonExistingDomainContact(CONTACT_RENE.getEmailAddress()); + } + + @Test + void deleteOperationShouldNotDeleteContactsOfOtherUsers() throws Exception { + createContact(CONTACT_RENE); + createContact(CONTACT_TUNG); + + // delete contact of Tung + LscModifications modifications = new LscModifications(LscModificationType.DELETE_OBJECT); + modifications.setMainIdentifer(CONTACT_TUNG.getEmailAddress()); + modifications.setLscAttributeModifications(ImmutableList.of()); + + boolean applied = testee.apply(modifications); + + // contact of Tung should be deleted, but not contact of Rene + assertThat(applied).isTrue(); + assertNonExistingDomainContact(CONTACT_TUNG.getEmailAddress()); + assertThat(jamesDao.getContact(CONTACT_RENE.getEmailAddress())) + .isEqualTo(new Contact(CONTACT_RENE.getEmailAddress(), CONTACT_RENE.getFirstname(), CONTACT_RENE.getSurname())); + } + + @Test + void deleteOperationWouldDeleteContactsOfUnwishedDomainByDefault() throws Exception { + // If we do not configure the DOMAIN_LIST_TO_SYNCHRONIZE which means we synchronize all domains by default + forceSynchronizeDomainListValue(Optional.empty()); + createContact(CONTACT_RENE); + createContact(CONTACT_WITH_UN_WISHED_DOMAIN); + + // Assume unwished domain entry does not exist in filtered LDAP baseDN of james.org domain + LscModifications modifications = new LscModifications(LscModificationType.DELETE_OBJECT); + modifications.setMainIdentifer(CONTACT_WITH_UN_WISHED_DOMAIN.getEmailAddress()); + modifications.setLscAttributeModifications(ImmutableList.of()); + + boolean applied = testee.apply(modifications); + + // then unwished domain contact would be deleted + assertThat(applied).isTrue(); + assertNonExistingDomainContact(CONTACT_WITH_UN_WISHED_DOMAIN.getEmailAddress()); + } + + @Test + void deleteShouldNotDeleteContactsOfUnwishedDomainWhenConfigured() throws Exception { + // Only synchronize james.org domain, ignore other domains (e.g. unwisheddomain.org) + forceSynchronizeDomainListValue(Arrays.asList("james.org")); + createContact(CONTACT_RENE); + createContact(CONTACT_WITH_UN_WISHED_DOMAIN); + + // Assume unwished domain entry does not exist in filtered LDAP baseDN of james.org domain + LscModifications modifications = new LscModifications(LscModificationType.DELETE_OBJECT); + modifications.setMainIdentifer(CONTACT_WITH_UN_WISHED_DOMAIN.getEmailAddress()); + modifications.setLscAttributeModifications(ImmutableList.of()); + + boolean applied = testee.apply(modifications); + + // then unwished domain contact should not be deleted + assertThat(applied).isFalse(); + assertThat(jamesDao.getContact(CONTACT_WITH_UN_WISHED_DOMAIN.getEmailAddress())) + .isEqualTo(new Contact(CONTACT_WITH_UN_WISHED_DOMAIN.getEmailAddress(), CONTACT_WITH_UN_WISHED_DOMAIN.getFirstname(), CONTACT_WITH_UN_WISHED_DOMAIN.getSurname())); + } + @Test void getBeanShouldReturnNullWhenEmptyDataset() throws Exception { assertThat(testee.getBean("email", new LscDatasets(), FROM_SAME_SERVICE)).isNull(); @@ -367,12 +442,21 @@ private void createContact(Contact contact) throws JsonProcessingException { } // using reflection to change DOMAIN_LIST_TO_SYNCHRONIZE value - private static void forceSynchronizeDomainListValue(List domainList) throws NoSuchFieldException, IllegalAccessException { + private static void forceSynchronizeDomainListValue(Optional> domainListOptional) throws NoSuchFieldException, IllegalAccessException { final Field field = SyncContactConfig.class.getDeclaredField("DOMAIN_LIST_TO_SYNCHRONIZE"); field.setAccessible(true); final Field modifiersField = Field.class.getDeclaredField("modifiers"); modifiersField.setAccessible(true); modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL); - field.set(null, Optional.of(domainList)); + field.set(null, domainListOptional); + } + + private static void forceSynchronizeDomainListValue(List domainList) throws NoSuchFieldException, IllegalAccessException { + forceSynchronizeDomainListValue(Optional.of(domainList)); + } + + private void assertNonExistingDomainContact(String email) { + assertThatThrownBy(() -> jamesDao.getContact(email)) + .isInstanceOf(NotFoundException.class); } }