Validate top-level keys for create index request (#23755) (#23869)

This commit ensures create index requests do not ignore unknown keys passed to the request.

closes #23755
This commit is contained in:
olcbean 2017-09-26 18:49:20 +02:00 committed by Ryan Ernst
parent 5df77a8c91
commit 6952f7b560
6 changed files with 63 additions and 33 deletions

View File

@ -374,38 +374,32 @@ public class CreateIndexRequest extends AcknowledgedRequest<CreateIndexRequest>
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public CreateIndexRequest source(Map<String, ?> source) { public CreateIndexRequest source(Map<String, ?> source) {
boolean found = false;
for (Map.Entry<String, ?> entry : source.entrySet()) { for (Map.Entry<String, ?> entry : source.entrySet()) {
String name = entry.getKey(); String name = entry.getKey();
if (name.equals("settings")) { if (name.equals("settings")) {
found = true;
settings((Map<String, Object>) entry.getValue()); settings((Map<String, Object>) entry.getValue());
} else if (name.equals("mappings")) { } else if (name.equals("mappings")) {
found = true;
Map<String, Object> mappings = (Map<String, Object>) entry.getValue(); Map<String, Object> mappings = (Map<String, Object>) entry.getValue();
for (Map.Entry<String, Object> entry1 : mappings.entrySet()) { for (Map.Entry<String, Object> entry1 : mappings.entrySet()) {
mapping(entry1.getKey(), (Map<String, Object>) entry1.getValue()); mapping(entry1.getKey(), (Map<String, Object>) entry1.getValue());
} }
} else if (name.equals("aliases")) { } else if (name.equals("aliases")) {
found = true;
aliases((Map<String, Object>) entry.getValue()); aliases((Map<String, Object>) entry.getValue());
} else { } else {
// maybe custom? // maybe custom?
IndexMetaData.Custom proto = IndexMetaData.lookupPrototype(name); IndexMetaData.Custom proto = IndexMetaData.lookupPrototype(name);
if (proto != null) { if (proto != null) {
found = true;
try { try {
customs.put(name, proto.fromMap((Map<String, Object>) entry.getValue())); customs.put(name, proto.fromMap((Map<String, Object>) entry.getValue()));
} catch (IOException e) { } catch (IOException e) {
throw new ElasticsearchParseException("failed to parse custom metadata for [{}]", name); throw new ElasticsearchParseException("failed to parse custom metadata for [{}]", name);
} }
} else {
// found a key which is neither custom defined nor one of the supported ones
throw new ElasticsearchParseException("unknown key [{}] for create index", name);
} }
} }
} }
if (!found) {
// the top level are settings, use them
settings(source);
}
return this; return this;
} }

View File

@ -19,6 +19,7 @@
package org.elasticsearch.action.admin.indices.create; package org.elasticsearch.action.admin.indices.create;
import org.elasticsearch.ElasticsearchParseException;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.common.xcontent.XContentFactory;
@ -31,6 +32,7 @@ import org.junit.Before;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.util.HashMap; import java.util.HashMap;
import java.util.Locale;
import java.util.Map; import java.util.Map;
public class CreateIndexRequestBuilderTests extends ESTestCase { public class CreateIndexRequestBuilderTests extends ESTestCase {
@ -58,16 +60,23 @@ public class CreateIndexRequestBuilderTests extends ESTestCase {
*/ */
public void testSetSource() throws IOException { public void testSetSource() throws IOException {
CreateIndexRequestBuilder builder = new CreateIndexRequestBuilder(this.testClient, CreateIndexAction.INSTANCE); CreateIndexRequestBuilder builder = new CreateIndexRequestBuilder(this.testClient, CreateIndexAction.INSTANCE);
builder.setSource("{\""+KEY+"\" : \""+VALUE+"\"}", XContentType.JSON);
ElasticsearchParseException e = expectThrows(ElasticsearchParseException.class,
() -> {builder.setSource("{\""+KEY+"\" : \""+VALUE+"\"}", XContentType.JSON);});
assertEquals(String.format(Locale.ROOT, "unknown key [%s] for create index", KEY), e.getMessage());
builder.setSource("{\"settings\" : {\""+KEY+"\" : \""+VALUE+"\"}}", XContentType.JSON);
assertEquals(VALUE, builder.request().settings().get(KEY)); assertEquals(VALUE, builder.request().settings().get(KEY));
XContentBuilder xContent = XContentFactory.jsonBuilder().startObject().field(KEY, VALUE).endObject(); XContentBuilder xContent = XContentFactory.jsonBuilder().startObject()
.startObject("settings").field(KEY, VALUE).endObject().endObject();
xContent.close(); xContent.close();
builder.setSource(xContent); builder.setSource(xContent);
assertEquals(VALUE, builder.request().settings().get(KEY)); assertEquals(VALUE, builder.request().settings().get(KEY));
ByteArrayOutputStream docOut = new ByteArrayOutputStream(); ByteArrayOutputStream docOut = new ByteArrayOutputStream();
XContentBuilder doc = XContentFactory.jsonBuilder(docOut).startObject().field(KEY, VALUE).endObject(); XContentBuilder doc = XContentFactory.jsonBuilder(docOut).startObject()
.startObject("settings").field(KEY, VALUE).endObject().endObject();
doc.close(); doc.close();
builder.setSource(docOut.toByteArray(), XContentType.JSON); builder.setSource(docOut.toByteArray(), XContentType.JSON);
assertEquals(VALUE, builder.request().settings().get(KEY)); assertEquals(VALUE, builder.request().settings().get(KEY));

View File

@ -19,6 +19,7 @@
package org.elasticsearch.action.admin.indices.create; package org.elasticsearch.action.admin.indices.create;
import org.elasticsearch.ElasticsearchParseException;
import org.elasticsearch.common.io.stream.BytesStreamOutput; import org.elasticsearch.common.io.stream.BytesStreamOutput;
import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.common.xcontent.XContentType;
@ -45,4 +46,27 @@ public class CreateIndexRequestTests extends ESTestCase {
} }
} }
} }
public void testTopLevelKeys() throws IOException {
String createIndex =
"{\n"
+ " \"FOO_SHOULD_BE_ILLEGAL_HERE\": {\n"
+ " \"BAR_IS_THE_SAME\": 42\n"
+ " },\n"
+ " \"mappings\": {\n"
+ " \"test\": {\n"
+ " \"properties\": {\n"
+ " \"field1\": {\n"
+ " \"type\": \"text\"\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ "}";
CreateIndexRequest request = new CreateIndexRequest();
ElasticsearchParseException e = expectThrows(ElasticsearchParseException.class,
() -> {request.source(createIndex, XContentType.JSON);});
assertEquals("unknown key [FOO_SHOULD_BE_ILLEGAL_HERE] for create index", e.getMessage());
}
} }

