You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by or...@apache.org on 2019/05/01 01:20:10 UTC

[qpid-broker-j] branch master updated: QPID-8301: [Broker-J] Expose information about keystore certificate details

This is an automated email from the ASF dual-hosted git repository.

orudyy pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/qpid-broker-j.git


The following commit(s) were added to refs/heads/master by this push:
     new 1b5f061  QPID-8301: [Broker-J] Expose information about keystore certificate details
1b5f061 is described below

commit 1b5f0614b849cb1149b420728cb44597465dae8d
Author: Alex Rudyy <or...@apache.org>
AuthorDate: Fri Apr 26 23:47:17 2019 +0100

    QPID-8301: [Broker-J] Expose information about keystore certificate details
    
    This closes #26
---
 .../org/apache/qpid/server/model/KeyStore.java     |  7 +++
 .../qpid/server/security/AbstractKeyStore.java     | 21 ++++++++
 .../AutoGeneratedSelfSignedKeyStoreImpl.java       |  8 +++
 .../qpid/server/security/FileKeyStoreImpl.java     | 61 +++++++++++++++++++---
 .../qpid/server/security/FileTrustStoreImpl.java   | 12 +----
 .../qpid/server/security/NonJavaKeyStoreImpl.java  | 13 ++++-
 .../transport/network/security/ssl/SSLUtil.java    | 17 ++++++
 .../java/resources/js/qpid/management/KeyStore.js  | 18 ++++++-
 .../src/main/java/resources/showStore.html         |  3 ++
 9 files changed, 141 insertions(+), 19 deletions(-)

diff --git a/broker-core/src/main/java/org/apache/qpid/server/model/KeyStore.java b/broker-core/src/main/java/org/apache/qpid/server/model/KeyStore.java
index b48a248..0d96b3d 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/model/KeyStore.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/model/KeyStore.java
@@ -21,8 +21,12 @@
 package org.apache.qpid.server.model;
 
 import java.security.GeneralSecurityException;
+import java.util.List;
+
 import javax.net.ssl.KeyManager;
 
+import org.apache.qpid.server.security.CertificateDetails;
+
 @ManagedObject( defaultType = "FileKeyStore" )
 public interface KeyStore<X extends KeyStore<X>> extends ConfiguredObject<X>
 {
@@ -46,4 +50,7 @@ public interface KeyStore<X extends KeyStore<X>> extends ConfiguredObject<X>
     int getCertificateExpiryCheckFrequency();
 
     KeyManager[] getKeyManagers() throws GeneralSecurityException;
+
+    @DerivedAttribute(description = "List of details about the certificates like validity dates, SANs, issuer and subject names, etc.")
+    List<CertificateDetails> getCertificateDetails();
 }
diff --git a/broker-core/src/main/java/org/apache/qpid/server/security/AbstractKeyStore.java b/broker-core/src/main/java/org/apache/qpid/server/security/AbstractKeyStore.java
index c970c82..1df12c9 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/security/AbstractKeyStore.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/security/AbstractKeyStore.java
@@ -20,13 +20,18 @@
  */
 package org.apache.qpid.server.security;
 
+import java.security.cert.Certificate;
 import java.security.cert.CertificateExpiredException;
 import java.security.cert.CertificateNotYetValidException;
 import java.security.cert.X509Certificate;
+import java.util.Collection;
+import java.util.Collections;
 import java.util.Date;
+import java.util.List;
 import java.util.Map;
 import java.util.concurrent.ScheduledFuture;
 import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
 
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
@@ -196,4 +201,20 @@ public abstract class AbstractKeyStore<X extends AbstractKeyStore<X>>
         }
         return checkFrequency;
     }
+
+    @Override
+    public List<CertificateDetails> getCertificateDetails()
+    {
+        Collection<Certificate> certificates = getCertificates();
+        if (!certificates.isEmpty())
+        {
+            return certificates.stream()
+                               .filter(cert -> cert instanceof X509Certificate)
+                               .map(x509cert -> new CertificateDetailsImpl((X509Certificate) x509cert))
+                               .collect(Collectors.toList());
+        }
+        return Collections.emptyList();
+    }
+
+    protected abstract Collection<Certificate> getCertificates();
 }
diff --git a/broker-core/src/main/java/org/apache/qpid/server/security/AutoGeneratedSelfSignedKeyStoreImpl.java b/broker-core/src/main/java/org/apache/qpid/server/security/AutoGeneratedSelfSignedKeyStoreImpl.java
index 648f9fd..f5feecf 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/security/AutoGeneratedSelfSignedKeyStoreImpl.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/security/AutoGeneratedSelfSignedKeyStoreImpl.java
@@ -37,6 +37,7 @@ import java.security.KeyStoreException;
 import java.security.NoSuchAlgorithmException;
 import java.security.PrivateKey;
 import java.security.SecureRandom;
