Load fielddata on behalf of scripts.

If we have to do the one-time loading of fieldata, it requires
more permissions than groovy scripts currently have (zero). This
is because of RamUsageEstimator reflection and so on in PagedBytes.

GroovySecurityTests only test a numeric field, so add a string field
to the test (so pagedbytes fielddata gets created etc).
This commit is contained in:
Robert Muir 2015-05-06 00:16:03 -04:00
parent e4beda94f9
commit 020f7d7195
2 changed files with 17 additions and 3 deletions

View File

@ -19,6 +19,7 @@
package org.elasticsearch.search.lookup; package org.elasticsearch.search.lookup;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import org.elasticsearch.common.Nullable; import org.elasticsearch.common.Nullable;
import org.elasticsearch.index.fielddata.IndexFieldDataService; import org.elasticsearch.index.fielddata.IndexFieldDataService;
import org.elasticsearch.index.fielddata.ScriptDocValues; import org.elasticsearch.index.fielddata.ScriptDocValues;
@ -26,6 +27,8 @@ import org.elasticsearch.index.mapper.FieldMapper;
import org.elasticsearch.index.mapper.MapperService; import org.elasticsearch.index.mapper.MapperService;
import org.apache.lucene.index.LeafReaderContext; import org.apache.lucene.index.LeafReaderContext;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Map; import java.util.Map;
@ -73,11 +76,18 @@ public class LeafDocLookup implements Map {
String fieldName = key.toString(); String fieldName = key.toString();
ScriptDocValues scriptValues = localCacheFieldData.get(fieldName); ScriptDocValues scriptValues = localCacheFieldData.get(fieldName);
if (scriptValues == null) { if (scriptValues == null) {
FieldMapper mapper = mapperService.smartNameFieldMapper(fieldName, types); final FieldMapper mapper = mapperService.smartNameFieldMapper(fieldName, types);
if (mapper == null) { if (mapper == null) {
throw new IllegalArgumentException("No field found for [" + fieldName + "] in mapping with types " + Arrays.toString(types) + ""); throw new IllegalArgumentException("No field found for [" + fieldName + "] in mapping with types " + Arrays.toString(types) + "");
} }
scriptValues = fieldDataService.getForField(mapper).load(reader).getScriptValues(); // load fielddata on behalf of the script: otherwise it would need additional permissions
// to deal with pagedbytes/ramusagestimator/etc
scriptValues = AccessController.doPrivileged(new PrivilegedAction<ScriptDocValues>() {
@Override
public ScriptDocValues run() {
return fieldDataService.getForField(mapper).load(reader).getScriptValues();
}
});
localCacheFieldData.put(fieldName, scriptValues); localCacheFieldData.put(fieldName, scriptValues);
} }
scriptValues.setNextDocId(docId); scriptValues.setNextDocId(docId);

View File

@ -54,10 +54,14 @@ public class GroovySecurityTests extends ElasticsearchIntegrationTest {
internalCluster().startNodesAsync(nodes, nodeSettings).get(); internalCluster().startNodesAsync(nodes, nodeSettings).get();
client().admin().cluster().prepareHealth().setWaitForNodes(nodes + "").get(); client().admin().cluster().prepareHealth().setWaitForNodes(nodes + "").get();
client().prepareIndex("test", "doc", "1").setSource("foo", 5).setRefresh(true).get(); client().prepareIndex("test", "doc", "1").setSource("foo", 5, "bar", "baz").setRefresh(true).get();
// Plain test // Plain test
assertSuccess(""); assertSuccess("");
// numeric field access
assertSuccess("def foo = doc['foo'].value; if (foo == null) { return 5; }");
// string field access
assertSuccess("def bar = doc['bar'].value; if (foo == null) { return 5; }");
// List // List
assertSuccess("def list = [doc['foo'].value, 3, 4]; def v = list.get(1); list.add(10)"); assertSuccess("def list = [doc['foo'].value, 3, 4]; def v = list.get(1); list.add(10)");
// Ranges // Ranges