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/07/26 23:01:41 UTC

[qpid-broker-j] branch master updated: QPID-8348: [Broker-J] Add ability to reload keystore/truststore

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 ca6626e  QPID-8348: [Broker-J] Add ability to reload keystore/truststore
ca6626e is described below

commit ca6626ee2a5f317ed0426b2219236364b859969f
Author: Alex Rudyy <or...@apache.org>
AuthorDate: Sat Jul 27 00:00:35 2019 +0100

    QPID-8348: [Broker-J] Add ability to reload keystore/truststore
---
 .../apache/qpid/server/security/FileKeyStore.java  |   5 +
 .../qpid/server/security/FileKeyStoreImpl.java     |   8 +-
 .../qpid/server/security/FileTrustStore.java       |   4 +
 .../qpid/server/security/FileTrustStoreImpl.java   |  12 ++-
 .../qpid/server/security/FileKeyStoreTest.java     |  62 +++++++++++
 .../qpid/server/security/FileTrustStoreTest.java   |  55 ++++++++++
 .../qpid/server/security/KeystoreTestHelper.java   | 114 +++++++++++++++++++++
 .../js/qpid/management/store/filekeystore/show.js  |  58 ++++++++++-
 .../qpid/management/store/filetruststore/show.js   |  58 ++++++++++-
 .../java/resources/store/filekeystore/show.html    |   3 +
 .../java/resources/store/filetruststore/show.html  |   3 +
 11 files changed, 373 insertions(+), 9 deletions(-)

diff --git a/broker-core/src/main/java/org/apache/qpid/server/security/FileKeyStore.java b/broker-core/src/main/java/org/apache/qpid/server/security/FileKeyStore.java
index 56eede1..cf1145b 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/security/FileKeyStore.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/security/FileKeyStore.java
@@ -29,6 +29,7 @@ import org.apache.qpid.server.model.KeyStore;
 import org.apache.qpid.server.model.ManagedAttribute;
 import org.apache.qpid.server.model.ManagedContextDefault;
 import org.apache.qpid.server.model.ManagedObject;
+import org.apache.qpid.server.model.ManagedOperation;
 
 @ManagedObject( category = false, type = "FileKeyStore" )
 public interface FileKeyStore<X extends FileKeyStore<X>> extends KeyStore<X>
@@ -70,4 +71,8 @@ public interface FileKeyStore<X extends FileKeyStore<X>> extends KeyStore<X>
 
     @ManagedAttribute( defaultValue = "true", description = "Use SNI server name from the SSL handshake to select the most appropriate certificate for the indicated hostname")
     boolean isUseHostNameMatching();
+
+    @ManagedOperation( description = "Reloads keystore.", changesConfiguredObjectState = true)
+    void reload();
+
 }
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 7f7408f..b6c6c1a 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
@@ -139,7 +139,7 @@ public class FileKeyStoreImpl extends AbstractKeyStore<FileKeyStoreImpl> impleme
         }
         catch (GeneralSecurityException | IOException e)
         {
-            result = Collections.emptyList();
+            throw new IllegalConfigurationException(String.format("Cannot instantiate keystore '%s'", getName()), e);
         }
         _certificates = result;
     }
@@ -275,6 +275,12 @@ public class FileKeyStoreImpl extends AbstractKeyStore<FileKeyStoreImpl> impleme
         return _useHostNameMatching;
     }
 
