Repository: ambari Updated Branches: refs/heads/trunk 86fbb3810 -> 015d40460
AMBARI-19723 Log Search portal not working if only solr needs SSL connection (mgergely) Change-Id: Iebb2ef076dd4f75af73757ab3f08f250c654df69 Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/015d4046 Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/015d4046 Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/015d4046 Branch: refs/heads/trunk Commit: 015d404604da164aa939635b7835a9551321cc5e Parents: 86fbb38 Author: Miklos Gergely <mgerg...@hortonworks.com> Authored: Sun Jan 29 13:24:00 2017 +0100 Committer: Miklos Gergely <mgerg...@hortonworks.com> Committed: Sun Jan 29 13:24:00 2017 +0100 ---------------------------------------------------------------------- .../ambari-logsearch-portal/pom.xml | 5 + .../org/apache/ambari/logsearch/LogSearch.java | 98 +------------ .../apache/ambari/logsearch/util/FileUtil.java | 26 ++++ .../apache/ambari/logsearch/util/SSLUtil.java | 141 +++++++++++++++---- 4 files changed, 148 insertions(+), 122 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/015d4046/ambari-logsearch/ambari-logsearch-portal/pom.xml ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-portal/pom.xml b/ambari-logsearch/ambari-logsearch-portal/pom.xml index 61dcb37..32d4e2c 100755 --- a/ambari-logsearch/ambari-logsearch-portal/pom.xml +++ b/ambari-logsearch/ambari-logsearch-portal/pom.xml @@ -786,5 +786,10 @@ <artifactId>bcprov-jdk15on</artifactId> <version>1.55</version> </dependency> + <dependency> + <groupId>org.bouncycastle</groupId> + <artifactId>bcpkix-jdk15on</artifactId> + <version>1.55</version> + </dependency> </dependencies> </project> http://git-wip-us.apache.org/repos/asf/ambari/blob/015d4046/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/LogSearch.java ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/LogSearch.java b/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/LogSearch.java index 88cc8bb..70053d2 100644 --- a/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/LogSearch.java +++ b/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/LogSearch.java @@ -18,17 +18,12 @@ */ package org.apache.ambari.logsearch; -import java.io.File; import java.io.IOException; import java.net.MalformedURLException; import java.net.ServerSocket; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; -import java.security.KeyPair; -import java.security.KeyStore; -import java.security.Security; -import java.security.cert.X509Certificate; import java.util.EnumSet; import org.apache.ambari.logsearch.common.ManageStartEndTime; @@ -36,12 +31,7 @@ import org.apache.ambari.logsearch.common.PropertiesHelper; import org.apache.ambari.logsearch.conf.ApplicationConfig; import org.apache.ambari.logsearch.util.SSLUtil; import org.apache.ambari.logsearch.web.listener.LogSearchSessionListener; -import org.apache.commons.io.FileUtils; import org.apache.commons.lang.StringUtils; -import org.apache.tools.ant.Project; -import org.apache.tools.ant.taskdefs.Chmod; -import org.apache.tools.ant.types.FileSet; -import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.HttpConfiguration; import org.eclipse.jetty.server.HttpConnectionFactory; @@ -73,8 +63,6 @@ public class LogSearch { private static final Logger LOG = LoggerFactory.getLogger(LogSearch.class); private static final String LOGSEARCH_PROTOCOL_PROP = "logsearch.protocol"; - private static final String LOGSEARCH_CERT_FOLDER_LOCATION = "logsearch.cert.folder.location"; - private static final String LOGSEARCH_CERT_ALGORITHM = "logsearch.cert.algorithm"; private static final String HTTPS_PROTOCOL = "https"; private static final String HTTP_PROTOCOL = "http"; private static final String HTTPS_PORT = "61889"; @@ -84,15 +72,6 @@ public class LogSearch { private static final String ROOT_CONTEXT = "/"; private static final Integer SESSION_TIMEOUT = 60 * 30; - private static final String LOGSEARCH_CERT_FILENAME = "logsearch.crt"; - private static final String LOGSEARCH_KEYSTORE_FILENAME = "logsearch.jks"; - private static final String LOGSEARCH_KEYSTORE_PRIVATE_KEY = "logsearch.private.key"; - private static final String LOGSEARCH_KEYSTORE_PUBLIC_KEY = "logsearch.public.key"; - private static final String LOGSEARCH_CERT_DEFAULT_ALGORITHM = "sha256WithRSAEncryption"; - - public static final String LOGSEARCH_CERT_DEFAULT_FOLDER = "/etc/ambari-logsearch-portal/conf/keys"; - public static final String LOGSEARCH_KEYSTORE_DEFAULT_PASSWORD = "bigdata"; - public static void main(String[] argv) { LogSearch logSearch = new LogSearch(); ManageStartEndTime.manage(); @@ -104,7 +83,8 @@ public class LogSearch { } public void run(String[] argv) throws Exception { - loadKeystore(); + SSLUtil.ensureStorePasswords(); + SSLUtil.loadKeystore(); Server server = buildSever(argv); HandlerList handlers = new HandlerList(); handlers.addHandler(createSwaggerContext()); @@ -113,11 +93,9 @@ public class LogSearch { server.setHandler(handlers); server.start(); - LOG - .debug("============================Server Dump======================================="); + LOG.debug("============================Server Dump======================================="); LOG.debug(server.dump()); - LOG - .debug("=============================================================================="); + LOG.debug("=============================================================================="); server.join(); } @@ -202,7 +180,7 @@ public class LogSearch { private URI findWebResourceBase() { URL fileCompleteUrl = Thread.currentThread().getContextClassLoader() .getResource(WEB_RESOURCE_FOLDER); - String errorMessage = "Web Resource Folder " + WEB_RESOURCE_FOLDER+ " not found in classpath"; + String errorMessage = "Web Resource Folder " + WEB_RESOURCE_FOLDER + " not found in classpath"; if (fileCompleteUrl != null) { try { return fileCompleteUrl.toURI().normalize(); @@ -238,70 +216,4 @@ public class LogSearch { } } } - - /** - * Create keystore with keys and certificate (only if the keystore does not exist or if you have no permissions on the keystore file) - */ - void loadKeystore() { - try { - String certFolder = PropertiesHelper.getProperty(LOGSEARCH_CERT_FOLDER_LOCATION, LOGSEARCH_CERT_DEFAULT_FOLDER); - String certAlgorithm = PropertiesHelper.getProperty(LOGSEARCH_CERT_ALGORITHM, LOGSEARCH_CERT_DEFAULT_ALGORITHM); - String certLocation = String.format("%s/%s", LOGSEARCH_CERT_DEFAULT_FOLDER, LOGSEARCH_CERT_FILENAME); - String keyStoreLocation = StringUtils.isNotEmpty(SSLUtil.getKeyStoreLocation()) ? SSLUtil.getKeyStoreLocation() - : String.format("%s/%s", LOGSEARCH_CERT_DEFAULT_FOLDER, LOGSEARCH_KEYSTORE_FILENAME); - char[] password = StringUtils.isNotEmpty(SSLUtil.getKeyStorePassword()) ? - SSLUtil.getKeyStorePassword().toCharArray() : LOGSEARCH_KEYSTORE_DEFAULT_PASSWORD.toCharArray(); - boolean keyStoreFileExists = new File(keyStoreLocation).exists(); - if (!keyStoreFileExists) { - createDefaultKeyFolder(certFolder); - LOG.warn("Keystore file ('{}') does not exist, creating new one. " + - "If the file exists, make sure you have proper permissions on that.", keyStoreLocation); - if (SSLUtil.isKeyStoreSpecified() && !"JKS".equalsIgnoreCase(SSLUtil.getKeyStoreType())) { - throw new RuntimeException(String.format("Keystore does not exist. Only JKS keystore can be auto generated. (%s)", keyStoreLocation)); - } - LOG.info("SSL keystore is not specified. Generating it with certificate ... (using default format: JKS)"); - Security.addProvider(new BouncyCastleProvider()); - KeyPair keyPair = SSLUtil.createKeyPair("RSA", 2048); - File privateKeyFile = new File(String.format("%s/%s", certFolder, LOGSEARCH_KEYSTORE_PRIVATE_KEY)); - if (!privateKeyFile.exists()) { - FileUtils.writeByteArrayToFile(privateKeyFile, keyPair.getPrivate().getEncoded()); - } - File file = new File(String.format("%s/%s", certFolder, LOGSEARCH_KEYSTORE_PUBLIC_KEY)); - if (!file.exists()) { - FileUtils.writeByteArrayToFile(file, keyPair.getPublic().getEncoded()); - } - X509Certificate cert = SSLUtil.generateCertificate(certLocation, keyPair, certAlgorithm); - KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); - keyStore.load(null, password); - SSLUtil.setKeyAndCertInKeystore(cert, keyPair, keyStore, keyStoreLocation, password); - setPermissionOnCertFolder(certFolder); - } - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - private void createDefaultKeyFolder(String certFolder) { - File keyFolderDirectory = new File(certFolder); - if (!keyFolderDirectory.exists()) { - LOG.info("Default key dir does not exist ({}). Creating ...", certFolder); - boolean mkDirSuccess = keyFolderDirectory.mkdirs(); - if (!mkDirSuccess) { - String errorMessage = String.format("Could not create directory %s", certFolder); - LOG.error(errorMessage); - throw new RuntimeException(errorMessage); - } - } - } - - private void setPermissionOnCertFolder(String certFolder) { - Chmod chmod = new Chmod(); - chmod.setProject(new Project()); - FileSet fileSet = new FileSet(); - fileSet.setDir(new File(certFolder)); - fileSet.setIncludes("**"); - chmod.addFileset(fileSet); - chmod.setPerm("600"); - chmod.execute(); - } } http://git-wip-us.apache.org/repos/asf/ambari/blob/015d4046/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/util/FileUtil.java ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/util/FileUtil.java b/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/util/FileUtil.java index f7330fa..5d4efbc 100644 --- a/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/util/FileUtil.java +++ b/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/util/FileUtil.java @@ -23,6 +23,9 @@ import java.io.File; import java.net.URL; import org.apache.log4j.Logger; +import org.apache.tools.ant.Project; +import org.apache.tools.ant.taskdefs.Chmod; +import org.apache.tools.ant.types.FileSet; public class FileUtil { private static final Logger logger = Logger.getLogger(FileUtil.class); @@ -43,4 +46,27 @@ public class FileUtil { return file; } + public static void createDirectory(String dirPath) { + File dir = new File(dirPath); + if (!dir.exists()) { + logger.info("Directory " + dirPath + " does not exist. Creating ..."); + boolean mkDirSuccess = dir.mkdirs(); + if (!mkDirSuccess) { + String errorMessage = String.format("Could not create directory %s", dirPath); + logger.error(errorMessage); + throw new RuntimeException(errorMessage); + } + } + } + + public static void setPermissionOnDirectory(String dirPath, String permission) { + Chmod chmod = new Chmod(); + chmod.setProject(new Project()); + FileSet fileSet = new FileSet(); + fileSet.setDir(new File(dirPath)); + fileSet.setIncludes("**"); + chmod.addFileset(fileSet); + chmod.setPerm(permission); + chmod.execute(); + } } http://git-wip-us.apache.org/repos/asf/ambari/blob/015d4046/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/util/SSLUtil.java ---------------------------------------------------------------------- diff --git a/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/util/SSLUtil.java b/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/util/SSLUtil.java index e0111e7..ea3474f 100644 --- a/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/util/SSLUtil.java +++ b/ambari-logsearch/ambari-logsearch-portal/src/main/java/org/apache/ambari/logsearch/util/SSLUtil.java @@ -26,10 +26,20 @@ import org.apache.commons.io.FileUtils; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang3.ArrayUtils; import org.apache.hadoop.conf.Configuration; -import org.apache.hadoop.fs.Path; -import org.bouncycastle.jce.X509Principal; +import org.bouncycastle.asn1.x500.X500Name; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; import org.bouncycastle.jce.provider.BouncyCastleProvider; -import org.bouncycastle.x509.X509V3CertificateGenerator; +import org.bouncycastle.operator.ContentSigner; +import org.bouncycastle.operator.DefaultDigestAlgorithmIdentifierFinder; +import org.bouncycastle.operator.DefaultSignatureAlgorithmIdentifierFinder; +import org.bouncycastle.operator.OperatorCreationException; +import org.bouncycastle.operator.bc.BcContentSignerBuilder; +import org.bouncycastle.operator.bc.BcRSAContentSignerBuilder; +import org.bouncycastle.cert.X509CertificateHolder; +import org.bouncycastle.cert.X509v3CertificateBuilder; +import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; +import org.bouncycastle.crypto.params.RSAKeyParameters; import org.eclipse.jetty.util.ssl.SslContextFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -37,6 +47,7 @@ import org.slf4j.LoggerFactory; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; +import java.io.IOException; import java.math.BigInteger; import java.net.InetAddress; import java.security.InvalidKeyException; @@ -49,14 +60,13 @@ import java.security.SecureRandom; import java.security.Security; import java.security.SignatureException; import java.security.cert.Certificate; -import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; import java.util.Date; -import static org.apache.ambari.logsearch.LogSearch.LOGSEARCH_CERT_DEFAULT_FOLDER; -import static org.apache.ambari.logsearch.LogSearch.LOGSEARCH_KEYSTORE_DEFAULT_PASSWORD; - public class SSLUtil { private static final Logger LOG = LoggerFactory.getLogger(SSLUtil.class); @@ -74,6 +84,18 @@ public class SSLUtil { private static final String TRUSTSTORE_PASSWORD_FILE = "ts_pass.txt"; private static final String CREDENTIAL_STORE_PROVIDER_PATH = "hadoop.security.credential.provider.path"; + private static final String LOGSEARCH_CERT_FOLDER_LOCATION = "logsearch.cert.folder.location"; + private static final String LOGSEARCH_CERT_ALGORITHM = "logsearch.cert.algorithm"; + + private static final String LOGSEARCH_CERT_FILENAME = "logsearch.crt"; + private static final String LOGSEARCH_KEYSTORE_FILENAME = "logsearch.jks"; + private static final String LOGSEARCH_KEYSTORE_PRIVATE_KEY = "logsearch.private.key"; + private static final String LOGSEARCH_KEYSTORE_PUBLIC_KEY = "logsearch.public.key"; + private static final String LOGSEARCH_CERT_DEFAULT_ALGORITHM = "sha256WithRSA"; + + private static final String LOGSEARCH_CERT_DEFAULT_FOLDER = "/etc/ambari-logsearch-portal/conf/keys"; + private static final String LOGSEARCH_KEYSTORE_DEFAULT_PASSWORD = "bigdata"; + private SSLUtil() { throw new UnsupportedOperationException(); } @@ -111,8 +133,6 @@ public class SSLUtil { } public static SslContextFactory getSslContextFactory() { - setPasswordIfSysPropIsEmpty(KEYSTORE_PASSWORD_ARG, KEYSTORE_PASSWORD_PROPERTY_NAME, KEYSTORE_PASSWORD_FILE); - setPasswordIfSysPropIsEmpty(TRUSTSTORE_PASSWORD_ARG, TRUSTSTORE_PASSWORD_PROPERTY_NAME, TRUSTSTORE_PASSWORD_FILE); SslContextFactory sslContextFactory = new SslContextFactory(); sslContextFactory.setKeyStorePath(getKeyStoreLocation()); sslContextFactory.setKeyStorePassword(getKeyStorePassword()); @@ -171,7 +191,7 @@ public class SSLUtil { char[] passwordChars = config.getPassword(propertyName); return (ArrayUtils.isNotEmpty(passwordChars)) ? new String(passwordChars) : null; } catch (Exception e) { - LOG.warn(String.format("Could not load password %s from credential store, using default password", propertyName)); + LOG.warn(String.format("Could not load password %s from credential store, using default password", propertyName), e); return null; } } @@ -193,7 +213,7 @@ public class SSLUtil { /** * Put private key into in-memory keystore and write it to a file (JKS file) */ - public static void setKeyAndCertInKeystore(X509Certificate cert, KeyPair keyPair, KeyStore keyStore, String keyStoreLocation, char[] password) + private static void setKeyAndCertInKeystore(X509Certificate cert, KeyPair keyPair, KeyStore keyStore, String keyStoreLocation, char[] password) throws Exception { Certificate[] certChain = new Certificate[1]; certChain[0] = cert; @@ -201,7 +221,7 @@ public class SSLUtil { keyStore.setKeyEntry("logsearch.alias", keyPair.getPrivate(), password, certChain); keyStore.store(fos, password); } catch (Exception e) { - LOG.error("Could not write certificate to Keystore"); + LOG.error("Could not write certificate to Keystore", e); throw e; } } @@ -209,7 +229,7 @@ public class SSLUtil { /** * Create in-memory keypair with bouncy castle */ - public static KeyPair createKeyPair(String encryptionType, int byteCount) + private static KeyPair createKeyPair(String encryptionType, int byteCount) throws NoSuchProviderException, NoSuchAlgorithmException { Security.addProvider(new BouncyCastleProvider()); KeyPairGenerator keyPairGenerator = createKeyPairGenerator(encryptionType, byteCount); @@ -219,7 +239,7 @@ public class SSLUtil { /** * Generate X509 certificate if it does not exist */ - public static X509Certificate generateCertificate(String certificateLocation, KeyPair keyPair, String algorithm) throws Exception { + private static X509Certificate generateCertificate(String certificateLocation, KeyPair keyPair, String algorithm) throws Exception { try { File certFile = new File(certificateLocation); if (certFile.exists()) { @@ -227,44 +247,65 @@ public class SSLUtil { return getCertFile(certificateLocation); } else { Security.addProvider(new BouncyCastleProvider()); - X509Certificate cert = SSLUtil.createCert(keyPair, algorithm, InetAddress.getLocalHost().getCanonicalHostName()); + X509Certificate cert = createCert(keyPair, algorithm, InetAddress.getLocalHost().getCanonicalHostName()); FileUtils.writeByteArrayToFile(certFile, cert.getEncoded()); return cert; } } catch (Exception e) { - LOG.error("Could not create certificate."); + LOG.error("Could not create certificate.", e); throw e; } } - private static void setPasswordIfSysPropIsEmpty(String pwdArg, String propertyName, String fileName) { - if (StringUtils.isEmpty(System.getProperty(pwdArg))) { + private static void ensureStorePassword(String locationArg, String pwdArg, String propertyName, String fileName) { + if (StringUtils.isNotEmpty(System.getProperty(locationArg)) && StringUtils.isEmpty(System.getProperty(pwdArg))) { String password = getPassword(propertyName, fileName); System.setProperty(pwdArg, password); } } + + public static void ensureStorePasswords() { + ensureStorePassword(KEYSTORE_LOCATION_ARG, KEYSTORE_PASSWORD_ARG, KEYSTORE_PASSWORD_PROPERTY_NAME, KEYSTORE_PASSWORD_FILE); + ensureStorePassword(TRUSTSTORE_LOCATION_ARG, TRUSTSTORE_PASSWORD_ARG, TRUSTSTORE_PASSWORD_PROPERTY_NAME, TRUSTSTORE_PASSWORD_FILE); + } private static X509Certificate getCertFile(String location) throws Exception { try (FileInputStream fos = new FileInputStream(location)) { CertificateFactory factory = CertificateFactory.getInstance("X.509"); return (X509Certificate) factory.generateCertificate(fos); } catch (Exception e) { - LOG.error("Cannot read cert file. ('{}')", location); + LOG.error("Cannot read cert file. ('" + location + "')", e); throw e; } } private static X509Certificate createCert(KeyPair keyPair, String signatureAlgoritm, String domainName) - throws CertificateEncodingException, NoSuchAlgorithmException, InvalidKeyException, SignatureException { - X509V3CertificateGenerator v3CertGen = new X509V3CertificateGenerator(); - v3CertGen.setSerialNumber(BigInteger.valueOf(Math.abs(new SecureRandom().nextInt()))); - v3CertGen.setIssuerDN(new X509Principal("CN=" + domainName + ", OU=None, O=None L=None, C=None")); - v3CertGen.setNotBefore(new Date(System.currentTimeMillis() - 1000L * 60 * 60 * 24 * 30)); - v3CertGen.setNotAfter(new Date(System.currentTimeMillis() + (1000L * 60 * 60 * 24 * 365*10))); - v3CertGen.setSubjectDN(new X509Principal("CN=" + domainName + ", OU=None, O=None L=None, C=None")); - v3CertGen.setPublicKey(keyPair.getPublic()); - v3CertGen.setSignatureAlgorithm(signatureAlgoritm); - return v3CertGen.generate(keyPair.getPrivate()); + throws NoSuchAlgorithmException, InvalidKeyException, SignatureException, OperatorCreationException, CertificateException, IOException { + + RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic(); + RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate(); + + AlgorithmIdentifier sigAlgId = new DefaultSignatureAlgorithmIdentifierFinder().find(signatureAlgoritm); + AlgorithmIdentifier digAlgId = new DefaultDigestAlgorithmIdentifierFinder().find(sigAlgId); + BcContentSignerBuilder sigGen = new BcRSAContentSignerBuilder(sigAlgId, digAlgId); + + SubjectPublicKeyInfo pubKey = new SubjectPublicKeyInfo(sigAlgId, rsaPublicKey.getEncoded()); + + X509v3CertificateBuilder v3CertBuilder = new X509v3CertificateBuilder( + new X500Name("CN=" + domainName + ", OU=None, O=None L=None, C=None"), + BigInteger.valueOf(Math.abs(new SecureRandom().nextInt())), + new Date(System.currentTimeMillis() - 1000L * 60 * 60 * 24 * 30), + new Date(System.currentTimeMillis() + (1000L * 60 * 60 * 24 * 365*10)), + new X500Name("CN=" + domainName + ", OU=None, O=None L=None, C=None"), + pubKey); + + RSAKeyParameters keyParams = new RSAKeyParameters(true, rsaPrivateKey.getPrivateExponent(), rsaPrivateKey.getModulus()); + ContentSigner contentSigner = sigGen.build(keyParams); + + X509CertificateHolder certificateHolder = v3CertBuilder.build(contentSigner); + + JcaX509CertificateConverter certConverter = new JcaX509CertificateConverter(); + return certConverter.getCertificate(certificateHolder); } private static KeyPairGenerator createKeyPairGenerator(String algorithmIdentifier, int bitCount) @@ -274,4 +315,46 @@ public class SSLUtil { return kpg; } + /** + * Create keystore with keys and certificate (only if the keystore does not exist or if you have no permissions on the keystore file) + */ + public static void loadKeystore() { + try { + String certFolder = PropertiesHelper.getProperty(LOGSEARCH_CERT_FOLDER_LOCATION, LOGSEARCH_CERT_DEFAULT_FOLDER); + String certAlgorithm = PropertiesHelper.getProperty(LOGSEARCH_CERT_ALGORITHM, LOGSEARCH_CERT_DEFAULT_ALGORITHM); + String certLocation = String.format("%s/%s", LOGSEARCH_CERT_DEFAULT_FOLDER, LOGSEARCH_CERT_FILENAME); + String keyStoreLocation = StringUtils.isNotEmpty(getKeyStoreLocation()) ? getKeyStoreLocation() + : String.format("%s/%s", LOGSEARCH_CERT_DEFAULT_FOLDER, LOGSEARCH_KEYSTORE_FILENAME); + char[] password = StringUtils.isNotEmpty(getKeyStorePassword()) ? + getKeyStorePassword().toCharArray() : LOGSEARCH_KEYSTORE_DEFAULT_PASSWORD.toCharArray(); + boolean keyStoreFileExists = new File(keyStoreLocation).exists(); + if (!keyStoreFileExists) { + FileUtil.createDirectory(certFolder); + LOG.warn("Keystore file ('{}') does not exist, creating new one. " + + "If the file exists, make sure you have proper permissions on that.", keyStoreLocation); + if (isKeyStoreSpecified() && !"JKS".equalsIgnoreCase(getKeyStoreType())) { + throw new RuntimeException(String.format("Keystore does not exist. Only JKS keystore can be auto generated. (%s)", keyStoreLocation)); + } + LOG.info("SSL keystore is not specified. Generating it with certificate ... (using default format: JKS)"); + Security.addProvider(new BouncyCastleProvider()); + KeyPair keyPair = createKeyPair("RSA", 2048); + File privateKeyFile = new File(String.format("%s/%s", certFolder, LOGSEARCH_KEYSTORE_PRIVATE_KEY)); + if (!privateKeyFile.exists()) { + FileUtils.writeByteArrayToFile(privateKeyFile, keyPair.getPrivate().getEncoded()); + } + File file = new File(String.format("%s/%s", certFolder, LOGSEARCH_KEYSTORE_PUBLIC_KEY)); + if (!file.exists()) { + FileUtils.writeByteArrayToFile(file, keyPair.getPublic().getEncoded()); + } + X509Certificate cert = generateCertificate(certLocation, keyPair, certAlgorithm); + KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); + keyStore.load(null, password); + setKeyAndCertInKeystore(cert, keyPair, keyStore, keyStoreLocation, password); + FileUtil.setPermissionOnDirectory(certFolder, "600"); + } + } catch (Exception e) { + throw new RuntimeException(e); + } + } + }