Fix query rewriting for document-level security to be stable.

Original commit: elastic/x-pack-elasticsearch@3ad7eb4ded
This commit is contained in:
Adrien Grand 2015-09-03 12:46:20 +02:00
parent f270e585f4
commit b4d5ef5904
1 changed files with 38 additions and 15 deletions

View File

@ -196,12 +196,19 @@ public final class ShieldIndexSearcherWrapper extends AbstractIndexShardComponen
setSimilarity(in.getSimilarity(true)); setSimilarity(in.getSimilarity(true));
setQueryCache(engineConfig.getQueryCache()); setQueryCache(engineConfig.getQueryCache());
setQueryCachingPolicy(engineConfig.getQueryCachingPolicy()); setQueryCachingPolicy(engineConfig.getQueryCachingPolicy());
this.roleQuery = roleQuery; try {
this.roleQuery = super.rewrite(roleQuery);
} catch (IOException e) {
throw new IllegalStateException("Could not rewrite role query", e);
}
} }
@Override @Override
public Query rewrite(Query original) throws IOException { public Query rewrite(Query query) throws IOException {
return super.rewrite(wrap(original)); query = super.rewrite(query);
query = wrap(query);
query = super.rewrite(query);
return query;
} }
@Override @Override
@ -209,21 +216,37 @@ public final class ShieldIndexSearcherWrapper extends AbstractIndexShardComponen
return "ShieldIndexSearcher(" + super.toString() + ")"; return "ShieldIndexSearcher(" + super.toString() + ")";
} }
private Query wrap(Query original) throws IOException { private boolean isFilteredBy(Query query, Query filter) {
// If already wrapped, don't wrap twice: if (query instanceof ConstantScoreQuery) {
if (original instanceof BooleanQuery) { return isFilteredBy(((ConstantScoreQuery) query).getQuery(), filter);
BooleanQuery bq = (BooleanQuery) original; } else if (query instanceof BooleanQuery) {
if (bq.clauses().size() == 2) { BooleanQuery bq = (BooleanQuery) query;
Query rewrittenRoleQuery = rewrite(roleQuery); for (BooleanClause clause : bq) {
if (rewrittenRoleQuery.equals(bq.clauses().get(1).getQuery())) { if (clause.isRequired() && isFilteredBy(clause.getQuery(), filter)) {
return original; return true;
} }
} }
return false;
} else {
Query queryClone = query.clone();
queryClone.setBoost(1);
Query filterClone = filter.clone();
filterClone.setBoost(1f);
return queryClone.equals(filterClone);
} }
BooleanQuery bq = new BooleanQuery(); }
bq.add(original, MUST);
bq.add(roleQuery, FILTER); private Query wrap(Query original) throws IOException {
return bq; if (isFilteredBy(original, roleQuery)) {
// this is necessary in order to make rewrite "stable",
// ie calling it several times on the same query keeps
// on returning the same query instance
return original;
}
return new BooleanQuery.Builder()
.add(original, MUST)
.add(roleQuery, FILTER)
.build();
} }
} }