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


The following commit(s) were added to refs/heads/master by this push:
     new e13beea8c6 JAMES-4050 Allow `%` and `*` characters in mailbox names
e13beea8c6 is described below

commit e13beea8c6b42c3246b00d4427b9d7492f086f14
Author: Quan Tran <hqt...@linagora.com>
AuthorDate: Tue Aug 27 14:50:34 2024 +0700

    JAMES-4050 Allow `%` and `*` characters in mailbox names
---
 .../servers/pages/distributed/configure/jvm.adoc   | 14 ++++-
 .../apache/james/mailbox/model/MailboxPath.java    | 10 +++-
 .../james/mailbox/model/MailboxPathTest.java       | 16 ++++++
 .../suite/ListingWithRelaxedMailboxName.java       | 55 ++++++++++++++++++
 .../ListWithPercentWildcardInMailboxName.test      | 67 ++++++++++++++++++++++
 mpt/impl/imap-mailbox/inmemory/pom.xml             |  2 +-
 .../InMemoryListingWithRelaxedMailboxNameTest.java | 45 +++++++++++++++
 .../docker-configuration/jvm.properties            |  6 +-
 .../sample-configuration/jvm.properties            |  6 +-
 .../docker-configuration/jvm.properties            |  4 ++
 .../sample-configuration/jvm.properties            |  6 +-
 .../docker-configuration/jvm.properties            |  4 ++
 .../sample-configuration/jvm.properties            |  6 +-
 .../jpa-app/sample-configuration/jvm.properties    |  6 +-
 .../memory-app/sample-configuration/jvm.properties |  6 +-
 15 files changed, 244 insertions(+), 9 deletions(-)

diff --git a/docs/modules/servers/pages/distributed/configure/jvm.adoc 
b/docs/modules/servers/pages/distributed/configure/jvm.adoc
index 7aefd940bc..58aac81469 100644
--- a/docs/modules/servers/pages/distributed/configure/jvm.adoc
+++ b/docs/modules/servers/pages/distributed/configure/jvm.adoc
@@ -118,4 +118,16 @@ Ex in `jvm.properties`
 ----
 james.mailet.container.check.enabled=false
 ----
