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