+    @Override
+    public void reload()
+    {
+        initialize();
+    }
+
     public void setPassword(String password)
     {
         _password = password;
diff --git a/broker-core/src/main/java/org/apache/qpid/server/security/FileTrustStore.java b/broker-core/src/main/java/org/apache/qpid/server/security/FileTrustStore.java
index a8e1975..6842130 100644
--- a/broker-core/src/main/java/org/apache/qpid/server/security/FileTrustStore.java
+++ b/broker-core/src/main/java/org/apache/qpid/server/security/FileTrustStore.java
@@ -28,6 +28,7 @@ import org.apache.qpid.server.model.DerivedAttribute;
 import org.apache.qpid.server.model.ManagedAttribute;
 import org.apache.qpid.server.model.ManagedContextDefault;
 import org.apache.qpid.server.model.ManagedObject;
+import org.apache.qpid.server.model.ManagedOperation;
 import org.apache.qpid.server.model.TrustStore;
 
 @ManagedObject( category = false, type = "FileTrustStore" )
@@ -69,4 +70,7 @@ public interface FileTrustStore<X extends FileTrustStore<X>> extends TrustStore<
     String getPassword();
 
     void setPassword(String password);
+
+    @ManagedOperation( description = "Reloads trust store.", changesConfiguredObjectState = true)
+    void reload();
 }
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 c503801..508e464 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
@@ -236,6 +236,12 @@ public class FileTrustStoreImpl extends AbstractTrustStore<FileTrustStoreImpl> i
     }
 
     @Override
+    public void reload()
+    {
+        initialize();
+    }
+
+    @Override
     protected TrustManager[] getTrustManagersInternal()
     {
         TrustManager[] trustManagers = _trustManagers;
@@ -287,8 +293,10 @@ public class FileTrustStoreImpl extends AbstractTrustStore<FileTrustStoreImpl> i
         try
         {
             KeyStore ts = initializeKeyStore(this);
-            _trustManagers = createTrustManagers(ts);
-            _certificates = createCertificates(ts);
+            TrustManager[] trustManagers = createTrustManagers(ts);
+            Certificate[] certificates = createCertificates(ts);
+            _trustManagers = trustManagers;
+            _certificates = certificates;
         }
         catch (Exception e)
         {
diff --git a/broker-core/src/test/java/org/apache/qpid/server/security/FileKeyStoreTest.java b/broker-core/src/test/java/org/apache/qpid/server/security/FileKeyStoreTest.java
index 3d75ac0..18b2d37 100644
--- a/broker-core/src/test/java/org/apache/qpid/server/security/FileKeyStoreTest.java
+++ b/broker-core/src/test/java/org/apache/qpid/server/security/FileKeyStoreTest.java
@@ -23,16 +23,23 @@ package org.apache.qpid.server.security;
 import static org.apache.qpid.server.security.FileTrustStoreTest.SYMMETRIC_KEY_KEYSTORE_RESOURCE;
 import static org.apache.qpid.server.security.FileTrustStoreTest.createDataUrlForFile;
 import static org.apache.qpid.test.utils.TestSSLConstants.JAVA_KEYSTORE_TYPE;
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.is;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeThat;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
+import java.io.File;
 import java.net.URL;
+import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 import javax.net.ssl.KeyManager;
@@ -49,7 +56,9 @@ import org.apache.qpid.server.model.BrokerModel;
 import org.apache.qpid.server.model.ConfiguredObjectFactory;
 import org.apache.qpid.server.model.KeyStore;
 import org.apache.qpid.server.model.Model;
+import org.apache.qpid.server.transport.network.security.ssl.SSLUtil;
 import org.apache.qpid.server.util.DataUrlUtils;
+import org.apache.qpid.test.utils.TestFileUtils;
 import org.apache.qpid.test.utils.TestSSLConstants;
 import org.apache.qpid.test.utils.UnitTestBase;
 
@@ -401,4 +410,57 @@ public class FileKeyStoreTest extends UnitTestBase
 
     }
 
+    @Test
+    public void testReloadKeystore() throws Exception
+    {
+        assumeThat(SSLUtil.canGenerateCerts(), is(equalTo(true)));
+
+        final SSLUtil.KeyCertPair selfSigned1 = KeystoreTestHelper.generateSelfSigned("CN=foo");
+        final SSLUtil.KeyCertPair selfSigned2 = KeystoreTestHelper.generateSelfSigned("CN=bar");
+
+        final File keyStoreFile = TestFileUtils.createTempFile(this, ".ks");
+        final String dummy = "changit";
+        final char[] pass = dummy.toCharArray();
+        final String certificateAlias = "test1";
+        final String keyAlias = "test2";
+        try
+        {
+            final java.security.KeyStore keyStore =
+                    KeystoreTestHelper.saveKeyStore(selfSigned1, certificateAlias, keyAlias, pass, keyStoreFile);
+
+            final Map<String, Object> attributes = new HashMap<>();
+            attributes.put(FileKeyStore.NAME, getTestName());
+            attributes.put(FileKeyStore.STORE_URL, keyStoreFile.getAbsolutePath());
+            attributes.put(FileKeyStore.PASSWORD, dummy);
+            attributes.put(FileKeyStore.KEY_STORE_TYPE, keyStore.getType());
+
+            final FileKeyStore keyStoreObject = (FileKeyStore) _factory.create(KeyStore.class, attributes, _broker);
+
+            final CertificateDetails certificate = getCertificate(keyStoreObject);
+            assertEquals("CN=foo", certificate.getIssuerName());
+
+            assertTrue(keyStoreFile.delete());
+            assertTrue(keyStoreFile.createNewFile());keyStoreFile.deleteOnExit();
+            KeystoreTestHelper.saveKeyStore(selfSigned2, certificateAlias, keyAlias, pass, keyStoreFile);
+
+            keyStoreObject.reload();
+
+            final CertificateDetails certificate2 = getCertificate(keyStoreObject);
+            assertEquals("CN=bar", certificate2.getIssuerName());
+        }
+        finally
+        {
+            assertTrue(keyStoreFile.delete());
+        }
+    }
+
+    public CertificateDetails getCertificate(final FileKeyStore keyStore) throws java.security.GeneralSecurityException
+    {
+        final List<CertificateDetails> certificates = keyStore.getCertificateDetails();
+
+        assertNotNull(certificates);
+        assertEquals(1, certificates.size());
+
+        return certificates.get(0);
+    }
 }
