SessionTimeOutTests.java revision 13213:416039f8eef1
1/* 2 * Copyright (c) 2001, 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// SunJSSE does not support dynamic system properties, no way to re-use 25// system properties in samevm/agentvm mode. 26 27/* 28 * @test 29 * @bug 4366807 30 * @summary Need new APIs to get/set session timeout and session cache size. 31 * @run main/othervm SessionTimeOutTests 32 */ 33 34import java.io.*; 35import java.net.*; 36import javax.net.ssl.*; 37import java.util.*; 38import java.security.*; 39import java.util.concurrent.atomic.AtomicInteger; 40 41/** 42 * Session reuse time-out tests cover the cases below: 43 * 1. general test, i.e timeout is set to x and session invalidates when 44 * its lifetime exceeds x. 45 * 2. Effect of changing the timeout limit. 46 * The test suite does not cover the default timeout(24 hours) usage. This 47 * case has been tested independetly. 48 * 49 * Invairant for passing this test is, at any given time, 50 * lifetime of a session < current_session_timeout, such that 51 * current_session_timeout > 0, for all sessions cached by the session 52 * context. 53 */ 54 55public class SessionTimeOutTests { 56 57 /* 58 * ============================================================= 59 * Set the various variables needed for the tests, then 60 * specify what tests to run on each side. 61 */ 62 63 /* 64 * Should we run the client or server in a separate thread? 65 * Both sides can throw exceptions, but do you have a preference 66 * as to which side should be the main thread. 67 */ 68 static boolean separateServerThread = true; 69 70 /* 71 * Where do we find the keystores? 72 */ 73 static String pathToStores = "../etc"; 74 static String keyStoreFile = "keystore"; 75 static String trustStoreFile = "truststore"; 76 static String passwd = "passphrase"; 77 78 private static int PORTS = 3; 79 80 /* 81 * Is the server ready to serve? 82 */ 83 AtomicInteger serverReady = new AtomicInteger(PORTS); 84 85 /* 86 * Turn on SSL debugging? 87 */ 88 static boolean debug = false; 89 90 /* 91 * If the client or server is doing some kind of object creation 92 * that the other side depends on, and that thread prematurely 93 * exits, you may experience a hang. The test harness will 94 * terminate all hung threads after its timeout has expired, 95 * currently 3 minutes by default, but you might try to be 96 * smart about it.... 97 */ 98 99 /* 100 * Define the server side of the test. 101 * 102 * If the server prematurely exits, serverReady will be set to zero 103 * to avoid infinite hangs. 104 */ 105 106 /* 107 * A limit on the number of connections at any given time 108 */ 109 static int MAX_ACTIVE_CONNECTIONS = 3; 110 111 void doServerSide(int serverPort, int serverConns) throws Exception { 112 113 SSLServerSocket sslServerSocket = 114 (SSLServerSocket) sslssf.createServerSocket(serverPort); 115 serverPorts[createdPorts++] = sslServerSocket.getLocalPort(); 116 117 /* 118 * Signal Client, we're ready for his connect. 119 */ 120 serverReady.getAndDecrement(); 121 int read = 0; 122 int nConnections = 0; 123 SSLSession sessions [] = new SSLSession [serverConns]; 124 125 while (nConnections < serverConns) { 126 SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept(); 127 InputStream sslIS = sslSocket.getInputStream(); 128 OutputStream sslOS = sslSocket.getOutputStream(); 129 read = sslIS.read(); 130 sessions[nConnections] = sslSocket.getSession(); 131 sslOS.write(85); 132 sslOS.flush(); 133 sslSocket.close(); 134 nConnections++; 135 } 136 } 137 138 /* 139 * Define the client side of the test. 140 * 141 * If the server prematurely exits, serverReady will be set to zero 142 * to avoid infinite hangs. 143 */ 144 void doClientSide() throws Exception { 145 146 /* 147 * Wait for server to get started. 148 */ 149 while (serverReady.get() > 0) { 150 Thread.sleep(50); 151 } 152 153 int nConnections = 0; 154 SSLSocket sslSockets[] = new SSLSocket [MAX_ACTIVE_CONNECTIONS]; 155 Vector sessions = new Vector(); 156 SSLSessionContext sessCtx = sslctx.getClientSessionContext(); 157 158 sessCtx.setSessionTimeout(10); // in secs 159 int timeout = sessCtx.getSessionTimeout(); 160 while (nConnections < MAX_ACTIVE_CONNECTIONS) { 161 // divide the connections among the available server ports 162 sslSockets[nConnections] = (SSLSocket) sslsf. 163 createSocket("localhost", 164 serverPorts [nConnections % (serverPorts.length)]); 165 InputStream sslIS = sslSockets[nConnections].getInputStream(); 166 OutputStream sslOS = sslSockets[nConnections].getOutputStream(); 167 sslOS.write(237); 168 sslOS.flush(); 169 int read = sslIS.read(); 170 SSLSession sess = sslSockets[nConnections].getSession(); 171 if (!sessions.contains(sess)) 172 sessions.add(sess); 173 nConnections++; 174 } 175 System.out.println(); 176 System.out.println("Current timeout is set to: " + timeout); 177 System.out.println("Testing SSLSessionContext.getSession()......"); 178 System.out.println("========================================" 179 + "======================="); 180 System.out.println("Session " 181 + "Session- Session"); 182 System.out.println(" " 183 + "lifetime timedout?"); 184 System.out.println("========================================" 185 + "======================="); 186 187 for (int i = 0; i < sessions.size(); i++) { 188 SSLSession session = (SSLSession) sessions.elementAt(i); 189 long currentTime = System.currentTimeMillis(); 190 long creationTime = session.getCreationTime(); 191 long lifetime = (currentTime - creationTime) / 1000; 192 193 System.out.print(session + " " + lifetime + " "); 194 if (sessCtx.getSession(session.getId()) == null) { 195 if (lifetime < timeout) 196 // sessions can be garbage collected before the timeout 197 // limit is reached 198 System.out.println("Invalidated before timeout"); 199 else 200 System.out.println("YES"); 201 } else { 202 System.out.println("NO"); 203 if ((timeout != 0) && (lifetime > timeout)) { 204 throw new Exception("Session timeout test failed for the" 205 + " obove session"); 206 } 207 } 208 // change the timeout 209 if (i == ((sessions.size()) / 2)) { 210 System.out.println(); 211 sessCtx.setSessionTimeout(2); // in secs 212 timeout = sessCtx.getSessionTimeout(); 213 System.out.println("timeout is changed to: " + timeout); 214 System.out.println(); 215 } 216 } 217 218 // check the ids returned by the enumerator 219 Enumeration e = sessCtx.getIds(); 220 System.out.println("----------------------------------------" 221 + "-----------------------"); 222 System.out.println("Testing SSLSessionContext.getId()......"); 223 System.out.println(); 224 225 SSLSession nextSess = null; 226 SSLSession sess; 227 for (int i = 0; i < sessions.size(); i++) { 228 sess = (SSLSession)sessions.elementAt(i); 229 String isTimedout = "YES"; 230 long currentTime = System.currentTimeMillis(); 231 long creationTime = sess.getCreationTime(); 232 long lifetime = (currentTime - creationTime) / 1000; 233 234 if (nextSess != null) { 235 if (isEqualSessionId(nextSess.getId(), sess.getId())) { 236 isTimedout = "NO"; 237 nextSess = null; 238 } 239 } else if (e.hasMoreElements()) { 240 nextSess = sessCtx.getSession((byte[]) e.nextElement()); 241 if ((nextSess != null) && isEqualSessionId(nextSess.getId(), 242 sess.getId())) { 243 nextSess = null; 244 isTimedout = "NO"; 245 } 246 } 247 248 /* 249 * A session not invalidated even after it's timeout? 250 */ 251 if ((timeout != 0) && (lifetime > timeout) && 252 (isTimedout.equals("NO"))) { 253 throw new Exception("Session timeout test failed for session: " 254 + sess + " lifetime: " + lifetime); 255 } 256 System.out.print(sess + " " + lifetime); 257 if (((timeout == 0) || (lifetime < timeout)) && 258 (isTimedout == "YES")) { 259 isTimedout = "Invalidated before timeout"; 260 } 261 262 System.out.println(" " + isTimedout); 263 } 264 for (int i = 0; i < nConnections; i++) { 265 sslSockets[i].close(); 266 } 267 System.out.println("----------------------------------------" 268 + "-----------------------"); 269 System.out.println("Session timeout test passed"); 270 } 271 272 boolean isEqualSessionId(byte[] id1, byte[] id2) { 273 if (id1.length != id2.length) 274 return false; 275 else { 276 for (int i = 0; i < id1.length; i++) { 277 if (id1[i] != id2[i]) { 278 return false; 279 } 280 } 281 return true; 282 } 283 } 284 285 286 /* 287 * ============================================================= 288 * The remainder is just support stuff 289 */ 290 291 volatile int serverPorts[] = new int[PORTS]; 292 volatile int createdPorts = 0; 293 static SSLServerSocketFactory sslssf; 294 static SSLSocketFactory sslsf; 295 static SSLContext sslctx; 296 297 volatile Exception serverException = null; 298 volatile Exception clientException = null; 299 300 public static void main(String[] args) throws Exception { 301 String keyFilename = 302 System.getProperty("test.src", "./") + "/" + pathToStores + 303 "/" + keyStoreFile; 304 String trustFilename = 305 System.getProperty("test.src", "./") + "/" + pathToStores + 306 "/" + trustStoreFile; 307 308 System.setProperty("javax.net.ssl.keyStore", keyFilename); 309 System.setProperty("javax.net.ssl.keyStorePassword", passwd); 310 System.setProperty("javax.net.ssl.trustStore", trustFilename); 311 System.setProperty("javax.net.ssl.trustStorePassword", passwd); 312 313 sslctx = SSLContext.getInstance("TLS"); 314 KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); 315 KeyStore ks = KeyStore.getInstance("JKS"); 316 ks.load(new FileInputStream(keyFilename), passwd.toCharArray()); 317 kmf.init(ks, passwd.toCharArray()); 318 sslctx.init(kmf.getKeyManagers(), null, null); 319 sslssf = (SSLServerSocketFactory) sslctx.getServerSocketFactory(); 320 sslsf = (SSLSocketFactory) sslctx.getSocketFactory(); 321 if (debug) 322 System.setProperty("javax.net.debug", "all"); 323 324 /* 325 * Start the tests. 326 */ 327 new SessionTimeOutTests(); 328 } 329 330 Thread clientThread = null; 331 Thread serverThread = null; 332 333 /* 334 * Primary constructor, used to drive remainder of the test. 335 * 336 * Fork off the other side, then do your work. 337 */ 338 SessionTimeOutTests() throws Exception { 339 340 /* 341 * create the SSLServerSocket and SSLSocket factories 342 */ 343 344 /* 345 * Divide the max connections among the available server ports. 346 * The use of more than one server port ensures creation of more 347 * than one session. 348 */ 349 int serverConns = MAX_ACTIVE_CONNECTIONS / (serverPorts.length); 350 int remainingConns = MAX_ACTIVE_CONNECTIONS % (serverPorts.length); 351 352 Exception startException = null; 353 try { 354 if (separateServerThread) { 355 for (int i = 0; i < serverPorts.length; i++) { 356 // distribute remaining connections among the 357 // vailable ports 358 if (i < remainingConns) 359 startServer(serverPorts[i], (serverConns + 1), true); 360 else 361 startServer(serverPorts[i], serverConns, true); 362 } 363 startClient(false); 364 } else { 365 startClient(true); 366 for (int i = 0; i < serverPorts.length; i++) { 367 if (i < remainingConns) 368 startServer(serverPorts[i], (serverConns + 1), false); 369 else 370 startServer(serverPorts[i], serverConns, false); 371 } 372 } 373 } catch (Exception e) { 374 startException = e; 375 } 376 377 /* 378 * Wait for other side to close down. 379 */ 380 if (separateServerThread) { 381 if (serverThread != null) { 382 serverThread.join(); 383 } 384 } else { 385 if (clientThread != null) { 386 clientThread.join(); 387 } 388 } 389 390 /* 391 * When we get here, the test is pretty much over. 392 * Which side threw the error? 393 */ 394 Exception local; 395 Exception remote; 396 397 if (separateServerThread) { 398 remote = serverException; 399 local = clientException; 400 } else { 401 remote = clientException; 402 local = serverException; 403 } 404 405 Exception exception = null; 406 407 /* 408 * Check various exception conditions. 409 */ 410 if ((local != null) && (remote != null)) { 411 // If both failed, return the curthread's exception. 412 local.initCause(remote); 413 exception = local; 414 } else if (local != null) { 415 exception = local; 416 } else if (remote != null) { 417 exception = remote; 418 } else if (startException != null) { 419 exception = startException; 420 } 421 422 /* 423 * If there was an exception *AND* a startException, 424 * output it. 425 */ 426 if (exception != null) { 427 if (exception != startException && startException != null) { 428 exception.addSuppressed(startException); 429 } 430 throw exception; 431 } 432 433 // Fall-through: no exception to throw! 434 } 435 436 void startServer(final int port, final int nConns, 437 boolean newThread) throws Exception { 438 if (newThread) { 439 serverThread = new Thread() { 440 public void run() { 441 try { 442 doServerSide(port, nConns); 443 } catch (Exception e) { 444 /* 445 * Our server thread just died. 446 * 447 * Release the client, if not active already... 448 */ 449 System.err.println("Server died..."); 450 e.printStackTrace(); 451 serverReady.set(0); 452 serverException = e; 453 } 454 } 455 }; 456 serverThread.start(); 457 } else { 458 try { 459 doServerSide(port, nConns); 460 } catch (Exception e) { 461 serverException = e; 462 } finally { 463 serverReady.set(0); 464 } 465 } 466 } 467 468 void startClient(boolean newThread) 469 throws Exception { 470 if (newThread) { 471 clientThread = new Thread() { 472 public void run() { 473 try { 474 doClientSide(); 475 } catch (Exception e) { 476 /* 477 * Our client thread just died. 478 */ 479 System.err.println("Client died..."); 480 clientException = e; 481 } 482 } 483 }; 484 clientThread.start(); 485 } else { 486 try { 487 doClientSide(); 488 } catch (Exception e) { 489 clientException = e; 490 } 491 } 492 } 493} 494