Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ISSUE-30 Enhance domain filter documentation for domain contact sync #31

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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.
Expand Down
2 changes: 1 addition & 1 deletion sample/ldap-to-tmail-contact/lsc.xml
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@
<conditions>
<create>true</create>
<update>true</update>
<delete>false</delete>
<delete>true</delete>
<changeId>false</changeId>
</conditions>
<dataset>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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<String> domainList) throws NoSuchFieldException, IllegalAccessException {
private static void forceSynchronizeDomainListValue(Optional<List<String>> 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<String> domainList) throws NoSuchFieldException, IllegalAccessException {
forceSynchronizeDomainListValue(Optional.of(domainList));
}

private void assertNonExistingDomainContact(String email) {
assertThatThrownBy(() -> jamesDao.getContact(email))
.isInstanceOf(NotFoundException.class);
}
}