1 import java.net.Socket; 2 import java.net.ServerSocket; 3 import java.io.*; 4 import javax.naming.*; 5 import javax.naming.directory.*; 6 import java.security.Permission; 7 import java.util.Hashtable; 8 import java.util.concurrent.*; 9 10 /** 11 * @test 12 * @compile TestDnsProvider.java 13 * @run main/othervm LdapDnsProviderTest 14 * @modules java.naming/com.sun.jndi.ldap 15 * @bug 8160768 16 * @summary ctx provider tests for ldap 17 */ 18 19 class DNSSecurityManager extends SecurityManager { 20 21 private boolean perm = false; 22 23 public void allowSetFactory() { 24 perm = true; 25 } 26 27 @Override 28 public void checkPermission(Permission p) { 29 if (p.getName().equals("setFactory") && !perm) { 30 throw new SecurityException(p.getName()); 31 } 32 } 33 } 34 35 class ProviderTest implements Callable { 36 37 private final String expected; 38 private final ScheduledExecutorService killSwitchPool; 39 private final LdapTestServer server; 40 private final Hashtable env = new Hashtable(11); 41 private final int HANGING_TEST_TIMEOUT = 1000; 42 43 public ProviderTest(LdapTestServer server, 44 ScheduledExecutorService killSwitchPool, 45 String expected) 46 throws IOException 47 { 48 this.server = server; 49 this.killSwitchPool = killSwitchPool; 50 this.expected = expected; 51 env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); 52 } 53 54 public ProviderTest(LdapTestServer server, 55 ScheduledExecutorService killSwitchPool, 56 String expected, 57 String dnsProvider) 58 throws IOException 59 { 60 this(server, killSwitchPool, expected); 61 env.put("com.sun.jndi.ldap.dnsProvider", dnsProvider); 62 } 63 64 boolean shutItDown(InitialContext ctx) { 65 try { 66 if (ctx != null) ctx.close(); 67 return true; 68 } catch (NamingException ex) { 69 return false; 70 } 71 } 72 73 public Boolean call() { 74 boolean passed; 75 InitialContext ctx = null; 76 ScheduledFuture killer = null; 77 // String providerUrl = "ldap://localhost:" + server.getLocalPort(); 78 String providerUrl = "ldap:///dc=example,dc=com"; 79 80 try { 81 while(!server.accepting()) { 82 Thread.sleep(200); // allow the server to start up 83 } 84 Thread.sleep(200); // to be sure 85 86 // if this is a hanging test, scheduled a thread to 87 // interrupt after a certain time 88 if (killSwitchPool != null) { 89 final Thread current = Thread.currentThread(); 90 killer = killSwitchPool.schedule( 91 (Callable<Void>) () -> { 92 current.interrupt(); 93 return null; 94 }, HANGING_TEST_TIMEOUT, TimeUnit.MILLISECONDS); 95 } 96 97 env.put(Context.PROVIDER_URL, providerUrl); 98 99 try { 100 ctx = new InitialDirContext(env); 101 SearchControls scl = new SearchControls(); 102 scl.setSearchScope(SearchControls.SUBTREE_SCOPE); 103 ((InitialDirContext)ctx).search( 104 "ou=People,o=Test", "(objectClass=*)", scl); 105 throw new RuntimeException("Search should not complete"); 106 } catch (NamingException e) { 107 System.err.println(e); 108 passed = e.toString().indexOf(expected) > -1; 109 } finally { 110 if (killer != null && !killer.isDone()) { 111 killer.cancel(true); 112 } 113 shutItDown(ctx); 114 server.close(); 115 } 116 return passed; 117 } catch (IOException|InterruptedException e) { 118 throw new RuntimeException(e); 119 } 120 } 121 } 122 123 124 class LdapTestServer extends Thread { 125 ServerSocket serverSock; 126 boolean accepting = false; 127 private byte[] bindResponse = { 128 0x30, 0x0C, 0x02, 0x01, 0x01, 0x61, 0x07, 0x0A, 129 0x01, 0x00, 0x04, 0x00, 0x04, 0x00 130 }; 131 132 public LdapTestServer() throws IOException { 133 this.serverSock = new ServerSocket(0); 134 start(); 135 } 136 137 public int getLocalPort() { 138 return serverSock.getLocalPort(); 139 } 140 141 public boolean accepting() { 142 return accepting; 143 } 144 145 public void close() throws IOException { 146 serverSock.close(); 147 } 148 149 public void run() { 150 try { 151 accepting = true; 152 Socket socket = serverSock.accept(); 153 InputStream in = socket.getInputStream(); 154 OutputStream out = socket.getOutputStream(); 155 156 // Read the LDAP BindRequest 157 while (in.read() != -1) { 158 in.skip(in.available()); 159 break; 160 } 161 162 // Write an LDAP BindResponse 163 out.write(bindResponse); 164 out.flush(); 165 } catch (IOException e) { 166 // ignore 167 } 168 } 169 } 170 171 public class LdapDnsProviderTest { 172 173 private static final ExecutorService testPool = 174 Executors.newFixedThreadPool(1); 175 private static final ScheduledExecutorService killSwitchPool = 176 Executors.newScheduledThreadPool(1); 177 private static DNSSecurityManager sm = new DNSSecurityManager(); 178 179 public static void main(String[] args) throws Exception { 180 LdapTestServer server = new LdapTestServer(); 181 try { 182 // TestDnsProvider, no SecurityManager 183 runTest(server, "yupyupyup:389", TestDnsProvider.class.getName()); 184 // DefaultDnsProvider, no SecurityManager 185 runTest(server, "localhost:389", "com.sun.jndi.ldap.DefaultLdapDnsProvider"); 186 // no (default) dnsProvider, no SecurityManager 187 runTest(server, "localhost:389", ""); 188 // no dnsProvider context property, no SecurityManager 189 runTest(server, "localhost:389"); 190 191 System.setSecurityManager(sm); 192 193 // TestDnsProvider with SecurityManager and no permissions 194 runTest(server, 195 "setFactory", 196 TestDnsProvider.class.getName()); 197 198 sm.allowSetFactory(); 199 200 // TestDnsProvider with SecurityManager and correct permissions 201 runTest(server, 202 "yupyupyup:389", 203 TestDnsProvider.class.getName()); 204 } finally { 205 LdapDnsProviderTest.killSwitchPool.shutdown(); 206 LdapDnsProviderTest.testPool.shutdown(); 207 } 208 } 209 210 private static boolean runTest(LdapTestServer server, 211 String expected) 212 throws IOException, InterruptedException, ExecutionException 213 { 214 Future test = testPool.submit( 215 new ProviderTest( 216 server, killSwitchPool, expected)); 217 218 while (!test.isDone()) { 219 if ((Boolean) test.get()) { 220 return true; 221 } 222 } 223 throw new AssertionError("FAILED: " + expected); 224 } 225 226 private static boolean runTest(LdapTestServer server, 227 String expected, 228 String dnsProvider) 229 throws IOException, InterruptedException, ExecutionException 230 { 231 Future test = testPool.submit( 232 new ProviderTest( 233 server, killSwitchPool, expected, dnsProvider)); 234 235 while (!test.isDone()) { 236 if ((Boolean) test.get()) { 237 return true; 238 } 239 } 240 throw new AssertionError("FAILED: " + expected + ", " + dnsProvider); 241 } 242 243 } 244