Fixing issue with security wrapping superqueries incorrectly and possibly leaving out valid results.
Project: http://git-wip-us.apache.org/repos/asf/incubator-blur/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-blur/commit/45c9d4cd Tree: http://git-wip-us.apache.org/repos/asf/incubator-blur/tree/45c9d4cd Diff: http://git-wip-us.apache.org/repos/asf/incubator-blur/diff/45c9d4cd Branch: refs/heads/master Commit: 45c9d4cdb985e9f50dd5f9294bd275d8ee7323ed Parents: c0e54e9 Author: Aaron McCurry <[email protected]> Authored: Wed Feb 11 09:18:47 2015 -0500 Committer: Aaron McCurry <[email protected]> Committed: Wed Feb 11 09:18:47 2015 -0500 ---------------------------------------------------------------------- .../blur/server/BlurSecureIndexSearcher.java | 73 ++++++++++ .../IndexSearcherCloseableSecureBase.java | 4 +- .../server/BlurSecureIndexSearcherTest.java | 145 +++++++++++++++++++ 3 files changed, 220 insertions(+), 2 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/45c9d4cd/blur-core/src/main/java/org/apache/blur/server/BlurSecureIndexSearcher.java ---------------------------------------------------------------------- diff --git a/blur-core/src/main/java/org/apache/blur/server/BlurSecureIndexSearcher.java b/blur-core/src/main/java/org/apache/blur/server/BlurSecureIndexSearcher.java new file mode 100644 index 0000000..222577f --- /dev/null +++ b/blur-core/src/main/java/org/apache/blur/server/BlurSecureIndexSearcher.java @@ -0,0 +1,73 @@ +/** + * 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.blur.server; + +import java.io.IOException; +import java.util.Collection; +import java.util.List; +import java.util.Set; +import java.util.concurrent.ExecutorService; + +import lucene.security.index.AccessControlFactory; +import lucene.security.search.SecureIndexSearcher; + +import org.apache.blur.lucene.search.SuperQuery; +import org.apache.blur.thrift.generated.ScoreType; +import org.apache.lucene.index.IndexReader; +import org.apache.lucene.index.Term; +import org.apache.lucene.search.BooleanClause; +import org.apache.lucene.search.BooleanQuery; +import org.apache.lucene.search.Filter; +import org.apache.lucene.search.FilteredQuery; +import org.apache.lucene.search.Query; + +public class BlurSecureIndexSearcher extends SecureIndexSearcher { + + public BlurSecureIndexSearcher(IndexReader r, ExecutorService executor, AccessControlFactory accessControlFactory, + Collection<String> readAuthorizations, Collection<String> discoverAuthorizations, Set<String> discoverableFields) + throws IOException { + super(r, executor, accessControlFactory, readAuthorizations, discoverAuthorizations, discoverableFields); + } + + /** + * This method is very important!!! It handles rewriting the real query (which + * can be a {@link SuperQuery} to have document (record) level filtering or + * access control. + */ + @Override + protected Query wrapFilter(Query query, Filter filter) { + if (filter == null) { + return query; + } else if (query instanceof SuperQuery) { + SuperQuery superQuery = (SuperQuery) query; + Query innerQuery = superQuery.getQuery(); + Term primeDocTerm = superQuery.getPrimeDocTerm(); + ScoreType scoreType = superQuery.getScoreType(); + return new SuperQuery(wrapFilter(innerQuery, filter), scoreType, primeDocTerm); + } else if (query instanceof BooleanQuery) { + BooleanQuery booleanQuery = (BooleanQuery) query; + List<BooleanClause> clauses = booleanQuery.clauses(); + for (BooleanClause booleanClause : clauses) { + booleanClause.setQuery(wrapFilter(booleanClause.getQuery(), filter)); + } + return booleanQuery; + } else { + return new FilteredQuery(query, filter); + } + } + +} http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/45c9d4cd/blur-core/src/main/java/org/apache/blur/server/IndexSearcherCloseableSecureBase.java ---------------------------------------------------------------------- diff --git a/blur-core/src/main/java/org/apache/blur/server/IndexSearcherCloseableSecureBase.java b/blur-core/src/main/java/org/apache/blur/server/IndexSearcherCloseableSecureBase.java index d3bfdda..d6a2625 100644 --- a/blur-core/src/main/java/org/apache/blur/server/IndexSearcherCloseableSecureBase.java +++ b/blur-core/src/main/java/org/apache/blur/server/IndexSearcherCloseableSecureBase.java @@ -24,7 +24,6 @@ import java.util.Set; import java.util.concurrent.ExecutorService; import lucene.security.index.AccessControlFactory; -import lucene.security.search.SecureIndexSearcher; import org.apache.blur.lucene.search.IndexSearcherCloseable; import org.apache.blur.trace.Trace; @@ -35,7 +34,8 @@ import org.apache.lucene.search.Collector; import org.apache.lucene.search.Weight; import org.apache.lucene.store.Directory; -public abstract class IndexSearcherCloseableSecureBase extends SecureIndexSearcher implements IndexSearcherCloseable { +public abstract class IndexSearcherCloseableSecureBase extends BlurSecureIndexSearcher implements + IndexSearcherCloseable { public IndexSearcherCloseableSecureBase(IndexReader r, ExecutorService executor, AccessControlFactory accessControlFactory, Collection<String> readAuthorizations, http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/45c9d4cd/blur-core/src/test/java/org/apache/blur/server/BlurSecureIndexSearcherTest.java ---------------------------------------------------------------------- diff --git a/blur-core/src/test/java/org/apache/blur/server/BlurSecureIndexSearcherTest.java b/blur-core/src/test/java/org/apache/blur/server/BlurSecureIndexSearcherTest.java new file mode 100644 index 0000000..6c015ec --- /dev/null +++ b/blur-core/src/test/java/org/apache/blur/server/BlurSecureIndexSearcherTest.java @@ -0,0 +1,145 @@ +/** + * 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.blur.server; + +import static org.junit.Assert.*; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +import lucene.security.index.AccessControlFactory; +import lucene.security.index.FilterAccessControlFactory; + +import org.apache.blur.lucene.search.SuperQuery; +import org.apache.blur.thrift.generated.ScoreType; +import org.apache.blur.utils.BlurConstants; +import org.apache.lucene.analysis.core.KeywordAnalyzer; +import org.apache.lucene.index.AtomicReaderContext; +import org.apache.lucene.index.DirectoryReader; +import org.apache.lucene.index.IndexReader; +import org.apache.lucene.index.IndexWriter; +import org.apache.lucene.index.IndexWriterConfig; +import org.apache.lucene.index.Term; +import org.apache.lucene.search.BooleanClause; +import org.apache.lucene.search.BooleanQuery; +import org.apache.lucene.search.DocIdSet; +import org.apache.lucene.search.Filter; +import org.apache.lucene.search.FilteredQuery; +import org.apache.lucene.search.Query; +import org.apache.lucene.search.TermQuery; +import org.apache.lucene.search.BooleanClause.Occur; +import org.apache.lucene.store.Directory; +import org.apache.lucene.store.RAMDirectory; +import org.apache.lucene.util.Bits; +import org.apache.lucene.util.Version; +import org.junit.Test; + +public class BlurSecureIndexSearcherTest { + + @Test + public void testQueryFilterWrap1() throws IOException { + IndexReader r = getIndexReader(); + AccessControlFactory accessControlFactory = new FilterAccessControlFactory(); + Collection<String> readAuthorizations = new ArrayList<String>(); + Collection<String> discoverAuthorizations = new ArrayList<String>(); + Set<String> discoverableFields = new HashSet<String>(Arrays.asList("rowid")); + BlurSecureIndexSearcher blurSecureIndexSearcher = new BlurSecureIndexSearcher(r, null, accessControlFactory, + readAuthorizations, discoverAuthorizations, discoverableFields); + Query wrapFilter; + Query query = new TermQuery(new Term("a", "b")); + Filter filter = new Filter() { + @Override + public DocIdSet getDocIdSet(AtomicReaderContext context, Bits acceptDocs) throws IOException { + throw new RuntimeException("Not implemented."); + } + }; + { + Term primeDocTerm = new Term(BlurConstants.PRIME_DOC, BlurConstants.PRIME_DOC_VALUE); + ScoreType scoreType = ScoreType.SUPER; + SuperQuery superQuery = new SuperQuery(query, scoreType, primeDocTerm); + wrapFilter = blurSecureIndexSearcher.wrapFilter(superQuery, filter); + System.out.println(wrapFilter); + } + { + assertTrue(wrapFilter instanceof SuperQuery); + SuperQuery sq = (SuperQuery) wrapFilter; + Query inner = sq.getQuery(); + assertTrue(inner instanceof FilteredQuery); + FilteredQuery filteredQuery = (FilteredQuery) inner; + Query innerFilteredQuery = filteredQuery.getQuery(); + assertEquals(innerFilteredQuery, query); + assertTrue(filteredQuery.getFilter() == filter); + } + } + + @Test + public void testQueryFilterWrap2() throws IOException { + IndexReader r = getIndexReader(); + AccessControlFactory accessControlFactory = new FilterAccessControlFactory(); + Collection<String> readAuthorizations = new ArrayList<String>(); + Collection<String> discoverAuthorizations = new ArrayList<String>(); + Set<String> discoverableFields = new HashSet<String>(Arrays.asList("rowid")); + BlurSecureIndexSearcher blurSecureIndexSearcher = new BlurSecureIndexSearcher(r, null, accessControlFactory, + readAuthorizations, discoverAuthorizations, discoverableFields); + Query wrapFilter; + Query query = new TermQuery(new Term("a", "b")); + Filter filter = new Filter() { + @Override + public DocIdSet getDocIdSet(AtomicReaderContext context, Bits acceptDocs) throws IOException { + throw new RuntimeException("Not implemented."); + } + }; + { + Term primeDocTerm = new Term(BlurConstants.PRIME_DOC, BlurConstants.PRIME_DOC_VALUE); + ScoreType scoreType = ScoreType.SUPER; + SuperQuery superQuery = new SuperQuery(query, scoreType, primeDocTerm); + BooleanQuery booleanQuery = new BooleanQuery(); + booleanQuery.add(superQuery, Occur.MUST); + wrapFilter = blurSecureIndexSearcher.wrapFilter(booleanQuery, filter); + System.out.println(wrapFilter); + } + { + assertTrue(wrapFilter instanceof BooleanQuery); + BooleanQuery booleanQuery = (BooleanQuery) wrapFilter; + assertEquals(1, booleanQuery.clauses().size()); + BooleanClause booleanClause = booleanQuery.clauses().get(0); + Query innerClause = booleanClause.getQuery(); + + assertTrue(innerClause instanceof SuperQuery); + SuperQuery sq = (SuperQuery) innerClause; + Query inner = sq.getQuery(); + assertTrue(inner instanceof FilteredQuery); + FilteredQuery filteredQuery = (FilteredQuery) inner; + Query innerFilteredQuery = filteredQuery.getQuery(); + assertEquals(innerFilteredQuery, query); + assertTrue(filteredQuery.getFilter() == filter); + } + } + + private IndexReader getIndexReader() throws IOException { + IndexWriterConfig conf = new IndexWriterConfig(Version.LUCENE_43, new KeywordAnalyzer()); + Directory dir = new RAMDirectory(); + IndexWriter writer = new IndexWriter(dir, conf); + writer.close(); + return DirectoryReader.open(dir); + } + +}
