mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

jvergara
05.04.2008 c3898cc948028c9e125efd13c45b90ac0d105067
Fix for issue 3536 ( 	LDAP entry browser is broken in control panel when SSL or Start TLS are enabled on the server).

Handle the case where the server presents a certificate when we connect using the Start TLS (or SSL) normal LDAP port.

In some cases an LDAPInterruptedException appeared when the user selected multiple entries. This has also been fixed.
3 files modified
221 ■■■■■ changed files
opends/src/guitools/org/opends/guitools/controlpanel/ui/AbstractBrowseEntriesPanel.java 201 ●●●●● patch | view | raw | blame | history
opends/src/guitools/org/opends/guitools/controlpanel/ui/BrowseEntriesPanel.java 8 ●●●● patch | view | raw | blame | history
opends/src/guitools/org/opends/guitools/controlpanel/util/BackgroundTask.java 12 ●●●●● patch | view | raw | blame | history
opends/src/guitools/org/opends/guitools/controlpanel/ui/AbstractBrowseEntriesPanel.java
@@ -28,6 +28,8 @@
package org.opends.guitools.controlpanel.ui;
import static org.opends.messages.AdminToolMessages.*;
import static org.opends.messages.QuickSetupMessages.INFO_CERTIFICATE_EXCEPTION;
import static org.opends.messages.QuickSetupMessages.INFO_NOT_AVAILABLE_LABEL;
import java.awt.Component;
import java.awt.GridBagConstraints;
@@ -39,12 +41,16 @@
import java.awt.event.ItemListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.net.URI;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.naming.NamingException;
import javax.naming.ldap.InitialLdapContext;
@@ -68,6 +74,7 @@
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;
import org.opends.admin.ads.util.ApplicationTrustManager;
import org.opends.admin.ads.util.ConnectionUtils;
import org.opends.guitools.controlpanel.browser.BrowserController;
import org.opends.guitools.controlpanel.datamodel.BackendDescriptor;
@@ -87,6 +94,10 @@
import org.opends.guitools.controlpanel.util.Utilities;
import org.opends.messages.Message;
import org.opends.messages.MessageBuilder;
import org.opends.quicksetup.UserDataCertificateException;
import org.opends.quicksetup.ui.CertificateDialog;
import org.opends.quicksetup.util.UIKeyStore;
import org.opends.quicksetup.util.Utils;
import org.opends.server.protocols.ldap.LDAPFilter;
import org.opends.server.types.AttributeType;
import org.opends.server.types.AttributeValue;
@@ -129,6 +140,8 @@
  private JLabel lNoMatchFound;
  private InitialLdapContext createdUserDataCtx;
  /**
   * The tree pane contained in this panel.
   */
