Path: blob/master/test/jdk/com/sun/jndi/ldap/DeadSSLLdapTimeoutTest.java
41153 views
/*1* Copyright (c) 2011, 2020, 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/*24* @test25* @bug 814137026* @key intermittent27* @library /test/lib28* @build DeadSSLSocketFactory29* @run main/othervm DeadSSLLdapTimeoutTest30*/3132import java.io.EOFException;33import java.io.IOException;34import java.net.InetAddress;35import java.net.InetSocketAddress;36import java.net.ServerSocket;37import java.net.Socket;38import java.net.SocketAddress;39import java.net.SocketTimeoutException;40import javax.naming.Context;41import javax.naming.InitialContext;42import javax.naming.NamingException;43import java.util.Hashtable;44import java.util.concurrent.Callable;45import java.util.concurrent.CountDownLatch;46import java.util.concurrent.TimeUnit;47import javax.naming.directory.InitialDirContext;48import javax.net.ssl.SSLHandshakeException;4950import jdk.test.lib.net.URIBuilder;5152import static java.util.concurrent.TimeUnit.NANOSECONDS;535455class DeadServerTimeoutSSLTest implements Callable<Boolean> {5657Hashtable<Object, Object> env;58DeadSSLServer server;59boolean passed = false;6061public DeadServerTimeoutSSLTest(Hashtable<Object, Object> env) throws IOException {62SocketAddress sockAddr = new InetSocketAddress(63InetAddress.getLoopbackAddress(), 0);64this.server = new DeadSSLServer(sockAddr);65this.env = env;66}6768public void handleNamingException(NamingException e) {69if (e.getCause() instanceof SocketTimeoutException70|| e.getCause().getCause() instanceof SocketTimeoutException) {71// SSL connect will timeout via readReply using72// SocketTimeoutException73System.out.println("PASS: Observed expected SocketTimeoutException");74pass();75} else if (e.getCause() instanceof SSLHandshakeException76&& e.getCause().getCause() instanceof EOFException) {77// test seems to be failing intermittently on some78// platforms.79System.out.println("PASS: Observed expected SSLHandshakeException/EOFException");80pass();81} else {82fail(e);83}84}8586public void pass() {87this.passed = true;88}8990public void fail() {91throw new RuntimeException("Test failed");92}9394public void fail(Exception e) {95System.err.println("FAIL: Unexpected exception was observed:" + e.getMessage());96throw new RuntimeException("Test failed", e);97}9899boolean shutItDown(InitialContext ctx) {100try {101if (ctx != null) ctx.close();102return true;103} catch (NamingException ex) {104return false;105}106}107108public Boolean call() {109InitialContext ctx = null;110111try {112server.serverStarted.await(); // Wait for the server to start-up113Thread.sleep(200); // to be sure114115env.put(Context.PROVIDER_URL,116URIBuilder.newBuilder()117.scheme("ldap")118.loopback()119.port(server.getLocalPort())120.buildUnchecked().toString()121);122123long start = System.nanoTime();124try {125ctx = new InitialDirContext(env);126fail();127} catch (NamingException e) {128long end = System.nanoTime();129System.out.println(this.getClass().toString() + " - elapsed: "130+ NANOSECONDS.toMillis(end - start));131handleNamingException(e);132} finally {133// Stop the server side thread134server.testDone.countDown();135shutItDown(ctx);136server.close();137}138return passed;139} catch (IOException | InterruptedException e) {140throw new RuntimeException(e);141}142}143}144145class DeadSSLServer extends Thread {146ServerSocket serverSock;147// Latch to be used by client to wait for server to start148CountDownLatch serverStarted = new CountDownLatch(1);149150// Latch to be used by server thread to wait for client to finish testing151CountDownLatch testDone = new CountDownLatch(1);152153public DeadSSLServer(SocketAddress socketAddress) throws IOException {154// create unbound server socket155var srvSock = new ServerSocket();156// bind it to the address provided157srvSock.bind(socketAddress);158this.serverSock = srvSock;159start();160}161162public void run() {163// Signal client to proceed with the test164serverStarted.countDown();165while (true) {166try (var acceptedSocket = serverSock.accept()) {167System.err.println("Accepted connection:" + acceptedSocket);168int iteration = 0;169// Wait for socket to get opened by DeadSSLSocketFactory and connected to the test server170while (iteration++ < 20) {171if (DeadSSLSocketFactory.firstCreatedSocket.get() != null &&172DeadSSLSocketFactory.firstCreatedSocket.get().isConnected()) {173break;174}175try {176TimeUnit.MILLISECONDS.sleep(50);177} catch (InterruptedException ie) {178}179}180Socket clientSideSocket = DeadSSLSocketFactory.firstCreatedSocket.get();181System.err.printf("Got SSLSocketFactory connection after %d iterations: %s%n",182iteration, clientSideSocket);183184if (clientSideSocket == null || !clientSideSocket.isConnected()) {185// If after 1000 ms client side connection is not opened - probably other local process186// tried to connect to the test server socket. Close current connection and retry accept.187continue;188} else {189// Check if accepted socket is connected to the LDAP client190if (acceptedSocket.getLocalPort() == clientSideSocket.getPort() &&191acceptedSocket.getPort() == clientSideSocket.getLocalPort() &&192acceptedSocket.getInetAddress().equals(clientSideSocket.getLocalAddress())) {193System.err.println("Accepted connection is originated from LDAP client:" + acceptedSocket);194try {195// Give LDAP client time to fully establish the connection.196// When client is done - the accepted socket will be closed197testDone.await();198} catch (InterruptedException e) {199}200break;201} else {202// If accepted socket is not from the LDAP client - the accepted connection will be closed and new203// one will be accepted204System.err.println("SSLSocketFactory connection has been established, but originated not from" +205" the test's LDAP client:" + acceptedSocket);206}207}208} catch (Exception e) {209System.err.println("Server socket. Failure to accept connection:" + e.getMessage());210}211}212}213214public int getLocalPort() {215return serverSock.getLocalPort();216}217218public void close() throws IOException {219serverSock.close();220}221}222223public class DeadSSLLdapTimeoutTest {224// com.sun.jndi.ldap.connect.timeout value to set225static final String CONNECT_TIMEOUT_MS = "10";226227// com.sun.jndi.ldap.read.timeout value to set228static final String READ_TIMEOUT_MS = "3000";229230static Hashtable<Object, Object> createEnv() {231Hashtable<Object, Object> env = new Hashtable<>(11);232env.put(Context.INITIAL_CONTEXT_FACTORY,233"com.sun.jndi.ldap.LdapCtxFactory");234return env;235}236237public static void main(String[] args) throws Exception {238//239// Running this test serially as it seems to tickle a problem240// on older kernels241//242// run the DeadServerTest with connect / read timeouts set243// and ssl enabled244// this should exit with a SocketTimeoutException as the root cause245// it should also use the connect timeout instead of the read timeout246System.out.printf("Running connect timeout test with %sms connect timeout," +247" %sms read timeout & SSL%n",248CONNECT_TIMEOUT_MS, READ_TIMEOUT_MS);249250Hashtable<Object, Object> sslenv = createEnv();251// Setup connect timeout environment property252sslenv.put("com.sun.jndi.ldap.connect.timeout", CONNECT_TIMEOUT_MS);253// Setup read timeout environment property254sslenv.put("com.sun.jndi.ldap.read.timeout", READ_TIMEOUT_MS);255// Setup DeadSSLSocketFactory to track the client's first LDAP connection256sslenv.put("java.naming.ldap.factory.socket", "DeadSSLSocketFactory");257// Use SSL protocol258sslenv.put(Context.SECURITY_PROTOCOL, "ssl");259260boolean testFailed = !new DeadServerTimeoutSSLTest(sslenv).call();261if (testFailed) {262throw new AssertionError("some tests failed");263}264}265}266267268269