You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by rc...@apache.org on 2020/06/08 03:12:29 UTC

[james-project] 08/16: JAMES-3196 CanSendFromImpl: enable sender correlation for SMTP and JMAP

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 e70b8696448b794b55fc46fba8bc028a13fe0f5d
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Fri May 29 09:17:21 2020 +0700

    JAMES-3196 CanSendFromImpl: enable sender correlation for SMTP and JMAP
    
    Explicitly link the user with the alias when allowing the mail
    submission to ease audit.
---
 .../methods/integration/SetMessagesMethodTest.java |  4 ++--
 .../methods/MailboxSendingNotAllowedException.java | 21 +++++++++++++------
 .../methods/SetMessagesCreationProcessor.java      | 24 ++++++++++++++++------
 .../draft/methods/SetMessagesUpdateProcessor.java  |  5 +++--
 .../SenderAuthIdentifyVerificationRcptHook.java    | 12 ++++++++++-
 5 files changed, 49 insertions(+), 17 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 46ab5db..38c9e99 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
@@ -2651,7 +2651,7 @@ public abstract class SetMessagesMethodTest {
             .body(ARGUMENTS + ".notCreated", aMapWithSize(1))
             .body(ARGUMENTS + ".notCreated", hasKey(messageCreationId))
             .body(ARGUMENTS + ".notCreated." + messageCreationId + ".type", equalTo("invalidProperties"))
-            .body(ARGUMENTS + ".notCreated." + messageCreationId + ".description", equalTo("Invalid 'from' field. Must be " + USERNAME.asString()));
+            .body(ARGUMENTS + ".notCreated." + messageCreationId + ".description", equalTo("Invalid 'from' field. One accepted value is " + USERNAME.asString()));
     }
 
     @Test
@@ -2999,7 +2999,7 @@ public abstract class SetMessagesMethodTest {
             .body(ARGUMENTS + ".notCreated[\"" + messageCreationId + "\"].type", equalTo("invalidProperties"))
             .body(ARGUMENTS + ".notCreated[\"" + messageCreationId + "\"].properties", hasSize(1))
             .body(ARGUMENTS + ".notCreated[\"" + messageCreationId + "\"].properties", contains("from"))
-            .body(ARGUMENTS + ".notCreated[\"" + messageCreationId + "\"].description", endsWith("Invalid 'from' field. Must be username@domain.tld"))
+            .body(ARGUMENTS + ".notCreated[\"" + messageCreationId + "\"].description", endsWith("Invalid 'from' field. One accepted value is username@domain.tld"))
             .body(ARGUMENTS + ".created", aMapWithSize(0));
     }
 
diff --git a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/methods/MailboxSendingNotAllowedException.java b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/methods/MailboxSendingNotAllowedException.java
index 19ac45f..8c3f0f5 100644
--- a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/methods/MailboxSendingNotAllowedException.java
+++ b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/methods/MailboxSendingNotAllowedException.java
@@ -19,18 +19,27 @@
 
 package org.apache.james.jmap.draft.methods;
 
