/*
* Licensed to 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.plugin;
import com.google.common.annotations.VisibleForTesting;
import io.crate.module.PluginLoaderModule;
import org.apache.logging.log4j.Logger;
import org.elasticsearch.cluster.routing.allocation.decider.AllocationDecider;
import org.elasticsearch.common.component.LifecycleComponent;
import org.elasticsearch.common.inject.Module;
import org.elasticsearch.common.logging.Loggers;
import org.elasticsearch.common.settings.ClusterSettings;
import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.index.IndexModule;
import org.elasticsearch.index.mapper.Mapper;
import org.elasticsearch.plugins.ActionPlugin;
import org.elasticsearch.plugins.ClusterPlugin;
import org.elasticsearch.plugins.MapperPlugin;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.rest.RestHandler;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.security.KeyStore;
import java.util.*;
public class PluginLoaderPlugin extends Plugin implements ActionPlugin, MapperPlugin, ClusterPlugin {
private static final Logger LOGGER = Loggers.getLogger(PluginLoaderPlugin.class);
@VisibleForTesting
final PluginLoader pluginLoader;
@VisibleForTesting
final Settings settings;
private final SQLPlugin sqlPlugin;
private final Settings additionalSettings;
private final List<Setting<?>> settingList = new ArrayList<>();
public PluginLoaderPlugin(Settings settings) {
pluginLoader = new PluginLoader(settings);
this.settings = Settings.builder()
.put(pluginLoader.additionalSettings())
.put(settings)
.build();
// SQLPlugin contains modules which use settings which may be overwritten by CratePlugins,
// so the SQLPLugin needs to be created here with settings that incl. pluginLoader.additionalSettings
sqlPlugin = new SQLPlugin(this.settings);
additionalSettings = Settings.builder()
.put(pluginLoader.additionalSettings())
.put(sqlPlugin.additionalSettings()).build();
settingList.add(PluginLoader.SETTING_CRATE_PLUGINS_PATH);
settingList.addAll(pluginLoader.getSettings());
settingList.addAll(sqlPlugin.getSettings());
try {
initializeTrustStore();
} catch (Exception e) {
LOGGER.error("Failed initializing TrustStore: {}", e.getMessage());
}
}
@Override
public Settings additionalSettings() {
return additionalSettings;
}
@Override
public List<Setting<?>> getSettings() {
return settingList;
}
@Override
public Collection<Class<? extends LifecycleComponent>> getGuiceServiceClasses() {
Collection<Class<? extends LifecycleComponent>> nodeServices = new ArrayList<>();
nodeServices.addAll(sqlPlugin.getGuiceServiceClasses());
nodeServices.addAll(pluginLoader.getGuiceServiceClasses());
return nodeServices;
}
@Override
public Collection<Module> createGuiceModules() {
Collection<Module> modules = new ArrayList<>();
modules.add(new PluginLoaderModule(pluginLoader));
modules.addAll(pluginLoader.createGuiceModules());
modules.addAll(sqlPlugin.createGuiceModules());
return modules;
}
@Override
public List<Class<? extends RestHandler>> getRestHandlers() {
List<Class<? extends RestHandler>> restHandlers = new ArrayList<>();
restHandlers.addAll(sqlPlugin.getRestHandlers());
return restHandlers;
}
@Override
public Map<String, Mapper.TypeParser> getMappers() {
Map<String, Mapper.TypeParser> mappers = new HashMap<>();
mappers.putAll(sqlPlugin.getMappers());
return mappers;
}
@Override
public Collection<AllocationDecider> createAllocationDeciders(Settings settings, ClusterSettings clusterSettings) {
return sqlPlugin.createAllocationDeciders(settings, clusterSettings);
}
@Override
public void onIndexModule(IndexModule indexModule) {
sqlPlugin.onIndexModule(indexModule);
}
public void onModule(Module module) {
pluginLoader.processModule(module);
}
/*
* Initialize our own TrustStore including StartCom CA
*
* TrustStore was generated by:
* 1. copy cacerts from $JAVA_HOME/jre/lib/security/cacerts
* 2. add crate.io certificate
* keytool -importcert -file crate.io.crt -alias crate -keystore cacerts -storepass changeit
*
* see also: http://www.cloudera.com/content/cloudera/en/documentation/core/v5-3-x/topics/cm_sg_create_key_trust.html
*/
private void initializeTrustStore() throws Exception {
String trustStorePath = "/ssl/truststore";
String trustPassword = "changeit";
// load our key store as a stream and initialize a KeyStore
try (InputStream trustStream = this.getClass().getResourceAsStream(trustStorePath)) {
if (trustStream == null) {
throw new FileNotFoundException("Resource [" + trustStorePath + "] not found in classpath");
}
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
// load the stream to our store
trustStore.load(trustStream, trustPassword.toCharArray());
// initialize a trust manager factory with the trusted store
TrustManagerFactory trustFactory =
TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustFactory.init(trustStore);
// get the trust managers from the factory
TrustManager[] trustManagers = trustFactory.getTrustManagers();
// initialize an ssl context to use these managers and set as default
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustManagers, null);
SSLContext.setDefault(sslContext);
}
}
}