1/* 2 * Copyright (c) 2003, 2004, 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 */ 23import sun.management.jmxremote.ConnectorBootstrap; 24 25import java.io.File; 26import java.io.FileInputStream; 27import java.io.InputStream; 28import java.io.FilenameFilter; 29import java.io.IOException; 30 31import java.security.GeneralSecurityException; 32import java.security.KeyStore; 33 34import java.util.Properties; 35import java.util.Iterator; 36import java.util.Set; 37import java.util.Arrays; 38import java.util.ArrayList; 39import java.util.HashMap; 40import java.util.Map; 41import java.util.Enumeration; 42 43import javax.management.remote.*; 44import javax.management.*; 45 46import jdk.internal.agent.AgentConfigurationError; 47 48/** 49 * <p>This class implements unit test for RMI Bootstrap. 50 * When called with no arguments main() looks in the directory indicated 51 * by the "test.src" system property for files called management*ok.properties 52 * or management*ko.properties. The *ok.properties files are assumed to be 53 * valid Java M&M config files for which the bootstrap should succeed. 54 * The *ko.properties files are assumed to be configurations for which the 55 * bootstrap & connection test will fail.</p> 56 * 57 * <p>The rmi port number can be specified with the "rmi.port" system property. 58 * If not, this test will use 12424</p> 59 * 60 * <p>When called with some argument, the main() will interprete its args to 61 * be Java M&M configuration file names. The filenames are expected to end 62 * with ok.properties or ko.properties - and are interpreted as above.</p> 63 * 64 * <p>Note that a limitation of the RMI registry (bug 4267864) prevent 65 * this test from succeeding if more than 1 configuration is used. 66 * As long as 4267864 isn't fix, this test must be called as many times 67 * as needed but with a single argument (no arguments, or several arguments 68 * will fail).</p> 69 * 70 * <p>Debug traces are logged in "sun.management.test"</p> 71 **/ 72public class RmiSslNoKeyStoreTest { 73 74 static TestLogger log = 75 new TestLogger("RmiSslNoKeyStoreTest"); 76 77 /** 78 * When launching several registries, we increment the port number 79 * to avoid falling into "port number already in use" problems. 80 **/ 81 static int testPort = 0; 82 83 /** 84 * Default values for RMI configuration properties. 85 **/ 86 public static interface DefaultValues { 87 public static final String PORT="0"; 88 public static final String CONFIG_FILE_NAME="management.properties"; 89 public static final String USE_SSL="true"; 90 public static final String USE_AUTHENTICATION="true"; 91 public static final String PASSWORD_FILE_NAME="jmxremote.password"; 92 public static final String ACCESS_FILE_NAME="jmxremote.access"; 93 public static final String KEYSTORE="keystore"; 94 public static final String KEYSTORE_PASSWD="password"; 95 public static final String TRUSTSTORE="truststore"; 96 public static final String TRUSTSTORE_PASSWD="trustword"; 97 } 98 99 /** 100 * Names of RMI configuration properties. 101 **/ 102 public static interface PropertyNames { 103 public static final String PORT="com.sun.management.jmxremote.port"; 104 public static final String CONFIG_FILE_NAME= 105 "com.sun.management.config.file"; 106 public static final String USE_SSL="com.sun.management.jmxremote.ssl"; 107 public static final String USE_AUTHENTICATION= 108 "com.sun.management.jmxremote.authenticate"; 109 public static final String PASSWORD_FILE_NAME= 110 "com.sun.management.jmxremote.password.file"; 111 public static final String ACCESS_FILE_NAME= 112 "com.sun.management.jmxremote.access.file"; 113 public static final String INSTRUMENT_ALL= 114 "com.sun.management.instrumentall"; 115 public static final String CREDENTIALS = 116 "jmx.remote.credentials"; 117 public static final String KEYSTORE="javax.net.ssl.keyStore"; 118 public static final String KEYSTORE_PASSWD= 119 "javax.net.ssl.keyStorePassword"; 120 public static final String KEYSTORE_TYPE="javax.net.ssl.keyStoreType"; 121 public static final String TRUSTSTORE="javax.net.ssl.trustStore"; 122 public static final String TRUSTSTORE_PASSWD= 123 "javax.net.ssl.trustStorePassword"; 124 } 125 126 /** 127 * Compute the full path name for a default file. 128 * @param basename basename (with extension) of the default file. 129 * @return ${JRE}/conf/management/${basename} 130 **/ 131 private static String getDefaultFileName(String basename) { 132 final String fileSeparator = File.separator; 133 final StringBuffer defaultFileName = 134 new StringBuffer(System.getProperty("java.home")). 135 append(fileSeparator).append("conf").append(fileSeparator). 136 append("management").append(fileSeparator). 137 append(basename); 138 return defaultFileName.toString(); 139 } 140 141 /** 142 * Compute the full path name for a default file. 143 * @param basename basename (with extension) of the default file. 144 * @return ${JRE}/conf/management/${basename} 145 **/ 146 private static String getDefaultStoreName(String basename) { 147 final String fileSeparator = File.separator; 148 final StringBuffer defaultFileName = 149 new StringBuffer(System.getProperty("test.src")). 150 append(fileSeparator).append("ssl").append(fileSeparator). 151 append(basename); 152 return defaultFileName.toString(); 153 } 154 155 private static void checkKeystore(Properties props) 156 throws IOException, GeneralSecurityException { 157 if (log.isDebugOn()) 158 log.debug("checkKeystore","Checking Keystore configuration"); 159 160 final String keyStore = 161 System.getProperty(PropertyNames.KEYSTORE); 162 if (keyStore == null) 163 throw new IllegalArgumentException("System property " + 164 PropertyNames.KEYSTORE + 165 " not specified"); 166 167 final String keyStorePass = 168 System.getProperty(PropertyNames.KEYSTORE_PASSWD); 169 if (keyStorePass == null) { 170 // We don't have the password, we can only check whether the 171 // file exists... 172 // 173 final File ksf = new File(keyStore); 174 if (! ksf.canRead()) 175 throw new IOException(keyStore + ": not readable"); 176 177 if (log.isDebugOn()) 178 log.debug("checkSSL", "No password."); 179 throw new IllegalArgumentException("System property " + 180 PropertyNames.KEYSTORE_PASSWD + 181 " not specified"); 182 } 183 184 // Now we're going to load the keyStore - just to check it's 185 // correct. 186 // 187 final String keyStoreType = 188 System.getProperty(PropertyNames.KEYSTORE_TYPE, 189 KeyStore.getDefaultType()); 190 final KeyStore ks = KeyStore.getInstance(keyStoreType); 191 final FileInputStream fin = new FileInputStream(keyStore); 192 final char keypassword[] = keyStorePass.toCharArray(); 193 194 try { 195 ks.load(fin,keypassword); 196 } finally { 197 Arrays.fill(keypassword,' '); 198 fin.close(); 199 } 200 201 if (log.isDebugOn()) 202 log.debug("checkSSL","SSL configuration successfully checked"); 203 } 204 205 private void checkSslConfiguration() throws Exception { 206 final String defaultConf = 207 getDefaultFileName(DefaultValues.CONFIG_FILE_NAME); 208 final String confname = 209 System.getProperty(PropertyNames.CONFIG_FILE_NAME,defaultConf); 210 211 final Properties props = new Properties(); 212 final File conf = new File(confname); 213 if (conf.exists()) { 214 FileInputStream fin = new FileInputStream(conf); 215 try {props.load(fin);} finally {fin.close();} 216 } 217 218 // Do we use SSL? 219 final String useSslStr = 220 props.getProperty(PropertyNames.USE_SSL, 221 DefaultValues.USE_SSL); 222 final boolean useSsl = 223 Boolean.valueOf(useSslStr).booleanValue(); 224 225 log.debug("checkSslConfiguration",PropertyNames.USE_SSL+"="+useSsl); 226 if (useSsl == false) { 227 final String msg = 228 PropertyNames.USE_SSL+"="+useSsl+", can't run test"; 229 throw new IllegalArgumentException(msg); 230 } 231 232 try { 233 checkKeystore(props); 234 } catch (Exception x) { 235 // Ok! 236 log.debug("checkSslConfiguration","Test configuration OK: " + x); 237 return; 238 } 239 240 final String msg = "KeyStore properly configured, can't run test"; 241 throw new IllegalArgumentException(msg); 242 } 243 244 /** 245 * Test the configuration indicated by `file'. 246 * Sets the appropriate System properties for config file and 247 * port and then calls ConnectorBootstrap.initialize(). 248 * eventually cleans up by calling ConnectorBootstrap.terminate(). 249 * @return null if the test succeeds, an error message otherwise. 250 **/ 251 private String testConfiguration(File file,int port) { 252 253 final String path = (file==null)?null:file.getAbsolutePath(); 254 final String config = (path==null)?"Default config file":path; 255 256 try { 257 System.out.println("***"); 258 System.out.println("*** Testing configuration (port="+ 259 port + "): "+ path); 260 System.out.println("***"); 261 262 System.setProperty("com.sun.management.jmxremote.port", 263 Integer.toString(port)); 264 if (path != null) 265 System.setProperty("com.sun.management.config.file", path); 266 else 267 System.getProperties(). 268 remove("com.sun.management.config.file"); 269 270 log.trace("testConfiguration","com.sun.management.jmxremote.port="+port); 271 if (path != null && log.isDebugOn()) 272 log.trace("testConfiguration", 273 "com.sun.management.config.file="+path); 274 275 checkSslConfiguration(); 276 277 final JMXConnectorServer cs; 278 try { 279 cs = ConnectorBootstrap.initialize(); 280 } catch (AgentConfigurationError x) { 281 final String err = "Failed to initialize connector:" + 282 "\n\tcom.sun.management.jmxremote.port=" + port + 283 ((path!=null)?"\n\tcom.sun.management.config.file="+path: 284 "\n\t"+config) + 285 "\n\tError is: " + x; 286 287 log.trace("testConfiguration","Expected failure: " + err); 288 log.debug("testConfiguration",x); 289 System.out.println("Got expected failure: " + x); 290 return null; 291 } catch (Exception x) { 292 log.debug("testConfiguration",x); 293 return x.toString(); 294 } 295 try { 296 JMXConnector cc = 297 JMXConnectorFactory.connect(cs.getAddress(), null); 298 cc.close(); 299 } catch (IOException x) { 300 final String err = "Failed to initialize connector:" + 301 "\n\tcom.sun.management.jmxremote.port=" + port + 302 ((path!=null)?"\n\tcom.sun.management.config.file="+path: 303 "\n\t"+config) + 304 "\n\tError is: " + x; 305 306 log.trace("testConfiguration","Expected failure: " + err); 307 log.debug("testConfiguration",x); 308 System.out.println("Got expected failure: " + x); 309 return null; 310 } catch (Exception x) { 311 log.debug("testConfiguration",x); 312 return x.toString(); 313 } 314 try { 315 cs.stop(); 316 } catch (Exception x) { 317 final String err = "Failed to terminate: "+x; 318 log.trace("testConfiguration",err); 319 log.debug("testConfiguration",x); 320 } 321 final String err = "Bootstrap should have failed:" + 322 "\n\tcom.sun.management.jmxremote.port=" + port + 323 ((path!=null)?"\n\tcom.sun.management.config.file="+path: 324 "\n\t"+config); 325 log.trace("testConfiguration",err); 326 return err; 327 } catch (Exception x) { 328 final String err = "Failed to test bootstrap for:" + 329 "\n\tcom.sun.management.jmxremote.port=" + port + 330 ((path!=null)?"\n\tcom.sun.management.config.file="+path: 331 "\n\t"+config)+ 332 "\n\tError is: " + x; 333 334 log.trace("testConfiguration",err); 335 log.debug("testConfiguration",x); 336 return err; 337 } 338 } 339 340 /** 341 * Test a configuration file. Determines whether the bootstrap 342 * should succeed or fail depending on the file name: 343 * *ok.properties: bootstrap should succeed. 344 * *ko.properties: bootstrap or connection should fail. 345 * @return null if the test succeeds, an error message otherwise. 346 **/ 347 private String testConfigurationFile(String fileName) { 348 File file = new File(fileName); 349 final String portStr = System.getProperty("rmi.port","12424"); 350 final int port = Integer.parseInt(portStr); 351 352 return testConfiguration(file,port+testPort++); 353 } 354 355 356 /** 357 * Tests the specified configuration files. 358 * If args[] is not empty, each element in args[] is expected to be 359 * a filename ending either by ok.properties or ko.properties. 360 * Otherwise, the configuration files will be automatically determined 361 * by looking at all *.properties files located in the directory 362 * indicated by the System property "test.src". 363 * @throws RuntimeException if the test fails. 364 **/ 365 public void run(String args[]) { 366 final String defaultKeyStore = 367 getDefaultStoreName(DefaultValues.KEYSTORE); 368 final String keyStore = 369 System.getProperty(PropertyNames.KEYSTORE, defaultKeyStore); 370 371 for (int i=0; i<args.length; i++) { 372 373 String errStr =testConfigurationFile(args[i]); 374 if (errStr != null) { 375 throw new RuntimeException(errStr); 376 } 377 378 if ((System.getProperty(PropertyNames.KEYSTORE) == null) && 379 (System.getProperty(PropertyNames.KEYSTORE_PASSWD) == null)) { 380 try { 381 382 // Specify the keystore, but don't specify the 383 // password. 384 // 385 System.setProperty(PropertyNames.KEYSTORE,keyStore); 386 log.trace("run",PropertyNames.KEYSTORE+"="+keyStore); 387 388 errStr =testConfigurationFile(args[i]); 389 if (errStr != null) { 390 throw new RuntimeException(errStr); 391 } 392 } finally { 393 System.getProperties().remove(PropertyNames.KEYSTORE); 394 } 395 } 396 } 397 } 398 399 /** 400 * Calls run(args[]). 401 * exit(1) if the test fails. 402 **/ 403 public static void main(String args[]) { 404 RmiSslNoKeyStoreTest manager = new RmiSslNoKeyStoreTest(); 405 try { 406 manager.run(args); 407 } catch (RuntimeException r) { 408 System.err.println("Test Failed: "+ r.getMessage()); 409 System.exit(1); 410 } catch (Throwable t) { 411 System.err.println("Test Failed: "+ t); 412 t.printStackTrace(); 413 System.exit(2); 414 } 415 System.out.println("**** Test RmiSslNoKeyStoreTest Passed ****"); 416 } 417 418} 419