Repository: james-project
Updated Branches:
  refs/heads/master e6a71cb50 -> c8d7d02c9


JAMES-1970 Push security of multi-mailbox search to the back-end


Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/541ee6e7
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/541ee6e7
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/541ee6e7

Branch: refs/heads/master
Commit: 541ee6e7ad6479ddd2cba4b7ca1a0761dbb9ea6d
Parents: e6a71cb
Author: Quynh Nguyen <qngu...@linagora.com>
Authored: Fri Mar 17 17:16:21 2017 +0700
Committer: benwa <btell...@linagora.com>
Committed: Tue Mar 21 07:47:23 2017 +0700

----------------------------------------------------------------------
 .../lucene/search/LuceneMessageSearchIndex.java | 50 ++++++++-------
 .../LuceneMailboxMessageSearchIndexTest.java    | 12 ++--
 .../search/AbstractMessageSearchIndexTest.java  | 65 +++++++++++++++++++-
 3 files changed, 97 insertions(+), 30 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/541ee6e7/mailbox/lucene/src/main/java/org/apache/james/mailbox/lucene/search/LuceneMessageSearchIndex.java
----------------------------------------------------------------------
diff --git 
a/mailbox/lucene/src/main/java/org/apache/james/mailbox/lucene/search/LuceneMessageSearchIndex.java
 
b/mailbox/lucene/src/main/java/org/apache/james/mailbox/lucene/search/LuceneMessageSearchIndex.java
index 2db951d..8fabcd4 100644
--- 
a/mailbox/lucene/src/main/java/org/apache/james/mailbox/lucene/search/LuceneMessageSearchIndex.java
+++ 
b/mailbox/lucene/src/main/java/org/apache/james/mailbox/lucene/search/LuceneMessageSearchIndex.java
@@ -101,6 +101,7 @@ import org.apache.lucene.index.IndexWriterConfig;
 import org.apache.lucene.index.IndexWriterConfig.OpenMode;
 import org.apache.lucene.index.Term;
 import org.apache.lucene.search.BooleanClause;
+import org.apache.lucene.search.BooleanClause.Occur;
 import org.apache.lucene.search.BooleanQuery;
 import org.apache.lucene.search.IndexSearcher;
 import org.apache.lucene.search.MatchAllDocsQuery;
