1 /*
2  * Copyright (c) 2009, 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 6449574
27  * @summary Invalid ldap filter is accepted and processed
28  */
29 
30 import java.io.*;
31 import javax.naming.*;
32 import javax.naming.directory.*;
33 import java.util.Properties;
34 import java.util.Hashtable;
35 
36 import java.net.Socket;
37 import java.net.ServerSocket;
38 
39 public class BalancedParentheses {
40     // Should we run the client or server in a separate thread?
41     //
42     // Both sides can throw exceptions, but do you have a preference
43     // as to which side should be the main thread.
44     static boolean separateServerThread = true;
45 
46     // use any free port by default
47     volatile int serverPort = 0;
48 
49     // Is the server ready to serve?
50     volatile static boolean serverReady = false;
51 
52     // Define the server side of the test.
53     //
54     // If the server prematurely exits, serverReady will be set to true
55     // to avoid infinite hangs.
doServerSide()56     void doServerSide() throws Exception {
57         ServerSocket serverSock = new ServerSocket(serverPort);
58 
59         // signal client, it's ready to accecpt connection
60         serverPort = serverSock.getLocalPort();
61         serverReady = true;
62 
63         // accept a connection
64         Socket socket = serverSock.accept();
65         System.out.println("Server: Connection accepted");
66 
67         InputStream is = socket.getInputStream();
68         OutputStream os = socket.getOutputStream();
69 
70         // read the bindRequest
71         while (is.read() != -1) {
72             // ignore
73             is.skip(is.available());
74             break;
75         }
76 
77         byte[] bindResponse = {0x30, 0x0C, 0x02, 0x01, 0x01, 0x61, 0x07, 0x0A,
78                                0x01, 0x00, 0x04, 0x00, 0x04, 0x00};
79         // write bindResponse
80         os.write(bindResponse);
81         os.flush();
82 
83         // ignore any more request.
84         while (is.read() != -1) {
85             // ignore
86             is.skip(is.available());
87         }
88 
89         is.close();
90         os.close();
91         socket.close();
92         serverSock.close();
93     }
94 
95     //  Define the client side of the test.
96     //
97     // If the server prematurely exits, serverReady will be set to true
98     // to avoid infinite hangs.
doClientSide()99     void doClientSide() throws Exception {
100         // Wait for server to get started.
101         while (!serverReady) {
102             Thread.sleep(50);
103         }
104 
105         // set up the environment for creating the initial context
106         Hashtable<Object, Object> env = new Hashtable<Object, Object>();
107         env.put(Context.INITIAL_CONTEXT_FACTORY,
108                                 "com.sun.jndi.ldap.LdapCtxFactory");
109         env.put(Context.PROVIDER_URL, "ldap://localhost:" + serverPort);
110         env.put("com.sun.jndi.ldap.read.timeout", "1000");
111 
112         // env.put(Context.SECURITY_AUTHENTICATION, "simple");
113         // env.put(Context.SECURITY_PRINCIPAL,"cn=root");
114         // env.put(Context.SECURITY_CREDENTIALS,"root");
115 
116         // create initial context
117         DirContext context = new InitialDirContext(env);
118 
119         // searching
120         SearchControls scs = new SearchControls();
121         scs.setSearchScope(SearchControls.SUBTREE_SCOPE);
122 
123         try {
124             NamingEnumeration answer = context.search(
125                                         "o=sun,c=us", "(&(cn=Bob)))", scs);
126         } catch (InvalidSearchFilterException isfe) {
127             // ignore, it is the expected filter exception.
128             System.out.println("Expected exception: " + isfe.getMessage());
129         } catch (NamingException ne) {
130             // maybe a read timeout exception, as the server does not response.
131             throw new Exception("Expect a InvalidSearchFilterException", ne);
132         }
133 
134         try {
135             NamingEnumeration answer = context.search(
136                                         "o=sun,c=us", ")(&(cn=Bob)", scs);
137         } catch (InvalidSearchFilterException isfe) {
138             // ignore, it is the expected filter exception.
139             System.out.println("Expected exception: " + isfe.getMessage());
140         } catch (NamingException ne) {
141             // maybe a read timeout exception, as the server does not response.
142             throw new Exception("Expect a InvalidSearchFilterException", ne);
143         }
144 
145         try {
146             NamingEnumeration answer = context.search(
147                                         "o=sun,c=us", "(&(cn=Bob))", scs);
148         } catch (InvalidSearchFilterException isfe) {
149             // ignore, it is the expected filter exception.
150             throw new Exception("Unexpected ISFE", isfe);
151         } catch (NamingException ne) {
152             // maybe a read timeout exception, as the server does not response.
153             System.out.println("Expected exception: " + ne.getMessage());
154         }
155 
156         context.close();
157     }
158 
159     /*
160      * ============================================================
161      * The remainder is just support stuff
162      */
163 
164     // client and server thread
165     Thread clientThread = null;
166     Thread serverThread = null;
167 
168     // client and server exceptions
169     volatile Exception serverException = null;
170     volatile Exception clientException = null;
171 
startServer(boolean newThread)172     void startServer(boolean newThread) throws Exception {
173         if (newThread) {
174             serverThread = new Thread() {
175                 public void run() {
176                     try {
177                         doServerSide();
178                     } catch (Exception e) {
179                         /*
180                          * Our server thread just died.
181                          *
182                          * Release the client, if not active already...
183                          */
184                         System.err.println("Server died...");
185                         System.err.println(e);
186                         serverReady = true;
187                         serverException = e;
188                     }
189                 }
190             };
191             serverThread.start();
192         } else {
193             doServerSide();
194         }
195     }
196 
startClient(boolean newThread)197     void startClient(boolean newThread) throws Exception {
198         if (newThread) {
199             clientThread = new Thread() {
200                 public void run() {
201                     try {
202                         doClientSide();
203                     } catch (Exception e) {
204                         /*
205                          * Our client thread just died.
206                          */
207                         System.err.println("Client died...");
208                         clientException = e;
209                     }
210                 }
211             };
212             clientThread.start();
213         } else {
214             doClientSide();
215         }
216     }
217 
218     // Primary constructor, used to drive remainder of the test.
BalancedParentheses()219     BalancedParentheses() throws Exception {
220         if (separateServerThread) {
221             startServer(true);
222             startClient(false);
223         } else {
224             startClient(true);
225             startServer(false);
226         }
227 
228         /*
229          * Wait for other side to close down.
230          */
231         if (separateServerThread) {
232             serverThread.join();
233         } else {
234             clientThread.join();
235         }
236 
237         /*
238          * When we get here, the test is pretty much over.
239          *
240          * If the main thread excepted, that propagates back
241          * immediately.  If the other thread threw an exception, we
242          * should report back.
243          */
244         if (serverException != null) {
245             System.out.print("Server Exception:");
246             throw serverException;
247         }
248         if (clientException != null) {
249             System.out.print("Client Exception:");
250             throw clientException;
251         }
252     }
253 
main(String[] args)254     public static void main(String[] args) throws Exception {
255         // start the test
256         new BalancedParentheses();
257     }
258 
259 }
260