SessionTimeOutTests.java revision 13470:c20bc888feea
1/* 2 * Copyright (c) 2001, 2016, 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 int slot = createdPorts.getAndIncrement(); 116 serverPorts[slot] = sslServerSocket.getLocalPort(); 117 118 /* 119 * Signal Client, we're ready for his connect. 120 */ 121 serverReady.getAndDecrement(); 122 int read = 0; 123 int nConnections = 0; 124 SSLSession sessions [] = new SSLSession [serverConns]; 125 126 while (nConnections < serverConns) { 127 SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept(); 128 InputStream sslIS = sslSocket.getInputStream(); 129 OutputStream sslOS = sslSocket.getOutputStream(); 130 read = sslIS.read(); 131 sessions[nConnections] = sslSocket.getSession(); 132 sslOS.write(85); 133 sslOS.flush(); 134 sslSocket.close(); 135 nConnections++; 136 } 137 } 138 139 /* 140 * Define the client side of the test. 141 * 142 * If the server prematurely exits, serverReady will be set to zero 143 * to avoid infinite hangs. 144 */ 145 void doClientSide() throws Exception { 146 147 /* 148 * Wait for server to get started. 149 */ 150 while (serverReady.get() > 0) { 151 Thread.sleep(50); 152 } 153 154 int nConnections = 0; 155 SSLSocket sslSockets[] = new SSLSocket [MAX_ACTIVE_CONNECTIONS]; 156 Vector sessions = new Vector(); 157 SSLSessionContext sessCtx = sslctx.getClientSessionContext(); 158 159 sessCtx.setSessionTimeout(10); // in secs 160 int timeout = sessCtx.getSessionTimeout(); 161 while (nConnections < MAX_ACTIVE_CONNECTIONS) { 162 // divide the connections among the available server ports 163 sslSockets[nConnections] = (SSLSocket) sslsf. 164 createSocket("localhost", 165 serverPorts [nConnections % (serverPorts.length)]); 166 InputStream sslIS = sslSockets[nConnections].getInputStream(); 167 OutputStream sslOS = sslSockets[nConnections].getOutputStream(); 168 sslOS.write(237); 169 sslOS.flush(); 170 int read = sslIS.read(); 171 SSLSession sess = sslSockets[nConnections].getSession(); 172 if (!sessions.contains(sess)) 173 sessions.add(sess); 174 nConnections++; 175 } 176 System.out.println(); 177 System.out.println("Current timeout is set to: " + timeout); 178 System.out.println("Testing SSLSessionContext.getSession()......"); 179 System.out.println("========================================" 180 + "======================="); 181 System.out.println("Session " 182 + "Session- Session"); 183 System.out.println(" " 184 + "lifetime timedout?"); 185 System.out.println("========================================" 186 + "======================="); 187 188 for (int i = 0; i < sessions.size(); i++) { 189 SSLSession session = (SSLSession) sessions.elementAt(i); 190 long currentTime = System.currentTimeMillis(); 191 long creationTime = session.getCreationTime(); 192 long lifetime = (currentTime - creationTime) / 1000; 193 194 System.out.print(session + " " + lifetime + " "); 195 if (sessCtx.getSession(session.getId()) == null) { 196 if (lifetime < timeout) 197 // sessions can be garbage collected before the timeout 198 // limit is reached 199 System.out.println("Invalidated before timeout"); 200 else 201 System.out.println("YES"); 202 } else { 203 System.out.println("NO"); 204 if ((timeout != 0) && (lifetime > timeout)) { 205 throw new Exception("Session timeout test failed for the" 206 + " obove session"); 207 } 208 } 209 // change the timeout 210 if (i == ((sessions.size()) / 2)) { 211 System.out.println(); 212 sessCtx.setSessionTimeout(2); // in secs 213 timeout = sessCtx.getSessionTimeout(); 214 System.out.println("timeout is changed to: " + timeout); 215 System.out.println(); 216 } 217 } 218 219 // check the ids returned by the enumerator 220 Enumeration e = sessCtx.getIds(); 221 System.out.println("----------------------------------------" 222 + "-----------------------"); 223 System.out.println("Testing SSLSessionContext.getId()......"); 224 System.out.println(); 225 226 SSLSession nextSess = null; 227 SSLSession sess; 228 for (int i = 0; i < sessions.size(); i++) { 229 sess = (SSLSession)sessions.elementAt(i); 230 String isTimedout = "YES"; 231 long currentTime = System.currentTimeMillis(); 232 long creationTime = sess.getCreationTime(); 233 long lifetime = (currentTime - creationTime) / 1000; 234 235 if (nextSess != null) { 236 if (isEqualSessionId(nextSess.getId(), sess.getId())) { 237 isTimedout = "NO"; 238 nextSess = null; 239 } 240 } else if (e.hasMoreElements()) { 241 nextSess = sessCtx.getSession((byte[]) e.nextElement()); 242 if ((nextSess != null) && isEqualSessionId(nextSess.getId(), 243 sess.getId())) { 244 nextSess = null; 245 isTimedout = "NO"; 246 } 247 } 248 249 /* 250 * A session not invalidated even after it's timeout? 251 */ 252 if ((timeout != 0) && (lifetime > timeout) && 253 (isTimedout.equals("NO"))) { 254 throw new Exception("Session timeout test failed for session: " 255 + sess + " lifetime: " + lifetime); 256 } 257 System.out.print(sess + " " + lifetime); 258 if (((timeout == 0) || (lifetime < timeout)) && 259 (isTimedout == "YES")) { 260 isTimedout = "Invalidated before timeout"; 261 } 262 263 System.out.println(" " + isTimedout); 264 } 265 for (int i = 0; i < nConnections; i++) { 266 sslSockets[i].close(); 267 } 268 System.out.println("----------------------------------------" 269 + "-----------------------"); 270 System.out.println("Session timeout test passed"); 271 } 272 273 boolean isEqualSessionId(byte[] id1, byte[] id2) { 274 if (id1.length != id2.length) 275 return false; 276 else { 277 for (int i = 0; i < id1.length; i++) { 278 if (id1[i] != id2[i]) { 279 return false; 280 } 281 } 282 return true; 283 } 284 } 285 286 287 /* 288 * ============================================================= 289 * The remainder is just support stuff 290 */ 291 292 int serverPorts[] = new int[PORTS]; 293 AtomicInteger createdPorts = new AtomicInteger(0); 294 static SSLServerSocketFactory sslssf; 295 static SSLSocketFactory sslsf; 296 static SSLContext sslctx; 297 298 volatile Exception serverException = null; 299 volatile Exception clientException = null; 300 301 public static void main(String[] args) throws Exception { 302 String keyFilename = 303 System.getProperty("test.src", "./") + "/" + pathToStores + 304 "/" + keyStoreFile; 305 String trustFilename = 306 System.getProperty("test.src", "./") + "/" + pathToStores + 307 "/" + trustStoreFile; 308 309 System.setProperty("javax.net.ssl.keyStore", keyFilename); 310 System.setProperty("javax.net.ssl.keyStorePassword", passwd); 311 System.setProperty("javax.net.ssl.trustStore", trustFilename); 312 System.setProperty("javax.net.ssl.trustStorePassword", passwd); 313 314 sslctx = SSLContext.getInstance("TLS"); 315 KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); 316 KeyStore ks = KeyStore.getInstance("JKS"); 317 ks.load(new FileInputStream(keyFilename), passwd.toCharArray()); 318 kmf.init(ks, passwd.toCharArray()); 319 sslctx.init(kmf.getKeyManagers(), null, null); 320 sslssf = (SSLServerSocketFactory) sslctx.getServerSocketFactory(); 321 sslsf = (SSLSocketFactory) sslctx.getSocketFactory(); 322 if (debug) 323 System.setProperty("javax.net.debug", "all"); 324 325 /* 326 * Start the tests. 327 */ 328 new SessionTimeOutTests(); 329 } 330 331 Thread clientThread = null; 332 Thread serverThread = null; 333 334 /* 335 * Primary constructor, used to drive remainder of the test. 336 * 337 * Fork off the other side, then do your work. 338 */ 339 SessionTimeOutTests() throws Exception { 340 341 /* 342 * create the SSLServerSocket and SSLSocket factories 343 */ 344 345 /* 346 * Divide the max connections among the available server ports. 347 * The use of more than one server port ensures creation of more 348 * than one session. 349 */ 350 int serverConns = MAX_ACTIVE_CONNECTIONS / (serverPorts.length); 351 int remainingConns = MAX_ACTIVE_CONNECTIONS % (serverPorts.length); 352 353 Exception startException = null; 354 try { 355 if (separateServerThread) { 356 for (int i = 0; i < serverPorts.length; i++) { 357 // distribute remaining connections among the 358 // vailable ports 359 if (i < remainingConns) 360 startServer(serverPorts[i], (serverConns + 1), true); 361 else 362 startServer(serverPorts[i], serverConns, true); 363 } 364 startClient(false); 365 } else { 366 startClient(true); 367 for (int i = 0; i < serverPorts.length; i++) { 368 if (i < remainingConns) 369 startServer(serverPorts[i], (serverConns + 1), false); 370 else 371 startServer(serverPorts[i], serverConns, false); 372 } 373 } 374 } catch (Exception e) { 375 startException = e; 376 } 377 378 /* 379 * Wait for other side to close down. 380 */ 381 if (separateServerThread) { 382 if (serverThread != null) { 383 serverThread.join(); 384 } 385 } else { 386 if (clientThread != null) { 387 clientThread.join(); 388 } 389 } 390 391 /* 392 * When we get here, the test is pretty much over. 393 * Which side threw the error? 394 */ 395 Exception local; 396 Exception remote; 397 398 if (separateServerThread) { 399 remote = serverException; 400 local = clientException; 401 } else { 402 remote = clientException; 403 local = serverException; 404 } 405 406 Exception exception = null; 407 408 /* 409 * Check various exception conditions. 410 */ 411 if ((local != null) && (remote != null)) { 412 // If both failed, return the curthread's exception. 413 local.initCause(remote); 414 exception = local; 415 } else if (local != null) { 416 exception = local; 417 } else if (remote != null) { 418 exception = remote; 419 } else if (startException != null) { 420 exception = startException; 421 } 422 423 /* 424 * If there was an exception *AND* a startException, 425 * output it. 426 */ 427 if (exception != null) { 428 if (exception != startException && startException != null) { 429 exception.addSuppressed(startException); 430 } 431 throw exception; 432 } 433 434 // Fall-through: no exception to throw! 435 } 436 437 void startServer(final int port, final int nConns, 438 boolean newThread) throws Exception { 439 if (newThread) { 440 serverThread = new Thread() { 441 public void run() { 442 try { 443 doServerSide(port, nConns); 444 } catch (Exception e) { 445 /* 446 * Our server thread just died. 447 * 448 * Release the client, if not active already... 449 */ 450 System.err.println("Server died..."); 451 e.printStackTrace(); 452 serverReady.set(0); 453 serverException = e; 454 } 455 } 456 }; 457 serverThread.start(); 458 } else { 459 try { 460 doServerSide(port, nConns); 461 } catch (Exception e) { 462 serverException = e; 463 } finally { 464 serverReady.set(0); 465 } 466 } 467 } 468 469 void startClient(boolean newThread) 470 throws Exception { 471 if (newThread) { 472 clientThread = new Thread() { 473 public void run() { 474 try { 475 doClientSide(); 476 } catch (Exception e) { 477 /* 478 * Our client thread just died. 479 */ 480 System.err.println("Client died..."); 481 clientException = e; 482 } 483 } 484 }; 485 clientThread.start(); 486 } else { 487 try { 488 doClientSide(); 489 } catch (Exception e) { 490 clientException = e; 491 } 492 } 493 } 494} 495