1/* 2 * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24/* 25 * @test 26 * @bug 8058865 27 * @summary Checks various secure ways of connecting from remote jmx client 28 * @author Olivier Lagneau 29 * @modules java.management.rmi 30 * @library /lib/testlibrary 31 * @compile MBS_Light.java ServerDelegate.java TestSampleLoginModule.java 32 * @run main/othervm/timeout=300 -DDEBUG_STANDARD -Dusername=SQE_username -Dpassword=SQE_password SecurityTest -server -mapType x.password.file -client -mapType credentials 33 * @run main/othervm/timeout=300 -DDEBUG_STANDARD -Dusername=UNKNOWN_username -Dpassword=SQE_password SecurityTest -server -mapType x.password.file -client -mapType credentials -expectedThrowable java.lang.SecurityException 34 * @run main/othervm/timeout=300 -DDEBUG_STANDARD -Dusername=SQE_username -Dpassword=WRONG_password SecurityTest -server -mapType x.password.file -client -mapType credentials -expectedThrowable java.lang.SecurityException 35 * @run main/othervm/timeout=300 -DDEBUG_STANDARD -Dsusername=TestJMXAuthenticatorUsername -Dspassword=TestJMXAuthenticatorPassword -Dusername=TestJMXAuthenticatorUsername -Dpassword=TestJMXAuthenticatorPassword SecurityTest -server -mapType x.authenticator -client -mapType credentials 36 * @run main/othervm/timeout=300 -DDEBUG_STANDARD -Dsusername=TestJMXAuthenticatorUsername -Dspassword=TestJMXAuthenticatorPassword -Dusername=AnotherTestJMXAuthenticatorUsername -Dpassword=TestJMXAuthenticatorPassword SecurityTest -server -mapType x.authenticator -client -mapType credentials -expectedThrowable java.lang.SecurityException 37 * @run main/othervm/timeout=300 -DDEBUG_STANDARD -Dlogin.config.file=${test.src}/login.config -Dpassword.file=password.properties -Dusername=usernameFileLoginModule -Dpassword=passwordFileLoginModule SecurityTest -server -mapType x.login.config.PasswordFileAuthentication -client -mapType credentials 38 * @run main/othervm/timeout=300 -DDEBUG_STANDARD -Dlogin.config.file=${test.src}/login.config.UNKNOWN -Dpassword.file=password.properties -Dusername=usernameFileLoginModule -Dpassword=passwordFileLoginModule SecurityTest -server -mapType x.login.config.PasswordFileAuthentication -client -mapType credentialss -expectedThrowable java.lang.SecurityException 39 * @run main/othervm/timeout=300 -DDEBUG_STANDARD -Dlogin.config.file=${test.src}/login.config -Dpassword.file=password.properties -Dusername=usernameFileLoginModule -Dpassword=passwordFileLoginModule SecurityTest -server -mapType x.login.config.UnknownAuthentication -client -mapType credentials -expectedThrowable java.lang.SecurityException 40 * @run main/othervm/timeout=300 -DDEBUG_STANDARD -Dlogin.config.file=${test.src}/login.config -Dsusername=usernameSampleLoginModule -Dspassword=passwordSampleLoginModule -Dpassword.file=password.properties -Dusername=usernameSampleLoginModule -Dpassword=passwordSampleLoginModule SecurityTest -server -mapType x.login.config.SampleLoginModule -client -mapType credentials 41 * @run main/othervm/timeout=300 -DDEBUG_STANDARD -Dlogin.config.file=${test.src}/login.config -Dsusername=usernameSampleLoginModule -Dspassword=passwordSampleLoginModule -Dpassword.file=password.properties -Dusername=AnotherUsernameSampleLoginModule -Dpassword=passwordSampleLoginModule SecurityTest -server -mapType x.login.config.SampleLoginModule -client -mapType credentials -expectedThrowable java.lang.SecurityException 42 * @run main/othervm/timeout=300 -DDEBUG_STANDARD SecurityTest -server -mapType rmi.client.socket.factory.ssl;rmi.server.socket.factory.ssl -keystore keystoreAgent -keystorepassword glopglop -client -truststore truststoreClient -truststorepassword glopglop 43 * @run main/othervm/timeout=300 -DDEBUG_STANDARD SecurityTest -server -mapType rmi.client.socket.factory.ssl;rmi.server.socket.factory.ssl -keystore keystoreAgent -keystorepassword glopglop -client -truststore truststoreClient -truststorepassword WRONG_password -expectedThrowable java.io.IOException 44 * @run main/othervm/timeout=300 -DDEBUG_STANDARD SecurityTest -server -mapType rmi.server.socket.factory.ssl -keystore keystoreAgent -keystorepassword glopglop -client -truststore truststoreClient -truststorepassword glopglop -expectedThrowable java.io.IOException 45 * @run main/othervm/timeout=300 -DDEBUG_STANDARD SecurityTest -server -mapType rmi.client.socket.factory.ssl -keystore keystoreAgent -keystorepassword glopglop -client -truststore truststoreClient -truststorepassword glopglop -expectedThrowable java.io.IOException 46 * @run main/othervm/timeout=300 -DDEBUG_STANDARD SecurityTest -server -mapType rmi.client.socket.factory.ssl;rmi.server.socket.factory.ssl -keystore keystoreAgent -keystorepassword glopglop -client -expectedThrowable java.io.IOException 47 * @run main/othervm/timeout=300 -DDEBUG_STANDARD SecurityTest -server -mapType rmi.client.socket.factory.ssl;rmi.server.socket.factory.ssl.need.client.authentication -keystore keystoreAgent -keystorepassword glopglop -truststore truststoreAgent -truststorepassword glopglop -client -keystore keystoreClient -keystorepassword glopglop -truststore truststoreClient -truststorepassword glopglop 48 * @run main/othervm/timeout=300 -DDEBUG_STANDARD SecurityTest -server -mapType rmi.client.socket.factory.ssl;rmi.server.socket.factory.ssl.need.client.authentication -keystore keystoreAgent -keystorepassword glopglop -truststore truststoreAgent -truststorepassword glopglop -client -keystore keystoreClient -keystorepassword WRONG_password -truststore truststoreClient -truststorepassword glopglop -expectedThrowable java.io.IOException 49 * @run main/othervm/timeout=300 -DDEBUG_STANDARD SecurityTest -server -mapType rmi.client.socket.factory.ssl;rmi.server.socket.factory.ssl.need.client.authentication -keystore keystoreAgent -keystorepassword glopglop -truststore truststoreAgent -truststorepassword glopglop -client -truststore truststoreClient -truststorepassword glopglop -expectedThrowable java.io.IOException 50 * @run main/othervm/timeout=300 -DDEBUG_STANDARD SecurityTest -server -mapType rmi.client.socket.factory.ssl;rmi.server.socket.factory.ssl.need.client.authentication -keystore keystoreAgent -keystorepassword glopglop -client -keystore keystoreClient -keystorepassword glopglop -truststore truststoreClient -truststorepassword glopglop -expectedThrowable java.io.IOException 51 * @run main/othervm/timeout=300 -DDEBUG_STANDARD -Djavax.rmi.ssl.client.enabledCipherSuites=SSL_RSA_WITH_RC4_128_MD5 SecurityTest -server -mapType rmi.client.socket.factory.ssl;rmi.server.socket.factory.ssl.enabled.cipher.suites.md5 -keystore keystoreAgent -keystorepassword glopglop -client -truststore truststoreClient -truststorepassword glopglop 52 * @run main/othervm/timeout=300 -DDEBUG_STANDARD -Djavax.rmi.ssl.client.enabledCipherSuites=SSL_RSA_WITH_RC4_128_SHA SecurityTest -server -mapType rmi.client.socket.factory.ssl;rmi.server.socket.factory.ssl.enabled.cipher.suites.md5 -keystore keystoreAgent -keystorepassword glopglop -client -truststore truststoreClient -truststorepassword glopglop -expectedThrowable java.io.IOException 53 * @run main/othervm/timeout=300 -DDEBUG_STANDARD -Djavax.rmi.ssl.client.enabledCipherSuites=SSL_RSA_WITH_RC4_128_MD5 SecurityTest -server -mapType rmi.client.socket.factory.ssl;rmi.server.socket.factory.ssl.enabled.cipher.suites.sha -keystore keystoreAgent -keystorepassword glopglop -client -truststore truststoreClient -truststorepassword glopglop -expectedThrowable java.io.IOException 54 * @run main/othervm/timeout=300 -DDEBUG_STANDARD -Djavax.rmi.ssl.client.enabledProtocols=SSLv3 SecurityTest -server -mapType rmi.client.socket.factory.ssl;rmi.server.socket.factory.ssl.enabled.protocols.sslv3 -keystore keystoreAgent -keystorepassword glopglop -client -truststore truststoreClient -truststorepassword glopglop 55 * @run main/othervm/timeout=300 -DDEBUG_STANDARD -Djavax.rmi.ssl.client.enabledProtocols=TLSv1 SecurityTest -server -mapType rmi.client.socket.factory.ssl;rmi.server.socket.factory.ssl.enabled.protocols.sslv3 -keystore keystoreAgent -keystorepassword glopglop -client -truststore truststoreClient -truststorepassword glopglop -expectedThrowable java.io.IOException 56 * @run main/othervm/timeout=300 -DDEBUG_STANDARD -Djavax.rmi.ssl.client.enabledProtocols=SSLv3 SecurityTest -server -mapType rmi.client.socket.factory.ssl;rmi.server.socket.factory.ssl.enabled.protocols.tlsv1 -keystore keystoreAgent -keystorepassword glopglop -client -truststore truststoreClient -truststorepassword glopglop -expectedThrowable java.io.IOException 57 */ 58 59import java.io.File; 60import java.util.Map ; 61import java.util.HashMap ; 62import java.util.List; 63import java.util.ArrayList; 64import java.util.Arrays; 65 66import javax.management.MBeanServer; 67import javax.management.MBeanServerFactory ; 68import javax.management.MBeanServerConnection; 69import javax.management.remote.JMXConnector; 70import javax.management.remote.JMXConnectorFactory; 71import javax.management.remote.JMXConnectorServer; 72import javax.management.remote.JMXConnectorServerFactory; 73import javax.management.remote.JMXServiceURL; 74 75import javax.management.Attribute ; 76import javax.management.ObjectName ; 77 78import javax.rmi.ssl.SslRMIClientSocketFactory; 79import javax.rmi.ssl.SslRMIServerSocketFactory; 80 81import java.security.Security; 82 83import jdk.testlibrary.ProcessTools; 84import jdk.testlibrary.JDKToolFinder; 85 86public class SecurityTest { 87 88 static final String SERVER_CLASS_NAME = "SecurityTest"; 89 static final String CLIENT_CLASS_NAME = "SecurityTest$ClientSide"; 90 static final String CLIENT_CLASS_MAIN = CLIENT_CLASS_NAME; 91 92 static final String USERNAME_PROPERTY = "username"; 93 static final String PASSWORD_PROPERTY = "password"; 94 95 static final String SERVER_DELEGATE_MBEAN_NAME = 96 "defaultDomain:class=ServerDelegate"; 97 98 static final String RMI_SERVER_SOCKET_FACTORY_SSL = "rmi.server.socket.factory.ssl"; 99 static final String RMI_CLIENT_SOCKET_FACTORY_SSL = "rmi.client.socket.factory.ssl"; 100 static final String KEYSTORE_PROPNAME = "javax.net.ssl.keyStore"; 101 static final String KEYSTORE_PWD_PROPNAME = "javax.net.ssl.keyStorePassword"; 102 static final String TRUSTSTORE_PROPNAME = "javax.net.ssl.trustStore"; 103 static final String TRUSTSTORE_PWD_PROPNAME = "javax.net.ssl.trustStorePassword"; 104 105 static final String RMI_SSL_CLIENT_ENABLEDCIPHERSUITES = 106 "javax.rmi.ssl.client.enabledCipherSuites"; 107 static final String RMI_SSL_CLIENT_ENABLEDPROTOCOLS = 108 "javax.rmi.ssl.client.enabledProtocols"; 109 110 private JMXConnectorServer cs; 111 112 // Construct and set keyStore properties from given map 113 static void setKeyStoreProperties(Map<String, Object> map) { 114 115 String keyStore = (String) map.get("-keystore"); 116 keyStore = buildSourcePath(keyStore); 117 System.setProperty(KEYSTORE_PROPNAME, keyStore); 118 System.out.println("keyStore location = \"" + keyStore + "\""); 119 120 String password = (String) map.get("-keystorepassword"); 121 System.setProperty(KEYSTORE_PWD_PROPNAME, password); 122 System.out.println("keyStore password = " + password); 123 124 } 125 126 // Construct and set trustStore properties from given map 127 static void setTrustStoreProperties(Map<String, Object> map) { 128 129 String trustStore = (String) map.get("-truststore"); 130 trustStore = buildSourcePath(trustStore); 131 System.setProperty(TRUSTSTORE_PROPNAME, trustStore); 132 System.out.println("trustStore location = \"" + trustStore + "\""); 133 134 String password = (String) map.get("-truststorepassword"); 135 System.setProperty(TRUSTSTORE_PWD_PROPNAME, password); 136 System.out.println("trustStore password = " + password); 137 138 } 139 140 /* 141 * First Debug properties and arguments are collect in expected 142 * map (argName, value) format, then calls original test's run method. 143 */ 144 public static void main(String args[]) throws Exception { 145 146 System.out.println("================================================="); 147 148 // Parses parameters 149 Utils.parseDebugProperties(); 150 151 // Supported parameters list format is : 152 // "MainClass [-server <param-spec> ...] [-client <param-spec> ...] 153 // with <param-spec> either "-parami valuei" or "-parami" 154 HashMap<String, Object> serverMap = new HashMap<>() ; 155 int clientArgsIndex = 156 Utils.parseServerParameters(args, SERVER_CLASS_NAME, serverMap); 157 158 // Extract and records client params 159 String[] clientParams = null; 160 if (clientArgsIndex < args.length) { 161 int clientParamsSize = args.length - clientArgsIndex; 162 clientParams = new String[clientParamsSize]; 163 System.arraycopy(args, clientArgsIndex, clientParams, 0, clientParamsSize); 164 } else { 165 clientParams = new String[0]; 166 } 167 168 // Run test 169 SecurityTest test = new SecurityTest(); 170 test.run(serverMap, clientParams); 171 172 } 173 174 // Return full path of filename in the test sopurce directory 175 private static String buildSourcePath(String filename) { 176 return System.getProperty("test.src") + File.separator + filename; 177 } 178 179 /* 180 * Collects security run params for server side. 181 */ 182 private HashMap<String, Object> setServerSecurityEnv(Map<String, Object> map) 183 throws Exception { 184 185 // Creates Authentication environment from server side params 186 HashMap<String, Object> env = new HashMap<>(); 187 188 // Retrieve and set keystore and truststore config if any 189 if (map.containsKey("-keystore") && 190 map.get("-keystore") != null) { 191 setKeyStoreProperties(map); 192 } 193 System.out.println("Done keystore properties"); 194 195 if (map.containsKey("-truststore") && 196 map.get("-truststore") != null) { 197 setTrustStoreProperties(map); 198 } 199 System.out.println("Done truststore properties"); 200 201 String value = null; 202 if ((value = (String)map.get("-mapType")) != null) { 203 204 // Case of remote password file with all authorized credentials 205 if (value.contains("x.password.file")) { 206 String passwordFileStr = buildSourcePath("password.properties"); 207 env.put("jmx.remote.x.password.file", passwordFileStr); 208 System.out.println("Added " + passwordFileStr + 209 " file as jmx.remote.x.password.file"); 210 } 211 212 // Case of dedicated authenticator class : TestJMXAuthenticator 213 if (value.contains("x.authenticator")) { 214 env.put("jmx.remote.authenticator", new TestJMXAuthenticator()) ; 215 System.out.println( 216 "Added \"jmx.remote.authenticator\" = TestJMXAuthenticator"); 217 } 218 219 // Case of security config file with standard Authentication 220 if (value.contains("x.login.config.PasswordFileAuthentication")) { 221 String loginConfig = System.getProperty("login.config.file"); 222 223 // Override the default JAAS configuration 224 System.setProperty("java.security.auth.login.config", 225 "file:" + loginConfig); 226 System.out.println("Overrided default JAAS configuration with " + 227 "\"java.security.auth.login.config\" = \"" + loginConfig + "\"") ; 228 229 env.put("jmx.remote.x.login.config", "PasswordFileAuthentication") ; 230 System.out.println( 231 "Added \"jmx.remote.x.login.config\" = " + 232 "\"PasswordFileAuthentication\"") ; 233 234 // redirects "password.file" property to file in ${test.src} 235 String passwordFileStr = 236 buildSourcePath(System.getProperty("password.file")); 237 System.setProperty("password.file", passwordFileStr); 238 System.out.println( 239 "Redirected \"password.file\" property value to = " + 240 passwordFileStr) ; 241 } 242 243 // Case of security config file with unexisting athentication config 244 if (value.contains("x.login.config.UnknownAuthentication")) { 245 String loginConfig = System.getProperty("login.config.file"); 246 247 // Override the default JAAS configuration 248 System.setProperty("java.security.auth.login.config", 249 "file:" + loginConfig); 250 System.out.println("Overrided default JAAS configuration with " + 251 "\"java.security.auth.login.config\" = \"" + loginConfig + "\"") ; 252 253 env.put("jmx.remote.x.login.config", "UnknownAuthentication") ; 254 System.out.println( 255 "Added \"jmx.remote.x.login.config\" = " + 256 "\"UnknownAuthentication\"") ; 257 258 // redirects "password.file" property to file in ${test.src} 259 String passwordFileStr = 260 buildSourcePath(System.getProperty("password.file")); 261 System.setProperty("password.file", passwordFileStr); 262 System.out.println( 263 "Redirected \"password.file\" property value to = " + 264 passwordFileStr) ; 265 } 266 267 // Case of security config file with dedicated login module 268 if (value.contains("x.login.config.SampleLoginModule")) { 269 String loginConfig = System.getProperty("login.config.file"); 270 271 // Override the default JAAS configuration 272 System.setProperty("java.security.auth.login.config", 273 "file:" + loginConfig); 274 System.out.println("Overrided default JAAS configuration with " + 275 "\"java.security.auth.login.config\" = \"" + loginConfig + "\"") ; 276 277 env.put("jmx.remote.x.login.config", "SampleLoginModule") ; 278 System.out.println( 279 "Added \"jmx.remote.x.login.config\" = " + 280 "\"SampleLoginModule\"") ; 281 } 282 283 // Simple rmi ssl authentication 284 if (value.contains(RMI_CLIENT_SOCKET_FACTORY_SSL)) { 285 env.put("jmx.remote.rmi.client.socket.factory", 286 new SslRMIClientSocketFactory()) ; 287 System.out.println( 288 "Added \"jmx.remote.rmi.client.socket.factory\"" + 289 " = SslRMIClientSocketFactory") ; 290 } 291 292 if (value.contains(RMI_SERVER_SOCKET_FACTORY_SSL)) { 293 if (value.contains( 294 "rmi.server.socket.factory.ssl.need.client.authentication")) { 295 // rmi ssl authentication with client authentication 296 env.put("jmx.remote.rmi.server.socket.factory", 297 new SslRMIServerSocketFactory(null, null, true)) ; 298 System.out.println( 299 "Added \"jmx.remote.rmi.server.socket.factory\"" + 300 " = SslRMIServerSocketFactory with client authentication") ; 301 302 } else if (value.contains("rmi.server.socket.factory.ssl.enabled.cipher.suites.md5")) { 303 // Allows all ciphering and protocols for testing purpose 304 Security.setProperty("jdk.tls.disabledAlgorithms", ""); 305 306 env.put("jmx.remote.rmi.server.socket.factory", 307 new SslRMIServerSocketFactory( 308 new String[] {"SSL_RSA_WITH_RC4_128_MD5"}, null, false)); 309 System.out.println( 310 "Added \"jmx.remote.rmi.server.socket.factory\"" + 311 " = SslRMIServerSocketFactory with SSL_RSA_WITH_RC4_128_MD5 cipher suite"); 312 313 } else if (value.contains("rmi.server.socket.factory.ssl.enabled.cipher.suites.sha")) { 314 // Allows all ciphering and protocols for testing purpose 315 Security.setProperty("jdk.tls.disabledAlgorithms", ""); 316 317 env.put("jmx.remote.rmi.server.socket.factory", 318 new SslRMIServerSocketFactory( 319 new String[] { "SSL_RSA_WITH_RC4_128_SHA" }, null, false)) ; 320 System.out.println( 321 "Added \"jmx.remote.rmi.server.socket.factory\"" + 322 " = SslRMIServerSocketFactory with SSL_RSA_WITH_RC4_128_SHA cipher suite") ; 323 324 } else if (value.contains("rmi.server.socket.factory.ssl.enabled.protocols.sslv3")) { 325 // Allows all ciphering and protocols for testing purpose 326 Security.setProperty("jdk.tls.disabledAlgorithms", ""); 327 328 env.put("jmx.remote.rmi.server.socket.factory", 329 new SslRMIServerSocketFactory(null, new String[] {"SSLv3"}, false)) ; 330 System.out.println( 331 "Added \"jmx.remote.rmi.server.socket.factory\"" + 332 " = SslRMIServerSocketFactory with SSLv3 protocol") ; 333 334 } else if (value.contains("rmi.server.socket.factory.ssl.enabled.protocols.tlsv1")) { 335 // Allows all ciphering and protocols for testing purpose 336 Security.setProperty("jdk.tls.disabledAlgorithms", ""); 337 338 env.put("jmx.remote.rmi.server.socket.factory", 339 new SslRMIServerSocketFactory(null, new String[] {"TLSv1"}, false)) ; 340 System.out.println( 341 "Added \"jmx.remote.rmi.server.socket.factory\"" + 342 " = SslRMIServerSocketFactory with TLSv1 protocol") ; 343 344 } else { 345 env.put("jmx.remote.rmi.server.socket.factory", 346 new SslRMIServerSocketFactory()); 347 System.out.println( 348 "Added \"jmx.remote.rmi.server.socket.factory\"" + 349 " = SslRMIServerSocketFactory"); 350 } 351 } 352 } 353 354 return env; 355 } 356 357 /* 358 * Create the MBeansServer side of the test and returns its address 359 */ 360 private JMXServiceURL createServerSide(Map<String, Object> serverMap) 361 throws Exception { 362 final int NINETY_SECONDS = 90; 363 364 System.out.println("SecurityTest::createServerSide: Start") ; 365 366 // Prepare server side security env 367 HashMap<String, Object> env = setServerSecurityEnv(serverMap); 368 369 // Create and start mbean server and connector server 370 MBeanServer mbs = MBeanServerFactory.newMBeanServer(); 371 JMXServiceURL url = new JMXServiceURL("rmi", null, 0); 372 cs = JMXConnectorServerFactory.newJMXConnectorServer(url, env, mbs); 373 cs.start(); 374 375 // Waits availibility of connector server 376 Utils.waitReady(cs, NINETY_SECONDS); 377 378 JMXServiceURL addr = cs.getAddress(); 379 380 System.out.println("SecurityTest::createServerSide: Done.") ; 381 382 return addr; 383 } 384 385 /* 386 * Creating command-line for running subprocess JVM: 387 * 388 * JVM command line is like: 389 * {test_jdk}/bin/java {defaultopts} -cp {test.class.path} {testopts} main 390 * 391 * {defaultopts} are the default java options set by the framework. 392 * 393 */ 394 private List<String> buildCommandLine(String args[]) { 395 396 System.out.println("SecurityTest::buildCommandLine: Start") ; 397 398 List<String> opts = new ArrayList<>(); 399 opts.add(JDKToolFinder.getJDKTool("java")); 400 opts.addAll(Arrays.asList(jdk.testlibrary.Utils.getTestJavaOpts())); 401 402 // We need to forward some properties to the client side 403 opts.add("-Dtest.src=" + System.getProperty("test.src")); 404 405 String usernameValue = System.getProperty(USERNAME_PROPERTY); 406 if (usernameValue != null) { 407 System.out.println("SecurityTest::buildCommandLine: "+ 408 " forward username property to client side"); 409 opts.add("-D" + USERNAME_PROPERTY + "=" + usernameValue); 410 } 411 String passwordValue = System.getProperty(PASSWORD_PROPERTY); 412 if (passwordValue != null) { 413 System.out.println("SecurityTest::buildCommandLine: "+ 414 " forward password property to client side"); 415 opts.add("-D" + PASSWORD_PROPERTY + "=" + passwordValue); 416 } 417 418 String enabledCipherSuites = 419 System.getProperty(RMI_SSL_CLIENT_ENABLEDCIPHERSUITES); 420 if (enabledCipherSuites != null) { 421 System.out.println("SecurityTest::buildCommandLine: "+ 422 " forward enabledCipherSuites property to client side"); 423 opts.add("-D" + RMI_SSL_CLIENT_ENABLEDCIPHERSUITES + 424 "=" + enabledCipherSuites); 425 } 426 427 String enabledProtocols = 428 System.getProperty(RMI_SSL_CLIENT_ENABLEDPROTOCOLS); 429 if (enabledProtocols != null) { 430 System.out.println("SecurityTest::buildCommandLine: "+ 431 " forward enabledProtocols property to client side"); 432 opts.add("-D" + RMI_SSL_CLIENT_ENABLEDPROTOCOLS + 433 "=" + enabledProtocols); 434 } 435 436 opts.add("-cp"); 437 opts.add(System.getProperty("test.class.path", "test.class.path")); 438 opts.add(CLIENT_CLASS_MAIN); 439 opts.addAll(Arrays.asList(args)); 440 441 System.out.println("SecurityTest::buildCommandLine: Done.") ; 442 443 return opts; 444 } 445 446 /** 447 * Runs SecurityTest$ClientSide with the passed options and redirects 448 * subprocess standard I/O to the current (parent) process. This provides a 449 * trace of what happens in the subprocess while it is runnning (and before 450 * it terminates). 451 * 452 * @param serviceUrlStr string representing the JMX service Url to connect to. 453 */ 454 private int runClientSide(String args[], String serviceUrlStr) throws Exception { 455 456 System.out.println("SecurityTest::runClientSide: Start") ; 457 458 // Building command-line 459 List<String> opts = buildCommandLine(args); 460 opts.add("-serviceUrl"); 461 opts.add(serviceUrlStr); 462 463 // Launch separate JVM subprocess 464 int exitCode = 0; 465 String[] optsArray = opts.toArray(new String[0]); 466 ProcessBuilder pb = new ProcessBuilder(optsArray); 467 Process p = ProcessTools.startProcess("SecurityTest$ClientSide", pb); 468 469 // Handling end of subprocess 470 try { 471 exitCode = p.waitFor(); 472 if (exitCode != 0) { 473 System.out.println( 474 "Subprocess unexpected exit value of [" + exitCode + 475 "]. Expected 0.\n"); 476 } 477 } catch (InterruptedException e) { 478 System.out.println("Parent process interrupted with exception : \n " + e + " :" ); 479 480 // Parent thread unknown state, killing subprocess. 481 p.destroyForcibly(); 482 483 throw new RuntimeException( 484 "Parent process interrupted with exception : \n " + e + " :" ); 485 486 } finally { 487 if (p.isAlive()) { 488 p.destroyForcibly(); 489 } 490 491 System.out.println("SecurityTest::runClientSide: Done") ; 492 493 return exitCode; 494 } 495 496 } 497 498 public void run(Map<String, Object> serverArgs, String clientArgs[]) { 499 500 System.out.println("SecurityTest::run: Start") ; 501 int errorCount = 0; 502 503 try { 504 // Initialise the server side 505 JMXServiceURL urlToUse = createServerSide(serverArgs); 506 507 // Run client side 508 errorCount = runClientSide(clientArgs, urlToUse.toString()); 509 510 if ( errorCount == 0 ) { 511 System.out.println("SecurityTest::run: Done without any error") ; 512 } else { 513 System.out.println( 514 "SecurityTest::run: Done with " + errorCount + " error(s)"); 515 throw new RuntimeException("errorCount = " + errorCount); 516 } 517 518 cs.stop(); 519 520 } catch(Exception e) { 521 throw new RuntimeException(e); 522 } 523 524 } 525 526 private static class ClientSide { 527 528 private JMXConnector cc = null; 529 private MBeanServerConnection mbsc = null; 530 531 public static void main(String args[]) throws Exception { 532 533 // Parses parameters 534 Utils.parseDebugProperties(); 535 536 // Supported parameters list format is : "MainClass [-client <param-spec> ...] 537 // with <param-spec> either "-parami valuei" or "-parami" 538 HashMap<String, Object> clientMap = new HashMap<>() ; 539 Utils.parseClientParameters(args, CLIENT_CLASS_NAME, clientMap); 540 541 // Run test 542 ClientSide test = new ClientSide(); 543 test.run(clientMap); 544 } 545 546 public void run(Map<String, Object> args) { 547 548 System.out.println("ClientSide::run: Start"); 549 int errorCount = 0; 550 551 try { 552 // Setup client side parameters 553 HashMap<String, Object> env = new HashMap<>(); 554 555 // If needed allows all ciphering and protocols for testing purpose 556 if (System.getProperty(RMI_SSL_CLIENT_ENABLEDCIPHERSUITES) != null) { 557 Security.setProperty("jdk.tls.disabledAlgorithms", ""); 558 } 559 560 // If needed allows all ciphering and protocols for testing purpose 561 if (System.getProperty(RMI_SSL_CLIENT_ENABLEDPROTOCOLS) != null) { 562 Security.setProperty("jdk.tls.disabledAlgorithms", ""); 563 } 564 565 // Retrieve and set keystore and truststore config if any 566 if (args.containsKey("-keystore") && 567 args.get("-keystore") != null) { 568 SecurityTest.setKeyStoreProperties(args); 569 } 570 if (args.containsKey("-truststore") && 571 args.get("-truststore") != null) { 572 SecurityTest.setTrustStoreProperties(args); 573 } 574 575 Object value = args.get("-mapType"); 576 if ((value != null) && 577 value.equals("credentials")) { 578 String username = System.getProperty("username"); 579 String password = System.getProperty("password"); 580 Utils.debug(Utils.DEBUG_STANDARD, 581 "add \"jmx.remote.credentials\" = \"" + 582 username + "\", \"" + password + "\""); 583 env.put("jmx.remote.credentials", 584 new String[] { username , password }); 585 } 586 587 String expectedThrowable = (String) args.get("-expectedThrowable"); 588 589 String authCallCountName = "-expectedAuthenticatorCallCount"; 590 int authCallCountValue = 0; 591 if (args.containsKey(authCallCountName)) { 592 authCallCountValue = 593 (new Integer((String) args.get(authCallCountName))).intValue(); 594 } 595 596 try { 597 // Get a connection to remote mbean server 598 JMXServiceURL addr = new JMXServiceURL((String)args.get("-serviceUrl")); 599 cc = JMXConnectorFactory.connect(addr,env); 600 mbsc = cc.getMBeanServerConnection(); 601 602 // In case we should have got an exception 603 if (expectedThrowable != null) { 604 System.out.println("ClientSide::run: (ERROR) " + 605 " Connect did not fail with expected " + expectedThrowable); 606 errorCount++; 607 } else { 608 System.out.println("ClientSide::run: (OK) Connect succeed"); 609 } 610 } catch (Throwable e) { 611 Utils.printThrowable(e, true); 612 if (expectedThrowable != null) { 613 if (Utils.compareThrowable(e, expectedThrowable)) { 614 System.out.println("ClientSide::run: (OK) " + 615 "Connect failed with expected " + expectedThrowable); 616 } else { 617 System.out.println("ClientSide::run: (ERROR) Connect failed with " + 618 e.getClass() + " instead of expected " + 619 expectedThrowable); 620 errorCount++; 621 } 622 } else { 623 System.out.println("ClientSide::run: (ERROR) " + 624 "Connect failed with exception"); 625 errorCount++; 626 } 627 } 628 629 // Depending on the client state, 630 // perform some requests 631 if (mbsc != null && errorCount == 0) { 632 // Perform some little JMX requests 633 System.out.println("ClientSide::run: Start sending requests"); 634 635 doRequests(); 636 637 // In case authentication has been used we check how it did. 638 if (authCallCountValue != 0) { 639 errorCount += checkAuthenticator(mbsc, authCallCountValue); 640 } 641 } 642 } catch (Exception e) { 643 Utils.printThrowable(e, true); 644 errorCount++; 645 } finally { 646 // Terminate the JMX Client if any 647 if (cc != null) { 648 try { 649 cc.close(); 650 } catch (Exception e) { 651 Utils.printThrowable(e, true) ; 652 errorCount++; 653 } 654 } 655 } 656 657 System.out.println("ClientSide::run: Done"); 658 659 // Handle result 660 if (errorCount != 0) { 661 throw new RuntimeException(); 662 } 663 } 664 665 private void doRequests() throws Exception { 666 667 // Send some requests to the remote JMX server 668 ObjectName objName1 = 669 new ObjectName("TestDomain:class=MBS_Light,rank=1"); 670 String mbeanClass = "MBS_Light"; 671 Exception exception = new Exception("MY TEST EXCEPTION"); 672 Attribute attException = new Attribute("AnException", exception); 673 Error error = new Error("MY TEST ERROR"); 674 Attribute attError = new Attribute("AnError", error); 675 String opParamString = "TOTORO"; 676 RjmxMBeanParameter opParam = new RjmxMBeanParameter(opParamString); 677 Object[] params1 = {opParamString}; 678 String[] sig1 = {"java.lang.String"}; 679 Object[] params2 = {opParam}; 680 String[] sig2 = {"RjmxMBeanParameter"}; 681 682 // Create and register the MBean 683 Utils.debug(Utils.DEBUG_STANDARD, 684 "ClientSide::doRequests: Create and register the MBean"); 685 mbsc.createMBean(mbeanClass, objName1); 686 if (!mbsc.isRegistered(objName1)) { 687 throw new Exception("Unable to register an MBean"); 688 } 689 690 // Set attributes of the MBean 691 Utils.debug(Utils.DEBUG_STANDARD, 692 "ClientSide::doRequests: Set attributes of the MBean"); 693 mbsc.setAttribute(objName1, attException); 694 mbsc.setAttribute(objName1, attError); 695 696 // Get attributes of the MBean 697 Utils.debug(Utils.DEBUG_STANDARD, 698 "ClientSide::doRequests: Get attributes of the MBean"); 699 Exception retException = 700 (Exception) mbsc.getAttribute(objName1,"AnException"); 701 if (!retException.getMessage().equals(exception.getMessage())) { 702 System.out.println("Expected = " + exception); 703 System.out.println("Got = " + retException); 704 throw new Exception("Attribute AnException not as expected"); 705 } 706 Error retError = (Error) mbsc.getAttribute(objName1, "AnError"); 707 if (!retError.getMessage().equals(error.getMessage())) { 708 System.out.println("Expected = " + error); 709 System.out.println("Got = " + retError); 710 throw new Exception("Attribute AnError not as expected"); 711 } 712 713 // Invoke operations on the MBean 714 Utils.debug(Utils.DEBUG_STANDARD, 715 "ClientSide::doRequests: Invoke operations on the MBean"); 716 RjmxMBeanParameter res1 = 717 (RjmxMBeanParameter) mbsc.invoke(objName1, "operate1", params1, sig1); 718 if (!res1.equals(opParam)) { 719 System.out.println("Expected = " + opParam); 720 System.out.println("Got = " + res1); 721 throw new Exception("Operation operate1 behaved badly"); 722 } 723 String res2 = 724 (String) mbsc.invoke(objName1, "operate2", params2, sig2); 725 if (!res2.equals(opParamString)) { 726 System.out.println("Expected = " + opParamString); 727 System.out.println("Got = " + res2); 728 throw new Exception("Operation operate2 behaved badly"); 729 } 730 731 // Unregister the MBean 732 Utils.debug(Utils.DEBUG_STANDARD, 733 "ClientSide::doRequests: Unregister the MBean"); 734 mbsc.unregisterMBean(objName1); 735 if (mbsc.isRegistered(objName1)) { 736 throw new Exception("Unable to unregister an MBean"); 737 } 738 } 739 740 /** 741 * Make some check about the instance of TestJMXAuthenticator. 742 * The authenticator is supposed to have set some properties on 743 * a ServerDelegate MBean. 744 * We compare the number of times it has been called with the expected value. 745 * We also check the Principal that has been given to the authenticator 746 * was not null. 747 * That method is of use to authentication with the JSR 262. 748 * @param mbs 749 * @param expectedAuthenticatorCallCount 750 * @return The number of errors encountered. 751 * @throws java.lang.Exception 752 */ 753 protected int checkAuthenticator(MBeanServerConnection mbs, 754 int expectedAuthenticatorCallCount) throws Exception { 755 int errorCount = 0; 756 757 // Ensure the authenticator has been called the right number 758 // of times. 759 int callCount = 760 ((Integer) mbs.getAttribute( 761 new ObjectName(SERVER_DELEGATE_MBEAN_NAME), 762 "TestJMXAuthenticatorCallCount")).intValue(); 763 764 if (callCount == expectedAuthenticatorCallCount) { 765 System.out.println("---- OK Authenticator has been called " 766 + expectedAuthenticatorCallCount + " time"); 767 } else { 768 errorCount++; 769 System.out.println("---- ERROR Authenticator has been called " + callCount 770 + " times in place of " + expectedAuthenticatorCallCount); 771 } 772 773 // Ensure the provider has been called with 774 // a non null Principal. 775 String principalString = 776 (String) mbs.getAttribute( 777 new ObjectName(SERVER_DELEGATE_MBEAN_NAME), 778 "TestJMXAuthenticatorPrincipalString"); 779 780 if (principalString == null) { 781 errorCount++; 782 System.out.println("---- ERROR Authenticator has been called" 783 + " with a null Principal"); 784 } else { 785 if (principalString.length() > 0) { 786 System.out.println("---- OK Authenticator has been called" 787 + " with the Principal " + principalString); 788 } else { 789 errorCount++; 790 System.out.println("---- ERROR Authenticator has been called" 791 + " with an empty Principal"); 792 } 793 } 794 795 return errorCount; 796 } 797 798 } 799 800} 801