1 /* 2 * Copyright (c) 2010, 2020, 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 /** 25 * @test 26 * @bug 6916202 7041125 27 * @library /test/lib 28 * @summary More cases of invalid ldap filters accepted and processed 29 * LDAP API does not catch malformed filters that contain two operands 30 * for the ! operator 31 * @run main/othervm InvalidLdapFilters valid (cn=Babs) 32 * @run main/othervm InvalidLdapFilters valid (&(cn=Bob)) 33 * @run main/othervm InvalidLdapFilters valid (&(objectClass=*)(uid=*)) 34 * @run main/othervm InvalidLdapFilters valid (|(cn=Bob)) 35 * @run main/othervm InvalidLdapFilters valid (|(objectClass=*)(uid=*)) 36 * @run main/othervm InvalidLdapFilters valid (!(cn=Tim)) 37 * @run main/othervm InvalidLdapFilters valid (!(!(cn=Tim))) 38 * @run main/othervm InvalidLdapFilters valid (!(&(objectClass=*)(uid=*))) 39 * @run main/othervm InvalidLdapFilters valid (!(|(objectClass=*)(uid=*))) 40 * @run main/othervm InvalidLdapFilters valid (&(objectClass=*)(!(uid=*))) 41 * @run main/othervm InvalidLdapFilters valid (o=univ*of*mich*) 42 * @run main/othervm InvalidLdapFilters valid (seeAlso=) 43 * @run main/othervm InvalidLdapFilters valid (cn:caseExactMatch:=Flintstone) 44 * @run main/othervm InvalidLdapFilters valid (cn:=Betty) 45 * @run main/othervm InvalidLdapFilters valid (sn:dn:2.4.6.8.10:=Barney) 46 * @run main/othervm InvalidLdapFilters valid (o:dn:=Ace) 47 * @run main/othervm InvalidLdapFilters valid (:1.2.3:=Wilma) 48 * @run main/othervm InvalidLdapFilters valid (:DN:2.4.6.8.10:=Dino) 49 * @run main/othervm InvalidLdapFilters valid (1.2.3=abc) 50 * @run main/othervm InvalidLdapFilters valid (cn;lang-de;lang-en=abc) 51 * @run main/othervm InvalidLdapFilters valid (owner=abc) 52 * @run main/othervm InvalidLdapFilters valid (sn;lang-en:dn:2.4.6.8.10:=Barney) 53 * @run main/othervm InvalidLdapFilters valid 54 (&(objectClass=Person)(|(sn=Jensen)(cn=Bab*))) 55 * @run main/othervm InvalidLdapFilters valid 56 (orcluserapplnprovstatus;EMAIL_email=PROVISIONING_FAILURE) 57 * @run main/othervm InvalidLdapFilters invalid "(&(cn=Robert Dean)))" 58 * @run main/othervm InvalidLdapFilters invalid (&|(cn=Bob)) 59 * @run main/othervm InvalidLdapFilters invalid (&&(cn=Bob)) 60 * @run main/othervm InvalidLdapFilters invalid (|&(cn=Bob)) 61 * @run main/othervm InvalidLdapFilters invalid (||(cn=Bob)) 62 * @run main/othervm InvalidLdapFilters invalid (:1.2.:=Wilma) 63 * @run main/othervm InvalidLdapFilters invalid (::DN:2.4.6.8.10:=Dino) 64 * @run main/othervm InvalidLdapFilters invalid (:DN::2.4.6.8.10:=Dino) 65 * @run main/othervm InvalidLdapFilters invalid (:DN:2.4.6.8.10::=Dino) 66 * @run main/othervm InvalidLdapFilters invalid (:DN:2.4.6..8.10:=Dino) 67 * @run main/othervm InvalidLdapFilters invalid (:DN:2.4.6.8.:=Dino) 68 * @run main/othervm InvalidLdapFilters invalid (1.2.;::=abc) 69 * @run main/othervm InvalidLdapFilters invalid (1.2.3;::=abc) 70 * @run main/othervm InvalidLdapFilters invalid (1.2.3;x;=abc) 71 * @run main/othervm InvalidLdapFilters invalid (1.2.3:x::=abc) 72 * @run main/othervm InvalidLdapFilters invalid (1.2.3:x=abc) 73 * @run main/othervm InvalidLdapFilters invalid (sn;:dn:2.4.6.8.10:=Barney) 74 * @run main/othervm InvalidLdapFilters invalid "\"((objectClass=*)&(uid=*))\"" 75 * @run main/othervm InvalidLdapFilters invalid "&(objectClass=*)(uid=*)" 76 * @run main/othervm InvalidLdapFilters invalid "(:DN:2.4.6.8.10:cn:=Dino)" 77 * @run main/othervm InvalidLdapFilters invalid "(:DN:2.4.6.8.10:cn=Dino)" 78 * @run main/othervm InvalidLdapFilters invalid 79 "((objectCategory=person)(cn=u)(!(cn=u2*)))" 80 * @run main/othervm InvalidLdapFilters invalid 81 "((&(objectClass=user)(cn=andy*)(cn=steve*)(cn=bob*)))" 82 * @run main/othervm InvalidLdapFilters invalid 83 (&(objectClass=Person)(!(sn=Jensen)(cn=Bab))) 84 * 85 * @author Xuelei Fan 86 */ 87 88 import java.io.*; 89 import javax.naming.*; 90 import javax.naming.directory.*; 91 import java.net.InetAddress; 92 import java.net.InetSocketAddress; 93 import java.net.SocketAddress; 94 import java.util.Hashtable; 95 96 import java.net.Socket; 97 import java.net.ServerSocket; 98 99 import jdk.test.lib.net.URIBuilder; 100 101 public class InvalidLdapFilters { 102 // Should we run the client or server in a separate thread? 103 // 104 // Both sides can throw exceptions, but do you have a preference 105 // as to which side should be the main thread. 106 static boolean separateServerThread = true; 107 108 // use any free port by default 109 volatile int serverPort = 0; 110 111 // Is the server ready to serve? 112 volatile static boolean serverReady = false; 113 114 // Define the server side of the test. 115 // 116 // If the server prematurely exits, serverReady will be set to true 117 // to avoid infinite hangs. 118 void doServerSide() throws Exception { 119 ServerSocket serverSock = new ServerSocket(); 120 SocketAddress sockAddr = new InetSocketAddress( 121 InetAddress.getLoopbackAddress(), serverPort); 122 // Bind server socket 123 serverSock.bind(sockAddr); 124 125 // signal client, it's ready to accept connection 126 serverPort = serverSock.getLocalPort(); 127 serverReady = true; 128 129 // accept a connection 130 Socket socket = serverSock.accept(); 131 System.out.println("Server: Connection accepted"); 132 133 InputStream is = socket.getInputStream(); 134 OutputStream os = socket.getOutputStream(); 135 136 // read the bindRequest 137 while (is.read() != -1) { 138 // ignore 139 is.skip(is.available()); 140 break; 141 } 142 143 byte[] bindResponse = {0x30, 0x0C, 0x02, 0x01, 0x01, 0x61, 0x07, 0x0A, 144 0x01, 0x00, 0x04, 0x00, 0x04, 0x00}; 145 // write bindResponse 146 os.write(bindResponse); 147 os.flush(); 148 149 // ignore any more request. 150 while (is.read() != -1) { 151 // ignore 152 is.skip(is.available()); 153 } 154 155 is.close(); 156 os.close(); 157 socket.close(); 158 serverSock.close(); 159 } 160 161 // Define the client side of the test. 162 // 163 // If the server prematurely exits, serverReady will be set to true 164 // to avoid infinite hangs. 165 void doClientSide() throws Exception { 166 // Wait for server to get started. 167 while (!serverReady) { 168 Thread.sleep(50); 169 } 170 171 // set up the environment for creating the initial context 172 Hashtable<Object, Object> env = new Hashtable<>(); 173 env.put(Context.INITIAL_CONTEXT_FACTORY, 174 "com.sun.jndi.ldap.LdapCtxFactory"); 175 String providerUrl = URIBuilder.newBuilder() 176 .scheme("ldap") 177 .loopback() 178 .port(serverPort) 179 .build() 180 .toString(); 181 env.put(Context.PROVIDER_URL, providerUrl); 182 env.put("com.sun.jndi.ldap.read.timeout", "1000"); 183 184 // env.put(Context.SECURITY_AUTHENTICATION, "simple"); 185 // env.put(Context.SECURITY_PRINCIPAL,"cn=root"); 186 // env.put(Context.SECURITY_CREDENTIALS,"root"); 187 188 // create initial context 189 DirContext context = null; 190 int i = 0; 191 while (true) { 192 try { 193 context = new InitialDirContext(env); 194 break; 195 } catch (NamingException ne) { 196 // may be a connection or read timeout, try again 197 // no more than 5 times 198 if (i++ > 5) { 199 throw new Exception( 200 "Maybe timeout during context initialization", ne); 201 } 202 } 203 } 204 205 // searching 206 SearchControls scs = new SearchControls(); 207 scs.setSearchScope(SearchControls.SUBTREE_SCOPE); 208 209 try { 210 NamingEnumeration<?> answer = 211 context.search("o=sun,c=us", searchFilter, scs); 212 } catch (InvalidSearchFilterException isfe) { 213 if (filterIsValid) { 214 // unexpected filter exception. 215 throw new Exception("Unexpected ISFE", isfe); 216 } else { 217 // ignore, it is the expected filter exception. 218 System.out.println("Expected exception: " + isfe.getMessage()); 219 } 220 } catch (NamingException ne) { 221 // maybe a read timeout exception, as the server does not response. 222 if (filterIsValid) { 223 System.out.println("Expected exception: " + ne.getMessage()); 224 } else { 225 throw new Exception("Not an InvalidSearchFilterException", ne); 226 } 227 } 228 229 context.close(); 230 } 231 232 private static boolean filterIsValid; 233 private static String searchFilter; 234 235 private static void parseArguments(String[] args) { 236 System.out.println("arguments length: " + args.length); 237 if (args[0].equals("valid")) { 238 filterIsValid = true; 239 } 240 241 searchFilter = args[1]; 242 } 243 244 /* 245 * ============================================================ 246 * The remainder is just support stuff 247 */ 248 249 // client and server thread 250 Thread clientThread = null; 251 Thread serverThread = null; 252 253 // client and server exceptions 254 volatile Exception serverException = null; 255 volatile Exception clientException = null; 256 257 void startServer(boolean newThread) throws Exception { 258 if (newThread) { 259 serverThread = new Thread() { 260 public void run() { 261 try { 262 doServerSide(); 263 } catch (Exception e) { 264 /* 265 * Our server thread just died. 266 * 267 * Release the client, if not active already... 268 */ 269 System.err.println("Server died..."); 270 System.err.println(e); 271 serverReady = true; 272 serverException = e; 273 } 274 } 275 }; 276 serverThread.start(); 277 } else { 278 doServerSide(); 279 } 280 } 281 282 void startClient(boolean newThread) throws Exception { 283 if (newThread) { 284 clientThread = new Thread() { 285 public void run() { 286 try { 287 doClientSide(); 288 } catch (Exception e) { 289 /* 290 * Our client thread just died. 291 */ 292 System.err.println("Client died..."); 293 clientException = e; 294 } 295 } 296 }; 297 clientThread.start(); 298 } else { 299 doClientSide(); 300 } 301 } 302 303 // Primary constructor, used to drive remainder of the test. 304 InvalidLdapFilters() throws Exception { 305 if (separateServerThread) { 306 startServer(true); 307 startClient(false); 308 } else { 309 startClient(true); 310 startServer(false); 311 } 312 313 /* 314 * Wait for other side to close down. 315 */ 316 if (separateServerThread) { 317 serverThread.join(); 318 } else { 319 clientThread.join(); 320 } 321 322 /* 323 * When we get here, the test is pretty much over. 324 * 325 * If the main thread excepted, that propagates back 326 * immediately. If the other thread threw an exception, we 327 * should report back. 328 */ 329 if (serverException != null) { 330 System.out.print("Server Exception:"); 331 throw serverException; 332 } 333 if (clientException != null) { 334 System.out.print("Client Exception:"); 335 throw clientException; 336 } 337 } 338 339 public static void main(String[] args) throws Exception { 340 // parse the customized arguments 341 parseArguments(args); 342 343 // start the test 344 new InvalidLdapFilters(); 345 } 346 347 }