diff --git a/broker-core/src/test/java/org/apache/qpid/server/security/FileTrustStoreTest.java b/broker-core/src/test/java/org/apache/qpid/server/security/FileTrustStoreTest.java
index 4e99790..427e0b7 100644
--- a/broker-core/src/test/java/org/apache/qpid/server/security/FileTrustStoreTest.java
+++ b/broker-core/src/test/java/org/apache/qpid/server/security/FileTrustStoreTest.java
@@ -66,7 +66,9 @@ import org.apache.qpid.server.model.ConfiguredObjectFactory;
 import org.apache.qpid.server.model.Model;
 import org.apache.qpid.server.model.TrustStore;
 import org.apache.qpid.server.transport.network.security.ssl.QpidPeersOnlyTrustManager;
+import org.apache.qpid.server.transport.network.security.ssl.SSLUtil;
 import org.apache.qpid.server.util.DataUrlUtils;
+import org.apache.qpid.test.utils.TestFileUtils;
 import org.apache.qpid.test.utils.TestSSLConstants;
 import org.apache.qpid.test.utils.UnitTestBase;
 
@@ -444,6 +446,59 @@ public class FileTrustStoreTest extends UnitTestBase
                             (long) certificates.length);
     }
 
+    @Test
+    public void testReloadKeystore() throws Exception
+    {
+        assumeThat(SSLUtil.canGenerateCerts(), is(equalTo(true)));
+
+        final SSLUtil.KeyCertPair selfSigned1 = KeystoreTestHelper.generateSelfSigned("CN=foo");
+        final SSLUtil.KeyCertPair selfSigned2 = KeystoreTestHelper.generateSelfSigned("CN=bar");
+
+        final File keyStoreFile = TestFileUtils.createTempFile(this, ".ks");
+        final String dummy = "changit";
+        final char[] pass = dummy.toCharArray();
+        final String alias = "test";
+        try
+        {
+            final java.security.KeyStore keyStore =
+                    KeystoreTestHelper.saveKeyStore(alias, selfSigned1.getCertificate(), pass, keyStoreFile);
+
+            final Map<String, Object> attributes = new HashMap<>();
+            attributes.put(FileTrustStore.NAME, getTestName());
+            attributes.put(FileTrustStore.PASSWORD, dummy);
+            attributes.put(FileTrustStore.STORE_URL, keyStoreFile.getAbsolutePath());
+            attributes.put(FileTrustStore.TRUST_STORE_TYPE, keyStore.getType());
+
+            final FileTrustStore trustStore = (FileTrustStore) _factory.create(TrustStore.class, attributes, _broker);
+
+            final X509Certificate certificate = getCertificate(trustStore);
+            assertEquals("CN=foo", certificate.getIssuerX500Principal().getName());
+
+            KeystoreTestHelper.saveKeyStore(alias, selfSigned2.getCertificate(), pass, keyStoreFile);
+
+            trustStore.reload();
+
+            final X509Certificate certificate2 = getCertificate(trustStore);
+            assertEquals("CN=bar", certificate2.getIssuerX500Principal().getName());
+        }
+        finally
+        {
+            assertTrue(keyStoreFile.delete());
+        }
+    }
+
+    public X509Certificate getCertificate(final FileTrustStore trustStore) throws java.security.GeneralSecurityException
+    {
+        Certificate[] certificates = trustStore.getCertificates();
+
+        assertNotNull(certificates);
+        assertEquals(1, certificates.length);
+
+        Certificate certificate = certificates[0];
+        assertTrue(certificate instanceof X509Certificate);
+        return (X509Certificate)certificate;
+    }
+
     private int getNumberOfCertificates(URL url, String type) throws Exception
     {
         KeyStore ks = KeyStore.getInstance(type);
diff --git a/broker-core/src/test/java/org/apache/qpid/server/security/KeystoreTestHelper.java b/broker-core/src/test/java/org/apache/qpid/server/security/KeystoreTestHelper.java
new file mode 100644
index 0000000..6278f33
--- /dev/null
+++ b/broker-core/src/test/java/org/apache/qpid/server/security/KeystoreTestHelper.java
@@ -0,0 +1,114 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.qpid.server.security;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.time.Duration;
+import java.time.Instant;
+import java.time.temporal.ChronoUnit;
+import java.util.Collections;
+
+import org.apache.qpid.server.transport.network.security.ssl.SSLUtil;
+
+public class KeystoreTestHelper
+{
+    public static KeyStore saveKeyStore(final String alias,
+                                        final X509Certificate certificate,
+                                        final char[] pass,
+                                        final File file)
+            throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException
+    {
+        final KeyStore ks = createEmptyKeyStore();
+        ks.setCertificateEntry(alias, certificate);
+        saveKeyStore(ks, pass, file);
+        return ks;
+    }
+
+    public static KeyStore saveKeyStore(final SSLUtil.KeyCertPair keyCertPair,
+                                        final String keyAlias,
+                                        final String certificateAlias,
+                                        final char[] pass,
+                                        final File file)
+            throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException
+    {
+        final KeyStore ks = createKeyStore(keyCertPair, keyAlias, certificateAlias, pass);
+        saveKeyStore(ks, pass, file);
+        return ks;
+    }
+
+
+    public static SSLUtil.KeyCertPair generateSelfSigned(final String cn)
+            throws IllegalAccessException, InvocationTargetException, InstantiationException
+    {
+        return SSLUtil.generateSelfSignedCertificate("RSA",
+                                                     "SHA256WithRSA",
+                                                     2048,
+                                                     Instant.now()
+                                                            .minus(1, ChronoUnit.DAYS)
+                                                            .toEpochMilli(),
+                                                     Duration.of(365, ChronoUnit.DAYS)
+                                                             .getSeconds(),
+                                                     cn,
+                                                     Collections.emptySet(),
+                                                     Collections.emptySet());
+    }
+
+
+    private static File saveKeyStore(final KeyStore ks, final char[] pass, final File storeFile)
+            throws IOException, KeyStoreException, NoSuchAlgorithmException, CertificateException
+    {
+        try (FileOutputStream fos = new FileOutputStream(storeFile))
+        {
+            ks.store(fos, pass);
+        }
+        return storeFile;
+    }
+
+    private static KeyStore createKeyStore(final SSLUtil.KeyCertPair keyCertPair,
+                                           final String keyAlias,
+                                           final String certificateAlias,
+                                           final char[] pass)
+            throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException
+    {
+        final KeyStore ks = createEmptyKeyStore();
+        ks.setCertificateEntry(certificateAlias, keyCertPair.getCertificate());
+        ks.setKeyEntry(keyAlias,
+                       keyCertPair.getPrivateKey(),
+                       pass,
+                       new X509Certificate[]{keyCertPair.getCertificate()});
+        return ks;
+    }
+
+    private static KeyStore createEmptyKeyStore()
+            throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException
+    {
+        final KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
+        ks.load(null);
+        return ks;
+    }
+}
diff --git a/broker-plugins/management-http/src/main/java/resources/js/qpid/management/store/filekeystore/show.js b/broker-plugins/management-http/src/main/java/resources/js/qpid/management/store/filekeystore/show.js
index 267f2ae..90253f8 100644
--- a/broker-plugins/management-http/src/main/java/resources/js/qpid/management/store/filekeystore/show.js
+++ b/broker-plugins/management-http/src/main/java/resources/js/qpid/management/store/filekeystore/show.js
@@ -17,7 +17,16 @@
  * under the License.
  */
 
-define(["qpid/common/util", "dojo/domReady!"], function (util)
+define(["dojo/_base/lang",
+        "qpid/common/util",
+        "dojo/query",
+        "dojo/mouse",
+        "dojo/on",
+        "dijit/registry",
+        "dijit/Tooltip",
+        "dijit/form/Button",
+        "dojo/domReady!"],
+    function (lang, util, query, mouse, on, registry, Tooltip)
 {
 
     function FileKeyStoreProvider(data)
@@ -28,13 +37,56 @@ define(["qpid/common/util", "dojo/domReady!"], function (util)
         {
             this.fields.push(name);
         }
-        util.buildUI(data.containerNode, data.parent, "store/filekeystore/show.html", this.fields, this);
+
+        this.parent = data.parent;
+        this.management = data.parent.management;
+        this.modelObj = data.parent.modelObj;
+        this.containerNode = data.containerNode;
+
+        util.buildUI(data.containerNode,
+                     data.parent,
+                    "store/filekeystore/show.html",
+                     this.fields,
+                     this,
+                     lang.hitch(this, function(){
+                         this.reloadButton = registry.byNode(query(".reload", data.containerNode)[0]);
+                         this.reloadButton.on("click", lang.hitch(this, this.reload));
+                     }));
     }
 
     FileKeyStoreProvider.prototype.update = function (data)
     {
         util.updateUI(data, this.fields, this);
-    }
+    };
+
+    FileKeyStoreProvider.prototype.reload = function (evt)
+    {
+        evt.preventDefault();
+        evt.stopPropagation();
+        this.reloadButton.set("disabled", true);
+        var parentModelObj = this.modelObj;
+        var modelObj = {
+            type: parentModelObj.type,
+            name: "reload",
+            parent: parentModelObj
+        };
+        var url = this.management.buildObjectURL(modelObj);
+        this.management.post({url: url}, {})
+            .then(lang.hitch(this, function () {
+                    this.parent.update();
+                    var domNode = this.reloadButton.domNode;
+                    Tooltip.show("Keystore is reloaded successfully", domNode);
+                    on.once(domNode, mouse.leave, function()
+                    {
+                        Tooltip.hide(domNode);
+                    });
+            }),
+            this.management.xhrErrorHandler)
+            .always(lang.hitch(this, function ()
+            {
+                this.reloadButton.set("disabled", false);
+            }));
+    };
 
     return FileKeyStoreProvider;
 });
diff --git a/broker-plugins/management-http/src/main/java/resources/js/qpid/management/store/filetruststore/show.js b/broker-plugins/management-http/src/main/java/resources/js/qpid/management/store/filetruststore/show.js
index 83e0d37..7638bfc 100644
--- a/broker-plugins/management-http/src/main/java/resources/js/qpid/management/store/filetruststore/show.js
+++ b/broker-plugins/management-http/src/main/java/resources/js/qpid/management/store/filetruststore/show.js
@@ -17,7 +17,16 @@
  * under the License.
  */
 
-define(["qpid/common/util", "dojo/domReady!"], function (util)
+define(["dojo/_base/lang",
+        "qpid/common/util",
+        "dojo/query",
+        "dojo/mouse",
+        "dojo/on",
+        "dijit/registry",
+        "dijit/Tooltip",
+        "dijit/form/Button",
+        "dojo/domReady!"],
+    function (lang, util, query, mouse, on, registry, Tooltip)
 {
 
     function FileTrustStoreProvider(data)
@@ -28,13 +37,56 @@ define(["qpid/common/util", "dojo/domReady!"], function (util)
         {
             this.fields.push(name);
         }
-        util.buildUI(data.containerNode, data.parent, "store/filetruststore/show.html", this.fields, this);
+
+        this.parent = data.parent;
+        this.management = data.parent.management;
+        this.modelObj = data.parent.modelObj;
+        this.containerNode = data.containerNode;
+
+        util.buildUI(data.containerNode,
+                     data.parent,
+                    "store/filetruststore/show.html",
+                     this.fields,
+                     this,
+                     lang.hitch(this, function(){
+                         this.reloadButton = registry.byNode(query(".reload", data.containerNode)[0]);
+                         this.reloadButton.on("click", lang.hitch(this, this.reload));
+                     }));
     }
 
     FileTrustStoreProvider.prototype.update = function (data)
     {
         util.updateUI(data, this.fields, this);
-    }
+    };
+
+    FileTrustStoreProvider.prototype.reload = function (evt)
+    {
+        evt.preventDefault();
+        evt.stopPropagation();
+        this.reloadButton.set("disabled", true);
+        var parentModelObj = this.modelObj;
+        var modelObj = {
+            type: parentModelObj.type,
+            name: "reload",
+            parent: parentModelObj
+        };
+        var url = this.management.buildObjectURL(modelObj);
+        this.management.post({url: url}, {})
+            .then(lang.hitch(this, function () {
+                this.parent.update();
+                var domNode = this.reloadButton.domNode;
+                Tooltip.show("Truststore is reloaded successfully", domNode);
+                on.once(domNode, mouse.leave, function()
+                {
+                    Tooltip.hide(domNode);
+                });
+            }),
+            this.management.xhrErrorHandler)
+            .always(lang.hitch(this, function ()
+            {
+                this.reloadButton.set("disabled", false);
+            }));
+    };
 
     return FileTrustStoreProvider;
 });
diff --git a/broker-plugins/management-http/src/main/java/resources/store/filekeystore/show.html b/broker-plugins/management-http/src/main/java/resources/store/filekeystore/show.html
index 74284e5..a7c5540 100644
--- a/broker-plugins/management-http/src/main/java/resources/store/filekeystore/show.html
+++ b/broker-plugins/management-http/src/main/java/resources/store/filekeystore/show.html
@@ -38,6 +38,9 @@
         <div class="formLabel-labelCell">Use SNI host name matching:</div>
         <div><span class="useHostNameMatching" ></span></div>
     </div>
+    <div class="clear">
+        <button data-dojo-type="dijit/form/Button" class="reload">Reload</button>
+    </div>
     <div class="clear"></div>
 </div>
 
diff --git a/broker-plugins/management-http/src/main/java/resources/store/filetruststore/show.html b/broker-plugins/management-http/src/main/java/resources/store/filetruststore/show.html
index 99190d1..f936e56 100644
--- a/broker-plugins/management-http/src/main/java/resources/store/filetruststore/show.html
+++ b/broker-plugins/management-http/src/main/java/resources/store/filetruststore/show.html
@@ -34,6 +34,9 @@
         <div class="formLabel-labelCell">Trust manager factory algorithm:</div>
         <div><span class="trustManagerFactoryAlgorithm" ></span></div>
     </div>
+    <div class="clear">
+        <button data-dojo-type="dijit/form/Button" class="reload">Reload</button>
+    </div>
     <div class="clear"></div>
 </div>
 


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