@@ -183,6 +196,9 @@
      "organizationalUnit"
  };
  private static final Logger LOG =
    Logger.getLogger(AbstractBrowseEntriesPanel.class.getName());
  /**
   * Default constructor.
   *
@@ -1188,8 +1204,7 @@
            if (getInfo().getUserDataDirContext() == null)
            {
              InitialLdapContext ctxUserData =
                Utilities.getUserDataDirContext(getInfo(),
                    ConnectionUtils.getBindDN(ctx),
                createUserDataDirContext(ConnectionUtils.getBindDN(ctx),
                    ConnectionUtils.getBindPassword(ctx));
              getInfo().setUserDataDirContext(ctxUserData);
            }
@@ -1395,6 +1410,188 @@
  }
  /**
   * Creates the context to be used to retrieve user data for some given
   * credentials.
   * @param bindDN the bind DN.
   * @param bindPassword the bind password.
   * @return the context to be used to retrieve user data for some given
   * credentials.
   * @throws NamingException if an error occurs connecting to the server.
   * @throws ConfigReadException if an error occurs reading the configuration.
   */
  private InitialLdapContext createUserDataDirContext(
      final String bindDN, final String bindPassword)
  throws NamingException, ConfigReadException
  {
    createdUserDataCtx = null;
    try
    {
      createdUserDataCtx = Utilities.getUserDataDirContext(getInfo(),
          bindDN, bindPassword);
    }
    catch (NamingException ne)
    {
      if (Utils.isCertificateException(ne))
      {
        ApplicationTrustManager.Cause cause =
          getInfo().getTrustManager().getLastRefusedCause();
        LOG.log(Level.INFO, "Certificate exception cause: "+cause);
        UserDataCertificateException.Type excType = null;
        if (cause == ApplicationTrustManager.Cause.NOT_TRUSTED)
        {
          excType = UserDataCertificateException.Type.NOT_TRUSTED;
        }
        else if (cause ==
          ApplicationTrustManager.Cause.HOST_NAME_MISMATCH)
        {
          excType = UserDataCertificateException.Type.HOST_NAME_MISMATCH;
        }
        if (excType != null)
        {
          String h;
          int p;
          try
          {
            URI uri = new URI(getInfo().getAdminConnectorURL());
            h = uri.getHost();
            p = uri.getPort();
          }
          catch (Throwable t)
          {
            LOG.log(Level.WARNING,
                "Error parsing ldap url of ldap url.", t);
            h = INFO_NOT_AVAILABLE_LABEL.get().toString();
            p = -1;
          }
          final UserDataCertificateException udce =
            new UserDataCertificateException(null,
                INFO_CERTIFICATE_EXCEPTION.get(h, String.valueOf(p)),
                ne, h, p,
                getInfo().getTrustManager().getLastRefusedChain(),
                getInfo().getTrustManager().getLastRefusedAuthType(),
                excType);
          if (SwingUtilities.isEventDispatchThread())
          {
            handleCertificateException(udce, bindDN, bindPassword);
          }
          else
          {
            final ConfigReadException[] fcre = {null};
            final NamingException[] fne = {null};
            try
            {
              SwingUtilities.invokeAndWait(new Runnable()
              {
                public void run()
                {
                  try
                  {
                    handleCertificateException(udce, bindDN, bindPassword);
                  }
                  catch (ConfigReadException cre)
                  {
                    fcre[0] = cre;
                  }
                  catch (NamingException ne)
                  {
                    fne[0] = ne;
                  }
                }
              });
            }
            catch (Throwable t)
            {
              throw new IllegalArgumentException("Unexpected error: "+t, t);
            }
            if (fcre[0] != null)
            {
              throw fcre[0];
            }
            if (fne[0] != null)
            {
              throw fne[0];
            }
          }
        }
      }
      else
      {
        throw ne;
      }
    }
    return createdUserDataCtx;
  }
  /**
   * Displays a dialog asking the user to accept a certificate if the user
   * accepts it, we update the trust manager and simulate a click on "OK" to
   * re-check the authentication.
   * This method assumes that we are being called from the event thread.
   * @param bindDN the bind DN.
   * @param bindPassword the bind password.
   */
  private void handleCertificateException(UserDataCertificateException ce,
      String bindDN, String bindPassword)
  throws NamingException, ConfigReadException
  {
    CertificateDialog dlg = new CertificateDialog(null, ce);
    dlg.pack();
    Utilities.centerGoldenMean(dlg, Utilities.getParentDialog(this));
    dlg.setVisible(true);
    if (dlg.getUserAnswer() !=
      CertificateDialog.ReturnType.NOT_ACCEPTED)
    {
      X509Certificate[] chain = ce.getChain();
      String authType = ce.getAuthType();
      String host = ce.getHost();
      if ((chain != null) && (authType != null) && (host != null))
      {
        LOG.log(Level.INFO, "Accepting certificate presented by host "+host);
        getInfo().getTrustManager().acceptCertificate(chain, authType, host);
        createdUserDataCtx = createUserDataDirContext(bindDN, bindPassword);
      }
      else
      {
        if (chain == null)
        {
          LOG.log(Level.WARNING,
              "The chain is null for the UserDataCertificateException");
        }
        if (authType == null)
        {
          LOG.log(Level.WARNING,
              "The auth type is null for the UserDataCertificateException");
        }
        if (host == null)
        {
          LOG.log(Level.WARNING,
              "The host is null for the UserDataCertificateException");
        }
      }
    }
    if (dlg.getUserAnswer() ==
      CertificateDialog.ReturnType.ACCEPTED_PERMANENTLY)
    {
      X509Certificate[] chain = ce.getChain();
      if (chain != null)
      {
        try
        {
          UIKeyStore.acceptCertificate(chain);
        }
        catch (Throwable t)
        {
          LOG.log(Level.WARNING, "Error accepting certificate: "+t, t);
        }
      }
    }
  }
  /**
   *  This class is used simply to avoid an inset on the left for the
   *  'All Base DNs' item.
   *  Since this item is a CategorizedComboBoxElement of type
opends/src/guitools/org/opends/guitools/controlpanel/ui/BrowseEntriesPanel.java
@@ -52,6 +52,7 @@
import java.util.ArrayList;
import java.util.LinkedHashSet;
import javax.naming.InterruptedNamingException;
import javax.naming.ldap.InitialLdapContext;
import javax.swing.ButtonGroup;
import javax.swing.JComponent;
@@ -522,8 +523,11 @@
      }
      catch (Throwable t)
      {
        EntryReadErrorEvent ev = new EntryReadErrorEvent(this, dn, t);
        entryPane.entryReadError(ev);
        if (!(t instanceof InterruptedNamingException))
        {
          EntryReadErrorEvent ev = new EntryReadErrorEvent(this, dn, t);
          entryPane.entryReadError(ev);
        }
      }
    }
    else
opends/src/guitools/org/opends/guitools/controlpanel/util/BackgroundTask.java
@@ -36,6 +36,7 @@
public abstract class BackgroundTask<T>
{
  private BackgroundTaskThread<T> taskThread;
  private boolean interrupted;
  /**
   * Creates a new thread and begins running the task in the background.  When
   * the task has completed, the {@code backgroundTaskCompleted} method will be
@@ -43,6 +44,7 @@
   */
  public final void startBackgroundTask()
  {
    interrupted = false;
    taskThread = new BackgroundTaskThread<T>(this);
    taskThread.start();
  }
@@ -53,6 +55,7 @@
   */
  public final void interrupt()
  {
    interrupted = true;
    if (taskThread != null)
    {
      taskThread.interrupt();
@@ -67,14 +70,7 @@
   */
  public boolean isInterrupted()
  {
    if (taskThread != null)
    {
      return taskThread.isInterrupted();
    }
    else
    {
      return false;
    }
    return interrupted;
  }
  /**