+import java.security.cert.Certificate;
 import java.security.cert.CertificateEncodingException;
 import java.security.cert.CertificateException;
 import java.security.cert.CertificateFactory;
@@ -45,6 +46,7 @@ import java.security.spec.InvalidKeySpecException;
 import java.util.Arrays;
 import java.util.Base64;
 import java.util.Calendar;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.Date;
 import java.util.HashSet;
@@ -313,6 +315,12 @@ public class AutoGeneratedSelfSignedKeyStoreImpl
         }
     }
 
+    @Override
+    protected Collection<Certificate> getCertificates()
+    {
+        return Collections.singleton(_certificate);
+    }
+
 
     private void generateKeyManagers()
     {
diff --git a/broker-core/src/main/java/org/apache/qpid/server/security/FileKeyStoreImpl.java b/broker-core/src/main/java/org/apache/qpid/server/security/FileKeyStoreImpl.java
index 50e9560..7f7408f 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/security/FileKeyStoreImpl.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/security/FileKeyStoreImpl.java
@@ -30,6 +30,7 @@ import java.security.NoSuchAlgorithmException;
 import java.security.UnrecoverableKeyException;
 import java.security.cert.Certificate;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.Date;
 import java.util.Enumeration;
@@ -79,6 +80,8 @@ public class FileKeyStoreImpl extends AbstractKeyStore<FileKeyStoreImpl> impleme
     @ManagedAttributeField
     private String _password;
 
+    private volatile Collection<Certificate> _certificates;
+
     static
     {
         Handler.register();
@@ -108,6 +111,40 @@ public class FileKeyStoreImpl extends AbstractKeyStore<FileKeyStoreImpl> impleme
     }
 
     @Override
+    protected void onOpen()
+    {
+        super.onOpen();
+        initialize();
+    }
+
+    @Override
+    protected void changeAttributes(final Map<String, Object> attributes)
+    {
+        super.changeAttributes(attributes);
+        if (attributes.containsKey(STORE_URL)
+            || attributes.containsKey(PASSWORD)
+            || attributes.containsKey(KEY_STORE_TYPE)
+            || attributes.containsKey(KEY_MANAGER_FACTORY_ALGORITHM))
+        {
+            initialize();
+        }
+    }
+
+    private void initialize()
+    {
+        Collection<Certificate> result;
+        try
+        {
+            result = Collections.unmodifiableCollection(SSLUtil.getCertificates(getInitializedKeyStore(this)));
+        }
+        catch (GeneralSecurityException | IOException e)
+        {
+            result = Collections.emptyList();
+        }
+        _certificates = result;
+    }
+
+    @Override
     protected void validateChange(final ConfiguredObject<?> proxyForValidation, final Set<String> changedAttributes)
     {
         super.validateChange(proxyForValidation, changedAttributes);
@@ -128,10 +165,7 @@ public class FileKeyStoreImpl extends AbstractKeyStore<FileKeyStoreImpl> impleme
         final String loggableStoreUrl = StringUtil.elideDataUrl(fileKeyStore.getStoreUrl());
         try
         {
-            URL url = getUrlFromString(fileKeyStore.getStoreUrl());
-            String password = fileKeyStore.getPassword();
-            String keyStoreType = fileKeyStore.getKeyStoreType();
-            java.security.KeyStore keyStore = SSLUtil.getInitializedKeyStore(url, password, keyStoreType);
+            java.security.KeyStore keyStore = getInitializedKeyStore(fileKeyStore);
 
             final String certAlias = fileKeyStore.getCertificateAlias();
             if (certAlias != null)
@@ -190,6 +224,15 @@ public class FileKeyStoreImpl extends AbstractKeyStore<FileKeyStoreImpl> impleme
         checkCertificateExpiry();
     }
 
+    private java.security.KeyStore getInitializedKeyStore(final FileKeyStore<?> fileKeyStore)
+            throws GeneralSecurityException, IOException
+    {
+        URL url = getUrlFromString(fileKeyStore.getStoreUrl());
+        String password = fileKeyStore.getPassword();
+        String keyStoreType = fileKeyStore.getKeyStoreType();
+        return SSLUtil.getInitializedKeyStore(url, password, keyStoreType);
+    }
+
     @Override
     public String getStoreUrl()
     {
@@ -319,8 +362,7 @@ public class FileKeyStoreImpl extends AbstractKeyStore<FileKeyStoreImpl> impleme
 
             try
             {
-                URL url = getUrlFromString(_storeUrl);
-                final java.security.KeyStore ks = SSLUtil.getInitializedKeyStore(url, getPassword(), _keyStoreType);
+                final java.security.KeyStore ks = getInitializedKeyStore(this);
 
                 char[] keyStoreCharPassword = getPassword() == null ? null : getPassword().toCharArray();
 
@@ -352,6 +394,13 @@ public class FileKeyStoreImpl extends AbstractKeyStore<FileKeyStoreImpl> impleme
 
     }
 
+    @Override
+    protected Collection<Certificate> getCertificates()
+    {
+        final Collection<Certificate> certificates = _certificates;
+        return certificates == null ? Collections.emptyList() : certificates;
+    }
+
     private boolean containsPrivateKey(final java.security.KeyStore keyStore) throws KeyStoreException
     {
         final Enumeration<String> aliasesEnum = keyStore.aliases();
diff --git a/broker-core/src/main/java/org/apache/qpid/server/security/FileTrustStoreImpl.java b/broker-core/src/main/java/org/apache/qpid/server/security/FileTrustStoreImpl.java
index d6a4925..c503801 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/security/FileTrustStoreImpl.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/security/FileTrustStoreImpl.java
@@ -349,17 +349,7 @@ public class FileTrustStoreImpl extends AbstractTrustStore<FileTrustStoreImpl> i
 
     private Certificate[] createCertificates(final KeyStore ts) throws KeyStoreException
     {
-        final Collection<Certificate> certificates = new ArrayList<>();
-
-        Enumeration<String> aliases = ts.aliases();
-        while (aliases.hasMoreElements())
-        {
-            String alias = aliases.nextElement();
-            if (ts.isCertificateEntry(alias))
-            {
-                certificates.add(ts.getCertificate(alias));
-            }
-        }
+        final Collection<Certificate> certificates = SSLUtil.getCertificates(ts);
 
         return certificates.toArray(new Certificate[certificates.size()]);
     }
diff --git a/broker-core/src/main/java/org/apache/qpid/server/security/NonJavaKeyStoreImpl.java b/broker-core/src/main/java/org/apache/qpid/server/security/NonJavaKeyStoreImpl.java
index c8a4670..3a92a6c 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/security/NonJavaKeyStoreImpl.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/security/NonJavaKeyStoreImpl.java
@@ -29,9 +29,12 @@ import java.nio.charset.StandardCharsets;
 import java.security.GeneralSecurityException;
 import java.security.PrivateKey;
 import java.security.SecureRandom;
+import java.security.cert.Certificate;
 import java.security.cert.X509Certificate;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
 import java.util.Date;
 import java.util.List;
 import java.util.Map;
@@ -82,6 +85,7 @@ public class NonJavaKeyStoreImpl extends AbstractKeyStore<NonJavaKeyStoreImpl> i
     }
 
     private volatile X509Certificate _certificate;
+    private volatile Collection<Certificate> _certificates;
 
     @ManagedObjectFactoryConstructor
     public NonJavaKeyStoreImpl(final Map<String, Object> attributes, Broker<?> broker)
@@ -212,9 +216,9 @@ public class NonJavaKeyStoreImpl extends AbstractKeyStore<NonJavaKeyStoreImpl> i
             {
                 PrivateKey privateKey = SSLUtil.readPrivateKey(getUrlFromString(_privateKeyUrl));
                 X509Certificate[] certs = SSLUtil.readCertificates(getUrlFromString(_certificateUrl));
+                List<X509Certificate> allCerts = new ArrayList<>(Arrays.asList(certs));
                 if(_intermediateCertificateUrl != null)
                 {
-                    List<X509Certificate> allCerts = new ArrayList<>(Arrays.asList(certs));
                     allCerts.addAll(Arrays.asList(SSLUtil.readCertificates(getUrlFromString(_intermediateCertificateUrl))));
                     certs = allCerts.toArray(new X509Certificate[allCerts.size()]);
                 }
@@ -233,6 +237,7 @@ public class NonJavaKeyStoreImpl extends AbstractKeyStore<NonJavaKeyStoreImpl> i
                 kmf.init(inMemoryKeyStore, chars);
                 _keyManagers = kmf.getKeyManagers();
                 _certificate = certs[0];
+                _certificates = Collections.unmodifiableCollection(allCerts);
             }
 
         }
@@ -294,4 +299,10 @@ public class NonJavaKeyStoreImpl extends AbstractKeyStore<NonJavaKeyStoreImpl> i
         return url;
     }
 
+    @Override
+    protected Collection<Certificate> getCertificates()
+    {
+        final Collection<Certificate> certificates = _certificates;
+        return certificates == null ? Collections.emptyList() : certificates;
+    }
 }
