This is an automated email from the ASF dual-hosted git repository. btellier pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/james-project.git
commit 2b80ac3444edbe676efffc6dba949ac83993b806 Author: Benoit Tellier <[email protected]> AuthorDate: Thu Mar 12 20:28:24 2020 +0700 JAMES-3113 Mails send from an alias should be considered as localSender --- .../mailets/SenderIsLocalIntegrationTest.java | 141 +++++++++++++++++++++ .../james/mailets/configuration/Constants.java | 1 + .../mailetcontainer/impl/JamesMailetContext.java | 28 +++- .../impl/JamesMailetContextTest.java | 5 +- 4 files changed, 171 insertions(+), 4 deletions(-) diff --git a/server/mailet/integration-testing/src/test/java/org/apache/james/mailets/SenderIsLocalIntegrationTest.java b/server/mailet/integration-testing/src/test/java/org/apache/james/mailets/SenderIsLocalIntegrationTest.java new file mode 100644 index 0000000..57e2898 --- /dev/null +++ b/server/mailet/integration-testing/src/test/java/org/apache/james/mailets/SenderIsLocalIntegrationTest.java @@ -0,0 +1,141 @@ +/**************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one * + * or more contributor license agreements. See the NOTICE file * + * distributed with this work for additional information * + * regarding copyright ownership. The ASF licenses this file * + * to you under the Apache License, Version 2.0 (the * + * "License"); you may not use this file except in compliance * + * with the License. You may obtain a copy of the License at * + * * + * http://www.apache.org/licenses/LICENSE-2.0 * + * * + * Unless required by applicable law or agreed to in writing, * + * software distributed under the License is distributed on an * + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * + * KIND, either express or implied. See the License for the * + * specific language governing permissions and limitations * + * under the License. * + ****************************************************************/ + +package org.apache.james.mailets; + +import static org.apache.james.mailets.configuration.Constants.ALIAS; +import static org.apache.james.mailets.configuration.Constants.DEFAULT_DOMAIN; +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.RECIPIENT; +import static org.apache.james.mailets.configuration.Constants.RECIPIENT2; +import static org.apache.james.mailets.configuration.Constants.awaitAtMostOneMinute; + +import org.apache.james.MemoryJamesServerMain; +import org.apache.james.mailets.configuration.CommonProcessors; +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.mailrepository.api.MailRepositoryUrl; +import org.apache.james.modules.protocols.ImapGuiceProbe; +import org.apache.james.modules.protocols.SmtpGuiceProbe; +import org.apache.james.probe.DataProbe; +import org.apache.james.transport.mailets.Bounce; +import org.apache.james.transport.mailets.DSNBounce; +import org.apache.james.transport.mailets.Forward; +import org.apache.james.transport.mailets.LocalDelivery; +import org.apache.james.transport.mailets.NotifyPostmaster; +import org.apache.james.transport.mailets.NotifySender; +import org.apache.james.transport.mailets.Redirect; +import org.apache.james.transport.mailets.Resend; +import org.apache.james.transport.mailets.ToRepository; +import org.apache.james.transport.matchers.All; +import org.apache.james.transport.matchers.RecipientIs; +import org.apache.james.transport.matchers.SenderIsLocal; +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.apache.james.utils.WebAdminGuiceProbe; +import org.apache.james.webadmin.WebAdminUtils; +import org.apache.james.webadmin.routes.AliasRoutes; +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; + +import io.restassured.specification.RequestSpecification; + +public class SenderIsLocalIntegrationTest { + private static final String POSTMASTER = "postmaster@" + DEFAULT_DOMAIN; + private static final MailRepositoryUrl LOCAL_SENDER_REPOSITORY = MailRepositoryUrl.from("memory://var/mail/local/sender/"); + private static final MailRepositoryUrl REMOTE_SENDER_REPOSITORY = MailRepositoryUrl.from("memory://var/mail/remote/sender/"); + + @Rule + public TemporaryFolder temporaryFolder = new TemporaryFolder(); + @Rule + public IMAPMessageReader imapMessageReader = new IMAPMessageReader(); + @Rule + public SMTPMessageSender messageSender = new SMTPMessageSender(DEFAULT_DOMAIN); + + private TemporaryJamesServer jamesServer; + private MailRepositoryProbeImpl probe; + private RequestSpecification webAdminApi; + + @Before + public void setUp() throws Exception { + jamesServer = TemporaryJamesServer.builder() + .withBase(MemoryJamesServerMain.IN_MEMORY_SERVER_AGGREGATE_MODULE) + .withMailetContainer(TemporaryJamesServer.DEFAULT_MAILET_CONTAINER_CONFIGURATION + .postmaster(POSTMASTER) + .putProcessor(transport())) + .build(temporaryFolder.newFolder()); + probe = jamesServer.getProbe(MailRepositoryProbeImpl.class); + + DataProbe dataProbe = jamesServer.getProbe(DataProbeImpl.class); + dataProbe.addDomain(DEFAULT_DOMAIN); + dataProbe.addUser(RECIPIENT, PASSWORD); + webAdminApi = WebAdminUtils.spec(jamesServer.getProbe(WebAdminGuiceProbe.class).getWebAdminPort()); + } + + @After + public void tearDown() { + jamesServer.shutdown(); + } + + @Test + public void shouldMatchLocalSender() throws Exception { + messageSender.connect(LOCALHOST_IP, jamesServer.getProbe(SmtpGuiceProbe.class).getSmtpPort()) + .sendMessage(RECIPIENT, RECIPIENT); + + awaitAtMostOneMinute.until(() -> probe.getRepositoryMailCount(LOCAL_SENDER_REPOSITORY) == 1); + } + + @Test + public void shouldMatchLocalSenderAlias() throws Exception { + webAdminApi.put(AliasRoutes.ROOT_PATH + "/" + RECIPIENT + "/sources/" + ALIAS); + + messageSender.connect(LOCALHOST_IP, jamesServer.getProbe(SmtpGuiceProbe.class).getSmtpPort()) + .sendMessage(ALIAS, RECIPIENT); + + awaitAtMostOneMinute.until(() -> probe.getRepositoryMailCount(LOCAL_SENDER_REPOSITORY) == 1); + } + + @Test + public void shouldNotMatchRemoteSender() throws Exception { + messageSender.connect(LOCALHOST_IP, jamesServer.getProbe(SmtpGuiceProbe.class).getSmtpPort()) + .sendMessage("[email protected]", RECIPIENT); + + awaitAtMostOneMinute.until(() -> probe.getRepositoryMailCount(REMOTE_SENDER_REPOSITORY) == 1); + } + + private ProcessorConfiguration.Builder transport() { + return ProcessorConfiguration.transport() + .addMailet(MailetConfiguration.builder() + .matcher(SenderIsLocal.class) + .mailet(ToRepository.class) + .addProperty("repositoryPath", LOCAL_SENDER_REPOSITORY.asString())) + .addMailet(MailetConfiguration.builder() + .matcher(All.class) + .mailet(ToRepository.class) + .addProperty("repositoryPath", REMOTE_SENDER_REPOSITORY.asString())) + .addMailetsFrom(CommonProcessors.transport()); + } +} diff --git a/server/mailet/integration-testing/src/test/java/org/apache/james/mailets/configuration/Constants.java b/server/mailet/integration-testing/src/test/java/org/apache/james/mailets/configuration/Constants.java index 13522f4..8e18a09 100644 --- a/server/mailet/integration-testing/src/test/java/org/apache/james/mailets/configuration/Constants.java +++ b/server/mailet/integration-testing/src/test/java/org/apache/james/mailets/configuration/Constants.java @@ -45,5 +45,6 @@ public class Constants { public static final String PASSWORD = "secret"; public static final String FROM = "user@" + DEFAULT_DOMAIN; public static final String RECIPIENT = "user2@" + DEFAULT_DOMAIN; + public static final String ALIAS = "user2alias@" + DEFAULT_DOMAIN; public static final String RECIPIENT2 = "user3@" + DEFAULT_DOMAIN; } diff --git a/server/mailet/mailetcontainer-camel/src/main/java/org/apache/james/mailetcontainer/impl/JamesMailetContext.java b/server/mailet/mailetcontainer-camel/src/main/java/org/apache/james/mailetcontainer/impl/JamesMailetContext.java index e1c3483..6309e52 100644 --- a/server/mailet/mailetcontainer-camel/src/main/java/org/apache/james/mailetcontainer/impl/JamesMailetContext.java +++ b/server/mailet/mailetcontainer-camel/src/main/java/org/apache/james/mailetcontainer/impl/JamesMailetContext.java @@ -22,6 +22,7 @@ package org.apache.james.mailetcontainer.impl; import java.io.IOException; import java.util.Collection; import java.util.Date; +import java.util.EnumSet; import java.util.HashSet; import java.util.Iterator; import java.util.List; @@ -56,6 +57,10 @@ import org.apache.james.lifecycle.api.Disposable; import org.apache.james.lifecycle.api.LifecycleUtil; import org.apache.james.queue.api.MailQueue; import org.apache.james.queue.api.MailQueueFactory; +import org.apache.james.rrt.api.RecipientRewriteTable; +import org.apache.james.rrt.api.RecipientRewriteTable.ErrorMappingException; +import org.apache.james.rrt.api.RecipientRewriteTableException; +import org.apache.james.rrt.lib.Mapping; import org.apache.james.server.core.MailImpl; import org.apache.james.user.api.UsersRepository; import org.apache.james.user.api.UsersRepositoryException; @@ -66,11 +71,13 @@ import org.apache.mailet.base.RFC2822Headers; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.github.fge.lambdas.Throwing; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableSet; public class JamesMailetContext implements MailetContext, Configurable, Disposable { private static final Logger LOGGER = LoggerFactory.getLogger(JamesMailetContext.class); + public static final EnumSet<Mapping.Type> ALIAS_TYPES = EnumSet.of(Mapping.Type.Alias, Mapping.Type.DomainAlias); /** * A hash table of server attributes These are the MailetContext attributes @@ -80,15 +87,17 @@ public class JamesMailetContext implements MailetContext, Configurable, Disposab protected final DNSService dns; private final UsersRepository localusers; private final DomainList domains; + private final RecipientRewriteTable recipientRewriteTable; private final MailQueueFactory<?> mailQueueFactory; private MailQueue rootMailQueue; private MailAddress postmaster; @Inject - public JamesMailetContext(DNSService dns, UsersRepository localusers, DomainList domains, MailQueueFactory<?> mailQueueFactory) { + public JamesMailetContext(DNSService dns, UsersRepository localusers, DomainList domains, RecipientRewriteTable recipientRewriteTable, MailQueueFactory<?> mailQueueFactory) { this.dns = dns; this.localusers = localusers; this.domains = domains; + this.recipientRewriteTable = recipientRewriteTable; this.mailQueueFactory = mailQueueFactory; } @@ -261,14 +270,27 @@ public class JamesMailetContext implements MailetContext, Configurable, Disposab return false; } try { - return localusers.contains(localusers.getUser(mailAddress)); - } catch (UsersRepositoryException e) { + return isLocaluser(mailAddress) + || isLocalAlias(mailAddress); + } catch (UsersRepositoryException | ErrorMappingException | RecipientRewriteTableException e) { LOGGER.error("Unable to access UsersRepository", e); } } return false; } + private boolean isLocaluser(MailAddress mailAddress) throws UsersRepositoryException { + return localusers.contains(localusers.getUser(mailAddress)); + } + + private boolean isLocalAlias(MailAddress mailAddress) throws UsersRepositoryException, ErrorMappingException, RecipientRewriteTableException { + return recipientRewriteTable.getResolvedMappings(mailAddress.getLocalPart(), mailAddress.getDomain(), ALIAS_TYPES) + .asStream() + .map(mapping -> mapping.asMailAddress() + .orElseThrow(() -> new IllegalStateException(String.format("Can not compute address for mapping %s", mapping.asString())))) + .anyMatch(Throwing.predicate(this::isLocaluser).sneakyThrow()); + } + @Override public MailAddress getPostmaster() { return postmaster; diff --git a/server/mailet/mailetcontainer-camel/src/test/java/org/apache/james/mailetcontainer/impl/JamesMailetContextTest.java b/server/mailet/mailetcontainer-camel/src/test/java/org/apache/james/mailetcontainer/impl/JamesMailetContextTest.java index 6dccf9c..b3c8713 100644 --- a/server/mailet/mailetcontainer-camel/src/test/java/org/apache/james/mailetcontainer/impl/JamesMailetContextTest.java +++ b/server/mailet/mailetcontainer-camel/src/test/java/org/apache/james/mailetcontainer/impl/JamesMailetContextTest.java @@ -40,6 +40,7 @@ import org.apache.james.domainlist.lib.DomainListConfiguration; import org.apache.james.domainlist.memory.MemoryDomainList; import org.apache.james.queue.api.MailQueue; import org.apache.james.queue.api.MailQueueFactory; +import org.apache.james.rrt.memory.MemoryRecipientRewriteTable; import org.apache.james.server.core.MailImpl; import org.apache.james.user.memory.MemoryUsersRepository; import org.apache.james.util.MimeMessageUtil; @@ -80,11 +81,13 @@ public class JamesMailetContextTest { .build()); usersRepository = MemoryUsersRepository.withVirtualHosting(domainList); + MemoryRecipientRewriteTable recipientRewriteTable = new MemoryRecipientRewriteTable(); + recipientRewriteTable.configure(new BaseHierarchicalConfiguration()); MailQueueFactory<MailQueue> mailQueueFactory = mock(MailQueueFactory.class); spoolMailQueue = mock(MailQueue.class); when(mailQueueFactory.createQueue(MailQueueFactory.SPOOL)).thenReturn(spoolMailQueue); DNSService dnsService = null; - testee = new JamesMailetContext(dnsService, usersRepository, domainList, mailQueueFactory); + testee = new JamesMailetContext(dnsService, usersRepository, domainList, recipientRewriteTable, mailQueueFactory); testee.configure(new BaseHierarchicalConfiguration()); mailAddress = new MailAddress(USERMAIL.asString()); } --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
