You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@james.apache.org by rc...@apache.org on 2024/07/02 07:55:43 UTC
(james-project) 06/09: JAMES-4044 Handle both presence and value matching
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
commit 9fbcaca010f10c74d5b2f9d7f58c0be54de92786
Author: Benoit TELLIER <bt...@linagora.com>
AuthorDate: Wed Jun 19 15:10:01 2024 +0200
JAMES-4044 Handle both presence and value matching
---
docs/modules/servers/partials/LDAPMatchers.adoc | 30 +++++++++-
server/mailet/ldap/README.md | 26 +++++++-
.../james/transport/matchers/HasLDAPAttribute.java | 37 +++++++-----
.../transport/matchers/SenderHasLDAPAttribute.java | 33 +++++++----
.../transport/matchers/HasLDAPAttributeTest.java | 67 ++++++++++++++++++++-
.../matchers/SenderHasLDAPAttributeTest.java | 69 ++++++++++++++++++++++
6 files changed, 228 insertions(+), 34 deletions(-)
diff --git a/docs/modules/servers/partials/LDAPMatchers.adoc b/docs/modules/servers/partials/LDAPMatchers.adoc
index a202ba65ec..44980ca084 100644
--- a/docs/modules/servers/partials/LDAPMatchers.adoc
+++ b/docs/modules/servers/partials/LDAPMatchers.adoc
@@ -24,18 +24,42 @@ Then copy the JAR located in `/target` into the `extensions-jars` folder of your
The LDAP settings are reused from the `usersrepository.xml` configuration file.
-Then LDAP matchers can be configured within `mailetcontainer.xml`. For instance:
+Then LDAP matchers can be configured within `mailetcontainer.xml`.
+
+Then LDAP matchers can be configured within `mailetcontainer.xml`.
+
+For instance:
....xml
+<!-- Matches recipients that have the following attribute with the specified value-->
<mailet matcher="HasLDAPAttibute=description:blocked" class="Null">
-
+
</mailet>
....
or
....xml
+<!-- Matches sender that have the following attribute with the specified value-->
<mailet matcher="SenderHasLDAPAttibute=description:blocked" class="Null">
-
+
+</mailet>
+....
+
+or
+
+....xml
+<!-- Matches recipients that have the following attribute regardless of the actual value-->
+<mailet matcher="HasLDAPAttibute=description" class="Null">
+
+</mailet>
+....
+
+or
+
+....xml
+<!-- Matches sender that have the following attribute regardless of the actual value-->
+<mailet matcher="SenderHasLDAPAttibute=description" class="Null">
+
</mailet>
....
diff --git a/server/mailet/ldap/README.md b/server/mailet/ldap/README.md
index 16c21dbd83..b2ccb82d26 100644
--- a/server/mailet/ldap/README.md
+++ b/server/mailet/ldap/README.md
@@ -24,18 +24,40 @@ Then copy the JAR located in `/target` into the `extensions-jars` folder of your
The LDAP settings are reused from the `usersrepository.xml` configuration file.
-Then LDAP matchers can be configured within `mailetcontainer.xml`. For instance:
+Then LDAP matchers can be configured within `mailetcontainer.xml`.
+
+For instance:
```xml
+<!-- Matches recipients that have the following attribute with the specified value-->
<mailet matcher="HasLDAPAttibute=description:blocked" class="Null">
-
+
</mailet>
```
or
```xml
+<!-- Matches sender that have the following attribute with the specified value-->
<mailet matcher="SenderHasLDAPAttibute=description:blocked" class="Null">
+
+</mailet>
+```
+
+or
+
+```xml
+<!-- Matches recipients that have the following attribute regardless of the actual value-->
+<mailet matcher="HasLDAPAttibute=description" class="Null">
+
+</mailet>
+```
+
+or
+
+```xml
+<!-- Matches sender that have the following attribute regardless of the actual value-->
+<mailet matcher="SenderHasLDAPAttibute=description" class="Null">
</mailet>
```
diff --git a/server/mailet/ldap/src/main/java/org/apache/james/transport/matchers/HasLDAPAttribute.java b/server/mailet/ldap/src/main/java/org/apache/james/transport/matchers/HasLDAPAttribute.java
index f922ff484c..ce529f5edd 100644
--- a/server/mailet/ldap/src/main/java/org/apache/james/transport/matchers/HasLDAPAttribute.java
+++ b/server/mailet/ldap/src/main/java/org/apache/james/transport/matchers/HasLDAPAttribute.java
@@ -41,6 +41,7 @@ import com.unboundid.ldap.sdk.LDAPConnectionPool;
import com.unboundid.ldap.sdk.LDAPException;
import com.unboundid.ldap.sdk.LDAPSearchException;
import com.unboundid.ldap.sdk.SearchResult;
+import com.unboundid.ldap.sdk.SearchResultEntry;
import com.unboundid.ldap.sdk.SearchScope;
public class HasLDAPAttribute extends GenericMatcher {
@@ -49,7 +50,7 @@ public class HasLDAPAttribute extends GenericMatcher {
private final Filter objectClassFilter;
private final Optional<Filter> userExtraFilter;
private String attributeName;
- private String attributeValue;
+ private Optional<String> attributeValue;
private String[] attributes;
@Inject
@@ -67,16 +68,17 @@ public class HasLDAPAttribute extends GenericMatcher {
String condition = getCondition().trim();
int commaPosition = condition.indexOf(':');
- if (-1 == commaPosition) {
- throw new MessagingException("Syntax Error. Missing ':'.");
+ if (commaPosition == -1) {
+ attributeName = condition;
+ attributeValue = Optional.empty();
+ } else {
+ if (commaPosition == 0) {
+ throw new MessagingException("Syntax Error. Missing attribute name.");
+ }
+ attributeName = condition.substring(0, commaPosition).trim();
+ attributeValue = Optional.of(condition.substring(commaPosition + 1).trim());
}
- if (0 == commaPosition) {
- throw new MessagingException("Syntax Error. Missing attribute name.");
- }
-
- attributeName = condition.substring(0, commaPosition).trim();
- attributeValue = condition.substring(commaPosition + 1).trim();
attributes = ImmutableSet.builder()
.add(configuration.getReturnedAttributes())
.add(attributeName)
@@ -98,17 +100,22 @@ public class HasLDAPAttribute extends GenericMatcher {
createFilter(rcpt.asString(), configuration.getUserIdAttribute()),
attributes);
- return searchResult.getSearchEntries().stream()
- .anyMatch(entry -> Optional.ofNullable(entry.getAttribute(attributeName))
- .map(Attribute::getValue)
- .map(attributeValue::equals)
- .orElse(false));
-
+ return searchResult.getSearchEntries()
+ .stream()
+ .anyMatch(this::hasAttribute);
} catch (LDAPSearchException e) {
throw new RuntimeException("Failed searching LDAP", e);
}
}
+ private boolean hasAttribute(SearchResultEntry entry) {
+ return attributeValue.map(value -> Optional.ofNullable(entry.getAttribute(attributeName))
+ .map(Attribute::getValue)
+ .map(value::equals)
+ .orElse(false))
+ .orElseGet(() -> entry.hasAttribute(attributeName));
+ }
+
private Filter createFilter(String retrievalName, String ldapUserRetrievalAttribute) {
Filter specificUserFilter = Filter.createEqualityFilter(ldapUserRetrievalAttribute, retrievalName);
return userExtraFilter
diff --git a/server/mailet/ldap/src/main/java/org/apache/james/transport/matchers/SenderHasLDAPAttribute.java b/server/mailet/ldap/src/main/java/org/apache/james/transport/matchers/SenderHasLDAPAttribute.java
index e4103d4f00..54915d4ff3 100644
--- a/server/mailet/ldap/src/main/java/org/apache/james/transport/matchers/SenderHasLDAPAttribute.java
+++ b/server/mailet/ldap/src/main/java/org/apache/james/transport/matchers/SenderHasLDAPAttribute.java
@@ -41,6 +41,7 @@ import com.unboundid.ldap.sdk.LDAPConnectionPool;
import com.unboundid.ldap.sdk.LDAPException;
import com.unboundid.ldap.sdk.LDAPSearchException;
import com.unboundid.ldap.sdk.SearchResult;
+import com.unboundid.ldap.sdk.SearchResultEntry;
import com.unboundid.ldap.sdk.SearchScope;
public class SenderHasLDAPAttribute extends GenericMatcher {
@@ -49,7 +50,7 @@ public class SenderHasLDAPAttribute extends GenericMatcher {
private final Filter objectClassFilter;
private final Optional<Filter> userExtraFilter;
private String attributeName;
- private String attributeValue;
+ private Optional<String> attributeValue;
private String[] attributes;
@Inject
@@ -67,16 +68,17 @@ public class SenderHasLDAPAttribute extends GenericMatcher {
String condition = getCondition().trim();
int commaPosition = condition.indexOf(':');
- if (-1 == commaPosition) {
- throw new MessagingException("Syntax Error. Missing ':'.");
+ if (commaPosition == -1) {
+ attributeName = condition;
+ attributeValue = Optional.empty();
+ } else {
+ if (commaPosition == 0) {
+ throw new MessagingException("Syntax Error. Missing attribute name.");
+ }
+ attributeName = condition.substring(0, commaPosition).trim();
+ attributeValue = Optional.of(condition.substring(commaPosition + 1).trim());
}
- if (0 == commaPosition) {
- throw new MessagingException("Syntax Error. Missing attribute name.");
- }
-
- attributeName = condition.substring(0, commaPosition).trim();
- attributeValue = condition.substring(commaPosition + 1).trim();
attributes = ImmutableSet.builder()
.add(configuration.getReturnedAttributes())
.add(attributeName)
@@ -102,16 +104,21 @@ public class SenderHasLDAPAttribute extends GenericMatcher {
attributes);
return searchResult.getSearchEntries().stream()
- .anyMatch(entry -> Optional.ofNullable(entry.getAttribute(attributeName))
- .map(Attribute::getValue)
- .map(attributeValue::equals)
- .orElse(false));
+ .anyMatch(this::hasAttribute);
} catch (LDAPSearchException e) {
throw new RuntimeException("Failed searching LDAP", e);
}
}
+ private boolean hasAttribute(SearchResultEntry entry) {
+ return attributeValue.map(value -> Optional.ofNullable(entry.getAttribute(attributeName))
+ .map(Attribute::getValue)
+ .map(value::equals)
+ .orElse(false))
+ .orElseGet(() -> entry.hasAttribute(attributeName));
+ }
+
private Filter createFilter(String retrievalName, String ldapUserRetrievalAttribute) {
Filter specificUserFilter = Filter.createEqualityFilter(ldapUserRetrievalAttribute, retrievalName);
return userExtraFilter
diff --git a/server/mailet/ldap/src/test/java/org/apache/james/transport/matchers/HasLDAPAttributeTest.java b/server/mailet/ldap/src/test/java/org/apache/james/transport/matchers/HasLDAPAttributeTest.java
index f1cdddaca4..7be38f426a 100644
--- a/server/mailet/ldap/src/test/java/org/apache/james/transport/matchers/HasLDAPAttributeTest.java
+++ b/server/mailet/ldap/src/test/java/org/apache/james/transport/matchers/HasLDAPAttributeTest.java
@@ -22,10 +22,14 @@ package org.apache.james.transport.matchers;
import static org.apache.james.user.ldap.DockerLdapSingleton.ADMIN;
import static org.apache.james.user.ldap.DockerLdapSingleton.ADMIN_PASSWORD;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatCode;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
import java.util.Collection;
import java.util.Optional;
+import jakarta.mail.MessagingException;
+
import org.apache.commons.configuration2.HierarchicalConfiguration;
import org.apache.commons.configuration2.plist.PropertyListConfiguration;
import org.apache.commons.configuration2.tree.ImmutableNode;
@@ -55,7 +59,7 @@ class HasLDAPAttributeTest {
}
@Test
- void shouldReturnRecipientWhenHasAttribute() throws Exception {
+ void shouldReturnRecipientWhenHasAttributeWithValue() throws Exception {
HasLDAPAttribute testee = new HasLDAPAttribute(LdapRepositoryConfiguration.from(ldapRepositoryConfigurationWithVirtualHosting(ldapContainer)));
FakeMatcherConfig matcherConfig = FakeMatcherConfig.builder()
.matcherName("HasLDAPAttribute")
@@ -72,6 +76,67 @@ class HasLDAPAttributeTest {
assertThat(matched).containsOnly(recipient);
}
+ @Test
+ void shouldThrowWhenPrefixedWithDelimiter() throws Exception {
+ HasLDAPAttribute testee = new HasLDAPAttribute(LdapRepositoryConfiguration.from(ldapRepositoryConfigurationWithVirtualHosting(ldapContainer)));
+ FakeMatcherConfig matcherConfig = FakeMatcherConfig.builder()
+ .matcherName("HasLDAPAttribute")
+ .condition(":abcdef")
+ .build();
+
+ assertThatThrownBy(() -> testee.init(matcherConfig))
+ .isInstanceOf(MessagingException.class);
+ }
+
+ @Test
+ void shouldNotThrowWhenValueContainsDelimiter() throws Exception {
+ HasLDAPAttribute testee = new HasLDAPAttribute(LdapRepositoryConfiguration.from(ldapRepositoryConfigurationWithVirtualHosting(ldapContainer)));
+ FakeMatcherConfig matcherConfig = FakeMatcherConfig.builder()
+ .matcherName("HasLDAPAttribute")
+ .condition("description:abc:def")
+ .build();
+ testee.init(matcherConfig);
+
+ assertThatCode(() -> testee.init(matcherConfig))
+ .doesNotThrowAnyException();;
+ }
+
+ @Test
+ void shouldReturnRecipientWhenHasAttribute() throws Exception {
+ HasLDAPAttribute testee = new HasLDAPAttribute(LdapRepositoryConfiguration.from(ldapRepositoryConfigurationWithVirtualHosting(ldapContainer)));
+ FakeMatcherConfig matcherConfig = FakeMatcherConfig.builder()
+ .matcherName("HasLDAPAttribute")
+ .condition("description")
+ .build();
+ testee.init(matcherConfig);
+
+ MailAddress recipient = new MailAddress("james-user@james.org");
+ Collection<MailAddress> matched = testee.match(FakeMail.builder()
+ .name("default-id")
+ .recipient(recipient)
+ .build());
+
+ assertThat(matched).containsOnly(recipient);
+ }
+
+ @Test
+ void shouldNotReturnRecipientWhenDoesNotHaveAttibure() throws Exception {
+ HasLDAPAttribute testee = new HasLDAPAttribute(LdapRepositoryConfiguration.from(ldapRepositoryConfigurationWithVirtualHosting(ldapContainer)));
+ FakeMatcherConfig matcherConfig = FakeMatcherConfig.builder()
+ .matcherName("HasLDAPAttribute")
+ .condition("descriptionaa")
+ .build();
+ testee.init(matcherConfig);
+
+ MailAddress recipient = new MailAddress("james-user@james.org");
+ Collection<MailAddress> matched = testee.match(FakeMail.builder()
+ .name("default-id")
+ .recipient(recipient)
+ .build());
+
+ assertThat(matched).isEmpty();
+ }
+
@Test
void shouldReturnEmptyWhenHasNoAttribute() throws Exception {
HasLDAPAttribute testee = new HasLDAPAttribute(LdapRepositoryConfiguration.from(ldapRepositoryConfigurationWithVirtualHosting(ldapContainer)));
diff --git a/server/mailet/ldap/src/test/java/org/apache/james/transport/matchers/SenderHasLDAPAttributeTest.java b/server/mailet/ldap/src/test/java/org/apache/james/transport/matchers/SenderHasLDAPAttributeTest.java
index 02ebabc2b3..cbf1cfc500 100644
--- a/server/mailet/ldap/src/test/java/org/apache/james/transport/matchers/SenderHasLDAPAttributeTest.java
+++ b/server/mailet/ldap/src/test/java/org/apache/james/transport/matchers/SenderHasLDAPAttributeTest.java
@@ -22,10 +22,14 @@ package org.apache.james.transport.matchers;
import static org.apache.james.user.ldap.DockerLdapSingleton.ADMIN;
import static org.apache.james.user.ldap.DockerLdapSingleton.ADMIN_PASSWORD;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatCode;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
import java.util.Collection;
import java.util.Optional;
+import jakarta.mail.MessagingException;
+
import org.apache.commons.configuration2.HierarchicalConfiguration;
import org.apache.commons.configuration2.plist.PropertyListConfiguration;
import org.apache.commons.configuration2.tree.ImmutableNode;
@@ -54,6 +58,71 @@ class SenderHasLDAPAttributeTest {
ldapContainer.stop();
}
+ @Test
+ void shouldThrowWhenPrefixedWithDelimiter() throws Exception {
+ SenderHasLDAPAttribute testee = new SenderHasLDAPAttribute(LdapRepositoryConfiguration.from(ldapRepositoryConfigurationWithVirtualHosting(ldapContainer)));
+ FakeMatcherConfig matcherConfig = FakeMatcherConfig.builder()
+ .matcherName("HasLDAPAttribute")
+ .condition(":abcdef")
+ .build();
+
+ assertThatThrownBy(() -> testee.init(matcherConfig))
+ .isInstanceOf(MessagingException.class);
+ }
+
+ @Test
+ void shouldNotThrowWhenValueContainsDelimiter() throws Exception {
+ SenderHasLDAPAttribute testee = new SenderHasLDAPAttribute(LdapRepositoryConfiguration.from(ldapRepositoryConfigurationWithVirtualHosting(ldapContainer)));
+ FakeMatcherConfig matcherConfig = FakeMatcherConfig.builder()
+ .matcherName("HasLDAPAttribute")
+ .condition("description:abc:def")
+ .build();
+ testee.init(matcherConfig);
+
+ assertThatCode(() -> testee.init(matcherConfig))
+ .doesNotThrowAnyException();;
+ }
+
+ @Test
+ void shouldReturnRecipientWhenHasAttribute() throws Exception {
+ SenderHasLDAPAttribute testee = new SenderHasLDAPAttribute(LdapRepositoryConfiguration.from(ldapRepositoryConfigurationWithVirtualHosting(ldapContainer)));
+ FakeMatcherConfig matcherConfig = FakeMatcherConfig.builder()
+ .matcherName("SenderHasLDAPAttribute")
+ .condition("description")
+ .build();
+ testee.init(matcherConfig);
+
+ MailAddress sender = new MailAddress("james-user@james.org");
+ MailAddress recipient = new MailAddress("recipient@james.org");
+ Collection<MailAddress> matched = testee.match(FakeMail.builder()
+ .name("default-id")
+ .sender(sender)
+ .recipient(recipient)
+ .build());
+
+ assertThat(matched).containsOnly(recipient);
+ }
+
+ @Test
+ void shouldNotReturnRecipientWhenDoesNotHaveAttribute() throws Exception {
+ SenderHasLDAPAttribute testee = new SenderHasLDAPAttribute(LdapRepositoryConfiguration.from(ldapRepositoryConfigurationWithVirtualHosting(ldapContainer)));
+ FakeMatcherConfig matcherConfig = FakeMatcherConfig.builder()
+ .matcherName("SenderHasLDAPAttribute")
+ .condition("descriptionaa")
+ .build();
+ testee.init(matcherConfig);
+
+ MailAddress sender = new MailAddress("james-user@james.org");
+ MailAddress recipient = new MailAddress("recipient@james.org");
+ Collection<MailAddress> matched = testee.match(FakeMail.builder()
+ .name("default-id")
+ .sender(sender)
+ .recipient(recipient)
+ .build());
+
+ assertThat(matched).isEmpty();
+ }
+
@Test
void shouldReturnSenderWhenHasAttribute() throws Exception {
SenderHasLDAPAttribute testee = new SenderHasLDAPAttribute(LdapRepositoryConfiguration.from(ldapRepositoryConfigurationWithVirtualHosting(ldapContainer)));
---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@james.apache.org
For additional commands, e-mail: notifications-help@james.apache.org