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 2023/04/06 02:17:27 UTC

[james-project] 02/03: IMAP - Make reactive SetACLProcessor

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 1d7dfd874ed925350378b2520e2d361ee6a3bb16
Author: Tung Van TRAN <vt...@linagora.com>
AuthorDate: Wed Mar 29 16:45:34 2023 +0700

    IMAP - Make reactive SetACLProcessor
---
 .../james/imap/processor/SetACLProcessor.java      | 150 +++++++++++----------
 .../james/imap/processor/SetACLProcessorTest.java  |  42 +++---
 2 files changed, 100 insertions(+), 92 deletions(-)

diff --git a/protocols/imap/src/main/java/org/apache/james/imap/processor/SetACLProcessor.java b/protocols/imap/src/main/java/org/apache/james/imap/processor/SetACLProcessor.java
index 269963abc0..cda9a652f7 100644
--- a/protocols/imap/src/main/java/org/apache/james/imap/processor/SetACLProcessor.java
+++ b/protocols/imap/src/main/java/org/apache/james/imap/processor/SetACLProcessor.java
@@ -19,10 +19,14 @@
 
 package org.apache.james.imap.processor;
 
+import static org.apache.james.util.ReactorUtils.logOnError;
+
 import java.util.List;
 
 import javax.inject.Inject;
 
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.tuple.Pair;
 import org.apache.james.imap.api.ImapConstants;
 import org.apache.james.imap.api.display.HumanReadableText;
 import org.apache.james.imap.api.message.Capability;
@@ -41,12 +45,15 @@ import org.apache.james.mailbox.model.MailboxACL.EntryKey;
 import org.apache.james.mailbox.model.MailboxACL.Rfc4314Rights;
 import org.apache.james.mailbox.model.MailboxPath;
 import org.apache.james.metrics.api.MetricFactory;
+import org.apache.james.util.FunctionalUtils;
 import org.apache.james.util.MDCBuilder;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.google.common.collect.ImmutableList;
 
+import reactor.core.publisher.Mono;
+
 /**
  * SETACL Processor.
  */
@@ -62,19 +69,39 @@ public class SetACLProcessor extends AbstractMailboxProcessor<SetACLRequest> imp
     }
 
     @Override
