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