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 81c283387b JAMES-4032 Manage multiple domains with DKIMHook (#2657) 81c283387b is described below commit 81c283387b6dff8ea73c41535cd9b3594ae9ef89 Author: Benoit TELLIER <btell...@linagora.com> AuthorDate: Thu Feb 27 17:41:50 2025 +0700 JAMES-4032 Manage multiple domains with DKIMHook (#2657) --- .../java/org/apache/james/smtpserver/DKIMHook.java | 41 ++++++++++++++++------ .../org/apache/james/smtpserver/DKIMHookTest.java | 19 ++++++++-- 2 files changed, 48 insertions(+), 12 deletions(-) diff --git a/server/protocols/protocols-smtp-dkim/src/main/java/org/apache/james/smtpserver/DKIMHook.java b/server/protocols/protocols-smtp-dkim/src/main/java/org/apache/james/smtpserver/DKIMHook.java index e97cda41a8..9425ba9206 100644 --- a/server/protocols/protocols-smtp-dkim/src/main/java/org/apache/james/smtpserver/DKIMHook.java +++ b/server/protocols/protocols-smtp-dkim/src/main/java/org/apache/james/smtpserver/DKIMHook.java @@ -22,6 +22,7 @@ package org.apache.james.smtpserver; import static org.apache.james.protocols.smtp.SMTPRetCode.AUTH_REQUIRED; import static org.apache.james.protocols.smtp.SMTPRetCode.LOCAL_ERROR; +import java.util.Collection; import java.util.List; import java.util.Objects; import java.util.Optional; @@ -52,6 +53,7 @@ import org.slf4j.LoggerFactory; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Preconditions; +import com.google.common.base.Splitter; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; @@ -91,7 +93,7 @@ public class DKIMHook implements JamesMessageHook { @FunctionalInterface interface DKIMCheckNeeded extends Predicate<Mail> { - static DKIMCheckNeeded or(ImmutableList<DKIMCheckNeeded> checkNeededs) { + static DKIMCheckNeeded or(List<DKIMCheckNeeded> checkNeededs) { return mail -> checkNeededs.stream() .anyMatch(predicate -> predicate.test(mail)); } @@ -138,6 +140,7 @@ public class DKIMHook implements JamesMessageHook { } DKIMCheckNeeded ALL = any -> true; + DKIMCheckNeeded NONE = any -> false; } @FunctionalInterface @@ -152,6 +155,16 @@ public class DKIMHook implements JamesMessageHook { }; } + static SignatureRecordValidation or(SignatureRecordValidation a, SignatureRecordValidation b) { + return (sender, records) -> { + HookResult hookResult = a.validate(sender, records); + if (hookResult.equals(HookResult.DECLINED)) { + return hookResult; + } + return b.validate(sender, records); + }; + } + static SignatureRecordValidation signatureRequired(boolean required) { return (sender, records) -> { if (required && (records == null || records.isEmpty())) { @@ -194,13 +207,16 @@ public class DKIMHook implements JamesMessageHook { config.getBoolean("forceCRLF", true), config.getBoolean("signatureRequired", true), Optional.ofNullable(config.getString("onlyForSenderDomain", null)) - .map(Domain::of), + .map(s -> Splitter.on(',').splitToStream(s) + .map(Domain::of) + .toList()), Optional.ofNullable(config.getString("validatedEntities", null)) .map(entities -> Stream.of(entities.split(",")) .map(ValidatedEntity::from) .collect(ImmutableList.toImmutableList())) .orElse(DEFAULT_VALIDATED_ENTITIES), - Optional.ofNullable(config.getString("expectedDToken", null))); + Optional.ofNullable(config.getString("expectedDToken", null)) + .map(s -> Splitter.on(',').splitToList(s))); } public enum ValidatedEntity { @@ -219,12 +235,12 @@ public class DKIMHook implements JamesMessageHook { private final boolean forceCRLF; private final boolean signatureRequired; - private final Optional<Domain> onlyForSenderDomain; + private final Optional<List<Domain>> onlyForSenderDomain; private final ImmutableList<ValidatedEntity> validatedEntities; - private final Optional<String> expectedDToken; + private final Optional<List<String>> expectedDToken; - public Config(boolean forceCRLF, boolean signatureRequired, Optional<Domain> onlyForSenderDomain, - ImmutableList<ValidatedEntity> validatedEntities, Optional<String> expectedDToken) { + public Config(boolean forceCRLF, boolean signatureRequired, Optional<List<Domain>> onlyForSenderDomain, + ImmutableList<ValidatedEntity> validatedEntities, Optional<List<String>> expectedDToken) { this.forceCRLF = forceCRLF; this.signatureRequired = signatureRequired; this.onlyForSenderDomain = onlyForSenderDomain; @@ -234,15 +250,20 @@ public class DKIMHook implements JamesMessageHook { DKIMCheckNeeded dkimCheckNeeded() { return onlyForSenderDomain - .map(domain -> DKIMCheckNeeded.or(computeDKIMChecksNeeded(domain))) + .map(domains -> DKIMCheckNeeded.or(domains.stream() + .map(this::computeDKIMChecksNeeded) + .flatMap(Collection::stream) + .toList())) .orElse(DKIMCheckNeeded.ALL); } SignatureRecordValidation signatureRecordValidation() { return SignatureRecordValidation.and( SignatureRecordValidation.signatureRequired(signatureRequired), - expectedDToken.map(SignatureRecordValidation::expectedDToken) - .orElse(SignatureRecordValidation.ALLOW_ALL)); + expectedDToken.map(tokens -> tokens.stream() + .map(SignatureRecordValidation::expectedDToken) + .reduce(SignatureRecordValidation::or) + .get()).orElse(SignatureRecordValidation.ALLOW_ALL)); } private ImmutableList<DKIMCheckNeeded> computeDKIMChecksNeeded(Domain domain) { diff --git a/server/protocols/protocols-smtp-dkim/src/test/java/org/apache/james/smtpserver/DKIMHookTest.java b/server/protocols/protocols-smtp-dkim/src/test/java/org/apache/james/smtpserver/DKIMHookTest.java index dbb1184f9a..710dc09bf5 100644 --- a/server/protocols/protocols-smtp-dkim/src/test/java/org/apache/james/smtpserver/DKIMHookTest.java +++ b/server/protocols/protocols-smtp-dkim/src/test/java/org/apache/james/smtpserver/DKIMHookTest.java @@ -22,6 +22,7 @@ package org.apache.james.smtpserver; import static org.apache.james.smtpserver.DKIMHook.Config.DEFAULT_VALIDATED_ENTITIES; import static org.assertj.core.api.Assertions.assertThat; +import java.util.List; import java.util.Optional; import org.apache.commons.configuration2.BaseHierarchicalConfiguration; @@ -250,8 +251,22 @@ class DKIMHookTest { configuration.addProperty("expectedDToken", "apache.org"); assertThat(DKIMHook.Config.parse(configuration)) - .isEqualTo(new DKIMHook.Config(false, false, Optional.of(Domain.of("linagora.com")), - ImmutableList.of(ValidatedEntity.envelope), Optional.of("apache.org"))); + .isEqualTo(new DKIMHook.Config(false, false, Optional.of(List.of(Domain.of("linagora.com"))), + ImmutableList.of(ValidatedEntity.envelope), Optional.of(List.of("apache.org")))); + } + + @Test + void multivaluedConfiguration() { + BaseHierarchicalConfiguration configuration = new BaseHierarchicalConfiguration(); + configuration.addProperty("forceCRLF", false); + configuration.addProperty("signatureRequired", false); + configuration.addProperty("onlyForSenderDomain", "linagora.com,linto.ai"); + configuration.addProperty("validatedEntities", "envelope"); + configuration.addProperty("expectedDToken", "apache.org,linagora.vn"); + + assertThat(DKIMHook.Config.parse(configuration)) + .isEqualTo(new DKIMHook.Config(false, false, Optional.of(List.of(Domain.of("linagora.com"), Domain.of("linto.ai"))), + ImmutableList.of(ValidatedEntity.envelope), Optional.of(List.of("apache.org", "linagora.vn")))); } } } \ No newline at end of file --------------------------------------------------------------------- To unsubscribe, e-mail: notifications-unsubscr...@james.apache.org For additional commands, e-mail: notifications-h...@james.apache.org