diff --git a/core/src/main/java/org/jivesoftware/spark/ui/login/CertificateDialog.java b/core/src/main/java/org/jivesoftware/spark/ui/login/CertificateDialog.java index 28beb176c..a51bceb48 100644 --- a/core/src/main/java/org/jivesoftware/spark/ui/login/CertificateDialog.java +++ b/core/src/main/java/org/jivesoftware/spark/ui/login/CertificateDialog.java @@ -23,6 +23,8 @@ import javax.swing.JScrollPane; import javax.swing.JTextArea; import javax.swing.JTextField; import javax.swing.ScrollPaneConstants; +import javax.swing.SwingUtilities; + import org.jivesoftware.resource.Res; import org.jivesoftware.spark.util.ResourceUtils; import org.jivesoftware.sparkimpl.certificates.CertificateController; @@ -209,19 +211,27 @@ public class CertificateDialog extends JDialog implements ActionListener { buttonPanel.add(okButton, new GridBagConstraints(1, 2, 1, 1, 0.2, 0.0, CENTER, HORIZONTAL, new Insets(5, 100, 5, 5), 0, 0)); buttonPanel.add(cancelButton, new GridBagConstraints(2, 2, 1, 1, 0.2, 0.0, CENTER, HORIZONTAL, new Insets(5, 5, 5, 100), 0, 0)); + trust.setSelected(cert.isValid() || cert.isExempted()); + distrust.setSelected(!cert.isValid() && !cert.isExempted()); + scrollPane = new JScrollPane(panel); scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); if (addInfo) { - add(infoLabel, new GridBagConstraints(0, 0, 4, 1, 1.0, 1.0, WEST, BOTH, DEFAULT_INSETS, 0, 0)); + add(infoLabel, new GridBagConstraints(0, 0, 4, 1, 1.0, 0.0, WEST, BOTH, DEFAULT_INSETS, 0, 0)); } add(scrollPane, new GridBagConstraints(0, 1, 4, 1, 1.0, 1.0, WEST, BOTH, DEFAULT_INSETS, 0, 0)); add(buttonPanel, new GridBagConstraints(0, 2, 1, 1, 1.0, 0.0, WEST, HORIZONTAL, DEFAULT_INSETS, 0, 0)); - - setVisible(true); - scrollPane.getVerticalScrollBar().setValue(0); + //scrolls scrollPane to top + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + panel.scrollRectToVisible(versionField.getBounds()); } + }); + + setVisible(true); } diff --git a/core/src/main/java/org/jivesoftware/spark/ui/login/CertificatesManagerSettingsPanel.java b/core/src/main/java/org/jivesoftware/spark/ui/login/CertificatesManagerSettingsPanel.java index 02e3e5cdd..0e855836f 100644 --- a/core/src/main/java/org/jivesoftware/spark/ui/login/CertificatesManagerSettingsPanel.java +++ b/core/src/main/java/org/jivesoftware/spark/ui/login/CertificatesManagerSettingsPanel.java @@ -5,6 +5,7 @@ import static java.awt.GridBagConstraints.WEST; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; +import java.awt.HeadlessException; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; @@ -16,6 +17,7 @@ import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.cert.CertificateException; +import javax.naming.InvalidNameException; import javax.swing.BorderFactory; import javax.swing.JButton; import javax.swing.JCheckBox; @@ -164,6 +166,8 @@ public class CertificatesManagerSettingsPanel extends JPanel implements ActionLi Log.error("Cannot upload certificate file", ex); } catch (IllegalArgumentException ex) { Log.warning("Certificate or it's alias cannot be null", ex); + } catch (HeadlessException | InvalidNameException ex) { + Log.error("Error at setting certificate alias", ex); } } } diff --git a/core/src/main/java/org/jivesoftware/sparkimpl/certificates/CertificateController.java b/core/src/main/java/org/jivesoftware/sparkimpl/certificates/CertificateController.java index 3622329f2..7c7bd5331 100644 --- a/core/src/main/java/org/jivesoftware/sparkimpl/certificates/CertificateController.java +++ b/core/src/main/java/org/jivesoftware/sparkimpl/certificates/CertificateController.java @@ -17,6 +17,9 @@ import java.util.Base64; import java.util.Enumeration; import java.util.List; +import javax.naming.InvalidNameException; +import javax.naming.ldap.LdapName; +import javax.naming.ldap.Rdn; import javax.swing.JOptionPane; import javax.swing.table.DefaultTableModel; import org.jivesoftware.resource.Res; @@ -100,7 +103,7 @@ public class CertificateController { tableModel.addRow(certEntry); } } catch (KeyStoreException | NoSuchAlgorithmException | CertificateException | IOException e) { - Log.warning("Cannot acces Truststore, it might be not set up", e); + Log.warning("Cannot access Truststore, it might be not set up", e); } } @@ -112,56 +115,74 @@ public class CertificateController { * @throws CertificateException * @throws NoSuchAlgorithmException * @throws IOException + * @throws InvalidNameException + * @throws HeadlessException */ - public void addCertificateToKeystore(File file) throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException{ + public void addCertificateToKeystore(File file) throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException, HeadlessException, InvalidNameException{ if(file == null){ throw new IllegalArgumentException(); } try (InputStream inputStream = new FileInputStream(file)) { CertificateFactory cf = CertificateFactory.getInstance("X509"); X509Certificate addedCert = (X509Certificate) cf.generateCertificate(inputStream); - showCertificate(new CertificateModel(addedCert), true); - + if (checkForSameCertificate(addedCert) == false) { + showCertificate(new CertificateModel(addedCert), true); + } // value of addToKeyStore is changed by setter in CertificateDialog if (addToKeystore == true) { addToKeystore = false; - String alias; - do{ - alias =null; - alias = JOptionPane.showInputDialog(null, Res.getString("dialog.certificate.provide.alias.and.confirm")); - - //check if entry pass all requirements - if (alias != null - && checkForSameAlias(alias) == false - && checkForSameCertificate(alias, addedCert) == false - && checkIfAliasIsEmpty(alias) == false) { - //add entry to Truststore - trustStore.setCertificateEntry(alias, addedCert); - try (FileOutputStream outputStream = new FileOutputStream(localPreferences.getTrustStorePath())) { - trustStore.store(outputStream, localPreferences.getTrustStorePassword().toCharArray()); - break; - } - } - } while (alias != null); + String alias = useCommonNameAsAlias(addedCert); + trustStore.setCertificateEntry(alias, addedCert); + try (FileOutputStream outputStream = new FileOutputStream(localPreferences.getTrustStorePath())) { + trustStore.store(outputStream, localPreferences.getTrustStorePassword().toCharArray()); + JOptionPane.showMessageDialog(null, Res.getString("dialog.certificate.has.been.added")); + } } } } + /** + * Extract from certificate common name ("CN") and returns it to use as certificate name. + * This method also assure that it will not add second same alias to Truststore by adding number to alias. + * In case when common name cannot be extracted method will return "cert{number}". + * + * @param cert + * @return + * @throws InvalidNameException + * @throws HeadlessException + * @throws KeyStoreException + */ + private String useCommonNameAsAlias(X509Certificate cert) throws InvalidNameException, HeadlessException, KeyStoreException { + String alias = null; + String dn = cert.getSubjectX500Principal().getName(); + LdapName ldapDN = new LdapName(dn); + for (Rdn rdn : ldapDN.getRdns()) { + if (rdn.getType().equals("CN")) { + alias = rdn.getValue().toString(); + int i = 1; + while (checkForSameAlias(alias)) { + alias = alias + Integer.toString(i); + i++; + } + break; + } + } + // Certificate subject doesn't have easy distinguishable common name then generate alias as cert{integer} + if (alias == null) { + alias = "cert"; + int i = 1; + while (checkForSameAlias(alias)) { + alias = alias + Integer.toString(i); + i++; + } + } + return alias; + } - /** - * Check if alias is empty String. - * @return - */ - private boolean checkIfAliasIsEmpty(String alias){ - if(alias.equals("")){ - JOptionPane.showMessageDialog(null, Res.getString("dialog.certificate.alias.cannot.be.empty")); - return true; - } - return false; - } /** * Check if there is certificate entry in Truststore with the same alias. + * * @param alias * @return * @throws HeadlessException @@ -169,7 +190,6 @@ public class CertificateController { */ private boolean checkForSameAlias(String alias) throws HeadlessException, KeyStoreException { if (trustStore.getCertificate(alias) != null) { - JOptionPane.showMessageDialog(null, Res.getString("dialog.certificate.wrong.alias")); return true; } return false; @@ -182,7 +202,7 @@ public class CertificateController { * @return * @throws KeyStoreException */ - private boolean checkForSameCertificate(String alias, X509Certificate addedCert) throws KeyStoreException{ + private boolean checkForSameCertificate(X509Certificate addedCert) throws KeyStoreException{ // check if this certificate isn't already added to Truststore Enumeration storeCheck = trustStore.aliases(); while (storeCheck.hasMoreElements()) { diff --git a/core/src/main/resources/i18n/spark_i18n.properties b/core/src/main/resources/i18n/spark_i18n.properties index e44449dd8..bc206c82e 100644 --- a/core/src/main/resources/i18n/spark_i18n.properties +++ b/core/src/main/resources/i18n/spark_i18n.properties @@ -1178,7 +1178,6 @@ dialog.confirm.to.reveal.visibility.title=Are you sure? dialog.confirm.to.reveal.visibility.msg=If you are going to proceed your invisibility will be revealed dialog.confirm.close.all.conferences.if.invisible.msg=If you want to proceed all conference room will be closed dialog.certificate.provide.alias.and.confirm = \t Provide alias for Truststore entry. \n Are you sure you want to add this \n certificate to your Truststore? -dialog.certificate.show = This is the certificate you try to add to Truststore

After adding this certificate, Spark will be able to establish secured
communications with servers that are identified by this certificate.

If you are sure that you want to add this certificate click OK button. -dialog.certificate.wrong.alias = Cannot add second certificate with the same alias to Truststore. \n Please choose other alias. -dialog.certificate.alias.cannot.be.empty = Certificate's alias cannot be empty. -dialog.certificate.cannot.have.copy = This certificate is already stored within Truststore. \ No newline at end of file +dialog.certificate.show = This is the certificate you try to add to Truststore.

After adding this certificate, Spark will be able to establish secured
communications with servers that are identified by this certificate.

If you are sure that you want to add this certificate click Ok button. +dialog.certificate.cannot.have.copy = This certificate is already stored within Truststore. +dialog.certificate.has.been.added = Certificate has been added to the Truststore. \ No newline at end of file