-To disable the mailet container check at James startup.
\ No newline at end of file
+To disable the mailet container check at James startup.
+
+== Relax mailbox name validation
+
+The property `james.relaxed.mailbox.name.validation` allows to accept `*` and 
`%` characters in mailbox name.
+
+Optional. Boolean. Default to false.
+
+Ex in `jvm.properties`
+----
+james.relaxed.mailbox.name.validation=true
+----
+To relax validating `\*` and `%` characters in the mailbox name. Be careful as 
`%` and `*` are ambiguous for the LIST / LSUB commands that interpret those as 
wildcard thus returning all mailboxes matching the pattern.
\ No newline at end of file
diff --git 
a/mailbox/api/src/main/java/org/apache/james/mailbox/model/MailboxPath.java 
b/mailbox/api/src/main/java/org/apache/james/mailbox/model/MailboxPath.java
index bba81a2082..d43641de5d 100644
--- a/mailbox/api/src/main/java/org/apache/james/mailbox/model/MailboxPath.java
+++ b/mailbox/api/src/main/java/org/apache/james/mailbox/model/MailboxPath.java
@@ -51,6 +51,7 @@ public class MailboxPath {
     private static final Joiner PARTS_JOINER = Joiner.on(':');
     private static final LookupTranslator USERNAME_ESCAPER = new 
LookupTranslator(Map.of(":", "/;", "/", "//"));
     private static final LookupTranslator USERNAME_UNESCAPER = new 
LookupTranslator(Map.of("/;", ":", "//", "/"));
+    private static final boolean RELAX_MAILBOX_NAME_VALIDATION = 
Boolean.parseBoolean(System.getProperty("james.relaxed.mailbox.name.validation",
 "false"));
 
     /**
      * Return a {@link MailboxPath} which represent the INBOX of the given
@@ -94,7 +95,14 @@ public class MailboxPath {
         return Username.of(USERNAME_UNESCAPER.translate(parts.get(1)));
     }
 
-    private static final String INVALID_CHARS = "%*\r\n";
+    private static String evaluateInvalidChars() {
+        if (RELAX_MAILBOX_NAME_VALIDATION) {
+            return "\r\n";
+        }
+        return "%*\r\n";
+    }
+
+    private static final String INVALID_CHARS = evaluateInvalidChars();
     private static final CharMatcher INVALID_CHARS_MATCHER = 
CharMatcher.anyOf(INVALID_CHARS);
     // This is the size that all mailbox backend should support
     public  static final int MAX_MAILBOX_NAME_LENGTH = 200;
diff --git 
a/mailbox/api/src/test/java/org/apache/james/mailbox/model/MailboxPathTest.java 
b/mailbox/api/src/test/java/org/apache/james/mailbox/model/MailboxPathTest.java
index d679f1c491..676db676be 100644
--- 
a/mailbox/api/src/test/java/org/apache/james/mailbox/model/MailboxPathTest.java
+++ 
b/mailbox/api/src/test/java/org/apache/james/mailbox/model/MailboxPathTest.java
@@ -373,6 +373,14 @@ class MailboxPathTest {
             .isInstanceOf(MailboxNameException.class);
     }
 
+    @Test
+    void assertAcceptableShouldNotThrowOnPercentWhenRelaxMode() {
+        System.setProperty("james.relaxed.mailbox.name.validation", "true");
+
+        assertThatCode(() -> MailboxPath.forUser(USER, "a%b"))
+            .doesNotThrowAnyException();
+    }
+
     @Test
     void assertAcceptableShouldThrowOnWildcard() {
         assertThatThrownBy(() -> MailboxPath.forUser(USER, "a*b")
@@ -380,6 +388,14 @@ class MailboxPathTest {
             .isInstanceOf(MailboxNameException.class);
     }
 
+    @Test
+    void assertAcceptableShouldNotThrowOnWildcardWhenRelaxMode() {
+        System.setProperty("james.relaxed.mailbox.name.validation", "true");
+
+        assertThatCode(() -> MailboxPath.forUser(USER, "a*b"))
+            .doesNotThrowAnyException();
+    }
+
     @Test
     void assertAcceptableShouldThrowOnTooLongMailboxName() {
         assertThatThrownBy(() -> MailboxPath.forUser(USER, Strings.repeat("a", 
201))
diff --git 
a/mpt/impl/imap-mailbox/core/src/main/java/org/apache/james/mpt/imapmailbox/suite/ListingWithRelaxedMailboxName.java
 
b/mpt/impl/imap-mailbox/core/src/main/java/org/apache/james/mpt/imapmailbox/suite/ListingWithRelaxedMailboxName.java
new file mode 100644
index 0000000000..4fa368b3ae
--- /dev/null
+++ 
b/mpt/impl/imap-mailbox/core/src/main/java/org/apache/james/mpt/imapmailbox/suite/ListingWithRelaxedMailboxName.java
@@ -0,0 +1,55 @@
+/****************************************************************
+ * 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.mpt.imapmailbox.suite;
+
+import java.util.Locale;
+
+import org.apache.james.mpt.api.ImapHostSystem;
+import org.apache.james.mpt.imapmailbox.ImapTestConstants;
+import org.apache.james.mpt.imapmailbox.suite.base.BasicImapCommands;
+import org.apache.james.mpt.script.SimpleScriptedTestProtocol;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+public abstract class ListingWithRelaxedMailboxName implements 
ImapTestConstants {
+
+    protected abstract ImapHostSystem createImapHostSystem();
+    
+    protected ImapHostSystem system;
+    protected SimpleScriptedTestProtocol simpleScriptedTestProtocol;
+
+    @BeforeEach
+    public void setUp() throws Exception {
+        System.setProperty("james.relaxed.mailbox.name.validation", "true");
+
+        system = createImapHostSystem();
+        simpleScriptedTestProtocol = new 
SimpleScriptedTestProtocol("/org/apache/james/imap/scripts/", system)
+                .withUser(USER, PASSWORD);
+        BasicImapCommands.welcome(simpleScriptedTestProtocol);
+        BasicImapCommands.authenticate(simpleScriptedTestProtocol);
+    }
+
+    @Test
+    public void testListWithPercentWildcardInMailboxNameUS() throws Exception {
+        simpleScriptedTestProtocol
+            .withLocale(Locale.US)
+            .run("ListWithPercentWildcardInMailboxName");
+    }
+}
diff --git 
a/mpt/impl/imap-mailbox/core/src/main/resources/org/apache/james/imap/scripts/ListWithPercentWildcardInMailboxName.test
 
b/mpt/impl/imap-mailbox/core/src/main/resources/org/apache/james/imap/scripts/ListWithPercentWildcardInMailboxName.test
new file mode 100644
index 0000000000..d716d2a108
--- /dev/null
+++ 
b/mpt/impl/imap-mailbox/core/src/main/resources/org/apache/james/imap/scripts/ListWithPercentWildcardInMailboxName.test
@@ -0,0 +1,67 @@
+# Test creating and searching mailboxes with literal '*' and '%' characters in 
their names
+C: B01 CREATE "star*mailbox"
+S: B01 OK \[MAILBOXID \(.+\)\] CREATE completed.
+C: B011 CREATE "starmailbox"
+S: B011 OK \[MAILBOXID \(.+\)\] CREATE completed.
+C: B02 CREATE "percent%mailbox"
+S: B02 OK \[MAILBOXID \(.+\)\] CREATE completed.
+C: B021 CREATE "percentmailbox"
+S: B021 OK \[MAILBOXID \(.+\)\] CREATE completed.
+
+C: B03 LIST "" "star*mailbox"
+SUB {
+S: \* LIST \(\\HasNoChildren\) \"\.\" \"star\*mailbox\"
+S: \* LIST \(\\HasNoChildren\) \"\.\" \"starmailbox\"
+}
+S: B03 OK LIST completed.
+
+C: B04 LIST "" "percent%mailbox"
+SUB {
+S: \* LIST \(\\HasNoChildren\) \"\.\" \"percent%mailbox\"
+S: \* LIST \(\\HasNoChildren\) \"\.\" \"percentmailbox\"
+}
+S: B04 OK LIST completed.
+
+C: B05 LIST "" %
+SUB {
+S: \* LIST \(\\HasNoChildren\) \"\.\" \"star\*mailbox\"
+S: \* LIST \(\\HasNoChildren\) \"\.\" \"starmailbox\"
+S: \* LIST \(\\HasNoChildren\) \"\.\" \"percent%mailbox\"
+S: \* LIST \(\\HasNoChildren\) \"\.\" \"percentmailbox\"
+S: \* LIST \(\\HasNoChildren\) \"\.\" \"INBOX\"
+}
+S: B05 OK LIST completed.
+
+C: B06 LIST "" *
+SUB {
+S: \* LIST \(\\HasNoChildren\) \"\.\" \"star\*mailbox\"
+S: \* LIST \(\\HasNoChildren\) \"\.\" \"starmailbox\"
+S: \* LIST \(\\HasNoChildren\) \"\.\" \"percent%mailbox\"
+S: \* LIST \(\\HasNoChildren\) \"\.\" \"percentmailbox\"
+S: \* LIST \(\\HasNoChildren\) \"\.\" \"INBOX\"
+}
+S: B06 OK LIST completed.
+
+C: B07 LIST "" "star*mail%"
+SUB {
+S: \* LIST \(\\HasNoChildren\) \"\.\" \"star\*mailbox\"
+S: \* LIST \(\\HasNoChildren\) \"\.\" \"starmailbox\"
+}
+S: B07 OK LIST completed.
+
+C: B08 LIST "" "percent%mail*"
+SUB {
+S: \* LIST \(\\HasNoChildren\) \"\.\" \"percent%mailbox\"
+S: \* LIST \(\\HasNoChildren\) \"\.\" \"percentmailbox\"
+}
+S: B08 OK LIST completed.
+
+# Cleanup
+C: D9 DELETE "star*mailbox"
+S: D9 OK DELETE completed.
+C: D10 DELETE "starmailbox"
+S: D10 OK DELETE completed.
+C: D11 DELETE "percent%mailbox"
+S: D11 OK DELETE completed.
+C: D12 DELETE "percentmailbox"
+S: D12 OK DELETE completed.
\ No newline at end of file
diff --git a/mpt/impl/imap-mailbox/inmemory/pom.xml 
b/mpt/impl/imap-mailbox/inmemory/pom.xml
index 5ce1fd9fa5..b814ece20d 100644
--- a/mpt/impl/imap-mailbox/inmemory/pom.xml
+++ b/mpt/impl/imap-mailbox/inmemory/pom.xml
@@ -81,7 +81,7 @@
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-surefire-plugin</artifactId>
                 <configuration>
-                    <reuseForks>true</reuseForks>
+                    <reuseForks>false</reuseForks>
                     <forkCount>1C</forkCount>
                 </configuration>
             </plugin>
diff --git 
a/mpt/impl/imap-mailbox/inmemory/src/test/java/org/apache/james/mpt/imapmailbox/inmemory/InMemoryListingWithRelaxedMailboxNameTest.java
 
b/mpt/impl/imap-mailbox/inmemory/src/test/java/org/apache/james/mpt/imapmailbox/inmemory/InMemoryListingWithRelaxedMailboxNameTest.java
new file mode 100644
index 0000000000..e757e5322d
--- /dev/null
+++ 
b/mpt/impl/imap-mailbox/inmemory/src/test/java/org/apache/james/mpt/imapmailbox/inmemory/InMemoryListingWithRelaxedMailboxNameTest.java
@@ -0,0 +1,45 @@
+/****************************************************************
+ * 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.mpt.imapmailbox.inmemory;
+
+import org.apache.james.mpt.api.ImapHostSystem;
+import org.apache.james.mpt.imapmailbox.inmemory.host.InMemoryHostSystem;
+import org.apache.james.mpt.imapmailbox.suite.ListingWithRelaxedMailboxName;
+import org.junit.jupiter.api.BeforeEach;
+
+public class InMemoryListingWithRelaxedMailboxNameTest extends 
ListingWithRelaxedMailboxName {
+    private ImapHostSystem system;
+
+    @Override
+    @BeforeEach
+    public void setUp() throws Exception {
+        System.setProperty("james.relaxed.mailbox.name.validation", "true");
+
+        system = new InMemoryHostSystem();
+        system.beforeTest();
+        super.setUp();
+    }
+    
+    @Override
+    protected ImapHostSystem createImapHostSystem() {
+        return system;
+    }
+
+}
diff --git a/server/apps/cassandra-app/docker-configuration/jvm.properties 
b/server/apps/cassandra-app/docker-configuration/jvm.properties
index 7e3e6463ef..f638855ef4 100644
--- a/server/apps/cassandra-app/docker-configuration/jvm.properties
+++ b/server/apps/cassandra-app/docker-configuration/jvm.properties
@@ -45,4 +45,8 @@ config.file=/root/conf/cassandra-driver.conf
 
 # JMX, when enable causes RMI to plan System.gc every hour. Set this instead 
to once every 1000h.
 sun.rmi.dgc.server.gcInterval=3600000000
-sun.rmi.dgc.client.gcInterval=3600000000
\ No newline at end of file
+sun.rmi.dgc.client.gcInterval=3600000000
+
+# Relax validating `*` and `%` characters in the mailbox name. Defaults to 
false.
+# Be careful turning on this as `%` and `*` are ambiguous for the LIST / LSUB 
commands that interpret those as wildcard thus returning all mailboxes matching 
the pattern.
+#james.relaxed.mailbox.name.validation=true
\ No newline at end of file
diff --git a/server/apps/cassandra-app/sample-configuration/jvm.properties 
b/server/apps/cassandra-app/sample-configuration/jvm.properties
index 7cef86567a..3cc3d17386 100644
--- a/server/apps/cassandra-app/sample-configuration/jvm.properties
+++ b/server/apps/cassandra-app/sample-configuration/jvm.properties
@@ -68,4 +68,8 @@ jmx.remote.x.mlet.allow.getMBeansFromURL=false
 # james.jwt.zip.allow=false
 
 # Enable/disable mailet container check at James startup. Defaults to true.
-# james.mailet.container.check.enabled=true
\ No newline at end of file
+# james.mailet.container.check.enabled=true
+
+# Relax validating `*` and `%` characters in the mailbox name. Defaults to 
false.
+# Be careful turning on this as `%` and `*` are ambiguous for the LIST / LSUB 
commands that interpret those as wildcard thus returning all mailboxes matching 
the pattern.
+#james.relaxed.mailbox.name.validation=true
\ No newline at end of file
diff --git a/server/apps/distributed-app/docker-configuration/jvm.properties 
b/server/apps/distributed-app/docker-configuration/jvm.properties
index 93165bbf95..b7183468f0 100644
--- a/server/apps/distributed-app/docker-configuration/jvm.properties
+++ b/server/apps/distributed-app/docker-configuration/jvm.properties
@@ -46,3 +46,7 @@ config.file=/root/conf/cassandra-driver.conf
 # JMX, when enable causes RMI to plan System.gc every hour. Set this instead 
to once every 1000h.
 sun.rmi.dgc.server.gcInterval=3600000000
 sun.rmi.dgc.client.gcInterval=3600000000
+
+# Relax validating `*` and `%` characters in the mailbox name. Defaults to 
false.
+# Be careful turning on this as `%` and `*` are ambiguous for the LIST / LSUB 
commands that interpret those as wildcard thus returning all mailboxes matching 
the pattern.
+#james.relaxed.mailbox.name.validation=true
\ No newline at end of file
diff --git a/server/apps/distributed-app/sample-configuration/jvm.properties 
b/server/apps/distributed-app/sample-configuration/jvm.properties
index f55d3d20fe..9365a7fe91 100644
--- a/server/apps/distributed-app/sample-configuration/jvm.properties
+++ b/server/apps/distributed-app/sample-configuration/jvm.properties
@@ -84,4 +84,8 @@ jmx.remote.x.mlet.allow.getMBeansFromURL=false
 # james.reactor.inputstream.prefetch=4
 
 # Enable/disable mailet container check at James startup. Defaults to true.
-# james.mailet.container.check.enabled=true
\ No newline at end of file
+# james.mailet.container.check.enabled=true
+
+# Relax validating `*` and `%` characters in the mailbox name. Defaults to 
false.
+# Be careful turning on this as `%` and `*` are ambiguous for the LIST / LSUB 
commands that interpret those as wildcard thus returning all mailboxes matching 
the pattern.
+#james.relaxed.mailbox.name.validation=true
\ No newline at end of file
diff --git 
a/server/apps/distributed-pop3-app/docker-configuration/jvm.properties 
b/server/apps/distributed-pop3-app/docker-configuration/jvm.properties
index 93dedf3ef8..f638855ef4 100644
--- a/server/apps/distributed-pop3-app/docker-configuration/jvm.properties
+++ b/server/apps/distributed-pop3-app/docker-configuration/jvm.properties
@@ -46,3 +46,7 @@ config.file=/root/conf/cassandra-driver.conf
 # JMX, when enable causes RMI to plan System.gc every hour. Set this instead 
to once every 1000h.
 sun.rmi.dgc.server.gcInterval=3600000000
 sun.rmi.dgc.client.gcInterval=3600000000
+
+# Relax validating `*` and `%` characters in the mailbox name. Defaults to 
false.
+# Be careful turning on this as `%` and `*` are ambiguous for the LIST / LSUB 
commands that interpret those as wildcard thus returning all mailboxes matching 
the pattern.
+#james.relaxed.mailbox.name.validation=true
\ No newline at end of file
diff --git 
a/server/apps/distributed-pop3-app/sample-configuration/jvm.properties 
b/server/apps/distributed-pop3-app/sample-configuration/jvm.properties
index e7ece390c2..2612e150ff 100644
--- a/server/apps/distributed-pop3-app/sample-configuration/jvm.properties
+++ b/server/apps/distributed-pop3-app/sample-configuration/jvm.properties
@@ -58,4 +58,8 @@ jmx.remote.x.mlet.allow.getMBeansFromURL=false
 # james.jwt.zip.allow=false
 
 # Enable/disable mailet container check at James startup. Defaults to true.
-# james.mailet.container.check.enabled=true
\ No newline at end of file
+# james.mailet.container.check.enabled=true
+
+# Relax validating `*` and `%` characters in the mailbox name. Defaults to 
false.
+# Be careful turning on this as `%` and `*` are ambiguous for the LIST / LSUB 
commands that interpret those as wildcard thus returning all mailboxes matching 
the pattern.
+#james.relaxed.mailbox.name.validation=true
\ No newline at end of file
diff --git a/server/apps/jpa-app/sample-configuration/jvm.properties 
b/server/apps/jpa-app/sample-configuration/jvm.properties
index 04cfad0b6c..68859135ac 100644
--- a/server/apps/jpa-app/sample-configuration/jvm.properties
+++ b/server/apps/jpa-app/sample-configuration/jvm.properties
@@ -56,4 +56,8 @@ openjpa.Multithreaded=true
 # james.jwt.zip.allow=false
 
 # Enable/disable mailet container check at James startup. Defaults to true.
-# james.mailet.container.check.enabled=true
\ No newline at end of file
+# james.mailet.container.check.enabled=true
+
+# Relax validating `*` and `%` characters in the mailbox name. Defaults to 
false.
+# Be careful turning on this as `%` and `*` are ambiguous for the LIST / LSUB 
commands that interpret those as wildcard thus returning all mailboxes matching 
the pattern.
+#james.relaxed.mailbox.name.validation=true
\ No newline at end of file
diff --git a/server/apps/memory-app/sample-configuration/jvm.properties 
b/server/apps/memory-app/sample-configuration/jvm.properties
index 649b5fc3b1..692bc6bf46 100644
--- a/server/apps/memory-app/sample-configuration/jvm.properties
+++ b/server/apps/memory-app/sample-configuration/jvm.properties
@@ -58,4 +58,8 @@ jmx.remote.x.mlet.allow.getMBeansFromURL=false
 # james.jwt.zip.allow=false
 
 # Enable/disable mailet container check at James startup. Defaults to true.
-# james.mailet.container.check.enabled=true
\ No newline at end of file
+# james.mailet.container.check.enabled=true
+
+# Relax validating `*` and `%` characters in the mailbox name. Defaults to 
false.
+# Be careful turning on this as `%` and `*` are ambiguous for the LIST / LSUB 
commands that interpret those as wildcard thus returning all mailboxes matching 
the pattern.
+#james.relaxed.mailbox.name.validation=true
\ 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

Reply via email to