|
@@ -8,6 +8,7 @@
|
|
|
package org.elasticsearch.xpack.logstash.rest;
|
|
|
|
|
|
import org.elasticsearch.client.internal.node.NodeClient;
|
|
|
+import org.elasticsearch.common.Strings;
|
|
|
import org.elasticsearch.common.bytes.BytesArray;
|
|
|
import org.elasticsearch.rest.BaseRestHandler;
|
|
|
import org.elasticsearch.rest.RestRequest;
|
|
@@ -23,12 +24,17 @@ import org.elasticsearch.xpack.logstash.action.PutPipelineResponse;
|
|
|
|
|
|
import java.io.IOException;
|
|
|
import java.util.List;
|
|
|
+import java.util.regex.Pattern;
|
|
|
|
|
|
import static org.elasticsearch.rest.RestRequest.Method.PUT;
|
|
|
|
|
|
@ServerlessScope(Scope.PUBLIC)
|
|
|
public class RestPutPipelineAction extends BaseRestHandler {
|
|
|
|
|
|
+ // A pipeline ID pattern to validate.
|
|
|
+ // Reference: https://www.elastic.co/docs/reference/logstash/configuring-centralized-pipelines#wildcard-in-pipeline-id
|
|
|
+ private static final Pattern PIPELINE_ID_PATTERN = Pattern.compile("[a-zA-Z_][a-zA-Z0-9_-]*");
|
|
|
+
|
|
|
@Override
|
|
|
public String getName() {
|
|
|
return "logstash_put_pipeline";
|
|
@@ -39,9 +45,31 @@ public class RestPutPipelineAction extends BaseRestHandler {
|
|
|
return List.of(new Route(PUT, "/_logstash/pipeline/{id}"));
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Validates pipeline ID for:
|
|
|
+ * - must begin with a letter or underscore
|
|
|
+ * - can contain only letters, underscores, dashes, and numbers
|
|
|
+ */
|
|
|
+ private static void validatePipelineId(String id) {
|
|
|
+ if (Strings.isEmpty(id)) {
|
|
|
+ throw new IllegalArgumentException("Pipeline ID cannot be null or empty");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (PIPELINE_ID_PATTERN.matcher(id).matches() == false) {
|
|
|
+ throw new IllegalArgumentException(
|
|
|
+ "Invalid pipeline ["
|
|
|
+ + id
|
|
|
+ + "] ID received. Pipeline ID must begin with a letter or underscore and can contain only letters, "
|
|
|
+ + "underscores, dashes, hyphens, and numbers"
|
|
|
+ );
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
@Override
|
|
|
protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) throws IOException {
|
|
|
final String id = request.param("id");
|
|
|
+ validatePipelineId(id);
|
|
|
+
|
|
|
try (XContentParser parser = request.contentParser()) {
|
|
|
// parse pipeline for validation
|
|
|
Pipeline.PARSER.apply(parser, id);
|