From f054d4fe2ec7b1fc3004b1c301eef881ca74b4fc Mon Sep 17 00:00:00 2001 From: Alex Coomans Date: Thu, 5 May 2016 14:56:00 -0700 Subject: [PATCH] Allow user-specifiable SSL / TLS protocols and ciphers to the JVM agent Developer Certificate of Origin Version 1.1 Copyright (C) 2004, 2006 The Linux Foundation and its contributors. 660 York Street, Suite 102, San Francisco, CA 94110 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Developer's Certificate of Origin 1.1 By making a contribution to this project, I certify that: (a) The contribution was created in whole or in part by me and I have the right to submit it under the open source license indicated in the file; or (b) The contribution is based upon previous work that, to the best of my knowledge, is covered under an appropriate open source license and I have the right under that license to submit that work with modifications, whether created in whole or in part by me, under the same open source license (unless I am permitted to submit under a different license), as indicated in the file; or (c) The contribution was provided directly to me by some other person who certified (a), (b) or (c) and I have not modified it. (d) I understand and agree that this project and the contribution are public and that a record of the contribution (including all personal information I submit with it, including my sign-off) is maintained indefinitely and may be redistributed consistent with this project or the open source license(s) involved. Signed-off-by: Alex Coomans --- .../org/jolokia/jvmagent/JolokiaServer.java | 47 +++--- .../jolokia/jvmagent/JolokiaServerConfig.java | 87 ++++++++++- .../java/org/jolokia/jvmagent/JvmAgent.java | 4 +- .../jvmagent/client/command/HelpCommand.java | 5 +- .../jvmagent/client/util/OptionsAndArgs.java | 3 +- .../jolokia/jvmagent/JolokiaServerTest.java | 139 +++++++++++++++-- ...agent-test-specialHttpsSettings.properties | 39 +++++ src/docbkx/agents/jvm.xml | 141 +++++++++++------- 8 files changed, 372 insertions(+), 93 deletions(-) create mode 100644 agent/jvm/src/test/resources/agent-test-specialHttpsSettings.properties diff --git a/agent/jvm/src/main/java/org/jolokia/jvmagent/JolokiaServer.java b/agent/jvm/src/main/java/org/jolokia/jvmagent/JolokiaServer.java index ad16bb714..f6f58d0c0 100644 --- a/agent/jvm/src/main/java/org/jolokia/jvmagent/JolokiaServer.java +++ b/agent/jvm/src/main/java/org/jolokia/jvmagent/JolokiaServer.java @@ -169,7 +169,7 @@ public JolokiaServerConfig getServerConfig() { protected final void init(JolokiaServerConfig pConfig, boolean pLazy) throws IOException { // We manage it on our own httpServer = createHttpServer(pConfig); - init(httpServer,pConfig,pLazy); + init(httpServer, pConfig, pLazy); } /** @@ -186,7 +186,7 @@ protected final void init(HttpServer pServer, JolokiaServerConfig pConfig, boole // Create proper context along with handler final String contextPath = pConfig.getContextPath(); - jolokiaHttpHandler = useHttps(pConfig) ? + jolokiaHttpHandler = pConfig.useHttps() ? new JolokiaHttpsHandler(pConfig) : new JolokiaHttpHandler(pConfig.getJolokiaConfig()); HttpContext context = pServer.createContext(contextPath, jolokiaHttpHandler); @@ -240,7 +240,7 @@ private HttpServer createHttpServer(JolokiaServerConfig pConfig) throws IOExcept InetAddress address = pConfig.getAddress(); InetSocketAddress socketAddress = new InetSocketAddress(address,port); - HttpServer server = useHttps(pConfig) ? + HttpServer server = pConfig.useHttps() ? createHttpsServer(socketAddress, pConfig) : HttpServer.create(socketAddress, pConfig.getBacklog()); @@ -261,13 +261,7 @@ private HttpServer createHttpServer(JolokiaServerConfig pConfig) throws IOExcept // ========================================================================================================= // HTTPS handling - - private boolean useHttps(JolokiaServerConfig pConfig) { - String protocol = pConfig.getProtocol(); - return protocol.equalsIgnoreCase("https"); - } - - private HttpServer createHttpsServer(InetSocketAddress pSocketAddress,JolokiaServerConfig pConfig) { + private HttpServer createHttpsServer(InetSocketAddress pSocketAddress, JolokiaServerConfig pConfig) { // initialise the HTTPS server try { HttpsServer server = HttpsServer.create(pSocketAddress, pConfig.getBacklog()); @@ -285,8 +279,12 @@ private HttpServer createHttpsServer(InetSocketAddress pSocketAddress,JolokiaSer tmf.init(ks); // setup the HTTPS context and parameters - sslContext.init(kmf.getKeyManagers(),tmf.getTrustManagers(), null); - server.setHttpsConfigurator(new JolokiaHttpsConfigurator(sslContext, pConfig.useSslClientAuthentication())); + sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); + + // Update the config to filter out bad protocols or ciphers + pConfig.updateHTTPSSettingsFromContext(sslContext); + + server.setHttpsConfigurator(new JolokiaHttpsConfigurator(sslContext, pConfig)); return server; } catch (GeneralSecurityException e) { throw new IllegalStateException("Cannot use keystore for https communication: " + e,e); @@ -401,29 +399,34 @@ public Thread newThread(Runnable r) { // HTTPS configurator private static final class JolokiaHttpsConfigurator extends HttpsConfigurator { - private boolean useClientAuthentication; + private JolokiaServerConfig serverConfig; private SSLContext context; - private JolokiaHttpsConfigurator(SSLContext pSSLContext,boolean pUseClientAuthentication) { + private JolokiaHttpsConfigurator(SSLContext pSSLContext, JolokiaServerConfig pConfig) { super(pSSLContext); this.context = pSSLContext; - useClientAuthentication = pUseClientAuthentication; + this.serverConfig = pConfig; } /** {@inheritDoc} */ public void configure(HttpsParameters params) { - // initialise the SSL context SSLEngine engine = context.createSSLEngine(); - params.setNeedClientAuth(useClientAuthentication); - params.setCipherSuites(engine.getEnabledCipherSuites()); - params.setProtocols(engine.getEnabledProtocols()); - // get the default parameters SSLParameters defaultSSLParameters = context.getDefaultSSLParameters(); - defaultSSLParameters.setNeedClientAuth(useClientAuthentication); - params.setSSLParameters(defaultSSLParameters); + params.setNeedClientAuth(serverConfig.useSslClientAuthentication()); + defaultSSLParameters.setNeedClientAuth(serverConfig.useSslClientAuthentication()); + + // Cipher Suites + params.setCipherSuites(serverConfig.getSSLCipherSuites()); + defaultSSLParameters.setCipherSuites(serverConfig.getSSLCipherSuites()); + + // Protocols + params.setProtocols(serverConfig.getSSLProtocols()); + defaultSSLParameters.setProtocols(serverConfig.getSSLProtocols()); + + params.setSSLParameters(defaultSSLParameters); } } } diff --git a/agent/jvm/src/main/java/org/jolokia/jvmagent/JolokiaServerConfig.java b/agent/jvm/src/main/java/org/jolokia/jvmagent/JolokiaServerConfig.java index c6fab18a7..d54699394 100644 --- a/agent/jvm/src/main/java/org/jolokia/jvmagent/JolokiaServerConfig.java +++ b/agent/jvm/src/main/java/org/jolokia/jvmagent/JolokiaServerConfig.java @@ -28,6 +28,8 @@ import java.util.regex.Pattern; import com.sun.net.httpserver.Authenticator; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLParameters; import org.jolokia.config.ConfigKey; import org.jolokia.config.Configuration; import org.jolokia.jvmagent.security.*; @@ -68,6 +70,8 @@ public class JolokiaServerConfig { private String serverKeyAlgorithm; private List clientPrincipals; private boolean extendedClientCheck; + private String[] sslProtocols; + private String[] sslCipherSuites; /** * Constructor which prepares the server configuration from a map @@ -136,6 +140,15 @@ public String getProtocol() { return protocol; } + /** + * Whether or not to use https as the procol + * + * @return true when using https as the protocol + */ + public boolean useHttps() { + return protocol.equalsIgnoreCase("https"); + } + /** * Address to bind to, which is either used from the configuration option * "host" or by default from {@link InetAddress#getLocalHost()} @@ -261,12 +274,73 @@ public String getServerKey() { /** * The algorithm to use for extracting the private server key. * - * @return the server keyl algoritm + * @return the server key algorithm */ public String getServerKeyAlgorithm() { return serverKeyAlgorithm; } + /** + * The list of enabled SSL / TLS protocols to serve with + * + * @return the list of enabled protocols + */ + public String[] getSSLProtocols() { return sslProtocols; } + + /** + * The list of enabled SSL / TLS cipher suites + * + * @return the list of cipher suites + */ + public String[] getSSLCipherSuites() { + return sslCipherSuites; + } + + /** + * Filter the list of protocols and ciphers to those supported by the given SSLContext + * + * @param sslContext the SSLContext to pull information from + */ + public void updateHTTPSSettingsFromContext(SSLContext sslContext) { + SSLParameters parameters = sslContext.getSupportedSSLParameters(); + + // Protocols + if (sslProtocols == null) { + sslProtocols = parameters.getProtocols(); + } else { + List supportedProtocols = Arrays.asList(parameters.getProtocols()); + List sslProtocolsList = new ArrayList(Arrays.asList(sslProtocols)); + + Iterator pit = sslProtocolsList.iterator(); + while (pit.hasNext()) { + String protocol = pit.next(); + if (!supportedProtocols.contains(protocol)) { + System.out.println("Jolokia: Discarding unsupported protocol: " + protocol); + pit.remove(); + } + } + sslProtocols = sslProtocolsList.toArray(new String[0]); + } + + // Cipher Suites + if (sslCipherSuites == null) { + sslCipherSuites = parameters.getCipherSuites(); + } else { + List supportedCipherSuites = Arrays.asList(parameters.getCipherSuites()); + List sslCipherSuitesList = new ArrayList(Arrays.asList(sslCipherSuites)); + + Iterator cit = sslCipherSuitesList.iterator(); + while (cit.hasNext()) { + String cipher = cit.next(); + if (!supportedCipherSuites.contains(cipher)) { + System.out.println("Jolokia: Discarding unsupported cipher suite: " + cipher); + cit.remove(); + } + } + sslCipherSuites = sslCipherSuitesList.toArray(new String[0]); + } + } + // Initialise and validate early in order to fail fast in case of an configuration error protected void initConfigAndValidate(Map agentConfig) { initContext(); @@ -401,9 +475,18 @@ private void initHttpsRelatedSettings(Map agentConfig) { keystorePassword = password != null ? decipherPasswordIfNecessary(password) : new char[0]; serverKeyAlgorithm = agentConfig.get("serverKeyAlgorithm"); - clientPrincipals = extractList(agentConfig,"clientPrincipal"); + clientPrincipals = extractList(agentConfig, "clientPrincipal"); String xCheck = agentConfig.get("extendedClientCheck"); extendedClientCheck = xCheck != null && Boolean.valueOf(xCheck); + + List sslProtocolsList = extractList(agentConfig, "sslProtocol"); + if (sslProtocolsList != null) { + sslProtocols = sslProtocolsList.toArray(new String[0]); + } + List sslCipherSuitesList = extractList(agentConfig, "sslCipherSuite"); + if (sslCipherSuitesList != null) { + sslCipherSuites = sslCipherSuitesList.toArray(new String[0]); + } } private char[] decipherPasswordIfNecessary(String password) { diff --git a/agent/jvm/src/main/java/org/jolokia/jvmagent/JvmAgent.java b/agent/jvm/src/main/java/org/jolokia/jvmagent/JvmAgent.java index b16a8a7ea..2fcd2a9c7 100644 --- a/agent/jvm/src/main/java/org/jolokia/jvmagent/JvmAgent.java +++ b/agent/jvm/src/main/java/org/jolokia/jvmagent/JvmAgent.java @@ -64,7 +64,7 @@ private JvmAgent() {} * @param agentArgs arguments as given on the command line */ public static void premain(String agentArgs) { - startAgent(new JvmAgentConfig(agentArgs),true /* register and detect lazy */); + startAgent(new JvmAgentConfig(agentArgs), true /* register and detect lazy */); } /** @@ -82,7 +82,7 @@ public static void agentmain(String agentArgs) { } } - private static void startAgent(JvmAgentConfig pConfig,boolean pLazy) { + private static void startAgent(JvmAgentConfig pConfig, boolean pLazy) { try { server = new JolokiaServer(pConfig,pLazy); diff --git a/agent/jvm/src/main/java/org/jolokia/jvmagent/client/command/HelpCommand.java b/agent/jvm/src/main/java/org/jolokia/jvmagent/client/command/HelpCommand.java index e15ef58f8..b27cb1dcb 100644 --- a/agent/jvm/src/main/java/org/jolokia/jvmagent/client/command/HelpCommand.java +++ b/agent/jvm/src/main/java/org/jolokia/jvmagent/client/command/HelpCommand.java @@ -100,9 +100,12 @@ static void printUsage() { " --serverKey Path to a PEM encoded server key file (https only)\n" + " --serverKeyAlgorithm Algorithm to use for decrypting the server key (https only, default: RSA)\n" + " --clientPrincipal Allow only this principal in the client cert (https & sslClientAuth only)\n" + +" If supplied multiple times, any one of the clientPrincipals must match\n" + " --extendedClientCheck Additional validation of client certs for the proper key usage (https & sslClientAuth only)\n" + " --discoveryEnabled Enable/Disable discovery multicast responses (default: true)\n" + " --discoveryAgentUrl The URL to use for answering discovery requests. Will be autodetected if not given.\n" + +" --sslProtocol SSL / TLS protocol to enable, can be provided multiple times\n" + +" --sslCipherSuite SSL / TLS cipher suite to enable, can be provided multiple times\n" + " --debug Switch on agent debugging\n" + " --debugMaxEntries Number of debug entries to keep in memory which can be fetched from the Jolokia MBean\n" + " --maxDepth Maximum number of levels for serialization of beans\n" + @@ -128,7 +131,7 @@ static void printUsage() { "is printed\n" + "\n" + "There are several possible reasons, why attaching to a process can fail:\n" + -" * The UID of this launcher must be the very *same*as the process to attach too. It not sufficient to be root.\n" + +" * The UID of this launcher must be the very *same* as the process to attach too. It not sufficient to be root.\n" + " * The JVM must have HotSpot enabled and be a JVM 1.6 or larger.\n" + " * It must be a Java process ;-)\n" + "\n" + diff --git a/agent/jvm/src/main/java/org/jolokia/jvmagent/client/util/OptionsAndArgs.java b/agent/jvm/src/main/java/org/jolokia/jvmagent/client/util/OptionsAndArgs.java index b209a6c71..bc10458d5 100644 --- a/agent/jvm/src/main/java/org/jolokia/jvmagent/client/util/OptionsAndArgs.java +++ b/agent/jvm/src/main/java/org/jolokia/jvmagent/client/util/OptionsAndArgs.java @@ -47,6 +47,7 @@ public final class OptionsAndArgs { "keystore", "keystorePassword", "useSslClientAuthentication!", "secureSocketProtocol", "keyStoreType", "keyManagerAlgorithm", "trustManagerAlgorithm", "caCert", "serverCert", "serverKey", "serverKeyAlgorithm", "clientPrincipal", "extractClientCheck", + "sslProtocol", "sslCipherSuite", // Jolokia options: "historyMaxEntries", "debug!", "debugMaxEntries", "dispatcherClasses", "maxDepth", "maxCollectionSize", @@ -57,7 +58,7 @@ public final class OptionsAndArgs { "config", "help!")); private static final Set LIST_OPTIONS = new HashSet(Arrays.asList( - "clientPrincipal")); + "clientPrincipal", "sslProtocol", "sslCipherSuite")); static { String shortOptsDef[] = { diff --git a/agent/jvm/src/test/java/org/jolokia/jvmagent/JolokiaServerTest.java b/agent/jvm/src/test/java/org/jolokia/jvmagent/JolokiaServerTest.java index f8e5040b1..2129d5935 100644 --- a/agent/jvm/src/test/java/org/jolokia/jvmagent/JolokiaServerTest.java +++ b/agent/jvm/src/test/java/org/jolokia/jvmagent/JolokiaServerTest.java @@ -22,7 +22,9 @@ import java.security.*; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; +import java.util.Arrays; import java.util.HashMap; +import java.util.List; import java.util.Map; import javax.net.ssl.*; @@ -52,7 +54,7 @@ public void http() throws Exception { }; for (String c : configs) { - roundtrip(c,true); + roundtrip(c, true); } } @@ -60,15 +62,15 @@ public void http() throws Exception { @Test(expectedExceptions = IOException.class,expectedExceptionsMessageRegExp = ".*401.*") public void httpWithAuthenticationRejected() throws Exception { Map config = new HashMap(); - config.put("user","roland"); - config.put("password","s!cr!t"); - config.put("port","0"); - roundtrip(config,true); + config.put("user", "roland"); + config.put("password", "s!cr!t"); + config.put("port", "0"); + roundtrip(config, true); } @Test public void serverPicksThePort() throws Exception { - roundtrip("host=localhost,port=0",true); + roundtrip("host=localhost,port=0", true); } @@ -101,17 +103,17 @@ public void serverPicksThePort() throws Exception { @Test public void t_11_https_only() throws Exception { - httpsRoundtrip("agentId=test",false); + httpsRoundtrip("agentId=test", false); } @Test public void t_12_with_keystore() throws Exception { - httpsRoundtrip("keystore=" + getResourcePath("/keystore") + ",keystorePassword=jetty7",false); + httpsRoundtrip("keystore=" + getResourcePath("/keystore") + ",keystorePassword=jetty7", false); } @Test(expectedExceptions = IllegalArgumentException.class, expectedExceptionsMessageRegExp = ".*without.*key.*") public void serverCertWithoutKey() throws Exception { - httpsRoundtrip("serverCert=" + getCertPath("server/cert.pem"),false); + httpsRoundtrip("serverCert=" + getCertPath("server/cert.pem"), false); } @Test @@ -218,18 +220,82 @@ public void sslWithAdditionalHttpsSettings() throws Exception { false); } + @Test + public void sslWithSpecialHttpsSettings() throws Exception { + JvmAgentConfig config = new JvmAgentConfig( + prepareConfigString("host=localhost,port=" + EnvTestUtil.getFreePort() + ",protocol=https," + + getFullCertSetup() + ",config=" + getResourcePath("/agent-test-specialHttpsSettings.properties"))); + JolokiaServer server = new JolokiaServer(config, false); + server.start(); + + // Skipping hostname verification because the cert doesn't have a SAN of localhost + HostnameVerifier verifier = new HostnameVerifier() { + @Override + public boolean verify(String host, SSLSession sslSession) { + return true; + } + }; + + HostnameVerifier oldVerifier = HttpsURLConnection.getDefaultHostnameVerifier(); + SSLSocketFactory oldSslSocketFactory = HttpsURLConnection.getDefaultSSLSocketFactory(); + + List cipherSuites = Arrays.asList(config.getSSLCipherSuites()); + List protocols = Arrays.asList(config.getSSLProtocols()); + + for (String protocol : new String[]{"SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2"}) { + // Make sure at least one connection for this protocol succeeds (if expected to) + boolean connectionSucceeded = false; + + for (String cipherSuite : oldSslSocketFactory.getSupportedCipherSuites()) { + if (!cipherSuites.contains(cipherSuite)) + continue; + + try { + TrustManager tms[] = getTrustManagers(true); + SSLContext sc = SSLContext.getInstance(protocol); + sc.init(new KeyManager[0], tms, new java.security.SecureRandom()); + + HttpsURLConnection.setDefaultHostnameVerifier(verifier); + HttpsURLConnection.setDefaultSSLSocketFactory( + new FakeSSLSocketFactory(sc.getSocketFactory(), new String[]{protocol}, new String[]{cipherSuite})); + + URL url = new URL(server.getUrl()); + String resp = EnvTestUtil.readToString(url.openStream()); + assertTrue( + resp.matches(".*type.*version.*" + Version.getAgentVersion() + ".*")); + if (!protocols.contains(protocol) || !cipherSuites.contains(cipherSuite)) { + fail(String.format("Expected SSLHandshakeException with the %s protocol and %s cipher suite", protocol, cipherSuite)); + } + connectionSucceeded = true; + } catch (javax.net.ssl.SSLHandshakeException e) { + // We make sure at least one connection with this protocol succeeds if expected + // down below + } finally { + HttpsURLConnection.setDefaultHostnameVerifier(oldVerifier); + HttpsURLConnection.setDefaultSSLSocketFactory(oldSslSocketFactory); + } + } + + if (protocols.contains(protocol) && !connectionSucceeded) { + fail("Expected at least one connection to succeed on " + protocol); + } + } + + server.stop(); + } + @Test(expectedExceptions = IllegalArgumentException.class,expectedExceptionsMessageRegExp = ".*password.*") public void invalidConfig() throws IOException, InterruptedException { JvmAgentConfig cfg = new JvmAgentConfig("user=roland,port=" + EnvTestUtil.getFreePort()); Thread.sleep(1000); - new JolokiaServer(cfg,false); + new JolokiaServer(cfg, false); } @Test public void customHttpServer() throws IOException, NoSuchFieldException, IllegalAccessException { HttpServer httpServer = HttpServer.create(); JvmAgentConfig cfg = new JvmAgentConfig(""); - JolokiaServer server = new JolokiaServer(httpServer,cfg,false); + JolokiaServer server = new JolokiaServer(httpServer, cfg, false); Field field = JolokiaServer.class.getDeclaredField("httpServer"); field.setAccessible(true); assertNull(field.get(server)); @@ -252,7 +318,7 @@ private String getResourcePath(String relativeResourcePath) { } private void roundtrip(Map pConfig, boolean pDoRequest) throws Exception { - checkServer(new JvmAgentConfig(pConfig),pDoRequest); + checkServer(new JvmAgentConfig(pConfig), pDoRequest); } private void roundtrip(String pConfig, boolean pDoRequest) throws Exception { @@ -261,7 +327,7 @@ private void roundtrip(String pConfig, boolean pDoRequest) throws Exception { } private void httpsRoundtrip(String pConfig, boolean pValidateCa) throws Exception { - httpsRoundtrip(pConfig,pValidateCa,"client/with-key-usage"); + httpsRoundtrip(pConfig, pValidateCa, "client/with-key-usage"); } private void httpsRoundtrip(String pConfig, boolean pValidateCa, String clientCert) throws Exception { @@ -325,7 +391,7 @@ private void checkServer(JvmAgentConfig pConfig, boolean pDoRequest, HostnameVerifier pVerifier, boolean pValidateCa, String pClientCert) throws Exception { - JolokiaServer server = new JolokiaServer(pConfig,false); + JolokiaServer server = new JolokiaServer(pConfig, false); server.start(); //Thread.sleep(2000); HostnameVerifier oldVerifier = HttpsURLConnection.getDefaultHostnameVerifier(); @@ -365,5 +431,50 @@ private void checkServer(JvmAgentConfig pConfig, boolean pDoRequest, } } + // FakeSSLSocketFactory wraps a normal SSLSocketFactory so it can set the explicit SSL / TLS + // protocol version(s) and cipher suite(s) + private static class FakeSSLSocketFactory extends SSLSocketFactory { + private String[] cipherSuites; + private String[] protocols; + private SSLSocketFactory socketFactory; + + public FakeSSLSocketFactory(SSLSocketFactory socketFactory, String[] protocols, String[] cipherSuites) { + super(); + this.socketFactory = socketFactory; + this.protocols = protocols; + this.cipherSuites = cipherSuites; + } + + public Socket createSocket(InetAddress host, int port) throws IOException { + return wrapSocket((SSLSocket)socketFactory.createSocket(host, port)); + } + + public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException { + return wrapSocket((SSLSocket)socketFactory.createSocket(s, host, port, autoClose)); + } + + public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException { + return wrapSocket((SSLSocket)socketFactory.createSocket(address, port, localAddress, localPort)); + } + + public Socket createSocket(String host, int port) throws IOException { + return wrapSocket((SSLSocket)socketFactory.createSocket(host, port)); + } + + public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException { + return wrapSocket((SSLSocket)socketFactory.createSocket(host, port, localHost, localPort)); + } + public String[] getDefaultCipherSuites() { + return socketFactory.getDefaultCipherSuites(); + } + + public String[] getSupportedCipherSuites() { return socketFactory.getSupportedCipherSuites(); } + + private Socket wrapSocket(SSLSocket sslSocket) { + sslSocket.setEnabledProtocols(this.protocols); + sslSocket.setEnabledCipherSuites(this.cipherSuites); + return sslSocket; + } + } } diff --git a/agent/jvm/src/test/resources/agent-test-specialHttpsSettings.properties b/agent/jvm/src/test/resources/agent-test-specialHttpsSettings.properties new file mode 100644 index 000000000..25a356e62 --- /dev/null +++ b/agent/jvm/src/test/resources/agent-test-specialHttpsSettings.properties @@ -0,0 +1,39 @@ +# +# Copyright 2009-2016 Roland Huss +# +# Licensed 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. +# + +secureSocketProtocol=TLSv1.2 +sslProtocol.1=TLSv1.1 +sslProtocol.2=TLSv1.2 + +# Copied from https://wiki.mozilla.org/Security/Server_Side_TLS#Recommended_configurations and compared +# against http://docs.oracle.com/javase/8/docs/technotes/guides/security/SunProviders.html#SunJSSEProvider +sslCipherSuite.1=TLS_EMPTY_RENEGOTIATION_INFO_SCSV + +# Only available in Java 1.8 +sslCipherSuite.2=TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 +sslCipherSuite.3=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 +sslCipherSuite.4=TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 +sslCipherSuite.5=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 +# These work in Java 1.7 on TLSv1.2 only, Java 1.8 all protocols +sslCipherSuite.6=TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 +sslCipherSuite.7=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 +sslCipherSuite.8=TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 +sslCipherSuite.9=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 +# These work in Java 1.6+ +sslCipherSuite.10=TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA +sslCipherSuite.11=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA +sslCipherSuite.12=TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA +sslCipherSuite.13=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA diff --git a/src/docbkx/agents/jvm.xml b/src/docbkx/agents/jvm.xml index 0fe8f833c..13d84e9a3 100644 --- a/src/docbkx/agents/jvm.xml +++ b/src/docbkx/agents/jvm.xml @@ -430,8 +430,7 @@ java -javaagent:agent.jar=port=7777,host=localhost]]> pairs (except for the config property of course :) - - + discoveryEnabled @@ -458,6 +457,29 @@ java -javaagent:agent.jar=port=7777,host=localhost]]> http://10.9.11.87:8778/jolokia + + sslProtocol + + The list of SSL / TLS protocols enabled. Valid options are available in the documentation + on SunJSSEProvider for your JDK version. Using only TLSv1.1 and + TLSv1.2 is recommended in Java 1.7 and Java 1.8. Using only + TLSv1 is recommended in Java 1.6. Multiple protocols can be configured + by using additional options with consecutive index suffixes like in + sslProtocol.1, sslProtocol.2, ... + + TLSv1.2 + + + sslCipherSuite + + The list of SSL / TLS cipher suites to enable. The table of available cipher suites is + available under the "Default Enabled Cipher Suites" at the SunJSSEProvider documentation + here. + Multiple cipher suites can be configured by using additional options with consecutive index + suffixes like in sslCipherSuite.1, sslCipherSuite.2, ... + + + Upon successful startup the agent will print out a success @@ -485,12 +507,12 @@ java -javaagent:agent.jar=port=7777,host=localhost]]> --help to get a short usage information: +Usage: java -jar jolokia-jvm-1.3.4-agent.jar [options] where is one of start -- Start a Jolokia agent for the process specified @@ -502,53 +524,70 @@ where is one of [options] are used for providing runtime information for attaching the agent: - --host Hostname or IP address to which to bind on - (default: InetAddress.getLocalHost()) - --port Port to listen on (default: 8778) - --agentContext HTTP Context under which the agent is reachable (default: /jolokia) - --agentId VM unique identifier used by this agent (default: autogenerated) - --agentDescription Agent description - --user User used for Basic-Authentication - --password Password used for Basic-Authentication - --quiet No output. "status" will exit with code 0 if the agent is running, - 1 otherwise - --verbose Verbose output - --executor Executor policy for HTTP Threads to use (default: single) - "fixed" -- Thread pool with a fixed number of threads (default: 5) - "cached" -- Cached Thread Pool, creates threads on demand - "single" -- Single Thread - --threadNr Number of fixed threads if "fixed" is used as executor - --backlog How many request to keep in the backlog (default: 10) - --protocol Protocol which must be either "http" or "https" (default: http) - --keystore Path to keystore (https only) - --keystorePassword Password to the keystore (https only) - --useSslClientAuthentication Use client certificate authentication (https only) - --secureSocketProtocol Secure protocol (https only, default: TLS) - --keyStoreType Keystore type (https only, default: JKS) - --keyManagerAlgorithm Key manager algorithm (https only, default: SunX509) - --trustManagerAlgorithm Trust manager algorithm (https only, default: SunX509) - --discoveryEnabled Enable/Disable discovery multicast responses (default: true) - --discoveryAgentUrl The URL to use for answering discovery requests. Will be autodetected - if not given. - --debug Switch on agent debugging - --debugMaxEntries Number of debug entries to keep in memory which can be fetched from the - Jolokia MBean - --maxDepth Maximum number of levels for serialization of beans (default: null) - --maxCollectionSize Maximum number of element in collections to keep when serializing the - response (default: null) - --maxObjects Maximum number of objects to consider for serialization - (default: maxObjects) - --policyLocation Location of a Jolokia policy file + --host Hostname or IP address to which to bind on + (default: InetAddress.getLocalHost()) + --port Port to listen on (default: 8778) + --agentContext HTTP Context under which the agent is reachable (default: /jolokia) + --agentId VM unique identifier used by this agent (default: autogenerated) + --agentDescription Agent description + --authMode Authentication mode: 'basic' (default), 'jaas' or 'delegate' + --authClass Classname of an custom Authenticator which must be loadable from + the classpath + --authUrl URL used for a dispatcher authentication (authMode == delegate) + --authPrincipalSpec Extractor specification for getting the principal + (authMode == delegate) + --authIgnoreCerts Whether to ignore CERTS when doing a dispatching authentication + (authMode == delegate) + --user User used for Basic-Authentication + --password Password used for Basic-Authentication + --quiet No output. "status" will exit with code 0 if the agent is running, + 1 otherwise + --verbose Verbose output + --executor Executor policy for HTTP Threads to use (default: single) + "fixed" -- Thread pool with a fixed number of threads (default: 5) + "cached" -- Cached Thread Pool, creates threads on demand + "single" -- Single Thread + --threadNr Number of fixed threads if "fixed" is used as executor + --backlog How many request to keep in the backlog (default: 10) + --protocol Protocol which must be either "http" or "https" (default: http) + --keystore Path to keystore (https only) + --keystorePassword Password to the keystore (https only) + --useSslClientAuthentication Use client certificate authentication (https only) + --secureSocketProtocol Secure protocol (https only, default: TLS) + --keyStoreType Keystore type (https only, default: JKS) + --keyManagerAlgorithm Key manager algorithm (https only, default: SunX509) + --trustManagerAlgorithm Trust manager algorithm (https only, default: SunX509) + --caCert Path to a PEM encoded CA cert file (https & sslClientAuth only) + --serverCert Path to a PEM encoded server cert file (https only) + --serverKey Path to a PEM encoded server key file (https only) + --serverKeyAlgorithm Algorithm to use for decrypting the server key (https only, default: RSA) + --clientPrincipal Allow only this principal in the client cert (https & sslClientAuth only) + If supplied multiple times, any one of the clientPrincipals must match + --extendedClientCheck Additional validation of client certs for the proper key usage + (https & sslClientAuth only) + --discoveryEnabled Enable/Disable discovery multicast responses (default: true) + --discoveryAgentUrl The URL to use for answering discovery requests. Will be autodetected + if not given. + --sslProtocol SSL / TLS protocol to enable, can be provided multiple times + --sslCipherSuite SSL / TLS cipher suite to enable, can be provided multiple times + --debug Switch on agent debugging + --debugMaxEntries Number of debug entries to keep in memory which can be fetched from the + Jolokia MBean + --maxDepth Maximum number of levels for serialization of beans + --maxCollectionSize Maximum number of element in collections to keep when serializing the + response + --maxObjects Maximum number of objects to consider for serialization --restrictorClass Classname of an custom restrictor which must be loadable from the classpath - --mbeanQualifier Qualifier to use when registering Jolokia internal MBeans - --canonicalNaming whether to use canonicalName for ObjectNames in 'list' or 'search' - (default: true) - --includeStackTrace whether to include StackTraces for error messages (default: true) - --serializeException whether to add a serialized version of the exception in the Jolokia - response (default: false) - --config Path to a property file from where to read the configuration - --help This help documentation - --version Version of this agent + --policyLocation Location of a Jolokia policy file + --mbeanQualifier Qualifier to use when registering Jolokia internal MBeans + --canonicalNaming whether to use canonicalName for ObjectNames in 'list' or 'search' + (default: true) + --includeStackTrace whether to include StackTraces for error messages (default: true) + --serializeException whether to add a serialized version of the exception in the Jolokia + response (default: false) + --config Path to a property file from where to read the configuration + --help This help documentation + --version Version of this agent (it's 1.3.4 btw :) can be either a numeric process id or a regular expression. A regular expression is matched against the processes' names (ignoring case) and must be specific enough to select exactly one process. @@ -560,7 +599,7 @@ If neither nor is given, a list of Java processes along with the is printed There are several possible reasons, why attaching to a process can fail: - * The UID of this launcher must be the very *same*as the process to attach too. It not sufficient + * The UID of this launcher must be the very *same* as the process to attach too. It not sufficient to be root. * The JVM must have HotSpot enabled and be a JVM 1.6 or larger. * It must be a Java process ;-)