001/*
002 * The contents of this file are subject to the terms of the Common Development and
003 * Distribution License (the License). You may not use this file except in compliance with the
004 * License.
005 *
006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
007 * specific language governing permission and limitations under the License.
008 *
009 * When distributing Covered Software, include this CDDL Header Notice in each file and include
010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
011 * Header, with the fields enclosed by brackets [] replaced by your own identifying
012 * information: "Portions Copyright [year] [name of copyright owner]".
013 *
014 * Copyright 2008-2009 Sun Microsystems, Inc.
015 * Portions Copyright 2013-2016 ForgeRock AS.
016 */
017package org.opends.quicksetup.ui;
018
019import static org.opends.messages.QuickSetupMessages.*;
020
021import java.awt.CardLayout;
022import java.awt.Component;
023import java.awt.Dimension;
024import java.awt.GridBagConstraints;
025import java.awt.GridBagLayout;
026import java.awt.event.ActionEvent;
027import java.awt.event.ActionListener;
028import java.awt.event.WindowAdapter;
029import java.awt.event.WindowEvent;
030import java.security.MessageDigest;
031import java.security.NoSuchAlgorithmException;
032import java.security.cert.CertificateEncodingException;
033import java.security.cert.X509Certificate;
034import java.text.DateFormat;
035import java.util.Date;
036import java.util.HashMap;
037import java.util.Map;
038
039import javax.naming.ldap.LdapName;
040import javax.naming.ldap.Rdn;
041import javax.swing.Box;
042import javax.swing.JButton;
043import javax.swing.JComboBox;
044import javax.swing.JComponent;
045import javax.swing.JDialog;
046import javax.swing.JEditorPane;
047import javax.swing.JFrame;
048import javax.swing.JLabel;
049import javax.swing.JPanel;
050import javax.swing.JScrollPane;
051import javax.swing.border.EmptyBorder;
052import javax.swing.event.HyperlinkEvent;
053import javax.swing.event.HyperlinkListener;
054
055import org.forgerock.i18n.LocalizableMessage;
056import org.forgerock.i18n.LocalizableMessageBuilder;
057import org.forgerock.i18n.slf4j.LocalizedLogger;
058import org.opends.quicksetup.UserDataCertificateException;
059import org.opends.quicksetup.event.MinimumSizeComponentListener;
060
061/**
062 * This class is used to present the user a certificate to the user in order
063 * it to be accepted.
064 */
065public class CertificateDialog extends JDialog implements HyperlinkListener
066{
067  /**
068   * The enumeration that defines the different answers that the user can
069   * provide for this dialog.
070   */
071  public enum ReturnType
072  {
073    /** The user did not accept the certificate. */
074    NOT_ACCEPTED,
075    /** The user accepted the certificate only for this session. */
076    ACCEPTED_FOR_SESSION,
077    /** The user accepted the certificate permanently. */
078    ACCEPTED_PERMANENTLY
079  }
080  private static final long serialVersionUID = -8989965057591475064L;
081  private ReturnType returnValue = ReturnType.NOT_ACCEPTED;
082  private final UserDataCertificateException ce;
083  private JButton doNotAcceptButton;
084  private JComponent certificateDetails;
085  private JEditorPane explanationPane;
086  private boolean detailsAlreadyClicked;
087  private String explanationWithHideDetails;
088  private String explanationWithShowDetails;
089
090  private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
091
092  /**
093   * Constructor of the certificate dialog.
094   * @param parent the parent frame for this dialog.
095   * @param ce the UserDataCertificateException we use to get the information
096   * about the certificate that was presented and the reason why it was
097   * rejected.
098   */
099  public CertificateDialog(JFrame parent, UserDataCertificateException ce)
100  {
101    super(parent);
102    this.ce = ce;
103    setTitle(INFO_CERTIFICATE_DIALOG_TITLE.get().toString());
104    getContentPane().add(createPanel());
105    setModal(true);
106    pack();
107    if (parent != null
108        && getPreferredSize().width > parent.getWidth())
109    {
110      setPreferredSize(new Dimension(Math.max(parent.getWidth() - 20, 600),
111          getPreferredSize().height));
112    }
113    pack();
114    int minWidth = (int) getPreferredSize().getWidth();
115    int minHeight = (int) getPreferredSize().getHeight();
116    addComponentListener(new MinimumSizeComponentListener(this, minWidth,
117        minHeight));
118    getRootPane().setDefaultButton(doNotAcceptButton);
119
120    addWindowListener(new WindowAdapter()
121    {
122      @Override
123      public void windowClosing(WindowEvent e)
124      {
125        doNotAccept();
126      }
127    });
128    setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
129
130    Utilities.centerOnComponent(this, parent);
131  }
132
133  /**
134   * Wheter the user accepted the certificate or not.
135   * @return the ReturnType object defining what the user chose to do with the
136   * certificate.
137   */
138  public ReturnType getUserAnswer()
139  {
140    return returnValue;
141  }
142
143  /**
144   * Implements HyperlinkListener.  When the user clicks on a link we assume
145   * that is the show details/hide details and we update the visible components
146   * accordingly.
147   *
148   * @param e the HyperlinkEvent.
149   */
150  @Override
151  public void hyperlinkUpdate(HyperlinkEvent e)
152  {
153    if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED)
154    {
155      boolean detailsVisible = !certificateDetails.isVisible();
156      explanationPane.setText(detailsVisible?
157          explanationWithHideDetails:explanationWithShowDetails);
158      certificateDetails.setVisible(detailsVisible);
159      if (detailsVisible && !detailsAlreadyClicked)
160      {
161        detailsAlreadyClicked = true;
162        pack();
163      }
164    }
165  }
166
167  /**
168   * Creates and returns the panel of the dialog.
169   * @return the panel of the dialog.
170   */
171  private JPanel createPanel()
172  {
173    GridBagConstraints gbc = new GridBagConstraints();
174
175    JPanel contentPanel = new JPanel(new GridBagLayout());
176    contentPanel.setBackground(UIFactory.DEFAULT_BACKGROUND);
177    gbc.anchor = GridBagConstraints.NORTHWEST;
178    gbc.insets = UIFactory.getEmptyInsets();
179    gbc.fill = GridBagConstraints.BOTH;
180    gbc.gridwidth = GridBagConstraints.REMAINDER;
181    gbc.weightx = 1.0;
182
183    JPanel topPanel = new JPanel(new GridBagLayout());
184    topPanel.setBorder(UIFactory.DIALOG_PANEL_BORDER);
185    topPanel.setBackground(UIFactory.CURRENT_STEP_PANEL_BACKGROUND);
186
187    gbc.weighty = 0.0;
188    gbc.insets = UIFactory.getCurrentStepPanelInsets();
189    topPanel.add(createTitlePanel(), gbc);
190    gbc.insets.top = UIFactory.TOP_INSET_INSTRUCTIONS_SUBPANEL;
191    topPanel.add(createTextPane(), gbc);
192    certificateDetails = createCertificateDetailsPane();
193    gbc.insets.top = 0;
194    gbc.insets.bottom = 0;
195    topPanel.add(Box.createHorizontalStrut(
196        certificateDetails.getPreferredSize().width), gbc);
197    gbc.insets.top = 0;
198    gbc.weighty = 1.0;
199    JPanel auxPanel = UIFactory.makeJPanel();
200    auxPanel.setLayout(new GridBagLayout());
201    gbc.weightx = 0.0;
202    gbc.insets = UIFactory.getEmptyInsets();
203    gbc.gridwidth = GridBagConstraints.RELATIVE;
204    auxPanel.add(Box.createVerticalStrut(100), gbc);
205    gbc.weightx = 1.0;
206    gbc.gridwidth = GridBagConstraints.REMAINDER;
207    auxPanel.add(certificateDetails, gbc);
208    gbc.insets = UIFactory.getCurrentStepPanelInsets();
209    gbc.insets.bottom = UIFactory.TOP_INSET_INPUT_SUBPANEL;
210    topPanel.add(auxPanel, gbc);
211    certificateDetails.setVisible(false);
212    gbc.weighty = 0.2;
213    gbc.insets = UIFactory.getEmptyInsets();
214    topPanel.add(Box.createVerticalGlue(), gbc);
215    contentPanel.add(topPanel, gbc);
216    gbc.weighty = 0.0;
217    gbc.insets = UIFactory.getButtonsPanelInsets();
218    gbc.fill = GridBagConstraints.HORIZONTAL;
219    contentPanel.add(createButtonsPanel(), gbc);
220
221    return contentPanel;
222  }
223
224  /**
225   * Creates and returns the title sub panel.
226   * @return the title sub panel.
227   */
228  private Component createTitlePanel()
229  {
230    JPanel titlePanel = UIFactory.makeJPanel();
231    titlePanel.setLayout(new GridBagLayout());
232    GridBagConstraints gbc = new GridBagConstraints();
233    gbc.anchor = GridBagConstraints.NORTHWEST;
234    gbc.fill = GridBagConstraints.BOTH;
235    gbc.weightx = 0.0;
236    gbc.gridwidth = GridBagConstraints.RELATIVE;
237
238    LocalizableMessage title = INFO_CERTIFICATE_TITLE.get();
239    JLabel l =
240        UIFactory.makeJLabel(UIFactory.IconType.NO_ICON, title,
241            UIFactory.TextStyle.TITLE);
242    l.setOpaque(false);
243    titlePanel.add(l, gbc);
244
245    gbc.gridwidth = GridBagConstraints.RELATIVE;
246    gbc.anchor = GridBagConstraints.NORTHWEST;
247    gbc.weightx = 1.0;
248    gbc.gridwidth = GridBagConstraints.REMAINDER;
249    gbc.insets.left = 0;
250    gbc.weightx = 1.0;
251    gbc.gridwidth = GridBagConstraints.REMAINDER;
252    titlePanel.add(Box.createHorizontalGlue(), gbc);
253
254    return titlePanel;
255  }
256
257  /**
258   * Creates and returns the text sub panel.
259   * @return the text sub panel.
260   */
261  private Component createTextPane()
262  {
263    LocalizableMessage text;
264    if (ce.getType() == UserDataCertificateException.Type.NOT_TRUSTED)
265    {
266      text = INFO_CERTIFICATE_NOT_TRUSTED_TEXT.get(
267          ce.getHost(), ce.getPort(),
268          ce.getHost(), ce.getPort());
269    }
270    else
271    {
272      text = INFO_CERTIFICATE_NAME_MISMATCH_TEXT.get(
273              ce.getHost(), ce.getPort(),
274              ce.getHost(),
275              ce.getHost(), ce.getPort(),
276              ce.getHost(), ce.getPort());
277    }
278    JPanel p = UIFactory.makeJPanel();
279    p.setLayout(new GridBagLayout());
280    GridBagConstraints gbc = new GridBagConstraints();
281    gbc.gridwidth = GridBagConstraints.RELATIVE;
282    gbc.anchor = GridBagConstraints.NORTHWEST;
283    p.add(UIFactory.makeJLabel(UIFactory.IconType.WARNING_LARGE, null,
284        UIFactory.TextStyle.NO_STYLE), gbc);
285    gbc.weightx = 1.0;
286    gbc.gridwidth = GridBagConstraints.REMAINDER;
287    gbc.fill = GridBagConstraints.BOTH;
288    gbc.insets.left = UIFactory.LEFT_INSET_PRIMARY_FIELD;
289    gbc.insets.bottom = 0;
290    explanationPane = UIFactory.makeHtmlPane(null, UIFactory.INSTRUCTIONS_FONT);
291    explanationPane.setOpaque(false);
292    explanationPane.setEditable(false);
293    explanationPane.addHyperlinkListener(this);
294    p.add(explanationPane, gbc);
295    if (ce.getChain() != null && ce.getChain().length > 0)
296    {
297      LocalizableMessageBuilder mb = new LocalizableMessageBuilder();
298      mb.append(text);
299      mb.append(INFO_CERTIFICATE_SHOW_DETAILS_TEXT.get());
300      explanationWithShowDetails = UIFactory.applyFontToHtml(
301              mb.toString(), UIFactory.INSTRUCTIONS_FONT);
302      LocalizableMessageBuilder mb2 = new LocalizableMessageBuilder();
303      mb2.append(text);
304      mb2.append(INFO_CERTIFICATE_HIDE_DETAILS_TEXT.get());
305      explanationWithHideDetails = UIFactory.applyFontToHtml(
306              mb2.toString(), UIFactory.INSTRUCTIONS_FONT);
307
308      explanationPane.setText(explanationWithShowDetails);
309    }
310    else
311    {
312      explanationPane.setText(text.toString());
313    }
314    return p;
315  }
316
317  /**
318   * Creates and returns the buttons DO NOT ACCEPT/ACCEPT FOR THIS SESSION/
319   * ACCEPT PERMANENTLY sub panel.
320   * @return the buttons DO NOT ACCEPT/ACCEPT FOR THIS SESSION/ACCEPT
321   * PERMANENTLY sub panel.
322   */
323  private Component createButtonsPanel()
324  {
325    JPanel buttonsPanel = UIFactory.makeJPanel();
326    buttonsPanel.setLayout(new GridBagLayout());
327    GridBagConstraints gbc = new GridBagConstraints();
328    gbc.fill = GridBagConstraints.HORIZONTAL;
329    gbc.gridwidth = 4;
330    gbc.insets = UIFactory.getEmptyInsets();
331    gbc.insets.left = UIFactory.getCurrentStepPanelInsets().left;
332    buttonsPanel.add(UIFactory.makeJLabel(UIFactory.IconType.NO_ICON,
333        null, UIFactory.TextStyle.NO_STYLE), gbc);
334    gbc.weightx = 1.0;
335    gbc.gridwidth--;
336    gbc.insets.left = 0;
337    buttonsPanel.add(Box.createHorizontalGlue(), gbc);
338    gbc.gridwidth = 3;
339    gbc.fill = GridBagConstraints.NONE;
340    gbc.weightx = 0.0;
341    JButton acceptSessionButton = UIFactory.makeJButton(
342        INFO_CERTIFICATE_DIALOG_ACCEPT_FOR_SESSION_BUTTON_LABEL.get(),
343        INFO_CERTIFICATE_DIALOG_ACCEPT_FOR_SESSION_BUTTON_TOOLTIP.get());
344    buttonsPanel.add(acceptSessionButton, gbc);
345    acceptSessionButton.addActionListener(new ActionListener() {
346      @Override
347      public void actionPerformed(ActionEvent ev) {
348        acceptForSession();
349      }
350    });
351
352    gbc.gridwidth = GridBagConstraints.RELATIVE;
353    gbc.insets.left = UIFactory.HORIZONTAL_INSET_BETWEEN_BUTTONS;
354    JButton acceptPermanentlyButton = UIFactory.makeJButton(
355        INFO_CERTIFICATE_DIALOG_ACCEPT_PERMANENTLY_BUTTON_LABEL.get(),
356        INFO_CERTIFICATE_DIALOG_ACCEPT_PERMANENTLY_BUTTON_TOOLTIP.get());
357    buttonsPanel.add(acceptPermanentlyButton, gbc);
358    acceptPermanentlyButton.addActionListener(new ActionListener() {
359      @Override
360      public void actionPerformed(ActionEvent ev) {
361        acceptPermanently();
362      }
363    });
364
365    gbc.gridwidth = GridBagConstraints.REMAINDER;
366    doNotAcceptButton =
367      UIFactory.makeJButton(
368          INFO_CERTIFICATE_DIALOG_DO_NOT_ACCEPT_BUTTON_LABEL.get(),
369          INFO_CERTIFICATE_DIALOG_DO_NOT_ACCEPT_BUTTON_TOOLTIP.get());
370    buttonsPanel.add(doNotAcceptButton, gbc);
371    doNotAcceptButton.addActionListener(new ActionListener()
372    {
373      @Override
374      public void actionPerformed(ActionEvent ev)
375      {
376        doNotAccept();
377      }
378    });
379
380    return buttonsPanel;
381  }
382
383  /**
384   * Creates the panel containing a representation of the certificate chain.
385   * @return the panel containing a representation of the certificate chain.
386   */
387  private JComponent createCertificateDetailsPane()
388  {
389    JPanel p = UIFactory.makeJPanel();
390    p.setLayout(new GridBagLayout());
391    if (ce.getChain() != null && ce.getChain().length > 0)
392    {
393      final JComboBox<String> combo = new JComboBox<String>();
394      combo.setToolTipText(
395              INFO_CERTIFICATE_CHAIN_COMBO_TOOLTIP.get().toString());
396      final CardLayout cl = new CardLayout();
397      final JPanel cardPanel = new JPanel(cl);
398      final Map<String, JPanel> hmPanels = new HashMap<>();
399
400      LocalizableMessage[] labels =
401      {
402          INFO_CERTIFICATE_SUBJECT_LABEL.get(),
403          INFO_CERTIFICATE_ISSUED_BY_LABEL.get(),
404          INFO_CERTIFICATE_VALID_FROM_LABEL.get(),
405          INFO_CERTIFICATE_EXPIRES_ON_LABEL.get(),
406          INFO_CERTIFICATE_TYPE_LABEL.get(),
407          INFO_CERTIFICATE_SERIAL_NUMBER_LABEL.get(),
408          INFO_CERTIFICATE_MD5_FINGERPRINT_LABEL.get(),
409          INFO_CERTIFICATE_SHA1_FINGERPRINT_LABEL.get()
410      };
411
412      for (int i=0; i<ce.getChain().length; i++)
413      {
414        X509Certificate cert = ce.getChain()[i];
415        JComponent[] components =
416        {
417            createSubjectComponent(cert),
418            createIssuedByComponent(cert),
419            createValidFromComponent(cert),
420            createExpiresOnComponent(cert),
421            createTypeComponent(cert),
422            createSerialNumberComponent(cert),
423            createMD5FingerprintComponent(cert),
424            createSHA1FingerprintComponent(cert)
425        };
426        JPanel certPanel = UIFactory.makeJPanel();
427        certPanel.setLayout(new GridBagLayout());
428        GridBagConstraints gbc = new GridBagConstraints();
429        gbc.anchor = GridBagConstraints.NORTHWEST;
430        gbc.fill = GridBagConstraints.HORIZONTAL;
431
432        for (int j=0; j<labels.length; j++)
433        {
434          JLabel l = UIFactory.makeJLabel(UIFactory.IconType.NO_ICON,
435              labels[j], UIFactory.TextStyle.PRIMARY_FIELD_VALID);
436
437          l.setLabelFor(components[j]);
438          if (j > 0)
439          {
440            gbc.insets.top = UIFactory.TOP_INSET_SECONDARY_FIELD;
441          }
442          gbc.gridwidth = GridBagConstraints.RELATIVE;
443          gbc.weightx = 0.0;
444          gbc.insets.left = 0;
445          certPanel.add(l, gbc);
446          gbc.gridwidth = GridBagConstraints.REMAINDER;
447          gbc.weightx = 1.0;
448          gbc.insets.left = UIFactory.LEFT_INSET_SECONDARY_FIELD;
449          certPanel.add(components[j], gbc);
450        }
451        String name = getName(cert);
452        hmPanels.put(name, certPanel);
453        cardPanel.add(name, certPanel);
454        combo.addItem(name);
455      }
456      GridBagConstraints gbc = new GridBagConstraints();
457      if (ce.getChain().length == 1)
458      {
459        gbc.gridwidth = GridBagConstraints.REMAINDER;
460        gbc.weightx = 1.0;
461        gbc.fill = GridBagConstraints.BOTH;
462        p.add(cardPanel, gbc);
463
464        gbc.weighty = 1.0;
465        p.add(Box.createVerticalGlue(), gbc);
466      }
467      else
468      {
469        gbc.anchor = GridBagConstraints.WEST;
470        gbc.gridwidth = 3;
471        gbc.fill = GridBagConstraints.HORIZONTAL;
472        JPanel auxPanel = UIFactory.makeJPanel();
473        auxPanel.setLayout(new GridBagLayout());
474        JLabel l = UIFactory.makeJLabel(UIFactory.IconType.NO_ICON,
475            INFO_CERTIFICATE_CHAIN_LABEL.get(),
476            UIFactory.TextStyle.PRIMARY_FIELD_VALID);
477        auxPanel.add(l, gbc);
478        gbc.gridwidth = GridBagConstraints.RELATIVE;
479        gbc.insets.left = UIFactory.LEFT_INSET_SECONDARY_FIELD;
480        auxPanel.add(combo, gbc);
481        l.setLabelFor(combo);
482        gbc.gridwidth = GridBagConstraints.REMAINDER;
483        gbc.insets.left = 0;
484        gbc.weightx = 1.0;
485        auxPanel.add(Box.createHorizontalGlue(), gbc);
486
487        p.add(auxPanel, gbc);
488
489        gbc.insets.top = UIFactory.TOP_INSET_PRIMARY_FIELD;
490        gbc.fill = GridBagConstraints.BOTH;
491        p.add(cardPanel, gbc);
492
493        gbc.weighty = 1.0;
494        p.add(Box.createVerticalGlue(), gbc);
495      }
496
497      combo.addActionListener(new ActionListener()
498      {
499        @Override
500        public void actionPerformed(ActionEvent ev)
501        {
502          String selectedItem = (String)combo.getSelectedItem();
503          cl.show(hmPanels.get(selectedItem), selectedItem);
504        }
505      });
506    }
507    JScrollPane scroll = new JScrollPane(p);
508    scroll.setViewportBorder(new EmptyBorder(0, 0, 0, 0));
509    scroll.setOpaque(false);
510    scroll.getViewport().setOpaque(false);
511    scroll.setPreferredSize(new Dimension(scroll.getPreferredSize().width,
512        175));
513    return scroll;
514  }
515
516  private JComponent createSubjectComponent(X509Certificate cert)
517  {
518    LocalizableMessage dn = LocalizableMessage.raw(cert.getSubjectX500Principal().getName());
519    return makeValueLabel(dn);
520  }
521
522  private JComponent createIssuedByComponent(X509Certificate cert)
523  {
524    LocalizableMessage dn = LocalizableMessage.raw(cert.getIssuerX500Principal().getName());
525    return makeValueLabel(dn);
526  }
527
528  private JComponent createValidFromComponent(X509Certificate cert)
529  {
530    JComponent c;
531
532    Date date = cert.getNotBefore();
533    DateFormat df = DateFormat.getDateTimeInstance(DateFormat.SHORT,
534        DateFormat.SHORT);
535    LocalizableMessage value = LocalizableMessage.raw(df.format(date));
536    long t1 = System.currentTimeMillis();
537    long t2 = date.getTime();
538    boolean isNotValidYet = t1 < t2;
539
540    if (isNotValidYet)
541    {
542      c = UIFactory.makeJLabel(UIFactory.IconType.ERROR,
543          INFO_CERTIFICATE_NOT_VALID_YET.get(value),
544          UIFactory.TextStyle.SECONDARY_FIELD_INVALID);
545    }
546    else
547    {
548      c = makeValueLabel(value);
549    }
550    return c;
551  }
552
553
554  private JComponent createExpiresOnComponent(X509Certificate cert)
555  {
556    JComponent c;
557
558    Date date = cert.getNotAfter();
559    DateFormat df = DateFormat.getDateTimeInstance(DateFormat.SHORT,
560    DateFormat.SHORT);
561    LocalizableMessage value = LocalizableMessage.raw(df.format(date));
562    long t1 = System.currentTimeMillis();
563    long t2 = date.getTime();
564    boolean isExpired = t1 > t2;
565
566    if (isExpired)
567    {
568      c = UIFactory.makeJLabel(UIFactory.IconType.ERROR,
569          INFO_CERTIFICATE_EXPIRED.get(value),
570          UIFactory.TextStyle.SECONDARY_FIELD_INVALID);
571    }
572    else
573    {
574      c = makeValueLabel(value);
575    }
576    return c;
577  }
578
579
580  private JComponent createTypeComponent(X509Certificate cert)
581  {
582    LocalizableMessage type = LocalizableMessage.raw(cert.getType());
583    return makeValueLabel(type);
584  }
585
586  private JComponent createSerialNumberComponent(X509Certificate cert)
587  {
588    LocalizableMessage serialNumber = LocalizableMessage.raw(String.valueOf(cert.getSerialNumber()));
589    return makeValueLabel(serialNumber);
590  }
591
592
593  /**
594   * Returns the LocalizableMessage representation of the SHA1 fingerprint.
595   * @param cert the certificate object.
596   * @return the LocalizableMessage representation of the SHA1 fingerprint.
597   */
598  private static LocalizableMessage getSHA1FingerPrint(X509Certificate cert)
599  {
600    return getFingerPrint(cert, "SHA1");
601  }
602
603  /**
604   * Returns the LocalizableMessage representation of the MD5 fingerprint.
605   * @param cert the certificate object.
606   * @return the LocalizableMessage representation of the MD5 fingerprint.
607   */
608  private static LocalizableMessage getMD5FingerPrint(X509Certificate cert)
609  {
610    return getFingerPrint(cert, "MD5");
611  }
612
613  private static LocalizableMessage getFingerPrint(X509Certificate cert, String algorithm)
614  {
615    try {
616      MessageDigest md = MessageDigest.getInstance(algorithm);
617      byte[] b = md.digest(cert.getEncoded());
618      StringBuilder sb = new StringBuilder();
619      for (int i = 0; i < b.length; i++)
620      {
621        if (i > 0)
622        {
623          sb.append(":");
624        }
625        sb.append(Integer.toHexString(b[i] & 0xFF));
626      }
627      return LocalizableMessage.raw(sb);
628    }
629    catch (NoSuchAlgorithmException nsae) {
630      logger.warn(LocalizableMessage.raw(algorithm + " algorithm not supported: " + nsae, nsae));
631      return null;
632    }
633    catch (CertificateEncodingException cee) {
634      logger.warn(LocalizableMessage.raw("Certificate encoding exception: "+cee, cee));
635      return null;
636    }
637  }
638
639  private JComponent createSHA1FingerprintComponent(X509Certificate cert)
640  {
641    return UIFactory.makeTextPane(getSHA1FingerPrint(cert),
642        UIFactory.TextStyle.SECONDARY_FIELD_VALID);
643  }
644
645  private JComponent createMD5FingerprintComponent(X509Certificate cert)
646  {
647    return UIFactory.makeTextPane(getMD5FingerPrint(cert),
648        UIFactory.TextStyle.SECONDARY_FIELD_VALID);
649  }
650
651  private JLabel makeValueLabel(LocalizableMessage value)
652  {
653    if (value == null)
654    {
655      value = INFO_NOT_AVAILABLE_LABEL.get();
656    }
657    return UIFactory.makeJLabel(UIFactory.IconType.NO_ICON, value,
658        UIFactory.TextStyle.SECONDARY_FIELD_VALID);
659  }
660
661  private String getName(X509Certificate cert)
662  {
663    String name = cert.getSubjectX500Principal().getName();
664    try
665    {
666      LdapName dn = new LdapName(name);
667      Rdn rdn = dn.getRdn(0);
668      return rdn.getValue().toString();
669    }
670    catch (Throwable t)
671    {
672      logger.warn(LocalizableMessage.raw("Error parsing subject dn: "+
673          cert.getSubjectX500Principal(), t));
674      return name;
675    }
676  }
677
678  /** Method called when user clicks on ok. */
679  private void acceptForSession()
680  {
681    returnValue = ReturnType.ACCEPTED_FOR_SESSION;
682    dispose();
683  }
684
685  /** Method called when user clicks on cancel. */
686  private void doNotAccept()
687  {
688    returnValue = ReturnType.NOT_ACCEPTED;
689    dispose();
690  }
691
692  /** Method called when user clicks on ok. */
693  private void acceptPermanently()
694  {
695    returnValue = ReturnType.ACCEPTED_PERMANENTLY;
696    dispose();
697  }
698}