mirror of
https://github.com/honeymoose/OpenSearch.git
synced 2025-02-17 18:35:25 +00:00
security: Add _field_names
field to the list of meta fields that are always allowed visible
The logic that filters `_field_names` field's terms is encapsulated in `FieldSubsetReader.java`, but that doesn't kick in if `_field_names` is an allowed field. Closes elastic/elasticsearch#2504 Original commit: elastic/x-pack-elasticsearch@d81ec9477a
This commit is contained in:
parent
eb5248d127
commit
1ecebab0aa
@ -35,6 +35,7 @@ import org.elasticsearch.index.cache.bitset.BitsetFilterCache;
|
||||
import org.elasticsearch.index.engine.EngineException;
|
||||
import org.elasticsearch.index.mapper.DocumentMapper;
|
||||
import org.elasticsearch.index.mapper.MapperService;
|
||||
import org.elasticsearch.index.mapper.internal.FieldNamesFieldMapper;
|
||||
import org.elasticsearch.index.mapper.internal.ParentFieldMapper;
|
||||
import org.elasticsearch.index.query.ParsedQuery;
|
||||
import org.elasticsearch.index.query.QueryBuilder;
|
||||
@ -90,6 +91,7 @@ public class ShieldIndexSearcherWrapper extends IndexSearcherWrapper {
|
||||
|
||||
Set<String> allowedMetaFields = new HashSet<>();
|
||||
allowedMetaFields.addAll(Arrays.asList(MapperService.getAllMetaFields()));
|
||||
allowedMetaFields.add(FieldNamesFieldMapper.NAME); // TODO: add _field_names to MapperService#META_FIELDS?
|
||||
allowedMetaFields.add("_source"); // TODO: add _source to MapperService#META_FIELDS?
|
||||
allowedMetaFields.add("_version"); // TODO: add _version to MapperService#META_FIELDS?
|
||||
allowedMetaFields.remove("_all"); // The _all field contains actual data and we can't include that by default.
|
||||
|
@ -34,6 +34,7 @@ import java.util.Collections;
|
||||
|
||||
import static org.elasticsearch.action.support.WriteRequest.RefreshPolicy.IMMEDIATE;
|
||||
import static org.elasticsearch.index.query.QueryBuilders.constantScoreQuery;
|
||||
import static org.elasticsearch.index.query.QueryBuilders.existsQuery;
|
||||
import static org.elasticsearch.index.query.QueryBuilders.hasChildQuery;
|
||||
import static org.elasticsearch.index.query.QueryBuilders.matchQuery;
|
||||
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
|
||||
@ -881,28 +882,28 @@ public class FieldLevelSecurityTests extends ShieldIntegTestCase {
|
||||
.prepareSearch("test")
|
||||
.addSort("field1", SortOrder.ASC)
|
||||
.get();
|
||||
assertThat((Long) response.getHits().getAt(0).sortValues()[0], equalTo(1L));
|
||||
assertThat(response.getHits().getAt(0).sortValues()[0], equalTo(1L));
|
||||
|
||||
// user2 is not granted to use field1, so the default missing sort value is included
|
||||
response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD)))
|
||||
.prepareSearch("test")
|
||||
.addSort("field1", SortOrder.ASC)
|
||||
.get();
|
||||
assertThat((Long) response.getHits().getAt(0).sortValues()[0], equalTo(Long.MAX_VALUE));
|
||||
assertThat(response.getHits().getAt(0).sortValues()[0], equalTo(Long.MAX_VALUE));
|
||||
|
||||
// user1 is not granted to use field2, so the default missing sort value is included
|
||||
response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)))
|
||||
.prepareSearch("test")
|
||||
.addSort("field2", SortOrder.ASC)
|
||||
.get();
|
||||
assertThat((Long) response.getHits().getAt(0).sortValues()[0], equalTo(Long.MAX_VALUE));
|
||||
assertThat(response.getHits().getAt(0).sortValues()[0], equalTo(Long.MAX_VALUE));
|
||||
|
||||
// user2 is granted to use field2, so it is included in the sort_values
|
||||
response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD)))
|
||||
.prepareSearch("test")
|
||||
.addSort("field2", SortOrder.ASC)
|
||||
.get();
|
||||
assertThat((Long) response.getHits().getAt(0).sortValues()[0], equalTo(2L));
|
||||
assertThat(response.getHits().getAt(0).sortValues()[0], equalTo(2L));
|
||||
}
|
||||
|
||||
public void testAggs() throws Exception {
|
||||
@ -1223,4 +1224,64 @@ public class FieldLevelSecurityTests extends ShieldIntegTestCase {
|
||||
assertThat(response.getHits().getAt(0).sourceAsMap().get("field2").toString(), equalTo("value2"));
|
||||
}
|
||||
|
||||
public void testExistQuery() {
|
||||
assertAcked(client().admin().indices().prepareCreate("test")
|
||||
.addMapping("type1", "field1", "type=text", "field2", "type=text", "field3", "type=text")
|
||||
);
|
||||
client().prepareIndex("test", "type1", "1").setSource("field1", "value1", "field2", "value2", "field3", "value3")
|
||||
.setRefreshPolicy(IMMEDIATE)
|
||||
.get();
|
||||
|
||||
// user1 has access to field1, so the query should match with the document:
|
||||
SearchResponse response = client()
|
||||
.filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)))
|
||||
.prepareSearch("test")
|
||||
.setQuery(existsQuery("field1"))
|
||||
.get();
|
||||
assertHitCount(response, 1);
|
||||
// user1 has no access to field2, so the query should not match with the document:
|
||||
response = client()
|
||||
.filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user1", USERS_PASSWD)))
|
||||
.prepareSearch("test")
|
||||
.setQuery(existsQuery("field2"))
|
||||
.get();
|
||||
assertHitCount(response, 0);
|
||||
// user2 has no access to field1, so the query should not match with the document:
|
||||
response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD)))
|
||||
.prepareSearch("test")
|
||||
.setQuery(existsQuery("field1"))
|
||||
.get();
|
||||
assertHitCount(response, 0);
|
||||
// user2 has access to field2, so the query should match with the document:
|
||||
response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user2", USERS_PASSWD)))
|
||||
.prepareSearch("test")
|
||||
.setQuery(existsQuery("field2"))
|
||||
.get();
|
||||
assertHitCount(response, 1);
|
||||
// user3 has access to field1 and field2, so the query should match with the document:
|
||||
response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user3", USERS_PASSWD)))
|
||||
.prepareSearch("test")
|
||||
.setQuery(existsQuery("field1"))
|
||||
.get();
|
||||
assertHitCount(response, 1);
|
||||
// user3 has access to field1 and field2, so the query should match with the document:
|
||||
response = client().filterWithHeader(Collections.singletonMap(BASIC_AUTH_HEADER, basicAuthHeaderValue("user3", USERS_PASSWD)))
|
||||
.prepareSearch("test")
|
||||
.setQuery(existsQuery("field2"))
|
||||
.get();
|
||||
assertHitCount(response, 1);
|
||||
// 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(existsQuery("field1"))
|
||||
.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(existsQuery("field2"))
|
||||
.get();
|
||||
assertHitCount(response, 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -133,7 +133,7 @@ public class ShieldIndexSearcherWrapperUnitTests extends ESTestCase {
|
||||
|
||||
FieldSubsetReader.FieldSubsetDirectoryReader result =
|
||||
(FieldSubsetReader.FieldSubsetDirectoryReader) shieldIndexSearcherWrapper.wrap(esIn);
|
||||
assertThat(result.getFieldNames().size(), equalTo(11));
|
||||
assertThat(result.getFieldNames().size(), equalTo(12));
|
||||
assertThat(result.getFieldNames().contains("_uid"), is(true));
|
||||
assertThat(result.getFieldNames().contains("_id"), is(true));
|
||||
assertThat(result.getFieldNames().contains("_version"), is(true));
|
||||
@ -145,6 +145,7 @@ public class ShieldIndexSearcherWrapperUnitTests extends ESTestCase {
|
||||
assertThat(result.getFieldNames().contains("_ttl"), is(true));
|
||||
assertThat(result.getFieldNames().contains("_size"), is(true));
|
||||
assertThat(result.getFieldNames().contains("_index"), is(true));
|
||||
assertThat(result.getFieldNames().contains("_field_names"), is(true));
|
||||
// _all contains actual user data and therefor can't be included by default
|
||||
assertThat(result.getFieldNames().contains("_all"), is(false));
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user