Path: blob/master/test/jdk/javax/net/ssl/SSLSession/SessionTimeOutTests.java
41152 views
/*1* Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223// SunJSSE does not support dynamic system properties, no way to re-use24// system properties in samevm/agentvm mode.2526/*27* @test28* @bug 436680729* @summary Need new APIs to get/set session timeout and session cache size.30* @run main/othervm SessionTimeOutTests31*/3233import java.io.*;34import java.net.InetSocketAddress;35import java.net.SocketTimeoutException;3637import javax.net.ssl.*;38import java.util.*;39import java.security.*;40import java.util.concurrent.CountDownLatch;41import java.util.concurrent.TimeUnit;4243/**44* Session reuse time-out tests cover the cases below:45* 1. general test, i.e timeout is set to x and session invalidates when46* its lifetime exceeds x.47* 2. Effect of changing the timeout limit.48* The test suite does not cover the default timeout(24 hours) usage. This49* case has been tested independently.50*51* Invariant for passing this test is, at any given time,52* lifetime of a session < current_session_timeout, such that53* current_session_timeout > 0, for all sessions cached by the session54* context.55*/5657public class SessionTimeOutTests {5859/*60* =============================================================61* Set the various variables needed for the tests, then62* specify what tests to run on each side.63*/6465/*66* Should we run the client or server in a separate thread?67* Both sides can throw exceptions, but do you have a preference68* as to which side should be the main thread.69*/70static boolean separateServerThread = true;7172/*73* Where do we find the keystores?74*/75static String pathToStores = "../etc";76static String keyStoreFile = "keystore";77static String trustStoreFile = "truststore";78static String passwd = "passphrase";7980private static int PORTS = 3;8182/*83* Is the server ready to serve?84*/85private final CountDownLatch serverCondition = new CountDownLatch(PORTS);8687/*88* Turn on SSL debugging?89*/90static boolean debug = false;9192/*93* If the client or server is doing some kind of object creation94* that the other side depends on, and that thread prematurely95* exits, you may experience a hang. The test harness will96* terminate all hung threads after its timeout has expired,97* currently 3 minutes by default, but you might try to be98* smart about it....99*/100101/*102* Define the server side of the test.103*/104105/*106* A limit on the number of connections at any given time107*/108static int MAX_ACTIVE_CONNECTIONS = 3;109110/*111* Divide the max connections among the available server ports.112* The use of more than one server port ensures creation of more113* than one session.114*/115private static final int serverConns = MAX_ACTIVE_CONNECTIONS / PORTS;116private static final int remainingConns = MAX_ACTIVE_CONNECTIONS % PORTS;117118private static final int TIMEOUT = 30000; // in millisecond119120void doServerSide(int slot, int serverConns) throws Exception {121122SSLServerSocket sslServerSocket123= (SSLServerSocket) sslssf.createServerSocket(0);124sslServerSocket.setSoTimeout(TIMEOUT);125serverPorts[slot] = sslServerSocket.getLocalPort();126127/*128* Signal Client, one server is ready for its connect.129*/130serverCondition.countDown();131132for (int nConnections = 0; nConnections < serverConns; nConnections++) {133SSLSocket sslSocket = null;134try {135sslSocket = (SSLSocket) sslServerSocket.accept();136} catch (SocketTimeoutException ste) {137System.out.println(138"No incoming client connection. Ignore in server side.");139continue;140}141InputStream sslIS = sslSocket.getInputStream();142OutputStream sslOS = sslSocket.getOutputStream();143sslIS.read();144sslSocket.getSession();145sslOS.write(85);146sslOS.flush();147sslSocket.close();148}149}150151/*152* Define the client side of the test.153*154* If the server prematurely exits, serverReady will be set to zero155* to avoid infinite hangs.156*/157void doClientSide() throws Exception {158/*159* Wait for server to get started.160*/161if (!serverCondition.await(TIMEOUT, TimeUnit.MILLISECONDS)) {162System.out.println(163"The server side is not ready yet. Ignore in client side.");164return;165}166167SSLSocket sslSockets[] = new SSLSocket[MAX_ACTIVE_CONNECTIONS];168Vector<SSLSession> sessions = new Vector<>();169SSLSessionContext sessCtx = sslctx.getClientSessionContext();170171sessCtx.setSessionTimeout(10); // in secs172int timeout = sessCtx.getSessionTimeout();173for (int nConnections = 0; nConnections < MAX_ACTIVE_CONNECTIONS;174nConnections++) {175// divide the connections among the available server ports176try {177SSLSocket sslSocket = (SSLSocket) sslsf.createSocket();178sslSocket.connect(new InetSocketAddress("localhost",179serverPorts[nConnections % serverPorts.length]),180TIMEOUT);181sslSockets[nConnections] = sslSocket;182} catch (IOException ioe) {183// The server side may be impacted by naughty test cases or184// third party routines, and cannot accept connections.185//186// Just ignore the test if the connection cannot be187// established.188System.out.println(189"Cannot make a connection in time. Ignore in client side.");190continue;191}192193InputStream sslIS = sslSockets[nConnections].getInputStream();194OutputStream sslOS = sslSockets[nConnections].getOutputStream();195sslOS.write(237);196sslOS.flush();197sslIS.read();198SSLSession sess = sslSockets[nConnections].getSession();199if (!sessions.contains(sess))200sessions.add(sess);201}202System.out.println();203System.out.println("Current timeout is set to: " + timeout);204System.out.println("Testing SSLSessionContext.getSession()......");205System.out.println("========================================"206+ "=======================");207System.out.println("Session "208+ "Session- Session");209System.out.println(" "210+ "lifetime timedout?");211System.out.println("========================================"212+ "=======================");213214for (int i = 0; i < sessions.size(); i++) {215SSLSession session = (SSLSession) sessions.elementAt(i);216long currentTime = System.currentTimeMillis();217long creationTime = session.getCreationTime();218long lifetime = (currentTime - creationTime) / 1000;219220System.out.print(session + " " + lifetime + " ");221if (sessCtx.getSession(session.getId()) == null) {222if (lifetime < timeout)223// sessions can be garbage collected before the timeout224// limit is reached225System.out.println("Invalidated before timeout");226else227System.out.println("YES");228} else {229System.out.println("NO");230if ((timeout != 0) && (lifetime > timeout)) {231throw new Exception("Session timeout test failed for the"232+ " obove session");233}234}235// change the timeout236if (i == ((sessions.size()) / 2)) {237System.out.println();238sessCtx.setSessionTimeout(2); // in secs239timeout = sessCtx.getSessionTimeout();240System.out.println("timeout is changed to: " + timeout);241System.out.println();242}243}244245// check the ids returned by the enumerator246Enumeration<byte[]> e = sessCtx.getIds();247System.out.println("----------------------------------------"248+ "-----------------------");249System.out.println("Testing SSLSessionContext.getId()......");250System.out.println();251252SSLSession nextSess = null;253SSLSession sess;254for (int i = 0; i < sessions.size(); i++) {255sess = (SSLSession)sessions.elementAt(i);256String isTimedout = "YES";257long currentTime = System.currentTimeMillis();258long creationTime = sess.getCreationTime();259long lifetime = (currentTime - creationTime) / 1000;260261if (nextSess != null) {262if (isEqualSessionId(nextSess.getId(), sess.getId())) {263isTimedout = "NO";264nextSess = null;265}266} else if (e.hasMoreElements()) {267nextSess = sessCtx.getSession((byte[]) e.nextElement());268if ((nextSess != null) && isEqualSessionId(nextSess.getId(),269sess.getId())) {270nextSess = null;271isTimedout = "NO";272}273}274275/*276* A session not invalidated even after it's timeout?277*/278if ((timeout != 0) && (lifetime > timeout) &&279(isTimedout.equals("NO"))) {280throw new Exception("Session timeout test failed for session: "281+ sess + " lifetime: " + lifetime);282}283System.out.print(sess + " " + lifetime);284if (((timeout == 0) || (lifetime < timeout)) &&285(isTimedout.equals("YES"))) {286isTimedout = "Invalidated before timeout";287}288289System.out.println(" " + isTimedout);290}291for (int i = 0; i < sslSockets.length; i++) {292sslSockets[i].close();293}294System.out.println("----------------------------------------"295+ "-----------------------");296System.out.println("Session timeout test passed");297}298299boolean isEqualSessionId(byte[] id1, byte[] id2) {300if (id1.length != id2.length)301return false;302else {303for (int i = 0; i < id1.length; i++) {304if (id1[i] != id2[i]) {305return false;306}307}308return true;309}310}311312313/*314* =============================================================315* The remainder is just support stuff316*/317318int serverPorts[] = new int[PORTS];319static SSLServerSocketFactory sslssf;320static SSLSocketFactory sslsf;321static SSLContext sslctx;322323volatile Exception serverException = null;324volatile Exception clientException = null;325326public static void main(String[] args) throws Exception {327String keyFilename =328System.getProperty("test.src", "./") + "/" + pathToStores +329"/" + keyStoreFile;330String trustFilename =331System.getProperty("test.src", "./") + "/" + pathToStores +332"/" + trustStoreFile;333334System.setProperty("javax.net.ssl.keyStore", keyFilename);335System.setProperty("javax.net.ssl.keyStorePassword", passwd);336System.setProperty("javax.net.ssl.trustStore", trustFilename);337System.setProperty("javax.net.ssl.trustStorePassword", passwd);338339if (debug)340System.setProperty("javax.net.debug", "all");341342sslctx = SSLContext.getInstance("TLS");343KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");344KeyStore ks = KeyStore.getInstance("JKS");345ks.load(new FileInputStream(keyFilename), passwd.toCharArray());346kmf.init(ks, passwd.toCharArray());347sslctx.init(kmf.getKeyManagers(), null, null);348sslssf = (SSLServerSocketFactory) sslctx.getServerSocketFactory();349sslsf = (SSLSocketFactory) sslctx.getSocketFactory();350351/*352* Start the tests.353*/354new SessionTimeOutTests();355}356357Thread clientThread = null;358Thread serverThread = null;359360/*361* Primary constructor, used to drive remainder of the test.362*363* Fork off the other side, then do your work.364*/365SessionTimeOutTests() throws Exception {366367/*368* create the SSLServerSocket and SSLSocket factories369*/370371Exception startException = null;372try {373if (separateServerThread) {374for (int i = 0; i < serverPorts.length; i++) {375// distribute remaining connections among the376// available ports377if (i < remainingConns)378startServer(i, (serverConns + 1), true);379else380startServer(i, serverConns, true);381}382startClient(false);383} else {384startClient(true);385for (int i = 0; i < PORTS; i++) {386if (i < remainingConns)387startServer(i, (serverConns + 1), false);388else389startServer(i, serverConns, false);390}391}392} catch (Exception e) {393startException = e;394}395396/*397* Wait for other side to close down.398*/399if (separateServerThread) {400if (serverThread != null) {401serverThread.join();402}403} else {404if (clientThread != null) {405clientThread.join();406}407}408409/*410* When we get here, the test is pretty much over.411* Which side threw the error?412*/413Exception local;414Exception remote;415416if (separateServerThread) {417remote = serverException;418local = clientException;419} else {420remote = clientException;421local = serverException;422}423424Exception exception = null;425426/*427* Check various exception conditions.428*/429if ((local != null) && (remote != null)) {430// If both failed, return the curthread's exception.431local.initCause(remote);432exception = local;433} else if (local != null) {434exception = local;435} else if (remote != null) {436exception = remote;437} else if (startException != null) {438exception = startException;439}440441/*442* If there was an exception *AND* a startException,443* output it.444*/445if (exception != null) {446if (exception != startException && startException != null) {447exception.addSuppressed(startException);448}449throw exception;450}451452// Fall-through: no exception to throw!453}454455void startServer(final int slot, final int nConns, boolean newThread)456throws Exception {457if (newThread) {458serverThread = new Thread() {459public void run() {460try {461doServerSide(slot, nConns);462} catch (Exception e) {463/*464* Our server thread just died.465*466* Release the client, if not active already...467*/468System.err.println("Server died...");469e.printStackTrace();470serverException = e;471}472}473};474serverThread.start();475} else {476try {477doServerSide(slot, nConns);478} catch (Exception e) {479serverException = e;480}481}482}483484void startClient(boolean newThread)485throws Exception {486if (newThread) {487clientThread = new Thread() {488public void run() {489try {490doClientSide();491} catch (Exception e) {492/*493* Our client thread just died.494*/495System.err.println("Client died...");496clientException = e;497}498}499};500clientThread.start();501} else {502try {503doClientSide();504} catch (Exception e) {505clientException = e;506}507}508}509}510511512