--- /dev/null 2020-08-14 15:34:23.000000000 +0300 +++ new/test/jdk/com/sun/jndi/ldap/LdapCBPropertiesTest.java 2020-08-14 15:34:23.000000000 +0300 @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2020, Azul Systems, Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8245527 + * @library lib/ /test/lib + * @run main/othervm LdapCBPropertiesTest true true com.sun.jndi.ldap.tls.cbtype tls-server-end-point + * @run main/othervm LdapCBPropertiesTest false false com.sun.jndi.ldap.tls.cbtype tls-server-end-point + * @run main/othervm LdapCBPropertiesTest true true com.sun.jndi.ldap.tls.cbtype tls-server-end-point com.sun.jndi.ldap.connect.timeout 2000 + * @run main/othervm LdapCBPropertiesTest false false com.sun.jndi.ldap.tls.cbtype tls-server-end-point com.sun.jndi.ldap.connect.timeout 2000 + * @run main/othervm LdapCBPropertiesTest false true com.sun.jndi.ldap.tls.cbtype tls-unique + * @run main/othervm LdapCBPropertiesTest false true com.sun.jndi.ldap.tls.cbtype tls-unknown + * @run main/othervm LdapCBPropertiesTest false true jdk.internal.sasl.tlschannelbinding value + * @summary test new JNDI property to control the Channel Binding data + */ + +import javax.naming.AuthenticationException; +import javax.naming.CommunicationException; +import javax.naming.Context; +import javax.naming.NamingException; +import javax.naming.directory.DirContext; +import javax.naming.directory.InitialDirContext; +import java.net.InetAddress; +import java.net.URI; +import java.util.Hashtable; + +import org.ietf.jgss.GSSException; + +import javax.net.ssl.SSLException; +import javax.net.ssl.SSLServerSocket; +import javax.net.ssl.SSLServerSocketFactory; +import javax.security.sasl.SaslException; + +import jdk.test.lib.net.URIBuilder; + +public class LdapCBPropertiesTest { + /* + * Where do we find the keystores? + */ + static String pathToStores = "../../../../javax/net/ssl/etc"; + static String keyStoreFile = "keystore"; + static String trustStoreFile = "truststore"; + static String passwd = "passphrase"; + + static boolean debug = false; + + public static void main(String[] args) throws Exception { + String keyFilename = + System.getProperty("test.src", "./") + "/" + pathToStores + + "/" + keyStoreFile; + String trustFilename = + System.getProperty("test.src", "./") + "/" + pathToStores + + "/" + trustStoreFile; + + System.setProperty("javax.net.ssl.keyStore", keyFilename); + System.setProperty("javax.net.ssl.keyStorePassword", passwd); + System.setProperty("javax.net.ssl.trustStore", trustFilename); + System.setProperty("javax.net.ssl.trustStorePassword", passwd); + + if (debug) + System.setProperty("javax.net.debug", "all"); + + /* + * Start the tests. + */ + new LdapCBPropertiesTest(args); + } + + /* + * Primary constructor, used to drive remainder of the test. + */ + LdapCBPropertiesTest(String[] args) throws Exception { + InetAddress loopback = InetAddress.getLoopbackAddress(); + SSLServerSocketFactory sslssf = + (SSLServerSocketFactory) SSLServerSocketFactory.getDefault(); + SSLServerSocket sslServerSocket = + (SSLServerSocket) sslssf.createServerSocket(0, 0, loopback); + int serverPort = sslServerSocket.getLocalPort(); + + try (var ignore = new BaseLdapServer(sslServerSocket).start()) { + doClientSide(serverPort, args); + } + } + + /* + * Define the client side of the test. + * + * The server should start at this time already + */ + void doClientSide(int serverPort, String[] args) throws Exception { + boolean passed = false; + boolean shouldPass = Boolean.parseBoolean(args[0]); + boolean shouldConnect = Boolean.parseBoolean(args[1]); + // set disableEndpointIdentification to disable hostname verification + if (shouldConnect) { + System.setProperty( + "com.sun.jndi.ldap.object.disableEndpointIdentification", "true"); + } + + // Set up the environment for creating the initial context + Hashtable env = new Hashtable(); + URI uri = URIBuilder.newBuilder() + .scheme("ldaps") + .loopback() + .port(serverPort) + .build(); + env.put(Context.PROVIDER_URL, uri.toString()); + env.put(Context.INITIAL_CONTEXT_FACTORY, + "com.sun.jndi.ldap.LdapCtxFactory"); + env.put(Context.SECURITY_AUTHENTICATION, "GSSAPI"); + + // read properties + for (int i = 2; i < args.length; i += 2) { + env.put(args[i], args[i + 1]); + if (debug) + System.out.println("Env=" + args[i] + "=" + args[i + 1]); + } + + try { + DirContext ctx = new InitialDirContext(env); + passed = shouldPass; + ctx.close(); + } catch (NamingException ne) { + // only NamingException is allowed + if (debug) + System.out.println("Exception=" + ne + " cause=" + ne.getRootCause()); + passed = handleNamingException(ne, shouldPass, shouldConnect); + } catch(Exception e) { + System.err.println("Failed: caught an unexpected Exception - " + e); + throw e; + } finally { + // test if internal property accessible to application + if(shouldPass && + env.get("jdk.internal.sasl.tlschannelbinding") != null) { + throw new Exception( + "Test FAILED: jdk.internal.sasl.tlschannelbinding should not be accessible"); + } + } + if (!passed) { + throw new Exception( + "Test FAILED: NamingException exception should be thrown"); + } + System.out.println("Test PASSED"); + } + + private static boolean handleNamingException(NamingException ne, boolean shouldPass, boolean shouldConnect) + throws NamingException { + if (ne instanceof AuthenticationException && + ne.getRootCause() instanceof SaslException) { + SaslException saslEx = (SaslException) ne.getRootCause(); + if (shouldConnect && saslEx.getCause() instanceof GSSException) { + // SSL connection successful, expected exception from SaslClient + if (shouldPass) + return true; + } + } + if (!shouldConnect) { + // SSL handshake fails + Exception ex = ne; + while(ex != null && !(ex instanceof CommunicationException)) { + ex = (Exception)ex.getCause(); + } + if (ex != null) { + if (ex.getCause() instanceof SSLException) { + if (!shouldPass) + return true; + } + } + } + if (!shouldPass && ne.getRootCause() == null) { + // Expected exception caused by Channel Binding parameter inconsistency + return true; + } + throw ne; + } +}