@@ -273,6 +274,10 @@ public class LuceneMessageSearchIndex extends 
ListeningMessageSearchIndex {
     public final static String MAILBOX_ID_FIELD ="mailboxid";
 
     /**
+     * {@link Field} which will contain the user of the {@link MailboxSession}
+     */
+    public final static String USERS = "userSession";
+    /**
      * {@link Field} which will contain the id of the {@link MessageId}
      */
     public final static String MESSAGE_ID_FIELD ="messageid";
@@ -454,11 +459,12 @@ public class LuceneMessageSearchIndex extends 
ListeningMessageSearchIndex {
     public Iterator<MessageUid> search(MailboxSession session, Mailbox 
mailbox, SearchQuery searchQuery) throws MailboxException {
         Preconditions.checkArgument(session != null, "'session' is mandatory");
         MailboxId mailboxId = mailbox.getMailboxId();
-        return FluentIterable.from(searchMultimap(
-            MultimailboxesSearchQuery
-                .from(searchQuery)
-                .inMailboxes(mailboxId)
-                .build()))
+        MultimailboxesSearchQuery multimailboxesSearchQuery = 
MultimailboxesSearchQuery
+            .from(searchQuery)
+            .inMailboxes(mailboxId)
+            .build();
+
+        return FluentIterable.from(searchMultimap(multimailboxesSearchQuery, 
session))
             .transform(new Function<SearchResult, MessageUid>() {
                 @Override
                 public MessageUid apply(SearchResult input) {
@@ -471,7 +477,7 @@ public class LuceneMessageSearchIndex extends 
ListeningMessageSearchIndex {
     @Override
     public List<MessageId> search(MailboxSession session, 
MultimailboxesSearchQuery searchQuery, long limit) throws MailboxException {
         Preconditions.checkArgument(session != null, "'session' is mandatory");
-        return FluentIterable.from(searchMultimap(searchQuery))
+        return FluentIterable.from(searchMultimap(searchQuery, session))
             .transform(new Function<SearchResult, MessageId>() {
                 @Override
                 public MessageId apply(SearchResult input) {
@@ -483,7 +489,7 @@ public class LuceneMessageSearchIndex extends 
ListeningMessageSearchIndex {
             .toList();
     }
     
-    private List<SearchResult> searchMultimap(MultimailboxesSearchQuery 
searchQuery) throws MailboxException {
+    private List<SearchResult> searchMultimap(MultimailboxesSearchQuery 
searchQuery, MailboxSession session) throws MailboxException {
         ImmutableList.Builder<SearchResult> results = ImmutableList.builder();
         IndexSearcher searcher = null;
 
@@ -495,6 +501,7 @@ public class LuceneMessageSearchIndex extends 
ListeningMessageSearchIndex {
             query.add(inMailboxes, BooleanClause.Occur.MUST);
             // Not return flags documents
             query.add(new PrefixQuery(new Term(FLAGS_FIELD, "")), 
BooleanClause.Occur.MUST_NOT);
+            query.add(new TermQuery(new Term(USERS, 
session.getUser().getUserName().toUpperCase(Locale.US))), Occur.MUST);
             List<Criterion> crits = 
searchQuery.getSearchQuery().getCriterias();
             for (Criterion crit : crits) {
                 query.add(createQuery(crit, inMailboxes, 
searchQuery.getSearchQuery().getRecentMessageUids()), BooleanClause.Occur.MUST);
@@ -555,13 +562,14 @@ public class LuceneMessageSearchIndex extends 
ListeningMessageSearchIndex {
     private Document createMessageDocument(final MailboxSession session, final 
MailboxMessage membership) throws MailboxException{
         final Document doc = new Document();
         // TODO: Better handling
-        doc.add(new Field(MAILBOX_ID_FIELD, 
membership.getMailboxId().serialize().toUpperCase(Locale.ENGLISH), Store.YES, 
Index.NOT_ANALYZED));
+        doc.add(new Field(USERS, 
session.getUser().getUserName().toUpperCase(Locale.US), Store.YES, 
Index.NOT_ANALYZED));
+        doc.add(new Field(MAILBOX_ID_FIELD, 
membership.getMailboxId().serialize().toUpperCase(Locale.US), Store.YES, 
Index.NOT_ANALYZED));
         doc.add(new NumericField(UID_FIELD,Store.YES, 
true).setLongValue(membership.getUid().asLong()));
         doc.add(new Field(HAS_ATTACHMENT_FIELD, 
Boolean.toString(hasAttachment(membership)), Store.YES, Index.NOT_ANALYZED));
         doc.add(new Field(MESSAGE_ID_FIELD, 
SearchUtil.getSerializedMessageIdIfSupportedByUnderlyingStorageOrNull(membership),
 Store.YES, Index.NOT_ANALYZED));
 
         // create an unqiue key for the document which can be used later on 
updates to find the document
-        doc.add(new Field(ID_FIELD, 
membership.getMailboxId().serialize().toUpperCase(Locale.ENGLISH) +"-" + 
Long.toString(membership.getUid().asLong()), Store.YES, Index.NOT_ANALYZED));
+        doc.add(new Field(ID_FIELD, 
membership.getMailboxId().serialize().toUpperCase(Locale.US) +"-" + 
Long.toString(membership.getUid().asLong()), Store.YES, Index.NOT_ANALYZED));
 
         doc.add(new Field(INTERNAL_DATE_FIELD_YEAR_RESOLUTION, 
DateTools.dateToString(membership.getInternalDate(), 
DateTools.Resolution.YEAR), Store.NO, Index.NOT_ANALYZED));
         doc.add(new Field(INTERNAL_DATE_FIELD_MONTH_RESOLUTION, 
DateTools.dateToString(membership.getInternalDate(), 
DateTools.Resolution.MONTH), Store.NO, Index.NOT_ANALYZED));
@@ -590,9 +598,9 @@ public class LuceneMessageSearchIndex extends 
ListeningMessageSearchIndex {
                 Iterator<org.apache.james.mime4j.stream.Field> fields = 
header.iterator();
                 while(fields.hasNext()) {
                     org.apache.james.mime4j.stream.Field f = fields.next();
-                    String headerName = 
f.getName().toUpperCase(Locale.ENGLISH);
-                    String headerValue = 
f.getBody().toUpperCase(Locale.ENGLISH);
-                    String fullValue =  
f.toString().toUpperCase(Locale.ENGLISH);
+                    String headerName = f.getName().toUpperCase(Locale.US);
+                    String headerValue = f.getBody().toUpperCase(Locale.US);
+                    String fullValue =  f.toString().toUpperCase(Locale.US);
                     doc.add(new Field(HEADERS_FIELD, fullValue, Store.NO, 
Index.ANALYZED));
                     doc.add(new Field(PREFIX_HEADER_FIELD + headerName, 
headerValue, Store.NO, Index.ANALYZED));
                     
@@ -633,7 +641,7 @@ public class LuceneMessageSearchIndex extends 
ListeningMessageSearchIndex {
                                     Address address = aList.get(i);
                                     if (address instanceof 
org.apache.james.mime4j.dom.address.Mailbox) {
                                         
org.apache.james.mime4j.dom.address.Mailbox mailbox = 
(org.apache.james.mime4j.dom.address.Mailbox) address;
-                                        String value = 
AddressFormatter.DEFAULT.encode(mailbox).toUpperCase(Locale.ENGLISH);
+                                        String value = 
AddressFormatter.DEFAULT.encode(mailbox).toUpperCase(Locale.US);
                                         doc.add(new Field(field, value, 
Store.NO, Index.ANALYZED));
                                         if (i == 0) {
                                             String mailboxAddress = 
SearchUtil.getMailboxAddress(mailbox);
@@ -655,7 +663,7 @@ public class LuceneMessageSearchIndex extends 
ListeningMessageSearchIndex {
                                         MailboxList mList = ((Group) 
address).getMailboxes();
                                         for (int a = 0; a < mList.size(); a++) 
{
                                             
org.apache.james.mime4j.dom.address.Mailbox mailbox = mList.get(a);
-                                            String value = 
AddressFormatter.DEFAULT.encode(mailbox).toUpperCase(Locale.ENGLISH);
+                                            String value = 
AddressFormatter.DEFAULT.encode(mailbox).toUpperCase(Locale.US);
                                             doc.add(new Field(field, value, 
Store.NO, Index.ANALYZED));
 
                                             if (i == 0 && a == 0) {
@@ -727,7 +735,7 @@ public class LuceneMessageSearchIndex extends 
ListeningMessageSearchIndex {
                     BufferedReader bodyReader = new BufferedReader(new 
InputStreamReader(in, charset));
                     String line = null;
                     while((line = bodyReader.readLine()) != null) {
-                        doc.add(new Field(BODY_FIELD,  
line.toUpperCase(Locale.ENGLISH),Store.NO, Index.ANALYZED));
+                        doc.add(new Field(BODY_FIELD,  
line.toUpperCase(Locale.US),Store.NO, Index.ANALYZED));
                     }
                     
                 }
@@ -794,7 +802,7 @@ public class LuceneMessageSearchIndex extends 
ListeningMessageSearchIndex {
 
 
     private static Calendar getGMT() {
-        return Calendar.getInstance(TimeZone.getTimeZone("GMT"), 
Locale.ENGLISH);
+        return Calendar.getInstance(TimeZone.getTimeZone("GMT"), Locale.US);
     }
 
     
@@ -884,11 +892,11 @@ public class LuceneMessageSearchIndex extends 
ListeningMessageSearchIndex {
      */
     private Query createHeaderQuery(SearchQuery.HeaderCriterion crit) throws 
UnsupportedSearchException {
         HeaderOperator op = crit.getOperator();
-        String name = crit.getHeaderName().toUpperCase(Locale.ENGLISH);
+        String name = crit.getHeaderName().toUpperCase(Locale.US);
         String fieldName = PREFIX_HEADER_FIELD + name;
         if (op instanceof SearchQuery.ContainsOperator) {
             ContainsOperator cop = (ContainsOperator) op;
-            return createTermQuery(fieldName, 
cop.getValue().toUpperCase(Locale.ENGLISH));
+            return createTermQuery(fieldName, 
cop.getValue().toUpperCase(Locale.US));
         } else if (op instanceof SearchQuery.ExistsOperator){
             return new PrefixQuery(new Term(fieldName, ""));
         } else if (op instanceof SearchQuery.DateOperator) {
@@ -896,8 +904,8 @@ public class LuceneMessageSearchIndex extends 
ListeningMessageSearchIndex {
                 String field = toSentDateField(dop.getDateResultion());
                 return createQuery(field, dop);
         } else if (op instanceof SearchQuery.AddressOperator) {
-            String field = name.toLowerCase(Locale.ENGLISH);
-            return createTermQuery(field, ((SearchQuery.AddressOperator) 
op).getAddress().toUpperCase(Locale.ENGLISH));
+            String field = name.toLowerCase(Locale.US);
+            return createTermQuery(field, ((SearchQuery.AddressOperator) 
op).getAddress().toUpperCase(Locale.US));
         } else {
             // Operator not supported
             throw new UnsupportedSearchException();
@@ -1184,7 +1192,7 @@ public class LuceneMessageSearchIndex extends 
ListeningMessageSearchIndex {
      * @throws UnsupportedSearchException
      */
     private Query createTextQuery(SearchQuery.TextCriterion crit) throws 
UnsupportedSearchException {
-        String value = 
crit.getOperator().getValue().toUpperCase(Locale.ENGLISH);
+        String value = crit.getOperator().getValue().toUpperCase(Locale.US);
         switch(crit.getType()) {
         case BODY:
             return createTermQuery(BODY_FIELD, value);

http://git-wip-us.apache.org/repos/asf/james-project/blob/541ee6e7/mailbox/lucene/src/test/java/org/apache/james/mailbox/lucene/search/LuceneMailboxMessageSearchIndexTest.java
----------------------------------------------------------------------
diff --git 
a/mailbox/lucene/src/test/java/org/apache/james/mailbox/lucene/search/LuceneMailboxMessageSearchIndexTest.java
 
b/mailbox/lucene/src/test/java/org/apache/james/mailbox/lucene/search/LuceneMailboxMessageSearchIndexTest.java
index 2068cd2..413e4fb 100644
--- 
a/mailbox/lucene/src/test/java/org/apache/james/mailbox/lucene/search/LuceneMailboxMessageSearchIndexTest.java
+++ 
b/mailbox/lucene/src/test/java/org/apache/james/mailbox/lucene/search/LuceneMailboxMessageSearchIndexTest.java
@@ -94,6 +94,7 @@ public class LuceneMailboxMessageSearchIndexTest {
     
     @Before
     public void setUp() throws Exception {
+        session = new MockMailboxSession("username");
         TestMessageId.Factory factory = new TestMessageId.Factory();
         id1 = factory.generate();
         id2 = factory.generate();
@@ -122,23 +123,23 @@ public class LuceneMailboxMessageSearchIndexTest {
         
         uid1 = MessageUid.of(1);
         SimpleMailboxMembership m = new SimpleMailboxMembership(id1, 
mailbox.getMailboxId(), uid1, 0, new Date(), 200, new Flags(Flag.ANSWERED), "My 
Body".getBytes(), headersSubject);
-        index.add(null, mailbox, m);
+        index.add(session, mailbox, m);
 
         uid2 = MessageUid.of(1);
         SimpleMailboxMembership m2 = new SimpleMailboxMembership(id2, 
mailbox2.getMailboxId(), uid2, 0, new Date(), 20, new Flags(Flag.ANSWERED), "My 
Body".getBytes(), headersSubject);
-        index.add(null, mailbox2, m2);
+        index.add(session, mailbox2, m2);
         
         uid3 = MessageUid.of(2);
         Calendar cal = Calendar.getInstance();
         cal.set(1980, 2, 10);
         SimpleMailboxMembership m3 = new SimpleMailboxMembership(id3, 
mailbox.getMailboxId(), uid3, 0, cal.getTime(), 20, new Flags(Flag.DELETED), 
"My Otherbody".getBytes(), headersTest);
-        index.add(null, mailbox, m3);
+        index.add(session, mailbox, m3);
         
         uid4 = MessageUid.of(3);
         Calendar cal2 = Calendar.getInstance();
         cal2.set(8000, 2, 10);
         SimpleMailboxMembership m4 = new SimpleMailboxMembership(id4, 
mailbox.getMailboxId(), uid4, 0, cal2.getTime(), 20, new Flags(Flag.DELETED), 
"My Otherbody2".getBytes(), headersTestSubject);
-        index.add(null, mailbox, m4);
+        index.add(session, mailbox, m4);
         
         uid5 = MessageUid.of(10);
         MessageBuilder builder = new MessageBuilder();
@@ -150,9 +151,8 @@ public class LuceneMailboxMessageSearchIndexTest {
         builder.uid = uid5;
         builder.mailboxId = mailbox3.getMailboxId();
         
-        index.add(null, mailbox3, builder.build(id5));
+        index.add(session, mailbox3, builder.build(id5));
 
-        session = new MockMailboxSession("username");
     }
     
 

http://git-wip-us.apache.org/repos/asf/james-project/blob/541ee6e7/mailbox/store/src/test/java/org/apache/james/mailbox/store/search/AbstractMessageSearchIndexTest.java
----------------------------------------------------------------------
diff --git 
a/mailbox/store/src/test/java/org/apache/james/mailbox/store/search/AbstractMessageSearchIndexTest.java
 
b/mailbox/store/src/test/java/org/apache/james/mailbox/store/search/AbstractMessageSearchIndexTest.java
index 785e216..48b2708 100644
--- 
a/mailbox/store/src/test/java/org/apache/james/mailbox/store/search/AbstractMessageSearchIndexTest.java
+++ 
b/mailbox/store/src/test/java/org/apache/james/mailbox/store/search/AbstractMessageSearchIndexTest.java
@@ -31,6 +31,7 @@ import org.apache.james.mailbox.MailboxSession;
 import org.apache.james.mailbox.MessageIdManager;
 import org.apache.james.mailbox.exception.MailboxException;
 import org.apache.james.mailbox.model.ComposedMessageId;
+import org.apache.james.mailbox.model.MailboxConstants;
 import org.apache.james.mailbox.model.MailboxPath;
 import org.apache.james.mailbox.model.MessageId;
 import org.apache.james.mailbox.model.MultimailboxesSearchQuery;
@@ -50,6 +51,10 @@ import com.google.common.collect.Lists;
 
 public abstract class AbstractMessageSearchIndexTest {
 
+    private static final String INBOX = "INBOX";
+    private static final String OTHERUSER = "otheruser";
+    private static final String USERNAME = "benwa";
+
     private static final Logger LOGGER = 
LoggerFactory.getLogger(AbstractMessageSearchIndexTest.class);
     public static final long LIMIT = 100L;
 
@@ -58,7 +63,9 @@ public abstract class AbstractMessageSearchIndexTest {
     protected MessageIdManager messageIdManager;
     private Mailbox mailbox;
     private Mailbox mailbox2;
+    private Mailbox otherMailbox;
     private MailboxSession session;
+    private MailboxSession otherSession;
 
     private ComposedMessageId m1;
     private ComposedMessageId m2;
@@ -72,6 +79,7 @@ public abstract class AbstractMessageSearchIndexTest {
     private ComposedMessageId mOther;
     private ComposedMessageId mailWithAttachment;
     private ComposedMessageId mailWithInlinedAttachment;
+    private ComposedMessageId m10;
     private StoreMessageManager myFolderMessageManager;
 
 
@@ -79,16 +87,24 @@ public abstract class AbstractMessageSearchIndexTest {
     public void setUp() throws Exception {
         initializeMailboxManager();
 
-        session = storeMailboxManager.createSystemSession("benwa", LOGGER);
+        session = storeMailboxManager.createSystemSession(USERNAME, LOGGER);
+        otherSession = storeMailboxManager.createSystemSession(OTHERUSER, 
LOGGER);
+
+        MailboxPath inboxPath = new 
MailboxPath(MailboxConstants.USER_NAMESPACE, USERNAME, INBOX);
+        MailboxPath otherInboxPath = new 
MailboxPath(MailboxConstants.USER_NAMESPACE, OTHERUSER, INBOX);
 
-        MailboxPath inboxPath = new MailboxPath("#private", "benwa", "INBOX");
         storeMailboxManager.createMailbox(inboxPath, session);
+        storeMailboxManager.createMailbox(otherInboxPath, otherSession);
+
         StoreMessageManager inboxMessageManager = (StoreMessageManager) 
storeMailboxManager.getMailbox(inboxPath, session);
-        MailboxPath myFolderPath = new MailboxPath("#private", "benwa", 
"MyFolder");
+        StoreMessageManager otherInboxMessageManager = (StoreMessageManager) 
storeMailboxManager.getMailbox(otherInboxPath, otherSession);
+
+        MailboxPath myFolderPath = new 
MailboxPath(MailboxConstants.USER_NAMESPACE, USERNAME, "MyFolder");
         storeMailboxManager.createMailbox(myFolderPath, session);
         myFolderMessageManager = (StoreMessageManager) 
storeMailboxManager.getMailbox(myFolderPath, session);
         mailbox = inboxMessageManager.getMailboxEntity();
         mailbox2 = myFolderMessageManager.getMailboxEntity();
+        otherMailbox = otherInboxMessageManager.getMailboxEntity();
 
         m1 = inboxMessageManager.appendMessage(
             ClassLoader.getSystemResourceAsStream("eml/spamMail.eml"),
@@ -181,6 +197,12 @@ public abstract class AbstractMessageSearchIndexTest {
             true,
             new Flags("Hello you"));
 
+        m10 = otherInboxMessageManager.appendMessage(
+            ClassLoader.getSystemResourceAsStream("eml/mail1.eml"),
+            new Date(1391295600000L),
+            otherSession,
+            true,
+            new Flags());
         await();
     }
 
@@ -1052,4 +1074,41 @@ public abstract class AbstractMessageSearchIndexTest {
         assertThat(actual).containsOnly(m1.getMessageId(), m2.getMessageId(), 
m3.getMessageId(), m4.getMessageId(), m5.getMessageId(),
             m6.getMessageId(), m7.getMessageId(), m8.getMessageId(), 
m9.getMessageId(), mOther.getMessageId(), mailWithAttachment.getMessageId(), 
mailWithInlinedAttachment.getMessageId());
     }
+
+    @Test
+    public void 
searchInMultiMailboxShouldReturnMessagesBelongingToUserSession() throws 
Exception {
+        SearchQuery query = new SearchQuery();
+        query.andCriteria(SearchQuery.all());
+
+        MultimailboxesSearchQuery multiMailboxesQuery = 
MultimailboxesSearchQuery.from(query).build();
+
+        assertThat(messageSearchIndex.search(otherSession, 
multiMailboxesQuery, LIMIT))
+            .hasSize(1)
+            .containsOnly(m10.getMessageId());
+    }
+
+    @Test
+    public void 
searchInMultiMailboxShouldNotReturnMessagesBelongingToAnotherUserSession() 
throws Exception {
+        SearchQuery query = new SearchQuery();
+        query.andCriteria(SearchQuery.all());
+
+        MultimailboxesSearchQuery multiMailboxesQuery = 
MultimailboxesSearchQuery.from(query).build();
+
+        assertThat(messageSearchIndex.search(session, multiMailboxesQuery, 
LIMIT))
+            .doesNotContain(m10.getMessageId());
+    }
+
+    @Test
+    public void searchShouldFilterMailboxBelongingToMailboxSession() throws 
Exception {
+        SearchQuery searchQuery = new SearchQuery();
+
+        assertThat(messageSearchIndex.search(otherSession, otherMailbox, 
searchQuery)).containsOnly(m10.getUid());
+    }
+
+    @Test
+    public void 
searchShouldReturnEmptyWhenMailboxBelongingToAnotherMailboxSession() throws 
Exception {
+        SearchQuery searchQuery = new SearchQuery();
+
+        assertThat(messageSearchIndex.search(otherSession, mailbox, 
searchQuery)).isEmpty();
+    }
 }


---------------------------------------------------------------------
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