diff --git a/src/main/java/com/fr/plugin/db/es/fun/ElasticsearchConnection.java b/src/main/java/com/fr/plugin/db/es/fun/ElasticsearchConnection.java index b504fb0..6728518 100644 --- a/src/main/java/com/fr/plugin/db/es/fun/ElasticsearchConnection.java +++ b/src/main/java/com/fr/plugin/db/es/fun/ElasticsearchConnection.java @@ -39,6 +39,12 @@ public class ElasticsearchConnection extends BaseConnection { private Conf username = HolderKit.simple(StringKit.EMPTY); @Identifier("password") private Conf password = HolderKit.simple(StringKit.EMPTY); + @Identifier("useSSL") + private Conf useSSL = HolderKit.simple(false); + @Identifier("keyStoreFilePath") + private Conf keyStoreFilePath = HolderKit.simple(StringKit.EMPTY); + @Identifier("keyStorePassword") + private Conf keyStorePassword = HolderKit.simple(StringKit.EMPTY); public String getHost() { return host.get(); @@ -72,6 +78,30 @@ public class ElasticsearchConnection extends BaseConnection { this.password.set(password); } + public boolean isUseSSL() { + return useSSL.get(); + } + + public void setUseSSL(boolean useSSL) { + this.useSSL.set(useSSL); + } + + public String getKeyStoreFilePath() { + return keyStoreFilePath.get(); + } + + public void setKeyStoreFilePath(String keyStoreFilePath) { + this.keyStoreFilePath.set(keyStoreFilePath); + } + + public String getKeyStorePassword() { + return keyStorePassword.get(); + } + + public void setKeyStorePassword(String keyStorePassword) { + this.keyStorePassword.set(keyStorePassword); + } + @Override public void testConnection() throws Exception { RestHighLevelClient client = createRestHighLevelClient(); @@ -90,12 +120,16 @@ public class ElasticsearchConnection extends BaseConnection { public RestHighLevelClient createRestHighLevelClient() { Pair setting = setting(); - return ElasticsearchClientFactory.buildHighLevelClient(setting.getFirst(), setting.getSecond(), getUsername(), getPassword()); + return isUseSSL() ? + ElasticsearchClientFactory.buildHighLevelSSLClient(getKeyStoreFilePath(), getKeyStorePassword(), setting.getFirst(), setting.getSecond(), getUsername(), getPassword()) + : ElasticsearchClientFactory.buildHighLevelClient(setting.getFirst(), setting.getSecond(), getUsername(), getPassword()); } public RestClient createClient() { Pair setting = setting(); - return ElasticsearchClientFactory.buildClient(setting.getFirst(), setting.getSecond(), getUsername(), getPassword()); + return isUseSSL() ? + ElasticsearchClientFactory.buildSSLClient(getKeyStoreFilePath(), getKeyStorePassword(), setting.getFirst(), setting.getSecond(), getUsername(), getPassword()) + : ElasticsearchClientFactory.buildClient(setting.getFirst(), setting.getSecond(), getUsername(), getPassword()); } private Pair setting() { @@ -104,7 +138,7 @@ public class ElasticsearchConnection extends BaseConnection { String[] hosts = host.split(","); String[] portArr = port.split(","); Integer[] ports = new Integer[portArr.length]; - for (int i = 0; i < portArr.length; i ++) { + for (int i = 0; i < portArr.length; i++) { ports[i] = Integer.parseInt(portArr[i]); } return new Pair(hosts, ports); diff --git a/src/main/java/com/fr/plugin/db/es/fun/help/ElasticsearchClientFactory.java b/src/main/java/com/fr/plugin/db/es/fun/help/ElasticsearchClientFactory.java index ff2f42c..923be85 100644 --- a/src/main/java/com/fr/plugin/db/es/fun/help/ElasticsearchClientFactory.java +++ b/src/main/java/com/fr/plugin/db/es/fun/help/ElasticsearchClientFactory.java @@ -1,17 +1,28 @@ package com.fr.plugin.db.es.fun.help; +import com.fanruan.api.log.LogKit; import com.fanruan.api.util.ArrayKit; import com.fanruan.api.util.StringKit; +import com.fr.io.utils.ResourceIOUtils; import org.apache.http.HttpHost; import org.apache.http.auth.AuthScope; import org.apache.http.auth.UsernamePasswordCredentials; import org.apache.http.client.CredentialsProvider; import org.apache.http.impl.client.BasicCredentialsProvider; import org.apache.http.impl.nio.client.HttpAsyncClientBuilder; +import org.apache.http.ssl.SSLContextBuilder; +import org.apache.http.ssl.SSLContexts; +import org.apache.http.ssl.TrustStrategy; import org.elasticsearch.client.RestClient; import org.elasticsearch.client.RestClientBuilder; import org.elasticsearch.client.RestHighLevelClient; +import javax.net.ssl.SSLContext; +import java.io.InputStream; +import java.security.KeyStore; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; + /** * @author richie * @version 10.0 @@ -23,10 +34,18 @@ public class ElasticsearchClientFactory { return new RestHighLevelClient(build(hosts, ports, username, password)); } + public static RestHighLevelClient buildHighLevelSSLClient(String keyStoreFilePath, String keyStorePassword, String[] hosts, Integer[] ports, String username, String password) { + return new RestHighLevelClient(buildSSL(keyStoreFilePath, keyStorePassword, hosts, ports, username, password)); + } + public static RestClient buildClient(String[] hosts, Integer[] ports, String username, String password) { return build(hosts, ports, username, password).build(); } + public static RestClient buildSSLClient(String keyStoreFilePath, String keyStorePassword, String[] hosts, Integer[] ports, String username, String password) { + return buildSSL(keyStoreFilePath, keyStorePassword, hosts, ports, username, password).build(); + } + private static RestClientBuilder build(String[] hosts, Integer[] ports, String username, String password) { int hostCount = ArrayKit.getLength(hosts); int portCount = ArrayKit.getLength(ports); @@ -50,4 +69,45 @@ public class ElasticsearchClientFactory { } return builder; } + + private static RestClientBuilder buildSSL(String keyStoreFilePath, String keyStorePassword, String[] hosts, Integer[] ports, String username, String password) { + int hostCount = ArrayKit.getLength(hosts); + int portCount = ArrayKit.getLength(ports); + if (portCount != hostCount) { + throw new IllegalArgumentException("Hosts and ports must be matched!"); + } + HttpHost[] httpHosts = new HttpHost[hostCount]; + for (int i = 0; i < hostCount; i++) { + httpHosts[i] = new HttpHost(hosts[i], ports[i], "https"); + } + + RestClientBuilder builder = RestClient.builder(httpHosts); + if (StringKit.isNotEmpty(username)) { + final CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); + credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(username, password)); + if (StringKit.isEmpty(keyStoreFilePath)) { + // 没有使用自定义的ssl证书 + builder.setHttpClientConfigCallback(httpAsyncClientBuilder -> httpAsyncClientBuilder.setDefaultCredentialsProvider(credentialsProvider)); + } else { + // 用自定义ssl证书 + try { + KeyStore truststore = KeyStore.getInstance("jks"); + try (InputStream is = ResourceIOUtils.read(keyStoreFilePath)) { + truststore.load(is, keyStorePassword.toCharArray()); + } + SSLContextBuilder sslBuilder = SSLContexts.custom().loadTrustMaterial(truststore, new TrustStrategy(){ + public boolean isTrusted(X509Certificate[] chain, String authType) + throws CertificateException { + return true; + } + }); + final SSLContext sslContext = sslBuilder.build(); + builder.setHttpClientConfigCallback(httpAsyncClientBuilder -> httpAsyncClientBuilder.setSSLContext(sslContext).setDefaultCredentialsProvider(credentialsProvider)); + } catch (Exception e) { + LogKit.error(e.getMessage(), e); + } + } + } + return builder; + } } diff --git a/src/main/java/com/fr/plugin/db/es/ui/ElasticsearchConnectionPane.java b/src/main/java/com/fr/plugin/db/es/ui/ElasticsearchConnectionPane.java index 7c0a69c..328c502 100644 --- a/src/main/java/com/fr/plugin/db/es/ui/ElasticsearchConnectionPane.java +++ b/src/main/java/com/fr/plugin/db/es/ui/ElasticsearchConnectionPane.java @@ -2,6 +2,7 @@ package com.fr.plugin.db.es.ui; import com.fanruan.api.design.DesignKit; import com.fanruan.api.design.ui.component.UIButton; +import com.fanruan.api.design.ui.component.UICheckBox; import com.fanruan.api.design.ui.component.UILabel; import com.fanruan.api.design.ui.component.UIPasswordField; import com.fanruan.api.design.ui.component.UITextField; @@ -10,9 +11,11 @@ import com.fanruan.api.design.ui.layout.TableLayoutKit; import com.fanruan.api.design.util.GUICoreKit; import com.fanruan.api.design.work.DatabaseConnectionPane; import com.fanruan.api.util.IOKit; +import com.fr.design.gui.ifilechooser.UINativeFileChooser; import com.fr.plugin.db.es.fun.ElasticsearchConnection; import javax.swing.*; +import javax.swing.filechooser.FileNameExtensionFilter; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; @@ -28,6 +31,10 @@ public class ElasticsearchConnectionPane extends DatabaseConnectionPane checkEnabled()); + fileSelectButton = new UIButton("..."); + fileSelectButton.addActionListener(e -> { + UINativeFileChooser fileChooser = new UINativeFileChooser(); + fileChooser.setFileFilter(new FileNameExtensionFilter("JKS", "jks")); + int r = fileChooser.showOpenDialog(SwingUtilities.getWindowAncestor(ElasticsearchConnectionPane.this)); + if (r == JFileChooser.APPROVE_OPTION) { + keyStoreFilePathTextField.setText(fileChooser.getSelectedFile().getAbsolutePath()); + } + }); + keyStoreFilePathTextField.setPlaceholder(DesignKit.i18nText("Plugin-Elasticsearch_Key_Store_Path_Description")); + Component[][] components = new Component[][]{ {new UILabel(DesignKit.i18nText("Plugin-Elasticsearch_Host") + ":"), GUICoreKit.createBorderLayoutPane(hostTextField, BorderLayout.CENTER, helpButton, BorderLayout.EAST)}, {new UILabel(DesignKit.i18nText("Plugin-Elasticsearch_Port") + ":"), portTextField}, {new UILabel(DesignKit.i18nText("Plugin-Elasticsearch_Username") + ":"), usernameTextField}, {new UILabel(DesignKit.i18nText("Plugin-Elasticsearch_Password") + ":"), passwordTextField}, + {new UILabel(DesignKit.i18nText("Plugin-Elasticsearch_Protocol") + ":"), useSSLCheckBox}, + {new UILabel(DesignKit.i18nText("Plugin-Elasticsearch_Key_Store_Path") + ":"), GUICoreKit.createBorderLayoutPane( + keyStoreFilePathTextField, BorderLayout.CENTER, + fileSelectButton, BorderLayout.EAST + )}, + {new UILabel(DesignKit.i18nText("Plugin-Elasticsearch_Key_Store_Password") + ":"), keyStorePasswordTextField} }; - double p = TableLayoutKit.PREFERRED; - double[] rowSize = new double[]{p, p, p, p, p}; - double[] columnSize = new double[]{p, 400}; + double[] rowSize = new double[]{p, p, p, p, p, p, p, p}; + double[] columnSize = new double[]{p, 600}; JPanel settingsUI = TableLayoutKit.createTableLayoutPane(components, rowSize, columnSize); settingsUI.setBorder(UITitledBorder.createBorderWithTitle("Elasticsearch")); @@ -79,7 +106,12 @@ public class ElasticsearchConnectionPane extends DatabaseConnectionPane