001/*
002 * CDDL HEADER START
003 *
004 * The contents of this file are subject to the terms of the
005 * Common Development and Distribution License, Version 1.0 only
006 * (the "License").  You may not use this file except in compliance
007 * with the License.
008 *
009 * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
010 * or http://forgerock.org/license/CDDLv1.0.html.
011 * See the License for the specific language governing permissions
012 * and limitations under the License.
013 *
014 * When distributing Covered Code, include this CDDL HEADER in each
015 * file and include the License file at legal-notices/CDDLv1_0.txt.
016 * If applicable, add the following below this CDDL HEADER, with the
017 * fields enclosed by brackets "[]" replaced with your own identifying
018 * information:
019 *      Portions Copyright [yyyy] [name of copyright owner]
020 *
021 * CDDL HEADER END
022 *
023 *
024 *      Copyright 2009-2010 Sun Microsystems, Inc.
025 *      Portions Copyright 2011-2015 ForgeRock AS
026 */
027
028package org.opends.guitools.controlpanel.ui;
029
030import java.awt.Component;
031import java.awt.GridBagConstraints;
032import java.awt.event.ActionEvent;
033import java.awt.event.ActionListener;
034import java.io.File;
035import java.io.IOException;
036import java.net.URI;
037import java.security.cert.X509Certificate;
038import java.util.ArrayList;
039import java.util.Iterator;
040import java.util.LinkedHashSet;
041
042import javax.naming.NamingEnumeration;
043import javax.naming.NamingException;
044import javax.naming.directory.SearchControls;
045import javax.naming.directory.SearchResult;
046import javax.naming.ldap.InitialLdapContext;
047import javax.swing.Box;
048import javax.swing.DefaultComboBoxModel;
049import javax.swing.JComboBox;
050import javax.swing.JEditorPane;
051import javax.swing.JLabel;
052import javax.swing.JPasswordField;
053import javax.swing.JTextField;
054import javax.swing.SwingUtilities;
055
056import org.forgerock.i18n.LocalizableMessage;
057import org.forgerock.i18n.slf4j.LocalizedLogger;
058import org.opends.admin.ads.ServerDescriptor;
059import org.opends.admin.ads.util.ApplicationTrustManager;
060import org.opends.admin.ads.util.ConnectionUtils;
061import org.opends.guitools.controlpanel.ControlPanelArgumentParser;
062import org.opends.guitools.controlpanel.datamodel.ConfigReadException;
063import org.opends.guitools.controlpanel.datamodel.CustomSearchResult;
064import org.opends.guitools.controlpanel.event.ConfigurationChangeEvent;
065import org.opends.guitools.controlpanel.task.OnlineUpdateException;
066import org.opends.guitools.controlpanel.util.BackgroundTask;
067import org.opends.guitools.controlpanel.util.Utilities;
068import org.opends.quicksetup.Installation;
069import org.opends.quicksetup.UserData;
070import org.opends.quicksetup.UserDataCertificateException;
071import org.opends.quicksetup.ui.CertificateDialog;
072import org.opends.quicksetup.util.UIKeyStore;
073import org.opends.quicksetup.util.Utils;
074import org.opends.server.monitors.VersionMonitorProvider;
075import org.opends.server.types.DN;
076import org.opends.server.types.OpenDsException;
077import org.opends.server.util.DynamicConstants;
078import org.opends.server.util.StaticUtils;
079
080import static com.forgerock.opendj.cli.Utils.*;
081
082import static org.opends.admin.ads.util.ConnectionUtils.*;
083import static org.opends.guitools.controlpanel.util.Utilities.*;
084import static org.opends.messages.AdminToolMessages.*;
085import static org.opends.messages.QuickSetupMessages.*;
086import static org.opends.server.monitors.VersionMonitorProvider.*;
087
088/**
089 * The panel that appears when the user is asked to provide authentication.
090 */
091public class LocalOrRemotePanel extends StatusGenericPanel
092{
093
094  private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
095  private static final long serialVersionUID = 5051556513294844797L;
096
097  private JComboBox combo;
098  private JLabel portLabel;
099  private JTextField hostName;
100  private JTextField port;
101  private JPasswordField pwd;
102  private JTextField dn;
103  private JLabel pwdLabel;
104  private JLabel dnLabel;
105  private String usedUrl;
106  private JLabel localInstallLabel;
107  private JEditorPane localInstall;
108  private JLabel localNotRunning;
109  private boolean isLocalServerRunning;
110  private boolean callOKWhenVisible;
111
112  /** Default constructor. */
113  public LocalOrRemotePanel()
114  {
115    super();
116    createLayout();
117  }
118
119  /** {@inheritDoc} */
120  @Override
121  public LocalizableMessage getTitle()
122  {
123    return INFO_CTRL_PANEL_LOCAL_OR_REMOTE_PANEL_TITLE.get();
124  }
125
126  /** {@inheritDoc} */
127  @Override
128  public GenericDialog.ButtonType getButtonType()
129  {
130    return GenericDialog.ButtonType.OK_CANCEL;
131  }
132
133  /**
134   * Returns the displayed host name.
135   * @return the displayed host name.
136   */
137  public String getHostName()
138  {
139    return hostName.getText();
140  }
141
142  /**
143   * Returns the displayed administration port.
144   * @return the displayed administration port.
145   */
146  public int getPort()
147  {
148    try
149    {
150      return Integer.valueOf(this.port.getText().trim());
151    }
152    catch (Exception ignored)
153    {
154      return -1;
155    }
156  }
157
158  /**
159   * Returns the displayed bind DN.
160   * @return the displayed bind DN.
161   */
162  public String getBindDN()
163  {
164    return dn.getText();
165  }
166
167  /**
168   * Returns the displayed password.
169   * @return the displayed password.
170   */
171  public char[] getBindPassword()
172  {
173    return pwd.getPassword();
174  }
175
176  /**
177   * Returns whether the panel displays the remote or the local server.
178   * @return whether the panel displays the remote or the local server.
179   */
180  public boolean isRemote()
181  {
182    int index = combo.getSelectedIndex();
183    return index == 1;
184  }
185
186  /**
187   * Sets the displayed host name.
188   * @param hostName the host name.
189   */
190  public void setHostName(String hostName)
191  {
192    this.hostName.setText(hostName);
193  }
194
195  /**
196   * Sets the displayed administration port.
197   * @param port the displayed administration port.
198   */
199  public void setPort(int port)
200  {
201    this.port.setText(String.valueOf(port));
202  }
203
204  /**
205   * Sets the displayed bind DN.
206   * @param bindDN the displayed bind DN.
207   */
208  public void setBindDN(String bindDN)
209  {
210    this.dn.setText(bindDN);
211  }
212
213  /**
214   * Sets the displayed password.
215   * @param pwd the password.
216   */
217  public void setBindPassword(char[] pwd)
218  {
219    this.pwd.setText(new String(pwd));
220  }
221
222  /**
223   * Sets whether the panel should display the remote or the local server.
224   * @param remote whether the panel should display the remote or the local
225   * server.
226   */
227  public void setRemote(boolean remote)
228  {
229    int index = remote ? 1 : 0;
230    combo.setSelectedIndex(index);
231    updateComponentState();
232  }
233
234  /**
235   * Method to be called when we want the panel to call automatically okClicked
236   * method when the panel is made visible.
237   * @param callOKWhenVisible whether okClicked must be called automatically
238   * when the panel is made visible or not.
239   */
240  public void setCallOKWhenVisible(boolean callOKWhenVisible)
241  {
242    this.callOKWhenVisible = callOKWhenVisible;
243  }
244
245  /**
246   * Returns whether okClicked must be called automatically when the panel is
247   * made visible or not.
248   * @return whether okClicked must be called automatically when the panel is
249   * made visible or not.
250   */
251  public boolean isCallOKWhenVisible()
252  {
253    return callOKWhenVisible;
254  }
255
256  /**
257   * Creates the layout of the panel (but the contents are not populated here).
258   */
259  private void createLayout()
260  {
261    GridBagConstraints gbc = new GridBagConstraints();
262
263    gbc.anchor = GridBagConstraints.WEST;
264    gbc.gridx = 0;
265    gbc.gridy = 0;
266
267    gbc.weightx = 0.0;
268    gbc.weighty = 0.0;
269    String localServerInstallPath;
270    File instancePath = Installation.getLocal().getInstanceDirectory();
271    try
272    {
273      localServerInstallPath = instancePath.getCanonicalPath();
274    }
275    catch (IOException ioe)
276    {
277      localServerInstallPath = instancePath.getAbsolutePath();
278    }
279    combo = Utilities.createComboBox();
280    combo.setModel(new DefaultComboBoxModel(
281        new Object[] {INFO_CTRL_PANEL_LOCAL_SERVER.get(),
282            INFO_CTRL_PANEL_REMOTE_SERVER.get()}));
283    combo.setSelectedIndex(0);
284    gbc.gridwidth = 2;
285    JLabel l = Utilities.createDefaultLabel(
286        INFO_CTRL_PANEL_LOCAL_OR_REMOTE.get());
287    add(l, gbc);
288    gbc.gridwidth = 1;
289    gbc.insets.top = 10;
290    gbc.gridy ++;
291    add(combo, gbc);
292    l.setLabelFor(combo);
293    gbc.gridx = 1;
294
295    localNotRunning = Utilities.createDefaultLabel();
296    Utilities.setWarningLabel(localNotRunning,
297        INFO_CTRL_PANEL_LOCAL_SERVER_NOT_RUNNING.get());
298    gbc.insets.left = 10;
299    add(localNotRunning, gbc);
300    localNotRunning.setFocusable(true);
301    hostName = Utilities.createMediumTextField();
302    hostName.setText(UserData.getDefaultHostName());
303    hostName.setToolTipText(
304        INFO_CTRL_PANEL_REMOTE_SERVER_TOOLTIP.get().toString());
305    add(hostName, gbc);
306    gbc.insets.top = 10;
307    gbc.gridy ++;
308    gbc.insets.left = 0;
309    gbc.weightx = 0.0;
310    gbc.insets.right = 0;
311    gbc.gridx = 0;
312
313    ActionListener actionListener = new ActionListener()
314    {
315      @Override
316      public void actionPerformed(ActionEvent ev)
317      {
318        updateComponentState();
319      }
320    };
321    combo.addActionListener(actionListener);
322
323    gbc.gridx = 0;
324    gbc.gridwidth = 1;
325
326
327    localInstallLabel = Utilities.createPrimaryLabel(
328        INFO_CTRL_PANEL_INSTANCE_PATH_LABEL.get());
329    gbc.insets.left = 0;
330    add(localInstallLabel, gbc);
331    gbc.gridx = 1;
332    gbc.insets.left = 10;
333    gbc.fill = GridBagConstraints.HORIZONTAL;
334    gbc.weightx = 0.1;
335    localInstall = Utilities.makeHtmlPane(localServerInstallPath,
336        ColorAndFontConstants.defaultFont);
337    add(localInstall, gbc);
338    localInstallLabel.setLabelFor(localInstall);
339    gbc.gridx ++;
340    gbc.weightx = 1.0;
341    gbc.insets.left = 0;
342    add(Box.createHorizontalGlue(), gbc);
343
344    gbc.gridy ++;
345    gbc.insets.top = 10;
346    gbc.insets.left = 0;
347    gbc.gridx = 0;
348    gbc.weightx = 0.0;
349    portLabel = Utilities.createPrimaryLabel(
350        INFO_CTRL_PANEL_ADMINISTRATION_PORT.get());
351    add(portLabel, gbc);
352    gbc.gridx = 1;
353    gbc.insets.left = 10;
354    port = Utilities.createMediumTextField();
355    port.setText(String.valueOf(
356        ControlPanelArgumentParser.getDefaultAdministrationPort()));
357    gbc.weightx = 1.0;
358    gbc.fill = GridBagConstraints.HORIZONTAL;
359    add(port, gbc);
360    portLabel.setLabelFor(port);
361
362    gbc.gridy ++;
363    gbc.gridx = 0;
364    gbc.weightx = 0.0;
365    gbc.fill = GridBagConstraints.NONE;
366    gbc.insets.left = 0;
367    dnLabel = Utilities.createPrimaryLabel(INFO_CTRL_PANEL_BIND_DN_LABEL.get());
368    add(dnLabel, gbc);
369    gbc.insets.left = 10;
370    gbc.gridx = 1;
371    dn = Utilities.createTextField(
372        ControlPanelArgumentParser.getDefaultBindDN(), 20);
373    gbc.weightx = 1.0;
374    gbc.fill = GridBagConstraints.HORIZONTAL;
375    gbc.insets.left = 10;
376    add(dn, gbc);
377    dnLabel.setLabelFor(dn);
378    gbc.insets.top = 10;
379    gbc.insets.left = 0;
380
381    gbc.gridx = 0;
382    gbc.gridy ++;
383    gbc.weightx = 0.0;
384    gbc.fill = GridBagConstraints.NONE;
385    pwdLabel = Utilities.createPrimaryLabel(
386        INFO_CTRL_PANEL_BIND_PASSWORD_LABEL.get());
387    gbc.insets.left = 0;
388    add(pwdLabel, gbc);
389    gbc.insets.left = 10;
390    gbc.gridx = 1;
391    pwd = Utilities.createPasswordField();
392    gbc.weightx = 1.0;
393    gbc.fill = GridBagConstraints.HORIZONTAL;
394    add(pwd, gbc);
395    pwdLabel.setLabelFor(pwd);
396
397    addBottomGlue(gbc);
398  }
399
400  /** {@inheritDoc} */
401  @Override
402  public Component getPreferredFocusComponent()
403  {
404    if (pwd.isVisible())
405    {
406      return pwd;
407    }
408    return combo;
409  }
410
411  /** {@inheritDoc} */
412  @Override
413  public void configurationChanged(ConfigurationChangeEvent ev)
414  {
415  }
416
417  /** {@inheritDoc} */
418  @Override
419  public void toBeDisplayed(boolean visible)
420  {
421    super.toBeDisplayed(visible);
422    if (visible)
423    {
424      // Do it outside the event thread if the panel requires it.
425      BackgroundTask<Void> worker = new BackgroundTask<Void>()
426      {
427        @Override
428        public Void processBackgroundTask() throws Throwable
429        {
430          StaticUtils.sleep(200);
431          File instancePath = Installation.getLocal().getInstanceDirectory();
432          isLocalServerRunning = Utilities.isServerRunning(instancePath);
433          return null;
434        }
435
436
437        @Override
438        public void backgroundTaskCompleted(Void returnValue,
439            Throwable t)
440        {
441          updateComponentState();
442          displayMainPanel();
443          Component comp = getPreferredFocusComponent();
444          if (comp != null)
445          {
446            comp.requestFocusInWindow();
447          }
448          if (isCallOKWhenVisible())
449          {
450            okClicked();
451          }
452        }
453      };
454      displayMessage(INFO_CTRL_PANEL_LOADING_PANEL_SUMMARY.get());
455      worker.startBackgroundTask();
456      if (!isCallOKWhenVisible())
457      {
458        pwd.setText("");
459      }
460    }
461  }
462
463  /** {@inheritDoc} */
464  @Override
465  public void okClicked()
466  {
467    setPrimaryValid(portLabel);
468    setPrimaryValid(dnLabel);
469    setPrimaryValid(pwdLabel);
470    final LinkedHashSet<LocalizableMessage> errors = new LinkedHashSet<>();
471
472    boolean dnInvalid = false;
473    boolean pwdInvalid = false;
474
475    final boolean isLocal = combo.getSelectedIndex() == 0;
476
477    boolean doChecks = !isLocal || isLocalServerRunning;
478    if (doChecks)
479    {
480      if ("".equals(dn.getText().trim()))
481      {
482        dnInvalid = true;
483        errors.add(INFO_EMPTY_DIRECTORY_MANAGER_DN.get());
484      }
485      else if (!isDN(dn.getText()))
486      {
487        dnInvalid = true;
488        errors.add(INFO_NOT_A_DIRECTORY_MANAGER_DN.get());
489      }
490
491      if (pwd.getPassword().length == 0)
492      {
493        pwdInvalid = true;
494        errors.add(INFO_EMPTY_PWD.get());
495      }
496      if (dnInvalid)
497      {
498        setPrimaryInvalid(dnLabel);
499      }
500
501      if (pwdInvalid)
502      {
503        setPrimaryInvalid(pwdLabel);
504      }
505
506      if (!isLocal)
507      {
508        if ("".equals(hostName.getText().trim()))
509        {
510          errors.add(INFO_EMPTY_REMOTE_HOST_NAME.get());
511        }
512
513        try
514        {
515          int p = Integer.parseInt(port.getText());
516          if (p <= 0 || p > 65535)
517          {
518            errors.add(INFO_INVALID_REMOTE_SERVER_PORT.get(0, 65535));
519          }
520        }
521        catch (Throwable t)
522        {
523          errors.add(INFO_INVALID_REMOTE_SERVER_PORT.get(0, 65535));
524        }
525      }
526    }
527
528    if (errors.isEmpty())
529    {
530      setEnabledOK(false);
531      displayMessage(INFO_CTRL_PANEL_VERIFYING_AUTHENTICATION_SUMMARY.get());
532
533      BackgroundTask<InitialLdapContext> worker =
534        new BackgroundTask<InitialLdapContext>()
535      {
536        /** {@inheritDoc} */
537        @Override
538        public InitialLdapContext processBackgroundTask() throws Throwable
539        {
540          getInfo().stopPooling();
541          if (isLocal)
542          {
543            // At least load the local information.
544            SwingUtilities.invokeLater(new Runnable()
545            {
546              @Override
547              public void run()
548              {
549                displayMessage(
550                    INFO_CTRL_PANEL_READING_CONFIGURATION_SUMMARY.get());
551              }
552            });
553            if (getInfo().isLocal() != isLocal)
554            {
555              closeInfoConnections();
556            }
557            getInfo().setIsLocal(isLocal);
558            getInfo().regenerateDescriptor();
559            if (!isLocalServerRunning)
560            {
561              return null;
562            }
563          }
564          InitialLdapContext ctx = null;
565          try
566          {
567            if (isLocal)
568            {
569              usedUrl = getInfo().getAdminConnectorURL();
570              ctx = Utilities.getAdminDirContext(getInfo(), dn.getText(),
571                  String.valueOf(pwd.getPassword()));
572            }
573            else
574            {
575              usedUrl = ConnectionUtils.getLDAPUrl(hostName.getText().trim(),
576                  Integer.valueOf(port.getText().trim()), true);
577              ctx = createLdapsContext(usedUrl, dn.getText(),
578                  String.valueOf(pwd.getPassword()),
579                  getInfo().getConnectTimeout(), null,
580                  getInfo().getTrustManager(), null);
581              checkVersion(ctx);
582            }
583
584            StaticUtils.sleep(500);
585            SwingUtilities.invokeLater(new Runnable()
586            {
587              @Override
588              public void run()
589              {
590                displayMessage(INFO_CTRL_PANEL_READING_CONFIGURATION_SUMMARY.get());
591              }
592            });
593            closeInfoConnections();
594            getInfo().setIsLocal(isLocal);
595            getInfo().setDirContext(ctx);
596            getInfo().setUserDataDirContext(null);
597            getInfo().regenerateDescriptor();
598            return ctx;
599          } catch (Throwable t)
600          {
601            StaticUtils.close(ctx);
602            throw t;
603          }
604        }
605
606        /** {@inheritDoc} */
607        @Override
608        public void backgroundTaskCompleted(InitialLdapContext ctx,
609            Throwable throwable)
610        {
611          boolean handleCertificateException = false;
612          boolean localServerErrorConnecting = false;
613
614          if (throwable != null)
615          {
616            logger.info(LocalizableMessage.raw("Error connecting: " + throwable, throwable));
617
618            if (isVersionException(throwable))
619            {
620              errors.add(((OpenDsException)throwable).getMessageObject());
621            }
622            else if (isCertificateException(throwable))
623            {
624              ApplicationTrustManager.Cause cause =
625                getInfo().getTrustManager().getLastRefusedCause();
626
627              logger.info(LocalizableMessage.raw("Certificate exception cause: "+cause));
628              UserDataCertificateException.Type excType = null;
629              if (cause == ApplicationTrustManager.Cause.NOT_TRUSTED)
630              {
631                excType = UserDataCertificateException.Type.NOT_TRUSTED;
632              }
633              else if (cause ==
634                ApplicationTrustManager.Cause.HOST_NAME_MISMATCH)
635              {
636                excType = UserDataCertificateException.Type.HOST_NAME_MISMATCH;
637              }
638              else
639              {
640                LocalizableMessage msg = getThrowableMsg(
641                    INFO_ERROR_CONNECTING_TO_LOCAL.get(), throwable);
642                errors.add(msg);
643              }
644
645              if (excType != null)
646              {
647                String h;
648                int p;
649                try
650                {
651                  URI uri = new URI(usedUrl);
652                  h = uri.getHost();
653                  p = uri.getPort();
654                }
655                catch (Throwable t)
656                {
657                  logger.warn(LocalizableMessage.raw(
658                      "Error parsing ldap url of ldap url.", t));
659                  h = INFO_NOT_AVAILABLE_LABEL.get().toString();
660                  p = -1;
661                }
662                UserDataCertificateException udce =
663                  new UserDataCertificateException(null,
664                      INFO_CERTIFICATE_EXCEPTION.get(h, p),
665                      throwable, h, p,
666                      getInfo().getTrustManager().getLastRefusedChain(),
667                      getInfo().getTrustManager().getLastRefusedAuthType(),
668                      excType);
669
670                handleCertificateException(udce);
671                handleCertificateException = true;
672              }
673            }
674            else if (throwable instanceof NamingException)
675            {
676              boolean found = false;
677              String providedDn = dn.getText();
678              if (isLocal)
679              {
680                Iterator<DN> it = getInfo().getServerDescriptor().
681                getAdministrativeUsers().iterator();
682                while (it.hasNext() && !found)
683                {
684                  found = Utils.areDnsEqual(providedDn, it.next().toString());
685                }
686                if (!found)
687                {
688                  errors.add(INFO_NOT_A_DIRECTORY_MANAGER_IN_CONFIG.get());
689                }
690                else
691                {
692                  errors.add(Utils.getMessageForException(
693                      (NamingException)throwable));
694                }
695                localServerErrorConnecting = true;
696              }
697              else
698              {
699                String hostPort = ServerDescriptor.getServerRepresentation(
700                    hostName.getText().trim(),
701                    Integer.valueOf(port.getText().trim()));
702                NamingException ne = (NamingException)throwable;
703                errors.add(getMessageForException(ne, hostPort));
704                setPrimaryInvalid(portLabel);
705              }
706              setPrimaryInvalid(dnLabel);
707              setPrimaryInvalid(pwdLabel);
708            }
709            else if (throwable instanceof ConfigReadException)
710            {
711              logger.warn(LocalizableMessage.raw(
712                  "Error reading configuration: "+throwable, throwable));
713              errors.add(((ConfigReadException)throwable).getMessageObject());
714            }
715            else
716            {
717              // This is a bug
718              logger.error(LocalizableMessage.raw(
719                  "Unexpected error: "+throwable, throwable));
720              errors.add(getThrowableMsg(INFO_BUG_MSG.get(), throwable));
721            }
722          }
723          displayMainPanel();
724          setEnabledOK(true);
725          if (!errors.isEmpty())
726          {
727            if (!localServerErrorConnecting)
728            {
729              displayErrorDialog(errors);
730            }
731            else
732            {
733              ArrayList<String> stringErrors = new ArrayList<>();
734              for (LocalizableMessage err : errors)
735              {
736                stringErrors.add(err.toString());
737              }
738              String msg = Utilities.getStringFromCollection(stringErrors,
739                  "<br>");
740              if (displayConfirmationDialog(
741                  INFO_CTRL_PANEL_CONFIRMATION_REQUIRED_SUMMARY.get(),
742                  INFO_CTRL_PANEL_ERROR_CONNECTING_TO_LOCAL.get(msg)))
743              {
744                Utilities.getParentDialog(
745                    LocalOrRemotePanel.this).setVisible(false);
746              }
747            }
748            pwd.setSelectionStart(0);
749            pwd.setSelectionEnd(pwd.getPassword().length);
750            pwd.requestFocusInWindow();
751          }
752          else if (!handleCertificateException)
753          {
754            Utilities.getParentDialog(
755                LocalOrRemotePanel.this).setVisible(false);
756          }
757
758          if (!handleCertificateException)
759          {
760            startPooling();
761          }
762        }
763      };
764      worker.startBackgroundTask();
765    }
766    else
767    {
768      displayErrorDialog(errors);
769      if (dnInvalid)
770      {
771        dn.setSelectionStart(0);
772        dn.setSelectionEnd(dn.getText().length());
773        dn.requestFocusInWindow();
774      }
775      if (pwdInvalid)
776      {
777        pwd.setSelectionStart(0);
778        pwd.setSelectionEnd(pwd.getPassword().length);
779        pwd.requestFocusInWindow();
780      }
781    }
782  }
783
784  /** {@inheritDoc} */
785  @Override
786  public void cancelClicked()
787  {
788    setPrimaryValid(dnLabel);
789    setPrimaryValid(pwdLabel);
790    setPrimaryValid(portLabel);
791    pwd.setText(null);
792    super.cancelClicked();
793  }
794
795  /**
796   * Displays a dialog asking the user to accept a certificate if the user
797   * accepts it, we update the trust manager and simulate a click on "OK" to
798   * re-check the authentication.
799   * This method assumes that we are being called from the event thread.
800   */
801  private void handleCertificateException(UserDataCertificateException ce)
802  {
803    CertificateDialog dlg = new CertificateDialog(null, ce);
804    dlg.pack();
805    Utilities.centerGoldenMean(dlg, Utilities.getParentDialog(this));
806    dlg.setVisible(true);
807    if (dlg.getUserAnswer() !=
808      CertificateDialog.ReturnType.NOT_ACCEPTED)
809    {
810      X509Certificate[] chain = ce.getChain();
811      String authType = ce.getAuthType();
812      String host = ce.getHost();
813
814      if (chain != null && authType != null && host != null)
815      {
816        logger.info(LocalizableMessage.raw("Accepting certificate presented by host "+host));
817        getInfo().getTrustManager().acceptCertificate(chain, authType, host);
818        /* Simulate a click on the OK by calling in the okClicked method. */
819        SwingUtilities.invokeLater(new Runnable()
820        {
821          @Override
822          public void run()
823          {
824            okClicked();
825          }
826        });
827      }
828      else
829      {
830        if (chain == null)
831        {
832          logger.warn(LocalizableMessage.raw(
833              "The chain is null for the UserDataCertificateException"));
834        }
835        if (authType == null)
836        {
837          logger.warn(LocalizableMessage.raw(
838              "The auth type is null for the UserDataCertificateException"));
839        }
840        if (host == null)
841        {
842          logger.warn(LocalizableMessage.raw(
843              "The host is null for the UserDataCertificateException"));
844        }
845      }
846    }
847    if (dlg.getUserAnswer() ==
848      CertificateDialog.ReturnType.ACCEPTED_PERMANENTLY)
849    {
850      X509Certificate[] chain = ce.getChain();
851      if (chain != null)
852      {
853        try
854        {
855          UIKeyStore.acceptCertificate(chain);
856        }
857        catch (Throwable t)
858        {
859          logger.warn(LocalizableMessage.raw("Error accepting certificate: "+t, t));
860        }
861      }
862    }
863  }
864
865  private void updateComponentState()
866  {
867    boolean isLocal = combo.getSelectedIndex() == 0;
868    hostName.setVisible(!isLocal);
869    port.setVisible(!isLocal);
870    portLabel.setVisible(!isLocal);
871    localInstall.setVisible(isLocal);
872    localInstallLabel.setVisible(isLocal);
873
874    boolean displayAuthentication = !isLocal || isLocalServerRunning;
875    dn.setVisible(displayAuthentication);
876    dnLabel.setVisible(displayAuthentication);
877    pwd.setVisible(displayAuthentication);
878    pwdLabel.setVisible(displayAuthentication);
879
880    localNotRunning.setVisible(isLocal && !isLocalServerRunning);
881  }
882
883  private void startPooling()
884  {
885    // The server descriptor has been already retrieved.
886    // startPooling tries to retrieve immediately the server descriptor, so
887    // sleep the pooling period before calling it.
888    Thread t = new Thread(new Runnable()
889    {
890      @Override
891      public void run()
892      {
893        StaticUtils.sleep(getInfo().getPoolingPeriod());
894        getInfo().startPooling();
895      }
896    });
897    t.start();
898  }
899
900  private void checkVersion(InitialLdapContext ctx) throws OpenDsException
901  {
902    LocalizableMessage msg = null;
903    try
904    {
905      // Search for the version on the remote server.
906      SearchControls searchControls = new SearchControls();
907      searchControls.setSearchScope(
908      SearchControls.OBJECT_SCOPE);
909      searchControls.setReturningAttributes(
910      new String[] {
911          VersionMonitorProvider.ATTR_PRODUCT_NAME,
912          VersionMonitorProvider.ATTR_MAJOR_VERSION,
913          VersionMonitorProvider.ATTR_POINT_VERSION,
914          VersionMonitorProvider.ATTR_MINOR_VERSION
915          });
916      NamingEnumeration<SearchResult> en =
917        ctx.search("cn=Version,cn=monitor", "objectclass=*", searchControls);
918      SearchResult sr = null;
919      try
920      {
921        while (en.hasMore())
922        {
923          sr = en.next();
924        }
925      }
926      finally
927      {
928        en.close();
929      }
930
931      CustomSearchResult csr = new CustomSearchResult(sr, "cn=Version,cn=monitor");
932
933      String hostName = ConnectionUtils.getHostName(ctx);
934
935      String productName = String.valueOf(getFirstValueAsString(csr, ATTR_PRODUCT_NAME));
936      String major = String.valueOf(getFirstValueAsString(csr, ATTR_MAJOR_VERSION));
937      String point = String.valueOf(getFirstValueAsString(csr, ATTR_POINT_VERSION));
938      String minor = String.valueOf(getFirstValueAsString(csr, ATTR_MINOR_VERSION));
939      // Be strict, control panel is only compatible with exactly the same version
940      if (!productName.equalsIgnoreCase(DynamicConstants.PRODUCT_NAME))
941      {
942        msg = ERR_NOT_SAME_PRODUCT_IN_REMOTE_SERVER_NOT_FOUND.get(hostName,
943            productName, DynamicConstants.PRODUCT_NAME);
944      }
945      else if (!String.valueOf(DynamicConstants.MAJOR_VERSION).equals(major)
946          || !String.valueOf(DynamicConstants.MINOR_VERSION).equals(minor)
947          || !String.valueOf(DynamicConstants.POINT_VERSION).equals(point))
948      {
949        msg = ERR_INCOMPATIBLE_VERSION_IN_REMOTE_SERVER.get(hostName,
950            major, minor, point, DynamicConstants.MAJOR_VERSION,
951            DynamicConstants.MINOR_VERSION, DynamicConstants.POINT_VERSION);
952      }
953    }
954    catch (Throwable t)
955    {
956      msg = ERR_VERSION_IN_REMOTE_SERVER_NOT_FOUND.get();
957    }
958    if (msg != null)
959    {
960      throw new OnlineUpdateException(msg, null);
961    }
962  }
963
964  private boolean isVersionException(Throwable t)
965  {
966    if (t instanceof OpenDsException)
967    {
968      OpenDsException oe = (OpenDsException)t;
969      if (oe.getMessageObject() != null)
970      {
971        LocalizableMessage msg = oe.getMessageObject();
972        if (StaticUtils.hasDescriptor(msg, ERR_INCOMPATIBLE_VERSION_IN_REMOTE_SERVER) ||
973            StaticUtils.hasDescriptor(msg, ERR_VERSION_IN_REMOTE_SERVER_NOT_FOUND) ||
974            StaticUtils.hasDescriptor(msg, ERR_NOT_SAME_PRODUCT_IN_REMOTE_SERVER_NOT_FOUND))
975        {
976          return true;
977        }
978      }
979    }
980    return false;
981  }
982
983  private void closeInfoConnections()
984  {
985    StaticUtils.close(getInfo().getDirContext(), getInfo().getUserDataDirContext());
986  }
987}