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
setKeyStoreProperties(Map<String, Object> 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
setTrustStoreProperties(Map<String, Object> 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      */
main(String args[])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
buildSourcePath(String filename)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      */
setServerSecurityEnv(Map<String, Object> map)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      */
createServerSide(Map<String, Object> serverMap)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      */
buildCommandLine(String args[])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      */
runClientSide(String args[], String serviceUrlStr)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 
run(Map<String, Object> serverArgs, String clientArgs[])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 
main(String args[])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 
run(Map<String, Object> args)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 
doRequests()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          */
checkAuthenticator(MBeanServerConnection mbs, int expectedAuthenticatorCallCount)753         protected int checkAuthenticator(MBeanServerConnection mbs,
754                 int expectedAuthenticatorCallCount) throws Exception {
755             int errorCount = 0;
756 
757             // Ensure the authenticator has been called the right number
758             // of times.
759             int callCount =
760                     ((Integer) mbs.getAttribute(
761                     new ObjectName(SERVER_DELEGATE_MBEAN_NAME),
762                     "TestJMXAuthenticatorCallCount")).intValue();
763 
764             if (callCount == expectedAuthenticatorCallCount) {
765                 System.out.println("---- OK Authenticator has been called "
766                         + expectedAuthenticatorCallCount + " time");
767             } else {
768                 errorCount++;
769                 System.out.println("---- ERROR Authenticator has been called " + callCount
770                         + " times in place of " + expectedAuthenticatorCallCount);
771             }
772 
773             // Ensure the provider has been called with
774             // a non null Principal.
775             String principalString =
776                 (String) mbs.getAttribute(
777                 new ObjectName(SERVER_DELEGATE_MBEAN_NAME),
778                 "TestJMXAuthenticatorPrincipalString");
779 
780             if (principalString == null) {
781                 errorCount++;
782                 System.out.println("---- ERROR Authenticator has been called"
783                         + " with a null Principal");
784             } else {
785                 if (principalString.length() > 0) {
786                     System.out.println("---- OK Authenticator has been called"
787                             + " with the Principal " + principalString);
788                 } else {
789                     errorCount++;
790                     System.out.println("---- ERROR Authenticator has been called"
791                             + " with an empty Principal");
792                 }
793             }
794 
795             return errorCount;
796         }
797 
798     }
799 
800 }
801