View File

@ -86,25 +86,27 @@ Here is an example:
-------------------------------------------------- --------------------------------------------------
PUT /compound_word_example PUT /compound_word_example
{ {
"index": { "settings": {
"analysis": { "index": {
"analyzer": { "analysis": {
"my_analyzer": { "analyzer": {
"type": "custom", "my_analyzer": {
"tokenizer": "standard", "type": "custom",
"filter": ["dictionary_decompounder", "hyphenation_decompounder"] "tokenizer": "standard",
} "filter": ["dictionary_decompounder", "hyphenation_decompounder"]
}, }
"filter": {
"dictionary_decompounder": {
"type": "dictionary_decompounder",
"word_list": ["one", "two", "three"]
}, },
"hyphenation_decompounder": { "filter": {
"type" : "hyphenation_decompounder", "dictionary_decompounder": {
"word_list_path": "analysis/example_word_list.txt", "type": "dictionary_decompounder",
"hyphenation_patterns_path": "analysis/hyphenation_patterns.xml", "word_list": ["one", "two", "three"]
"max_subword_size": 22 },
"hyphenation_decompounder": {
"type" : "hyphenation_decompounder",
"word_list_path": "analysis/example_word_list.txt",
"hyphenation_patterns_path": "analysis/hyphenation_patterns.xml",
"max_subword_size": 22
}
} }
} }
} }

View File

@ -3,8 +3,9 @@
indices.create: indices.create:
index: smb-test index: smb-test
body: body:
index: settings:
store.type: smb_mmap_fs index:
store.type: smb_mmap_fs
- do: - do:
index: index:

View File

@ -47,7 +47,7 @@
- do: - do:
indices.create: indices.create:
index: test index: test
body: { "index.number_of_shards": 1, "index.number_of_replicas": 9 } body: { "settings": { "index.number_of_shards": 1, "index.number_of_replicas": 9 } }
- do: - do:
cluster.state: cluster.state: