From 43e9c7913fc664b725e167090fe6d389a4558315 Mon Sep 17 00:00:00 2001
From: jvergara <jvergara@localhost>
Date: Fri, 08 Jun 2007 14:43:45 +0000
Subject: [PATCH] The following commit adds all the code necessary to be able to configure replication using the setup.

---
 opends/src/quicksetup/org/opends/quicksetup/util/Utils.java |  422 +++++++++++++++++++++++++++++++---------------------
 1 files changed, 254 insertions(+), 168 deletions(-)

diff --git a/opends/src/quicksetup/org/opends/quicksetup/util/Utils.java b/opends/src/quicksetup/org/opends/quicksetup/util/Utils.java
index ab56bdf..fc78b0e 100644
--- a/opends/src/quicksetup/org/opends/quicksetup/util/Utils.java
+++ b/opends/src/quicksetup/org/opends/quicksetup/util/Utils.java
@@ -38,20 +38,22 @@
 import java.io.InputStream;
 import java.io.PrintWriter;
 import java.io.RandomAccessFile;
-import java.net.ConnectException;
+import java.security.GeneralSecurityException;
 import java.util.*;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
-import javax.naming.CommunicationException;
-import javax.naming.Context;
 import javax.naming.NamingException;
-import javax.naming.directory.SearchControls;
+import javax.naming.directory.SearchResult;
 import javax.naming.ldap.InitialLdapContext;
 import javax.naming.ldap.LdapName;
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.SSLHandshakeException;
+import javax.net.ssl.TrustManager;
 import javax.swing.JFrame;
 import javax.swing.JOptionPane;
 
+import org.opends.admin.ads.util.ConnectionUtils;
 import org.opends.quicksetup.*;
 import org.opends.quicksetup.webstart.JnlpProperties;
 import org.opends.quicksetup.i18n.ResourceProvider;
@@ -67,8 +69,6 @@
   private static final Logger LOG =
           Logger.getLogger(Utils.class.getName());
 
-  private static final int DEFAULT_LDAP_CONNECT_TIMEOUT = 3000;
-
   private static final int BUFFER_SIZE = 1024;
 
   private static final int MAX_LINE_WIDTH = 80;
@@ -757,6 +757,20 @@
     return p.waitFor();
   }
 
+  /**
+   * Returns the String that can be used to represent a given host name in a
+   * LDAP URL.
+   * This method must be used when we have IPv6 addresses (the address in the
+   * LDAP URL must be enclosed with brackets).
+   * @param host the host name.
+   * @return the String that can be used to represent a given host name in a
+   * LDAP URL.
+   */
+  public static String getHostNameForLdapUrl(String host)
+  {
+    return ConnectionUtils.getHostNameForLdapUrl(host);
+  }
+
   // Very limited for the moment: apply only permissions to the current user and
   // does not work in non-English environments... to work in non English we
   // should use xcalcs but it does not come in the windows default install...
@@ -847,56 +861,83 @@
       String pwd, int timeout, Hashtable<String, String> env)
       throws NamingException
   {
-    if (env != null)
-    { // We clone 'env' so that we can modify it freely
-      env = new Hashtable<String, String>(env);
-    } else
-    {
-      env = new Hashtable<String, String>();
-    }
-    env
-        .put(Context.INITIAL_CONTEXT_FACTORY,
-            "com.sun.jndi.ldap.LdapCtxFactory");
-    env.put(Context.PROVIDER_URL, ldapURL);
-    if (timeout >= 1)
-    {
-      env.put("com.sun.jndi.ldap.connect.timeout", String.valueOf(timeout));
-    }
-    if (dn != null)
-    {
-      env.put(Context.SECURITY_PRINCIPAL, dn);
-    }
-    if (pwd != null)
-    {
-      env.put(Context.SECURITY_CREDENTIALS, pwd);
-    }
-
-    /* Contains the DirContext and the Exception if any */
-    final Object[] pair = new Object[]
-      { null, null };
-    final Hashtable fEnv = env;
-    Thread t = new Thread(new Runnable()
-    {
-      public void run()
-      {
-        try
-        {
-          pair[0] = new InitialLdapContext(fEnv, null);
-
-        } catch (NamingException ne)
-        {
-          pair[1] = ne;
-
-        } catch (Throwable t)
-        {
-          pair[1] = t;
-        }
-      }
-    });
-    return getInitialLdapContext(t, pair, timeout);
+    return ConnectionUtils.createLdapContext(ldapURL, dn, pwd, timeout, env);
   }
 
   /**
+   * Creates an LDAPS connection and returns the corresponding LdapContext.
+   * This method uses the TrusteSocketFactory class so that the specified
+   * trust manager gets called during the SSL handshake. If trust manager is
+   * null, certificates are not verified during SSL handshake.
+   *
+   * @param ldapsURL      the target *LDAPS* URL.
+   * @param dn            passed as Context.SECURITY_PRINCIPAL if not null.
+   * @param pwd           passed as Context.SECURITY_CREDENTIALS if not null.
+   * @param timeout       passed as com.sun.jndi.ldap.connect.timeout if > 0.
+   * @param env           null or additional environment properties.
+   * @param trustManager  null or the trust manager to be invoked during SSL
+   * negociation.
+   *
+   * @return the established connection with the given parameters.
+   *
+   * @throws NamingException the exception thrown when instantiating
+   * InitialLdapContext.
+   *
+   * @see javax.naming.Context
+   * @see javax.naming.ldap.InitialLdapContext
+   * @see TrustedSocketFactory
+   */
+  public static InitialLdapContext createLdapsContext(String ldapsURL,
+      String dn, String pwd, int timeout, Hashtable<String, String> env,
+      TrustManager trustManager) throws NamingException {
+    return ConnectionUtils.createLdapsContext(ldapsURL, dn, pwd, timeout, env,
+        trustManager);
+  }
+
+  /**
+   * Creates an LDAP+StartTLS connection and returns the corresponding
+   * LdapContext.
+   * This method first creates an LdapContext with anonymous bind. Then it
+   * requests a StartTlsRequest extended operation. The StartTlsResponse is
+   * setup with the specified hostname verifier. Negotiation is done using a
+   * TrustSocketFactory so that the specified TrustManager gets called during
+   * the SSL handshake.
+   * If trust manager is null, certificates are not checked during SSL
+   * handshake.
+   *
+   * @param ldapsURL      the target *LDAPS* URL.
+   * @param dn            passed as Context.SECURITY_PRINCIPAL if not null.
+   * @param pwd           passed as Context.SECURITY_CREDENTIALS if not null.
+   * @param timeout       passed as com.sun.jndi.ldap.connect.timeout if > 0.
+   * @param env           null or additional environment properties.
+   * @param trustManager  null or the trust manager to be invoked during SSL.
+   * negociation.
+   * @param verifier      null or the hostname verifier to be setup in the
+   * StartTlsResponse.
+   *
+   * @return the established connection with the given parameters.
+   *
+   * @throws NamingException the exception thrown when instantiating
+   * InitialLdapContext.
+   *
+   * @see javax.naming.Context
+   * @see javax.naming.ldap.InitialLdapContext
+   * @see javax.naming.ldap.StartTlsRequest
+   * @see javax.naming.ldap.StartTlsResponse
+   * @see TrustedSocketFactory
+   */
+
+  public static InitialLdapContext createStartTLSContext(String ldapsURL,
+      String dn, String pwd, int timeout, Hashtable<String, String> env,
+      TrustManager trustManager, HostnameVerifier verifier)
+  throws NamingException
+  {
+    return ConnectionUtils.createStartTLSContext(ldapsURL, dn, pwd, timeout,
+        env, trustManager, verifier);
+  }
+
+
+  /**
    * Method used to know if we can connect as administrator in a server with a
    * given password and dn.
    * @param ldapUrl the ldap URL of the server.
@@ -908,33 +949,40 @@
   public static boolean canConnectAsAdministrativeUser(String ldapUrl,
       String dn, String pwd)
   {
-    boolean canConnectAsAdministrativeUser = false;
-    try
-    {
-      InitialLdapContext ctx =
-        Utils.createLdapContext(ldapUrl, dn, pwd,
-            Utils.getDefaultLDAPTimeout(), null);
+    return ConnectionUtils.canConnectAsAdministrativeUser(ldapUrl, dn, pwd);
+  }
 
-      /*
-       * Search for the config to check that it is the directory manager.
-       */
-      SearchControls searchControls = new SearchControls();
-      searchControls.setCountLimit(1);
-      searchControls.setSearchScope(
-      SearchControls. OBJECT_SCOPE);
-      searchControls.setReturningAttributes(
-      new String[] {"dn"});
-      ctx.search("cn=config", "objectclass=*", searchControls);
+/**
+ * Tells whether the provided Throwable was caused because of a problem with
+ * a certificate while trying to establish a connection.
+ * @param t the Throwable to analyze.
+ * @return <CODE>true</CODE> if the provided Throwable was caused because of a
+ * problem with a certificate while trying to establish a connection and
+ * <CODE>false</CODE> otherwise.
+ */
+  public static boolean isCertificateException(Throwable t)
+  {
+    boolean returnValue = false;
 
-      canConnectAsAdministrativeUser = true;
-    } catch (NamingException ne)
+    while (!returnValue && (t != null))
     {
-      // Nothing to do.
-    } catch (Throwable t)
-    {
-      throw new IllegalStateException("Unexpected throwable.", t);
+      returnValue = (t instanceof SSLHandshakeException) ||
+      (t instanceof GeneralSecurityException);
+      t = t.getCause();
     }