-    protected void processRequest(SetACLRequest request, ImapSession session, Responder responder) {
-
+    protected Mono<Void> processRequestReactive(SetACLRequest request, ImapSession session, Responder responder) {
         final MailboxManager mailboxManager = getMailboxManager();
         final MailboxSession mailboxSession = session.getMailboxSession();
         final String mailboxName = request.getMailboxName();
         final String identifier = request.getIdentifier();
-        try {
-            
-            /* parsing the rights is the the cheapest thing to begin with */
-            EditMode editMode = EditMode.REPLACE;
-            String rights = request.getRights();
-            if (rights != null && rights.length() > 0) {
-                switch (rights.charAt(0)) {
+        MailboxPath mailboxPath = PathConverter.forSession(session).buildFullPath(mailboxName);
+
+        return checkLookupRight(request, responder, mailboxManager, mailboxSession, mailboxPath)
+            .filter(FunctionalUtils.identityPredicate())
+            .flatMap(hasLookupRight -> checkAdminRight(request, responder, mailboxManager, mailboxSession, mailboxName, mailboxPath))
+            .filter(FunctionalUtils.identityPredicate())
+            .flatMap(hasAdminRight -> applyRight(mailboxManager, mailboxSession, identifier, request, mailboxPath)
+                .then(Mono.fromRunnable(() -> okComplete(request, responder)))
+                .then())
+            .onErrorResume(UnsupportedRightException.class,
+                error -> Mono.fromRunnable(() -> taggedBad(request, responder,
+                    new HumanReadableText(
+                        HumanReadableText.UNSUPPORTED_RIGHT_KEY,
+                        HumanReadableText.UNSUPPORTED_RIGHT_DEFAULT_VALUE,
+                        error.getUnsupportedRight()))))
+            .onErrorResume(MailboxNotFoundException.class,
+                error -> Mono.fromRunnable(() -> no(request, responder, HumanReadableText.MAILBOX_NOT_FOUND)))
+            .doOnEach(logOnError(MailboxException.class, e -> LOGGER.error("{} failed for mailbox {}", request.getCommand().getName(), mailboxName, e)))
+            .onErrorResume(MailboxException.class,
+                error -> Mono.fromRunnable(() -> no(request, responder, HumanReadableText.GENERIC_FAILURE_DURING_PROCESSING)));
+    }
+
+    /* parsing the rights is the cheapest thing to begin with */
+    private Pair<Rfc4314Rights, EditMode> parsingRightAndEditMode(SetACLRequest request) throws UnsupportedRightException {
+        EditMode editMode = EditMode.REPLACE;
+        String rights = request.getRights();
+        if (StringUtils.isNotEmpty(rights)) {
+            switch (rights.charAt(0)) {
                 case MailboxACL.ADD_RIGHTS_MARKER:
                     editMode = EditMode.ADD;
                     rights = rights.substring(1);
@@ -83,74 +110,49 @@ public class SetACLProcessor extends AbstractMailboxProcessor<SetACLRequest> imp
                     editMode = EditMode.REMOVE;
                     rights = rights.substring(1);
                     break;
-                }
-            }
-            Rfc4314Rights mailboxAclRights = Rfc4314Rights.fromSerializedRfc4314Rights(rights);
-
-            MailboxPath mailboxPath = PathConverter.forSession(session).buildFullPath(mailboxName);
-            // Check that mailbox exists
-            mailboxManager.getMailbox(mailboxPath, mailboxSession);
-
-            /*
-             * RFC 4314 section 6.
-             * An implementation MUST make sure the ACL commands themselves do
-             * not give information about mailboxes with appropriately
-             * restricted ACLs. For example, when a user agent executes a GETACL
-             * command on a mailbox that the user has no permission to LIST, the
-             * server would respond to that request with the same error that
-             * would be used if the mailbox did not exist, thus revealing no
-             * existence information, much less the mailbox’s ACL.
-             */
-            if (!mailboxManager.hasRight(mailboxPath, MailboxACL.Right.Lookup, mailboxSession)) {
-                no(request, responder, HumanReadableText.MAILBOX_NOT_FOUND);
-            } else if (!mailboxManager.hasRight(mailboxPath, MailboxACL.Right.Administer, mailboxSession)) {
-                /* RFC 4314 section 4. */
-                Object[] params = new Object[] {
-                        MailboxACL.Right.Administer.toString(),
-                        request.getCommand().getName(),
-                        mailboxName
-                };
-                HumanReadableText text = new HumanReadableText(HumanReadableText.UNSUFFICIENT_RIGHTS_KEY, HumanReadableText.UNSUFFICIENT_RIGHTS_DEFAULT_VALUE, params);
-                no(request, responder, text);
-            } else {
-                
-                EntryKey key = EntryKey.deserialize(identifier);
-                
-                // FIXME check if identifier is a valid user or group
-                // FIXME Servers, when processing a command that has an identifier as a
-                // parameter (i.e., any of SETACL, DELETEACL, and LISTRIGHTS commands),
-                // SHOULD first prepare the received identifier using "SASLprep" profile
-                // [SASLprep] of the "stringprep" algorithm [Stringprep].  If the
-                // preparation of the identifier fails or results in an empty string,
-                // the server MUST refuse to perform the command with a BAD response.
-                // Note that Section 6 recommends additional identifier’s verification
-                // steps.
-
-                mailboxManager.applyRightsCommand(mailboxPath,
-                    MailboxACL.command().key(key).mode(editMode).rights(mailboxAclRights).build(),
-                    mailboxSession);
-
-                okComplete(request, responder);
-                // FIXME should we send unsolicited responses here?
-                // unsolicitedResponses(session, responder, false);
             }
-        } catch (UnsupportedRightException e) {
-            /*
-             * RFc 4314, section 3.1
-             * Note that an unrecognized right MUST cause the command to return the
-             * BAD response.  In particular, the server MUST NOT silently ignore
-             * unrecognized rights.
-             * */
-            Object[] params = new Object[] {e.getUnsupportedRight()};
-            HumanReadableText text = new HumanReadableText(HumanReadableText.UNSUPPORTED_RIGHT_KEY, HumanReadableText.UNSUPPORTED_RIGHT_DEFAULT_VALUE, params);
-            taggedBad(request, responder, text);
-        } catch (MailboxNotFoundException e) {
-            no(request, responder, HumanReadableText.MAILBOX_NOT_FOUND);
-        } catch (MailboxException e) {
-            LOGGER.error("{} failed for mailbox {}", request.getCommand().getName(), mailboxName, e);
-            no(request, responder, HumanReadableText.GENERIC_FAILURE_DURING_PROCESSING);
         }
+        return Pair.of(Rfc4314Rights.fromSerializedRfc4314Rights(rights), editMode);
+    }
+
+    private Mono<Void> applyRight(MailboxManager mailboxManager,
+                                  MailboxSession mailboxSession,
+                                  String identifier,
+                                  SetACLRequest request,
+                                  MailboxPath mailboxPath) {
+        return Mono.fromCallable(() -> parsingRightAndEditMode(request))
+            .flatMap(rightAndEditMode -> Mono.from(mailboxManager.applyRightsCommandReactive(
+                mailboxPath,
+                MailboxACL.command()
+                    .key(EntryKey.deserialize(identifier))
+                    .mode(rightAndEditMode.getRight())
+                    .rights(rightAndEditMode.getLeft())
+                    .build(),
+                mailboxSession)));
+    }
 
+    private Mono<Boolean> checkAdminRight(SetACLRequest request, Responder responder, MailboxManager mailboxManager, MailboxSession mailboxSession, String mailboxName, MailboxPath mailboxPath) {
+        return Mono.from(mailboxManager.hasRightReactive(mailboxPath, MailboxACL.Right.Administer, mailboxSession))
+            .doOnNext(hasRight -> {
+                if (!hasRight) {
+                    no(request, responder,
+                        new HumanReadableText(
+                            HumanReadableText.UNSUFFICIENT_RIGHTS_KEY,
+                            HumanReadableText.UNSUFFICIENT_RIGHTS_DEFAULT_VALUE,
+                            MailboxACL.Right.Administer.toString(),
+                            request.getCommand().getName(),
+                            mailboxName));
+                }
+            });
+    }
+
+    private Mono<Boolean> checkLookupRight(SetACLRequest request, Responder responder, MailboxManager mailboxManager, MailboxSession mailboxSession, MailboxPath mailboxPath) {
+        return Mono.from(mailboxManager.hasRightReactive(mailboxPath, MailboxACL.Right.Lookup, mailboxSession))
+            .doOnNext(hasRight -> {
+                if (!hasRight) {
+                    no(request, responder, HumanReadableText.MAILBOX_NOT_FOUND);
+                }
+            });
     }
 
     @Override
diff --git a/protocols/imap/src/test/java/org/apache/james/imap/processor/SetACLProcessorTest.java b/protocols/imap/src/test/java/org/apache/james/imap/processor/SetACLProcessorTest.java
index 791fb347d0..847d3fe223 100644
--- a/protocols/imap/src/test/java/org/apache/james/imap/processor/SetACLProcessorTest.java
+++ b/protocols/imap/src/test/java/org/apache/james/imap/processor/SetACLProcessorTest.java
@@ -41,7 +41,6 @@ import org.apache.james.mailbox.MailboxSessionUtil;
 import org.apache.james.mailbox.MessageManager;
 import org.apache.james.mailbox.MessageManager.MailboxMetaData;
 import org.apache.james.mailbox.MessageManager.MailboxMetaData.FetchGroup;
-import org.apache.james.mailbox.exception.MailboxException;
 import org.apache.james.mailbox.exception.MailboxNotFoundException;
 import org.apache.james.mailbox.model.MailboxACL;
 import org.apache.james.mailbox.model.MailboxACL.EditMode;
@@ -109,11 +108,13 @@ class SetACLProcessorTest {
     }
     
     @Test
-    void testUnsupportedRight() throws Exception {
+    void testUnsupportedRight() {
         SetACLRequest setACLRequest = new SetACLRequest(TAG, MAILBOX_NAME, USER_1.asString(), UNSUPPORTED_RIGHT);
 
-        when(mailboxManager.hasRight(path, MailboxACL.Right.Lookup, mailboxSession))
-            .thenReturn(false);
+        when(mailboxManager.hasRightReactive(path, MailboxACL.Right.Lookup, mailboxSession))
+            .thenReturn(Mono.just(true));
+        when(mailboxManager.hasRightReactive(path, MailboxACL.Right.Administer, mailboxSession))
+            .thenReturn(Mono.just(true));
 
         subject.doProcess(setACLRequest, responder, imapSession).block();
 
@@ -127,11 +128,11 @@ class SetACLProcessorTest {
     }
     
     @Test
-    void testNoAdminRight() throws Exception {
-        when(mailboxManager.hasRight(path, MailboxACL.Right.Lookup, mailboxSession))
-            .thenReturn(true);
-        when(mailboxManager.hasRight(path, MailboxACL.Right.Administer, mailboxSession))
-            .thenReturn(false);
+    void testNoAdminRight() {
+        when(mailboxManager.hasRightReactive(path, MailboxACL.Right.Lookup, mailboxSession))
+            .thenReturn(Mono.just(true));
+        when(mailboxManager.hasRightReactive(path, MailboxACL.Right.Administer, mailboxSession))
+            .thenReturn(Mono.just(false));
 
         subject.doProcess(replaceAclRequest, responder, imapSession).block();
 
@@ -145,9 +146,10 @@ class SetACLProcessorTest {
     }
     
     @Test
-    void testInexistentMailboxName() throws Exception {
-        when(mailboxManager.getMailbox(any(MailboxPath.class), any(MailboxSession.class)))
-            .thenThrow(new MailboxNotFoundException(""));
+    void testInexistentMailboxName() {
+        when(mailboxManager.hasRightReactive(any(MailboxPath.class),
+            any(),any(MailboxSession.class)))
+            .thenReturn(Mono.error(new MailboxNotFoundException("")));
 
         subject.doProcess(replaceAclRequest, responder, imapSession).block();
 
@@ -175,16 +177,20 @@ class SetACLProcessorTest {
         testOp("", EditMode.REPLACE);
     }
     
-    private void testOp(String prefix, EditMode editMode) throws MailboxException {
-        when(mailboxManager.hasRight(path, MailboxACL.Right.Lookup, mailboxSession))
-            .thenReturn(true);
-        when(mailboxManager.hasRight(path, MailboxACL.Right.Administer, mailboxSession))
-            .thenReturn(true);
+    private void testOp(String prefix, EditMode editMode) {
+        when(mailboxManager.hasRightReactive(path, MailboxACL.Right.Lookup, mailboxSession))
+            .thenReturn(Mono.just(true));
+        when(mailboxManager.hasRightReactive(path, MailboxACL.Right.Administer, mailboxSession))
+            .thenReturn(Mono.just(true));
+        when(mailboxManager.applyRightsCommandReactive(path,
+            MailboxACL.command().key(user1Key).rights(setRights).mode(editMode).build(),
+            mailboxSession))
+            .thenReturn(Mono.empty());
 
         SetACLRequest r = new SetACLRequest(TAG, MAILBOX_NAME, USER_1.asString(), prefix + SET_RIGHTS);
         subject.doProcess(r, responder, imapSession).block();
 
-        verify(mailboxManager).applyRightsCommand(path,
+        verify(mailboxManager).applyRightsCommandReactive(path,
             MailboxACL.command().key(user1Key).rights(setRights).mode(editMode).build(),
             mailboxSession);
 


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@james.apache.org
For additional commands, e-mail: notifications-help@james.apache.org