BROOKLYN-162 - apply org.apache package prefix to jmx util/agent projects
Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/e6ac83be Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/e6ac83be Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/e6ac83be Branch: refs/heads/master Commit: e6ac83be8f4e5c0e7dc70c46fa6fb854d90428e7 Parents: e114a25 Author: Alex Heneveld <[email protected]> Authored: Tue Aug 18 14:10:57 2015 +0100 Committer: Alex Heneveld <[email protected]> Committed: Tue Aug 18 14:51:57 2015 +0100 ---------------------------------------------------------------------- .../java/brooklyn/entity/java/JmxSupport.java | 5 +- .../brooklyn/entity/java/JmxmpSslSupport.java | 3 +- .../java/brooklyn/event/feed/jmx/JmxHelper.java | 2 +- .../java/brooklyn/entity/java/JavaOptsTest.java | 3 +- .../entity/java/VanillaJavaAppTest.java | 3 +- utils/jmx/jmxmp-ssl-agent/pom.xml | 4 +- .../brooklyn/util/jmx/jmxmp/JmxmpAgent.java | 335 ------------------ .../brooklyn/util/jmx/jmxmp/JmxmpAgent.java | 337 +++++++++++++++++++ .../util/jmx/jmxmp/JmxmpAgentSslTest.java | 256 -------------- .../brooklyn/util/jmx/jmxmp/JmxmpClient.java | 88 ----- .../util/jmx/jmxmp/JmxmpAgentSslTest.java | 257 ++++++++++++++ .../brooklyn/util/jmx/jmxmp/JmxmpClient.java | 89 +++++ utils/jmx/jmxrmi-agent/pom.xml | 4 +- .../brooklyn/util/jmx/jmxrmi/JmxRmiAgent.java | 188 ----------- .../brooklyn/util/jmx/jmxrmi/JmxRmiAgent.java | 190 +++++++++++ .../brooklyn/util/jmx/jmxrmi/JmxRmiClient.java | 47 --- .../brooklyn/util/jmx/jmxrmi/JmxRmiClient.java | 47 +++ 17 files changed, 930 insertions(+), 928 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e6ac83be/software/base/src/main/java/brooklyn/entity/java/JmxSupport.java ---------------------------------------------------------------------- diff --git a/software/base/src/main/java/brooklyn/entity/java/JmxSupport.java b/software/base/src/main/java/brooklyn/entity/java/JmxSupport.java index b519804..58b148b 100644 --- a/software/base/src/main/java/brooklyn/entity/java/JmxSupport.java +++ b/software/base/src/main/java/brooklyn/entity/java/JmxSupport.java @@ -43,14 +43,13 @@ import org.apache.brooklyn.location.basic.SshMachineLocation; import org.apache.brooklyn.util.collections.MutableList; import org.apache.brooklyn.util.collections.MutableMap; import org.apache.brooklyn.util.guava.Maybe; +import org.apache.brooklyn.util.jmx.jmxmp.JmxmpAgent; +import org.apache.brooklyn.util.jmx.jmxrmi.JmxRmiAgent; import org.apache.brooklyn.util.maven.MavenArtifact; import org.apache.brooklyn.util.maven.MavenRetriever; import org.apache.brooklyn.util.net.Urls; import org.apache.brooklyn.util.text.Strings; -import brooklyn.util.jmx.jmxmp.JmxmpAgent; -import brooklyn.util.jmx.jmxrmi.JmxRmiAgent; - import com.google.common.base.Preconditions; import com.google.common.net.HostAndPort; http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e6ac83be/software/base/src/main/java/brooklyn/entity/java/JmxmpSslSupport.java ---------------------------------------------------------------------- diff --git a/software/base/src/main/java/brooklyn/entity/java/JmxmpSslSupport.java b/software/base/src/main/java/brooklyn/entity/java/JmxmpSslSupport.java index 51587ab..99601e8 100644 --- a/software/base/src/main/java/brooklyn/entity/java/JmxmpSslSupport.java +++ b/software/base/src/main/java/brooklyn/entity/java/JmxmpSslSupport.java @@ -31,10 +31,9 @@ import org.apache.brooklyn.core.util.crypto.SecureKeys; import org.apache.brooklyn.core.util.task.Tasks; import org.apache.brooklyn.util.collections.MutableMap.Builder; import org.apache.brooklyn.util.exceptions.Exceptions; +import org.apache.brooklyn.util.jmx.jmxmp.JmxmpAgent; import org.apache.brooklyn.util.net.Urls; -import brooklyn.util.jmx.jmxmp.JmxmpAgent; - import com.google.common.base.Preconditions; public class JmxmpSslSupport { http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e6ac83be/software/base/src/main/java/brooklyn/event/feed/jmx/JmxHelper.java ---------------------------------------------------------------------- diff --git a/software/base/src/main/java/brooklyn/event/feed/jmx/JmxHelper.java b/software/base/src/main/java/brooklyn/event/feed/jmx/JmxHelper.java index 7a4a3a0..4438c2d 100644 --- a/software/base/src/main/java/brooklyn/event/feed/jmx/JmxHelper.java +++ b/software/base/src/main/java/brooklyn/event/feed/jmx/JmxHelper.java @@ -65,6 +65,7 @@ import org.apache.brooklyn.core.util.crypto.SecureKeys; import org.apache.brooklyn.util.crypto.SslTrustUtils; import org.apache.brooklyn.util.exceptions.Exceptions; import org.apache.brooklyn.util.exceptions.RuntimeInterruptedException; +import org.apache.brooklyn.util.jmx.jmxmp.JmxmpAgent; import org.apache.brooklyn.util.repeat.Repeater; import org.apache.brooklyn.util.time.Duration; import org.apache.brooklyn.util.time.Time; @@ -73,7 +74,6 @@ import org.slf4j.LoggerFactory; import brooklyn.entity.java.JmxSupport; import brooklyn.entity.java.UsesJmx; -import brooklyn.util.jmx.jmxmp.JmxmpAgent; import com.google.common.base.Preconditions; import com.google.common.base.Throwables; http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e6ac83be/software/base/src/test/java/brooklyn/entity/java/JavaOptsTest.java ---------------------------------------------------------------------- diff --git a/software/base/src/test/java/brooklyn/entity/java/JavaOptsTest.java b/software/base/src/test/java/brooklyn/entity/java/JavaOptsTest.java index bfe8af8..0bc08b0 100644 --- a/software/base/src/test/java/brooklyn/entity/java/JavaOptsTest.java +++ b/software/base/src/test/java/brooklyn/entity/java/JavaOptsTest.java @@ -46,10 +46,9 @@ import org.apache.brooklyn.location.basic.SshMachineLocation; import org.apache.brooklyn.util.collections.MutableList; import org.apache.brooklyn.util.collections.MutableMap; import org.apache.brooklyn.util.collections.MutableSet; +import org.apache.brooklyn.util.jmx.jmxmp.JmxmpAgent; import org.apache.brooklyn.util.text.Strings; -import brooklyn.util.jmx.jmxmp.JmxmpAgent; - import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.MapDifference.ValueDifference; http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e6ac83be/software/base/src/test/java/brooklyn/entity/java/VanillaJavaAppTest.java ---------------------------------------------------------------------- diff --git a/software/base/src/test/java/brooklyn/entity/java/VanillaJavaAppTest.java b/software/base/src/test/java/brooklyn/entity/java/VanillaJavaAppTest.java index da65c68..c0fd3e3 100644 --- a/software/base/src/test/java/brooklyn/entity/java/VanillaJavaAppTest.java +++ b/software/base/src/test/java/brooklyn/entity/java/VanillaJavaAppTest.java @@ -50,6 +50,7 @@ import org.apache.brooklyn.test.Asserts; import org.apache.brooklyn.test.entity.TestApplication; import org.apache.brooklyn.util.collections.MutableMap; import org.apache.brooklyn.util.crypto.SslTrustUtils; +import org.apache.brooklyn.util.jmx.jmxmp.JmxmpAgent; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.testng.annotations.AfterMethod; @@ -63,8 +64,6 @@ import brooklyn.event.feed.jmx.JmxHelper; import org.apache.brooklyn.location.basic.LocalhostMachineProvisioningLocation; import org.apache.brooklyn.location.basic.PortRanges; -import brooklyn.util.jmx.jmxmp.JmxmpAgent; - import com.google.common.base.Predicate; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e6ac83be/utils/jmx/jmxmp-ssl-agent/pom.xml ---------------------------------------------------------------------- diff --git a/utils/jmx/jmxmp-ssl-agent/pom.xml b/utils/jmx/jmxmp-ssl-agent/pom.xml index 10a45d9..77b5e41 100644 --- a/utils/jmx/jmxmp-ssl-agent/pom.xml +++ b/utils/jmx/jmxmp-ssl-agent/pom.xml @@ -107,8 +107,8 @@ <configuration> <archive> <manifestEntries> - <Premain-Class>brooklyn.util.jmx.jmxmp.JmxmpAgent</Premain-Class> - <Agent-Class>brooklyn.util.jmx.jmxmp.JmxmpAgent</Agent-Class> + <Premain-Class>org.apache.brooklyn.util.jmx.jmxmp.JmxmpAgent</Premain-Class> + <Agent-Class>org.apache.brooklyn.util.jmx.jmxmp.JmxmpAgent</Agent-Class> </manifestEntries> </archive> </configuration> http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e6ac83be/utils/jmx/jmxmp-ssl-agent/src/main/java/brooklyn/util/jmx/jmxmp/JmxmpAgent.java ---------------------------------------------------------------------- diff --git a/utils/jmx/jmxmp-ssl-agent/src/main/java/brooklyn/util/jmx/jmxmp/JmxmpAgent.java b/utils/jmx/jmxmp-ssl-agent/src/main/java/brooklyn/util/jmx/jmxmp/JmxmpAgent.java deleted file mode 100644 index f9697f8..0000000 --- a/utils/jmx/jmxmp-ssl-agent/src/main/java/brooklyn/util/jmx/jmxmp/JmxmpAgent.java +++ /dev/null @@ -1,335 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package brooklyn.util.jmx.jmxmp; - -import java.io.FileInputStream; -import java.lang.management.ManagementFactory; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.rmi.registry.LocateRegistry; -import java.security.KeyStore; -import java.security.cert.X509Certificate; -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Properties; - -import javax.management.MBeanServer; -import javax.management.remote.JMXConnectorServer; -import javax.management.remote.JMXConnectorServerFactory; -import javax.management.remote.JMXServiceURL; -import javax.management.remote.rmi.RMIConnectorServer; -import javax.net.ssl.KeyManagerFactory; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLSocketFactory; -import javax.net.ssl.TrustManager; -import javax.net.ssl.TrustManagerFactory; -import javax.net.ssl.X509TrustManager; - - -/** - * This exposes JMX access over JMXMP, suitable for high-security environments, - * with support for going through firewalls as well as encrypting and authenticating securely. - * <p> - * Listens on 11099 unless overridden by system property brooklyn.jmxmp.port. - * <p> - * Use the usual com.sun.management.jmxremote.ssl to enable both SSL _and_ authentication - * (setting brooklyn.jmxmp.ssl.authenticate false if you need to disable authentication for some reason); - * unless you disable client-side server authentication you will need to supply brooklyn.jmxmp.ssl.keyStore, - * and similarly unless server-side client auth is off you'll need the corresponding trustStore - * (both pointing to files on the local file system). - * <p> - * Service comes up on: service:jmx:jmxmp://${HOSTNAME}:${PORT} - * <p> - * If {@link #RMI_REGISTRY_PORT_PROPERTY} is also set, this agent will start a normal JMX/RMI server bound to - * all interfaces, which is contactable on: service:jmx:rmi:///jndi/rmi://${HOSTNAME}:${RMI_REGISTRY_PORT}/jmxrmi - * <p> - * NB: To use JConsole with this endpoing, you need the jmxremote_optional JAR, and the - * following command (even more complicated if using SSL): - * java -classpath $JAVA_HOME/lib/jconsole.jar:$HOME/.m2/repository/javax/management/jmxremote_optional/1.0.1_04/jmxremote_optional-1.0.1_04.jar sun.tools.jconsole.JConsole - */ -public class JmxmpAgent { - - /** port to listen on; default to {@link #JMXMP_DEFAULT_PORT} */ - public static final String JMXMP_PORT_PROPERTY = "brooklyn.jmxmp.port"; - /** hostname to advertise, and if {@value #JMX_SERVER_ADDRESS_WILDCARD_PROPERTY} is false also the hostname/interface to bind to */ - public static final String RMI_HOSTNAME_PROPERTY = "java.rmi.server.hostname"; - /** whether JMX should bind to all interfaces */ - public static final String JMX_SERVER_ADDRESS_WILDCARD_PROPERTY = "jmx.remote.server.address.wildcard"; - - /** optional port for RMI registry to listen on; if not supplied, RMI is disabled. 1099 is a common choice. - * it will *always* use an anonymous high-numbered port as the rmi server it redirects to - * (ie it behaves like the default JMX agent, not the custom JmxRmiAgent). */ - public static final String RMI_REGISTRY_PORT_PROPERTY = "brooklyn.jmxmp.rmi-port"; - - /** whether to use SSL (TLS) encryption; requires a keystore to be set */ - public static final String USE_SSL_PROPERTY = "com.sun.management.jmxremote.ssl"; - /** whether to use SSL (TLS) certificates to authenticate the client; - * requires a truststore to be set, and requires {@link #USE_SSL_PROPERTY} true - * (different to 'com.sun.management.jmxremote.authenticate' because something else - * insists on intercepting that and uses it for passwords); - * defaults to true iff {@link #USE_SSL_PROPERTY} is set because - * who wouldn't want client authentication if you're encrypting the link */ - public static final String AUTHENTICATE_CLIENTS_PROPERTY = "brooklyn.jmxmp.ssl.authenticate"; - - public static final String JMXMP_KEYSTORE_FILE_PROPERTY = "brooklyn.jmxmp.ssl.keyStore"; - public static final String JMXMP_KEYSTORE_PASSWORD_PROPERTY = "brooklyn.jmxmp.ssl.keyStorePassword"; - public static final String JMXMP_KEYSTORE_KEY_PASSWORD_PROPERTY = "brooklyn.jmxmp.ssl.keyStore.keyPassword"; - public static final String JMXMP_KEYSTORE_TYPE_PROPERTY = "brooklyn.jmxmp.ssl.keyStoreType"; - - public static final String JMXMP_TRUSTSTORE_FILE_PROPERTY = "brooklyn.jmxmp.ssl.trustStore"; - public static final String JMXMP_TRUSTSTORE_PASSWORD_PROPERTY = "brooklyn.jmxmp.ssl.trustStorePassword"; - public static final String JMXMP_TRUSTSTORE_TYPE_PROPERTY = "brooklyn.jmxmp.ssl.trustStoreType"; - - // properties above affect behaviour; those below are simply used in code - - - public static final String TLS_NEED_AUTHENTICATE_CLIENTS_PROPERTY = "jmx.remote.tls.need.client.authentication"; - public static final String TLS_WANT_AUTHENTICATE_CLIENTS_PROPERTY = "jmx.remote.tls.want.client.authentication"; - public static final String TLS_SOCKET_FACTORY_PROPERTY = "jmx.remote.tls.socket.factory"; - - public static final String TLS_JMX_REMOTE_PROFILES = "TLS"; - public static final int JMXMP_DEFAULT_PORT = 11099; - - public static void premain(String agentArgs) { - doMain(agentArgs); - } - - public static void agentmain(String agentArgs) { - doMain(agentArgs); - } - - public static void doMain(final String agentArgs) { - // do the work in a daemon thread so that if the main class terminates abnormally, - // such that shutdown hooks aren't called, we don't keep the application running - // (e.g. if the app is compiled with java7 then run with java6, with a java6 agent here; - // that causes the agent to launch, the main to fail, but the process to keep going) - Thread t = new Thread() { - public void run() { - doMainForeground(agentArgs); - } - }; - t.setDaemon(true); - t.start(); - } - - public static void doMainForeground(String agentArgs) { - final List<JMXConnectorServer> connectors = new JmxmpAgent().startConnectors(System.getProperties()); - if (!connectors.isEmpty()) { - Runtime.getRuntime().addShutdownHook(new Thread("jmxmp-agent-shutdownHookThread") { - @Override public void run() { - for (JMXConnectorServer connector: connectors) { - try { - connector.stop(); - } catch (Exception e) { - System.err.println("Error closing jmxmp connector "+connector+" in shutdown hook (continuing): "+e); - } - } - }}); - } - } - - public List<JMXConnectorServer> startConnectors(Properties properties) { - List<JMXConnectorServer> connectors = new ArrayList<JMXConnectorServer>(); - addIfNotNull(startJmxmpConnector(properties), connectors); - addIfNotNull(startNormalJmxRmiConnectorIfRequested(properties), connectors); - return connectors; - } - - private static <T> void addIfNotNull(T item, List<T> list) { - if (item!=null) list.add(item); - } - - public JMXConnectorServer startJmxmpConnector(Properties properties) { - try { - final int port = Integer.parseInt(properties.getProperty(JMXMP_PORT_PROPERTY, ""+JMXMP_DEFAULT_PORT)); - - String hostname = getLocalhostHostname(properties); - JMXServiceURL serviceUrl = new JMXServiceURL("service:jmx:jmxmp://"+hostname+":"+port); - - Map<String,Object> env = new LinkedHashMap<String, Object>(); - propagate(properties, env, JMX_SERVER_ADDRESS_WILDCARD_PROPERTY, null); - - if (asBoolean(properties, USE_SSL_PROPERTY, false, true)) { - setSslEnvFromProperties(env, properties); - } else { - if (asBoolean(properties, AUTHENTICATE_CLIENTS_PROPERTY, false, true)) { - throw new IllegalStateException("Client authentication not supported when not using SSL"); - } - } - MBeanServer platformMBeanServer = ManagementFactory.getPlatformMBeanServer(); - - JMXConnectorServer connector = JMXConnectorServerFactory.newJMXConnectorServer(serviceUrl, env, platformMBeanServer); - connector.start(); - - System.out.println("JmxmpAgent active at: "+serviceUrl); - - return connector; - } catch (RuntimeException e) { - System.err.println("Unable to start JmxmpAgent: "+e); - throw e; - } catch (Exception e) { - System.err.println("Unable to start JmxmpAgent: "+e); - throw new RuntimeException(e); - } - } - - /** optionally starts a normal JMXRMI connector in addition */ - public JMXConnectorServer startNormalJmxRmiConnectorIfRequested(Properties properties) { - try { - String rmiPortS = properties.getProperty(RMI_REGISTRY_PORT_PROPERTY); - if (rmiPortS==null || rmiPortS.length()==0) - return null; - - int rmiPort = Integer.parseInt(rmiPortS); - LocateRegistry.createRegistry(rmiPort); - MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer(); - String svc = - "service:jmx:rmi:///jndi/rmi://localhost:"+rmiPort+"/jmxrmi"; - - JMXServiceURL url = new JMXServiceURL(svc); - RMIConnectorServer rmiServer = new RMIConnectorServer(url, null, mbeanServer); - rmiServer.start(); - return rmiServer; - } catch (Exception e) { - System.err.println("Unable to start JmxmpAgent: "+e); - throw new RuntimeException(e); - } - } - - public static String getLocalhostHostname(Properties properties) throws UnknownHostException { - String hostname = properties==null ? null : properties.getProperty(RMI_HOSTNAME_PROPERTY); - if (hostname==null || hostname.isEmpty()) { - try { - hostname = InetAddress.getLocalHost().getHostName(); - } catch (Exception e) { - System.err.println("Misconfigured hostname when setting JmxmpAgent; reverting to 127.0.0.1: "+e); - hostname = "127.0.0.1"; - } - } - return hostname; - } - - /** copies the value of key from the source to the target, if set; - * otherwise sets the defaultValueIfNotNull (final arg) if that is not null; - * returns whether anything is set - */ - private static boolean propagate(Properties source, Map<String, Object> target, String key, Object defaultValueIfNotNull) { - Object v = source.getProperty(key); - if (v==null) v = defaultValueIfNotNull; - if (v==null) return false; - target.put(key, v); - return true; - } - - /** returns boolean interpretation of a string, - * defaulting to valueIfUnknownText (last arg) if the value is unset or unrecognised, - * throwing exception if that is null and value is unset or unrecognised */ - private boolean asBoolean(Properties properties, String key, Boolean valueIfNull, Boolean valueIfUnknownText) { - Object v = properties.get(key); - if (v==null) { - if (valueIfNull==null) throw new IllegalStateException("Property '"+key+"' is required."); - return valueIfNull; - } - String vv = v.toString(); - if ("true".equalsIgnoreCase(vv)) return true; - if ("false".equalsIgnoreCase(vv)) return false; - if (valueIfUnknownText==null) - throw new IllegalStateException("Property '"+key+"' has illegal value '"+vv+"'; should be true or false"); - return valueIfUnknownText; - } - - public void setSslEnvFromProperties(Map<String, Object> env, Properties properties) throws Exception { - env.put("jmx.remote.profiles", TLS_JMX_REMOTE_PROFILES); - - boolean authenticating = asBoolean(properties, AUTHENTICATE_CLIENTS_PROPERTY, true, null); - if (authenticating) { - env.put(AUTHENTICATE_CLIENTS_PROPERTY, "true"); - // NB: the above seem to be ignored (horrid API!); we need the ones below set - propagate(properties, env, TLS_NEED_AUTHENTICATE_CLIENTS_PROPERTY, "true"); - // also note, the above seems to be overridden by below internally ! - // (setting WANT=false and NEED=true allows access if no trust managers are specified) - propagate(properties, env, TLS_WANT_AUTHENTICATE_CLIENTS_PROPERTY, "true"); - } - - - if (!propagate(properties, env, TLS_SOCKET_FACTORY_PROPERTY, null)) { - String keyStoreFile = properties.getProperty(JMXMP_KEYSTORE_FILE_PROPERTY); - String keyStorePass = properties.getProperty(JMXMP_KEYSTORE_PASSWORD_PROPERTY, ""); - String keyStoreType = properties.getProperty(JMXMP_KEYSTORE_TYPE_PROPERTY, KeyStore.getDefaultType()); - String keyStoreKeyPass = properties.getProperty(JMXMP_KEYSTORE_KEY_PASSWORD_PROPERTY, ""); - - KeyStore ks = KeyStore.getInstance(keyStoreType); - if (keyStoreFile!=null) - ks.load(new FileInputStream(keyStoreFile), keyStorePass.toCharArray()); - else - ks.load(null, null); - KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); - kmf.init(ks, keyStoreKeyPass.toCharArray()); - - String trustStoreFile = properties.getProperty(JMXMP_TRUSTSTORE_FILE_PROPERTY); - String trustStorePass = properties.getProperty(JMXMP_TRUSTSTORE_PASSWORD_PROPERTY, ""); - String trustStoreType = properties.getProperty(JMXMP_TRUSTSTORE_TYPE_PROPERTY, KeyStore.getDefaultType()); - - TrustManager[] tms; - if (trustStoreFile!=null) { - TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); - KeyStore ts = KeyStore.getInstance(trustStoreType); - ts.load(new FileInputStream(trustStoreFile), trustStorePass.toCharArray()); - tmf.init(ts); -// tms = tmf.getTrustManagers(); - // line above causes tests to fail! bug in JMXMP TLS impl? - tms = new TrustManager[] { newInspectAllTrustManager((X509TrustManager) tmf.getTrustManagers()[0]) }; - } else { - tms = null; - if (authenticating) - System.err.println("Authentication required but no truststore supplied to JmxmpAgent. Client connections will likely fail."); - } - - SSLContext ctx = SSLContext.getInstance("TLSv1"); - ctx.init(kmf.getKeyManagers(), tms, null); - SSLSocketFactory ssf = ctx.getSocketFactory(); - env.put(TLS_SOCKET_FACTORY_PROPERTY, ssf); - } - } - - public static final TrustManager newInspectAllTrustManager(final X509TrustManager delegate) { - return new X509TrustManager() { - public X509Certificate[] getAcceptedIssuers() { - // overriding this method fixes bug where non-accepted issuers have an "accept all" policy, in JMXMP/TLS - return new X509Certificate[0]; - } - @Override - public void checkClientTrusted(X509Certificate[] chain, String authType) - throws java.security.cert.CertificateException { - delegate.checkClientTrusted(chain, authType); - } - @Override - public void checkServerTrusted(X509Certificate[] chain, String authType) - throws java.security.cert.CertificateException { - delegate.checkServerTrusted(chain, authType); - } - }; - }; - - public static void main(String[] args) { - premain(""); - } -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e6ac83be/utils/jmx/jmxmp-ssl-agent/src/main/java/org/apache/brooklyn/util/jmx/jmxmp/JmxmpAgent.java ---------------------------------------------------------------------- diff --git a/utils/jmx/jmxmp-ssl-agent/src/main/java/org/apache/brooklyn/util/jmx/jmxmp/JmxmpAgent.java b/utils/jmx/jmxmp-ssl-agent/src/main/java/org/apache/brooklyn/util/jmx/jmxmp/JmxmpAgent.java new file mode 100644 index 0000000..0ac40bc --- /dev/null +++ b/utils/jmx/jmxmp-ssl-agent/src/main/java/org/apache/brooklyn/util/jmx/jmxmp/JmxmpAgent.java @@ -0,0 +1,337 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.brooklyn.util.jmx.jmxmp; + +import java.io.FileInputStream; +import java.lang.management.ManagementFactory; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.rmi.registry.LocateRegistry; +import java.security.KeyStore; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; + +import javax.management.MBeanServer; +import javax.management.remote.JMXConnectorServer; +import javax.management.remote.JMXConnectorServerFactory; +import javax.management.remote.JMXServiceURL; +import javax.management.remote.rmi.RMIConnectorServer; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; +import javax.net.ssl.X509TrustManager; + +import org.apache.brooklyn.util.jmx.jmxmp.JmxmpAgent; + + +/** + * This exposes JMX access over JMXMP, suitable for high-security environments, + * with support for going through firewalls as well as encrypting and authenticating securely. + * <p> + * Listens on 11099 unless overridden by system property brooklyn.jmxmp.port. + * <p> + * Use the usual com.sun.management.jmxremote.ssl to enable both SSL _and_ authentication + * (setting brooklyn.jmxmp.ssl.authenticate false if you need to disable authentication for some reason); + * unless you disable client-side server authentication you will need to supply brooklyn.jmxmp.ssl.keyStore, + * and similarly unless server-side client auth is off you'll need the corresponding trustStore + * (both pointing to files on the local file system). + * <p> + * Service comes up on: service:jmx:jmxmp://${HOSTNAME}:${PORT} + * <p> + * If {@link #RMI_REGISTRY_PORT_PROPERTY} is also set, this agent will start a normal JMX/RMI server bound to + * all interfaces, which is contactable on: service:jmx:rmi:///jndi/rmi://${HOSTNAME}:${RMI_REGISTRY_PORT}/jmxrmi + * <p> + * NB: To use JConsole with this endpoing, you need the jmxremote_optional JAR, and the + * following command (even more complicated if using SSL): + * java -classpath $JAVA_HOME/lib/jconsole.jar:$HOME/.m2/repository/javax/management/jmxremote_optional/1.0.1_04/jmxremote_optional-1.0.1_04.jar sun.tools.jconsole.JConsole + */ +public class JmxmpAgent { + + /** port to listen on; default to {@link #JMXMP_DEFAULT_PORT} */ + public static final String JMXMP_PORT_PROPERTY = "brooklyn.jmxmp.port"; + /** hostname to advertise, and if {@value #JMX_SERVER_ADDRESS_WILDCARD_PROPERTY} is false also the hostname/interface to bind to */ + public static final String RMI_HOSTNAME_PROPERTY = "java.rmi.server.hostname"; + /** whether JMX should bind to all interfaces */ + public static final String JMX_SERVER_ADDRESS_WILDCARD_PROPERTY = "jmx.remote.server.address.wildcard"; + + /** optional port for RMI registry to listen on; if not supplied, RMI is disabled. 1099 is a common choice. + * it will *always* use an anonymous high-numbered port as the rmi server it redirects to + * (ie it behaves like the default JMX agent, not the custom JmxRmiAgent). */ + public static final String RMI_REGISTRY_PORT_PROPERTY = "brooklyn.jmxmp.rmi-port"; + + /** whether to use SSL (TLS) encryption; requires a keystore to be set */ + public static final String USE_SSL_PROPERTY = "com.sun.management.jmxremote.ssl"; + /** whether to use SSL (TLS) certificates to authenticate the client; + * requires a truststore to be set, and requires {@link #USE_SSL_PROPERTY} true + * (different to 'com.sun.management.jmxremote.authenticate' because something else + * insists on intercepting that and uses it for passwords); + * defaults to true iff {@link #USE_SSL_PROPERTY} is set because + * who wouldn't want client authentication if you're encrypting the link */ + public static final String AUTHENTICATE_CLIENTS_PROPERTY = "brooklyn.jmxmp.ssl.authenticate"; + + public static final String JMXMP_KEYSTORE_FILE_PROPERTY = "brooklyn.jmxmp.ssl.keyStore"; + public static final String JMXMP_KEYSTORE_PASSWORD_PROPERTY = "brooklyn.jmxmp.ssl.keyStorePassword"; + public static final String JMXMP_KEYSTORE_KEY_PASSWORD_PROPERTY = "brooklyn.jmxmp.ssl.keyStore.keyPassword"; + public static final String JMXMP_KEYSTORE_TYPE_PROPERTY = "brooklyn.jmxmp.ssl.keyStoreType"; + + public static final String JMXMP_TRUSTSTORE_FILE_PROPERTY = "brooklyn.jmxmp.ssl.trustStore"; + public static final String JMXMP_TRUSTSTORE_PASSWORD_PROPERTY = "brooklyn.jmxmp.ssl.trustStorePassword"; + public static final String JMXMP_TRUSTSTORE_TYPE_PROPERTY = "brooklyn.jmxmp.ssl.trustStoreType"; + + // properties above affect behaviour; those below are simply used in code + + + public static final String TLS_NEED_AUTHENTICATE_CLIENTS_PROPERTY = "jmx.remote.tls.need.client.authentication"; + public static final String TLS_WANT_AUTHENTICATE_CLIENTS_PROPERTY = "jmx.remote.tls.want.client.authentication"; + public static final String TLS_SOCKET_FACTORY_PROPERTY = "jmx.remote.tls.socket.factory"; + + public static final String TLS_JMX_REMOTE_PROFILES = "TLS"; + public static final int JMXMP_DEFAULT_PORT = 11099; + + public static void premain(String agentArgs) { + doMain(agentArgs); + } + + public static void agentmain(String agentArgs) { + doMain(agentArgs); + } + + public static void doMain(final String agentArgs) { + // do the work in a daemon thread so that if the main class terminates abnormally, + // such that shutdown hooks aren't called, we don't keep the application running + // (e.g. if the app is compiled with java7 then run with java6, with a java6 agent here; + // that causes the agent to launch, the main to fail, but the process to keep going) + Thread t = new Thread() { + public void run() { + doMainForeground(agentArgs); + } + }; + t.setDaemon(true); + t.start(); + } + + public static void doMainForeground(String agentArgs) { + final List<JMXConnectorServer> connectors = new JmxmpAgent().startConnectors(System.getProperties()); + if (!connectors.isEmpty()) { + Runtime.getRuntime().addShutdownHook(new Thread("jmxmp-agent-shutdownHookThread") { + @Override public void run() { + for (JMXConnectorServer connector: connectors) { + try { + connector.stop(); + } catch (Exception e) { + System.err.println("Error closing jmxmp connector "+connector+" in shutdown hook (continuing): "+e); + } + } + }}); + } + } + + public List<JMXConnectorServer> startConnectors(Properties properties) { + List<JMXConnectorServer> connectors = new ArrayList<JMXConnectorServer>(); + addIfNotNull(startJmxmpConnector(properties), connectors); + addIfNotNull(startNormalJmxRmiConnectorIfRequested(properties), connectors); + return connectors; + } + + private static <T> void addIfNotNull(T item, List<T> list) { + if (item!=null) list.add(item); + } + + public JMXConnectorServer startJmxmpConnector(Properties properties) { + try { + final int port = Integer.parseInt(properties.getProperty(JMXMP_PORT_PROPERTY, ""+JMXMP_DEFAULT_PORT)); + + String hostname = getLocalhostHostname(properties); + JMXServiceURL serviceUrl = new JMXServiceURL("service:jmx:jmxmp://"+hostname+":"+port); + + Map<String,Object> env = new LinkedHashMap<String, Object>(); + propagate(properties, env, JMX_SERVER_ADDRESS_WILDCARD_PROPERTY, null); + + if (asBoolean(properties, USE_SSL_PROPERTY, false, true)) { + setSslEnvFromProperties(env, properties); + } else { + if (asBoolean(properties, AUTHENTICATE_CLIENTS_PROPERTY, false, true)) { + throw new IllegalStateException("Client authentication not supported when not using SSL"); + } + } + MBeanServer platformMBeanServer = ManagementFactory.getPlatformMBeanServer(); + + JMXConnectorServer connector = JMXConnectorServerFactory.newJMXConnectorServer(serviceUrl, env, platformMBeanServer); + connector.start(); + + System.out.println("JmxmpAgent active at: "+serviceUrl); + + return connector; + } catch (RuntimeException e) { + System.err.println("Unable to start JmxmpAgent: "+e); + throw e; + } catch (Exception e) { + System.err.println("Unable to start JmxmpAgent: "+e); + throw new RuntimeException(e); + } + } + + /** optionally starts a normal JMXRMI connector in addition */ + public JMXConnectorServer startNormalJmxRmiConnectorIfRequested(Properties properties) { + try { + String rmiPortS = properties.getProperty(RMI_REGISTRY_PORT_PROPERTY); + if (rmiPortS==null || rmiPortS.length()==0) + return null; + + int rmiPort = Integer.parseInt(rmiPortS); + LocateRegistry.createRegistry(rmiPort); + MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer(); + String svc = + "service:jmx:rmi:///jndi/rmi://localhost:"+rmiPort+"/jmxrmi"; + + JMXServiceURL url = new JMXServiceURL(svc); + RMIConnectorServer rmiServer = new RMIConnectorServer(url, null, mbeanServer); + rmiServer.start(); + return rmiServer; + } catch (Exception e) { + System.err.println("Unable to start JmxmpAgent: "+e); + throw new RuntimeException(e); + } + } + + public static String getLocalhostHostname(Properties properties) throws UnknownHostException { + String hostname = properties==null ? null : properties.getProperty(RMI_HOSTNAME_PROPERTY); + if (hostname==null || hostname.isEmpty()) { + try { + hostname = InetAddress.getLocalHost().getHostName(); + } catch (Exception e) { + System.err.println("Misconfigured hostname when setting JmxmpAgent; reverting to 127.0.0.1: "+e); + hostname = "127.0.0.1"; + } + } + return hostname; + } + + /** copies the value of key from the source to the target, if set; + * otherwise sets the defaultValueIfNotNull (final arg) if that is not null; + * returns whether anything is set + */ + private static boolean propagate(Properties source, Map<String, Object> target, String key, Object defaultValueIfNotNull) { + Object v = source.getProperty(key); + if (v==null) v = defaultValueIfNotNull; + if (v==null) return false; + target.put(key, v); + return true; + } + + /** returns boolean interpretation of a string, + * defaulting to valueIfUnknownText (last arg) if the value is unset or unrecognised, + * throwing exception if that is null and value is unset or unrecognised */ + private boolean asBoolean(Properties properties, String key, Boolean valueIfNull, Boolean valueIfUnknownText) { + Object v = properties.get(key); + if (v==null) { + if (valueIfNull==null) throw new IllegalStateException("Property '"+key+"' is required."); + return valueIfNull; + } + String vv = v.toString(); + if ("true".equalsIgnoreCase(vv)) return true; + if ("false".equalsIgnoreCase(vv)) return false; + if (valueIfUnknownText==null) + throw new IllegalStateException("Property '"+key+"' has illegal value '"+vv+"'; should be true or false"); + return valueIfUnknownText; + } + + public void setSslEnvFromProperties(Map<String, Object> env, Properties properties) throws Exception { + env.put("jmx.remote.profiles", TLS_JMX_REMOTE_PROFILES); + + boolean authenticating = asBoolean(properties, AUTHENTICATE_CLIENTS_PROPERTY, true, null); + if (authenticating) { + env.put(AUTHENTICATE_CLIENTS_PROPERTY, "true"); + // NB: the above seem to be ignored (horrid API!); we need the ones below set + propagate(properties, env, TLS_NEED_AUTHENTICATE_CLIENTS_PROPERTY, "true"); + // also note, the above seems to be overridden by below internally ! + // (setting WANT=false and NEED=true allows access if no trust managers are specified) + propagate(properties, env, TLS_WANT_AUTHENTICATE_CLIENTS_PROPERTY, "true"); + } + + + if (!propagate(properties, env, TLS_SOCKET_FACTORY_PROPERTY, null)) { + String keyStoreFile = properties.getProperty(JMXMP_KEYSTORE_FILE_PROPERTY); + String keyStorePass = properties.getProperty(JMXMP_KEYSTORE_PASSWORD_PROPERTY, ""); + String keyStoreType = properties.getProperty(JMXMP_KEYSTORE_TYPE_PROPERTY, KeyStore.getDefaultType()); + String keyStoreKeyPass = properties.getProperty(JMXMP_KEYSTORE_KEY_PASSWORD_PROPERTY, ""); + + KeyStore ks = KeyStore.getInstance(keyStoreType); + if (keyStoreFile!=null) + ks.load(new FileInputStream(keyStoreFile), keyStorePass.toCharArray()); + else + ks.load(null, null); + KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); + kmf.init(ks, keyStoreKeyPass.toCharArray()); + + String trustStoreFile = properties.getProperty(JMXMP_TRUSTSTORE_FILE_PROPERTY); + String trustStorePass = properties.getProperty(JMXMP_TRUSTSTORE_PASSWORD_PROPERTY, ""); + String trustStoreType = properties.getProperty(JMXMP_TRUSTSTORE_TYPE_PROPERTY, KeyStore.getDefaultType()); + + TrustManager[] tms; + if (trustStoreFile!=null) { + TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + KeyStore ts = KeyStore.getInstance(trustStoreType); + ts.load(new FileInputStream(trustStoreFile), trustStorePass.toCharArray()); + tmf.init(ts); +// tms = tmf.getTrustManagers(); + // line above causes tests to fail! bug in JMXMP TLS impl? + tms = new TrustManager[] { newInspectAllTrustManager((X509TrustManager) tmf.getTrustManagers()[0]) }; + } else { + tms = null; + if (authenticating) + System.err.println("Authentication required but no truststore supplied to JmxmpAgent. Client connections will likely fail."); + } + + SSLContext ctx = SSLContext.getInstance("TLSv1"); + ctx.init(kmf.getKeyManagers(), tms, null); + SSLSocketFactory ssf = ctx.getSocketFactory(); + env.put(TLS_SOCKET_FACTORY_PROPERTY, ssf); + } + } + + public static final TrustManager newInspectAllTrustManager(final X509TrustManager delegate) { + return new X509TrustManager() { + public X509Certificate[] getAcceptedIssuers() { + // overriding this method fixes bug where non-accepted issuers have an "accept all" policy, in JMXMP/TLS + return new X509Certificate[0]; + } + @Override + public void checkClientTrusted(X509Certificate[] chain, String authType) + throws java.security.cert.CertificateException { + delegate.checkClientTrusted(chain, authType); + } + @Override + public void checkServerTrusted(X509Certificate[] chain, String authType) + throws java.security.cert.CertificateException { + delegate.checkServerTrusted(chain, authType); + } + }; + }; + + public static void main(String[] args) { + premain(""); + } +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e6ac83be/utils/jmx/jmxmp-ssl-agent/src/test/java/brooklyn/util/jmx/jmxmp/JmxmpAgentSslTest.java ---------------------------------------------------------------------- diff --git a/utils/jmx/jmxmp-ssl-agent/src/test/java/brooklyn/util/jmx/jmxmp/JmxmpAgentSslTest.java b/utils/jmx/jmxmp-ssl-agent/src/test/java/brooklyn/util/jmx/jmxmp/JmxmpAgentSslTest.java deleted file mode 100644 index 771ba6d..0000000 --- a/utils/jmx/jmxmp-ssl-agent/src/test/java/brooklyn/util/jmx/jmxmp/JmxmpAgentSslTest.java +++ /dev/null @@ -1,256 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package brooklyn.util.jmx.jmxmp; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.security.KeyPair; -import java.security.KeyStore; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.security.Security; -import java.security.cert.CertificateException; -import java.security.cert.X509Certificate; -import java.util.LinkedHashMap; -import java.util.Properties; - -import javax.management.remote.JMXConnectorServer; - -import org.apache.brooklyn.core.util.crypto.FluentKeySigner; -import org.apache.brooklyn.core.util.crypto.SecureKeys; -import org.bouncycastle.jce.provider.BouncyCastleProvider; -import org.bouncycastle.x509.extension.AuthorityKeyIdentifierStructure; -import org.testng.annotations.AfterMethod; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; - -public class JmxmpAgentSslTest { - - KeyPair caRootKey; - FluentKeySigner caRootSigner; - X509Certificate caRootCert; - - KeyPair caChildKey; - X509Certificate caChildCert; - FluentKeySigner caChildSigner; - - KeyPair grandchildKey; - X509Certificate grandchildCert; - - KeyPair child2Key; - X509Certificate child2Cert; - - KeyPair selfSign1Key; - X509Certificate selfSign1Cert; - - KeyPair selfSign2Key; - X509Certificate selfSign2Cert; - - KeyStore serverKeystore; - KeyStore serverTruststore; - KeyStore clientTruststore; - KeyStore clientKeystore; - - JMXConnectorServer server; - - static { Security.addProvider(new BouncyCastleProvider()); } - - @BeforeMethod - public void setup() throws Exception { - caRootSigner = new FluentKeySigner("ca-root").selfsign(); - caRootKey = caRootSigner.getKey(); - caRootCert = caRootSigner.getAuthorityCertificate(); - - caChildKey = SecureKeys.newKeyPair(); - caChildCert = caRootSigner.newCertificateFor("ca-child", caChildKey); - caChildSigner = new FluentKeySigner("ca-child", caChildKey). - authorityKeyIdentifier(new AuthorityKeyIdentifierStructure(caChildCert)); - - grandchildKey = SecureKeys.newKeyPair(); - grandchildCert = caChildSigner.newCertificateFor("grandchild", grandchildKey); - - child2Key = SecureKeys.newKeyPair(); - child2Cert = - caRootSigner. - newCertificateFor("child-2", child2Key); - - selfSign1Key = SecureKeys.newKeyPair(); - selfSign1Cert = - new FluentKeySigner("self-1", selfSign1Key). - newCertificateFor("self-1", selfSign1Key); - - selfSign2Key = SecureKeys.newKeyPair(); - selfSign2Cert = - new FluentKeySigner("self-2", selfSign2Key). - newCertificateFor("self-2", selfSign2Key); - - serverKeystore = KeyStore.getInstance(KeyStore.getDefaultType()); - serverKeystore.load(null, null); - - serverTruststore = KeyStore.getInstance(KeyStore.getDefaultType()); - serverTruststore.load(null, null); - - clientTruststore = KeyStore.getInstance(KeyStore.getDefaultType()); - clientTruststore.load(null, null); - - clientKeystore = KeyStore.getInstance(KeyStore.getDefaultType()); - clientKeystore.load(null, null); - } - - @AfterMethod - public void teardown() throws Exception { - if (server!=null) server.stop(); - server = null; - } - - private Properties saveStoresAndGetConnectorProperties() throws - KeyStoreException, IOException, NoSuchAlgorithmException, - CertificateException, FileNotFoundException { - String keystoreFile = File.createTempFile("server-keystore", ".jmx.test").getAbsolutePath(); - String truststoreFile = File.createTempFile("server-truststore", ".jmx.test").getAbsolutePath(); - if (serverKeystore!=null) serverKeystore.store( new FileOutputStream(keystoreFile), new char[0]); - if (serverTruststore!=null) serverTruststore.store( new FileOutputStream(truststoreFile), new char[0]); - Properties p = new Properties(); - p.put(JmxmpAgent.JMXMP_KEYSTORE_FILE_PROPERTY, keystoreFile); - p.put(JmxmpAgent.JMXMP_TRUSTSTORE_FILE_PROPERTY, truststoreFile); - p.put(JmxmpAgent.USE_SSL_PROPERTY, "true"); - p.put(JmxmpAgent.AUTHENTICATE_CLIENTS_PROPERTY, "true"); - return p; - } - - @SuppressWarnings("rawtypes") - @Test - public void testNoAuth() throws Exception { - serverKeystore = null; - serverTruststore = null; - clientKeystore = null; - clientTruststore = null; - - Properties p = saveStoresAndGetConnectorProperties(); - p.put(JmxmpAgent.USE_SSL_PROPERTY, "false"); - p.put(JmxmpAgent.AUTHENTICATE_CLIENTS_PROPERTY, "false"); - - server = new JmxmpAgent().startJmxmpConnector(p); - new JmxmpClient().connect("service:jmx:jmxmp://localhost:11099", new LinkedHashMap()); - } - - @SuppressWarnings("rawtypes") - @Test(expectedExceptions = { IllegalStateException.class }) - public void testAuthWithoutSslFails() throws Exception { - serverKeystore = null; - serverTruststore = null; - clientKeystore = null; - clientTruststore = null; - - Properties p = saveStoresAndGetConnectorProperties(); - p.put(JmxmpAgent.USE_SSL_PROPERTY, "false"); - p.put(JmxmpAgent.AUTHENTICATE_CLIENTS_PROPERTY, "true"); - - server = new JmxmpAgent().startJmxmpConnector(p); - new JmxmpClient().connect("service:jmx:jmxmp://localhost:11099", new LinkedHashMap()); - } - - @Test - public void testAllGoodSignatures() throws Exception { - serverKeystore.setKeyEntry("child-2", child2Key.getPrivate(), new char[]{}, - new java.security.cert.Certificate[]{ child2Cert, caRootCert }); - serverTruststore.setCertificateEntry("ca-child", caChildCert); - - clientKeystore.setKeyEntry("grandchild", grandchildKey.getPrivate(), new char[] {}, - new java.security.cert.Certificate[]{ grandchildCert }); - clientTruststore.setCertificateEntry("ca-root", caRootCert); - - Properties p = saveStoresAndGetConnectorProperties(); - server = new JmxmpAgent().startJmxmpConnector(p); - new JmxmpClient().connectTls("service:jmx:jmxmp://localhost:11099", - clientKeystore, "", clientTruststore); - } - - @Test(expectedExceptions = { Exception.class }) - public void testWrongServerKey() throws Exception { - /** not a trusted key */ - serverKeystore.setKeyEntry("self-1", selfSign1Key.getPrivate(), new char[]{}, - new java.security.cert.Certificate[]{ selfSign1Cert }); - serverTruststore.setCertificateEntry("ca-child", caChildCert); - - clientKeystore.setKeyEntry("grandchild", grandchildKey.getPrivate(), new char[] {}, - new java.security.cert.Certificate[]{ grandchildCert }); - clientTruststore.setCertificateEntry("ca-root", caRootCert); - - Properties p = saveStoresAndGetConnectorProperties(); - server = new JmxmpAgent().startJmxmpConnector(p); - new JmxmpClient().connectTls("service:jmx:jmxmp://localhost:11099", - clientKeystore, "", clientTruststore); - } - - @Test(expectedExceptions = { Exception.class }) - public void testLyingServerChain() throws Exception { - /** caChildCert hasn't signed this */ - serverKeystore.setKeyEntry("self-1", selfSign1Key.getPrivate(), new char[]{}, - new java.security.cert.Certificate[]{ selfSign1Cert, caChildCert }); - serverTruststore.setCertificateEntry("ca-child", caChildCert); - - clientKeystore.setKeyEntry("grandchild", grandchildKey.getPrivate(), new char[] {}, - new java.security.cert.Certificate[]{ grandchildCert, caChildCert }); - clientTruststore.setCertificateEntry("ca-root", caRootCert); - - Properties p = saveStoresAndGetConnectorProperties(); - server = new JmxmpAgent().startJmxmpConnector(p); - new JmxmpClient().connectTls("service:jmx:jmxmp://localhost:11099", - clientKeystore, "", clientTruststore); - } - - @Test(expectedExceptions = { Exception.class }) - public void testWrongClientKey() throws Exception { - serverKeystore.setKeyEntry("child-2", child2Key.getPrivate(), new char[]{}, - new java.security.cert.Certificate[]{ child2Cert, caRootCert }); - serverTruststore.setCertificateEntry("ca-child", caChildCert); - - /** this key should not have access */ - clientKeystore.setKeyEntry("self-1", selfSign1Key.getPrivate(), new char[] {}, - new java.security.cert.Certificate[]{ selfSign1Cert }); - clientTruststore.setCertificateEntry("ca-root", caRootCert); - - Properties p = saveStoresAndGetConnectorProperties(); - server = new JmxmpAgent().startJmxmpConnector(p); - new JmxmpClient().connectTls("service:jmx:jmxmp://localhost:11099", - clientKeystore, "", clientTruststore); - } - - @Test(expectedExceptions = { Exception.class }) - public void testLyingClientChain() throws Exception { - serverKeystore.setKeyEntry("child-2", child2Key.getPrivate(), new char[]{}, - new java.security.cert.Certificate[]{ child2Cert, caRootCert }); - serverTruststore.setCertificateEntry("ca-child", caChildCert); - - /** caChildCert hasn't signed this */ - clientKeystore.setKeyEntry("self-1", selfSign1Key.getPrivate(), new char[] {}, - new java.security.cert.Certificate[]{ selfSign1Cert, caChildCert }); - clientTruststore.setCertificateEntry("ca-root", caRootCert); - - Properties p = saveStoresAndGetConnectorProperties(); - server = new JmxmpAgent().startJmxmpConnector(p); - new JmxmpClient().connectTls("service:jmx:jmxmp://localhost:11099", - clientKeystore, "", clientTruststore); - } - - -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e6ac83be/utils/jmx/jmxmp-ssl-agent/src/test/java/brooklyn/util/jmx/jmxmp/JmxmpClient.java ---------------------------------------------------------------------- diff --git a/utils/jmx/jmxmp-ssl-agent/src/test/java/brooklyn/util/jmx/jmxmp/JmxmpClient.java b/utils/jmx/jmxmp-ssl-agent/src/test/java/brooklyn/util/jmx/jmxmp/JmxmpClient.java deleted file mode 100644 index dbad7b8..0000000 --- a/utils/jmx/jmxmp-ssl-agent/src/test/java/brooklyn/util/jmx/jmxmp/JmxmpClient.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package brooklyn.util.jmx.jmxmp; - -import java.io.IOException; -import java.net.MalformedURLException; -import java.security.InvalidKeyException; -import java.security.KeyManagementException; -import java.security.KeyStore; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.security.SignatureException; -import java.security.UnrecoverableKeyException; -import java.security.cert.CertificateException; -import java.util.LinkedHashMap; -import java.util.Map; - -import javax.management.MBeanServerConnection; -import javax.management.remote.JMXConnector; -import javax.management.remote.JMXConnectorFactory; -import javax.management.remote.JMXServiceURL; -import javax.net.ssl.KeyManagerFactory; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLSocketFactory; -import javax.net.ssl.TrustManager; - -import org.apache.brooklyn.core.util.crypto.SecureKeys; -import org.apache.brooklyn.util.crypto.SslTrustUtils; - -@SuppressWarnings({"rawtypes","unchecked"}) -public class JmxmpClient { - - public void connect(String urlString, Map env) throws MalformedURLException, IOException { - JMXServiceURL url = new JMXServiceURL(urlString); - System.out.println("JmxmpClient connecting to "+url); - JMXConnector jmxc = JMXConnectorFactory.connect(url, env); - - MBeanServerConnection mbsc = jmxc.getMBeanServerConnection(); - String domains[] = mbsc.getDomains(); - for (int i = 0; i < domains.length; i++) { - System.out.println("Domain[" + i + "] = " + domains[i]); - } - - jmxc.close(); - } - - /** tries to connect to the given JMX url over tls, - * optionally using the given keystore (if null using a randomly generated key) - * and optionally using the given truststore (if null trusting all) */ - public void connectTls(String urlString, KeyStore keyStore, String keyStorePass, KeyStore trustStore) throws NoSuchAlgorithmException, UnrecoverableKeyException, KeyStoreException, InvalidKeyException, CertificateException, SecurityException, SignatureException, IOException, KeyManagementException { - Map env = new LinkedHashMap(); - - env.put("jmx.remote.profiles", JmxmpAgent.TLS_JMX_REMOTE_PROFILES); - - if (keyStore==null) throw new NullPointerException("keyStore must be supplied"); - KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); //"SunX509"); - kmf.init(keyStore, (keyStorePass!=null ? keyStorePass : "").toCharArray()); - - TrustManager tms = trustStore!=null ? SecureKeys.getTrustManager(trustStore) : SslTrustUtils.TRUST_ALL; - - SSLContext ctx = SSLContext.getInstance("TLSv1"); - ctx.init(kmf.getKeyManagers(), new TrustManager[] { tms }, null); - SSLSocketFactory ssf = ctx.getSocketFactory(); - env.put(JmxmpAgent.TLS_SOCKET_FACTORY_PROPERTY, ssf); - - connect(urlString, env); - } - - public static void main(String[] args) throws Exception { - new JmxmpClient().connect("service:jmx:jmxmp://localhost:1099", null); - } -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e6ac83be/utils/jmx/jmxmp-ssl-agent/src/test/java/org/apache/brooklyn/util/jmx/jmxmp/JmxmpAgentSslTest.java ---------------------------------------------------------------------- diff --git a/utils/jmx/jmxmp-ssl-agent/src/test/java/org/apache/brooklyn/util/jmx/jmxmp/JmxmpAgentSslTest.java b/utils/jmx/jmxmp-ssl-agent/src/test/java/org/apache/brooklyn/util/jmx/jmxmp/JmxmpAgentSslTest.java new file mode 100644 index 0000000..9aa1bad --- /dev/null +++ b/utils/jmx/jmxmp-ssl-agent/src/test/java/org/apache/brooklyn/util/jmx/jmxmp/JmxmpAgentSslTest.java @@ -0,0 +1,257 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.brooklyn.util.jmx.jmxmp; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.security.KeyPair; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.Security; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.LinkedHashMap; +import java.util.Properties; + +import javax.management.remote.JMXConnectorServer; + +import org.apache.brooklyn.core.util.crypto.FluentKeySigner; +import org.apache.brooklyn.core.util.crypto.SecureKeys; +import org.apache.brooklyn.util.jmx.jmxmp.JmxmpAgent; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.x509.extension.AuthorityKeyIdentifierStructure; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +public class JmxmpAgentSslTest { + + KeyPair caRootKey; + FluentKeySigner caRootSigner; + X509Certificate caRootCert; + + KeyPair caChildKey; + X509Certificate caChildCert; + FluentKeySigner caChildSigner; + + KeyPair grandchildKey; + X509Certificate grandchildCert; + + KeyPair child2Key; + X509Certificate child2Cert; + + KeyPair selfSign1Key; + X509Certificate selfSign1Cert; + + KeyPair selfSign2Key; + X509Certificate selfSign2Cert; + + KeyStore serverKeystore; + KeyStore serverTruststore; + KeyStore clientTruststore; + KeyStore clientKeystore; + + JMXConnectorServer server; + + static { Security.addProvider(new BouncyCastleProvider()); } + + @BeforeMethod + public void setup() throws Exception { + caRootSigner = new FluentKeySigner("ca-root").selfsign(); + caRootKey = caRootSigner.getKey(); + caRootCert = caRootSigner.getAuthorityCertificate(); + + caChildKey = SecureKeys.newKeyPair(); + caChildCert = caRootSigner.newCertificateFor("ca-child", caChildKey); + caChildSigner = new FluentKeySigner("ca-child", caChildKey). + authorityKeyIdentifier(new AuthorityKeyIdentifierStructure(caChildCert)); + + grandchildKey = SecureKeys.newKeyPair(); + grandchildCert = caChildSigner.newCertificateFor("grandchild", grandchildKey); + + child2Key = SecureKeys.newKeyPair(); + child2Cert = + caRootSigner. + newCertificateFor("child-2", child2Key); + + selfSign1Key = SecureKeys.newKeyPair(); + selfSign1Cert = + new FluentKeySigner("self-1", selfSign1Key). + newCertificateFor("self-1", selfSign1Key); + + selfSign2Key = SecureKeys.newKeyPair(); + selfSign2Cert = + new FluentKeySigner("self-2", selfSign2Key). + newCertificateFor("self-2", selfSign2Key); + + serverKeystore = KeyStore.getInstance(KeyStore.getDefaultType()); + serverKeystore.load(null, null); + + serverTruststore = KeyStore.getInstance(KeyStore.getDefaultType()); + serverTruststore.load(null, null); + + clientTruststore = KeyStore.getInstance(KeyStore.getDefaultType()); + clientTruststore.load(null, null); + + clientKeystore = KeyStore.getInstance(KeyStore.getDefaultType()); + clientKeystore.load(null, null); + } + + @AfterMethod + public void teardown() throws Exception { + if (server!=null) server.stop(); + server = null; + } + + private Properties saveStoresAndGetConnectorProperties() throws + KeyStoreException, IOException, NoSuchAlgorithmException, + CertificateException, FileNotFoundException { + String keystoreFile = File.createTempFile("server-keystore", ".jmx.test").getAbsolutePath(); + String truststoreFile = File.createTempFile("server-truststore", ".jmx.test").getAbsolutePath(); + if (serverKeystore!=null) serverKeystore.store( new FileOutputStream(keystoreFile), new char[0]); + if (serverTruststore!=null) serverTruststore.store( new FileOutputStream(truststoreFile), new char[0]); + Properties p = new Properties(); + p.put(JmxmpAgent.JMXMP_KEYSTORE_FILE_PROPERTY, keystoreFile); + p.put(JmxmpAgent.JMXMP_TRUSTSTORE_FILE_PROPERTY, truststoreFile); + p.put(JmxmpAgent.USE_SSL_PROPERTY, "true"); + p.put(JmxmpAgent.AUTHENTICATE_CLIENTS_PROPERTY, "true"); + return p; + } + + @SuppressWarnings("rawtypes") + @Test + public void testNoAuth() throws Exception { + serverKeystore = null; + serverTruststore = null; + clientKeystore = null; + clientTruststore = null; + + Properties p = saveStoresAndGetConnectorProperties(); + p.put(JmxmpAgent.USE_SSL_PROPERTY, "false"); + p.put(JmxmpAgent.AUTHENTICATE_CLIENTS_PROPERTY, "false"); + + server = new JmxmpAgent().startJmxmpConnector(p); + new JmxmpClient().connect("service:jmx:jmxmp://localhost:11099", new LinkedHashMap()); + } + + @SuppressWarnings("rawtypes") + @Test(expectedExceptions = { IllegalStateException.class }) + public void testAuthWithoutSslFails() throws Exception { + serverKeystore = null; + serverTruststore = null; + clientKeystore = null; + clientTruststore = null; + + Properties p = saveStoresAndGetConnectorProperties(); + p.put(JmxmpAgent.USE_SSL_PROPERTY, "false"); + p.put(JmxmpAgent.AUTHENTICATE_CLIENTS_PROPERTY, "true"); + + server = new JmxmpAgent().startJmxmpConnector(p); + new JmxmpClient().connect("service:jmx:jmxmp://localhost:11099", new LinkedHashMap()); + } + + @Test + public void testAllGoodSignatures() throws Exception { + serverKeystore.setKeyEntry("child-2", child2Key.getPrivate(), new char[]{}, + new java.security.cert.Certificate[]{ child2Cert, caRootCert }); + serverTruststore.setCertificateEntry("ca-child", caChildCert); + + clientKeystore.setKeyEntry("grandchild", grandchildKey.getPrivate(), new char[] {}, + new java.security.cert.Certificate[]{ grandchildCert }); + clientTruststore.setCertificateEntry("ca-root", caRootCert); + + Properties p = saveStoresAndGetConnectorProperties(); + server = new JmxmpAgent().startJmxmpConnector(p); + new JmxmpClient().connectTls("service:jmx:jmxmp://localhost:11099", + clientKeystore, "", clientTruststore); + } + + @Test(expectedExceptions = { Exception.class }) + public void testWrongServerKey() throws Exception { + /** not a trusted key */ + serverKeystore.setKeyEntry("self-1", selfSign1Key.getPrivate(), new char[]{}, + new java.security.cert.Certificate[]{ selfSign1Cert }); + serverTruststore.setCertificateEntry("ca-child", caChildCert); + + clientKeystore.setKeyEntry("grandchild", grandchildKey.getPrivate(), new char[] {}, + new java.security.cert.Certificate[]{ grandchildCert }); + clientTruststore.setCertificateEntry("ca-root", caRootCert); + + Properties p = saveStoresAndGetConnectorProperties(); + server = new JmxmpAgent().startJmxmpConnector(p); + new JmxmpClient().connectTls("service:jmx:jmxmp://localhost:11099", + clientKeystore, "", clientTruststore); + } + + @Test(expectedExceptions = { Exception.class }) + public void testLyingServerChain() throws Exception { + /** caChildCert hasn't signed this */ + serverKeystore.setKeyEntry("self-1", selfSign1Key.getPrivate(), new char[]{}, + new java.security.cert.Certificate[]{ selfSign1Cert, caChildCert }); + serverTruststore.setCertificateEntry("ca-child", caChildCert); + + clientKeystore.setKeyEntry("grandchild", grandchildKey.getPrivate(), new char[] {}, + new java.security.cert.Certificate[]{ grandchildCert, caChildCert }); + clientTruststore.setCertificateEntry("ca-root", caRootCert); + + Properties p = saveStoresAndGetConnectorProperties(); + server = new JmxmpAgent().startJmxmpConnector(p); + new JmxmpClient().connectTls("service:jmx:jmxmp://localhost:11099", + clientKeystore, "", clientTruststore); + } + + @Test(expectedExceptions = { Exception.class }) + public void testWrongClientKey() throws Exception { + serverKeystore.setKeyEntry("child-2", child2Key.getPrivate(), new char[]{}, + new java.security.cert.Certificate[]{ child2Cert, caRootCert }); + serverTruststore.setCertificateEntry("ca-child", caChildCert); + + /** this key should not have access */ + clientKeystore.setKeyEntry("self-1", selfSign1Key.getPrivate(), new char[] {}, + new java.security.cert.Certificate[]{ selfSign1Cert }); + clientTruststore.setCertificateEntry("ca-root", caRootCert); + + Properties p = saveStoresAndGetConnectorProperties(); + server = new JmxmpAgent().startJmxmpConnector(p); + new JmxmpClient().connectTls("service:jmx:jmxmp://localhost:11099", + clientKeystore, "", clientTruststore); + } + + @Test(expectedExceptions = { Exception.class }) + public void testLyingClientChain() throws Exception { + serverKeystore.setKeyEntry("child-2", child2Key.getPrivate(), new char[]{}, + new java.security.cert.Certificate[]{ child2Cert, caRootCert }); + serverTruststore.setCertificateEntry("ca-child", caChildCert); + + /** caChildCert hasn't signed this */ + clientKeystore.setKeyEntry("self-1", selfSign1Key.getPrivate(), new char[] {}, + new java.security.cert.Certificate[]{ selfSign1Cert, caChildCert }); + clientTruststore.setCertificateEntry("ca-root", caRootCert); + + Properties p = saveStoresAndGetConnectorProperties(); + server = new JmxmpAgent().startJmxmpConnector(p); + new JmxmpClient().connectTls("service:jmx:jmxmp://localhost:11099", + clientKeystore, "", clientTruststore); + } + + +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e6ac83be/utils/jmx/jmxmp-ssl-agent/src/test/java/org/apache/brooklyn/util/jmx/jmxmp/JmxmpClient.java ---------------------------------------------------------------------- diff --git a/utils/jmx/jmxmp-ssl-agent/src/test/java/org/apache/brooklyn/util/jmx/jmxmp/JmxmpClient.java b/utils/jmx/jmxmp-ssl-agent/src/test/java/org/apache/brooklyn/util/jmx/jmxmp/JmxmpClient.java new file mode 100644 index 0000000..3c7d664 --- /dev/null +++ b/utils/jmx/jmxmp-ssl-agent/src/test/java/org/apache/brooklyn/util/jmx/jmxmp/JmxmpClient.java @@ -0,0 +1,89 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.brooklyn.util.jmx.jmxmp; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.security.InvalidKeyException; +import java.security.KeyManagementException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.SignatureException; +import java.security.UnrecoverableKeyException; +import java.security.cert.CertificateException; +import java.util.LinkedHashMap; +import java.util.Map; + +import javax.management.MBeanServerConnection; +import javax.management.remote.JMXConnector; +import javax.management.remote.JMXConnectorFactory; +import javax.management.remote.JMXServiceURL; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.TrustManager; + +import org.apache.brooklyn.core.util.crypto.SecureKeys; +import org.apache.brooklyn.util.crypto.SslTrustUtils; +import org.apache.brooklyn.util.jmx.jmxmp.JmxmpAgent; + +@SuppressWarnings({"rawtypes","unchecked"}) +public class JmxmpClient { + + public void connect(String urlString, Map env) throws MalformedURLException, IOException { + JMXServiceURL url = new JMXServiceURL(urlString); + System.out.println("JmxmpClient connecting to "+url); + JMXConnector jmxc = JMXConnectorFactory.connect(url, env); + + MBeanServerConnection mbsc = jmxc.getMBeanServerConnection(); + String domains[] = mbsc.getDomains(); + for (int i = 0; i < domains.length; i++) { + System.out.println("Domain[" + i + "] = " + domains[i]); + } + + jmxc.close(); + } + + /** tries to connect to the given JMX url over tls, + * optionally using the given keystore (if null using a randomly generated key) + * and optionally using the given truststore (if null trusting all) */ + public void connectTls(String urlString, KeyStore keyStore, String keyStorePass, KeyStore trustStore) throws NoSuchAlgorithmException, UnrecoverableKeyException, KeyStoreException, InvalidKeyException, CertificateException, SecurityException, SignatureException, IOException, KeyManagementException { + Map env = new LinkedHashMap(); + + env.put("jmx.remote.profiles", JmxmpAgent.TLS_JMX_REMOTE_PROFILES); + + if (keyStore==null) throw new NullPointerException("keyStore must be supplied"); + KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); //"SunX509"); + kmf.init(keyStore, (keyStorePass!=null ? keyStorePass : "").toCharArray()); + + TrustManager tms = trustStore!=null ? SecureKeys.getTrustManager(trustStore) : SslTrustUtils.TRUST_ALL; + + SSLContext ctx = SSLContext.getInstance("TLSv1"); + ctx.init(kmf.getKeyManagers(), new TrustManager[] { tms }, null); + SSLSocketFactory ssf = ctx.getSocketFactory(); + env.put(JmxmpAgent.TLS_SOCKET_FACTORY_PROPERTY, ssf); + + connect(urlString, env); + } + + public static void main(String[] args) throws Exception { + new JmxmpClient().connect("service:jmx:jmxmp://localhost:1099", null); + } +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e6ac83be/utils/jmx/jmxrmi-agent/pom.xml ---------------------------------------------------------------------- diff --git a/utils/jmx/jmxrmi-agent/pom.xml b/utils/jmx/jmxrmi-agent/pom.xml index e9ea011..d725405 100644 --- a/utils/jmx/jmxrmi-agent/pom.xml +++ b/utils/jmx/jmxrmi-agent/pom.xml @@ -52,8 +52,8 @@ <artifactId>maven-bundle-plugin</artifactId> <configuration> <instructions> - <Premain-Class>brooklyn.util.jmx.jmxrmi.JmxRmiAgent</Premain-Class> - <Agent-Class>brooklyn.util.jmx.jmxrmi.JmxRmiAgent</Agent-Class> + <Premain-Class>org.apache.brooklyn.util.jmx.jmxrmi.JmxRmiAgent</Premain-Class> + <Agent-Class>org.apache.brooklyn.util.jmx.jmxrmi.JmxRmiAgent</Agent-Class> </instructions> </configuration> </plugin> http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e6ac83be/utils/jmx/jmxrmi-agent/src/main/java/brooklyn/util/jmx/jmxrmi/JmxRmiAgent.java ---------------------------------------------------------------------- diff --git a/utils/jmx/jmxrmi-agent/src/main/java/brooklyn/util/jmx/jmxrmi/JmxRmiAgent.java b/utils/jmx/jmxrmi-agent/src/main/java/brooklyn/util/jmx/jmxrmi/JmxRmiAgent.java deleted file mode 100644 index 089de45..0000000 --- a/utils/jmx/jmxrmi-agent/src/main/java/brooklyn/util/jmx/jmxrmi/JmxRmiAgent.java +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package brooklyn.util.jmx.jmxrmi; - -import java.lang.management.ManagementFactory; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.rmi.registry.LocateRegistry; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.Properties; - -import javax.management.MBeanServer; -import javax.management.remote.JMXConnectorServer; -import javax.management.remote.JMXConnectorServerFactory; -import javax.management.remote.JMXServiceURL; - -/** - * This exposes JMX support for going through firewalls by starting an RMI registry server - * on a well-known port. - * <p> - * This implementation DOES NOT support port-forwarding however. The same hostname used internally - * (specified in {@link #RMI_HOSTNAME_PROPERTY} or autodetected by java) must also be addressable - * by the JMX client. This is due to how the property is used internally by java during the - * RMI registry re-direction. - * <p> - * If you require that the client connects to a different hostname/IP than the one where the - * service is bound, consider using the Brooklyn JmxmpAgent, as this will not work! - * <p> - * This listens on {@value #RMI_REGISTRY_PORT_PROPERTY} unless overridden by system property - * {@link #RMI_REGISTRY_PORT_PROPERTY} ({@value #RMI_REGISTRY_PORT_PROPERTY}). - * - * @see brooklyn.util.jmx.jmxmp.JmxmpAgent - * @see https://blogs.oracle.com/jmxetc/entry/connecting_through_firewall_using_jmx - * @see https://blogs.oracle.com/jmxetc/entry/more_on_premain_and_jmx - */ -public class JmxRmiAgent { - - /** Port for RMI registry to listen on. Default to {@link #RMI_REGISTRY_DEFAULT_PORT}. */ - public static final String RMI_REGISTRY_PORT_PROPERTY = "brooklyn.jmx-agent.rmi-port"; - public static final String RMI_REGISTRY_DEFAULT_PORT = "9001"; - - /** Port for JMX server (sometimes called JMX_RMI server) to listen on. Default to {@link #JMX_SERVER_DEFAULT_PORT}. */ - public static final String JMX_SERVER_PORT_PROPERTY = "brooklyn.jmx-agent.jmx-port"; - public static final String JMX_SERVER_DEFAULT_PORT = "11099"; - - /** Hostname to advertise, and if {@value #JMX_SERVER_ADDRESS_WILDCARD_PROPERTY} is false also the hostname/interface to bind to. - * Should never be 0.0.0.0 as it is publicly advertised. */ - public static final String RMI_HOSTNAME_PROPERTY = "java.rmi.server.hostname"; - - /** Whether JMX should bind to all interfaces. */ - public static final String JMX_SERVER_ADDRESS_WILDCARD_PROPERTY = "jmx.remote.server.address.wildcard"; - - /** - * The entry point, uses the JDK dynamic agent loading feature. - */ - public static void premain(String agentArgs) { - doMain(agentArgs); - } - - public static void agentmain(String agentArgs) { - doMain(agentArgs); - } - - public static void doMain(final String agentArgs) { - // taken from JmxmpAgent in sister project - - // do the work in a daemon thread so that if the main class terminates abnormally, - // such that shutdown hooks aren't called, we don't keep the application running - // (e.g. if the app is compiled with java7 then run with java6, with a java6 agent here; - // that causes the agent to launch, the main to fail, but the process to keep going) - Thread t = new Thread() { - public void run() { - doMainForeground(agentArgs); - } - }; - t.setDaemon(true); - t.start(); - } - - public static void doMainForeground(String agentArgs) { - final JMXConnectorServer connector = new JmxRmiAgent().startServer(System.getProperties()); - if (connector != null) { - Runtime.getRuntime().addShutdownHook(new Thread("jmxrmi-agent-shutdownHookThread") { - @Override public void run() { - try { - connector.stop(); - } catch (Exception e) { - System.err.println("Error closing jmxrmi connector in shutdown hook (continuing): "+e); - } - }}); - } - } - - public JMXConnectorServer startServer(Properties properties) { - try { - // Ensure cryptographically strong random number generator used - // to choose the object number - see java.rmi.server.ObjID - System.setProperty("java.rmi.server.randomIDs", "true"); - - // Start an RMI registry on port specified - final int rmiPort = Integer.parseInt(System.getProperty(RMI_REGISTRY_PORT_PROPERTY, RMI_REGISTRY_DEFAULT_PORT)); - final int jmxPort = Integer.parseInt(System.getProperty(JMX_SERVER_PORT_PROPERTY, JMX_SERVER_DEFAULT_PORT)); - final String hostname = getLocalhostHostname(properties); - - System.out.println("Setting up JmxRmiAgent for: "+hostname+" "+rmiPort+" / "+jmxPort); - - LocateRegistry.createRegistry(rmiPort); - - // Retrieve the PlatformMBeanServer. - MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); - - // Environment map. - Map<String, Object> env = new LinkedHashMap<String, Object>(); - propagate(properties, env, JMX_SERVER_ADDRESS_WILDCARD_PROPERTY, "true"); - - // TODO Security - - // Create an RMI connector server. - JMXServiceURL url = new JMXServiceURL("service:jmx:rmi://" + hostname + ":" + jmxPort + "/jndi/rmi://" + hostname + ":" + rmiPort + "/jmxrmi"); - - // Now create the server from the JMXServiceURL - JMXConnectorServer connector = JMXConnectorServerFactory.newJMXConnectorServer(url, env, mbs); - - // Start the RMI connector server. - connector.start(); - System.out.println("JmxRmiAgent JMXConnectorServer active at: " + url); - - return connector; - } catch (RuntimeException e) { - System.err.println("Unable to start JMXConnectorServer: " + e); - throw e; - } catch (Exception e) { - System.err.println("Unable to start JMXConnectorServer: " + e); - throw new RuntimeException(e); - } - } - - /** - * Copies the value of key from the source to the target, if set. Otherwise - * sets the {@code defaultValueIfNotNull} if that is not null. - * - * @return whether anything is set - */ - private static boolean propagate(Properties source, Map<String, Object> target, String key, Object defaultValueIfNotNull) { - Object v = source.getProperty(key); - if (v == null) v = defaultValueIfNotNull; - if (v == null) return false; - target.put(key, v); - return true; - } - - private String getLocalhostHostname(Properties properties) throws UnknownHostException { - String hostname = properties == null ? null : properties.getProperty(RMI_HOSTNAME_PROPERTY); - if ("0.0.0.0".equals(hostname)) { - System.err.println("WARN: invalid hostname 0.0.0.0 specified for JmxRmiAgent; " + - "it typically must be an address or hostname which is bindable on the machine where " + - "this service is running AND accessible by a client machine (access will likely be impossible)"); - } - if (hostname == null || hostname.isEmpty()) { - hostname = InetAddress.getLocalHost().getHostName(); - } - return hostname; - } - - /** - * Convenience main method. - */ - public static void main(String[] args) throws Exception { - premain(""); - } -}
