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 441d729c6073073587d5db6342429f0799fdf609
Author: RĂ©mi KOWALSKI <rkowal...@linagora.com>
AuthorDate: Mon Feb 10 11:43:46 2020 +0100

    JAMES-3032 allow user to send a mail from an alias, allow alias in 
SetMessageUpdateProcessor
---
 .../methods/integration/SetMessagesMethodTest.java |  54 ++++++
 .../draft/methods/SetMessagesUpdateProcessor.java  |  23 ++-
 .../methods/SetMessagesUpdateProcessorTest.java    | 211 +++++++++++++++++++--
 3 files changed, 258 insertions(+), 30 deletions(-)

diff --git 
a/server/protocols/jmap-draft-integration-testing/jmap-draft-integration-testing-common/src/test/java/org/apache/james/jmap/draft/methods/integration/SetMessagesMethodTest.java
 
b/server/protocols/jmap-draft-integration-testing/jmap-draft-integration-testing-common/src/test/java/org/apache/james/jmap/draft/methods/integration/SetMessagesMethodTest.java
index a5776b2..85a6743 100644
--- 
a/server/protocols/jmap-draft-integration-testing/jmap-draft-integration-testing-common/src/test/java/org/apache/james/jmap/draft/methods/integration/SetMessagesMethodTest.java
+++ 
b/server/protocols/jmap-draft-integration-testing/jmap-draft-integration-testing-common/src/test/java/org/apache/james/jmap/draft/methods/integration/SetMessagesMethodTest.java
@@ -2164,6 +2164,60 @@ public abstract class SetMessagesMethodTest {
     }
 
     @Test
