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