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 
  59 import java.io.File;
  60 import java.util.Map ;
  61 import java.util.HashMap ;
  62 import java.util.List;
  63 import java.util.ArrayList;
  64 import java.util.Arrays;
  65 
  66 import javax.management.MBeanServer;
  67 import javax.management.MBeanServerFactory ;
  68 import javax.management.MBeanServerConnection;
  69 import javax.management.remote.JMXConnector;
  70 import javax.management.remote.JMXConnectorFactory;
  71 import javax.management.remote.JMXConnectorServer;
  72 import javax.management.remote.JMXConnectorServerFactory;
  73 import javax.management.remote.JMXServiceURL;
  74 
  75 import javax.management.Attribute ;
  76 import javax.management.ObjectName ;
  77 
  78 import javax.rmi.ssl.SslRMIClientSocketFactory;
  79 import javax.rmi.ssl.SslRMIServerSocketFactory;
  80 
  81 import java.security.Security;
  82 
  83 import jdk.testlibrary.ProcessTools;
  84 import jdk.testlibrary.JDKToolFinder;
  85 
  86 public 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 }