From 67f9e8fa234443eb754ed780e62e5deff18b67b0 Mon Sep 17 00:00:00 2001 From: Gordon Brown Date: Fri, 9 Nov 2018 10:11:26 -0700 Subject: [PATCH] Enforce limitations on ILM policy names (#35104) Enforces restrictions on ILM policy names to ensure we don't accept policy names the system can't handle, or may reserve for future use. --- .../core/indexlifecycle/LifecyclePolicy.java | 27 +++++++++++++++++++ .../indexlifecycle/LifecyclePolicyTests.java | 16 +++++++++++ .../TimeSeriesLifecycleActionsIT.java | 22 +++++++++++++++ .../action/TransportPutLifecycleAction.java | 2 ++ 4 files changed, 67 insertions(+) diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/indexlifecycle/LifecyclePolicy.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/indexlifecycle/LifecyclePolicy.java index a56818355c3..380f9888668 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/indexlifecycle/LifecyclePolicy.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/indexlifecycle/LifecyclePolicy.java @@ -21,12 +21,14 @@ import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.xpack.core.indexlifecycle.Step.StepKey; import java.io.IOException; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.ListIterator; import java.util.Map; import java.util.Objects; +import java.util.function.BiFunction; import java.util.function.Function; import java.util.stream.Collectors; @@ -40,6 +42,7 @@ import java.util.stream.Collectors; public class LifecyclePolicy extends AbstractDiffable implements ToXContentObject, Diffable { private static final Logger logger = LogManager.getLogger(LifecyclePolicy.class); + private static final int MAX_INDEX_NAME_BYTES = 255; public static final ParseField PHASES_FIELD = new ParseField("phases"); @@ -241,6 +244,30 @@ public class LifecyclePolicy extends AbstractDiffable } } + /** + * Validate the name for an policy against some static rules. Intended to match + * {@link org.elasticsearch.cluster.metadata.MetaDataCreateIndexService#validateIndexOrAliasName(String, BiFunction)} + * @param policy the policy name to validate + * @throws IllegalArgumentException if the name is invalid + */ + public static void validatePolicyName(String policy) { + if (policy.contains(",")) { + throw new IllegalArgumentException("invalid policy name [" + policy + "]: must not contain ','"); + } + if (policy.contains(" ")) { + throw new IllegalArgumentException("invalid policy name [" + policy + "]: must not contain spaces"); + } + if (policy.charAt(0) == '_') { + throw new IllegalArgumentException("invalid policy name [" + policy + "]: must not start with '_'"); + } + int byteCount = 0; + byteCount = policy.getBytes(StandardCharsets.UTF_8).length; + if (byteCount > MAX_INDEX_NAME_BYTES) { + throw new IllegalArgumentException("invalid policy name [" + policy + "]: name is too long, (" + byteCount + " > " + + MAX_INDEX_NAME_BYTES + ")"); + } + } + @Override public int hashCode() { return Objects.hash(name, phases); diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/indexlifecycle/LifecyclePolicyTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/indexlifecycle/LifecyclePolicyTests.java index 9d90cc025b0..f61d0189782 100644 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/indexlifecycle/LifecyclePolicyTests.java +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/indexlifecycle/LifecyclePolicyTests.java @@ -316,4 +316,20 @@ public class LifecyclePolicyTests extends AbstractSerializingTestCase LifecyclePolicy.validatePolicyName(randomAlphaOfLengthBetween(0,10) + + "," + randomAlphaOfLengthBetween(0,10))); + expectThrows(IllegalArgumentException.class, () -> LifecyclePolicy.validatePolicyName(randomAlphaOfLengthBetween(0,10) + + " " + randomAlphaOfLengthBetween(0,10))); + expectThrows(IllegalArgumentException.class, () -> LifecyclePolicy.validatePolicyName("_" + randomAlphaOfLengthBetween(1, 20))); + expectThrows(IllegalArgumentException.class, () -> LifecyclePolicy.validatePolicyName(randomAlphaOfLengthBetween(256, 1000))); + + LifecyclePolicy.validatePolicyName(randomAlphaOfLengthBetween(1,10) + "_" + randomAlphaOfLengthBetween(0,10)); + + LifecyclePolicy.validatePolicyName(randomAlphaOfLengthBetween(0,10) + "-" + randomAlphaOfLengthBetween(0,10)); + LifecyclePolicy.validatePolicyName(randomAlphaOfLengthBetween(0,10) + "+" + randomAlphaOfLengthBetween(0,10)); + + LifecyclePolicy.validatePolicyName(randomAlphaOfLengthBetween(1,255)); + } } diff --git a/x-pack/plugin/ilm/qa/multi-node/src/test/java/org/elasticsearch/xpack/indexlifecycle/TimeSeriesLifecycleActionsIT.java b/x-pack/plugin/ilm/qa/multi-node/src/test/java/org/elasticsearch/xpack/indexlifecycle/TimeSeriesLifecycleActionsIT.java index 8dc8427bc76..94609128c94 100644 --- a/x-pack/plugin/ilm/qa/multi-node/src/test/java/org/elasticsearch/xpack/indexlifecycle/TimeSeriesLifecycleActionsIT.java +++ b/x-pack/plugin/ilm/qa/multi-node/src/test/java/org/elasticsearch/xpack/indexlifecycle/TimeSeriesLifecycleActionsIT.java @@ -36,6 +36,7 @@ import org.junit.Before; import java.io.IOException; import java.io.InputStream; +import java.io.UnsupportedEncodingException; import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -45,6 +46,7 @@ import java.util.function.Supplier; import static java.util.Collections.singletonMap; import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder; +import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.greaterThan; import static org.hamcrest.Matchers.not; @@ -399,6 +401,26 @@ public class TimeSeriesLifecycleActionsIT extends ESRestTestCase { } + public void testInvalidPolicyNames() throws UnsupportedEncodingException { + ResponseException ex; + + policy = randomAlphaOfLengthBetween(0,10) + "," + randomAlphaOfLengthBetween(0,10); + ex = expectThrows(ResponseException.class, () -> createNewSingletonPolicy("delete", new DeleteAction())); + assertThat(ex.getCause().getMessage(), containsString("invalid policy name")); + + policy = randomAlphaOfLengthBetween(0,10) + "%20" + randomAlphaOfLengthBetween(0,10); + ex = expectThrows(ResponseException.class, () -> createNewSingletonPolicy("delete", new DeleteAction())); + assertThat(ex.getCause().getMessage(), containsString("invalid policy name")); + + policy = "_" + randomAlphaOfLengthBetween(1, 20); + ex = expectThrows(ResponseException.class, () -> createNewSingletonPolicy("delete", new DeleteAction())); + assertThat(ex.getMessage(), containsString("invalid policy name")); + + policy = randomAlphaOfLengthBetween(256, 1000); + ex = expectThrows(ResponseException.class, () -> createNewSingletonPolicy("delete", new DeleteAction())); + assertThat(ex.getMessage(), containsString("invalid policy name")); + } + private void createFullPolicy(TimeValue hotTime) throws IOException { Map warmActions = new HashMap<>(); warmActions.put(ForceMergeAction.NAME, new ForceMergeAction(1)); diff --git a/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/indexlifecycle/action/TransportPutLifecycleAction.java b/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/indexlifecycle/action/TransportPutLifecycleAction.java index dd4196c0a88..da51bb68962 100644 --- a/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/indexlifecycle/action/TransportPutLifecycleAction.java +++ b/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/indexlifecycle/action/TransportPutLifecycleAction.java @@ -21,6 +21,7 @@ import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.transport.TransportService; import org.elasticsearch.xpack.core.ClientHelper; import org.elasticsearch.xpack.core.indexlifecycle.IndexLifecycleMetadata; +import org.elasticsearch.xpack.core.indexlifecycle.LifecyclePolicy; import org.elasticsearch.xpack.core.indexlifecycle.LifecyclePolicyMetadata; import org.elasticsearch.xpack.core.indexlifecycle.OperationMode; import org.elasticsearch.xpack.core.indexlifecycle.action.PutLifecycleAction; @@ -65,6 +66,7 @@ public class TransportPutLifecycleAction extends TransportMasterNodeAction filteredHeaders = threadPool.getThreadContext().getHeaders().entrySet().stream() .filter(e -> ClientHelper.SECURITY_HEADER_FILTERS.contains(e.getKey())) .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + LifecyclePolicy.validatePolicyName(request.getPolicy().getName()); clusterService.submitStateUpdateTask("put-lifecycle-" + request.getPolicy().getName(), new AckedClusterStateUpdateTask(request, listener) { @Override