[ML-DataFrame] validate group name to not contain invalid characters (#42292)
disallows of creating groupBy field with '[', ']', '>' in the name to be consistent with aggregations
This commit is contained in:
parent
3493f3b637
commit
ad24231c1a
|
@ -20,6 +20,7 @@ import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
import org.elasticsearch.common.xcontent.XContentFactory;
|
import org.elasticsearch.common.xcontent.XContentFactory;
|
||||||
import org.elasticsearch.common.xcontent.XContentParser;
|
import org.elasticsearch.common.xcontent.XContentParser;
|
||||||
import org.elasticsearch.common.xcontent.XContentType;
|
import org.elasticsearch.common.xcontent.XContentType;
|
||||||
|
import org.elasticsearch.search.aggregations.AggregatorFactories;
|
||||||
import org.elasticsearch.xpack.core.dataframe.DataFrameField;
|
import org.elasticsearch.xpack.core.dataframe.DataFrameField;
|
||||||
import org.elasticsearch.xpack.core.dataframe.DataFrameMessages;
|
import org.elasticsearch.xpack.core.dataframe.DataFrameMessages;
|
||||||
import org.elasticsearch.xpack.core.dataframe.utils.ExceptionsHelper;
|
import org.elasticsearch.xpack.core.dataframe.utils.ExceptionsHelper;
|
||||||
|
@ -29,6 +30,7 @@ import java.util.LinkedHashMap;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
|
||||||
import static org.elasticsearch.common.xcontent.XContentParserUtils.ensureExpectedToken;
|
import static org.elasticsearch.common.xcontent.XContentParserUtils.ensureExpectedToken;
|
||||||
|
|
||||||
|
@ -135,6 +137,7 @@ public class GroupConfig implements Writeable, ToXContentObject {
|
||||||
|
|
||||||
private static Map<String, SingleGroupSource> parseGroupConfig(final XContentParser parser,
|
private static Map<String, SingleGroupSource> parseGroupConfig(final XContentParser parser,
|
||||||
boolean lenient) throws IOException {
|
boolean lenient) throws IOException {
|
||||||
|
Matcher validAggMatcher = AggregatorFactories.VALID_AGG_NAME.matcher("");
|
||||||
LinkedHashMap<String, SingleGroupSource> groups = new LinkedHashMap<>();
|
LinkedHashMap<String, SingleGroupSource> groups = new LinkedHashMap<>();
|
||||||
|
|
||||||
// be parsing friendly, whether the token needs to be advanced or not (similar to what ObjectParser does)
|
// be parsing friendly, whether the token needs to be advanced or not (similar to what ObjectParser does)
|
||||||
|
@ -150,6 +153,11 @@ public class GroupConfig implements Writeable, ToXContentObject {
|
||||||
|
|
||||||
ensureExpectedToken(XContentParser.Token.FIELD_NAME, token, parser::getTokenLocation);
|
ensureExpectedToken(XContentParser.Token.FIELD_NAME, token, parser::getTokenLocation);
|
||||||
String destinationFieldName = parser.currentName();
|
String destinationFieldName = parser.currentName();
|
||||||
|
if (validAggMatcher.reset(destinationFieldName).matches() == false) {
|
||||||
|
throw new ParsingException(parser.getTokenLocation(), "Invalid group name [" + destinationFieldName
|
||||||
|
+ "]. Group names can contain any character except '[', ']', and '>'");
|
||||||
|
}
|
||||||
|
|
||||||
token = parser.nextToken();
|
token = parser.nextToken();
|
||||||
ensureExpectedToken(XContentParser.Token.START_OBJECT, token, parser::getTokenLocation);
|
ensureExpectedToken(XContentParser.Token.START_OBJECT, token, parser::getTokenLocation);
|
||||||
token = parser.nextToken();
|
token = parser.nextToken();
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
package org.elasticsearch.xpack.core.dataframe.transforms.pivot;
|
package org.elasticsearch.xpack.core.dataframe.transforms.pivot;
|
||||||
|
|
||||||
|
import org.elasticsearch.common.ParsingException;
|
||||||
import org.elasticsearch.common.bytes.BytesReference;
|
import org.elasticsearch.common.bytes.BytesReference;
|
||||||
import org.elasticsearch.common.io.stream.Writeable.Reader;
|
import org.elasticsearch.common.io.stream.Writeable.Reader;
|
||||||
import org.elasticsearch.common.xcontent.ToXContent;
|
import org.elasticsearch.common.xcontent.ToXContent;
|
||||||
|
@ -27,6 +28,9 @@ import java.util.Set;
|
||||||
|
|
||||||
public class GroupConfigTests extends AbstractSerializingTestCase<GroupConfig> {
|
public class GroupConfigTests extends AbstractSerializingTestCase<GroupConfig> {
|
||||||
|
|
||||||
|
// array of illegal characters, see {@link AggregatorFactories#VALID_AGG_NAME}
|
||||||
|
private static final char[] ILLEGAL_FIELD_NAME_CHARACTERS = {'[', ']', '>'};
|
||||||
|
|
||||||
public static GroupConfig randomGroupConfig() {
|
public static GroupConfig randomGroupConfig() {
|
||||||
Map<String, Object> source = new LinkedHashMap<>();
|
Map<String, Object> source = new LinkedHashMap<>();
|
||||||
Map<String, SingleGroupSource> groups = new LinkedHashMap<>();
|
Map<String, SingleGroupSource> groups = new LinkedHashMap<>();
|
||||||
|
@ -88,6 +92,34 @@ public class GroupConfigTests extends AbstractSerializingTestCase<GroupConfig> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testInvalidGroupByNames() throws IOException {
|
||||||
|
|
||||||
|
String invalidName = randomAlphaOfLengthBetween(0, 5)
|
||||||
|
+ ILLEGAL_FIELD_NAME_CHARACTERS[randomIntBetween(0, ILLEGAL_FIELD_NAME_CHARACTERS.length - 1)]
|
||||||
|
+ randomAlphaOfLengthBetween(0, 5);
|
||||||
|
|
||||||
|
XContentBuilder source = JsonXContent.contentBuilder()
|
||||||
|
.startObject()
|
||||||
|
.startObject(invalidName)
|
||||||
|
.startObject("terms")
|
||||||
|
.field("field", "user")
|
||||||
|
.endObject()
|
||||||
|
.endObject()
|
||||||
|
.endObject();
|
||||||
|
|
||||||
|
// lenient, passes but reports invalid
|
||||||
|
try (XContentParser parser = createParser(source)) {
|
||||||
|
GroupConfig groupConfig = GroupConfig.fromXContent(parser, true);
|
||||||
|
assertFalse(groupConfig.isValid());
|
||||||
|
}
|
||||||
|
|
||||||
|
// strict throws
|
||||||
|
try (XContentParser parser = createParser(source)) {
|
||||||
|
Exception e = expectThrows(ParsingException.class, () -> GroupConfig.fromXContent(parser, false));
|
||||||
|
assertTrue(e.getMessage().startsWith("Invalid group name"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static Map<String, Object> getSource(SingleGroupSource groupSource) {
|
private static Map<String, Object> getSource(SingleGroupSource groupSource) {
|
||||||
try (XContentBuilder xContentBuilder = XContentFactory.jsonBuilder()) {
|
try (XContentBuilder xContentBuilder = XContentFactory.jsonBuilder()) {
|
||||||
XContentBuilder content = groupSource.toXContent(xContentBuilder, ToXContent.EMPTY_PARAMS);
|
XContentBuilder content = groupSource.toXContent(xContentBuilder, ToXContent.EMPTY_PARAMS);
|
||||||
|
|
Loading…
Reference in New Issue