This is an automated email from the ASF dual-hosted git repository. rcordier pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/james-project.git
The following commit(s) were added to refs/heads/master by this push: new ad58064c1b JAMES-4029 Fix infinite loop with Bounce + forward ad58064c1b is described below commit ad58064c1bcd53ed82fc2e3080d20b4d0e7843eb Author: Benoit TELLIER <btell...@linagora.com> AuthorDate: Mon Apr 15 20:54:24 2024 +0200 JAMES-4029 Fix infinite loop with Bounce + forward --- .../mailets/ForwardBounceLoopIntegrationTest.java | 156 +++++++++++++++++++++ .../mailets/redirect/ProcessRedirectNotify.java | 7 + 2 files changed, 163 insertions(+) diff --git a/server/mailet/integration-testing/src/test/java/org/apache/james/mailets/ForwardBounceLoopIntegrationTest.java b/server/mailet/integration-testing/src/test/java/org/apache/james/mailets/ForwardBounceLoopIntegrationTest.java new file mode 100644 index 0000000000..75d421438f --- /dev/null +++ b/server/mailet/integration-testing/src/test/java/org/apache/james/mailets/ForwardBounceLoopIntegrationTest.java @@ -0,0 +1,156 @@ +/**************************************************************** + * 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.CommonProcessors.ERROR_REPOSITORY; +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.MailetConfiguration.TO_TRANSPORT; +import static org.apache.james.mailets.configuration.ProcessorConfiguration.STATE_BOUNCES; +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.File; + +import org.apache.james.core.Username; +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.modules.protocols.SmtpGuiceProbe; +import org.apache.james.rrt.lib.Mapping; +import org.apache.james.rrt.lib.MappingSource; +import org.apache.james.transport.mailets.Bounce; +import org.apache.james.transport.mailets.ToProcessor; +import org.apache.james.transport.matchers.All; +import org.apache.james.transport.matchers.RecipientIs; +import org.apache.james.utils.DataProbeImpl; +import org.apache.james.utils.FilteringManagementProbeImpl; +import org.apache.james.utils.GuiceProbe; +import org.apache.james.utils.MailRepositoryProbeImpl; +import org.apache.james.utils.SMTPMessageSender; +import org.apache.james.utils.SpoolerProbe; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.junit.jupiter.api.io.TempDir; +import org.testcontainers.shaded.org.awaitility.Awaitility; + +import com.google.inject.multibindings.Multibinder; + +public class ForwardBounceLoopIntegrationTest { + + private static final Username SENDER = Username.of("sender@" + DEFAULT_DOMAIN); + private static final Username ALICE = Username.of("alice@" + DEFAULT_DOMAIN); + private static final Username BOB = Username.of("bob@" + DEFAULT_DOMAIN); + private static final Username CEDRIC = Username.of("cedric@" + DEFAULT_DOMAIN); + private TemporaryJamesServer jamesServer; + private MailRepositoryProbeImpl mailRepositoryProbe; + + @RegisterExtension + public SMTPMessageSender messageSender = new SMTPMessageSender(DEFAULT_DOMAIN); + private DataProbeImpl dataProbe; + + private void setUp(File temporaryFolder, MailetContainer.Builder mailetConfiguration) throws Exception { + jamesServer = TemporaryJamesServer.builder() + .withOverrides(binder -> Multibinder.newSetBinder(binder, GuiceProbe.class).addBinding().to(FilteringManagementProbeImpl.class)) + .withMailetContainer(mailetConfiguration) + .build(temporaryFolder); + + jamesServer.start(); + + dataProbe = jamesServer.getProbe(DataProbeImpl.class); + dataProbe.addDomain(DEFAULT_DOMAIN); + + dataProbe.addUser(SENDER.asString(), PASSWORD); + dataProbe.addUser(ALICE.asString(), PASSWORD); + dataProbe.addUser(BOB.asString(), PASSWORD); + dataProbe.addUser(CEDRIC.asString(), PASSWORD); + + mailRepositoryProbe = jamesServer.getProbe(MailRepositoryProbeImpl.class); + } + + @AfterEach + void tearDown() { + jamesServer.shutdown(); + } + + @Test + void dsnBounceWithForwardShouldNotLeadToALoop(@TempDir File temporaryFolder) throws Exception { + setUp(temporaryFolder, MailetContainer.builder() + .putProcessor(ProcessorConfiguration.root() + .addMailet(MailetConfiguration.builder() + .matcher(RecipientIs.class) + .matcherCondition(CEDRIC.asString()) + .mailet(ToProcessor.class) + .addProperty("processor", STATE_BOUNCES)) + .addMailet(TO_TRANSPORT)) + .putProcessor(CommonProcessors.error()) + .putProcessor(CommonProcessors.rrtError()) + .putProcessor(CommonProcessors.transport()) + .putProcessor(CommonProcessors.bounces())); + + dataProbe.addMapping(MappingSource.fromUser(BOB), Mapping.forward(BOB.asString())); + dataProbe.addMapping(MappingSource.fromUser(BOB), Mapping.forward(CEDRIC.asString())); + + messageSender.connect(LOCALHOST_IP, jamesServer.getProbe(SmtpGuiceProbe.class).getSmtpPort()) + .authenticate(SENDER.asString(), PASSWORD) + .sendMessage(SENDER.asString(), BOB.asString()); + + Awaitility.await().until(() -> jamesServer.getProbe(SpoolerProbe.class).processingFinished()); + + assertThat(mailRepositoryProbe.getRepositoryMailCount(ERROR_REPOSITORY)) + .isZero(); + } + + @Test + void bounceWithForwardShouldNotLeadToALoop(@TempDir File temporaryFolder) throws Exception { + setUp(temporaryFolder, MailetContainer.builder() + .putProcessor(ProcessorConfiguration.root() + .addMailet(MailetConfiguration.builder() + .matcher(RecipientIs.class) + .matcherCondition(CEDRIC.asString()) + .mailet(ToProcessor.class) + .addProperty("processor", STATE_BOUNCES)) + .addMailet(TO_TRANSPORT)) + .putProcessor(CommonProcessors.error()) + .putProcessor(CommonProcessors.rrtError()) + .putProcessor(CommonProcessors.transport()) + .putProcessor(ProcessorConfiguration.bounces() + .enableJmx(false) + .addMailet(MailetConfiguration.builder() + .matcher(All.class) + .mailet(Bounce.class) + .addProperty("passThrough", "false")) + .build())); + + dataProbe.addMapping(MappingSource.fromUser(BOB), Mapping.forward(BOB.asString())); + dataProbe.addMapping(MappingSource.fromUser(BOB), Mapping.forward(CEDRIC.asString())); + + messageSender.connect(LOCALHOST_IP, jamesServer.getProbe(SmtpGuiceProbe.class).getSmtpPort()) + .authenticate(SENDER.asString(), PASSWORD) + .sendMessage(SENDER.asString(), BOB.asString()); + + Awaitility.await().until(() -> jamesServer.getProbe(SpoolerProbe.class).processingFinished()); + + assertThat(mailRepositoryProbe.getRepositoryMailCount(ERROR_REPOSITORY)) + .isZero(); + } +} diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/redirect/ProcessRedirectNotify.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/redirect/ProcessRedirectNotify.java index 5e78eae218..e0118f63af 100644 --- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/redirect/ProcessRedirectNotify.java +++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/redirect/ProcessRedirectNotify.java @@ -18,11 +18,16 @@ ****************************************************************/ package org.apache.james.transport.mailets.redirect; +import static org.apache.mailet.LoopPrevention.RECORDED_RECIPIENTS_ATTRIBUTE_NAME; + +import java.util.Optional; + import jakarta.mail.MessagingException; import jakarta.mail.internet.MimeMessage; import org.apache.james.lifecycle.api.LifecycleUtil; import org.apache.james.server.core.MailImpl; +import org.apache.mailet.Attribute; import org.apache.mailet.Mail; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -108,7 +113,9 @@ public class ProcessRedirectNotify { private void finalizeMail(MailImpl mail) throws MessagingException { mail.getMessage().saveChanges(); + Optional<Attribute> recordedRecipients = mail.getAttribute(RECORDED_RECIPIENTS_ATTRIBUTE_NAME); mail.removeAllAttributes(); + recordedRecipients.ifPresent(mail::setAttribute); } private boolean keepMessageId() { --------------------------------------------------------------------- To unsubscribe, e-mail: notifications-unsubscr...@james.apache.org For additional commands, e-mail: notifications-h...@james.apache.org