/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt * or http://forgerock.org/license/CDDLv1.0.html. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at legal-notices/CDDLv1_0.txt. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Copyright 2008-2010 Sun Microsystems, Inc. * Portions Copyright 2011-2015 ForgeRock AS */ package org.opends.server.util.cli; import static com.forgerock.opendj.cli.Utils.isDN; import static com.forgerock.opendj.cli.Utils.getAdministratorDN; import static com.forgerock.opendj.cli.Utils.getThrowableMsg; import static com.forgerock.opendj.cli.CliMessages.*; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.net.InetAddress; import java.net.URI; import java.net.UnknownHostException; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.cert.X509Certificate; import java.util.Enumeration; import java.util.LinkedHashMap; import javax.net.ssl.KeyManager; import org.forgerock.i18n.LocalizableMessage; import org.forgerock.i18n.slf4j.LocalizedLogger; import org.opends.admin.ads.util.ApplicationKeyManager; import org.opends.admin.ads.util.ApplicationTrustManager; import org.opends.server.admin.client.cli.SecureConnectionCliArgs; import org.opends.server.tools.LDAPConnectionOptions; import org.opends.server.tools.SSLConnectionException; import org.opends.server.tools.SSLConnectionFactory; import org.opends.server.util.CollectionUtils; import org.opends.server.util.SelectableCertificateKeyManager; import com.forgerock.opendj.cli.ArgumentException; import com.forgerock.opendj.cli.ClientException; import com.forgerock.opendj.cli.CommandBuilder; import com.forgerock.opendj.cli.ConsoleApplication; import com.forgerock.opendj.cli.Menu; import com.forgerock.opendj.cli.MenuBuilder; import com.forgerock.opendj.cli.MenuResult; import com.forgerock.opendj.cli.ValidationCallback; /** * Supports interacting with a user through the command line to prompt for * information necessary to create an LDAP connection. * * Actually the LDAPConnectionConsoleInteraction is used by UninstallCliHelper, StatusCli, * LDAPManagementContextFactory and ReplicationCliMain. */ public class LDAPConnectionConsoleInteraction { /** * Information from the latest console interaction. * TODO: should it extend MonoServerReplicationUserData or a subclass? */ private static class State { private boolean useSSL; private boolean useStartTLS; private String hostName; private String bindDN; private String providedBindDN; private String adminUID; private String providedAdminUID; private String bindPassword; /** The timeout to be used to connect. */ private int connectTimeout; /** Indicate if we need to display the heading. */ private boolean isHeadingDisplayed; private ApplicationTrustManager trustManager; /** Indicate if the trust store in in memory. */ private boolean trustStoreInMemory; /** Indicate if the all certificates are accepted. */ private boolean trustAll; /** Indicate that the trust manager was created with the parameters provided. */ private boolean trustManagerInitialized; /** The trust store to use for the SSL or STARTTLS connection. */ private KeyStore truststore; private String truststorePath; private String truststorePassword; private KeyManager keyManager; private String keystorePath; private String keystorePassword; private String certifNickname; private State(SecureConnectionCliArgs secureArgs) { useSSL = secureArgs.useSSL(); useStartTLS = secureArgs.useStartTLS(); trustAll = secureArgs.trustAllArg.isPresent(); } /** * @return */ protected LocalizableMessage getPrompt() { LocalizableMessage prompt; if (providedAdminUID != null) { prompt = INFO_LDAPAUTH_PASSWORD_PROMPT.get(providedAdminUID); } else if (providedBindDN != null) { prompt = INFO_LDAPAUTH_PASSWORD_PROMPT.get(providedBindDN); } else if (bindDN != null) { prompt = INFO_LDAPAUTH_PASSWORD_PROMPT.get(bindDN); } else { prompt = INFO_LDAPAUTH_PASSWORD_PROMPT.get(adminUID); } return prompt; } /** * @return */ protected String getAdminOrBindDN() { String dn; if (providedBindDN != null) { dn = providedBindDN; } else if (providedAdminUID != null) { dn = getAdministratorDN(providedAdminUID); } else if (bindDN != null) { dn = bindDN; } else if (adminUID != null) { dn = getAdministratorDN(adminUID); } else { dn = null; } return dn; } } /** The console application. */ private ConsoleApplication app; private State state; /** The SecureConnectionCliArgsList object. */ private SecureConnectionCliArgs secureArgsList; /** The command builder that we can return with the connection information. */ private CommandBuilder commandBuilder; /** A copy of the secureArgList for convenience. */ private SecureConnectionCliArgs copySecureArgsList; /** * Boolean that tells if we must propose LDAP if it is available even if the * user provided certificate parameters. */ private boolean displayLdapIfSecureParameters; private int portNumber; private LocalizableMessage heading = INFO_LDAP_CONN_HEADING_CONNECTION_PARAMETERS.get(); /** Boolean that tells if we ask for bind DN or admin UID in the same prompt. */ private boolean useAdminOrBindDn; /** Enumeration description protocols for interactive CLI choices. */ private enum Protocols { LDAP(1, INFO_LDAP_CONN_PROMPT_SECURITY_LDAP.get()), SSL(2, INFO_LDAP_CONN_PROMPT_SECURITY_USE_SSL.get()), START_TLS(3, INFO_LDAP_CONN_PROMPT_SECURITY_USE_START_TLS.get()); private Integer choice; private LocalizableMessage msg; /** * Private constructor. * * @param i * the menu return value. * @param msg * the message message. */ private Protocols(int i, LocalizableMessage msg) { choice = i; this.msg = msg; } /** * Returns the choice number. * * @return the attribute name. */ public Integer getChoice() { return choice; } /** * Return the menu message. * * @return the menu message. */ public LocalizableMessage getMenuMessage() { return msg; } } /** * Enumeration description protocols for interactive CLI choices. */ private enum TrustMethod { TRUSTALL(1, INFO_LDAP_CONN_PROMPT_SECURITY_USE_TRUST_ALL.get()), TRUSTSTORE(2, INFO_LDAP_CONN_PROMPT_SECURITY_TRUSTSTORE.get()), DISPLAY_CERTIFICATE(3, INFO_LDAP_CONN_PROMPT_SECURITY_MANUAL_CHECK.get()); private Integer choice; private LocalizableMessage msg; /** * Private constructor. * * @param i * the menu return value. * @param msg * the message message. */ private TrustMethod(int i, LocalizableMessage msg) { choice = Integer.valueOf(i); this.msg = msg; } /** * Returns the choice number. * * @return the attribute name. */ public Integer getChoice() { return choice; } /** * Return the menu message. * * @return the menu message. */ public LocalizableMessage getMenuMessage() { return msg; } } /** * Enumeration description server certificate trust option. */ private enum TrustOption { UNTRUSTED(1, INFO_LDAP_CONN_PROMPT_SECURITY_TRUST_OPTION_NO.get()), SESSION(2, INFO_LDAP_CONN_PROMPT_SECURITY_TRUST_OPTION_SESSION.get()), PERMAMENT(3, INFO_LDAP_CONN_PROMPT_SECURITY_TRUST_OPTION_ALWAYS.get()), CERTIFICATE_DETAILS(4, INFO_LDAP_CONN_PROMPT_SECURITY_CERTIFICATE_DETAILS.get()); private Integer choice; private LocalizableMessage msg; /** * Private constructor. * * @param i * the menu return value. * @param msg * the message message. */ private TrustOption(int i, LocalizableMessage msg) { choice = Integer.valueOf(i); this.msg = msg; } /** * Returns the choice number. * * @return the attribute name. */ public Integer getChoice() { return choice; } /** * Return the menu message. * * @return the menu message. */ public LocalizableMessage getMenuMessage() { return msg; } } /** * Constructs a parameterized instance. * * @param app * console application * @param secureArgs * existing set of arguments that have already been parsed and * contain some potential command line specified LDAP arguments */ public LDAPConnectionConsoleInteraction(ConsoleApplication app, SecureConnectionCliArgs secureArgs) { this.app = app; this.secureArgsList = secureArgs; this.commandBuilder = new CommandBuilder(null, null); state = new State(secureArgs); copySecureArgsList = new SecureConnectionCliArgs(secureArgs.alwaysSSL()); try { copySecureArgsList.createGlobalArguments(); } catch (Throwable t) { // This is a bug: we should always be able to create the global arguments // no need to localize this one. throw new RuntimeException("Unexpected error: " + t, t); } } /** * Interact with the user though the console to get information necessary to * establish an LDAP connection. * * @throws ArgumentException * if there is a problem with the arguments */ public void run() throws ArgumentException { run(true); } /** * Interact with the user though the console to get information necessary to * establish an LDAP connection. * * @param canUseStartTLS * whether we can propose to connect using Start TLS or not. * @throws ArgumentException * if there is a problem with the arguments */ public void run(boolean canUseStartTLS) throws ArgumentException { // Reset everything commandBuilder.clearArguments(); copySecureArgsList.createGlobalArguments(); boolean secureConnection = true; // Get the LDAP host. state.hostName = secureArgsList.hostNameArg.getValue(); final String tmpHostName = state.hostName; if (app.isInteractive() && !secureArgsList.hostNameArg.isPresent()) { checkHeadingDisplayed(); ValidationCallback<String> callback = new ValidationCallback<String>() { @Override public String validate(ConsoleApplication app, String input) throws ClientException { String ninput = input.trim(); if (ninput.length() == 0) { return tmpHostName; } else { try { InetAddress.getByName(ninput); return ninput; } catch (UnknownHostException e) { // Try again... app.println(); app.println(ERR_LDAP_CONN_BAD_HOST_NAME.get(ninput)); app.println(); return null; } } } }; try { app.println(); state.hostName = app.readValidatedInput(INFO_LDAP_CONN_PROMPT_HOST_NAME.get(state.hostName), callback); } catch (ClientException e) { throw cannotReadConnectionParameters(e); } } copySecureArgsList.hostNameArg.clearValues(); copySecureArgsList.hostNameArg.addValue(state.hostName); commandBuilder.addArgument(copySecureArgsList.hostNameArg); // Connection type state.useSSL = secureArgsList.useSSL(); state.useStartTLS = secureArgsList.useStartTLS(); boolean connectionTypeIsSet = secureArgsList.alwaysSSL() || secureArgsList.useSSLArg.isPresent() || secureArgsList.useStartTLSArg.isPresent() || (secureArgsList.useSSLArg.isValueSetByProperty() && secureArgsList.useStartTLSArg .isValueSetByProperty()); if (app.isInteractive() && !connectionTypeIsSet) { checkHeadingDisplayed(); MenuBuilder<Integer> builder = new MenuBuilder<>(app); builder.setPrompt(INFO_LDAP_CONN_PROMPT_SECURITY_USE_SECURE_CTX.get()); Protocols defaultProtocol; if (secureConnection) { defaultProtocol = Protocols.SSL; } else { defaultProtocol = Protocols.LDAP; } for (Protocols p : Protocols.values()) { if (secureConnection && p.equals(Protocols.LDAP) && !displayLdapIfSecureParameters) { continue; } if (!canUseStartTLS && p.equals(Protocols.START_TLS)) { continue; } int i = builder.addNumberedOption(p.getMenuMessage(), MenuResult.success(p .getChoice())); if (p.equals(defaultProtocol)) { builder.setDefault( INFO_LDAP_CONN_PROMPT_SECURITY_PROTOCOL_DEFAULT_CHOICE.get(i), MenuResult.success(p.getChoice())); } } Menu<Integer> menu = builder.toMenu(); try { MenuResult<Integer> result = menu.run(); if (result.isSuccess()) { if (result.getValue().equals(Protocols.SSL.getChoice())) { state.useSSL = true; } else if (result.getValue().equals(Protocols.START_TLS.getChoice())) { state.useStartTLS = true; } } else { // Should never happen. throw new RuntimeException(); } } catch (ClientException e) { throw new RuntimeException(e); } } if (state.useSSL) { commandBuilder.addArgument(copySecureArgsList.useSSLArg); } else if (state.useStartTLS) { commandBuilder.addArgument(copySecureArgsList.useStartTLSArg); } // Get the LDAP port. if (!state.useSSL) { portNumber = secureArgsList.portArg.getIntValue(); } else { if (secureArgsList.portArg.isPresent()) { portNumber = secureArgsList.portArg.getIntValue(); } else { portNumber = secureArgsList.getPortFromConfig(); } } final int tmpPortNumber = portNumber; if (app.isInteractive() && !secureArgsList.portArg.isPresent()) { checkHeadingDisplayed(); ValidationCallback<Integer> callback = new ValidationCallback<Integer>() { @Override public Integer validate(ConsoleApplication app, String input) throws ClientException { String ninput = input.trim(); if (ninput.length() == 0) { return tmpPortNumber; } else { try { int i = Integer.parseInt(ninput); if (i < 1 || i > 65535) { throw new NumberFormatException(); } return i; } catch (NumberFormatException e) { // Try again... app.println(); app.println(ERR_LDAP_CONN_BAD_PORT_NUMBER.get(ninput)); app.println(); return null; } } } }; try { app.println(); LocalizableMessage askPortNumber = null; if (secureArgsList.alwaysSSL()) { askPortNumber = INFO_ADMIN_CONN_PROMPT_PORT_NUMBER.get(portNumber); } else { askPortNumber = INFO_LDAP_CONN_PROMPT_PORT_NUMBER.get(portNumber); } portNumber = app.readValidatedInput(askPortNumber, callback); } catch (ClientException e) { throw cannotReadConnectionParameters(e); } } copySecureArgsList.portArg.clearValues(); copySecureArgsList.portArg.addValue(String.valueOf(portNumber)); commandBuilder.addArgument(copySecureArgsList.portArg); // Handle certificate if ((state.useSSL || state.useStartTLS) && state.trustManager == null) { initializeTrustManager(); } // Get the LDAP bind credentials. state.bindDN = secureArgsList.bindDnArg.getValue(); state.adminUID= secureArgsList.adminUidArg.getValue(); final boolean useAdmin = secureArgsList.useAdminUID(); if (useAdmin && secureArgsList.adminUidArg.isPresent()) { state.providedAdminUID = state.adminUID; } else { state.providedAdminUID = null; } if ((!useAdmin || useAdminOrBindDn) && secureArgsList.bindDnArg.isPresent()) { state.providedBindDN = state.bindDN; } else { state.providedBindDN = null; } boolean argIsPresent = state.providedAdminUID != null || state.providedBindDN != null; final String tmpBindDN = state.bindDN; final String tmpAdminUID = state.adminUID; if (state.keyManager == null) { if (app.isInteractive() && !argIsPresent) { checkHeadingDisplayed(); ValidationCallback<String> callback = new ValidationCallback<String>() { @Override public String validate(ConsoleApplication app, String input) throws ClientException { String ninput = input.trim(); if (ninput.length() == 0) { if (useAdmin) { return tmpAdminUID; } else { return tmpBindDN; } } else { return ninput; } } }; try { app.println(); if (useAdminOrBindDn) { String def = state.adminUID != null ? state.adminUID : state.bindDN; String v = app.readValidatedInput( INFO_LDAP_CONN_GLOBAL_ADMINISTRATOR_OR_BINDDN_PROMPT.get(def), callback); if (isDN(v)) { state.bindDN = v; state.providedBindDN = v; state.adminUID = null; state.providedAdminUID = null; } else { state.bindDN = null; state.providedBindDN = null; state.adminUID = v; state.providedAdminUID = v; } } else if (useAdmin) { state.adminUID = app.readValidatedInput(INFO_LDAP_CONN_PROMPT_ADMINISTRATOR_UID.get(state.adminUID), callback); state.providedAdminUID = state.adminUID; } else { state.bindDN = app.readValidatedInput(INFO_LDAP_CONN_PROMPT_BIND_DN.get(state.bindDN), callback); state.providedBindDN = state.bindDN; } } catch (ClientException e) { throw cannotReadConnectionParameters(e); } } if (useAdminOrBindDn) { boolean addAdmin = state.providedAdminUID != null; boolean addBindDN = state.providedBindDN != null; if (!addAdmin && !addBindDN) { addAdmin = getAdministratorUID() != null; addBindDN = getBindDN() != null; } if (addAdmin) { copySecureArgsList.adminUidArg.clearValues(); copySecureArgsList.adminUidArg.addValue(getAdministratorUID()); commandBuilder.addArgument(copySecureArgsList.adminUidArg); } else if (addBindDN) { copySecureArgsList.bindDnArg.clearValues(); copySecureArgsList.bindDnArg.addValue(getBindDN()); commandBuilder.addArgument(copySecureArgsList.bindDnArg); } } else if (useAdmin) { copySecureArgsList.adminUidArg.clearValues(); copySecureArgsList.adminUidArg.addValue(getAdministratorUID()); commandBuilder.addArgument(copySecureArgsList.adminUidArg); } else { copySecureArgsList.bindDnArg.clearValues(); copySecureArgsList.bindDnArg.addValue(getBindDN()); commandBuilder.addArgument(copySecureArgsList.bindDnArg); } } else { state.bindDN = null; state.adminUID = null; } boolean addedPasswordFileArgument = false; if (secureArgsList.bindPasswordArg.isPresent()) { state.bindPassword = secureArgsList.bindPasswordArg.getValue(); } if (state.keyManager == null) { if (secureArgsList.bindPasswordFileArg.isPresent()) { // Read from file if it exists. state.bindPassword = secureArgsList.bindPasswordFileArg.getValue(); if (state.bindPassword == null) { if (useAdmin) { throw new ArgumentException(ERR_ERROR_NO_ADMIN_PASSWORD.get(state.adminUID)); } else { throw new ArgumentException(ERR_ERROR_NO_ADMIN_PASSWORD.get(state.bindDN)); } } copySecureArgsList.bindPasswordFileArg.clearValues(); copySecureArgsList.bindPasswordFileArg.getNameToValueMap().putAll( secureArgsList.bindPasswordFileArg.getNameToValueMap()); commandBuilder.addArgument(copySecureArgsList.bindPasswordFileArg); addedPasswordFileArgument = true; } else if (state.bindPassword == null || "-".equals(state.bindPassword)) { // Read the password from the stdin. if (!app.isInteractive()) { throw new ArgumentException(ERR_ERROR_BIND_PASSWORD_NONINTERACTIVE.get()); } checkHeadingDisplayed(); try { app.println(); state.bindPassword = readPassword(state.getPrompt()); } catch (Exception e) { throw new ArgumentException(ERR_ERROR_CANNOT_READ_CONNECTION_PARAMETERS.get(e.getMessage()), e.getCause()); } } copySecureArgsList.bindPasswordArg.clearValues(); copySecureArgsList.bindPasswordArg.addValue(state.bindPassword); if (!addedPasswordFileArgument) { commandBuilder.addObfuscatedArgument(copySecureArgsList.bindPasswordArg); } } state.connectTimeout = secureArgsList.connectTimeoutArg.getIntValue(); } private ArgumentException cannotReadConnectionParameters(ClientException e) { return new ArgumentException(ERR_ERROR_CANNOT_READ_CONNECTION_PARAMETERS.get(e.getMessage()), e.getCause()); } private String readPassword(LocalizableMessage prompt) throws ClientException { final char[] pwd = app.readPassword(prompt); if (pwd != null) { return String.valueOf(pwd); } return null; } /** * Get the trust manager. * * @return The trust manager based on CLI args on interactive prompt. * @throws ArgumentException * If an error occurs when getting args values. */ private ApplicationTrustManager getTrustManagerInternal() throws ArgumentException { // Remove these arguments since this method might be called several times. commandBuilder.removeArgument(copySecureArgsList.trustAllArg); commandBuilder.removeArgument(copySecureArgsList.trustStorePathArg); commandBuilder.removeArgument(copySecureArgsList.trustStorePasswordArg); commandBuilder.removeArgument(copySecureArgsList.trustStorePasswordFileArg); // If we have the trustALL flag, don't do anything // just return null if (secureArgsList.trustAllArg.isPresent()) { commandBuilder.addArgument(copySecureArgsList.trustAllArg); return null; } // Check if some trust manager info are set boolean weDontKnowTheTrustMethod = !secureArgsList.trustAllArg.isPresent() && !secureArgsList.trustStorePathArg.isPresent() && !secureArgsList.trustStorePasswordArg.isPresent() && !secureArgsList.trustStorePasswordFileArg.isPresent(); boolean askForTrustStore = false; state.trustAll = secureArgsList.trustAllArg.isPresent(); // Try to use the local instance trust store, to avoid certificate // validation when both the CLI and the server are in the same instance. if (weDontKnowTheTrustMethod && addLocalTrustStore()) { weDontKnowTheTrustMethod = false; } if (app.isInteractive() && weDontKnowTheTrustMethod) { checkHeadingDisplayed(); app.println(); MenuBuilder<Integer> builder = new MenuBuilder<>(app); builder.setPrompt(INFO_LDAP_CONN_PROMPT_SECURITY_TRUST_METHOD.get()); TrustMethod defaultTrustMethod = TrustMethod.DISPLAY_CERTIFICATE; for (TrustMethod t : TrustMethod.values()) { int i = builder.addNumberedOption(t.getMenuMessage(), MenuResult.success(t .getChoice())); if (t.equals(defaultTrustMethod)) { builder.setDefault( INFO_LDAP_CONN_PROMPT_SECURITY_PROTOCOL_DEFAULT_CHOICE .get(Integer.valueOf(i)), MenuResult.success(t.getChoice())); } } Menu<Integer> menu = builder.toMenu(); state.trustStoreInMemory = false; try { MenuResult<Integer> result = menu.run(); if (result.isSuccess()) { if (result.getValue().equals(TrustMethod.TRUSTALL.getChoice())) { commandBuilder.addArgument(copySecureArgsList.trustAllArg); state.trustAll = true; // If we have the trustALL flag, don't do anything // just return null return null; } else if (result.getValue().equals(TrustMethod.TRUSTSTORE.getChoice())) { // We have to ask for trust store info askForTrustStore = true; } else if (result.getValue().equals( TrustMethod.DISPLAY_CERTIFICATE.getChoice())) { // The certificate will be displayed to the user askForTrustStore = false; state.trustStoreInMemory = true; // There is no direct equivalent for this option, so propose the // trust all option as command-line argument. commandBuilder.addArgument(copySecureArgsList.trustAllArg); } else { // Should never happen. throw new RuntimeException(); } } else { // Should never happen. throw new RuntimeException(); } } catch (ClientException e) { throw new RuntimeException(e); } } // If we do not trust all server certificates, we have to get info // about trust store. First get the trust store path. state.truststorePath = secureArgsList.trustStorePathArg.getValue(); if (app.isInteractive() && !secureArgsList.trustStorePathArg.isPresent() && askForTrustStore) { checkHeadingDisplayed(); ValidationCallback<String> callback = new ValidationCallback<String>() { @Override public String validate(ConsoleApplication app, String input) throws ClientException { String ninput = input.trim(); if (ninput.length() == 0) { app.println(); app.println(ERR_LDAP_CONN_PROMPT_SECURITY_INVALID_FILE_PATH.get()); app.println(); return null; } File f = new File(ninput); if (f.exists() && f.canRead() && !f.isDirectory()) { return ninput; } else { app.println(); app.println(ERR_LDAP_CONN_PROMPT_SECURITY_INVALID_FILE_PATH.get()); app.println(); return null; } } }; try { app.println(); state.truststorePath = app.readValidatedInput( INFO_LDAP_CONN_PROMPT_SECURITY_TRUSTSTORE_PATH.get(), callback); } catch (ClientException e) { throw cannotReadConnectionParameters(e); } } if (state.truststorePath != null) { copySecureArgsList.trustStorePathArg.clearValues(); copySecureArgsList.trustStorePathArg.addValue(state.truststorePath); commandBuilder.addArgument(copySecureArgsList.trustStorePathArg); } // Then the truststore password. // As the most common case is to have no password for truststore, // we don't ask it in the interactive mode. if (secureArgsList.trustStorePasswordArg.isPresent()) { state.truststorePassword = secureArgsList.trustStorePasswordArg.getValue(); } if (secureArgsList.trustStorePasswordFileArg.isPresent()) { // Read from file if it exists. state.truststorePassword = secureArgsList.trustStorePasswordFileArg.getValue(); } if ("-".equals(state.truststorePassword)) { // Read the password from the stdin. if (!app.isInteractive()) { state.truststorePassword = null; } else { checkHeadingDisplayed(); try { app.println(); LocalizableMessage prompt = INFO_LDAP_CONN_PROMPT_SECURITY_TRUSTSTORE_PASSWORD.get(state.truststorePath); state.truststorePassword = readPassword(prompt); } catch (Exception e) { throw new ArgumentException(ERR_ERROR_CANNOT_READ_CONNECTION_PARAMETERS.get(e.getMessage()), e.getCause()); } } } // We've got all the information to get the truststore manager try { state.truststore = KeyStore.getInstance(KeyStore.getDefaultType()); if (state.truststorePath != null) { try (FileInputStream fos = new FileInputStream(state.truststorePath)) { if (state.truststorePassword != null) { state.truststore.load(fos, state.truststorePassword.toCharArray()); } else { state.truststore.load(fos, null); } } } else { state.truststore.load(null, null); } if (secureArgsList.trustStorePasswordFileArg.isPresent() && state.truststorePath != null) { copySecureArgsList.trustStorePasswordFileArg.clearValues(); copySecureArgsList.trustStorePasswordFileArg.getNameToValueMap() .putAll(secureArgsList.trustStorePasswordFileArg.getNameToValueMap()); commandBuilder.addArgument(copySecureArgsList.trustStorePasswordFileArg); } else if (state.truststorePassword != null && state.truststorePath != null) { // Only add the trust store password if there is one AND if the user // specified a trust store path. copySecureArgsList.trustStorePasswordArg.clearValues(); copySecureArgsList.trustStorePasswordArg.addValue(state.truststorePassword); commandBuilder.addObfuscatedArgument(copySecureArgsList.trustStorePasswordArg); } return new ApplicationTrustManager(state.truststore); } catch (Exception e) { throw new ArgumentException(ERR_ERROR_CANNOT_READ_CONNECTION_PARAMETERS.get(e.getMessage()), e.getCause()); } } /** * Get the key manager. * * @return The key manager based on CLI args on interactive prompt. * @throws ArgumentException * If an error occurs when getting args values. */ private KeyManager getKeyManagerInternal() throws ArgumentException { // Remove these arguments since this method might be called several times. commandBuilder.removeArgument(copySecureArgsList.certNicknameArg); commandBuilder.removeArgument(copySecureArgsList.keyStorePathArg); commandBuilder.removeArgument(copySecureArgsList.keyStorePasswordArg); commandBuilder.removeArgument(copySecureArgsList.keyStorePasswordFileArg); // Do we need client side authentication ? // If one of the client side authentication args is set, we assume // that we // need client side authentication. boolean weDontKnowIfWeNeedKeystore = !secureArgsList.keyStorePathArg.isPresent() && !secureArgsList.keyStorePasswordArg.isPresent() && !secureArgsList.keyStorePasswordFileArg.isPresent() && !secureArgsList.certNicknameArg.isPresent(); // We don't have specific key manager parameter. // We assume that no client side authentication is required // Client side authentication is not the common use case. As a // consequence, interactive mode doesn't add an extra question // which will be in most cases useless. if (weDontKnowIfWeNeedKeystore) { return null; } // Get info about keystore. First get the keystore path. state.keystorePath = secureArgsList.keyStorePathArg.getValue(); if (app.isInteractive() && !secureArgsList.keyStorePathArg.isPresent()) { checkHeadingDisplayed(); ValidationCallback<String> callback = new ValidationCallback<String>() { @Override public String validate(ConsoleApplication app, String input) throws ClientException { String ninput = input.trim(); if (ninput.length() == 0) { return ninput; } File f = new File(ninput); if (f.exists() && f.canRead() && !f.isDirectory()) { return ninput; } else { app.println(); app.println(ERR_LDAP_CONN_PROMPT_SECURITY_INVALID_FILE_PATH.get()); app.println(); return null; } } }; try { app.println(); state.keystorePath = app.readValidatedInput(INFO_LDAP_CONN_PROMPT_SECURITY_KEYSTORE_PATH.get(), callback); } catch (ClientException e) { throw cannotReadConnectionParameters(e); } } if (state.keystorePath != null) { copySecureArgsList.keyStorePathArg.clearValues(); copySecureArgsList.keyStorePathArg.addValue(state.keystorePath); commandBuilder.addArgument(copySecureArgsList.keyStorePathArg); } else { // KeystorePath is null. Either it's unspecified or there's a pb // We should throw an exception here, anyway since code below will // anyway throw new ArgumentException(ERR_ERROR_INCOMPATIBLE_PROPERTY_MOD.get("null keystorePath")); } // Then the keystore password. state.keystorePassword = secureArgsList.keyStorePasswordArg.getValue(); if (secureArgsList.keyStorePasswordFileArg.isPresent()) { // Read from file if it exists. state.keystorePassword = secureArgsList.keyStorePasswordFileArg.getValue(); if (state.keystorePassword == null) { throw new ArgumentException(ERR_ERROR_NO_ADMIN_PASSWORD.get(state.keystorePassword)); } } else if (state.keystorePassword == null || "-".equals(state.keystorePassword)) { // Read the password from the stdin. if (!app.isInteractive()) { throw new ArgumentException(ERR_ERROR_BIND_PASSWORD_NONINTERACTIVE.get()); } checkHeadingDisplayed(); try { app.println(); LocalizableMessage prompt = INFO_LDAP_CONN_PROMPT_SECURITY_KEYSTORE_PASSWORD.get(state.keystorePath); state.keystorePassword = readPassword(prompt); } catch (Exception e) { throw new ArgumentException(ERR_ERROR_CANNOT_READ_CONNECTION_PARAMETERS.get(e.getMessage()), e.getCause()); } } // finally the certificate name, if needed. KeyStore keystore = null; Enumeration<String> aliasesEnum = null; try (FileInputStream fos = new FileInputStream(state.keystorePath)) { keystore = KeyStore.getInstance(KeyStore.getDefaultType()); keystore.load(fos, state.keystorePassword.toCharArray()); aliasesEnum = keystore.aliases(); } catch (Exception e) { throw new ArgumentException(ERR_ERROR_CANNOT_READ_CONNECTION_PARAMETERS.get(e.getMessage()), e.getCause()); } state.certifNickname = secureArgsList.certNicknameArg.getValue(); if (app.isInteractive() && !secureArgsList.certNicknameArg.isPresent() && aliasesEnum.hasMoreElements()) { checkHeadingDisplayed(); try { MenuBuilder<String> builder = new MenuBuilder<>(app); builder.setPrompt(INFO_LDAP_CONN_PROMPT_SECURITY_CERTIFICATE_ALIASES.get()); int certificateNumber = 0; for (; aliasesEnum.hasMoreElements();) { String alias = aliasesEnum.nextElement(); if (keystore.isKeyEntry(alias)) { X509Certificate certif = (X509Certificate) keystore.getCertificate(alias); certificateNumber++; builder.addNumberedOption( INFO_LDAP_CONN_PROMPT_SECURITY_CERTIFICATE_ALIAS.get(alias, certif.getSubjectDN().getName()), MenuResult.success(alias)); } } if (certificateNumber > 1) { app.println(); Menu<String> menu = builder.toMenu(); MenuResult<String> result = menu.run(); if (result.isSuccess()) { state.certifNickname = result.getValue(); } else { // Should never happen. throw new RuntimeException(); } } else { state.certifNickname = null; } } catch (KeyStoreException e) { throw new ArgumentException(ERR_ERROR_CANNOT_READ_CONNECTION_PARAMETERS.get(e.getMessage()), e.getCause()); } catch (ClientException e) { throw cannotReadConnectionParameters(e); } } // We'we got all the information to get the keys manager ApplicationKeyManager akm = new ApplicationKeyManager(keystore, state.keystorePassword.toCharArray()); if (secureArgsList.keyStorePasswordFileArg.isPresent()) { copySecureArgsList.keyStorePasswordFileArg.clearValues(); copySecureArgsList.keyStorePasswordFileArg.getNameToValueMap().putAll( secureArgsList.keyStorePasswordFileArg.getNameToValueMap()); commandBuilder.addArgument(copySecureArgsList.keyStorePasswordFileArg); } else if (state.keystorePassword != null) { copySecureArgsList.keyStorePasswordArg.clearValues(); copySecureArgsList.keyStorePasswordArg.addValue(state.keystorePassword); commandBuilder.addObfuscatedArgument(copySecureArgsList.keyStorePasswordArg); } if (state.certifNickname != null) { copySecureArgsList.certNicknameArg.clearValues(); copySecureArgsList.certNicknameArg.addValue(state.certifNickname); return SelectableCertificateKeyManager.wrap( new KeyManager[] { akm }, CollectionUtils.newTreeSet(state.certifNickname))[0]; } return akm; } /** * Indicates whether or not a connection should use SSL based on this * interaction. * * @return boolean where true means use SSL */ public boolean useSSL() { return state.useSSL; } /** * Indicates whether or not a connection should use StartTLS based on this * interaction. * * @return boolean where true means use StartTLS */ public boolean useStartTLS() { return state.useStartTLS; } /** * Gets the host name that should be used for connections based on this * interaction. * * @return host name for connections */ public String getHostName() { return state.hostName; } /** * Gets the port number name that should be used for connections based on this * interaction. * * @return port number for connections */ public int getPortNumber() { return portNumber; } /** * Sets the port number name that should be used for connections based on this * interaction. * * @param portNumber * port number for connections */ public void setPortNumber(int portNumber) { this.portNumber = portNumber; } /** * Gets the bind DN name that should be used for connections based on this * interaction. * * @return bind DN for connections */ public String getBindDN() { if (useAdminOrBindDn) { return state.getAdminOrBindDN(); } else if (secureArgsList.useAdminUID()) { return getAdministratorDN(state.adminUID); } else { return state.bindDN; } } /** * Gets the administrator UID name that should be used for connections based * on this interaction. * * @return administrator UID for connections */ public String getAdministratorUID() { return state.adminUID; } /** * Gets the bind password that should be used for connections based on this * interaction. * * @return bind password for connections */ public String getBindPassword() { return state.bindPassword; } /** * Gets the trust manager that should be used for connections based on this * interaction. * * @return trust manager for connections */ public ApplicationTrustManager getTrustManager() { return state.trustManager; } /** * Gets the key store that should be used for connections based on this * interaction. * * @return key store for connections */ public KeyStore getKeyStore() { return state.truststore; } /** * Gets the key manager that should be used for connections based on this * interaction. * * @return key manager for connections */ public KeyManager getKeyManager() { return state.keyManager; } /** * Indicate if the trust store is in memory. * * @return true if the trust store is in memory. */ public boolean isTrustStoreInMemory() { return state.trustStoreInMemory; } /** * Indicate if all certificates must be accepted. * * @return true all certificates must be accepted. */ public boolean isTrustAll() { return state.trustAll; } /** * Returns the timeout to be used to connect with the server. * * @return the timeout to be used to connect with the server. */ public int getConnectTimeout() { return state.connectTimeout; } /** * Indicate if the certificate chain can be trusted. * * @param chain * The certificate chain to validate * @param authType * the authentication type. * @param host * the host we tried to connect and that presented the certificate. * @return true if the server certificate is trusted. */ public boolean checkServerCertificate(X509Certificate[] chain, String authType, String host) { if (state.trustManager == null) { try { initializeTrustManager(); } catch (ArgumentException ae) { // Should not occur throw new RuntimeException(ae); } } app.println(); app.println(INFO_LDAP_CONN_PROMPT_SECURITY_SERVER_CERTIFICATE.get()); app.println(); for (int i = 0; i < chain.length; i++) { // Certificate DN app.println(INFO_LDAP_CONN_SECURITY_SERVER_CERTIFICATE_USER_DN.get(chain[i].getSubjectDN())); // certificate validity app.println(INFO_LDAP_CONN_SECURITY_SERVER_CERTIFICATE_VALIDITY.get( chain[i].getNotBefore(), chain[i].getNotAfter())); // certificate Issuer app.println(INFO_LDAP_CONN_SECURITY_SERVER_CERTIFICATE_ISSUER.get(chain[i].getIssuerDN())); if (i + 1 < chain.length) { app.println(); app.println(); } } MenuBuilder<Integer> builder = new MenuBuilder<>(app); builder.setPrompt(INFO_LDAP_CONN_PROMPT_SECURITY_TRUST_OPTION.get()); TrustOption defaultTrustMethod = TrustOption.SESSION; for (TrustOption t : TrustOption.values()) { int i = builder.addNumberedOption(t.getMenuMessage(), MenuResult.success(t.getChoice())); if (t.equals(defaultTrustMethod)) { builder.setDefault(INFO_LDAP_CONN_PROMPT_SECURITY_PROTOCOL_DEFAULT_CHOICE.get( Integer.valueOf(i)), MenuResult.success(t.getChoice())); } } app.println(); app.println(); Menu<Integer> menu = builder.toMenu(); while (true) { try { MenuResult<Integer> result = menu.run(); if (result.isSuccess()) { if (result.getValue().equals(TrustOption.UNTRUSTED.getChoice())) { return false; } if (result.getValue().equals( TrustOption.CERTIFICATE_DETAILS.getChoice())) { for (X509Certificate cert : chain) { app.println(); app.println(INFO_LDAP_CONN_SECURITY_SERVER_CERTIFICATE.get(cert)); } continue; } // We should add it in the memory truststore for (X509Certificate cert : chain) { String alias = cert.getSubjectDN().getName(); try { state.truststore.setCertificateEntry(alias, cert); } catch (KeyStoreException e1) { // What else should we do? return false; } } // Update the trust manager if (state.trustManager == null) { state.trustManager = new ApplicationTrustManager(state.truststore); } if (authType != null && host != null) { // Update the trust manager with the new certificate state.trustManager.acceptCertificate(chain, authType, host); } else { // Do a full reset of the contents of the keystore. state.trustManager = new ApplicationTrustManager(state.truststore); } if (result.getValue().equals(TrustOption.PERMAMENT.getChoice())) { ValidationCallback<String> callback = new ValidationCallback<String>() { @Override public String validate(ConsoleApplication app, String input) throws ClientException { String ninput = input.trim(); if (ninput.length() == 0) { app.println(); app.println(ERR_LDAP_CONN_PROMPT_SECURITY_INVALID_FILE_PATH.get()); app.println(); return null; } File f = new File(ninput); if (!f.isDirectory()) { return ninput; } else { app.println(); app.println(ERR_LDAP_CONN_PROMPT_SECURITY_INVALID_FILE_PATH.get()); app.println(); return null; } } }; String truststorePath; try { app.println(); truststorePath = app.readValidatedInput(INFO_LDAP_CONN_PROMPT_SECURITY_TRUSTSTORE_PATH.get(), callback); } catch (ClientException e) { return true; } // Read the password from the stdin. String truststorePassword; try { app.println(); LocalizableMessage prompt = INFO_LDAP_CONN_PROMPT_SECURITY_KEYSTORE_PASSWORD.get(truststorePath); truststorePassword = readPassword(prompt); } catch (Exception e) { return true; } try { KeyStore ts = KeyStore.getInstance("JKS"); FileInputStream fis; try { fis = new FileInputStream(truststorePath); } catch (FileNotFoundException e) { fis = null; } ts.load(fis, truststorePassword.toCharArray()); if (fis != null) { fis.close(); } for (X509Certificate cert : chain) { String alias = cert.getSubjectDN().getName(); ts.setCertificateEntry(alias, cert); } FileOutputStream fos = new FileOutputStream(truststorePath); try { ts.store(fos, truststorePassword.toCharArray()); } finally { fos.close(); } } catch (Exception e) { return true; } } return true; } else { // Should never happen. throw new RuntimeException(); } } catch (ClientException cliE) { throw new RuntimeException(cliE); } } } /** * Populates a set of LDAP options with state from this interaction. * * @param options * existing set of options; may be null in which case this method * will create a new set of <code>LDAPConnectionOptions</code> to be * returned * @return used during this interaction * @throws SSLConnectionException * if this interaction has specified the use of SSL and there is a * problem initializing the SSL connection factory */ public LDAPConnectionOptions populateLDAPOptions(LDAPConnectionOptions options) throws SSLConnectionException { if (options == null) { options = new LDAPConnectionOptions(); } options.setUseSSL(state.useSSL); options.setStartTLS(state.useStartTLS); if (state.useSSL) { SSLConnectionFactory sslConnectionFactory = new SSLConnectionFactory(); sslConnectionFactory.init(getTrustManager() == null, state.keystorePath, state.keystorePassword, state.certifNickname, state.truststorePath, state.truststorePassword); options.setSSLConnectionFactory(sslConnectionFactory); } return options; } /** * Prompts the user to accept the certificate. * * @param t * the throwable that was generated because the certificate was not * trusted. * @param usedTrustManager * the trustManager used when trying to establish the connection. * @param usedUrl * the LDAP URL used to connect to the server. * @param logger * the Logger used to log messages. * @return {@code true} if the user accepted the certificate and * {@code false} otherwise. */ public boolean promptForCertificateConfirmation(Throwable t, ApplicationTrustManager usedTrustManager, String usedUrl, LocalizedLogger logger) { ApplicationTrustManager.Cause cause; if (usedTrustManager != null) { cause = usedTrustManager.getLastRefusedCause(); } else { cause = null; } if (logger != null) { logger.debug(LocalizableMessage.raw("Certificate exception cause: " + cause)); } if (cause != null) { String h; int p; try { URI uri = new URI(usedUrl); h = uri.getHost(); p = uri.getPort(); } catch (Throwable t1) { printLogger(logger, "Error parsing ldap url of ldap url. " + t1); h = INFO_NOT_AVAILABLE_LABEL.get().toString(); p = -1; } String authType = usedTrustManager.getLastRefusedAuthType(); if (authType == null) { printLogger(logger, "Null auth type for this certificate exception."); } else { LocalizableMessage msg; if (authType.equals(ApplicationTrustManager.Cause.NOT_TRUSTED)) { msg = INFO_CERTIFICATE_NOT_TRUSTED_TEXT_CLI.get(h, p); } else { msg = INFO_CERTIFICATE_NAME_MISMATCH_TEXT_CLI.get(h, p, h, h, p); } app.println(msg); } X509Certificate[] chain = usedTrustManager.getLastRefusedChain(); if (chain == null) { printLogger(logger, "Null chain for this certificate exception."); return false; } if (h == null) { printLogger(logger, "Null host name for this certificate exception."); } return checkServerCertificate(chain, authType, h); } else { app.println(getThrowableMsg(INFO_ERROR_CONNECTING_TO_LOCAL.get(), t)); } return false; } private void printLogger(final LocalizedLogger logger, final String msg) { if (logger != null) { logger.warn(LocalizableMessage.raw(msg)); } } /** * Sets the heading that is displayed in interactive mode. * * @param heading * the heading that is displayed in interactive mode. */ public void setHeadingMessage(LocalizableMessage heading) { this.heading = heading; } /** * Returns the command builder with the equivalent arguments on the * non-interactive mode. * * @return the command builder with the equivalent arguments on the * non-interactive mode. */ public CommandBuilder getCommandBuilder() { return commandBuilder; } /** * Displays the heading if it was not displayed before. */ private void checkHeadingDisplayed() { if (!state.isHeadingDisplayed) { app.println(); app.println(); app.println(heading); state.isHeadingDisplayed = true; } } /** * Tells whether during interaction we can ask for both the DN or the admin * UID. * * @return {@code true} if during interaction we can ask for both the DN * and the admin UID and {@code false} otherwise. */ public boolean isUseAdminOrBindDn() { return useAdminOrBindDn; } /** * Tells whether we can ask during interaction for both the DN and the admin * UID or not. * * @param useAdminOrBindDn * whether we can ask for both the DN and the admin UID during * interaction or not. */ public void setUseAdminOrBindDn(boolean useAdminOrBindDn) { this.useAdminOrBindDn = useAdminOrBindDn; } /** * Tells whether we propose LDAP as protocol even if the user provided * security parameters. This is required in command-lines that access multiple * servers (like dsreplication). * * @param displayLdapIfSecureParameters * whether propose LDAP as protocol even if the user provided * security parameters or not. */ public void setDisplayLdapIfSecureParameters( boolean displayLdapIfSecureParameters) { this.displayLdapIfSecureParameters = displayLdapIfSecureParameters; } /** * Resets the heading displayed flag, so that next time we call run the * heading is displayed. */ public void resetHeadingDisplayed() { state.isHeadingDisplayed = false; } /** * Forces the initialization of the trust manager with the arguments provided * by the user. * * @throws ArgumentException * if there is an error with the arguments provided by the user. */ public void initializeTrustManagerIfRequired() throws ArgumentException { if (!state.trustManagerInitialized) { initializeTrustManager(); } } /** * Initializes the global arguments in the parser with the provided values. * This is useful when we want to call LDAPConnectionConsoleInteraction.run() * with some default values. * * @param hostName * the host name. * @param port * the port to connect to the server. * @param adminUid * the administrator UID. * @param bindDn * the bind DN to bind to the server. * @param bindPwd * the password to bind. * @param pwdFile * the Map containing the file and the password to bind. */ public void initializeGlobalArguments(String hostName, int port, String adminUid, String bindDn, String bindPwd, LinkedHashMap<String, String> pwdFile) { resetConnectionArguments(); if (hostName != null) { secureArgsList.hostNameArg.addValue(hostName); secureArgsList.hostNameArg.setPresent(true); } // resetConnectionArguments does not clear the values for the port secureArgsList.portArg.clearValues(); if (port != -1) { secureArgsList.portArg.addValue(String.valueOf(port)); secureArgsList.portArg.setPresent(true); } else { // This is done to be able to call IntegerArgument.getIntValue() secureArgsList.portArg.addValue(secureArgsList.portArg.getDefaultValue()); } secureArgsList.useSSLArg.setPresent(state.useSSL); secureArgsList.useStartTLSArg.setPresent(state.useStartTLS); if (adminUid != null) { secureArgsList.adminUidArg.addValue(adminUid); secureArgsList.adminUidArg.setPresent(true); } if (bindDn != null) { secureArgsList.bindDnArg.addValue(bindDn); secureArgsList.bindDnArg.setPresent(true); } if (pwdFile != null) { secureArgsList.bindPasswordFileArg.getNameToValueMap().putAll(pwdFile); for (String value : pwdFile.keySet()) { secureArgsList.bindPasswordFileArg.addValue(value); } secureArgsList.bindPasswordFileArg.setPresent(true); } else if (bindPwd != null) { secureArgsList.bindPasswordArg.addValue(bindPwd); secureArgsList.bindPasswordArg.setPresent(true); } state = new State(secureArgsList); } /** * Resets the connection parameters for the LDAPConsoleInteraction object. The * reset does not apply to the certificate parameters. This is called in order * the LDAPConnectionConsoleInteraction object to ask for all this connection * parameters next time we call LDAPConnectionConsoleInteraction.run(). */ public void resetConnectionArguments() { secureArgsList.hostNameArg.clearValues(); secureArgsList.hostNameArg.setPresent(false); secureArgsList.portArg.clearValues(); secureArgsList.portArg.setPresent(false); // This is done to be able to call IntegerArgument.getIntValue() secureArgsList.portArg.addValue(secureArgsList.portArg.getDefaultValue()); secureArgsList.bindDnArg.clearValues(); secureArgsList.bindDnArg.setPresent(false); secureArgsList.bindPasswordArg.clearValues(); secureArgsList.bindPasswordArg.setPresent(false); secureArgsList.bindPasswordFileArg.clearValues(); secureArgsList.bindPasswordFileArg.getNameToValueMap().clear(); secureArgsList.bindPasswordFileArg.setPresent(false); state.bindPassword = null; secureArgsList.adminUidArg.clearValues(); secureArgsList.adminUidArg.setPresent(false); } private void initializeTrustManager() throws ArgumentException { // Get trust store info state.trustManager = getTrustManagerInternal(); // Check if we need client side authentication state.keyManager = getKeyManagerInternal(); state.trustManagerInitialized = true; } /** * Returns the explicitly provided Admin UID from the user (interactively or * through the argument). * * @return the explicitly provided Admin UID from the user (interactively or * through the argument). */ public String getProvidedAdminUID() { return state.providedAdminUID; } /** * Returns the explicitly provided bind DN from the user (interactively or * through the argument). * * @return the explicitly provided bind DN from the user (interactively or * through the argument). */ public String getProvidedBindDN() { return state.providedBindDN; } /** * Add the TrustStore of the administration connector of the local instance. * * @return true if the local trust store has been added. */ private boolean addLocalTrustStore() { try { // If remote host, return if (!InetAddress.getLocalHost().getHostName().equals(state.hostName) || secureArgsList.getAdminPortFromConfig() != portNumber) { return false; } // check if we are in a local instance. Already checked the host, // now check the port if (secureArgsList.getAdminPortFromConfig() != portNumber) { return false; } String truststoreFileAbsolute = secureArgsList.getTruststoreFileFromConfig(); if (truststoreFileAbsolute != null) { secureArgsList.trustStorePathArg.addValue(truststoreFileAbsolute); return true; } return false; } catch (Exception ex) { // do nothing return false; } } }