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