1 /*
2  * Copyright (c) 2010, 2019, 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.
doServerSide()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.
doClientSide()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 
parseArguments(String[] args)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 
startServer(boolean newThread)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 
startClient(boolean newThread)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.
InvalidLdapFilters()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 
main(String[] args)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 }
348