security: change DLS behavior to OR queries together

This commit changes the behavior of combining multiple document level security queries
from an AND operation to an OR operation.

Additionally, the behavior is also changed when evaluating the combination of roles that
have document level security and roles that do not have document level security. Previously
when the permissions for these roles were combined, the queries from the roles with document
level security were still being applied, even though the user had access to all the documents.
This change now grants the user access to all documents in this scenario and the same applies
for field level security.

Closes elastic/elasticsearch#1074

Original commit: elastic/x-pack-elasticsearch@291107ec27
This commit is contained in:
jaymode 2016-02-29 08:58:02 -05:00
parent 0be2b6cbbc
commit de72f4aeee
6 changed files with 759 additions and 67 deletions

View File

@ -94,8 +94,9 @@ public class IndicesAccessControl {
// this code is a bit of a pita, but right now we can't just initialize an empty set,
// because an empty Set means no permissions on fields and
// <code>null</code> means no field level security
// Also, if one grants no access to fields and the other grants all access, merging should result in all access...
Set<String> fields = null;
if (this.fields != null || other.getFields() != null) {
if (this.fields != null && other.getFields() != null) {
fields = new HashSet<>();
if (this.fields != null) {
fields.addAll(this.fields);
@ -106,7 +107,7 @@ public class IndicesAccessControl {
fields = unmodifiableSet(fields);
}
Set<BytesReference> queries = null;
if (this.queries != null || other.getQueries() != null) {
if (this.queries != null && other.getQueries() != null) {
queries = new HashSet<>();
if (this.queries != null) {
queries.addAll(this.queries);

View File

@ -12,6 +12,7 @@ import org.apache.lucene.search.BulkScorer;
import org.apache.lucene.search.CollectionTerminatedException;
import org.apache.lucene.search.Collector;
import org.apache.lucene.search.ConjunctionDISI;
import org.apache.lucene.search.ConstantScoreQuery;
import org.apache.lucene.search.DocIdSetIterator;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.LeafCollector;
@ -52,7 +53,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.Set;
import static org.apache.lucene.search.BooleanClause.Occur.FILTER;
import static org.apache.lucene.search.BooleanClause.Occur.SHOULD;
/**
* An {@link IndexSearcherWrapper} implementation that is used for field and document level security.
@ -116,13 +117,15 @@ public class ShieldIndexSearcherWrapper extends IndexSearcherWrapper {
}
if (permissions.getQueries() != null) {
BooleanQuery.Builder roleQuery = new BooleanQuery.Builder();
BooleanQuery.Builder filter = new BooleanQuery.Builder();
for (BytesReference bytesReference : permissions.getQueries()) {
QueryShardContext queryShardContext = copyQueryShardContext(this.queryShardContext);
ParsedQuery parsedQuery = queryShardContext.parse(bytesReference);
roleQuery.add(parsedQuery.query(), FILTER);
filter.add(parsedQuery.query(), SHOULD);
}
reader = DocumentSubsetReader.wrap(reader, bitsetFilterCache, roleQuery.build());
// at least one of the queries should match
filter.setMinimumNumberShouldMatch(1);
reader = DocumentSubsetReader.wrap(reader, bitsetFilterCache, new ConstantScoreQuery(filter.build()));
}
if (permissions.getFields() != null) {

View File

@ -35,15 +35,16 @@ public class DocumentAndFieldLevelSecurityTests extends ShieldIntegTestCase {
return super.configUsers() +
"user1:" + USERS_PASSWD_HASHED + "\n" +
"user2:" + USERS_PASSWD_HASHED + "\n" +
"user3:" + USERS_PASSWD_HASHED + "\n" ;
"user3:" + USERS_PASSWD_HASHED + "\n" +
"user4:" + USERS_PASSWD_HASHED + "\n";
}
@Override
protected String configUsersRoles() {
return super.configUsersRoles() +
"role1:user1\n" +
"role2:user2\n" +
"role3:user3\n";
"role1:user1,user4\n" +
"role2:user2,user4\n" +
"role3:user3,user4\n";
}
@Override
@ -107,6 +108,14 @@ public class DocumentAndFieldLevelSecurityTests extends ShieldIntegTestCase {
assertSearchHits(response, "2");
assertThat(response.getHits().getAt(0).getSource().size(), equalTo(1));
assertThat(response.getHits().getAt(0).getSource().get("field2").toString(), equalTo("value2"));
response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user4", USERS_PASSWD)))
.prepareSearch("test")
.get();
assertHitCount(response, 2);
assertSearchHits(response, "1", "2");
assertThat(response.getHits().getAt(0).getSource().get("field1").toString(), equalTo("value1"));
assertThat(response.getHits().getAt(1).getSource().get("field2").toString(), equalTo("value2"));
}
public void testQueryCache() throws Exception {
@ -149,6 +158,19 @@ public class DocumentAndFieldLevelSecurityTests extends ShieldIntegTestCase {
assertHitCount(response, 1);
assertThat(response.getHits().getAt(0).getId(), equalTo("2"));
assertThat(response.getHits().getAt(0).sourceAsMap().size(), equalTo(0));
// user4 has all roles
response = client().filterWithHeader(
Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user4", USERS_PASSWD)))
.prepareSearch("test")
.get();
assertHitCount(response, 2);
assertThat(response.getHits().getAt(0).getId(), equalTo("1"));
assertThat(response.getHits().getAt(0).sourceAsMap().size(), equalTo(1));
assertThat(response.getHits().getAt(0).sourceAsMap().get("field1"), equalTo("value1"));
assertThat(response.getHits().getAt(1).getId(), equalTo("2"));
assertThat(response.getHits().getAt(1).sourceAsMap().size(), equalTo(1));
assertThat(response.getHits().getAt(1).sourceAsMap().get("field2"), equalTo("value2"));
}
}

View File

@ -16,6 +16,7 @@ import org.elasticsearch.action.termvectors.TermVectorsRequest;
import org.elasticsearch.action.termvectors.TermVectorsResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.indices.IndicesRequestCache;
import org.elasticsearch.rest.RestStatus;
@ -56,15 +57,17 @@ public class DocumentLevelSecurityTests extends ShieldIntegTestCase {
protected String configUsers() {
return super.configUsers() +
"user1:" + USERS_PASSWD_HASHED + "\n" +
"user2:" + USERS_PASSWD_HASHED + "\n" ;
"user2:" + USERS_PASSWD_HASHED + "\n" +
"user3:" + USERS_PASSWD_HASHED + "\n" ;
}
@Override
protected String configUsersRoles() {
return super.configUsersRoles() +
"role1:user1\n" +
"role2:user2\n";
"role1:user1,user3\n" +
"role2:user2,user3\n";
}
@Override
protected String configRoles() {
return super.configRoles() +
@ -94,7 +97,7 @@ public class DocumentLevelSecurityTests extends ShieldIntegTestCase {
public void testSimpleQuery() throws Exception {
assertAcked(client().admin().indices().prepareCreate("test")
.addMapping("type1", "field1", "type=string", "field2", "type=string")
.addMapping("type1", "field1", "type=string", "field2", "type=string", "field3", "type=string")
);
client().prepareIndex("test", "type1", "1").setSource("field1", "value1")
.setRefresh(true)
@ -102,6 +105,9 @@ public class DocumentLevelSecurityTests extends ShieldIntegTestCase {
client().prepareIndex("test", "type1", "2").setSource("field2", "value2")
.setRefresh(true)
.get();
client().prepareIndex("test", "type1", "3").setSource("field3", "value3")
.setRefresh(true)
.get();
SearchResponse response = client()
.filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)))
@ -110,24 +116,36 @@ public class DocumentLevelSecurityTests extends ShieldIntegTestCase {
.get();
assertHitCount(response, 1);
assertSearchHits(response, "1");
response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD)))
.prepareSearch("test")
.setQuery(randomBoolean() ? QueryBuilders.termQuery("field2", "value2") : QueryBuilders.matchAllQuery())
.get();
assertHitCount(response, 1);
assertSearchHits(response, "2");
QueryBuilder combined = QueryBuilders.boolQuery()
.should(QueryBuilders.termQuery("field2", "value2"))
.should(QueryBuilders.termQuery("field1", "value1"))
.minimumNumberShouldMatch(1);
response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user3", USERS_PASSWD)))
.prepareSearch("test")
.setQuery(randomBoolean() ? combined : QueryBuilders.matchAllQuery())
.get();
assertHitCount(response, 2);
assertSearchHits(response, "1", "2");
}
public void testGetApi() throws Exception {
assertAcked(client().admin().indices().prepareCreate("test")
.addMapping("type1", "field1", "type=string", "field2", "type=string")
.addMapping("type1", "field1", "type=string", "field2", "type=string", "field3", "type=string")
);
client().prepareIndex("test", "type1", "1").setSource("field1", "value1")
.get();
client().prepareIndex("test", "type1", "2").setSource("field2", "value2")
.get();
client().prepareIndex("test", "type1", "1").setSource("field1", "value1").get();
client().prepareIndex("test", "type1", "2").setSource("field2", "value2").get();
client().prepareIndex("test", "type1", "3").setSource("field3", "value3").get();
// test documents users can see
Boolean realtime = randomFrom(true, false, null);
GetResponse response = client()
.filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)))
@ -137,6 +155,7 @@ public class DocumentLevelSecurityTests extends ShieldIntegTestCase {
.get();
assertThat(response.isExists(), is(true));
assertThat(response.getId(), equalTo("1"));
response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD)))
.prepareGet("test", "type1", "2")
.setRealtime(realtime)
@ -145,6 +164,23 @@ public class DocumentLevelSecurityTests extends ShieldIntegTestCase {
assertThat(response.isExists(), is(true));
assertThat(response.getId(), equalTo("2"));
response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user3", USERS_PASSWD)))
.prepareGet("test", "type1", "1")
.setRealtime(realtime)
.setRefresh(true)
.get();
assertThat(response.isExists(), is(true));
assertThat(response.getId(), equalTo("1"));
response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user3", USERS_PASSWD)))
.prepareGet("test", "type1", "2")
.setRealtime(realtime)
.setRefresh(true)
.get();
assertThat(response.isExists(), is(true));
assertThat(response.getId(), equalTo("2"));
// test documents user cannot see
response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD)))
.prepareGet("test", "type1", "1")
.setRealtime(realtime)
@ -157,17 +193,22 @@ public class DocumentLevelSecurityTests extends ShieldIntegTestCase {
.setRefresh(true)
.get();
assertThat(response.isExists(), is(false));
response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user3", USERS_PASSWD)))
.prepareGet("test", "type1", "3")
.setRealtime(realtime)
.setRefresh(true)
.get();
assertThat(response.isExists(), is(false));
}
public void testMGetApi() throws Exception {
assertAcked(client().admin().indices().prepareCreate("test")
.addMapping("type1", "field1", "type=string", "field2", "type=string")
.addMapping("type1", "field1", "type=string", "field2", "type=string", "field3", "type=string")
);
client().prepareIndex("test", "type1", "1").setSource("field1", "value1")
.get();
client().prepareIndex("test", "type1", "2").setSource("field2", "value2")
.get();
client().prepareIndex("test", "type1", "1").setSource("field1", "value1").get();
client().prepareIndex("test", "type1", "2").setSource("field2", "value2").get();
client().prepareIndex("test", "type1", "3").setSource("field3", "value3").get();
Boolean realtime = randomFrom(true, false, null);
MultiGetResponse response = client()
@ -191,6 +232,20 @@ public class DocumentLevelSecurityTests extends ShieldIntegTestCase {
assertThat(response.getResponses()[0].getResponse().isExists(), is(true));
assertThat(response.getResponses()[0].getResponse().getId(), equalTo("2"));
response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user3", USERS_PASSWD)))
.prepareMultiGet()
.add("test", "type1", "1")
.add("test", "type1", "2")
.setRealtime(realtime)
.setRefresh(true)
.get();
assertThat(response.getResponses()[0].isFailed(), is(false));
assertThat(response.getResponses()[0].getResponse().isExists(), is(true));
assertThat(response.getResponses()[0].getResponse().getId(), equalTo("1"));
assertThat(response.getResponses()[1].isFailed(), is(false));
assertThat(response.getResponses()[1].getResponse().isExists(), is(true));
assertThat(response.getResponses()[1].getResponse().getId(), equalTo("2"));
response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD)))
.prepareMultiGet()
.add("test", "type1", "1")
@ -208,12 +263,22 @@ public class DocumentLevelSecurityTests extends ShieldIntegTestCase {
.get();
assertThat(response.getResponses()[0].isFailed(), is(false));
assertThat(response.getResponses()[0].getResponse().isExists(), is(false));
response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user3", USERS_PASSWD)))
.prepareMultiGet()
.add("test", "type1", "3")
.setRealtime(realtime)
.setRefresh(true)
.get();
assertThat(response.getResponses()[0].isFailed(), is(false));
assertThat(response.getResponses()[0].getResponse().isExists(), is(false));
}
public void testTVApi() throws Exception {
assertAcked(client().admin().indices().prepareCreate("test")
.addMapping("type1", "field1", "type=string,term_vector=with_positions_offsets_payloads",
"field2", "type=string,term_vector=with_positions_offsets_payloads")
"field2", "type=string,term_vector=with_positions_offsets_payloads",
"field3", "type=string,term_vector=with_positions_offsets_payloads")
);
client().prepareIndex("test", "type1", "1").setSource("field1", "value1")
.setRefresh(true)
@ -221,6 +286,9 @@ public class DocumentLevelSecurityTests extends ShieldIntegTestCase {
client().prepareIndex("test", "type1", "2").setSource("field2", "value2")
.setRefresh(true)
.get();
client().prepareIndex("test", "type1", "3").setSource("field3", "value3")
.setRefresh(true)
.get();
Boolean realtime = randomFrom(true, false, null);
TermVectorsResponse response = client()
@ -238,6 +306,20 @@ public class DocumentLevelSecurityTests extends ShieldIntegTestCase {
assertThat(response.isExists(), is(true));
assertThat(response.getId(), is("2"));
response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user3", USERS_PASSWD)))
.prepareTermVectors("test", "type1", "1")
.setRealtime(realtime)
.get();
assertThat(response.isExists(), is(true));
assertThat(response.getId(), is("1"));
response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user3", USERS_PASSWD)))
.prepareTermVectors("test", "type1", "2")
.setRealtime(realtime)
.get();
assertThat(response.isExists(), is(true));
assertThat(response.getId(), is("2"));
response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD)))
.prepareTermVectors("test", "type1", "1")
.setRealtime(realtime)
@ -249,12 +331,19 @@ public class DocumentLevelSecurityTests extends ShieldIntegTestCase {
.setRealtime(realtime)
.get();
assertThat(response.isExists(), is(false));
response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user3", USERS_PASSWD)))
.prepareTermVectors("test", "type1", "3")
.setRealtime(realtime)
.get();
assertThat(response.isExists(), is(false));
}
public void testMTVApi() throws Exception {
assertAcked(client().admin().indices().prepareCreate("test")
.addMapping("type1", "field1", "type=string,term_vector=with_positions_offsets_payloads",
"field2", "type=string,term_vector=with_positions_offsets_payloads")
"field2", "type=string,term_vector=with_positions_offsets_payloads",
"field3", "type=string,term_vector=with_positions_offsets_payloads")
);
client().prepareIndex("test", "type1", "1").setSource("field1", "value1")
.setRefresh(true)
@ -262,6 +351,9 @@ public class DocumentLevelSecurityTests extends ShieldIntegTestCase {
client().prepareIndex("test", "type1", "2").setSource("field2", "value2")
.setRefresh(true)
.get();
client().prepareIndex("test", "type1", "3").setSource("field3", "value3")
.setRefresh(true)
.get();
Boolean realtime = randomFrom(true, false, null);
MultiTermVectorsResponse response = client()
@ -281,6 +373,17 @@ public class DocumentLevelSecurityTests extends ShieldIntegTestCase {
assertThat(response.getResponses()[0].getResponse().isExists(), is(true));
assertThat(response.getResponses()[0].getResponse().getId(), is("2"));
response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user3", USERS_PASSWD)))
.prepareMultiTermVectors()
.add(new TermVectorsRequest("test", "type1", "1").realtime(realtime))
.add(new TermVectorsRequest("test", "type1", "2").realtime(realtime))
.get();
assertThat(response.getResponses().length, equalTo(2));
assertThat(response.getResponses()[0].getResponse().isExists(), is(true));
assertThat(response.getResponses()[0].getResponse().getId(), is("1"));
assertThat(response.getResponses()[1].getResponse().isExists(), is(true));
assertThat(response.getResponses()[1].getResponse().getId(), is("2"));
response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD)))
.prepareMultiTermVectors()
.add(new TermVectorsRequest("test", "type1", "1").realtime(realtime))
@ -294,11 +397,18 @@ public class DocumentLevelSecurityTests extends ShieldIntegTestCase {
.get();
assertThat(response.getResponses().length, equalTo(1));
assertThat(response.getResponses()[0].getResponse().isExists(), is(false));
response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user3", USERS_PASSWD)))
.prepareMultiTermVectors()
.add(new TermVectorsRequest("test", "type1", "3").realtime(realtime))
.get();
assertThat(response.getResponses().length, equalTo(1));
assertThat(response.getResponses()[0].getResponse().isExists(), is(false));
}
public void testGlobalAggregation() throws Exception {
assertAcked(client().admin().indices().prepareCreate("test")
.addMapping("type1", "field1", "type=string", "field2", "type=string")
.addMapping("type1", "field1", "type=string", "field2", "type=string", "field3", "type=string")
);
client().prepareIndex("test", "type1", "1").setSource("field1", "value1")
.setRefresh(true)
@ -306,15 +416,18 @@ public class DocumentLevelSecurityTests extends ShieldIntegTestCase {
client().prepareIndex("test", "type1", "2").setSource("field2", "value2")
.setRefresh(true)
.get();
client().prepareIndex("test", "type1", "3").setSource("field3", "value3")
.setRefresh(true)
.get();
SearchResponse response = client().prepareSearch("test")
.addAggregation(AggregationBuilders.global("global").subAggregation(AggregationBuilders.terms("field2").field("field2")))
.get();
assertHitCount(response, 2);
assertSearchHits(response, "1", "2");
assertHitCount(response, 3);
assertSearchHits(response, "1", "2", "3");
Global globalAgg = response.getAggregations().get("global");
assertThat(globalAgg.getDocCount(), equalTo(2L));
assertThat(globalAgg.getDocCount(), equalTo(3L));
Terms termsAgg = globalAgg.getAggregations().get("field2");
assertThat(termsAgg.getBuckets().get(0).getKeyAsString(), equalTo("value2"));
assertThat(termsAgg.getBuckets().get(0).getDocCount(), equalTo(1L));
@ -330,6 +443,30 @@ public class DocumentLevelSecurityTests extends ShieldIntegTestCase {
assertThat(globalAgg.getDocCount(), equalTo(1L));
termsAgg = globalAgg.getAggregations().get("field2");
assertThat(termsAgg.getBuckets().size(), equalTo(0));
response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD)))
.prepareSearch("test")
.addAggregation(AggregationBuilders.global("global").subAggregation(AggregationBuilders.terms("field2").field("field2")))
.get();
assertHitCount(response, 1);
assertSearchHits(response, "2");
globalAgg = response.getAggregations().get("global");
assertThat(globalAgg.getDocCount(), equalTo(1L));
termsAgg = globalAgg.getAggregations().get("field2");
assertThat(termsAgg.getBuckets().size(), equalTo(1));
response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user3", USERS_PASSWD)))
.prepareSearch("test")
.addAggregation(AggregationBuilders.global("global").subAggregation(AggregationBuilders.terms("field2").field("field2")))
.get();
assertHitCount(response, 2);
assertSearchHits(response, "1", "2");
globalAgg = response.getAggregations().get("global");
assertThat(globalAgg.getDocCount(), equalTo(2L));
termsAgg = globalAgg.getAggregations().get("field2");
assertThat(termsAgg.getBuckets().size(), equalTo(1));
}
public void testChildrenAggregation() throws Exception {
@ -372,34 +509,49 @@ public class DocumentLevelSecurityTests extends ShieldIntegTestCase {
assertThat(children.getDocCount(), equalTo(0L));
termsAgg = children.getAggregations().get("field3");
assertThat(termsAgg.getBuckets().size(), equalTo(0));
response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user3", USERS_PASSWD)))
.prepareSearch("test")
.setTypes("type1")
.addAggregation(AggregationBuilders.children("children", "type2")
.subAggregation(AggregationBuilders.terms("field3").field("field3")))
.get();
assertHitCount(response, 1);
assertSearchHits(response, "1");
children = response.getAggregations().get("children");
assertThat(children.getDocCount(), equalTo(0L));
termsAgg = children.getAggregations().get("field3");
assertThat(termsAgg.getBuckets().size(), equalTo(0));
}
public void testParentChild() {
assertAcked(prepareCreate("test")
.addMapping("parent")
.addMapping("child", "_parent", "type=parent", "field1", "type=string", "field2", "type=string"));
.addMapping("child", "_parent", "type=parent", "field1", "type=string", "field2", "type=string", "field3", "type=string"));
ensureGreen();
// index simple data
client().prepareIndex("test", "parent", "p1").setSource("field1", "value1").get();
client().prepareIndex("test", "child", "c1").setSource("field2", "value2").setParent("p1").get();
client().prepareIndex("test", "child", "c2").setSource("field2", "value2").setParent("p1").get();
client().prepareIndex("test", "child", "c3").setSource("field3", "value3").setParent("p1").get();
refresh();
SearchResponse searchResponse = client().prepareSearch("test")
.setQuery(hasChildQuery("child", matchAllQuery()))
.get();
assertHitCount(searchResponse, 1L);
assertThat(searchResponse.getHits().totalHits(), equalTo(1L));
assertThat(searchResponse.getHits().getAt(0).id(), equalTo("p1"));
searchResponse = client().prepareSearch("test")
.setQuery(hasParentQuery("parent", matchAllQuery()))
.addSort("_id", SortOrder.ASC)
.get();
assertHitCount(searchResponse, 2L);
assertHitCount(searchResponse, 3L);
assertThat(searchResponse.getHits().getAt(0).id(), equalTo("c1"));
assertThat(searchResponse.getHits().getAt(1).id(), equalTo("c2"));
assertThat(searchResponse.getHits().getAt(2).id(), equalTo("c3"));
// Both user1 and user2 can't see field1 and field2, no parent/child query should yield results:
searchResponse = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)))
@ -425,11 +577,27 @@ public class DocumentLevelSecurityTests extends ShieldIntegTestCase {
.setQuery(hasParentQuery("parent", matchAllQuery()))
.get();
assertHitCount(searchResponse, 0L);
// user 3 can see them but not c3
searchResponse = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user3", USERS_PASSWD)))
.prepareSearch("test")
.setQuery(hasChildQuery("child", matchAllQuery()))
.get();
assertHitCount(searchResponse, 1L);
assertThat(searchResponse.getHits().getAt(0).id(), equalTo("p1"));
searchResponse = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user3", USERS_PASSWD)))
.prepareSearch("test")
.setQuery(hasParentQuery("parent", matchAllQuery()))
.get();
assertHitCount(searchResponse, 2L);
assertThat(searchResponse.getHits().getAt(0).id(), equalTo("c1"));
assertThat(searchResponse.getHits().getAt(1).id(), equalTo("c2"));
}
public void testPercolateApi() {
assertAcked(client().admin().indices().prepareCreate("test")
.addMapping(".percolator", "field1", "type=string", "field2", "type=string")
.addMapping(".percolator", "field1", "type=string", "field2", "type=string", "field3", "type=string")
);
client().prepareIndex("test", ".percolator", "1")
.setSource("{\"query\" : { \"match_all\" : {} }, \"field1\" : \"value1\"}")
@ -446,6 +614,23 @@ public class DocumentLevelSecurityTests extends ShieldIntegTestCase {
assertThat(response.getCount(), equalTo(1L));
assertThat(response.getMatches()[0].getId().string(), equalTo("1"));
response = client()
.filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD)))
.preparePercolate()
.setDocumentType("type")
.setPercolateDoc(new PercolateSourceBuilder.DocBuilder().setDoc("{}"))
.get();
assertThat(response.getCount(), equalTo(0L));
response = client()
.filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user3", USERS_PASSWD)))
.preparePercolate()
.setDocumentType("type")
.setPercolateDoc(new PercolateSourceBuilder.DocBuilder().setDoc("{}"))
.get();
assertThat(response.getCount(), equalTo(1L));
assertThat(response.getMatches()[0].getId().string(), equalTo("1"));
// Percolator with a query on a document that the current user can see. Percolator will have one query to evaluate, so there is a
// match:
response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)))
@ -467,6 +652,15 @@ public class DocumentLevelSecurityTests extends ShieldIntegTestCase {
.get();
assertThat(response.getCount(), equalTo(0L));
response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user3", USERS_PASSWD)))
.preparePercolate()
.setDocumentType("type")
.setPercolateQuery(termQuery("field1", "value1"))
.setPercolateDoc(new PercolateSourceBuilder.DocBuilder().setDoc("{}"))
.get();
assertThat(response.getCount(), equalTo(1L));
assertThat(response.getMatches()[0].getId().string(), equalTo("1"));
assertAcked(client().admin().indices().prepareClose("test"));
assertAcked(client().admin().indices().prepareOpen("test"));
ensureGreen("test");
@ -484,12 +678,14 @@ public class DocumentLevelSecurityTests extends ShieldIntegTestCase {
public void testRequestCache() throws Exception {
assertAcked(client().admin().indices().prepareCreate("test")
.setSettings(Settings.builder().put(IndicesRequestCache.INDEX_CACHE_REQUEST_ENABLED_SETTING.getKey(), true))
.addMapping("type1", "field1", "type=string", "field2", "type=string")
.addMapping("type1", "field1", "type=string", "field2", "type=string", "field3", "type=string")
);
client().prepareIndex("test", "type1", "1").setSource("field1", "value1")
.get();
client().prepareIndex("test", "type1", "2").setSource("field2", "value2")
.get();
client().prepareIndex("test", "type1", "3").setSource("field3", "value3")
.get();
refresh();
int max = scaledRandomIntBetween(4, 32);
@ -512,6 +708,14 @@ public class DocumentLevelSecurityTests extends ShieldIntegTestCase {
.get();
assertNoFailures(response);
assertHitCount(response, 0);
response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user3", USERS_PASSWD)))
.prepareSearch("test")
.setSize(0)
.setQuery(termQuery("field1", "value1"))
.setRequestCache(requestCache)
.get();
assertNoFailures(response);
assertHitCount(response, 1);
}
}

View File

@ -45,7 +45,7 @@ import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.nullValue;
// The random usage of meta fields such as _timestamp add noice to the test, so disable random index templates:
// The random usage of meta fields such as _timestamp add noise to the test, so disable random index templates:
@ESIntegTestCase.ClusterScope(randomDynamicTemplates = false)
public class FieldLevelSecurityTests extends ShieldIntegTestCase {
@ -60,18 +60,20 @@ public class FieldLevelSecurityTests extends ShieldIntegTestCase {
"user3:" + USERS_PASSWD_HASHED + "\n" +
"user4:" + USERS_PASSWD_HASHED + "\n" +
"user5:" + USERS_PASSWD_HASHED + "\n" +
"user6:" + USERS_PASSWD_HASHED + "\n";
"user6:" + USERS_PASSWD_HASHED + "\n" +
"user7:" + USERS_PASSWD_HASHED + "\n" +
"user8:" + USERS_PASSWD_HASHED + "\n";
}
@Override
protected String configUsersRoles() {
return super.configUsersRoles() +
"role1:user1\n" +
"role2:user2\n" +
"role3:user3\n" +
"role4:user4\n" +
"role5:user5\n" +
"role5:user6\n";
"role1:user1,user7,user8\n" +
"role2:user2,user7,user8\n" +
"role3:user3,user7\n" +
"role4:user4,user7\n" +
"role5:user5,user7\n" +
"role6:user6\n";
}
@Override
protected String configRoles() {
@ -109,6 +111,7 @@ public class FieldLevelSecurityTests extends ShieldIntegTestCase {
"role6:\n" +
" cluster: all\n" +
" indices:\n" +
" '*':\n" +
" privileges: ALL\n" +
" fields: 'field*'\n";
}
@ -123,9 +126,9 @@ public class FieldLevelSecurityTests extends ShieldIntegTestCase {
public void testQuery() throws Exception {
assertAcked(client().admin().indices().prepareCreate("test")
.addMapping("type1", "field1", "type=string", "field2", "type=string")
.addMapping("type1", "field1", "type=string", "field2", "type=string", "field3", "type=string")
);
client().prepareIndex("test", "type1", "1").setSource("field1", "value1", "field2", "value2")
client().prepareIndex("test", "type1", "1").setSource("field1", "value1", "field2", "value2", "field3", "value3")
.setRefresh(true)
.get();
@ -160,6 +163,18 @@ public class FieldLevelSecurityTests extends ShieldIntegTestCase {
.setQuery(matchQuery("field1", "value1"))
.get();
assertHitCount(response, 1);
// user7 has roles with field level security configured and without field level security
response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user7", USERS_PASSWD)))
.prepareSearch("test")
.setQuery(matchQuery("field1", "value1"))
.get();
assertHitCount(response, 1);
// user8 has roles with field level security configured for field1 and field2
response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user8", USERS_PASSWD)))
.prepareSearch("test")
.setQuery(matchQuery("field1", "value1"))
.get();
assertHitCount(response, 1);
// user1 has no access to field1, so the query should not match with the document:
response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)))
@ -191,14 +206,70 @@ public class FieldLevelSecurityTests extends ShieldIntegTestCase {
.setQuery(matchQuery("field2", "value2"))
.get();
assertHitCount(response, 1);
// user7 has role with field level security and without field level security
response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user5", USERS_PASSWD)))
.prepareSearch("test")
.setQuery(matchQuery("field2", "value2"))
.get();
assertHitCount(response, 1);
// user8 has roles with field level security configured for field1 and field2
response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user8", USERS_PASSWD)))
.prepareSearch("test")
.setQuery(matchQuery("field2", "value2"))
.get();
assertHitCount(response, 1);
// user1 has access to field3, so the query should not match with the document:
response = client()
.filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)))
.prepareSearch("test")
.setQuery(matchQuery("field3", "value3"))
.get();
assertHitCount(response, 0);
// user2 has no access to field3, so the query should not match with the document:
response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD)))
.prepareSearch("test")
.setQuery(matchQuery("field3", "value3"))
.get();
assertHitCount(response, 0);
// user3 has access to field1 and field2 but not field3, so the query should not match with the document:
response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user3", USERS_PASSWD)))
.prepareSearch("test")
.setQuery(matchQuery("field3", "value3"))
.get();
assertHitCount(response, 0);
// user4 has access to no fields, so the query should not match with the document:
response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user4", USERS_PASSWD)))
.prepareSearch("test")
.setQuery(matchQuery("field3", "value3"))
.get();
assertHitCount(response, 0);
// user5 has no field level security configured, so the query should match with the document:
response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user5", USERS_PASSWD)))
.prepareSearch("test")
.setQuery(matchQuery("field3", "value3"))
.get();
assertHitCount(response, 1);
// user7 has roles with field level security and without field level security
response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user5", USERS_PASSWD)))
.prepareSearch("test")
.setQuery(matchQuery("field3", "value3"))
.get();
assertHitCount(response, 1);
// user8 has roles with field level security configured for field1 and field2
response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user8", USERS_PASSWD)))
.prepareSearch("test")
.setQuery(matchQuery("field3", "value3"))
.get();
assertHitCount(response, 0);
}
public void testGetApi() throws Exception {
assertAcked(client().admin().indices().prepareCreate("test")
.addMapping("type1", "field1", "type=string", "field2", "type=string")
.addMapping("type1", "field1", "type=string", "field2", "type=string", "field3", "type=string")
);
client().prepareIndex("test", "type1", "1").setSource("field1", "value1", "field2", "value2")
client().prepareIndex("test", "type1", "1").setSource("field1", "value1", "field2", "value2", "field3", "value3")
.get();
Boolean realtime = randomFrom(true, false, null);
@ -250,6 +321,42 @@ public class FieldLevelSecurityTests extends ShieldIntegTestCase {
.setRefresh(true)
.get();
assertThat(response.isExists(), is(true));
assertThat(response.getSource().size(), equalTo(3));
assertThat(response.getSource().get("field1").toString(), equalTo("value1"));
assertThat(response.getSource().get("field2").toString(), equalTo("value2"));
assertThat(response.getSource().get("field3").toString(), equalTo("value3"));
// user6 has access to field*
response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user6", USERS_PASSWD)))
.prepareGet("test", "type1", "1")
.setRealtime(realtime)
.setRefresh(true)
.get();
assertThat(response.isExists(), is(true));
assertThat(response.getSource().size(), equalTo(3));
assertThat(response.getSource().get("field1").toString(), equalTo("value1"));
assertThat(response.getSource().get("field2").toString(), equalTo("value2"));
assertThat(response.getSource().get("field3").toString(), equalTo("value3"));
// user7 has roles with field level security and without field level security
response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user7", USERS_PASSWD)))
.prepareGet("test", "type1", "1")
.setRealtime(realtime)
.setRefresh(true)
.get();
assertThat(response.isExists(), is(true));
assertThat(response.getSource().size(), equalTo(3));
assertThat(response.getSource().get("field1").toString(), equalTo("value1"));
assertThat(response.getSource().get("field2").toString(), equalTo("value2"));
assertThat(response.getSource().get("field3").toString(), equalTo("value3"));
// user8 has roles with field level security with access to field1 and field2
response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user8", USERS_PASSWD)))
.prepareGet("test", "type1", "1")
.setRealtime(realtime)
.setRefresh(true)
.get();
assertThat(response.isExists(), is(true));
assertThat(response.getSource().size(), equalTo(2));
assertThat(response.getSource().get("field1").toString(), equalTo("value1"));
assertThat(response.getSource().get("field2").toString(), equalTo("value2"));
@ -257,10 +364,9 @@ public class FieldLevelSecurityTests extends ShieldIntegTestCase {
public void testMGetApi() throws Exception {
assertAcked(client().admin().indices().prepareCreate("test")
.addMapping("type1", "field1", "type=string", "field2", "type=string")
.addMapping("type1", "field1", "type=string", "field2", "type=string", "field3", "type=string")
);
client().prepareIndex("test", "type1", "1").setSource("field1", "value1", "field2", "value2")
.get();
client().prepareIndex("test", "type1", "1").setSource("field1", "value1", "field2", "value2", "field3", "value3").get();
Boolean realtime = randomFrom(true, false, null);
// user1 is granted access to field1 only:
@ -321,6 +427,48 @@ public class FieldLevelSecurityTests extends ShieldIntegTestCase {
.get();
assertThat(response.getResponses()[0].isFailed(), is(false));
assertThat(response.getResponses()[0].getResponse().isExists(), is(true));
assertThat(response.getResponses()[0].getResponse().getSource().size(), equalTo(3));
assertThat(response.getResponses()[0].getResponse().getSource().get("field1").toString(), equalTo("value1"));
assertThat(response.getResponses()[0].getResponse().getSource().get("field2").toString(), equalTo("value2"));
assertThat(response.getResponses()[0].getResponse().getSource().get("field3").toString(), equalTo("value3"));
// user6 has access to field*
response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user6", USERS_PASSWD)))
.prepareMultiGet()
.add("test", "type1", "1")
.setRealtime(realtime)
.setRefresh(true)
.get();
assertThat(response.getResponses()[0].isFailed(), is(false));
assertThat(response.getResponses()[0].getResponse().isExists(), is(true));
assertThat(response.getResponses()[0].getResponse().getSource().size(), equalTo(3));
assertThat(response.getResponses()[0].getResponse().getSource().get("field1").toString(), equalTo("value1"));
assertThat(response.getResponses()[0].getResponse().getSource().get("field2").toString(), equalTo("value2"));
assertThat(response.getResponses()[0].getResponse().getSource().get("field3").toString(), equalTo("value3"));
// user7 has roles with field level security and without field level security
response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user7", USERS_PASSWD)))
.prepareMultiGet()
.add("test", "type1", "1")
.setRealtime(realtime)
.setRefresh(true)
.get();
assertThat(response.getResponses()[0].isFailed(), is(false));
assertThat(response.getResponses()[0].getResponse().isExists(), is(true));
assertThat(response.getResponses()[0].getResponse().getSource().size(), equalTo(3));
assertThat(response.getResponses()[0].getResponse().getSource().get("field1").toString(), equalTo("value1"));
assertThat(response.getResponses()[0].getResponse().getSource().get("field2").toString(), equalTo("value2"));
assertThat(response.getResponses()[0].getResponse().getSource().get("field3").toString(), equalTo("value3"));
// user8 has roles with field level security with access to field1 and field2
response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user8", USERS_PASSWD)))
.prepareMultiGet()
.add("test", "type1", "1")
.setRealtime(realtime)
.setRefresh(true)
.get();
assertThat(response.getResponses()[0].isFailed(), is(false));
assertThat(response.getResponses()[0].getResponse().isExists(), is(true));
assertThat(response.getResponses()[0].getResponse().getSource().size(), equalTo(2));
assertThat(response.getResponses()[0].getResponse().getSource().get("field1").toString(), equalTo("value1"));
assertThat(response.getResponses()[0].getResponse().getSource().get("field2").toString(), equalTo("value2"));
@ -328,9 +476,9 @@ public class FieldLevelSecurityTests extends ShieldIntegTestCase {
public void testFieldStatsApi() throws Exception {
assertAcked(client().admin().indices().prepareCreate("test")
.addMapping("type1", "field1", "type=string", "field2", "type=string")
.addMapping("type1", "field1", "type=string", "field2", "type=string", "field3", "type=string")
);
client().prepareIndex("test", "type1", "1").setSource("field1", "value1", "field2", "value2")
client().prepareIndex("test", "type1", "1").setSource("field1", "value1", "field2", "value2", "field3", "value3")
.setRefresh(true)
.get();
@ -338,7 +486,7 @@ public class FieldLevelSecurityTests extends ShieldIntegTestCase {
FieldStatsResponse response = client()
.filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)))
.prepareFieldStats()
.setFields("field1", "field2")
.setFields("field1", "field2", "field3")
.get();
assertThat(response.getAllFieldStats().size(), equalTo(1));
assertThat(response.getAllFieldStats().get("field1").getDocCount(), equalTo(1L));
@ -346,7 +494,7 @@ public class FieldLevelSecurityTests extends ShieldIntegTestCase {
// user2 is granted access to field2 only:
response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD)))
.prepareFieldStats()
.setFields("field1", "field2")
.setFields("field1", "field2", "field3")
.get();
assertThat(response.getAllFieldStats().size(), equalTo(1));
assertThat(response.getAllFieldStats().get("field2").getDocCount(), equalTo(1L));
@ -354,7 +502,7 @@ public class FieldLevelSecurityTests extends ShieldIntegTestCase {
// user3 is granted access to field1 and field2:
response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user3", USERS_PASSWD)))
.prepareFieldStats()
.setFields("field1", "field2")
.setFields("field1", "field2", "field3")
.get();
assertThat(response.getAllFieldStats().size(), equalTo(2));
assertThat(response.getAllFieldStats().get("field1").getDocCount(), equalTo(1L));
@ -370,7 +518,37 @@ public class FieldLevelSecurityTests extends ShieldIntegTestCase {
// user5 has no field level security configured:
response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user5", USERS_PASSWD)))
.prepareFieldStats()
.setFields("field1", "field2")
.setFields("field1", "field2", "field3")
.get();
assertThat(response.getAllFieldStats().size(), equalTo(3));
assertThat(response.getAllFieldStats().get("field1").getDocCount(), equalTo(1L));
assertThat(response.getAllFieldStats().get("field2").getDocCount(), equalTo(1L));
assertThat(response.getAllFieldStats().get("field3").getDocCount(), equalTo(1L));
// user6 has field level security configured for field*:
response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user6", USERS_PASSWD)))
.prepareFieldStats()
.setFields("field1", "field2", "field3")
.get();
assertThat(response.getAllFieldStats().size(), equalTo(3));
assertThat(response.getAllFieldStats().get("field1").getDocCount(), equalTo(1L));
assertThat(response.getAllFieldStats().get("field2").getDocCount(), equalTo(1L));
assertThat(response.getAllFieldStats().get("field3").getDocCount(), equalTo(1L));
// user7 has no field level security configured (roles with and without field level security):
response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user7", USERS_PASSWD)))
.prepareFieldStats()
.setFields("field1", "field2", "field3")
.get();
assertThat(response.getAllFieldStats().size(), equalTo(3));
assertThat(response.getAllFieldStats().get("field1").getDocCount(), equalTo(1L));
assertThat(response.getAllFieldStats().get("field2").getDocCount(), equalTo(1L));
assertThat(response.getAllFieldStats().get("field3").getDocCount(), equalTo(1L));
// user8 has field level security configured for field1 and field2 (multiple roles):
response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user8", USERS_PASSWD)))
.prepareFieldStats()
.setFields("field1", "field2", "field3")
.get();
assertThat(response.getAllFieldStats().size(), equalTo(2));
assertThat(response.getAllFieldStats().get("field1").getDocCount(), equalTo(1L));
@ -380,9 +558,9 @@ public class FieldLevelSecurityTests extends ShieldIntegTestCase {
public void testQueryCache() throws Exception {
assertAcked(client().admin().indices().prepareCreate("test")
.setSettings(Settings.builder().put(IndexModule.INDEX_QUERY_CACHE_EVERYTHING_SETTING.getKey(), true))
.addMapping("type1", "field1", "type=string", "field2", "type=string")
.addMapping("type1", "field1", "type=string", "field2", "type=string", "field3", "type=string")
);
client().prepareIndex("test", "type1", "1").setSource("field1", "value1", "field2", "value2")
client().prepareIndex("test", "type1", "1").setSource("field1", "value1", "field2", "value2", "field3", "value3")
.setRefresh(true)
.get();
@ -394,18 +572,31 @@ public class FieldLevelSecurityTests extends ShieldIntegTestCase {
.setQuery(constantScoreQuery(termQuery("field1", "value1")))
.get();
assertHitCount(response, 1);
assertThat(response.getHits().getAt(0).getSource().size(), is(1));
assertThat(response.getHits().getAt(0).getSource().get("field1"), is("value1"));
response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD)))
.prepareSearch("test")
.setQuery(constantScoreQuery(termQuery("field1", "value1")))
.get();
assertHitCount(response, 0);
String multipleFieldsUser = randomFrom("user5", "user6", "user7");
response = client()
.filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue(multipleFieldsUser, USERS_PASSWD)))
.prepareSearch("test")
.setQuery(constantScoreQuery(termQuery("field1", "value1")))
.get();
assertHitCount(response, 1);
assertThat(response.getHits().getAt(0).getSource().size(), is(3));
assertThat(response.getHits().getAt(0).getSource().get("field1"), is("value1"));
assertThat(response.getHits().getAt(0).getSource().get("field2"), is("value2"));
assertThat(response.getHits().getAt(0).getSource().get("field3"), is("value3"));
}
}
public void testRequestCache() throws Exception {
assertAcked(client().admin().indices().prepareCreate("test")
.setSettings(Settings.builder().put(IndicesRequestCache.INDEX_CACHE_REQUEST_ENABLED_SETTING.getKey(), true))
.addMapping("type1", "field1", "type=string", "field2", "type=string")
.addMapping("type1", "field1", "type=string", "field2", "type=string", "field3", "type=string")
);
client().prepareIndex("test", "type1", "1").setSource("field1", "value1", "field2", "value2")
.setRefresh(true)
@ -431,14 +622,25 @@ public class FieldLevelSecurityTests extends ShieldIntegTestCase {
.get();
assertNoFailures(response);
assertHitCount(response, 0);
String multipleFieldsUser = randomFrom("user5", "user6", "user7");
response = client()
.filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue(multipleFieldsUser, USERS_PASSWD)))
.prepareSearch("test")
.setSize(0)
.setQuery(termQuery("field1", "value1"))
.setRequestCache(requestCache)
.get();
assertNoFailures(response);
assertHitCount(response, 1);
}
}
public void testFields() throws Exception {
assertAcked(client().admin().indices().prepareCreate("test")
.addMapping("type1", "field1", "type=string,store=true", "field2", "type=string,store=true")
.addMapping("type1", "field1", "type=string,store=true", "field2", "type=string,store=true",
"field3", "type=string,store=true")
);
client().prepareIndex("test", "type1", "1").setSource("field1", "value1", "field2", "value2")
client().prepareIndex("test", "type1", "1").setSource("field1", "value1", "field2", "value2", "field3", "value3")
.setRefresh(true)
.get();
@ -448,6 +650,7 @@ public class FieldLevelSecurityTests extends ShieldIntegTestCase {
.prepareSearch("test")
.addField("field1")
.addField("field2")
.addField("field3")
.get();
assertThat(response.getHits().getAt(0).fields().size(), equalTo(1));
assertThat(response.getHits().getAt(0).fields().get("field1").<String>getValue(), equalTo("value1"));
@ -457,6 +660,7 @@ public class FieldLevelSecurityTests extends ShieldIntegTestCase {
.prepareSearch("test")
.addField("field1")
.addField("field2")
.addField("field3")
.get();
assertThat(response.getHits().getAt(0).fields().size(), equalTo(1));
assertThat(response.getHits().getAt(0).fields().get("field2").<String>getValue(), equalTo("value2"));
@ -466,6 +670,7 @@ public class FieldLevelSecurityTests extends ShieldIntegTestCase {
.prepareSearch("test")
.addField("field1")
.addField("field2")
.addField("field3")
.get();
assertThat(response.getHits().getAt(0).fields().size(), equalTo(2));
assertThat(response.getHits().getAt(0).fields().get("field1").<String>getValue(), equalTo("value1"));
@ -476,6 +681,7 @@ public class FieldLevelSecurityTests extends ShieldIntegTestCase {
.prepareSearch("test")
.addField("field1")
.addField("field2")
.addField("field3")
.get();
assertThat(response.getHits().getAt(0).fields().size(), equalTo(0));
@ -484,6 +690,43 @@ public class FieldLevelSecurityTests extends ShieldIntegTestCase {
.prepareSearch("test")
.addField("field1")
.addField("field2")
.addField("field3")
.get();
assertThat(response.getHits().getAt(0).fields().size(), equalTo(3));
assertThat(response.getHits().getAt(0).fields().get("field1").<String>getValue(), equalTo("value1"));
assertThat(response.getHits().getAt(0).fields().get("field2").<String>getValue(), equalTo("value2"));
assertThat(response.getHits().getAt(0).fields().get("field3").<String>getValue(), equalTo("value3"));
// user6 has field level security configured with access to field*:
response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user6", USERS_PASSWD)))
.prepareSearch("test")
.addField("field1")
.addField("field2")
.addField("field3")
.get();
assertThat(response.getHits().getAt(0).fields().size(), equalTo(3));
assertThat(response.getHits().getAt(0).fields().get("field1").<String>getValue(), equalTo("value1"));
assertThat(response.getHits().getAt(0).fields().get("field2").<String>getValue(), equalTo("value2"));
assertThat(response.getHits().getAt(0).fields().get("field3").<String>getValue(), equalTo("value3"));
// user7 has access to all fields due to a mix of roles without field level security and with:
response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user7", USERS_PASSWD)))
.prepareSearch("test")
.addField("field1")
.addField("field2")
.addField("field3")
.get();
assertThat(response.getHits().getAt(0).fields().size(), equalTo(3));
assertThat(response.getHits().getAt(0).fields().get("field1").<String>getValue(), equalTo("value1"));
assertThat(response.getHits().getAt(0).fields().get("field2").<String>getValue(), equalTo("value2"));
assertThat(response.getHits().getAt(0).fields().get("field3").<String>getValue(), equalTo("value3"));
// user8 has field level security configured with access to field1 and field2:
response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user8", USERS_PASSWD)))
.prepareSearch("test")
.addField("field1")
.addField("field2")
.addField("field3")
.get();
assertThat(response.getHits().getAt(0).fields().size(), equalTo(2));
assertThat(response.getHits().getAt(0).fields().get("field1").<String>getValue(), equalTo("value1"));
@ -492,9 +735,9 @@ public class FieldLevelSecurityTests extends ShieldIntegTestCase {
public void testSource() throws Exception {
assertAcked(client().admin().indices().prepareCreate("test")
.addMapping("type1", "field1", "type=string", "field2", "type=string")
.addMapping("type1", "field1", "type=string", "field2", "type=string", "field3", "type=string")
);
client().prepareIndex("test", "type1", "1").setSource("field1", "value1", "field2", "value2")
client().prepareIndex("test", "type1", "1").setSource("field1", "value1", "field2", "value2", "field3", "value3")
.setRefresh(true)
.get();
@ -531,6 +774,33 @@ public class FieldLevelSecurityTests extends ShieldIntegTestCase {
response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user5", USERS_PASSWD)))
.prepareSearch("test")
.get();
assertThat(response.getHits().getAt(0).sourceAsMap().size(), equalTo(3));
assertThat(response.getHits().getAt(0).sourceAsMap().get("field1").toString(), equalTo("value1"));
assertThat(response.getHits().getAt(0).sourceAsMap().get("field2").toString(), equalTo("value2"));
assertThat(response.getHits().getAt(0).sourceAsMap().get("field3").toString(), equalTo("value3"));
// user6 has field level security configured with access to field*:
response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user6", USERS_PASSWD)))
.prepareSearch("test")
.get();
assertThat(response.getHits().getAt(0).sourceAsMap().size(), equalTo(3));
assertThat(response.getHits().getAt(0).sourceAsMap().get("field1").toString(), equalTo("value1"));
assertThat(response.getHits().getAt(0).sourceAsMap().get("field2").toString(), equalTo("value2"));
assertThat(response.getHits().getAt(0).sourceAsMap().get("field3").toString(), equalTo("value3"));
// user7 has access to all fields
response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user7", USERS_PASSWD)))
.prepareSearch("test")
.get();
assertThat(response.getHits().getAt(0).sourceAsMap().size(), equalTo(3));
assertThat(response.getHits().getAt(0).sourceAsMap().get("field1").toString(), equalTo("value1"));
assertThat(response.getHits().getAt(0).sourceAsMap().get("field2").toString(), equalTo("value2"));
assertThat(response.getHits().getAt(0).sourceAsMap().get("field3").toString(), equalTo("value3"));
// user8 has field level security configured with access to field1 and field2:
response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user8", USERS_PASSWD)))
.prepareSearch("test")
.get();
assertThat(response.getHits().getAt(0).sourceAsMap().size(), equalTo(2));
assertThat(response.getHits().getAt(0).sourceAsMap().get("field1").toString(), equalTo("value1"));
assertThat(response.getHits().getAt(0).sourceAsMap().get("field2").toString(), equalTo("value2"));
@ -616,9 +886,10 @@ public class FieldLevelSecurityTests extends ShieldIntegTestCase {
public void testTVApi() throws Exception {
assertAcked(client().admin().indices().prepareCreate("test")
.addMapping("type1", "field1", "type=string,term_vector=with_positions_offsets_payloads",
"field2", "type=string,term_vector=with_positions_offsets_payloads")
"field2", "type=string,term_vector=with_positions_offsets_payloads",
"field3", "type=string,term_vector=with_positions_offsets_payloads")
);
client().prepareIndex("test", "type1", "1").setSource("field1", "value1", "field2", "value2")
client().prepareIndex("test", "type1", "1").setSource("field1", "value1", "field2", "value2", "field3", "value3")
.setRefresh(true)
.get();
@ -655,14 +926,54 @@ public class FieldLevelSecurityTests extends ShieldIntegTestCase {
.get();
assertThat(response.isExists(), is(true));
assertThat(response.getFields().size(), equalTo(0));
response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user5", USERS_PASSWD)))
.prepareTermVectors("test", "type1", "1")
.setRealtime(realtime)
.get();
assertThat(response.isExists(), is(true));
assertThat(response.getFields().size(), equalTo(3));
assertThat(response.getFields().terms("field1").size(), equalTo(1L));
assertThat(response.getFields().terms("field2").size(), equalTo(1L));
assertThat(response.getFields().terms("field3").size(), equalTo(1L));
response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user6", USERS_PASSWD)))
.prepareTermVectors("test", "type1", "1")
.setRealtime(realtime)
.get();
assertThat(response.isExists(), is(true));
assertThat(response.getFields().size(), equalTo(3));
assertThat(response.getFields().terms("field1").size(), equalTo(1L));
assertThat(response.getFields().terms("field2").size(), equalTo(1L));
assertThat(response.getFields().terms("field3").size(), equalTo(1L));
response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user7", USERS_PASSWD)))
.prepareTermVectors("test", "type1", "1")
.setRealtime(realtime)
.get();
assertThat(response.isExists(), is(true));
assertThat(response.getFields().size(), equalTo(3));
assertThat(response.getFields().terms("field1").size(), equalTo(1L));
assertThat(response.getFields().terms("field2").size(), equalTo(1L));
assertThat(response.getFields().terms("field3").size(), equalTo(1L));
response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user8", USERS_PASSWD)))
.prepareTermVectors("test", "type1", "1")
.setRealtime(realtime)
.get();
assertThat(response.isExists(), is(true));
assertThat(response.getFields().size(), equalTo(2));
assertThat(response.getFields().terms("field1").size(), equalTo(1L));
assertThat(response.getFields().terms("field2").size(), equalTo(1L));
}
public void testMTVApi() throws Exception {
assertAcked(client().admin().indices().prepareCreate("test")
.addMapping("type1", "field1", "type=string,term_vector=with_positions_offsets_payloads",
"field2", "type=string,term_vector=with_positions_offsets_payloads")
"field2", "type=string,term_vector=with_positions_offsets_payloads",
"field3", "type=string,term_vector=with_positions_offsets_payloads")
);
client().prepareIndex("test", "type1", "1").setSource("field1", "value1", "field2", "value2")
client().prepareIndex("test", "type1", "1").setSource("field1", "value1", "field2", "value2", "field3", "value3")
.setRefresh(true)
.get();
@ -703,6 +1014,49 @@ public class FieldLevelSecurityTests extends ShieldIntegTestCase {
assertThat(response.getResponses().length, equalTo(1));
assertThat(response.getResponses()[0].getResponse().isExists(), is(true));
assertThat(response.getResponses()[0].getResponse().getFields().size(), equalTo(0));
response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user5", USERS_PASSWD)))
.prepareMultiTermVectors()
.add(new TermVectorsRequest("test", "type1", "1").realtime(realtime))
.get();
assertThat(response.getResponses().length, equalTo(1));
assertThat(response.getResponses()[0].getResponse().isExists(), is(true));
assertThat(response.getResponses()[0].getResponse().getFields().size(), equalTo(3));
assertThat(response.getResponses()[0].getResponse().getFields().terms("field1").size(), equalTo(1L));
assertThat(response.getResponses()[0].getResponse().getFields().terms("field2").size(), equalTo(1L));
assertThat(response.getResponses()[0].getResponse().getFields().terms("field3").size(), equalTo(1L));
response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user6", USERS_PASSWD)))
.prepareMultiTermVectors()
.add(new TermVectorsRequest("test", "type1", "1").realtime(realtime))
.get();
assertThat(response.getResponses().length, equalTo(1));
assertThat(response.getResponses()[0].getResponse().isExists(), is(true));
assertThat(response.getResponses()[0].getResponse().getFields().size(), equalTo(3));
assertThat(response.getResponses()[0].getResponse().getFields().terms("field1").size(), equalTo(1L));
assertThat(response.getResponses()[0].getResponse().getFields().terms("field2").size(), equalTo(1L));
assertThat(response.getResponses()[0].getResponse().getFields().terms("field3").size(), equalTo(1L));
response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user7", USERS_PASSWD)))
.prepareMultiTermVectors()
.add(new TermVectorsRequest("test", "type1", "1").realtime(realtime))
.get();
assertThat(response.getResponses().length, equalTo(1));
assertThat(response.getResponses()[0].getResponse().isExists(), is(true));
assertThat(response.getResponses()[0].getResponse().getFields().size(), equalTo(3));
assertThat(response.getResponses()[0].getResponse().getFields().terms("field1").size(), equalTo(1L));
assertThat(response.getResponses()[0].getResponse().getFields().terms("field2").size(), equalTo(1L));
assertThat(response.getResponses()[0].getResponse().getFields().terms("field3").size(), equalTo(1L));
response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user8", USERS_PASSWD)))
.prepareMultiTermVectors()
.add(new TermVectorsRequest("test", "type1", "1").realtime(realtime))
.get();
assertThat(response.getResponses().length, equalTo(1));
assertThat(response.getResponses()[0].getResponse().isExists(), is(true));
assertThat(response.getResponses()[0].getResponse().getFields().size(), equalTo(2));
assertThat(response.getResponses()[0].getResponse().getFields().terms("field1").size(), equalTo(1L));
assertThat(response.getResponses()[0].getResponse().getFields().terms("field2").size(), equalTo(1L));
}
public void testPercolateApi() {

View File

@ -0,0 +1,108 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.shield.authz.accesscontrol;
import org.elasticsearch.common.bytes.BytesArray;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.util.set.Sets;
import org.elasticsearch.test.ESTestCase;
import java.util.Collections;
import org.elasticsearch.shield.authz.accesscontrol.IndicesAccessControl.IndexAccessControl;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.nullValue;
/**
* Unit tests for {@link IndicesAccessControl}
*/
public class IndicesAccessControlTests extends ESTestCase {
public void testEmptyIndicesAccessControl() {
IndicesAccessControl indicesAccessControl = new IndicesAccessControl(true, Collections.emptyMap());
assertThat(indicesAccessControl.isGranted(), is(true));
assertThat(indicesAccessControl.getIndexPermissions(randomAsciiOfLengthBetween(3,20)), nullValue());
}
public void testMergeFields() {
IndexAccessControl indexAccessControl = new IndexAccessControl(true, Sets.newHashSet("a", "c"), null);
IndexAccessControl other = new IndexAccessControl(true, Sets.newHashSet("b"), null);
IndexAccessControl merge1 = indexAccessControl.merge(other);
assertThat(merge1.getFields(), containsInAnyOrder("a", "b", "c"));
assertThat(merge1.isGranted(), is(true));
assertThat(merge1.getQueries(), nullValue());
IndexAccessControl merge2 = other.merge(indexAccessControl);
assertThat(merge2.getFields(), containsInAnyOrder("a", "b", "c"));
assertThat(merge2.isGranted(), is(true));
assertThat(merge2.getQueries(), nullValue());
}
public void testMergeEmptyAndNullFields() {
IndexAccessControl indexAccessControl = new IndexAccessControl(true, Collections.emptySet(), null);
IndexAccessControl other = new IndexAccessControl(true, null, null);
IndexAccessControl merge1 = indexAccessControl.merge(other);
assertThat(merge1.getFields(), nullValue());
assertThat(merge1.isGranted(), is(true));
assertThat(merge1.getQueries(), nullValue());
IndexAccessControl merge2 = other.merge(indexAccessControl);
assertThat(merge2.getFields(), nullValue());
assertThat(merge2.isGranted(), is(true));
assertThat(merge2.getQueries(), nullValue());
}
public void testMergeNullFields() {
IndexAccessControl indexAccessControl = new IndexAccessControl(true, Sets.newHashSet("a", "b"), null);
IndexAccessControl other = new IndexAccessControl(true, null, null);
IndexAccessControl merge1 = indexAccessControl.merge(other);
assertThat(merge1.getFields(), nullValue());
assertThat(merge1.isGranted(), is(true));
assertThat(merge1.getQueries(), nullValue());
IndexAccessControl merge2 = other.merge(indexAccessControl);
assertThat(merge2.getFields(), nullValue());
assertThat(merge2.isGranted(), is(true));
assertThat(merge2.getQueries(), nullValue());
}
public void testMergeQueries() {
BytesReference query1 = new BytesArray(new byte[] { 0x1 });
BytesReference query2 = new BytesArray(new byte[] { 0x2 });
IndexAccessControl indexAccessControl = new IndexAccessControl(true, null, Collections.singleton(query1));
IndexAccessControl other = new IndexAccessControl(true, null, Collections.singleton(query2));
IndexAccessControl merge1 = indexAccessControl.merge(other);
assertThat(merge1.getFields(), nullValue());
assertThat(merge1.isGranted(), is(true));
assertThat(merge1.getQueries(), containsInAnyOrder(query1, query2));
IndexAccessControl merge2 = other.merge(indexAccessControl);
assertThat(merge2.getFields(), nullValue());
assertThat(merge2.isGranted(), is(true));
assertThat(merge1.getQueries(), containsInAnyOrder(query1, query2));
}
public void testMergeNullQuery() {
BytesReference query1 = new BytesArray(new byte[] { 0x1 });
IndexAccessControl indexAccessControl = new IndexAccessControl(true, null, Collections.singleton(query1));
IndexAccessControl other = new IndexAccessControl(true, null, null);
IndexAccessControl merge1 = indexAccessControl.merge(other);
assertThat(merge1.getFields(), nullValue());
assertThat(merge1.isGranted(), is(true));
assertThat(merge1.getQueries(), nullValue());
IndexAccessControl merge2 = other.merge(indexAccessControl);
assertThat(merge2.getFields(), nullValue());
assertThat(merge2.isGranted(), is(true));
assertThat(merge1.getQueries(), nullValue());
}
}