+    public void 
setMessagesShouldSendMessageByMovingDraftToOutboxForAMailSentFromAnAlias() 
throws Exception {
+        
dataProbe.addUserAliasMapping(Username.of(ALIAS_OF_USERNAME_MAIL).getLocalPart(),
 ALIAS_OF_USERNAME.getDomainPart().get().asString(), USERNAME.asString());
+
+        String draftCreationId = "creationId1337";
+        String fromAddress = USERNAME.asString();
+        String createDraft = "[" +
+            "  [" +
+            "    \"setMessages\"," +
+            "    {" +
+            "      \"create\": { \"" + draftCreationId  + "\" : {" +
+            "        \"from\": { \"name\": \"Me\", \"email\": \"" + 
ALIAS_OF_USERNAME.asString() + "\"}," +
+            "        \"to\": [{ \"name\": \"BOB\", \"email\": \"" + 
BOB.asString() + "\"}]," +
+            "        \"subject\": \"subject\"," +
+            "        \"keywords\": {\"$Draft\": true}," +
+            "        \"mailboxIds\": [\"" + getDraftId(accessToken) + "\"]" +
+            "      }}" +
+            "    }," +
+            "    \"#0\"" +
+            "  ]" +
+            "]";
+
+        String draftId =
+            with()
+                .header("Authorization", accessToken.asString())
+                .body(createDraft)
+                .post("/jmap")
+            .then()
+                .extract()
+                .path(ARGUMENTS + ".created[\"" + draftCreationId + "\"].id");
+
+        String moveDraftToOutBox = "[" +
+            "  [" +
+            "    \"setMessages\"," +
+            "    {" +
+            "      \"update\": { \"" + draftId + "\" : {" +
+            "        \"keywords\": {}," +
+            "        \"mailboxIds\": [\"" + getOutboxId(accessToken) + "\"]" +
+            "      }}" +
+            "    }," +
+            "    \"#0\"" +
+            "  ]" +
+            "]";
+
+        with()
+            .header("Authorization", accessToken.asString())
+            .body(moveDraftToOutBox)
+            .post("/jmap");
+
+        calmlyAwait
+            .pollDelay(Duration.FIVE_HUNDRED_MILLISECONDS)
+            .atMost(30, TimeUnit.SECONDS).until(() -> 
isAnyMessageFoundInRecipientsMailboxes(bobAccessToken));
+    }
+
+    @Test
     public void setMessagesShouldRejectDraftCopyToOutbox() {
         String draftCreationId = "creationId1337";
         String fromAddress = USERNAME.asString();
diff --git 
a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/methods/SetMessagesUpdateProcessor.java
 
b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/methods/SetMessagesUpdateProcessor.java
index 07816cb..054e7ab 100644
--- 
a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/methods/SetMessagesUpdateProcessor.java
+++ 
b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/methods/SetMessagesUpdateProcessor.java
@@ -35,7 +35,6 @@ import javax.mail.MessagingException;
 import javax.mail.Session;
 import javax.mail.internet.MimeMessage;
 
-import org.apache.james.core.MailAddress;
 import org.apache.james.core.Username;
 import 
org.apache.james.jmap.draft.exceptions.DraftMessageMailboxUpdateException;
 import org.apache.james.jmap.draft.exceptions.InvalidOutboxMoveException;
@@ -64,6 +63,7 @@ import org.apache.james.mailbox.model.MessageMoves;
 import org.apache.james.mailbox.model.MessageResult;
 import org.apache.james.metrics.api.MetricFactory;
 import org.apache.james.metrics.api.TimeMetric;
+import org.apache.james.rrt.api.CanSendFrom;
 import org.apache.james.server.core.MailImpl;
 import org.apache.james.util.OptionalUtils;
 import org.slf4j.Logger;
@@ -87,6 +87,7 @@ public class SetMessagesUpdateProcessor implements 
SetMessagesProcessor {
     private final MessageSender messageSender;
 
     private final ReferenceUpdater referenceUpdater;
+    private final CanSendFrom canSendFrom;
 
     @Inject
     @VisibleForTesting SetMessagesUpdateProcessor(
@@ -96,7 +97,8 @@ public class SetMessagesUpdateProcessor implements 
SetMessagesProcessor {
             Factory mailboxIdFactory,
             MessageSender messageSender,
             MetricFactory metricFactory,
-            ReferenceUpdater referenceUpdater) {
+            ReferenceUpdater referenceUpdater,
+            CanSendFrom canSendFrom) {
         this.updatePatchConverter = updatePatchConverter;
         this.messageIdManager = messageIdManager;
         this.systemMailboxesProvider = systemMailboxesProvider;
@@ -104,6 +106,7 @@ public class SetMessagesUpdateProcessor implements 
SetMessagesProcessor {
         this.metricFactory = metricFactory;
         this.messageSender = messageSender;
         this.referenceUpdater = referenceUpdater;
+        this.canSendFrom = canSendFrom;
     }
 
     @Override
@@ -180,7 +183,10 @@ public class SetMessagesUpdateProcessor implements 
SetMessagesProcessor {
             if (maybeMessageToSend.isPresent()) {
                 MessageResult messageToSend = maybeMessageToSend.get();
                 MailImpl mail = buildMailFromMessage(messageToSend);
-                assertUserIsSender(mailboxSession, 
mail.getMaybeSender().asOptional());
+                Optional<Username> fromUser = mail.getMaybeSender()
+                    .asOptional()
+                    .map(Username::fromMailAddress);
+                assertUserCanSendFrom(mailboxSession.getUser(), fromUser);
                 messageSender.sendMessage(messageId, mail, mailboxSession);
                 referenceUpdater.updateReferences(messageToSend.getHeaders(), 
mailboxSession);
             } else {
@@ -189,12 +195,11 @@ public class SetMessagesUpdateProcessor implements 
SetMessagesProcessor {
         }
     }
 
-    private void assertUserIsSender(MailboxSession session, 
Optional<MailAddress> sender) throws MailboxSendingNotAllowedException {
-        boolean userIsSender = sender.map(address -> 
session.getUser().equals(Username.fromMailAddress(address)))
-            .orElse(false);
-
-        if (!userIsSender) {
-            String allowedSender = session.getUser().asString();
+    @VisibleForTesting
+    void assertUserCanSendFrom(Username connectedUser, Optional<Username> 
fromUser) throws MailboxSendingNotAllowedException {
+        if (!fromUser.filter(from -> 
canSendFrom.userCanSendFrom(connectedUser, from))
+            .isPresent()) {
+            String allowedSender = connectedUser.asString();
             throw new MailboxSendingNotAllowedException(allowedSender);
         }
     }
diff --git 
a/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/draft/methods/SetMessagesUpdateProcessorTest.java
 
b/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/draft/methods/SetMessagesUpdateProcessorTest.java
index 9a60e03..9b6f88a 100644
--- 
a/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/draft/methods/SetMessagesUpdateProcessorTest.java
+++ 
b/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/draft/methods/SetMessagesUpdateProcessorTest.java
@@ -20,21 +20,63 @@
 package org.apache.james.jmap.draft.methods;
 
 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 static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
+import java.net.UnknownHostException;
+import java.util.Optional;
+import java.util.function.Supplier;
+import java.util.stream.Stream;
+
+import javax.mail.internet.AddressException;
+
+import org.apache.commons.configuration2.ex.ConfigurationException;
+import org.apache.james.core.Domain;
+import org.apache.james.core.Username;
+import org.apache.james.dnsservice.api.DNSService;
+import org.apache.james.domainlist.api.DomainListException;
+import org.apache.james.domainlist.lib.DomainListConfiguration;
+import org.apache.james.domainlist.memory.MemoryDomainList;
+import org.apache.james.jmap.draft.model.CreationMessage;
+import org.apache.james.jmap.draft.model.CreationMessageId;
 import org.apache.james.jmap.draft.model.MessageProperties;
 import org.apache.james.jmap.draft.model.SetMessagesRequest;
 import org.apache.james.jmap.draft.model.SetMessagesResponse;
 import org.apache.james.jmap.draft.model.UpdateMessagePatch;
+import org.apache.james.jmap.draft.send.MailSpool;
+import org.apache.james.jmap.draft.utils.JsoupHtmlTextExtractor;
+import org.apache.james.mailbox.BlobManager;
+import org.apache.james.mailbox.MailboxManager;
+import org.apache.james.mailbox.MailboxSession;
+import org.apache.james.mailbox.MailboxSessionUtil;
 import org.apache.james.mailbox.MessageIdManager;
+import org.apache.james.mailbox.MessageManager;
+import org.apache.james.mailbox.MessageUid;
+import org.apache.james.mailbox.Role;
 import org.apache.james.mailbox.SystemMailboxesProvider;
+import org.apache.james.mailbox.exception.MailboxException;
+import org.apache.james.mailbox.inmemory.InMemoryId;
+import org.apache.james.mailbox.model.ComposedMessageId;
 import org.apache.james.mailbox.model.MailboxId;
+import org.apache.james.mailbox.model.MailboxPath;
 import org.apache.james.mailbox.model.MessageId;
 import org.apache.james.mailbox.model.TestMessageId;
 import org.apache.james.metrics.tests.RecordingMetricFactory;
+import org.apache.james.rrt.api.CanSendFrom;
+import org.apache.james.rrt.api.RecipientRewriteTableException;
+import org.apache.james.rrt.lib.CanSendFromImpl;
+import org.apache.james.rrt.lib.MappingSource;
+import org.apache.james.rrt.memory.MemoryRecipientRewriteTable;
+import org.apache.james.util.OptionalUtils;
+import org.apache.james.util.html.HtmlTextExtractor;
+import org.apache.james.util.mime.MessageContentExtractor;
+import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.ExpectedException;
 
 import com.fasterxml.jackson.databind.node.JsonNodeFactory;
 import com.fasterxml.jackson.databind.node.ObjectNode;
@@ -43,21 +85,131 @@ import com.google.common.collect.ImmutableMap;
 
 public class SetMessagesUpdateProcessorTest {
 
-    @Test
-    public void processShouldReturnEmptyUpdatedWhenRequestHasEmptyUpdate() {
-        UpdateMessagePatchConverter updatePatchConverter = null;
-        MessageIdManager messageIdManager = null;
-        SystemMailboxesProvider systemMailboxesProvider = null;
-        MailboxId.Factory mailboxIdFactory = null;
-        MessageSender messageSender = null;
-        ReferenceUpdater referenceUpdater = null;
-        SetMessagesUpdateProcessor sut = new 
SetMessagesUpdateProcessor(updatePatchConverter,
+
+    private static final Username USER = Username.of("u...@example.com");
+    private static final Username OTHER_USER = 
Username.of("ot...@example.com");
+    private static final String OUTBOX = "outbox";
+    private static final InMemoryId OUTBOX_ID = InMemoryId.of(12345);
+    private static final String DRAFTS = "drafts";
+    private static final InMemoryId DRAFTS_ID = InMemoryId.of(12);
+
+    public static class TestSystemMailboxesProvider implements 
SystemMailboxesProvider {
+
+        private final Supplier<Optional<MessageManager>> outboxSupplier;
+        private final Supplier<Optional<MessageManager>> draftsSupplier;
+
+        private TestSystemMailboxesProvider(Supplier<Optional<MessageManager>> 
outboxSupplier,
+                                            Supplier<Optional<MessageManager>> 
draftsSupplier) {
+            this.outboxSupplier = outboxSupplier;
+            this.draftsSupplier = draftsSupplier;
+        }
+
+        @Override
+        public Stream<MessageManager> getMailboxByRole(Role aRole, Username 
username) {
+            if (aRole.equals(Role.OUTBOX)) {
+                return OptionalUtils.toStream(outboxSupplier.get());
+            } else if (aRole.equals(Role.DRAFTS)) {
+                return OptionalUtils.toStream(draftsSupplier.get());
+            }
+            return Stream.empty();
+        }
+    }
+
+    private final CreationMessage.Builder creationMessageBuilder = 
CreationMessage.builder()
+        
.from(CreationMessage.DraftEmailer.builder().name("alice").email("al...@example.com").build())
+        
.to(ImmutableList.of(CreationMessage.DraftEmailer.builder().name("bob").email("b...@example.com").build()))
+        .subject("Hey! ");
+
+    private final CreationMessageId creationMessageId = 
CreationMessageId.of("dlkja");
+
+    private final SetMessagesRequest createMessageInOutbox = 
SetMessagesRequest.builder()
+        .create(
+            creationMessageId,
+            creationMessageBuilder
+                .mailboxId(OUTBOX_ID.serialize())
+                
.from(CreationMessage.DraftEmailer.builder().name("user").email("u...@example.com").build())
+                .build())
+        .build();
+
+    private MailSpool mockedMailSpool;
+    private SystemMailboxesProvider fakeSystemMailboxesProvider;
+    private MailboxSession session;
+    private MailboxManager mockedMailboxManager;
+    private MailboxId.Factory mockedMailboxIdFactory;
+    private MemoryRecipientRewriteTable recipientRewriteTable;
+    private CanSendFrom canSendFrom;
+    private SetMessagesUpdateProcessor sut;
+    private MessageIdManager mockMessageIdManager;
+    private MessageManager outbox;
+    private MessageManager drafts;
+    private Optional<MessageManager> optionalOutbox;
+    private Optional<MessageManager> optionalDrafts;
+
+    @Rule
+    public ExpectedException expectedException = ExpectedException.none();
+    private MessageSender messageSender;
+    private ReferenceUpdater referenceUpdater;
+
+    @Before
+    public void setUp() throws MailboxException, DomainListException, 
UnknownHostException, ConfigurationException {
+        MessageContentExtractor messageContentExtractor = new 
MessageContentExtractor();
+        HtmlTextExtractor htmlTextExtractor = new JsoupHtmlTextExtractor();
+        BlobManager blobManager = mock(BlobManager.class);
+        
when(blobManager.toBlobId(any(MessageId.class))).thenReturn(org.apache.james.mailbox.model.BlobId.fromString("fake"));
+        MessageIdManager messageIdManager = mock(MessageIdManager.class);
+        recipientRewriteTable = new MemoryRecipientRewriteTable();
+
+        DNSService dnsService = mock(DNSService.class);
+        MemoryDomainList domainList = new MemoryDomainList(dnsService);
+        domainList.configure(DomainListConfiguration.builder()
+            .autoDetect(false)
+            .autoDetectIp(false));
+        domainList.addDomain(Domain.of("example.com"));
+        domainList.addDomain(Domain.of("other.org"));
+        recipientRewriteTable.setDomainList(domainList);
+        canSendFrom = new CanSendFromImpl(recipientRewriteTable);
+        mockedMailSpool = mock(MailSpool.class);
+        mockedMailboxManager = mock(MailboxManager.class);
+        mockedMailboxIdFactory = mock(MailboxId.Factory.class);
+
+        mockMessageIdManager = mock(MessageIdManager.class);
+
+        fakeSystemMailboxesProvider = new TestSystemMailboxesProvider(() -> 
optionalOutbox, () -> optionalDrafts);
+        session = MailboxSessionUtil.create(USER);
+        messageSender = new MessageSender(mockedMailSpool);
+        referenceUpdater = new ReferenceUpdater(mockMessageIdManager, 
mockedMailboxManager);
+
+        UpdateMessagePatchConverter updateMessagePatchConverter = null;
+        sut = new SetMessagesUpdateProcessor(updateMessagePatchConverter,
             messageIdManager,
-            systemMailboxesProvider,
-            mailboxIdFactory,
+            fakeSystemMailboxesProvider,
+            mockedMailboxIdFactory,
             messageSender,
             new RecordingMetricFactory(),
-            referenceUpdater);
+            referenceUpdater,
+            canSendFrom);
+
+        outbox = mock(MessageManager.class);
+        when(mockedMailboxIdFactory.fromString(OUTBOX_ID.serialize()))
+            .thenReturn(OUTBOX_ID);
+        when(mockedMailboxManager.getMailbox(OUTBOX_ID, session))
+            .thenReturn(outbox);
+
+        when(outbox.getId()).thenReturn(OUTBOX_ID);
+        when(outbox.getMailboxPath()).thenReturn(MailboxPath.forUser(USER, 
OUTBOX));
+
+        when(outbox.appendMessage(any(MessageManager.AppendCommand.class), 
any(MailboxSession.class)))
+            .thenReturn(new ComposedMessageId(OUTBOX_ID, TestMessageId.of(23), 
MessageUid.of(1)));
+
+        drafts = mock(MessageManager.class);
+        when(drafts.getId()).thenReturn(DRAFTS_ID);
+        when(drafts.getMailboxPath()).thenReturn(MailboxPath.forUser(USER, 
DRAFTS));
+        optionalOutbox = Optional.of(outbox);
+        optionalDrafts = Optional.of(drafts);
+    }
+
+    @Test
+    public void processShouldReturnEmptyUpdatedWhenRequestHasEmptyUpdate() {
         SetMessagesRequest requestWithEmptyUpdate = 
SetMessagesRequest.builder().build();
 
         SetMessagesResponse result = sut.process(requestWithEmptyUpdate, null);
@@ -81,18 +233,15 @@ public class SetMessagesUpdateProcessorTest {
         when(mockConverter.fromJsonNode(any(ObjectNode.class)))
                 .thenReturn(mockInvalidPatch);
 
-        MessageIdManager messageIdManager = null;
-        SystemMailboxesProvider systemMailboxesProvider = null;
-        MailboxId.Factory mailboxIdFactory = null;
-        MessageSender messageSender = null;
-        ReferenceUpdater referenceUpdater = null;
+
         SetMessagesUpdateProcessor sut = new 
SetMessagesUpdateProcessor(mockConverter,
-            messageIdManager,
-            systemMailboxesProvider,
-            mailboxIdFactory,
+            mockMessageIdManager,
+            fakeSystemMailboxesProvider,
+            mockedMailboxIdFactory,
             messageSender,
             new RecordingMetricFactory(),
-            referenceUpdater);
+            referenceUpdater,
+            canSendFrom);
         MessageId requestMessageId = TestMessageId.of(1);
         SetMessagesRequest requestWithInvalidUpdate = 
SetMessagesRequest.builder()
                 .update(ImmutableMap.of(requestMessageId, 
JsonNodeFactory.instance.objectNode()))
@@ -109,4 +258,24 @@ public class SetMessagesUpdateProcessorTest {
         assertThat(result.getUpdated()).isEmpty();
     }
 
+    @Test
+    public void 
assertUserCanSendFromShouldNotThrowWhenSenderIsAnAliasOfTheConnectedUser() 
throws RecipientRewriteTableException, AddressException {
+        Username sender = Username.of("al...@example.com");
+
+        recipientRewriteTable.addAliasMapping(MappingSource.fromUser("alias", 
"example.com"), USER.asString());
+
+        assertThatCode(() -> sut.assertUserCanSendFrom(USER, 
Optional.of(sender)))
+            .doesNotThrowAnyException();
+    }
+
+    @Test
+    public void 
assertUserCanSendFromShouldThrowWhenSenderIsAnAliasOfAnotherUser() throws 
RecipientRewriteTableException, AddressException {
+        Username sender = Username.of("al...@example.com");
+
+        recipientRewriteTable.addAliasMapping(MappingSource.fromUser("alias", 
"example.com"), OTHER_USER.asString());
+
+        assertThatThrownBy(() -> sut.assertUserCanSendFrom(USER, 
Optional.of(sender)))
+            .isInstanceOf(MailboxSendingNotAllowedException.class);
+    }
+
 }
\ No newline at end of file


---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscr...@james.apache.org
For additional commands, e-mail: server-dev-h...@james.apache.org

Reply via email to