/*
* Licensed to CRATE Technology GmbH ("Crate") under one or more contributor
* license agreements. See the NOTICE file distributed with this work for
* additional information regarding copyright ownership. Crate licenses
* this file to you under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. You may
* obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* However, if you have executed another commercial license agreement
* with Crate these terms will supersede the license and you may use the
* software solely pursuant to the terms of the relevant commercial agreement.
*/
package io.crate.rest;
import com.google.common.collect.ImmutableSet;
import org.apache.logging.log4j.Logger;
import org.elasticsearch.client.node.NodeClient;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.logging.Loggers;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.rest.*;
import java.util.Locale;
import java.util.Set;
import java.util.regex.Pattern;
import static org.elasticsearch.rest.RestStatus.BAD_REQUEST;
/**
* RestFilter that disables all endpoints but the ones listed in SUPPORTED_ENDPOINTS
*/
public class CrateRestFilter extends RestFilter {
public static final Setting<Boolean> ES_API_ENABLED_SETTING = Setting.boolSetting(
"es.api.enabled", false, Setting.Property.NodeScope);
private static final Set<String> SUPPORTED_ENDPOINTS = ImmutableSet.of(
"/index.html",
"/static",
"/admin",
"/_sql",
"/_plugin",
"/_blobs"
);
// handle possible (wrong) URL '//' too
// as some http clients create wrong requests to the ``root`` path '/' with '//'
// we do handle arbitrary numbers of '/' in the path
private static final Pattern MAIN_PATTERN = Pattern.compile(String.format(Locale.ENGLISH, "^%s+$", CrateRestMainAction.PATH));
private final boolean esApiEnabled;
@Inject
public CrateRestFilter(Settings settings) {
this.esApiEnabled = ES_API_ENABLED_SETTING.get(settings);
Logger logger = Loggers.getLogger(getClass().getPackage().getName(), settings);
logger.info("Elasticsearch HTTP REST API {}enabled", esApiEnabled ? "" : "not ");
}
@Override
public void process(RestRequest request, RestChannel channel, NodeClient client, RestFilterChain filterChain) throws Exception {
if (esApiEnabled || endpointAllowed(request.rawPath())) {
filterChain.continueProcessing(request, channel, client);
} else {
channel.sendResponse(
new BytesRestResponse(
BAD_REQUEST,
String.format(Locale.ENGLISH,
"No handler found for uri [%s] and method [%s]",
request.uri(),
request.method())
));
}
}
private static boolean endpointAllowed(String rawPath) {
if (MAIN_PATTERN.matcher(rawPath).matches()) {
return true;
}
for (String supported : SUPPORTED_ENDPOINTS) {
if (rawPath.startsWith(supported)) {
return true;
}
}
return false;
}
}