-    return canConnectAsAdministrativeUser;
+
+    return returnValue;
+  }
+
+  /**
+   * Returns the default LDAP timeout in milliseconds when we try to connect to
+   * a server.
+   * @return the default LDAP timeout in milliseconds when we try to connect to
+   * a server.
+   */
+  public static int getDefaultLDAPTimeout()
+  {
+    return ConnectionUtils.getDefaultLDAPTimeout();
   }
 
   /**
@@ -999,7 +1047,7 @@
      String title)
  {
    return JOptionPane.YES_OPTION == JOptionPane.showOptionDialog(
-       parent, msg, title, JOptionPane.YES_NO_OPTION,
+       parent, wrapMsg(msg, 100), title, JOptionPane.YES_NO_OPTION,
        JOptionPane.QUESTION_MESSAGE, null, // don't use a custom
        // Icon
        null, // the titles of buttons
@@ -1018,7 +1066,7 @@
    */
   public static void displayError(Component parent, String msg, String title)
   {
-    JOptionPane.showMessageDialog(parent, msg, title,
+    JOptionPane.showMessageDialog(parent, wrapMsg(msg, 100), title,
         JOptionPane.ERROR_MESSAGE);
   }
 
@@ -1035,7 +1083,7 @@
   public static void displayInformationMessage(JFrame parent, String msg,
       String title)
   {
-    JOptionPane.showMessageDialog(parent, msg, title,
+    JOptionPane.showMessageDialog(parent, wrapMsg(msg, 100), title,
         JOptionPane.INFORMATION_MESSAGE);
   }
 
@@ -1087,95 +1135,6 @@
     return outsideLogs;
   }
 
-  /**
-   * This is just a commodity method used to try to get an InitialLdapContext.
-   * @param t the Thread to be used to create the InitialLdapContext.
-   * @param pair an Object[] array that contains the InitialLdapContext and the
-   * Throwable if any occurred.
-   * @param timeout the timeout.  If we do not get to create the connection
-   * before the timeout a CommunicationException will be thrown.
-   * @return the created InitialLdapContext
-   * @throws NamingException if something goes wrong during the creation.
-   */
-  private static InitialLdapContext getInitialLdapContext(Thread t,
-      Object[] pair, int timeout) throws NamingException
-  {
-    try
-    {
-      if (timeout > 0)
-      {
-        t.start();
-        t.join(timeout);
-      } else
-      {
-        t.run();
-      }
-
-    } catch (InterruptedException x)
-    {
-      // This might happen for problems in sockets
-      // so it does not necessarily imply a bug
-    }
-
-    boolean throwException = false;
-
-    if ((timeout > 0) && t.isAlive())
-    {
-      t.interrupt();
-      try
-      {
-        t.join(2000);
-      } catch (InterruptedException x)
-      {
-        // This might happen for problems in sockets
-        // so it does not necessarily imply a bug
-      }
-      throwException = true;
-    }
-
-    if ((pair[0] == null) && (pair[1] == null))
-    {
-      throwException = true;
-    }
-
-    if (throwException)
-    {
-      NamingException xx;
-      ConnectException x = new ConnectException("Connection timed out");
-      xx = new CommunicationException("Connection timed out");
-      xx.initCause(x);
-      throw xx;
-    }
-
-    if (pair[1] != null)
-    {
-      if (pair[1] instanceof NamingException)
-      {
-        throw (NamingException) pair[1];
-
-      } else if (pair[1] instanceof RuntimeException)
-      {
-        throw (RuntimeException) pair[1];
-
-      } else if (pair[1] instanceof Throwable)
-      {
-        throw new IllegalStateException("Unexpected throwable occurred",
-            (Throwable) pair[1]);
-      }
-    }
-    return (InitialLdapContext) pair[0];
-  }
-
-  /**
-   * Returns the default LDAP timeout in milliseconds when we try to connect to
-   * a server.
-   * @return the default LDAP timeout in milliseconds when we try to connect to
-   * a server.
-   */
-  public static int getDefaultLDAPTimeout()
-  {
-    return DEFAULT_LDAP_CONNECT_TIMEOUT;
-  }
 
   /**
 
@@ -1392,6 +1351,133 @@
   }
 
   /**
+   * Returns the String representation of the first value of an attribute in a
+   * LDAP entry.
+   * @param entry the entry.
+   * @param attrName the attribute name.
+   * @return the String representation of the first value of an attribute in a
+   * LDAP entry.
+   * @throws NamingException if there is an error processing the entry.
+   */
+  static public String getFirstValue(SearchResult entry, String attrName)
+  throws NamingException
+  {
+    return ConnectionUtils.getFirstValue(entry, attrName);
+  }
+
+  /**
+   * Private method used to wrap the messages that are displayed in dialogs
+   * of type JOptionPane.
+   * @param msg the message.
+   * @param width the maximum width of the column.
+   * @return the wrapped message.
+   */
+  private static String wrapMsg(String msg, int width)
+  {
+    StringBuilder   buffer        = new StringBuilder();
+    StringTokenizer lineTokenizer = new StringTokenizer(msg, "\n", true);
+    while (lineTokenizer.hasMoreTokens())
+    {
+      String line = lineTokenizer.nextToken();
+      if (line.equals("\n"))
+      {
+        // It's an end-of-line character, so append it as-is.
+        buffer.append(line);
+      }
+      else if (line.length() < width)
+      {
+        // The line fits in the specified width, so append it as-is.
+        buffer.append(line);
+      }
+      else
+      {
+        // The line doesn't fit in the specified width, so it needs to be
+        // wrapped.  Do so at space boundaries.
+        StringBuilder   lineBuffer    = new StringBuilder();
+        StringBuilder   delimBuffer   = new StringBuilder();
+        StringTokenizer wordTokenizer = new StringTokenizer(line, " ", true);
+        while (wordTokenizer.hasMoreTokens())
+        {
+          String word = wordTokenizer.nextToken();
+          if (word.equals(" "))
+          {
+            // It's a space, so add it to the delim buffer only if the line
+            // buffer is not empty.
+            if (lineBuffer.length() > 0)
+            {
+              delimBuffer.append(word);
+            }
+          }
+          else if (word.length() > width)
+          {
+            // This is a long word that can't be wrapped, so we'll just have to
+            // make do.
+            if (lineBuffer.length() > 0)
+            {
+              buffer.append(lineBuffer);
+              buffer.append("\n");
+              lineBuffer = new StringBuilder();
+            }
+            buffer.append(word);
+
+            if (wordTokenizer.hasMoreTokens())
+            {
+              // The next token must be a space, so remove it.  If there are
+              // still more tokens after that, then append an EOL.
+              wordTokenizer.nextToken();
+              if (wordTokenizer.hasMoreTokens())
+              {
+                buffer.append("\n");
+              }
+            }
+
+            if (delimBuffer.length() > 0)
+            {
+              delimBuffer = new StringBuilder();
+            }
+          }
+          else
+          {
+            // It's not a space, so see if we can fit it on the current line.
+            int newLineLength = lineBuffer.length() + delimBuffer.length() +
+            word.length();
+            if (newLineLength < width)
+            {
+              // It does fit on the line, so add it.
+              lineBuffer.append(delimBuffer).append(word);
+
+              if (delimBuffer.length() > 0)
+              {
+                delimBuffer = new StringBuilder();
+              }
+            }
+            else
+            {
+              // It doesn't fit on the line, so end the current line and start
+              // a new one.
+              buffer.append(lineBuffer);
+              buffer.append("\n");
+
+              lineBuffer = new StringBuilder();
+              lineBuffer.append(word);
+
+              if (delimBuffer.length() > 0)
+              {
+                delimBuffer = new StringBuilder();
+              }
+            }
+          }
+        }
+
+        // If there's anything left in the line buffer, then add it to the
+        // final buffer.
+        buffer.append(lineBuffer);
+      }
+    }
+    return buffer.toString();
+  }
+
+  /**
    * Inserts HTML break tags into <code>d</code> breaking it up
    * so that no line is longer than <code>maxll</code>.
    * @param d String to break

--
Gitblit v1.10.0