GEODE-3328: refactor ConnectCommand * connect command will prompt for missing ssl configs if ssl is indicated by any options * command ssl options will override the properties loaded in the file * reworked connect with ssl so that the configuration won't get cached accidentally. * have auto connect also prompt for missing ssl configs, not in the socket creator * change the properties file type in the start server and start locator command to be File instead of String
Project: http://git-wip-us.apache.org/repos/asf/geode/repo Commit: http://git-wip-us.apache.org/repos/asf/geode/commit/7352fcc7 Tree: http://git-wip-us.apache.org/repos/asf/geode/tree/7352fcc7 Diff: http://git-wip-us.apache.org/repos/asf/geode/diff/7352fcc7 Branch: refs/heads/feature/GEODE-3416 Commit: 7352fcc7e485984b57d72373b468440d09556b5a Parents: 1bd15f8 Author: Jinmei Liao <jil...@pivotal.io> Authored: Sat Jul 29 21:32:50 2017 -0700 Committer: Jinmei Liao <jil...@pivotal.io> Committed: Thu Aug 10 13:50:31 2017 -0700 ---------------------------------------------------------------------- .../distributed/ConfigurationProperties.java | 4 + .../internal/tcpserver/TcpClient.java | 12 +- .../internal/net/SSLConfigurationFactory.java | 202 ++++---- .../internal/JmxManagerLocatorRequest.java | 47 +- .../internal/beans/BeanUtilFuncs.java | 1 + .../cli/AbstractCliAroundInterceptor.java | 18 +- .../internal/cli/commands/ConnectCommand.java | 482 ++++++++----------- .../internal/cli/commands/ShellCommands.java | 77 ++- .../cli/commands/StartLocatorCommand.java | 148 ++---- .../internal/cli/commands/StartMemberUtils.java | 13 +- .../cli/commands/StartServerCommand.java | 34 +- .../cli/commands/UserInputProperty.java | 120 +++++ .../internal/cli/i18n/CliStrings.java | 4 +- .../management/internal/cli/shell/Gfsh.java | 20 +- .../internal/cli/shell/JmxOperationInvoker.java | 147 ++---- .../internal/cli/util/GfshConsoleReader.java | 16 +- .../ClusterConfigurationStatusRetriever.java | 17 +- .../net/SSLConfigurationFactoryJUnitTest.java | 37 +- .../ConnectToLocatorSSLDUnitTest.java | 104 ---- .../ConnectToLocatorWithLegacySSLDUnitTest.java | 118 ----- .../internal/cli/GfshParserConverterTest.java | 25 +- .../cli/commands/ConnectCommandTest.java | 300 ++++++++++++ .../cli/commands/GfshCommandJUnitTest.java | 41 +- .../cli/commands/UserInputPropertyTest.java | 102 ++++ .../CacheServerManagementDUnitTest.java | 58 ++- .../commands/ConnectCommandIntegrationTest.java | 50 ++ .../cli/commands/ConnectCommandWithSSLTest.java | 303 ++++++++++++ .../ConnectCommandWithSecurityTest.java | 55 +++ .../ConnectToLocatorSSLOverHttpTest.java | 43 -- 29 files changed, 1551 insertions(+), 1047 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/geode/blob/7352fcc7/geode-core/src/main/java/org/apache/geode/distributed/ConfigurationProperties.java ---------------------------------------------------------------------- diff --git a/geode-core/src/main/java/org/apache/geode/distributed/ConfigurationProperties.java b/geode-core/src/main/java/org/apache/geode/distributed/ConfigurationProperties.java index 91a6443..aae7d8a 100644 --- a/geode-core/src/main/java/org/apache/geode/distributed/ConfigurationProperties.java +++ b/geode-core/src/main/java/org/apache/geode/distributed/ConfigurationProperties.java @@ -687,6 +687,10 @@ public interface ConfigurationProperties { */ String SSL_WEB_ALIAS = "ssl-web-alias"; + + @Deprecated + String HTTP_SERVICE_SSL_PREFIX = "http-service-ssl-"; + /** * The static String definition of the <i>"http-service-ssl-ciphers"</i> property <a * name="http-service-ssl-ciphers"/a> http://git-wip-us.apache.org/repos/asf/geode/blob/7352fcc7/geode-core/src/main/java/org/apache/geode/distributed/internal/tcpserver/TcpClient.java ---------------------------------------------------------------------- diff --git a/geode-core/src/main/java/org/apache/geode/distributed/internal/tcpserver/TcpClient.java b/geode-core/src/main/java/org/apache/geode/distributed/internal/tcpserver/TcpClient.java index d406891..933b25d 100644 --- a/geode-core/src/main/java/org/apache/geode/distributed/internal/tcpserver/TcpClient.java +++ b/geode-core/src/main/java/org/apache/geode/distributed/internal/tcpserver/TcpClient.java @@ -24,9 +24,9 @@ import java.net.InetSocketAddress; import java.net.Socket; import java.util.HashMap; import java.util.Map; +import java.util.Properties; import javax.net.ssl.SSLException; -import javax.net.ssl.SSLHandshakeException; import org.apache.logging.log4j.Logger; @@ -36,7 +36,9 @@ import org.apache.geode.distributed.internal.DistributionConfig; import org.apache.geode.internal.Version; import org.apache.geode.internal.VersionedDataInputStream; import org.apache.geode.internal.VersionedDataOutputStream; +import org.apache.geode.internal.admin.SSLConfig; import org.apache.geode.internal.logging.LogService; +import org.apache.geode.internal.net.SSLConfigurationFactory; import org.apache.geode.internal.net.SocketCreator; import org.apache.geode.internal.net.SocketCreatorFactory; import org.apache.geode.internal.security.SecurableCommunicationChannel; @@ -72,6 +74,12 @@ public class TcpClient { this(SocketCreatorFactory.getSocketCreatorForComponent(SecurableCommunicationChannel.LOCATOR)); } + public TcpClient(Properties properties) { + SSLConfig sslConfig = SSLConfigurationFactory.getSSLConfigForComponent(properties, + SecurableCommunicationChannel.LOCATOR); + this.socketCreator = new SocketCreator(sslConfig); + } + /** * Constructs a new TcpClient * @@ -310,7 +318,7 @@ public class TcpClient { Object readObject = DataSerializer.readObject(in); if (!(readObject instanceof VersionResponse)) { throw new LocatorCancelException( - "Unrecognisable response received: object is null. This could be the result of trying to connect a non-SSL-enabled locator to an SSL-enabled locator."); + "Unrecognisable response received: This could be the result of trying to connect a non-SSL-enabled client to an SSL-enabled locator."); } VersionResponse response = (VersionResponse) readObject; if (response != null) { http://git-wip-us.apache.org/repos/asf/geode/blob/7352fcc7/geode-core/src/main/java/org/apache/geode/internal/net/SSLConfigurationFactory.java ---------------------------------------------------------------------- diff --git a/geode-core/src/main/java/org/apache/geode/internal/net/SSLConfigurationFactory.java b/geode-core/src/main/java/org/apache/geode/internal/net/SSLConfigurationFactory.java index 4b98617..00ccb74 100644 --- a/geode-core/src/main/java/org/apache/geode/internal/net/SSLConfigurationFactory.java +++ b/geode-core/src/main/java/org/apache/geode/internal/net/SSLConfigurationFactory.java @@ -24,6 +24,7 @@ import org.apache.commons.lang.StringUtils; import org.apache.geode.GemFireConfigException; import org.apache.geode.distributed.internal.DistributionConfig; +import org.apache.geode.distributed.internal.DistributionConfigImpl; import org.apache.geode.internal.admin.SSLConfig; import org.apache.geode.internal.security.SecurableCommunicationChannel; @@ -63,6 +64,11 @@ public class SSLConfigurationFactory { getInstance().distributionConfig = distributionConfig; } + /** + * @deprecated since GEODE 1.3, use #{getSSLConfigForComponent({@link DistributionConfig} , + * {@link SecurableCommunicationChannel})} instead + */ + @Deprecated public static SSLConfig getSSLConfigForComponent( SecurableCommunicationChannel sslEnabledComponent) { SSLConfig sslConfig = getInstance().getRegisteredSSLConfigForComponent(sslEnabledComponent); @@ -80,64 +86,68 @@ public class SSLConfigurationFactory { private SSLConfig createSSLConfigForComponent( final SecurableCommunicationChannel sslEnabledComponent) { - SSLConfig sslConfig = createSSLConfig(sslEnabledComponent); + return createSSLConfigForComponent(getDistributionConfig(), sslEnabledComponent); + } + + private SSLConfig createSSLConfigForComponent(final DistributionConfig distributionConfig, + final SecurableCommunicationChannel sslEnabledComponent) { + SSLConfig sslConfig = createSSLConfig(distributionConfig, sslEnabledComponent); SecurableCommunicationChannel[] sslEnabledComponents = - getDistributionConfig().getSecurableCommunicationChannels(); + distributionConfig.getSecurableCommunicationChannels(); if (sslEnabledComponents.length == 0) { - sslConfig = configureLegacyClusterSSL(sslConfig); + sslConfig = configureLegacyClusterSSL(distributionConfig, sslConfig); } sslConfig.setSecurableCommunicationChannel(sslEnabledComponent); switch (sslEnabledComponent) { case ALL: { // Create a SSLConfig separate for HTTP Service. As the require-authentication might differ - createSSLConfigForComponent(SecurableCommunicationChannel.WEB); + createSSLConfigForComponent(distributionConfig, SecurableCommunicationChannel.WEB); break; } case CLUSTER: { if (sslEnabledComponents.length > 0) { - sslConfig = setAliasForComponent(sslConfig, getDistributionConfig().getClusterSSLAlias()); + sslConfig = setAliasForComponent(sslConfig, distributionConfig.getClusterSSLAlias()); } else { - sslConfig = configureLegacyClusterSSL(sslConfig); + sslConfig = configureLegacyClusterSSL(distributionConfig, sslConfig); } break; } case LOCATOR: { if (sslEnabledComponents.length > 0) { - sslConfig = setAliasForComponent(sslConfig, getDistributionConfig().getLocatorSSLAlias()); + sslConfig = setAliasForComponent(sslConfig, distributionConfig.getLocatorSSLAlias()); } break; } case SERVER: { if (sslEnabledComponents.length > 0) { - sslConfig = setAliasForComponent(sslConfig, getDistributionConfig().getServerSSLAlias()); + sslConfig = setAliasForComponent(sslConfig, distributionConfig.getServerSSLAlias()); } else { - sslConfig = configureLegacyServerSSL(sslConfig); + sslConfig = configureLegacyServerSSL(distributionConfig, sslConfig); } break; } case GATEWAY: { if (sslEnabledComponents.length > 0) { - sslConfig = setAliasForComponent(sslConfig, getDistributionConfig().getGatewaySSLAlias()); + sslConfig = setAliasForComponent(sslConfig, distributionConfig.getGatewaySSLAlias()); } else { - sslConfig = configureLegacyGatewaySSL(sslConfig); + sslConfig = configureLegacyGatewaySSL(distributionConfig, sslConfig); } break; } case WEB: { if (sslEnabledComponents.length > 0) { - sslConfig = - setAliasForComponent(sslConfig, getDistributionConfig().getHTTPServiceSSLAlias()); - sslConfig.setRequireAuth(getDistributionConfig().getSSLWebRequireAuthentication()); + sslConfig = setAliasForComponent(sslConfig, distributionConfig.getHTTPServiceSSLAlias()); + sslConfig.setRequireAuth(distributionConfig.getSSLWebRequireAuthentication()); } else { - sslConfig = configureLegacyHttpServiceSSL(sslConfig); + sslConfig = configureLegacyHttpServiceSSL(distributionConfig, sslConfig); } break; } case JMX: { if (sslEnabledComponents.length > 0) { - sslConfig = setAliasForComponent(sslConfig, getDistributionConfig().getJMXSSLAlias()); + sslConfig = setAliasForComponent(sslConfig, distributionConfig.getJMXSSLAlias()); } else { - sslConfig = configureLegacyJMXSSL(sslConfig); + sslConfig = configureLegacyJMXSSL(distributionConfig, sslConfig); } break; } @@ -153,33 +163,35 @@ public class SSLConfigurationFactory { return sslConfig; } - private SSLConfig createSSLConfig(final SecurableCommunicationChannel sslEnabledComponent) { + private SSLConfig createSSLConfig(final DistributionConfig distributionConfig, + final SecurableCommunicationChannel sslEnabledComponent) { SSLConfig sslConfig = new SSLConfig(); - sslConfig.setCiphers(getDistributionConfig().getSSLCiphers()); - sslConfig.setEnabled(determineIfSSLEnabledForSSLComponent(sslEnabledComponent)); - sslConfig.setKeystore(getDistributionConfig().getSSLKeyStore()); - sslConfig.setKeystorePassword(getDistributionConfig().getSSLKeyStorePassword()); - sslConfig.setKeystoreType(getDistributionConfig().getSSLKeyStoreType()); - sslConfig.setTruststore(getDistributionConfig().getSSLTrustStore()); - sslConfig.setTruststorePassword(getDistributionConfig().getSSLTrustStorePassword()); - sslConfig.setTruststoreType(getDistributionConfig().getSSLTrustStoreType()); - sslConfig.setProtocols(getDistributionConfig().getSSLProtocols()); - sslConfig.setRequireAuth(getDistributionConfig().getSSLRequireAuthentication()); - sslConfig.setAlias(getDistributionConfig().getSSLDefaultAlias()); + sslConfig.setCiphers(distributionConfig.getSSLCiphers()); + sslConfig + .setEnabled(determineIfSSLEnabledForSSLComponent(distributionConfig, sslEnabledComponent)); + sslConfig.setKeystore(distributionConfig.getSSLKeyStore()); + sslConfig.setKeystorePassword(distributionConfig.getSSLKeyStorePassword()); + sslConfig.setKeystoreType(distributionConfig.getSSLKeyStoreType()); + sslConfig.setTruststore(distributionConfig.getSSLTrustStore()); + sslConfig.setTruststorePassword(distributionConfig.getSSLTrustStorePassword()); + sslConfig.setTruststoreType(distributionConfig.getSSLTrustStoreType()); + sslConfig.setProtocols(distributionConfig.getSSLProtocols()); + sslConfig.setRequireAuth(distributionConfig.getSSLRequireAuthentication()); + sslConfig.setAlias(distributionConfig.getSSLDefaultAlias()); return sslConfig; } - private boolean determineIfSSLEnabledForSSLComponent( + private boolean determineIfSSLEnabledForSSLComponent(final DistributionConfig distributionConfig, final SecurableCommunicationChannel sslEnabledComponent) { - if (ArrayUtils.contains(getDistributionConfig().getSecurableCommunicationChannels(), + if (ArrayUtils.contains(distributionConfig.getSecurableCommunicationChannels(), SecurableCommunicationChannel.NONE)) { return false; } - if (ArrayUtils.contains(getDistributionConfig().getSecurableCommunicationChannels(), + if (ArrayUtils.contains(distributionConfig.getSecurableCommunicationChannels(), SecurableCommunicationChannel.ALL)) { return true; } - return ArrayUtils.contains(getDistributionConfig().getSecurableCommunicationChannels(), + return ArrayUtils.contains(distributionConfig.getSecurableCommunicationChannels(), sslEnabledComponent) ? true : false; } @@ -189,17 +201,18 @@ public class SSLConfigurationFactory { * @return A sslConfig object describing the ssl config for the server component * @deprecated as of Geode 1.0 */ - private SSLConfig configureLegacyClusterSSL(SSLConfig sslConfig) { - sslConfig.setCiphers(getDistributionConfig().getClusterSSLCiphers()); - sslConfig.setEnabled(getDistributionConfig().getClusterSSLEnabled()); - sslConfig.setKeystore(getDistributionConfig().getClusterSSLKeyStore()); - sslConfig.setKeystorePassword(getDistributionConfig().getClusterSSLKeyStorePassword()); - sslConfig.setKeystoreType(getDistributionConfig().getClusterSSLKeyStoreType()); - sslConfig.setTruststore(getDistributionConfig().getClusterSSLTrustStore()); - sslConfig.setTruststorePassword(getDistributionConfig().getClusterSSLTrustStorePassword()); - sslConfig.setTruststoreType(getDistributionConfig().getClusterSSLKeyStoreType()); - sslConfig.setProtocols(getDistributionConfig().getClusterSSLProtocols()); - sslConfig.setRequireAuth(getDistributionConfig().getClusterSSLRequireAuthentication()); + private SSLConfig configureLegacyClusterSSL(final DistributionConfig distributionConfig, + final SSLConfig sslConfig) { + sslConfig.setCiphers(distributionConfig.getClusterSSLCiphers()); + sslConfig.setEnabled(distributionConfig.getClusterSSLEnabled()); + sslConfig.setKeystore(distributionConfig.getClusterSSLKeyStore()); + sslConfig.setKeystorePassword(distributionConfig.getClusterSSLKeyStorePassword()); + sslConfig.setKeystoreType(distributionConfig.getClusterSSLKeyStoreType()); + sslConfig.setTruststore(distributionConfig.getClusterSSLTrustStore()); + sslConfig.setTruststorePassword(distributionConfig.getClusterSSLTrustStorePassword()); + sslConfig.setTruststoreType(distributionConfig.getClusterSSLKeyStoreType()); + sslConfig.setProtocols(distributionConfig.getClusterSSLProtocols()); + sslConfig.setRequireAuth(distributionConfig.getClusterSSLRequireAuthentication()); return sslConfig; } @@ -209,17 +222,18 @@ public class SSLConfigurationFactory { * @return A sslConfig object describing the ssl config for the server component * @deprecated as of Geode 1.0 */ - private SSLConfig configureLegacyServerSSL(SSLConfig sslConfig) { - sslConfig.setCiphers(getDistributionConfig().getServerSSLCiphers()); - sslConfig.setEnabled(getDistributionConfig().getServerSSLEnabled()); - sslConfig.setKeystore(getDistributionConfig().getServerSSLKeyStore()); - sslConfig.setKeystorePassword(getDistributionConfig().getServerSSLKeyStorePassword()); - sslConfig.setKeystoreType(getDistributionConfig().getServerSSLKeyStoreType()); - sslConfig.setTruststore(getDistributionConfig().getServerSSLTrustStore()); - sslConfig.setTruststorePassword(getDistributionConfig().getServerSSLTrustStorePassword()); - sslConfig.setTruststoreType(getDistributionConfig().getServerSSLKeyStoreType()); - sslConfig.setProtocols(getDistributionConfig().getServerSSLProtocols()); - sslConfig.setRequireAuth(getDistributionConfig().getServerSSLRequireAuthentication()); + private SSLConfig configureLegacyServerSSL(final DistributionConfig distributionConfig, + final SSLConfig sslConfig) { + sslConfig.setCiphers(distributionConfig.getServerSSLCiphers()); + sslConfig.setEnabled(distributionConfig.getServerSSLEnabled()); + sslConfig.setKeystore(distributionConfig.getServerSSLKeyStore()); + sslConfig.setKeystorePassword(distributionConfig.getServerSSLKeyStorePassword()); + sslConfig.setKeystoreType(distributionConfig.getServerSSLKeyStoreType()); + sslConfig.setTruststore(distributionConfig.getServerSSLTrustStore()); + sslConfig.setTruststorePassword(distributionConfig.getServerSSLTrustStorePassword()); + sslConfig.setTruststoreType(distributionConfig.getServerSSLKeyStoreType()); + sslConfig.setProtocols(distributionConfig.getServerSSLProtocols()); + sslConfig.setRequireAuth(distributionConfig.getServerSSLRequireAuthentication()); return sslConfig; } @@ -229,17 +243,18 @@ public class SSLConfigurationFactory { * @return A sslConfig object describing the ssl config for the jmx component * @deprecated as of Geode 1.0 */ - private SSLConfig configureLegacyJMXSSL(SSLConfig sslConfig) { - sslConfig.setCiphers(getDistributionConfig().getJmxManagerSSLCiphers()); - sslConfig.setEnabled(getDistributionConfig().getJmxManagerSSLEnabled()); - sslConfig.setKeystore(getDistributionConfig().getJmxManagerSSLKeyStore()); - sslConfig.setKeystorePassword(getDistributionConfig().getJmxManagerSSLKeyStorePassword()); - sslConfig.setKeystoreType(getDistributionConfig().getJmxManagerSSLKeyStoreType()); - sslConfig.setTruststore(getDistributionConfig().getJmxManagerSSLTrustStore()); - sslConfig.setTruststorePassword(getDistributionConfig().getJmxManagerSSLTrustStorePassword()); - sslConfig.setTruststoreType(getDistributionConfig().getJmxManagerSSLKeyStoreType()); - sslConfig.setProtocols(getDistributionConfig().getJmxManagerSSLProtocols()); - sslConfig.setRequireAuth(getDistributionConfig().getJmxManagerSSLRequireAuthentication()); + private SSLConfig configureLegacyJMXSSL(final DistributionConfig distributionConfig, + final SSLConfig sslConfig) { + sslConfig.setCiphers(distributionConfig.getJmxManagerSSLCiphers()); + sslConfig.setEnabled(distributionConfig.getJmxManagerSSLEnabled()); + sslConfig.setKeystore(distributionConfig.getJmxManagerSSLKeyStore()); + sslConfig.setKeystorePassword(distributionConfig.getJmxManagerSSLKeyStorePassword()); + sslConfig.setKeystoreType(distributionConfig.getJmxManagerSSLKeyStoreType()); + sslConfig.setTruststore(distributionConfig.getJmxManagerSSLTrustStore()); + sslConfig.setTruststorePassword(distributionConfig.getJmxManagerSSLTrustStorePassword()); + sslConfig.setTruststoreType(distributionConfig.getJmxManagerSSLKeyStoreType()); + sslConfig.setProtocols(distributionConfig.getJmxManagerSSLProtocols()); + sslConfig.setRequireAuth(distributionConfig.getJmxManagerSSLRequireAuthentication()); return sslConfig; } @@ -249,16 +264,17 @@ public class SSLConfigurationFactory { * @return A sslConfig object describing the ssl config for the gateway component * @deprecated as of Geode 1.0 */ - private SSLConfig configureLegacyGatewaySSL(SSLConfig sslConfig) { - sslConfig.setCiphers(getDistributionConfig().getGatewaySSLCiphers()); - sslConfig.setEnabled(getDistributionConfig().getGatewaySSLEnabled()); - sslConfig.setKeystore(getDistributionConfig().getGatewaySSLKeyStore()); - sslConfig.setKeystorePassword(getDistributionConfig().getGatewaySSLKeyStorePassword()); - sslConfig.setKeystoreType(getDistributionConfig().getGatewaySSLKeyStoreType()); - sslConfig.setTruststore(getDistributionConfig().getGatewaySSLTrustStore()); - sslConfig.setTruststorePassword(getDistributionConfig().getGatewaySSLTrustStorePassword()); - sslConfig.setProtocols(getDistributionConfig().getGatewaySSLProtocols()); - sslConfig.setRequireAuth(getDistributionConfig().getGatewaySSLRequireAuthentication()); + private SSLConfig configureLegacyGatewaySSL(final DistributionConfig distributionConfig, + final SSLConfig sslConfig) { + sslConfig.setCiphers(distributionConfig.getGatewaySSLCiphers()); + sslConfig.setEnabled(distributionConfig.getGatewaySSLEnabled()); + sslConfig.setKeystore(distributionConfig.getGatewaySSLKeyStore()); + sslConfig.setKeystorePassword(distributionConfig.getGatewaySSLKeyStorePassword()); + sslConfig.setKeystoreType(distributionConfig.getGatewaySSLKeyStoreType()); + sslConfig.setTruststore(distributionConfig.getGatewaySSLTrustStore()); + sslConfig.setTruststorePassword(distributionConfig.getGatewaySSLTrustStorePassword()); + sslConfig.setProtocols(distributionConfig.getGatewaySSLProtocols()); + sslConfig.setRequireAuth(distributionConfig.getGatewaySSLRequireAuthentication()); return sslConfig; } @@ -268,17 +284,18 @@ public class SSLConfigurationFactory { * @return A sslConfig object describing the ssl config for the http service component * @deprecated as of Geode 1.0 */ - private SSLConfig configureLegacyHttpServiceSSL(SSLConfig sslConfig) { - sslConfig.setCiphers(getDistributionConfig().getHttpServiceSSLCiphers()); - sslConfig.setEnabled(getDistributionConfig().getHttpServiceSSLEnabled()); - sslConfig.setKeystore(getDistributionConfig().getHttpServiceSSLKeyStore()); - sslConfig.setKeystorePassword(getDistributionConfig().getHttpServiceSSLKeyStorePassword()); - sslConfig.setKeystoreType(getDistributionConfig().getHttpServiceSSLKeyStoreType()); - sslConfig.setTruststore(getDistributionConfig().getHttpServiceSSLTrustStore()); - sslConfig.setTruststorePassword(getDistributionConfig().getHttpServiceSSLTrustStorePassword()); - sslConfig.setTruststoreType(getDistributionConfig().getHttpServiceSSLKeyStoreType()); - sslConfig.setProtocols(getDistributionConfig().getHttpServiceSSLProtocols()); - sslConfig.setRequireAuth(getDistributionConfig().getHttpServiceSSLRequireAuthentication()); + private SSLConfig configureLegacyHttpServiceSSL(final DistributionConfig distributionConfig, + final SSLConfig sslConfig) { + sslConfig.setCiphers(distributionConfig.getHttpServiceSSLCiphers()); + sslConfig.setEnabled(distributionConfig.getHttpServiceSSLEnabled()); + sslConfig.setKeystore(distributionConfig.getHttpServiceSSLKeyStore()); + sslConfig.setKeystorePassword(distributionConfig.getHttpServiceSSLKeyStorePassword()); + sslConfig.setKeystoreType(distributionConfig.getHttpServiceSSLKeyStoreType()); + sslConfig.setTruststore(distributionConfig.getHttpServiceSSLTrustStore()); + sslConfig.setTruststorePassword(distributionConfig.getHttpServiceSSLTrustStorePassword()); + sslConfig.setTruststoreType(distributionConfig.getHttpServiceSSLKeyStoreType()); + sslConfig.setProtocols(distributionConfig.getHttpServiceSSLProtocols()); + sslConfig.setRequireAuth(distributionConfig.getHttpServiceSSLRequireAuthentication()); return sslConfig; } @@ -357,4 +374,15 @@ public class SSLConfigurationFactory { return sslConfig; } + + public static SSLConfig getSSLConfigForComponent(DistributionConfig distributionConfig, + SecurableCommunicationChannel sslEnabledComponent) { + return getInstance().createSSLConfigForComponent(distributionConfig, sslEnabledComponent); + } + + public static SSLConfig getSSLConfigForComponent(Properties properties, + SecurableCommunicationChannel sslEnabledComponent) { + return getInstance().createSSLConfigForComponent(new DistributionConfigImpl(properties), + sslEnabledComponent); + } } http://git-wip-us.apache.org/repos/asf/geode/blob/7352fcc7/geode-core/src/main/java/org/apache/geode/management/internal/JmxManagerLocatorRequest.java ---------------------------------------------------------------------- diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/JmxManagerLocatorRequest.java b/geode-core/src/main/java/org/apache/geode/management/internal/JmxManagerLocatorRequest.java index eb71d38..dcf9b22 100644 --- a/geode-core/src/main/java/org/apache/geode/management/internal/JmxManagerLocatorRequest.java +++ b/geode-core/src/main/java/org/apache/geode/management/internal/JmxManagerLocatorRequest.java @@ -19,14 +19,16 @@ import java.io.DataOutput; import java.io.IOException; import java.net.InetAddress; import java.net.InetSocketAddress; -import java.util.Map; import java.util.Properties; -import org.apache.geode.distributed.internal.DistributionConfigImpl; +import org.apache.geode.distributed.internal.tcpserver.LocatorCancelException; import org.apache.geode.distributed.internal.tcpserver.TcpClient; import org.apache.geode.internal.DataSerializableFixedID; import org.apache.geode.internal.Version; -import org.apache.geode.internal.net.*; +import org.apache.geode.internal.admin.SSLConfig; +import org.apache.geode.internal.net.SSLConfigurationFactory; +import org.apache.geode.internal.net.SocketCreator; +import org.apache.geode.internal.security.SecurableCommunicationChannel; /** * Sent to a locator to request it to find (and possibly start) a jmx manager for us. It returns a @@ -37,10 +39,6 @@ import org.apache.geode.internal.net.*; */ public class JmxManagerLocatorRequest implements DataSerializableFixedID { - public JmxManagerLocatorRequest() { - super(); - } - public void fromData(DataInput in) throws IOException, ClassNotFoundException {} public void toData(DataOutput out) throws IOException {} @@ -69,38 +67,25 @@ public class JmxManagerLocatorRequest implements DataSerializableFixedID { * have trouble communicating with it. */ public static JmxManagerLocatorResponse send(String locatorHost, int locatorPort, int msTimeout, - Map<String, String> sslConfigProps) throws IOException { - Properties distributionConfigProps = new Properties(); + Properties sslConfigProps) throws IOException, ClassNotFoundException { InetAddress networkAddress = InetAddress.getByName(locatorHost); InetSocketAddress inetSockAddr = new InetSocketAddress(networkAddress, locatorPort); - try { - if (sslConfigProps != null) { - distributionConfigProps.putAll(sslConfigProps); - } - - TcpClient client = new TcpClient(new DistributionConfigImpl(distributionConfigProps)); - Object responseFromServer = client.requestToServer(inetSockAddr, SINGLETON, msTimeout, true); + // simply need to turn sslConfigProps into sslConfig for locator + SSLConfig sslConfig = SSLConfigurationFactory.getSSLConfigForComponent(sslConfigProps, + SecurableCommunicationChannel.LOCATOR); + SocketCreator socketCreator = new SocketCreator(sslConfig); + TcpClient client = new TcpClient(socketCreator); + Object responseFromServer = client.requestToServer(inetSockAddr, SINGLETON, msTimeout, true); + if (responseFromServer instanceof JmxManagerLocatorResponse) return (JmxManagerLocatorResponse) responseFromServer; - } catch (ClassNotFoundException unexpected) { - throw new IllegalStateException(unexpected); - } catch (ClassCastException unexpected) { - // FIXME - Abhishek: object read is type "int" instead of - // JmxManagerLocatorResponse when the Locator is using SSL & the request - // didn't use SSL -> this causes ClassCastException. Not sure how to make - // locator meaningful message - throw new IllegalStateException(unexpected); - } finally { - distributionConfigProps.clear(); + else { + throw new LocatorCancelException( + "Unrecognisable response received: This could be the result of trying to connect a non-SSL-enabled client to an SSL-enabled locator."); } } - public static JmxManagerLocatorResponse send(String locatorHost, int locatorPort, int msTimeout) - throws IOException { - return send(locatorHost, locatorPort, msTimeout, null); - } - @Override public Version[] getSerializationVersions() { // TODO Auto-generated method stub http://git-wip-us.apache.org/repos/asf/geode/blob/7352fcc7/geode-core/src/main/java/org/apache/geode/management/internal/beans/BeanUtilFuncs.java ---------------------------------------------------------------------- diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/beans/BeanUtilFuncs.java b/geode-core/src/main/java/org/apache/geode/management/internal/beans/BeanUtilFuncs.java index 16d45bc..31a198b 100644 --- a/geode-core/src/main/java/org/apache/geode/management/internal/beans/BeanUtilFuncs.java +++ b/geode-core/src/main/java/org/apache/geode/management/internal/beans/BeanUtilFuncs.java @@ -308,6 +308,7 @@ public class BeanUtilFuncs { gemFirePropertyData.setSSLKeyStore(config.getSSLKeyStore()); gemFirePropertyData.setSSLKeyStoreType(config.getSSLKeyStoreType()); gemFirePropertyData.setSSLKeyStorePassword(config.getSSLKeyStorePassword()); + gemFirePropertyData.setSSLTrustStore(config.getSSLTrustStore()); gemFirePropertyData.setSSLTrustStorePassword(config.getSSLTrustStorePassword()); gemFirePropertyData.setSSLTrustStoreType(config.getSSLTrustStoreType()); http://git-wip-us.apache.org/repos/asf/geode/blob/7352fcc7/geode-core/src/main/java/org/apache/geode/management/internal/cli/AbstractCliAroundInterceptor.java ---------------------------------------------------------------------- diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/AbstractCliAroundInterceptor.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/AbstractCliAroundInterceptor.java index 3e1357d..1b84649 100644 --- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/AbstractCliAroundInterceptor.java +++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/AbstractCliAroundInterceptor.java @@ -16,8 +16,6 @@ package org.apache.geode.management.internal.cli; import org.apache.geode.management.internal.cli.shell.Gfsh; -import java.io.IOException; - /** * Semi-complete implementation of {@link CliAroundInterceptor} for convenience for implementors. * @@ -66,7 +64,7 @@ public abstract class AbstractCliAroundInterceptor implements CliAroundIntercept return gfsh != null && !gfsh.isQuietMode() && !gfsh.isHeadlessMode(); } - protected String interact(String message) throws IOException { + protected String interact(String message) { return Gfsh.getCurrentInstance().interact(message); } @@ -83,18 +81,12 @@ public abstract class AbstractCliAroundInterceptor implements CliAroundIntercept Response response = null; do { - try { - String userInput = interact(message); - - if (isNullOrEmpty(userInput)) { - return defaultResponse; - } - response = Response.fromString(userInput); + String userInput = interact(message); - } catch (IOException ioex) { - severe("Could not read user response", ioex); - // What can you do except try again??? + if (isNullOrEmpty(userInput)) { + return defaultResponse; } + response = Response.fromString(userInput); } while (response == null); http://git-wip-us.apache.org/repos/asf/geode/blob/7352fcc7/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ConnectCommand.java ---------------------------------------------------------------------- diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ConnectCommand.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ConnectCommand.java index be556a4..274f61c 100644 --- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ConnectCommand.java +++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ConnectCommand.java @@ -15,26 +15,19 @@ package org.apache.geode.management.internal.cli.commands; -import static org.apache.geode.distributed.ConfigurationProperties.LOCATORS; -import static org.apache.geode.distributed.ConfigurationProperties.MCAST_PORT; -import static org.apache.geode.distributed.ConfigurationProperties.SSL_CIPHERS; -import static org.apache.geode.distributed.ConfigurationProperties.SSL_KEYSTORE; -import static org.apache.geode.distributed.ConfigurationProperties.SSL_KEYSTORE_PASSWORD; -import static org.apache.geode.distributed.ConfigurationProperties.SSL_PROTOCOLS; -import static org.apache.geode.distributed.ConfigurationProperties.SSL_TRUSTSTORE; -import static org.apache.geode.distributed.ConfigurationProperties.SSL_TRUSTSTORE_PASSWORD; -import static org.apache.geode.management.internal.cli.shell.Gfsh.SSL_ENABLED_CIPHERS; -import static org.apache.geode.management.internal.cli.shell.Gfsh.SSL_ENABLED_PROTOCOLS; +import static org.apache.geode.distributed.ConfigurationProperties.CLUSTER_SSL_PREFIX; +import static org.apache.geode.distributed.ConfigurationProperties.HTTP_SERVICE_SSL_PREFIX; +import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_SSL_PREFIX; import java.io.File; import java.io.FileInputStream; import java.io.IOException; -import java.net.URL; +import java.net.MalformedURLException; import java.security.KeyStore; -import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedHashMap; +import java.util.Arrays; import java.util.Map; +import java.util.Objects; +import java.util.Properties; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.KeyManagerFactory; @@ -46,16 +39,16 @@ import org.springframework.shell.core.annotation.CliCommand; import org.springframework.shell.core.annotation.CliOption; import org.apache.geode.internal.DSFIDFactory; +import org.apache.geode.internal.admin.SSLConfig; import org.apache.geode.internal.lang.Initializer; -import org.apache.geode.internal.util.IOUtils; -import org.apache.geode.internal.util.PasswordUtil; +import org.apache.geode.internal.net.SSLConfigurationFactory; +import org.apache.geode.internal.security.SecurableCommunicationChannel; import org.apache.geode.management.cli.CliMetaData; import org.apache.geode.management.cli.ConverterHint; import org.apache.geode.management.cli.Result; import org.apache.geode.management.internal.JmxManagerLocatorRequest; import org.apache.geode.management.internal.JmxManagerLocatorResponse; import org.apache.geode.management.internal.SSLUtil; -import org.apache.geode.management.internal.cli.CliUtil; import org.apache.geode.management.internal.cli.LogWrapper; import org.apache.geode.management.internal.cli.converters.ConnectionEndpointConverter; import org.apache.geode.management.internal.cli.domain.ConnectToLocatorResult; @@ -65,6 +58,7 @@ import org.apache.geode.management.internal.cli.result.ResultBuilder; import org.apache.geode.management.internal.cli.shell.Gfsh; import org.apache.geode.management.internal.cli.shell.JmxOperationInvoker; import org.apache.geode.management.internal.cli.util.ConnectionEndpoint; +import org.apache.geode.management.internal.security.ResourceConstants; import org.apache.geode.management.internal.web.domain.LinkIndex; import org.apache.geode.management.internal.web.http.support.SimpleHttpRequester; import org.apache.geode.management.internal.web.shell.HttpOperationInvoker; @@ -75,6 +69,12 @@ public class ConnectCommand implements GfshCommand { // millis that connect --locator will wait for a response from the locator. public final static int CONNECT_LOCATOR_TIMEOUT_MS = 60000; // see bug 45971 + static UserInputProperty[] USERINPUTPROPERTIES = + {UserInputProperty.KEYSTORE, UserInputProperty.KEYSTORE_PASSWORD, + UserInputProperty.KEYSTORE_TYPE, UserInputProperty.TRUSTSTORE, + UserInputProperty.TRUSTSTORE_PASSWORD, UserInputProperty.TRUSTSTORE_TYPE, + UserInputProperty.CIPHERS, UserInputProperty.PROTOCOL, UserInputProperty.COMPONENT}; + @CliCommand(value = {CliStrings.CONNECT}, help = CliStrings.CONNECT__HELP) @CliMetaData(shellOnly = true, relatedTopic = {CliStrings.TOPIC_GFSH, CliStrings.TOPIC_GEODE_JMX, CliStrings.TOPIC_GEODE_MANAGER}) @@ -82,118 +82,178 @@ public class ConnectCommand implements GfshCommand { @CliOption(key = {CliStrings.CONNECT__LOCATOR}, unspecifiedDefaultValue = ConnectionEndpointConverter.DEFAULT_LOCATOR_ENDPOINTS, optionContext = ConnectionEndpoint.LOCATOR_OPTION_CONTEXT, - help = CliStrings.CONNECT__LOCATOR__HELP) ConnectionEndpoint locatorTcpHostPort, + help = CliStrings.CONNECT__LOCATOR__HELP) ConnectionEndpoint locatorEndPoint, @CliOption(key = {CliStrings.CONNECT__JMX_MANAGER}, - unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, optionContext = ConnectionEndpoint.JMXMANAGER_OPTION_CONTEXT, - help = CliStrings.CONNECT__JMX_MANAGER__HELP) ConnectionEndpoint memberRmiHostPort, - @CliOption(key = {CliStrings.CONNECT__USE_HTTP}, mandatory = false, - specifiedDefaultValue = "true", unspecifiedDefaultValue = "false", + help = CliStrings.CONNECT__JMX_MANAGER__HELP) ConnectionEndpoint jmxManagerEndPoint, + @CliOption(key = {CliStrings.CONNECT__USE_HTTP}, specifiedDefaultValue = "true", + unspecifiedDefaultValue = "false", help = CliStrings.CONNECT__USE_HTTP__HELP) boolean useHttp, - @CliOption(key = {CliStrings.CONNECT__URL}, mandatory = false, + @CliOption(key = {CliStrings.CONNECT__URL}, unspecifiedDefaultValue = CliStrings.CONNECT__DEFAULT_BASE_URL, help = CliStrings.CONNECT__URL__HELP) String url, @CliOption(key = {CliStrings.CONNECT__USERNAME}, - unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, help = CliStrings.CONNECT__USERNAME__HELP) String userName, @CliOption(key = {CliStrings.CONNECT__PASSWORD}, - unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, help = CliStrings.CONNECT__PASSWORD__HELP) String password, @CliOption(key = {CliStrings.CONNECT__KEY_STORE}, - unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, help = CliStrings.CONNECT__KEY_STORE__HELP) String keystore, @CliOption(key = {CliStrings.CONNECT__KEY_STORE_PASSWORD}, - unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, help = CliStrings.CONNECT__KEY_STORE_PASSWORD__HELP) String keystorePassword, @CliOption(key = {CliStrings.CONNECT__TRUST_STORE}, - unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, help = CliStrings.CONNECT__TRUST_STORE__HELP) String truststore, @CliOption(key = {CliStrings.CONNECT__TRUST_STORE_PASSWORD}, - unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, help = CliStrings.CONNECT__TRUST_STORE_PASSWORD__HELP) String truststorePassword, @CliOption(key = {CliStrings.CONNECT__SSL_CIPHERS}, - unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, help = CliStrings.CONNECT__SSL_CIPHERS__HELP) String sslCiphers, @CliOption(key = {CliStrings.CONNECT__SSL_PROTOCOLS}, - unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, help = CliStrings.CONNECT__SSL_PROTOCOLS__HELP) String sslProtocols, - @CliOption(key = CliStrings.CONNECT__SECURITY_PROPERTIES, - optionContext = ConverterHint.FILE_PATH, - unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, - help = CliStrings.CONNECT__SECURITY_PROPERTIES__HELP) final String gfSecurityPropertiesPath, + @CliOption(key = CliStrings.CONNECT__SECURITY_PROPERTIES, optionContext = ConverterHint.FILE, + help = CliStrings.CONNECT__SECURITY_PROPERTIES__HELP) final File gfSecurityPropertiesFile, @CliOption(key = {CliStrings.CONNECT__USE_SSL}, specifiedDefaultValue = "true", unspecifiedDefaultValue = "false", - help = CliStrings.CONNECT__USE_SSL__HELP) final boolean useSsl) { - Result result; - String passwordToUse = PasswordUtil.decrypt(password); - String keystoreToUse = keystore; - String keystorePasswordToUse = keystorePassword; - String truststoreToUse = truststore; - String truststorePasswordToUse = truststorePassword; - String sslCiphersToUse = sslCiphers; - String sslProtocolsToUse = sslProtocols; + help = CliStrings.CONNECT__USE_SSL__HELP) boolean useSsl) + throws MalformedURLException { + Result result; Gfsh gfsh = getGfsh(); + + // bail out if gfsh is already connected. if (gfsh != null && gfsh.isConnectedAndReady()) { return ResultBuilder .createInfoResult("Already connected to: " + getGfsh().getOperationInvoker().toString()); } - Map<String, String> sslConfigProps = null; - try { - if (userName != null && userName.length() > 0) { - if (passwordToUse == null || passwordToUse.length() == 0) { - passwordToUse = gfsh.readPassword(CliStrings.CONNECT__PASSWORD + ": "); - } - if (passwordToUse == null || passwordToUse.length() == 0) { - return ResultBuilder - .createConnectionErrorResult(CliStrings.CONNECT__MSG__JMX_PASSWORD_MUST_BE_SPECIFIED); - } - } + // ssl options are passed in in the order defined in USERINPUTPROPERTIES, note the two types + // are null, because we don't have connect command options for them yet + Properties gfProperties = resolveSslProperties(gfsh, useSsl, null, gfSecurityPropertiesFile, + keystore, keystorePassword, null, truststore, truststorePassword, null, sslCiphers, + sslProtocols, null); - sslConfigProps = this.readSSLConfiguration(useSsl, keystoreToUse, keystorePasswordToUse, - truststoreToUse, truststorePasswordToUse, sslCiphersToUse, sslProtocolsToUse, - gfSecurityPropertiesPath); - } catch (IOException e) { - return handleExcpetion(e, null); + if (containsSSLConfig(gfProperties) || containsLegacySSLConfig(gfProperties)) { + useSsl = true; + } + + // if username is specified in the option but password is not, prompt for the password + // note if gfProperties has username but no password, we would not prompt for password yet, + // because we may not need username/password combination to connect. + if (userName != null) { + gfProperties.setProperty(ResourceConstants.USER_NAME, userName); + if (password == null) { + password = UserInputProperty.PASSWORD.promptForAcceptableValue(gfsh); + } + gfProperties.setProperty(UserInputProperty.PASSWORD.getKey(), password); } + // TODO: refactor this to be more readable, like + /* + * if(useHttp) connectOverHttp else if(jmxManagerEndPoint==null) connectToLocator to get the + * jmxManagerEndPoint else connectTo jmxManagerEndPoint + */ if (useHttp) { - result = httpConnect(sslConfigProps, useSsl, url, userName, passwordToUse); + result = httpConnect(gfProperties, url); } else { - result = jmxConnect(sslConfigProps, memberRmiHostPort, locatorTcpHostPort, useSsl, userName, - passwordToUse, gfSecurityPropertiesPath, false); + result = jmxConnect(gfProperties, useSsl, jmxManagerEndPoint, locatorEndPoint, false); } return result; } + /** + * + * @param gfsh + * @param useSsl if true, and no files/options passed, we would still insist on prompting for ssl + * config (considered only when the last three parameters are null) + * @param gfPropertiesFile gemfire properties file, can be null + * @param gfSecurityPropertiesFile gemfire security properties file, can be null + * @param sslOptionValues an array of 9 in this order, as defined in USERINPUTPROPERTIES + * @return the properties + */ + Properties resolveSslProperties(Gfsh gfsh, boolean useSsl, File gfPropertiesFile, + File gfSecurityPropertiesFile, String... sslOptionValues) { - private Result httpConnect(Map<String, String> sslConfigProps, boolean useSsl, String url, - String userName, String passwordToUse) { - Gfsh gfsh = getGfsh(); - try { - Map<String, String> securityProperties = new HashMap<String, String>(); + // first trying to load the sslProperties from the file + Properties gfProperties = loadProperties(gfPropertiesFile, gfSecurityPropertiesFile); - // at this point, if userName is not empty, password should not be empty either - if (userName != null && userName.length() > 0) { - securityProperties.put("security-username", userName); - securityProperties.put("security-password", passwordToUse); + // if the security file is a legacy ssl security file, then the rest of the command options, if + // any, are ignored. Because we are not trying to add/replace the legacy ssl values using the + // command line values. all command line ssl values updates the ssl-* options. + if (containsLegacySSLConfig(gfProperties)) { + return gfProperties; + } + + // if nothing indicates we should prompt for missing ssl config info, return immediately + if (!(useSsl || containsSSLConfig(gfProperties) || isSslImpliedBySslOptions(sslOptionValues))) { + return gfProperties; + } + + // if use ssl is implied by any of the options, then command option will add to/update the + // properties loaded from file. If the ssl config is not specified anywhere, prompt user for it. + for (int i = 0; i < USERINPUTPROPERTIES.length; i++) { + UserInputProperty userInputProperty = USERINPUTPROPERTIES[i]; + String sslOptionValue = null; + if (sslOptionValues != null && sslOptionValues.length > i) { + sslOptionValue = sslOptionValues[i]; } + String sslConfigValue = gfProperties.getProperty(userInputProperty.getKey()); - if (useSsl) { - configureHttpsURLConnection(sslConfigProps); + // if this option is specified, always use this value + if (sslOptionValue != null) { + gfProperties.setProperty(userInputProperty.getKey(), sslOptionValue); + } + // if option is not specified and not present in the original properties, prompt for it + else if (sslConfigValue == null) { + gfProperties.setProperty(userInputProperty.getKey(), + userInputProperty.promptForAcceptableValue(gfsh)); + } + } + + return gfProperties; + } + + boolean isSslImpliedBySslOptions(String... sslOptions) { + if (sslOptions == null) { + return false; + } + return Arrays.stream(sslOptions).anyMatch(Objects::nonNull); + } + + Properties loadProperties(File... files) { + Properties properties = new Properties(); + if (files == null) { + return properties; + } + for (File file : files) { + if (file != null) { + properties.putAll(ShellCommands.loadProperties(file)); + } + } + return properties; + } + + static boolean containsLegacySSLConfig(Properties properties) { + return properties.stringPropertyNames().stream() + .anyMatch(key -> key.startsWith(CLUSTER_SSL_PREFIX) + || key.startsWith(JMX_MANAGER_SSL_PREFIX) || key.startsWith(HTTP_SERVICE_SSL_PREFIX)); + } + + static boolean containsSSLConfig(Properties properties) { + return properties.stringPropertyNames().stream().anyMatch(key -> key.startsWith("ssl-")); + } + + + Result httpConnect(Properties gfProperties, String url) { + Gfsh gfsh = getGfsh(); + try { + SSLConfig sslConfig = SSLConfigurationFactory.getSSLConfigForComponent(gfProperties, + SecurableCommunicationChannel.WEB); + if (sslConfig.isEnabled()) { + configureHttpsURLConnection(sslConfig); if (url.startsWith("http:")) { url = url.replace("http:", "https:"); } } - Iterator<String> it = sslConfigProps.keySet().iterator(); - while (it.hasNext()) { - String secKey = it.next(); - securityProperties.put(secKey, sslConfigProps.get(secKey)); - } - // This is so that SSL termination results in https URLs being returned String query = (url.startsWith("https")) ? "?scheme=https" : ""; @@ -201,14 +261,14 @@ public class ConnectCommand implements GfshCommand { "Sending HTTP request for Link Index at (%1$s)...", url.concat("/index").concat(query))); LinkIndex linkIndex = - new SimpleHttpRequester(gfsh, CONNECT_LOCATOR_TIMEOUT_MS, securityProperties) + new SimpleHttpRequester(gfsh, CONNECT_LOCATOR_TIMEOUT_MS, (Map) gfProperties) .exchange(url.concat("/index").concat(query), LinkIndex.class); LogWrapper.getInstance() .warning(String.format("Received Link Index (%1$s)", linkIndex.toString())); HttpOperationInvoker operationInvoker = - new RestHttpOperationInvoker(linkIndex, gfsh, url, securityProperties); + new RestHttpOperationInvoker(linkIndex, gfsh, url, (Map) gfProperties); Initializer.init(operationInvoker); gfsh.setOperationInvoker(operationInvoker); @@ -226,244 +286,103 @@ public class ConnectCommand implements GfshCommand { // if it's security exception, and we already sent in username and password, still retuns the // connection error - if (userName != null) { + if (gfProperties.containsKey(ResourceConstants.USER_NAME)) { return handleExcpetion(e, null); } // otherwise, prompt for username and password and retry the conenction - try { - userName = gfsh.readText(CliStrings.CONNECT__USERNAME + ": "); - passwordToUse = gfsh.readPassword(CliStrings.CONNECT__PASSWORD + ": "); - return httpConnect(sslConfigProps, useSsl, url, userName, passwordToUse); - } catch (IOException ioe) { - return handleExcpetion(ioe, null); - } + gfProperties.setProperty(UserInputProperty.USERNAME.getKey(), + UserInputProperty.USERNAME.promptForAcceptableValue(gfsh)); + gfProperties.setProperty(UserInputProperty.PASSWORD.getKey(), + UserInputProperty.PASSWORD.promptForAcceptableValue(gfsh)); + return httpConnect(gfProperties, url); + } finally { Gfsh.redirectInternalJavaLoggers(); } } - private Result jmxConnect(Map<String, String> sslConfigProps, - ConnectionEndpoint memberRmiHostPort, ConnectionEndpoint locatorTcpHostPort, boolean useSsl, - String userName, String passwordToUse, String gfSecurityPropertiesPath, boolean retry) { - ConnectionEndpoint hostPortToConnect = null; + Result jmxConnect(Properties gfProperties, boolean useSsl, ConnectionEndpoint memberRmiHostPort, + ConnectionEndpoint locatorTcpHostPort, boolean retry) { + ConnectionEndpoint jmxHostPortToConnect = null; Gfsh gfsh = getGfsh(); try { - - // trying to find the hostPortToConnect, if rmi host port exists, use that, otherwise, use + // trying to find the rmi host and port, if rmi host port exists, use that, otherwise, use // locator to find the rmi host port if (memberRmiHostPort != null) { - hostPortToConnect = memberRmiHostPort; + jmxHostPortToConnect = memberRmiHostPort; } else { - // Props required to configure a SocketCreator with SSL. - // Used for gfsh->locator connection & not needed for gfsh->manager connection - if (useSsl || !sslConfigProps.isEmpty()) { - sslConfigProps.put(MCAST_PORT, String.valueOf(0)); - sslConfigProps.put(LOCATORS, ""); - - String sslInfoLogMsg = "Connecting to Locator via SSL."; - if (useSsl) { - sslInfoLogMsg = CliStrings.CONNECT__USE_SSL + " is set to true. " + sslInfoLogMsg; - } - gfsh.logToFile(sslInfoLogMsg, null); + if (useSsl) { + gfsh.logToFile( + CliStrings.CONNECT__USE_SSL + " is set to true. Connecting to Locator via SSL.", + null); } Gfsh.println(CliStrings.format(CliStrings.CONNECT__MSG__CONNECTING_TO_LOCATOR_AT_0, new Object[] {locatorTcpHostPort.toString(false)})); ConnectToLocatorResult connectToLocatorResult = connectToLocator(locatorTcpHostPort.getHost(), locatorTcpHostPort.getPort(), - CONNECT_LOCATOR_TIMEOUT_MS, sslConfigProps); - hostPortToConnect = connectToLocatorResult.getMemberEndpoint(); + CONNECT_LOCATOR_TIMEOUT_MS, gfProperties); + jmxHostPortToConnect = connectToLocatorResult.getMemberEndpoint(); // when locator is configured to use SSL (ssl-enabled=true) but manager is not // (jmx-manager-ssl=false) - if ((useSsl || !sslConfigProps.isEmpty()) - && !connectToLocatorResult.isJmxManagerSslEnabled()) { + if (useSsl && !connectToLocatorResult.isJmxManagerSslEnabled()) { gfsh.logInfo( CliStrings.CONNECT__USE_SSL + " is set to true. But JMX Manager doesn't support SSL, connecting without SSL.", null); - sslConfigProps.clear(); + useSsl = false; } } - if (!sslConfigProps.isEmpty()) { + if (useSsl) { gfsh.logToFile("Connecting to manager via SSL.", null); } // print out the connecting endpoint if (!retry) { Gfsh.println(CliStrings.format(CliStrings.CONNECT__MSG__CONNECTING_TO_MANAGER_AT_0, - new Object[] {hostPortToConnect.toString(false)})); + new Object[] {jmxHostPortToConnect.toString(false)})); } InfoResultData infoResultData = ResultBuilder.createInfoResultData(); - JmxOperationInvoker operationInvoker = - new JmxOperationInvoker(hostPortToConnect.getHost(), hostPortToConnect.getPort(), - userName, passwordToUse, sslConfigProps, gfSecurityPropertiesPath); + JmxOperationInvoker operationInvoker = new JmxOperationInvoker(jmxHostPortToConnect.getHost(), + jmxHostPortToConnect.getPort(), gfProperties); gfsh.setOperationInvoker(operationInvoker); - infoResultData.addLine( - CliStrings.format(CliStrings.CONNECT__MSG__SUCCESS, hostPortToConnect.toString(false))); - LogWrapper.getInstance().info( - CliStrings.format(CliStrings.CONNECT__MSG__SUCCESS, hostPortToConnect.toString(false))); + infoResultData.addLine(CliStrings.format(CliStrings.CONNECT__MSG__SUCCESS, + jmxHostPortToConnect.toString(false))); + LogWrapper.getInstance().info(CliStrings.format(CliStrings.CONNECT__MSG__SUCCESS, + jmxHostPortToConnect.toString(false))); return ResultBuilder.buildResult(infoResultData); } catch (Exception e) { // all other exceptions, just logs it and returns a connection error if (!(e instanceof SecurityException) && !(e instanceof AuthenticationFailedException)) { - return handleExcpetion(e, hostPortToConnect); + return handleExcpetion(e, jmxHostPortToConnect); } // if it's security exception, and we already sent in username and password, still returns the // connection error - if (userName != null) { - return handleExcpetion(e, hostPortToConnect); + if (gfProperties.containsKey(ResourceConstants.USER_NAME)) { + return handleExcpetion(e, jmxHostPortToConnect); } // otherwise, prompt for username and password and retry the conenction - try { - userName = gfsh.readText(CliStrings.CONNECT__USERNAME + ": "); - passwordToUse = gfsh.readPassword(CliStrings.CONNECT__PASSWORD + ": "); - // GEODE-2250 If no value for both username and password, at this point we need to error to - // avoid a stack overflow. - if (userName == null && passwordToUse == null) - return handleExcpetion(e, hostPortToConnect); - return jmxConnect(sslConfigProps, hostPortToConnect, null, useSsl, userName, passwordToUse, - gfSecurityPropertiesPath, true); - } catch (IOException ioe) { - return handleExcpetion(ioe, hostPortToConnect); - } + gfProperties.setProperty(UserInputProperty.USERNAME.getKey(), + UserInputProperty.USERNAME.promptForAcceptableValue(gfsh)); + gfProperties.setProperty(UserInputProperty.PASSWORD.getKey(), + UserInputProperty.PASSWORD.promptForAcceptableValue(gfsh)); + return jmxConnect(gfProperties, useSsl, jmxHostPortToConnect, null, true); + } finally { Gfsh.redirectInternalJavaLoggers(); } } - /** - * Common code to read SSL information. Used by JMX, Locator & HTTP mode connect - */ - private Map<String, String> readSSLConfiguration(boolean useSsl, String keystoreToUse, - String keystorePasswordToUse, String truststoreToUse, String truststorePasswordToUse, - String sslCiphersToUse, String sslProtocolsToUse, String gfSecurityPropertiesPath) - throws IOException { - - Gfsh gfshInstance = getGfsh(); - final Map<String, String> sslConfigProps = new LinkedHashMap<String, String>(); - - // JMX SSL Config 1: - // First from gfsecurity properties file if it's specified OR - // if the default gfsecurity.properties exists useSsl==true - if (useSsl || gfSecurityPropertiesPath != null) { - // reference to hold resolved gfSecurityPropertiesPath - String gfSecurityPropertiesPathToUse = CliUtil.resolvePathname(gfSecurityPropertiesPath); - URL gfSecurityPropertiesUrl = null; - - // Case 1: User has specified gfSecurity properties file - if (StringUtils.isNotBlank(gfSecurityPropertiesPathToUse)) { - // User specified gfSecurity properties doesn't exist - if (!IOUtils.isExistingPathname(gfSecurityPropertiesPathToUse)) { - gfshInstance - .printAsSevere(CliStrings.format(CliStrings.GEODE_0_PROPERTIES_1_NOT_FOUND_MESSAGE, - "Security ", gfSecurityPropertiesPathToUse)); - } else { - gfSecurityPropertiesUrl = new File(gfSecurityPropertiesPathToUse).toURI().toURL(); - } - } else if (useSsl && gfSecurityPropertiesPath == null) { - // Case 2: User has specified to useSsl but hasn't specified - // gfSecurity properties file. Use default "gfsecurity.properties" - // in current dir, user's home or classpath - gfSecurityPropertiesUrl = ShellCommands.getFileUrl("gfsecurity.properties"); - } - // if 'gfSecurityPropertiesPath' OR gfsecurity.properties has resolvable path - if (gfSecurityPropertiesUrl != null) { - gfshInstance.logToFile("Using security properties file : " - + CliUtil.decodeWithDefaultCharSet(gfSecurityPropertiesUrl.getPath()), null); - Map<String, String> gfsecurityProps = - ShellCommands.loadPropertiesFromURL(gfSecurityPropertiesUrl); - // command line options (if any) would override props in gfsecurity.properties - sslConfigProps.putAll(gfsecurityProps); - } - } - - int numTimesPrompted = 0; - /* - * Using do-while here for a case when --use-ssl=true is specified but no SSL options were - * specified & there was no gfsecurity properties specified or readable in default gfsh - * directory. - * - * NOTE: 2nd round of prompting is done only when sslConfigProps map is empty & useSsl is true - - * so we won't over-write any previous values. - */ - do { - // JMX SSL Config 2: Now read the options - if (numTimesPrompted > 0) { - Gfsh.println("Please specify these SSL Configuration properties: "); - } - - if (numTimesPrompted > 0) { - // NOTE: sslConfigProps map was empty - keystoreToUse = gfshInstance.readText(CliStrings.CONNECT__KEY_STORE + ": "); - } - if (keystoreToUse != null && keystoreToUse.length() > 0) { - if (keystorePasswordToUse == null || keystorePasswordToUse.length() == 0) { - // Check whether specified in gfsecurity props earlier - keystorePasswordToUse = sslConfigProps.get(SSL_KEYSTORE_PASSWORD); - if (keystorePasswordToUse == null || keystorePasswordToUse.length() == 0) { - // not even in properties file, prompt user for it - keystorePasswordToUse = - gfshInstance.readPassword(CliStrings.CONNECT__KEY_STORE_PASSWORD + ": "); - sslConfigProps.put(SSL_KEYSTORE_PASSWORD, keystorePasswordToUse); - } - } else {// For cases where password is already part of command option - sslConfigProps.put(SSL_KEYSTORE_PASSWORD, keystorePasswordToUse); - } - sslConfigProps.put(SSL_KEYSTORE, keystoreToUse); - } - - if (numTimesPrompted > 0) { - truststoreToUse = gfshInstance.readText(CliStrings.CONNECT__TRUST_STORE + ": "); - } - if (truststoreToUse != null && truststoreToUse.length() > 0) { - if (truststorePasswordToUse == null || truststorePasswordToUse.length() == 0) { - // Check whether specified in gfsecurity props earlier? - truststorePasswordToUse = sslConfigProps.get(SSL_TRUSTSTORE_PASSWORD); - if (truststorePasswordToUse == null || truststorePasswordToUse.length() == 0) { - // not even in properties file, prompt user for it - truststorePasswordToUse = - gfshInstance.readPassword(CliStrings.CONNECT__TRUST_STORE_PASSWORD + ": "); - sslConfigProps.put(SSL_TRUSTSTORE_PASSWORD, truststorePasswordToUse); - } - } else {// For cases where password is already part of command option - sslConfigProps.put(SSL_TRUSTSTORE_PASSWORD, truststorePasswordToUse); - } - sslConfigProps.put(SSL_TRUSTSTORE, truststoreToUse); - } - - if (numTimesPrompted > 0) { - sslCiphersToUse = gfshInstance.readText(CliStrings.CONNECT__SSL_CIPHERS + ": "); - } - if (sslCiphersToUse != null && sslCiphersToUse.length() > 0) { - // sslConfigProps.put(DistributionConfig.CLUSTER_SSL_CIPHERS_NAME, sslCiphersToUse); - sslConfigProps.put(SSL_ENABLED_CIPHERS, sslCiphersToUse); - } - - if (numTimesPrompted > 0) { - sslProtocolsToUse = gfshInstance.readText(CliStrings.CONNECT__SSL_PROTOCOLS + ": "); - } - if (sslProtocolsToUse != null && sslProtocolsToUse.length() > 0) { - // sslConfigProps.put(DistributionConfig.CLUSTER_SSL_PROTOCOLS_NAME, sslProtocolsToUse); - sslConfigProps.put(SSL_ENABLED_PROTOCOLS, sslProtocolsToUse); - } - - // SSL is required to be used but no SSL config found - } while (useSsl && sslConfigProps.isEmpty() && (0 == numTimesPrompted++) - && !gfshInstance.isQuietMode()); - return sslConfigProps; - } - - public static ConnectToLocatorResult connectToLocator(String host, int port, int timeout, - Map<String, String> props) throws IOException { + Properties props) throws IOException, ClassNotFoundException { // register DSFID types first; invoked explicitly so that all message type // initializations do not happen in first deserialization on a possibly // "precious" thread @@ -497,48 +416,34 @@ public class ConnectCommand implements GfshCommand { locatorResponse.isJmxManagerSslEnabled()); } - private void configureHttpsURLConnection(Map<String, String> sslConfigProps) throws Exception { - String keystoreToUse = sslConfigProps.get(SSL_KEYSTORE); - String keystorePasswordToUse = sslConfigProps.get(SSL_KEYSTORE_PASSWORD); - String truststoreToUse = sslConfigProps.get(SSL_TRUSTSTORE); - String truststorePasswordToUse = sslConfigProps.get(SSL_TRUSTSTORE_PASSWORD); - // Ciphers are not passed to HttpsURLConnection. Could not find a clean way - // to pass this attribute to socket layer (see #51645) - String sslCiphersToUse = sslConfigProps.get(SSL_CIPHERS); - String sslProtocolsToUse = sslConfigProps.get(SSL_PROTOCOLS); - - // Commenting the code to set cipher suites in GFSH rest connect (see #51645) - /* - * if(sslCiphersToUse != null){ System.setProperty("https.cipherSuites", sslCiphersToUse); } - */ + private void configureHttpsURLConnection(SSLConfig sslConfig) throws Exception { FileInputStream keyStoreStream = null; FileInputStream trustStoreStream = null; try { - KeyManagerFactory keyManagerFactory = null; - if (StringUtils.isNotBlank(keystoreToUse)) { - KeyStore clientKeys = KeyStore.getInstance("JKS"); - keyStoreStream = new FileInputStream(keystoreToUse); - clientKeys.load(keyStoreStream, keystorePasswordToUse.toCharArray()); + if (StringUtils.isNotBlank(sslConfig.getKeystore())) { + KeyStore clientKeys = KeyStore.getInstance(sslConfig.getKeystoreType()); + keyStoreStream = new FileInputStream(sslConfig.getKeystore()); + clientKeys.load(keyStoreStream, sslConfig.getKeystorePassword().toCharArray()); keyManagerFactory = KeyManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); - keyManagerFactory.init(clientKeys, keystorePasswordToUse.toCharArray()); + keyManagerFactory.init(clientKeys, sslConfig.getKeystorePassword().toCharArray()); } // load server public key TrustManagerFactory trustManagerFactory = null; - if (StringUtils.isNotBlank(truststoreToUse)) { - KeyStore serverPub = KeyStore.getInstance("JKS"); - trustStoreStream = new FileInputStream(truststoreToUse); - serverPub.load(trustStoreStream, truststorePasswordToUse.toCharArray()); + if (StringUtils.isNotBlank(sslConfig.getTruststore())) { + KeyStore serverPub = KeyStore.getInstance(sslConfig.getTruststoreType()); + trustStoreStream = new FileInputStream(sslConfig.getTruststore()); + serverPub.load(trustStoreStream, sslConfig.getTruststorePassword().toCharArray()); trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); trustManagerFactory.init(serverPub); } SSLContext ssl = - SSLContext.getInstance(SSLUtil.getSSLAlgo(SSLUtil.readArray(sslProtocolsToUse))); + SSLContext.getInstance(SSLUtil.getSSLAlgo(SSLUtil.readArray(sslConfig.getProtocols()))); ssl.init(keyManagerFactory != null ? keyManagerFactory.getKeyManagers() : null, trustManagerFactory != null ? trustManagerFactory.getTrustManagers() : null, @@ -552,13 +457,9 @@ public class ConnectCommand implements GfshCommand { if (trustStoreStream != null) { trustStoreStream.close(); } - } - - } - private Result handleExcpetion(Exception e, ConnectionEndpoint hostPortToConnect) { String errorMessage = e.getMessage(); if (hostPortToConnect != null) { @@ -568,5 +469,4 @@ public class ConnectCommand implements GfshCommand { LogWrapper.getInstance().severe(errorMessage, e); return ResultBuilder.createConnectionErrorResult(errorMessage); } - } http://git-wip-us.apache.org/repos/asf/geode/blob/7352fcc7/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ShellCommands.java ---------------------------------------------------------------------- diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ShellCommands.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ShellCommands.java index 1aea253..84ee5db 100644 --- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ShellCommands.java +++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ShellCommands.java @@ -25,10 +25,7 @@ import java.io.InputStreamReader; import java.io.Writer; import java.net.MalformedURLException; import java.net.URL; -import java.util.Collections; -import java.util.HashSet; import java.util.Iterator; -import java.util.LinkedHashMap; import java.util.Map; import java.util.Map.Entry; import java.util.Properties; @@ -38,7 +35,6 @@ import org.springframework.shell.core.ExitShellRequest; import org.springframework.shell.core.annotation.CliCommand; import org.springframework.shell.core.annotation.CliOption; -import org.apache.geode.distributed.internal.DistributionConfig; import org.apache.geode.internal.ClassPathLoader; import org.apache.geode.internal.lang.SystemUtils; import org.apache.geode.internal.util.IOUtils; @@ -62,52 +58,43 @@ import org.apache.geode.management.internal.cli.shell.jline.GfshHistory; * @since GemFire 7.0 */ public class ShellCommands implements GfshCommand { + static Properties loadProperties(URL url) { + Properties properties = new Properties(); - /* package-private */ - static Map<String, String> loadPropertiesFromURL(URL gfSecurityPropertiesUrl) { - Map<String, String> propsMap = Collections.emptyMap(); + if (url == null) { + return properties; + } - if (gfSecurityPropertiesUrl != null) { - InputStream inputStream = null; - try { - Properties props = new Properties(); - inputStream = gfSecurityPropertiesUrl.openStream(); - props.load(inputStream); - if (!props.isEmpty()) { - Set<String> jmxSpecificProps = new HashSet<String>(); - propsMap = new LinkedHashMap<String, String>(); - Set<Entry<Object, Object>> entrySet = props.entrySet(); - for (Entry<Object, Object> entry : entrySet) { - - String key = (String) entry.getKey(); - if (key.endsWith(DistributionConfig.JMX_SSL_PROPS_SUFFIX)) { - key = - key.substring(0, key.length() - DistributionConfig.JMX_SSL_PROPS_SUFFIX.length()); - jmxSpecificProps.add(key); - - propsMap.put(key, (String) entry.getValue()); - } else if (!jmxSpecificProps.contains(key)) {// Prefer properties ending with "-jmx" - // over default SSL props. - propsMap.put(key, (String) entry.getValue()); - } - } - props.clear(); - jmxSpecificProps.clear(); - } - } catch (IOException io) { - throw new RuntimeException( - CliStrings.format(CliStrings.CONNECT__MSG__COULD_NOT_READ_CONFIG_FROM_0, - CliUtil.decodeWithDefaultCharSet(gfSecurityPropertiesUrl.getPath())), - io); - } finally { - IOUtils.close(inputStream); - } + try (InputStream inputStream = url.openStream()) { + properties.load(inputStream); + } catch (IOException io) { + throw new RuntimeException( + CliStrings.format(CliStrings.CONNECT__MSG__COULD_NOT_READ_CONFIG_FROM_0, + CliUtil.decodeWithDefaultCharSet(url.getPath())), + io); + } + + return properties; + } + + static Properties loadProperties(File propertyFile) { + try { + return loadProperties(propertyFile.toURI().toURL()); + } catch (MalformedURLException e) { + throw new RuntimeException( + CliStrings.format("Failed to load configuration properties from pathname (%1$s)!", + propertyFile.getAbsolutePath()), + e); } - return propsMap; } - // Copied from DistributedSystem.java - public static URL getFileUrl(String fileName) { + /** + * try to find the file in the current dir or the user home or the classpath in this order + * + * @param fileName the name of the file + * @return URL if the file is found, otherwise null + */ + public static URL searchFile(String fileName) { File file = new File(fileName); if (file.exists()) { http://git-wip-us.apache.org/repos/asf/geode/blob/7352fcc7/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/StartLocatorCommand.java ---------------------------------------------------------------------- diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/StartLocatorCommand.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/StartLocatorCommand.java index 5b289a5..72ccfbb 100644 --- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/StartLocatorCommand.java +++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/StartLocatorCommand.java @@ -17,17 +17,13 @@ package org.apache.geode.management.internal.cli.commands; import java.io.File; import java.net.InetAddress; -import java.net.MalformedURLException; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import java.util.Map; import java.util.Properties; import java.util.concurrent.TimeUnit; import javax.management.MalformedObjectNameException; import javax.net.ssl.SSLException; -import javax.net.ssl.SSLHandshakeException; import org.springframework.shell.core.annotation.CliCommand; import org.springframework.shell.core.annotation.CliOption; @@ -47,9 +43,7 @@ import org.apache.geode.internal.util.IOUtils; import org.apache.geode.management.cli.CliMetaData; import org.apache.geode.management.cli.ConverterHint; import org.apache.geode.management.cli.Result; -import org.apache.geode.management.internal.cli.CliUtil; import org.apache.geode.management.internal.cli.GfshParser; -import org.apache.geode.management.internal.cli.LogWrapper; import org.apache.geode.management.internal.cli.domain.ConnectToLocatorResult; import org.apache.geode.management.internal.cli.i18n.CliStrings; import org.apache.geode.management.internal.cli.result.InfoResultData; @@ -100,12 +94,11 @@ public class StartLocatorCommand implements GfshCommand { help = CliStrings.START_LOCATOR__PORT__HELP) final Integer port, @CliOption(key = CliStrings.START_LOCATOR__DIR, help = CliStrings.START_LOCATOR__DIR__HELP) String workingDirectory, - @CliOption(key = CliStrings.START_LOCATOR__PROPERTIES, - optionContext = ConverterHint.FILE_PATH, - help = CliStrings.START_LOCATOR__PROPERTIES__HELP) String gemfirePropertiesPathname, + @CliOption(key = CliStrings.START_LOCATOR__PROPERTIES, optionContext = ConverterHint.FILE, + help = CliStrings.START_LOCATOR__PROPERTIES__HELP) File gemfirePropertiesFile, @CliOption(key = CliStrings.START_LOCATOR__SECURITY_PROPERTIES, - optionContext = ConverterHint.FILE_PATH, - help = CliStrings.START_LOCATOR__SECURITY_PROPERTIES__HELP) String gemfireSecurityPropertiesPathname, + optionContext = ConverterHint.FILE, + help = CliStrings.START_LOCATOR__SECURITY_PROPERTIES__HELP) File gemfireSecurityPropertiesFile, @CliOption(key = CliStrings.START_LOCATOR__INITIALHEAP, help = CliStrings.START_LOCATOR__INITIALHEAP__HELP) final String initialHeap, @CliOption(key = CliStrings.START_LOCATOR__MAXHEAP, @@ -135,23 +128,16 @@ public class StartLocatorCommand implements GfshCommand { workingDirectory = StartMemberUtils.resolveWorkingDir(workingDirectory, memberName); - gemfirePropertiesPathname = CliUtil.resolvePathname(gemfirePropertiesPathname); - - if (StringUtils.isNotBlank(gemfirePropertiesPathname) - && !IOUtils.isExistingPathname(gemfirePropertiesPathname)) { + if (gemfirePropertiesFile != null && !gemfirePropertiesFile.exists()) { return ResultBuilder.createUserErrorResult( CliStrings.format(CliStrings.GEODE_0_PROPERTIES_1_NOT_FOUND_MESSAGE, StringUtils.EMPTY, - gemfirePropertiesPathname)); + gemfirePropertiesFile.getAbsolutePath())); } - gemfireSecurityPropertiesPathname = - CliUtil.resolvePathname(gemfireSecurityPropertiesPathname); - - if (StringUtils.isNotBlank(gemfireSecurityPropertiesPathname) - && !IOUtils.isExistingPathname(gemfireSecurityPropertiesPathname)) { + if (gemfireSecurityPropertiesFile != null && !gemfireSecurityPropertiesFile.exists()) { return ResultBuilder.createUserErrorResult( CliStrings.format(CliStrings.GEODE_0_PROPERTIES_1_NOT_FOUND_MESSAGE, "Security ", - gemfireSecurityPropertiesPathname)); + gemfireSecurityPropertiesFile.getAbsolutePath())); } File locatorPidFile = new File(workingDirectory, ProcessType.LOCATOR.getPidFileName()); @@ -200,8 +186,8 @@ public class StartLocatorCommand implements GfshCommand { LocatorLauncher locatorLauncher = locatorLauncherBuilder.build(); String[] locatorCommandLine = createStartLocatorCommandLine(locatorLauncher, - gemfirePropertiesPathname, gemfireSecurityPropertiesPathname, gemfireProperties, - classpath, includeSystemClasspath, jvmArgsOpts, initialHeap, maxHeap); + gemfirePropertiesFile, gemfireSecurityPropertiesFile, gemfireProperties, classpath, + includeSystemClasspath, jvmArgsOpts, initialHeap, maxHeap); final Process locatorProcess = new ProcessBuilder(locatorCommandLine) .directory(new File(locatorLauncher.getWorkingDirectory())).start(); @@ -240,7 +226,7 @@ public class StartLocatorCommand implements GfshCommand { new File(locatorLauncher.getWorkingDirectory()))), null); - locatorState = LocatorLauncher.LocatorState.fromDirectory(workingDirectory, memberName); + LocatorLauncher.LocatorState.fromDirectory(workingDirectory, memberName); do { if (locatorProcess.isAlive()) { Gfsh.print("."); @@ -289,33 +275,39 @@ public class StartLocatorCommand implements GfshCommand { if (asyncStart) { infoResultData.addLine( String.format(CliStrings.ASYNC_PROCESS_LAUNCH_MESSAGE, CliStrings.LOCATOR_TERM_NAME)); + return ResultBuilder.buildResult(infoResultData); + } + + infoResultData.addLine(locatorState.toString()); + String locatorHostName; + InetAddress bindAddr = locatorLauncher.getBindAddress(); + if (bindAddr != null) { + locatorHostName = bindAddr.getCanonicalHostName(); } else { - infoResultData.addLine(locatorState.toString()); - - String locatorHostName; - InetAddress bindAddr = locatorLauncher.getBindAddress(); - if (bindAddr != null) { - locatorHostName = bindAddr.getCanonicalHostName(); - } else { - locatorHostName = StringUtils.defaultIfBlank(locatorLauncher.getHostnameForClients(), - HostUtils.getLocalHost()); - } + locatorHostName = StringUtils.defaultIfBlank(locatorLauncher.getHostnameForClients(), + HostUtils.getLocalHost()); + } - int locatorPort = Integer.parseInt(locatorState.getPort()); + int locatorPort = Integer.parseInt(locatorState.getPort()); - // AUTO-CONNECT - // If the connect succeeds add the connected message to the result, - // Else, ask the user to use the "connect" command to connect to the Locator. - if (shouldAutoConnect(connect)) { - doAutoConnect(locatorHostName, locatorPort, gemfirePropertiesPathname, - gemfireSecurityPropertiesPathname, infoResultData); - } - // Report on the state of the Shared Configuration service if enabled... - if (enableSharedConfiguration) { - infoResultData.addLine( - ClusterConfigurationStatusRetriever.fromLocator(locatorHostName, locatorPort)); - } + + ConnectCommand connectCommand = new ConnectCommand(); + Properties configProperties = connectCommand.resolveSslProperties(getGfsh(), false, + gemfirePropertiesFile, gemfireSecurityPropertiesFile); + + // AUTO-CONNECT + // If the connect succeeds add the connected message to the result, + // Else, ask the user to use the "connect" command to connect to the Locator. + if (shouldAutoConnect(connect)) { + doAutoConnect(locatorHostName, locatorPort, configProperties, infoResultData); } + + // Report on the state of the Shared Configuration service if enabled... + if (enableSharedConfiguration) { + infoResultData.addLine(ClusterConfigurationStatusRetriever.fromLocator(locatorHostName, + locatorPort, configProperties)); + } + return ResultBuilder.buildResult(infoResultData); } catch (IllegalArgumentException e) { String message = e.getMessage(); @@ -348,38 +340,29 @@ public class StartLocatorCommand implements GfshCommand { // With execute option (-e), there could be multiple commands which might presume that a prior // "start locator" has formed the connection. private boolean shouldAutoConnect(final boolean connect) { - return (connect && !(getGfsh() == null || isConnectedAndReady())); + return (connect && !isConnectedAndReady()); } private void doAutoConnect(final String locatorHostname, final int locatorPort, - final String gemfirePropertiesPathname, final String gemfireSecurityPropertiesPathname, - final InfoResultData infoResultData) { + final Properties configurationProperties, final InfoResultData infoResultData) { boolean connectSuccess = false; boolean jmxManagerAuthEnabled = false; boolean jmxManagerSslEnabled = false; - Map<String, String> configurationProperties = loadConfigurationProperties( - gemfireSecurityPropertiesPathname, loadConfigurationProperties(gemfirePropertiesPathname)); - Map<String, String> locatorConfigurationProperties = new HashMap<>(configurationProperties); - String responseFailureMessage = null; for (int attempts = 0; (attempts < 10 && !connectSuccess); attempts++) { try { ConnectToLocatorResult connectToLocatorResult = ConnectCommand.connectToLocator(locatorHostname, locatorPort, - ConnectCommand.CONNECT_LOCATOR_TIMEOUT_MS / 4, locatorConfigurationProperties); + ConnectCommand.CONNECT_LOCATOR_TIMEOUT_MS / 4, configurationProperties); ConnectionEndpoint memberEndpoint = connectToLocatorResult.getMemberEndpoint(); jmxManagerSslEnabled = connectToLocatorResult.isJmxManagerSslEnabled(); - if (!jmxManagerSslEnabled) { - configurationProperties.clear(); - } - getGfsh().setOperationInvoker(new JmxOperationInvoker(memberEndpoint.getHost(), - memberEndpoint.getPort(), null, null, configurationProperties, null)); + memberEndpoint.getPort(), configurationProperties)); String shellAndLogMessage = CliStrings.format(CliStrings.CONNECT__MSG__SUCCESS, "JMX Manager " + memberEndpoint.toString(false)); @@ -403,16 +386,9 @@ public class StartLocatorCommand implements GfshCommand { jmxManagerAuthEnabled = true; break; // no need to continue after AuthenticationFailedException } catch (SSLException ignore) { - if (ignore instanceof SSLHandshakeException) { - // try to connect again without SSL since the SSL handshake failed implying a plain text - // connection... - locatorConfigurationProperties.clear(); - } else { - // another type of SSL error occurred (possibly a configuration issue); pass the buck... - getGfsh().logToFile(ignore.getMessage(), ignore); - responseFailureMessage = "Check your SSL configuration and try again."; - break; - } + // another type of SSL error occurred (possibly a configuration issue); pass the buck... + getGfsh().logToFile(ignore.getMessage(), ignore); + responseFailureMessage = "Check your SSL configuration and try again."; } catch (Exception ignore) { getGfsh().logToFile(ignore.getMessage(), ignore); responseFailureMessage = "Failed to connect; unknown cause: " + ignore.getMessage(); @@ -431,30 +407,6 @@ public class StartLocatorCommand implements GfshCommand { } - private Map<String, String> loadConfigurationProperties( - final String configurationPropertiesPathname) { - return loadConfigurationProperties(configurationPropertiesPathname, null); - } - - private Map<String, String> loadConfigurationProperties( - final String configurationPropertiesPathname, Map<String, String> configurationProperties) { - configurationProperties = - (configurationProperties != null ? configurationProperties : new HashMap<>()); - - if (IOUtils.isExistingPathname(configurationPropertiesPathname)) { - try { - configurationProperties.putAll(ShellCommands - .loadPropertiesFromURL(new File(configurationPropertiesPathname).toURI().toURL())); - } catch (MalformedURLException ignore) { - LogWrapper.getInstance() - .warning(String.format( - "Failed to load GemFire configuration properties from pathname (%1$s)!", - configurationPropertiesPathname), ignore); - } - } - return configurationProperties; - } - private void doOnConnectionFailure(final String locatorHostName, final int locatorPort, final boolean jmxManagerAuthEnabled, final boolean jmxManagerSslEnabled, final InfoResultData infoResultData) { @@ -481,7 +433,7 @@ public class StartLocatorCommand implements GfshCommand { } String[] createStartLocatorCommandLine(final LocatorLauncher launcher, - final String gemfirePropertiesPathname, final String gemfireSecurityPropertiesPathname, + final File gemfirePropertiesFile, final File gemfireSecurityPropertiesFile, final Properties gemfireProperties, final String userClasspath, final Boolean includeSystemClasspath, final String[] jvmArgsOpts, final String initialHeap, final String maxHeap) throws MalformedObjectNameException { @@ -494,8 +446,8 @@ public class StartLocatorCommand implements GfshCommand { .add(getLocatorClasspath(Boolean.TRUE.equals(includeSystemClasspath), userClasspath)); StartMemberUtils.addCurrentLocators(this, commandLine, gemfireProperties); - StartMemberUtils.addGemFirePropertyFile(commandLine, gemfirePropertiesPathname); - StartMemberUtils.addGemFireSecurityPropertyFile(commandLine, gemfireSecurityPropertiesPathname); + StartMemberUtils.addGemFirePropertyFile(commandLine, gemfirePropertiesFile); + StartMemberUtils.addGemFireSecurityPropertyFile(commandLine, gemfireSecurityPropertiesFile); StartMemberUtils.addGemFireSystemProperties(commandLine, gemfireProperties); StartMemberUtils.addJvmArgumentsAndOptions(commandLine, jvmArgsOpts); StartMemberUtils.addInitialHeap(commandLine, initialHeap);