diff --git a/broker-core/src/main/java/org/apache/qpid/server/transport/network/security/ssl/SSLUtil.java b/broker-core/src/main/java/org/apache/qpid/server/transport/network/security/ssl/SSLUtil.java
index edb753f..0ffab92 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/transport/network/security/ssl/SSLUtil.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/transport/network/security/ssl/SSLUtil.java
@@ -39,6 +39,7 @@ import java.nio.charset.StandardCharsets;
 import java.security.GeneralSecurityException;
 import java.security.KeyFactory;
 import java.security.KeyStore;
+import java.security.KeyStoreException;
 import java.security.NoSuchAlgorithmException;
 import java.security.Principal;
 import java.security.PrivateKey;
@@ -55,6 +56,7 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Date;
+import java.util.Enumeration;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Set;
@@ -1035,6 +1037,21 @@ public class SSLUtil
 
     }
 
+    public static Collection<Certificate> getCertificates(final KeyStore ks) throws KeyStoreException
+    {
+        List<Certificate> certificates = new ArrayList<>();
+        Enumeration<String> aliases = ks.aliases();
+        while (aliases.hasMoreElements())
+        {
+            String alias = aliases.nextElement();
+            if (ks.isCertificateEntry(alias))
+            {
+                certificates.add(ks.getCertificate(alias));
+            }
+        }
+        return certificates;
+    }
+
     public interface KeyCertPair
     {
         PrivateKey getPrivateKey();
diff --git a/broker-plugins/management-http/src/main/java/resources/js/qpid/management/KeyStore.js b/broker-plugins/management-http/src/main/java/resources/js/qpid/management/KeyStore.js
index 41a8fd9..97987e7 100644
--- a/broker-plugins/management-http/src/main/java/resources/js/qpid/management/KeyStore.js
+++ b/broker-plugins/management-http/src/main/java/resources/js/qpid/management/KeyStore.js
@@ -30,8 +30,10 @@ define(["dojo/dom",
         "qpid/common/formatter",
         "qpid/management/addStore",
         "dojo/text!showStore.html",
+        "qpid/management/store/CertificateGridWidget",
         "dojo/domReady!"],
-    function (dom, parser, query, connect, registry, entities, properties, updater, util, formatter, addStore, template)
+    function (dom, parser, query, connect, registry, entities, properties, updater, util, formatter, addStore, template,
+              CertificateGridWidget)
     {
 
         function KeyStore(kwArgs)
@@ -84,6 +86,13 @@ define(["dojo/dom",
                                 addStore.show(data, that.keyStoreUpdater.keyStoreData);
                             }, util.xhrErrorHandler);
                     });
+                    var gridNode = query(".managedCertificatesGrid", contentPane.containerNode)[0];
+                    that.certificatesGrid = new CertificateGridWidget({
+                        management: that.management,
+                        modelObj: that.modelObj
+                    }, gridNode);
+                    that.certificatesGrid.enableCertificateControls(false);
+                    that.certificatesGrid.startup();
                 });
 
         };
@@ -91,6 +100,11 @@ define(["dojo/dom",
         KeyStore.prototype.close = function ()
         {
             updater.remove(this.keyStoreUpdater);
+            if (this.certificatesGrid)
+            {
+                this.certificatesGrid.destroy();
+            }
+
         };
 
         function KeyStoreUpdater(tabObject)
@@ -149,6 +163,8 @@ define(["dojo/dom",
                         callback();
                     }
 
+                    that.tabObject.certificatesGrid.update(data.certificateDetails);
+
                     if (that.details)
                     {
                         that.details.update(that.keyStoreData);
diff --git a/broker-plugins/management-http/src/main/java/resources/showStore.html b/broker-plugins/management-http/src/main/java/resources/showStore.html
index e564726..5a0946d 100644
--- a/broker-plugins/management-http/src/main/java/resources/showStore.html
+++ b/broker-plugins/management-http/src/main/java/resources/showStore.html
@@ -36,6 +36,9 @@
             </div>
             <div class="clear">
             </div>
+            <div class="clear">
+                <div class="managedCertificatesGrid"></div>
+            </div>
         </div>
 
         <div class="dijitDialogPaneActionBar">


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org