JAMES-2413 Enable / disable repository creation in ToSenderDomainRepository
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/addce27e Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/addce27e Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/addce27e Branch: refs/heads/master Commit: addce27e46343b643404aebb9e05a9a7290ef06f Parents: be94620 Author: benwa <btell...@linagora.com> Authored: Thu Jun 7 11:03:52 2018 +0700 Committer: benwa <btell...@linagora.com> Committed: Wed Jun 13 09:42:35 2018 +0700 ---------------------------------------------------------------------- .../james/utils/MailRepositoryProbeImpl.java | 9 ++ .../mailets/ToSenderDomainRepositoryTest.java | 131 ++++++++++++++++--- .../mailets/ToSenderDomainRepository.java | 31 ++++- 3 files changed, 150 insertions(+), 21 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/james-project/blob/addce27e/server/container/guice/guice-common/src/main/java/org/apache/james/utils/MailRepositoryProbeImpl.java ---------------------------------------------------------------------- diff --git a/server/container/guice/guice-common/src/main/java/org/apache/james/utils/MailRepositoryProbeImpl.java b/server/container/guice/guice-common/src/main/java/org/apache/james/utils/MailRepositoryProbeImpl.java index e3143f2..f49fedd 100644 --- a/server/container/guice/guice-common/src/main/java/org/apache/james/utils/MailRepositoryProbeImpl.java +++ b/server/container/guice/guice-common/src/main/java/org/apache/james/utils/MailRepositoryProbeImpl.java @@ -43,10 +43,19 @@ public class MailRepositoryProbeImpl implements GuiceProbe { return repositoryStore.select(url).size(); } + public void createRepository(String url) throws Exception { + repositoryStore.select(url); + } + public List<String> listMailKeys(String url) throws Exception { return ImmutableList.copyOf( repositoryStore.select(url) .list()); } + public List<String> listRepositoryUrls() { + return ImmutableList.copyOf( + repositoryStore.getUrls()); + } + } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/james-project/blob/addce27e/server/mailet/integration-testing/src/test/java/org/apache/james/transport/mailets/ToSenderDomainRepositoryTest.java ---------------------------------------------------------------------- diff --git a/server/mailet/integration-testing/src/test/java/org/apache/james/transport/mailets/ToSenderDomainRepositoryTest.java b/server/mailet/integration-testing/src/test/java/org/apache/james/transport/mailets/ToSenderDomainRepositoryTest.java index 1e19e08..b811e8f 100644 --- a/server/mailet/integration-testing/src/test/java/org/apache/james/transport/mailets/ToSenderDomainRepositoryTest.java +++ b/server/mailet/integration-testing/src/test/java/org/apache/james/transport/mailets/ToSenderDomainRepositoryTest.java @@ -24,19 +24,18 @@ import static org.apache.james.mailets.configuration.Constants.LOCALHOST_IP; import static org.apache.james.mailets.configuration.Constants.PASSWORD; import static org.apache.james.mailets.configuration.Constants.SMTP_PORT; import static org.apache.james.mailets.configuration.Constants.awaitAtMostOneMinute; +import static org.assertj.core.api.Assertions.assertThat; import org.apache.james.mailets.TemporaryJamesServer; import org.apache.james.mailets.configuration.MailetConfiguration; import org.apache.james.mailets.configuration.MailetContainer; import org.apache.james.mailets.configuration.ProcessorConfiguration; -import org.apache.james.probe.DataProbe; import org.apache.james.transport.matchers.All; import org.apache.james.utils.DataProbeImpl; import org.apache.james.utils.IMAPMessageReader; import org.apache.james.utils.MailRepositoryProbeImpl; import org.apache.james.utils.SMTPMessageSender; import org.junit.After; -import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; @@ -45,6 +44,7 @@ public class ToSenderDomainRepositoryTest { private static final String RECIPIENT = "touser@" + DEFAULT_DOMAIN; private static final String CUSTOM_REPOSITORY_PREFIX = "file://var/mail/custom/"; + public static final String AWAIT_REPOSITORY_PATH = "file://var/mail/await/"; @Rule public TemporaryFolder temporaryFolder = new TemporaryFolder(); @@ -54,49 +54,140 @@ public class ToSenderDomainRepositoryTest { public SMTPMessageSender messageSender = new SMTPMessageSender(DEFAULT_DOMAIN); private TemporaryJamesServer jamesServer; - private MailRepositoryProbeImpl probe; - @Before - public void setup() throws Exception { - MailetContainer.Builder mailetContainer = TemporaryJamesServer.SIMPLE_MAILET_CONTAINER_CONFIGURATION + @After + public void tearDown() { + if (jamesServer != null) { + jamesServer.shutdown(); + } + } + + @Test + public void incomingMailShouldBeStoredInCorrespondingMailRepository() throws Exception { + initializeJamesServer(TemporaryJamesServer.SIMPLE_MAILET_CONTAINER_CONFIGURATION .putProcessor(ProcessorConfiguration.root() .addMailet(MailetConfiguration.builder() .matcher(All.class) .mailet(ToSenderDomainRepository.class) - .addProperty("urlPrefix", CUSTOM_REPOSITORY_PREFIX))); + .addProperty("urlPrefix", CUSTOM_REPOSITORY_PREFIX)))); - jamesServer = TemporaryJamesServer.builder() - .withMailetContainer(mailetContainer) - .build(temporaryFolder); + messageSender.connect(LOCALHOST_IP, SMTP_PORT) + .sendMessage(RECIPIENT, RECIPIENT); + + awaitAtMostOneMinute.until( + () -> jamesServer.getProbe(MailRepositoryProbeImpl.class) + .getRepositoryMailCount(CUSTOM_REPOSITORY_PREFIX + DEFAULT_DOMAIN) == 1); + } + + @Test + public void incomingMailShouldBeStoredWhenRepositoryDoNotExistAndAllowedToCreateRepository() throws Exception { + initializeJamesServer(TemporaryJamesServer.SIMPLE_MAILET_CONTAINER_CONFIGURATION + .putProcessor(ProcessorConfiguration.root() + .addMailet(MailetConfiguration.builder() + .matcher(All.class) + .mailet(ToSenderDomainRepository.class) + .addProperty("urlPrefix", CUSTOM_REPOSITORY_PREFIX) + .addProperty("allowRepositoryCreation", "true")))); - DataProbe dataProbe = jamesServer.getProbe(DataProbeImpl.class); - dataProbe.addDomain(DEFAULT_DOMAIN); - dataProbe.addUser(RECIPIENT, PASSWORD); + messageSender.connect(LOCALHOST_IP, SMTP_PORT) + .sendMessage(RECIPIENT, RECIPIENT); - probe = jamesServer.getProbe(MailRepositoryProbeImpl.class); + awaitAtMostOneMinute.until( + () -> jamesServer.getProbe(MailRepositoryProbeImpl.class) + .getRepositoryMailCount(CUSTOM_REPOSITORY_PREFIX + DEFAULT_DOMAIN) == 1); } - @After - public void tearDown() { - jamesServer.shutdown(); + @Test + public void incomingMailShouldBeStoredWhenRepositoryExistsAndAllowedToCreateRepository() throws Exception { + initializeJamesServer(TemporaryJamesServer.SIMPLE_MAILET_CONTAINER_CONFIGURATION + .putProcessor(ProcessorConfiguration.root() + .addMailet(MailetConfiguration.builder() + .matcher(All.class) + .mailet(ToSenderDomainRepository.class) + .addProperty("urlPrefix", CUSTOM_REPOSITORY_PREFIX) + .addProperty("allowRepositoryCreation", "true")))); + jamesServer.getProbe(MailRepositoryProbeImpl.class) + .createRepository(CUSTOM_REPOSITORY_PREFIX + DEFAULT_DOMAIN); + + messageSender.connect(LOCALHOST_IP, SMTP_PORT) + .sendMessage(RECIPIENT, RECIPIENT); + + awaitAtMostOneMinute.until( + () -> jamesServer.getProbe(MailRepositoryProbeImpl.class) + .getRepositoryMailCount(CUSTOM_REPOSITORY_PREFIX + DEFAULT_DOMAIN) == 1); } @Test - public void incomingMailShouldBeStoredInCorrespondingMailRepository() throws Exception { + public void incomingMailShouldBeIgnoredWhenRepositoryDoNotExistAndNotAllowedToCreateRepository() throws Exception { + initializeJamesServer(TemporaryJamesServer.SIMPLE_MAILET_CONTAINER_CONFIGURATION + .putProcessor(ProcessorConfiguration.root() + .addMailet(MailetConfiguration.builder() + .matcher(All.class) + .mailet(ToSenderDomainRepository.class) + .addProperty("urlPrefix", CUSTOM_REPOSITORY_PREFIX) + .addProperty("allowRepositoryCreation", "false") + .addProperty("passThrough", "true")) + .addMailet(MailetConfiguration.builder() + .matcher(All.class) + .mailet(ToRepository.class) + .addProperty("repositoryPath", AWAIT_REPOSITORY_PATH)))); + MailRepositoryProbeImpl mailRepositoryProbe = jamesServer.getProbe(MailRepositoryProbeImpl.class); + messageSender.connect(LOCALHOST_IP, SMTP_PORT) .sendMessage(RECIPIENT, RECIPIENT); awaitAtMostOneMinute.until( - () -> probe.getRepositoryMailCount(CUSTOM_REPOSITORY_PREFIX + DEFAULT_DOMAIN) == 1); + () -> mailRepositoryProbe.getRepositoryMailCount(AWAIT_REPOSITORY_PATH) == 1); + + assertThat(mailRepositoryProbe.listRepositoryUrls()) + .doesNotContain(CUSTOM_REPOSITORY_PREFIX + DEFAULT_DOMAIN); + } + + @Test + public void incomingMailShouldBeStoredWhenRepositoryExistsAndNotAllowedToCreateRepository() throws Exception { + initializeJamesServer(TemporaryJamesServer.SIMPLE_MAILET_CONTAINER_CONFIGURATION + .putProcessor(ProcessorConfiguration.root() + .addMailet(MailetConfiguration.builder() + .matcher(All.class) + .mailet(ToSenderDomainRepository.class) + .addProperty("urlPrefix", CUSTOM_REPOSITORY_PREFIX) + .addProperty("allowRepositoryCreation", "false")))); + jamesServer.getProbe(MailRepositoryProbeImpl.class) + .createRepository(CUSTOM_REPOSITORY_PREFIX + DEFAULT_DOMAIN); + + messageSender.connect(LOCALHOST_IP, SMTP_PORT) + .sendMessage(RECIPIENT, RECIPIENT); + + awaitAtMostOneMinute.until( + () -> jamesServer.getProbe(MailRepositoryProbeImpl.class) + .getRepositoryMailCount(CUSTOM_REPOSITORY_PREFIX + DEFAULT_DOMAIN) == 1); } @Test public void incomingMailsShouldBeStoredInCorrespondingMailRepository() throws Exception { + initializeJamesServer(TemporaryJamesServer.SIMPLE_MAILET_CONTAINER_CONFIGURATION + .putProcessor(ProcessorConfiguration.root() + .addMailet(MailetConfiguration.builder() + .matcher(All.class) + .mailet(ToSenderDomainRepository.class) + .addProperty("urlPrefix", CUSTOM_REPOSITORY_PREFIX)))); + messageSender.connect(LOCALHOST_IP, SMTP_PORT) .sendMessage(RECIPIENT, RECIPIENT) .sendMessage(RECIPIENT, RECIPIENT); awaitAtMostOneMinute.until( - () -> probe.getRepositoryMailCount(CUSTOM_REPOSITORY_PREFIX + DEFAULT_DOMAIN) == 2); + () -> jamesServer.getProbe(MailRepositoryProbeImpl.class) + .getRepositoryMailCount(CUSTOM_REPOSITORY_PREFIX + DEFAULT_DOMAIN) == 2); + } + + private void initializeJamesServer(MailetContainer.Builder mailetContainer) throws Exception { + jamesServer = TemporaryJamesServer.builder() + .withMailetContainer(mailetContainer) + .build(temporaryFolder); + + jamesServer.getProbe(DataProbeImpl.class) + .fluentAddDomain(DEFAULT_DOMAIN) + .fluentAddUser(RECIPIENT, PASSWORD); } } http://git-wip-us.apache.org/repos/asf/james-project/blob/addce27e/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/ToSenderDomainRepository.java ---------------------------------------------------------------------- diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/ToSenderDomainRepository.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/ToSenderDomainRepository.java index b86482e..8f417c6 100644 --- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/ToSenderDomainRepository.java +++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/ToSenderDomainRepository.java @@ -24,9 +24,15 @@ import java.util.Optional; import javax.inject.Inject; import javax.mail.MessagingException; +import org.apache.james.mailrepository.api.MailRepository; import org.apache.james.mailrepository.api.MailRepositoryStore; import org.apache.mailet.Mail; import org.apache.mailet.base.GenericMailet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.github.fge.lambdas.Throwing; +import com.github.fge.lambdas.consumers.ThrowingConsumer; /** * Stores incoming Mail in a repository defined by the sender's domain.<br> @@ -37,21 +43,29 @@ import org.apache.mailet.base.GenericMailet; * For example for the value 'cassandra://var/mail/sendersRepositories/', a mail sent by 'u...@james.org' * will be stored in 'cassandra://var/mail/sendersRepositories/james.org'. * - "passThrough" optional, defaults to false. If true, the processing of the mail continues. If false it stops. + * - "allowRepositoryCreation" optional, defaults to true. If true, non existing repository will be created. In case of + * misconfiguration, this might lead to arbitrary repository creation. If false, the incoming mails will be stored only + * in already existing repository. If not existing, the email will be dropped with an appropriate log warning (leading + * to potential data loss). * * Example: * * <mailet matcher="All" class="ToSenderDomainRepository"> * <urlPrefix>cassandra://var/mail/sendersRepositories/</urlPrefix> * <passThrough>false</passThrough> + * <allowRepositoryCreation>true</allowRepositoryCreation> * </mailet> */ public class ToSenderDomainRepository extends GenericMailet { + private static final Logger LOGGER = LoggerFactory.getLogger(ToSenderDomainRepository.class); private static final boolean DEFAULT_CONSUME = false; + private static final boolean DEFAULT_ALLOW_REPOSITORY_CREATION = true; private final MailRepositoryStore mailRepositoryStore; private String urlPrefix; private boolean passThrough; + private boolean allowRepositoryCreation; @Inject public ToSenderDomainRepository(MailRepositoryStore mailRepositoryStore) { @@ -63,6 +77,7 @@ public class ToSenderDomainRepository extends GenericMailet { urlPrefix = Optional.ofNullable(getInitParameter("urlPrefix")) .orElseThrow(() -> new MessagingException("'urlPrefix' is a mandatory configuration property")); passThrough = getInitParameter("passThrough", DEFAULT_CONSUME); + allowRepositoryCreation = getInitParameter("allowRepositoryCreation", DEFAULT_ALLOW_REPOSITORY_CREATION); } @Override @@ -76,12 +91,26 @@ public class ToSenderDomainRepository extends GenericMailet { private void store(Mail mail, String url) throws MessagingException { try { - mailRepositoryStore.select(url).store(mail); + Optional<MailRepository> mailRepository = retrieveRepository(url); + if (!mailRepository.isPresent()) { + LOGGER.warn("'{}' mail repository does not exist and will not be created. Mail {} will not be stored in it.", + url, mail.getName()); + } + ThrowingConsumer<MailRepository> storingConsumer = repository -> repository.store(mail); + mailRepository.ifPresent(Throwing.consumer(storingConsumer).sneakyThrow()); } catch (MailRepositoryStore.MailRepositoryStoreException e) { throw new MessagingException("Error while selecting url " + url, e); } } + private Optional<MailRepository> retrieveRepository(String url) throws MailRepositoryStore.MailRepositoryStoreException { + if (allowRepositoryCreation) { + return Optional.of(mailRepositoryStore.select(url)); + } else { + return mailRepositoryStore.get(url); + } + } + @Override public String getMailetInfo() { return "ToSenderDomainRepository Mailet"; --------------------------------------------------------------------- To unsubscribe, e-mail: server-dev-unsubscr...@james.apache.org For additional commands, e-mail: server-dev-h...@james.apache.org