+import java.util.Optional;
+
+import org.apache.james.core.Username;
 import org.apache.james.mailbox.exception.MailboxException;
 
 public class MailboxSendingNotAllowedException extends MailboxException {
 
-    private String allowedFrom;
+    private final Username connectedUser;
+    private final Optional<Username> fromField;
 
-    public MailboxSendingNotAllowedException(String allowedFrom) {
+    public MailboxSendingNotAllowedException(Username connectedUser, Optional<Username> fromField) {
         super();
-        this.allowedFrom = allowedFrom;
+        this.connectedUser = connectedUser;
+        this.fromField = fromField;
+    }
+
+    public Optional<Username> getFromField() {
+        return fromField;
     }
-    
-    public String getAllowedFrom() {
-        return allowedFrom;
+
+    public Username getConnectedUser() {
+        return connectedUser;
     }
 }
diff --git a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/methods/SetMessagesCreationProcessor.java b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/methods/SetMessagesCreationProcessor.java
index 77c53b6..a384bd8 100644
--- a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/methods/SetMessagesCreationProcessor.java
+++ b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/methods/SetMessagesCreationProcessor.java
@@ -132,12 +132,14 @@ public class SetMessagesCreationProcessor implements SetMessagesProcessor {
             assertIsUserOwnerOfMailboxes(mailboxIds, mailboxSession);
             performCreate(create, responseBuilder, mailboxSession);
         } catch (MailboxSendingNotAllowedException e) {
+            LOG.debug("{} is not allowed to send a mail using {} identity", e.getConnectedUser().asString(), e.getFromField());
+
             responseBuilder.notCreated(create.getCreationId(),
                     SetError.builder()
                         .type(SetError.Type.INVALID_PROPERTIES)
                         .properties(MessageProperty.from)
-                        .description("Invalid 'from' field. Must be " +
-                                e.getAllowedFrom())
+                        .description("Invalid 'from' field. One accepted value is " +
+                                e.getConnectedUser().asString())
                         .build());
 
         } catch (InvalidDraftKeywordsException e) {
@@ -296,14 +298,24 @@ public class SetMessagesCreationProcessor implements SetMessagesProcessor {
 
     @VisibleForTesting
     void assertUserCanSendFrom(Username connectedUser, Optional<DraftEmailer> from) throws MailboxSendingNotAllowedException {
-        if (!from.flatMap(DraftEmailer::getEmail)
-                .filter(email -> canSendFrom.userCanSendFrom(connectedUser, Username.of(email)))
-                .isPresent()) {
+
+        Optional<Username> maybeFromUser = from.flatMap(DraftEmailer::getEmail)
+            .map(Username::of);
+
+        if (!canSendMailUsingIdentity(connectedUser, maybeFromUser)) {
             String allowedSender = connectedUser.asString();
-            throw new MailboxSendingNotAllowedException(allowedSender);
+            throw new MailboxSendingNotAllowedException(connectedUser, maybeFromUser);
+        } else {
+            LOG.debug("{} is allowed to send a mail using {} identity", connectedUser.asString(), from);
         }
     }
 
+    private boolean canSendMailUsingIdentity(Username connectedUser, Optional<Username> maybeFromUser) {
+        return maybeFromUser
+                .filter(fromUser -> canSendFrom.userCanSendFrom(connectedUser, fromUser))
+                .isPresent();
+    }
+
     private MessageWithId handleDraftMessages(CreationMessageEntry entry, MailboxSession session) throws MailboxException, MessagingException, IOException {
         MetaDataWithContent newMessage = messageAppender.appendMessageInMailboxes(entry, toMailboxIds(entry), session);
         MessageFullView jmapMessage = messageFullViewFactory.fromMetaDataWithContent(newMessage).block();
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 c6f4039..35ba365 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
@@ -198,8 +198,9 @@ public class SetMessagesUpdateProcessor implements SetMessagesProcessor {
     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);
+            throw new MailboxSendingNotAllowedException(connectedUser, fromUser);
+        } else {
+            LOGGER.debug("{} is allowed to send a mail using {} identity", connectedUser.asString(), fromUser);
         }
     }
 
diff --git a/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/SenderAuthIdentifyVerificationRcptHook.java b/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/SenderAuthIdentifyVerificationRcptHook.java
index cf6924c..2543fab 100644
--- a/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/SenderAuthIdentifyVerificationRcptHook.java
+++ b/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/SenderAuthIdentifyVerificationRcptHook.java
@@ -32,11 +32,15 @@ import org.apache.james.protocols.smtp.hook.HookResult;
 import org.apache.james.rrt.api.CanSendFrom;
 import org.apache.james.user.api.UsersRepository;
 import org.apache.james.user.api.UsersRepositoryException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * Handler which check if the authenticated user is incorrect
  */
 public class SenderAuthIdentifyVerificationRcptHook extends AbstractSenderAuthIdentifyVerificationRcptHook {
+    private static final Logger LOGGER = LoggerFactory.getLogger(SenderAuthIdentifyVerificationRcptHook.class);
+
     private final DomainList domains;
     private final UsersRepository users;
     private final CanSendFrom canSendFrom;
@@ -78,6 +82,12 @@ public class SenderAuthIdentifyVerificationRcptHook extends AbstractSenderAuthId
 
     @Override
     protected boolean isSenderAllowed(Username connectedUser, Username sender) {
-        return canSendFrom.userCanSendFrom(connectedUser, sender);
+        boolean allowed = canSendFrom.userCanSendFrom(connectedUser, sender);
+        if (allowed) {
+            LOGGER.debug("{} is allowed to send a mail using {} identity", connectedUser.asString(), sender.asString());
+        } else {
+            LOGGER.info("{} is not allowed to send a mail using {} identity", connectedUser.asString(), sender.asString());
+        }
+        return allowed;
     }
 }


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