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 }