< prev index next >

src/java.naming/share/classes/com/sun/jndi/ldap/Connection.java

Print this page




  29 import java.io.BufferedOutputStream;
  30 import java.io.InterruptedIOException;
  31 import java.io.IOException;
  32 import java.io.OutputStream;
  33 import java.io.InputStream;
  34 import java.net.InetSocketAddress;
  35 import java.net.Socket;
  36 import javax.net.ssl.SSLSocket;
  37 
  38 import javax.naming.CommunicationException;
  39 import javax.naming.ServiceUnavailableException;
  40 import javax.naming.NamingException;
  41 import javax.naming.InterruptedNamingException;
  42 
  43 import javax.naming.ldap.Control;
  44 
  45 import java.lang.reflect.Method;
  46 import java.lang.reflect.InvocationTargetException;
  47 import java.security.AccessController;
  48 import java.security.PrivilegedAction;


  49 import java.util.Arrays;


  50 import javax.net.SocketFactory;
  51 import javax.net.ssl.SSLParameters;




  52 
  53 /**
  54   * A thread that creates a connection to an LDAP server.
  55   * After the connection, the thread reads from the connection.
  56   * A caller can invoke methods on the instance to read LDAP responses
  57   * and to send LDAP requests.
  58   * <p>
  59   * There is a one-to-one correspondence between an LdapClient and
  60   * a Connection. Access to Connection and its methods is only via
  61   * LdapClient with two exceptions: SASL authentication and StartTLS.
  62   * SASL needs to access Connection's socket IO streams (in order to do encryption
  63   * of the security layer). StartTLS needs to do replace IO streams
  64   * and close the IO  streams on nonfatal close. The code for SASL
  65   * authentication can be treated as being the same as from LdapClient
  66   * because the SASL code is only ever called from LdapClient, from
  67   * inside LdapClient's synchronized authenticate() method. StartTLS is called
  68   * directly by the application but should only occur when the underlying
  69   * connection is quiet.
  70   * <p>
  71   * In terms of synchronization, worry about data structures


  92   *     cleanup() - sync
  93   *     readReply() - access to sock sync
  94   *     unpauseReader() - (indirectly via writeRequest) sync on pauseLock
  95   * Members used by SASL auth (main thread):
  96   *     inStream, outStream - no sync; used to construct new stream; accessed
  97   *             only when conn is "quiet" and not shared
  98   *     replaceStreams() - sync method
  99   * Members used by StartTLS:
 100   *     inStream, outStream - no sync; used to record the existing streams;
 101   *             accessed only when conn is "quiet" and not shared
 102   *     replaceStreams() - sync method
 103   * <p>
 104   * Handles anonymous, simple, and SASL bind for v3; anonymous and simple
 105   * for v2.
 106   * %%% made public for access by LdapSasl %%%
 107   *
 108   * @author Vincent Ryan
 109   * @author Rosanna Lee
 110   * @author Jagane Sundar
 111   */
 112 public final class Connection implements Runnable {
 113 
 114     private static final boolean debug = false;
 115     private static final int dump = 0; // > 0 r, > 1 rw
 116 
 117 
 118     final private Thread worker;    // Initialized in constructor
 119 
 120     private boolean v3 = true;       // Set in setV3()
 121 
 122     final public String host;  // used by LdapClient for generating exception messages
 123                          // used by StartTlsResponse when creating an SSL socket
 124     final public int port;     // used by LdapClient for generating exception messages
 125                          // used by StartTlsResponse when creating an SSL socket
 126 
 127     private boolean bound = false;   // Set in setBound()
 128 
 129     // All three are initialized in constructor and read-only afterwards
 130     private OutputStream traceFile = null;
 131     private String traceTagIn = null;
 132     private String traceTagOut = null;


 325             if (socket == null) {
 326                 if (debug) {
 327                     System.err.println("Connection: creating socket");
 328                 }
 329                 // connected socket
 330                 socket = new Socket(host, port);
 331             }
 332         }
 333 
 334         // For LDAP connect timeouts on LDAP over SSL connections must treat
 335         // the SSL handshake following socket connection as part of the timeout.
 336         // So explicitly set a socket read timeout, trigger the SSL handshake,
 337         // then reset the timeout.
 338         if (socket instanceof SSLSocket) {
 339             SSLSocket sslSocket = (SSLSocket) socket;
 340             if (!IS_HOSTNAME_VERIFICATION_DISABLED) {
 341                 SSLParameters param = sslSocket.getSSLParameters();
 342                 param.setEndpointIdentificationAlgorithm("LDAPS");
 343                 sslSocket.setSSLParameters(param);
 344             }

 345             if (connectTimeout > 0) {
 346                 int socketTimeout = sslSocket.getSoTimeout();
 347                 sslSocket.setSoTimeout(connectTimeout); // reuse full timeout value
 348                 sslSocket.startHandshake();
 349                 sslSocket.setSoTimeout(socketTimeout);
 350             }
 351         }
 352         return socket;
 353     }
 354 
 355     ////////////////////////////////////////////////////////////////////////////
 356     //
 357     // Methods to IO to the LDAP server
 358     //
 359     ////////////////////////////////////////////////////////////////////////////
 360 
 361     synchronized int getMsgId() {
 362         return ++outMsgId;
 363     }
 364 


 620                     }
 621                     if (bound) {
 622                         ldapUnbind(reqCtls);
 623                     }
 624                 } finally {
 625                     try {
 626                         outStream.flush();
 627                         sock.close();
 628                         unpauseReader();
 629                     } catch (IOException ie) {
 630                         if (debug)
 631                             System.err.println("Connection: problem closing socket: " + ie);
 632                     }
 633                     if (!notifyParent) {
 634                         LdapRequest ldr = pendingRequests;
 635                         while (ldr != null) {
 636                             ldr.cancel();
 637                             ldr = ldr.next;
 638                         }
 639                     }









 640                     sock = null;
 641                 }
 642                 nparent = notifyParent;
 643             }
 644             if (nparent) {
 645                 LdapRequest ldr = pendingRequests;
 646                 while (ldr != null) {
 647                     ldr.close();
 648                         ldr = ldr.next;
 649                     }
 650                 }
 651             }
 652         if (nparent) {
 653             parent.processConnectionClosure();
 654         }
 655     }
 656 
 657 
 658     // Assume everything is "quiet"
 659     // "synchronize" might lead to deadlock so don't synchronize method


 955         while (nread < length) {
 956             int bytesToRead;
 957             if (nread >= buf.length) {  // need to allocate a larger buffer
 958                 bytesToRead = Math.min(length - nread, buf.length + 8192);
 959                 if (buf.length < nread + bytesToRead) {
 960                     buf = Arrays.copyOf(buf, nread + bytesToRead);
 961                 }
 962             } else {
 963                 bytesToRead = buf.length - nread;
 964             }
 965             int count = is.read(buf, nread, bytesToRead);
 966             if (count < 0) {
 967                 if (buf.length != nread)
 968                     buf = Arrays.copyOf(buf, nread);
 969                 break;
 970             }
 971             nread += count;
 972         }
 973         return buf;
 974     }










































 975 }


  29 import java.io.BufferedOutputStream;
  30 import java.io.InterruptedIOException;
  31 import java.io.IOException;
  32 import java.io.OutputStream;
  33 import java.io.InputStream;
  34 import java.net.InetSocketAddress;
  35 import java.net.Socket;
  36 import javax.net.ssl.SSLSocket;
  37 
  38 import javax.naming.CommunicationException;
  39 import javax.naming.ServiceUnavailableException;
  40 import javax.naming.NamingException;
  41 import javax.naming.InterruptedNamingException;
  42 
  43 import javax.naming.ldap.Control;
  44 
  45 import java.lang.reflect.Method;
  46 import java.lang.reflect.InvocationTargetException;
  47 import java.security.AccessController;
  48 import java.security.PrivilegedAction;
  49 import java.security.cert.Certificate;
  50 import java.security.cert.X509Certificate;
  51 import java.util.Arrays;
  52 import java.util.concurrent.CompletableFuture;
  53 import java.util.concurrent.ExecutionException;
  54 import javax.net.SocketFactory;
  55 import javax.net.ssl.SSLParameters;
  56 import javax.net.ssl.HandshakeCompletedEvent;
  57 import javax.net.ssl.HandshakeCompletedListener;
  58 import javax.net.ssl.SSLPeerUnverifiedException;
  59 import javax.security.sasl.SaslException;
  60 
  61 /**
  62   * A thread that creates a connection to an LDAP server.
  63   * After the connection, the thread reads from the connection.
  64   * A caller can invoke methods on the instance to read LDAP responses
  65   * and to send LDAP requests.
  66   * <p>
  67   * There is a one-to-one correspondence between an LdapClient and
  68   * a Connection. Access to Connection and its methods is only via
  69   * LdapClient with two exceptions: SASL authentication and StartTLS.
  70   * SASL needs to access Connection's socket IO streams (in order to do encryption
  71   * of the security layer). StartTLS needs to do replace IO streams
  72   * and close the IO  streams on nonfatal close. The code for SASL
  73   * authentication can be treated as being the same as from LdapClient
  74   * because the SASL code is only ever called from LdapClient, from
  75   * inside LdapClient's synchronized authenticate() method. StartTLS is called
  76   * directly by the application but should only occur when the underlying
  77   * connection is quiet.
  78   * <p>
  79   * In terms of synchronization, worry about data structures


 100   *     cleanup() - sync
 101   *     readReply() - access to sock sync
 102   *     unpauseReader() - (indirectly via writeRequest) sync on pauseLock
 103   * Members used by SASL auth (main thread):
 104   *     inStream, outStream - no sync; used to construct new stream; accessed
 105   *             only when conn is "quiet" and not shared
 106   *     replaceStreams() - sync method
 107   * Members used by StartTLS:
 108   *     inStream, outStream - no sync; used to record the existing streams;
 109   *             accessed only when conn is "quiet" and not shared
 110   *     replaceStreams() - sync method
 111   * <p>
 112   * Handles anonymous, simple, and SASL bind for v3; anonymous and simple
 113   * for v2.
 114   * %%% made public for access by LdapSasl %%%
 115   *
 116   * @author Vincent Ryan
 117   * @author Rosanna Lee
 118   * @author Jagane Sundar
 119   */
 120 public final class Connection implements Runnable, HandshakeCompletedListener {
 121 
 122     private static final boolean debug = false;
 123     private static final int dump = 0; // > 0 r, > 1 rw
 124 
 125 
 126     final private Thread worker;    // Initialized in constructor
 127 
 128     private boolean v3 = true;       // Set in setV3()
 129 
 130     final public String host;  // used by LdapClient for generating exception messages
 131                          // used by StartTlsResponse when creating an SSL socket
 132     final public int port;     // used by LdapClient for generating exception messages
 133                          // used by StartTlsResponse when creating an SSL socket
 134 
 135     private boolean bound = false;   // Set in setBound()
 136 
 137     // All three are initialized in constructor and read-only afterwards
 138     private OutputStream traceFile = null;
 139     private String traceTagIn = null;
 140     private String traceTagOut = null;


 333             if (socket == null) {
 334                 if (debug) {
 335                     System.err.println("Connection: creating socket");
 336                 }
 337                 // connected socket
 338                 socket = new Socket(host, port);
 339             }
 340         }
 341 
 342         // For LDAP connect timeouts on LDAP over SSL connections must treat
 343         // the SSL handshake following socket connection as part of the timeout.
 344         // So explicitly set a socket read timeout, trigger the SSL handshake,
 345         // then reset the timeout.
 346         if (socket instanceof SSLSocket) {
 347             SSLSocket sslSocket = (SSLSocket) socket;
 348             if (!IS_HOSTNAME_VERIFICATION_DISABLED) {
 349                 SSLParameters param = sslSocket.getSSLParameters();
 350                 param.setEndpointIdentificationAlgorithm("LDAPS");
 351                 sslSocket.setSSLParameters(param);
 352             }
 353             sslSocket.addHandshakeCompletedListener(this);
 354             if (connectTimeout > 0) {
 355                 int socketTimeout = sslSocket.getSoTimeout();
 356                 sslSocket.setSoTimeout(connectTimeout); // reuse full timeout value
 357                 sslSocket.startHandshake();
 358                 sslSocket.setSoTimeout(socketTimeout);
 359             }
 360         }
 361         return socket;
 362     }
 363 
 364     ////////////////////////////////////////////////////////////////////////////
 365     //
 366     // Methods to IO to the LDAP server
 367     //
 368     ////////////////////////////////////////////////////////////////////////////
 369 
 370     synchronized int getMsgId() {
 371         return ++outMsgId;
 372     }
 373 


 629                     }
 630                     if (bound) {
 631                         ldapUnbind(reqCtls);
 632                     }
 633                 } finally {
 634                     try {
 635                         outStream.flush();
 636                         sock.close();
 637                         unpauseReader();
 638                     } catch (IOException ie) {
 639                         if (debug)
 640                             System.err.println("Connection: problem closing socket: " + ie);
 641                     }
 642                     if (!notifyParent) {
 643                         LdapRequest ldr = pendingRequests;
 644                         while (ldr != null) {
 645                             ldr.cancel();
 646                             ldr = ldr.next;
 647                         }
 648                     }
 649                     if (isTlsConnection()) {
 650                         if (closureReason != null) {
 651                             CommunicationException ce = new CommunicationException();
 652                             ce.setRootCause(closureReason);
 653                             tlsHandshakeCompleted.completeExceptionally(ce);
 654                         } else {
 655                             tlsHandshakeCompleted.cancel(false);
 656                         }
 657                     }
 658                     sock = null;
 659                 }
 660                 nparent = notifyParent;
 661             }
 662             if (nparent) {
 663                 LdapRequest ldr = pendingRequests;
 664                 while (ldr != null) {
 665                     ldr.close();
 666                         ldr = ldr.next;
 667                     }
 668                 }
 669             }
 670         if (nparent) {
 671             parent.processConnectionClosure();
 672         }
 673     }
 674 
 675 
 676     // Assume everything is "quiet"
 677     // "synchronize" might lead to deadlock so don't synchronize method


 973         while (nread < length) {
 974             int bytesToRead;
 975             if (nread >= buf.length) {  // need to allocate a larger buffer
 976                 bytesToRead = Math.min(length - nread, buf.length + 8192);
 977                 if (buf.length < nread + bytesToRead) {
 978                     buf = Arrays.copyOf(buf, nread + bytesToRead);
 979                 }
 980             } else {
 981                 bytesToRead = buf.length - nread;
 982             }
 983             int count = is.read(buf, nread, bytesToRead);
 984             if (count < 0) {
 985                 if (buf.length != nread)
 986                     buf = Arrays.copyOf(buf, nread);
 987                 break;
 988             }
 989             nread += count;
 990         }
 991         return buf;
 992     }
 993 
 994     private CompletableFuture<X509Certificate> tlsHandshakeCompleted =
 995             new CompletableFuture<>();
 996 
 997     @Override
 998     public void handshakeCompleted(HandshakeCompletedEvent event) {
 999         try {
1000             X509Certificate tlsServerCert = null;
1001             Certificate[] certs;
1002             if (event.getSocket().getUseClientMode()) {
1003                 certs = event.getPeerCertificates();
1004             } else {
1005                 certs = event.getLocalCertificates();
1006             }
1007             if (certs != null && certs.length > 0 &&
1008                     certs[0] instanceof X509Certificate) {
1009                 tlsServerCert = (X509Certificate) certs[0];
1010             }
1011             tlsHandshakeCompleted.complete(tlsServerCert);
1012         } catch (SSLPeerUnverifiedException ex) {
1013             CommunicationException ce = new CommunicationException();
1014             ce.setRootCause(closureReason);
1015             tlsHandshakeCompleted.completeExceptionally(ex);
1016         }
1017     }
1018 
1019     public boolean isTlsConnection() {
1020         return sock instanceof SSLSocket;
1021     }
1022 
1023     public X509Certificate getTlsServerCertificate()
1024             throws SaslException {
1025         try {
1026             if (isTlsConnection())
1027                 return tlsHandshakeCompleted.get();
1028         } catch (InterruptedException iex) {
1029             throw new SaslException("TLS Handshake Exception ", iex);
1030         } catch (ExecutionException eex) {
1031             throw new SaslException("TLS Handshake Exception ", eex.getCause());
1032         }
1033         return null;
1034     }
1035 }
< prev index next >