summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Gemmell <robbie@apache.org>2013-04-12 16:16:09 +0000
committerRobert Gemmell <robbie@apache.org>2013-04-12 16:16:09 +0000
commit249369d22526b77b3ffa4c456854b55c287cfd7b (patch)
treed3706c9c525d196e824d1fdd51873ec275295eae
parent332410c66c62d5e075e9f9077d29fc4669e11db0 (diff)
downloadqpid-python-249369d22526b77b3ffa4c456854b55c287cfd7b.tar.gz
QPID-4739: complete support for defining multiple key/trust stores and assigning them on a port-specific basis
git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1467334 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagement.java5
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/addAuthenticationProvider.html10
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/addBinding.html5
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/addExchange.html5
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/addPort.html51
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/addQueue.html8
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/addVirtualHost.html3
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/index.html1
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/util.js74
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Broker.js161
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/KeyStore.js160
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/TrustStore.js160
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addAuthenticationProvider.js2
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addKeystore.js164
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addPort.js232
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/controller.js6
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/treeView.js5
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/showBroker.html26
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/showKeyStore.html47
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/showTrustStore.html47
-rw-r--r--qpid/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/JMXManagedObjectRegistry.java53
-rw-r--r--qpid/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/QpidSslRMIServerSocketFactory.java85
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/startup/BrokerRecoverer.java68
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/model/Broker.java32
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/model/KeyStore.java22
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/model/Port.java10
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/model/TrustStore.java8
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/AbstractAdapter.java49
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/AbstractKeyStoreAdapter.java51
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/AmqpPortAdapter.java14
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/BrokerAdapter.java291
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/KeyStoreAdapter.java175
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/PortAdapter.java85
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/PortFactory.java14
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/TrustStoreAdapter.java151
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/util/MapValueConverter.java6
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/startup/KeyStoreRecovererTest.java59
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/startup/TrustStoreRecovererTest.java50
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/store/ConfigurationEntryStoreTestCase.java2
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/model/adapter/PortFactoryTest.java86
-rw-r--r--qpid/java/common/src/main/java/org/apache/qpid/ssl/SSLContextFactory.java2
-rw-r--r--qpid/java/common/src/test/java/org/apache/qpid/test/utils/TestSSLConstants.java (renamed from qpid/java/systests/src/main/java/org/apache/qpid/test/utils/TestSSLConstants.java)6
-rw-r--r--qpid/java/systests/etc/config-systests.json14
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/client/ssl/SSLTest.java2
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationTest.java109
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/server/security/auth/manager/MultipleAuthenticationManagersTest.java2
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/ManagementLoggingTest.java6
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/Asserts.java4
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/BasicAuthRestTest.java2
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/BrokerRestHttpsTest.java4
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/BrokerRestTest.java24
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/KeyStoreRestTest.java269
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/PortRestTest.java16
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/TrustStoreRestTest.java261
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/test/utils/JMXTestUtils.java4
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/test/utils/TestBrokerConfiguration.java16
56 files changed, 2523 insertions, 701 deletions
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagement.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagement.java
index 2f51e30b57..3cc382596a 100644
--- a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagement.java
+++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagement.java
@@ -62,6 +62,7 @@ import org.apache.qpid.server.model.Protocol;
import org.apache.qpid.server.model.Queue;
import org.apache.qpid.server.model.Session;
import org.apache.qpid.server.model.State;
+import org.apache.qpid.server.model.TrustStore;
import org.apache.qpid.server.model.User;
import org.apache.qpid.server.model.VirtualHost;
import org.apache.qpid.server.model.adapter.AbstractPluginAdapter;
@@ -240,7 +241,7 @@ public class HttpManagement extends AbstractPluginAdapter implements HttpManagem
}
else if (protocols.contains(Protocol.HTTPS))
{
- KeyStore keyStore = _broker.getDefaultKeyStore();
+ KeyStore keyStore = port.getKeyStore();
if (keyStore == null)
{
throw new IllegalConfigurationException("Key store is not configured. Cannot start management on HTTPS port without keystore");
@@ -290,6 +291,8 @@ public class HttpManagement extends AbstractPluginAdapter implements HttpManagem
addRestServlet(root, "binding", VirtualHost.class, Exchange.class, Queue.class, Binding.class);
addRestServlet(root, "port", Port.class);
addRestServlet(root, "session", VirtualHost.class, Connection.class, Session.class);
+ addRestServlet(root, "keystore", KeyStore.class);
+ addRestServlet(root, "truststore", TrustStore.class);
root.addServlet(new ServletHolder(new StructureServlet()), "/rest/structure");
root.addServlet(new ServletHolder(new MessageServlet()), "/rest/message/*");
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/addAuthenticationProvider.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/addAuthenticationProvider.html
index 90dd1f1090..f4846ac556 100644
--- a/qpid/java/broker-plugins/management-http/src/main/java/resources/addAuthenticationProvider.html
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/addAuthenticationProvider.html
@@ -15,15 +15,16 @@
~ limitations under the License.
-->
<div class="dijitHidden">
- <div data-dojo-type="dijit.Dialog" style="width:600px;" data-dojo-props="title:'Authentication Provider'" id="addAuthenticationProvider">
+ <div data-dojo-type="dijit.Dialog" data-dojo-props="title:'Authentication Provider'" id="addAuthenticationProvider">
<form id="formAddAuthenticationProvider" method="post" dojoType="dijit.form.Form">
+ <div style="height:100px; width:420px; overflow: auto">
<table class="tableContainer-table tableContainer-table-horiz" width="100%" cellspacing="1">
<tr>
- <td class="tableContainer-labelCell" style="width: 300px;">Type*:</td>
+ <td class="tableContainer-labelCell" style="width: 200px;">Type*:</td>
<td class="tableContainer-valueCell"><div id="addAuthenticationProvider.selectAuthenticationProviderDiv"></div></td>
</tr>
<tr>
- <td class="tableContainer-labelCell" style="width: 300px;">Name*:</td>
+ <td class="tableContainer-labelCell" style="width: 200px;">Name*:</td>
<td class="tableContainer-valueCell"><input type="text" required="true" name="name"
id="formAddAuthenticationProvider.name" placeholder="Name" regexp="^[\x20-\x2e\x30-\x7F]{1,255}$"
dojoType="dijit.form.ValidationTextBox" missingMessage="A name must be supplied" /></div></td>
@@ -31,8 +32,11 @@
</table>
<input type="hidden" id="formAddAuthenticationProvider.id" name="id"/>
<div id="addAuthenticationProvider.fieldSets"></div>
+ </div>
+ <div class="dijitDialogPaneActionBar">
<!-- submit buttons -->
<input type="submit" value="Save Authentication Provider" label="Save Authentication Provider" dojoType="dijit.form.Button" />
+ </div>
</form>
</div>
</div>
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/addBinding.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/addBinding.html
index 8dbd219c8d..9aebca90d7 100644
--- a/qpid/java/broker-plugins/management-http/src/main/java/resources/addBinding.html
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/addBinding.html
@@ -32,11 +32,10 @@
dojoType="dijit.form.ValidationTextBox" missingMessage="A name must be supplied" /></td>
</tr>
</table>
- <br/>
-
+ <div class="dijitDialogPaneActionBar">
<!-- submit buttons -->
<input type="submit" value="Create Binding" label="Create Binding" dojoType="dijit.form.Button" />
-
+ </div>
</form>
</div>
</div>
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/addExchange.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/addExchange.html
index 4a59cd2cbc..8c9968e37a 100644
--- a/qpid/java/broker-plugins/management-http/src/main/java/resources/addExchange.html
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/addExchange.html
@@ -44,11 +44,10 @@
</td>
</tr>
</table>
- <br/>
-
+ <div class="dijitDialogPaneActionBar">
<!-- submit buttons -->
<input type="submit" value="Create Exchange" label="Create Exchange" dojoType="dijit.form.Button" />
-
+ </div>
</form>
</div>
</div>
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/addPort.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/addPort.html
index c37b879bd5..391783c6d8 100644
--- a/qpid/java/broker-plugins/management-http/src/main/java/resources/addPort.html
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/addPort.html
@@ -19,9 +19,9 @@
-
-->
<div class="dijitHidden">
- <div data-dojo-type="dijit.Dialog" style="width:600px;" data-dojo-props="title:'Port'" id="addPort">
+ <div data-dojo-type="dijit.Dialog" data-dojo-props="title:'Port'" id="addPort">
<form id="formAddPort" method="post" dojoType="dijit.form.Form">
- <div class="dijitDialogPaneContentArea">
+ <div style="height:320px; width:420px; overflow: auto">
<div id="formAddPort:fields">
<input type="text" required="true" name="name" id="formAddPort.name" placeholder="Name"
data-dojo-props="label: 'Name*:'" dojoType="dijit.form.ValidationTextBox"
@@ -29,13 +29,7 @@
<input data-dojo-type="dijit.form.NumberSpinner" id="formAddPort.port" required="true" data-dojo-props="label: 'Port Number*:'"
name="port" smallDelta="1" constraints="{min:1,max:65535,places:0, pattern: '#####'}"
missingMessage="A port number must be supplied" />
- <select id="formAddPort.transports" data-dojo-type="dijit.form.FilteringSelect"
- data-dojo-props="name: 'transports',label: 'Transport:',searchAttr: 'name',required:false,placeHolder: 'TCP', value: '' "
- style="margin: 0;">
- <option value="TCP">TCP</option>
- <option value="SSL">SSL</option>
- </select>
- <select id="formAddPort.authenticationProvider" data-dojo-type="dijit.form.FilteringSelect" style="margin: 0;"
+ <select id="formAddPort.authenticationProvider" data-dojo-type="dijit.form.FilteringSelect"
data-dojo-props="name:'authenticationProvider',label:'Authentication Provider:', searchAttr: 'name', required: false, placeHolder: 'Default', value: '' ">
</select>
<select id="formAddPort.type" data-dojo-type="dijit.form.FilteringSelect"
@@ -45,17 +39,11 @@
<option value="HTTP">HTTP</option>
</select>
</div>
- <div id="formAddPort:fieldsClientAuth">
- <input id="formAddPort.needClientAuth" type="checkbox" name="needClientAuth"
- dojoType="dijit.form.CheckBox" data-dojo-props="label: 'Need SSL Client Certificate:'"/>
- <input id="formAddPort.wantClientAuth" type="checkbox" name="wantClientAuth"
- dojoType="dijit.form.CheckBox" data-dojo-props="label: 'Want SSL Client Certificate:'"/>
- </div>
<div id="formAddPort:fieldsAMQP">
<input id="formAddPort.bindingAddress" type="text" name="bindingAddress" placeholder="*"
dojoType="dijit.form.TextBox" data-dojo-props="label: 'Binding address:'"/>
<input id="formAddPort.protocolsDefault" type="checkbox" checked="checked"
- dojoType="dijit.form.CheckBox" data-dojo-props="label: 'Support broker default AMQP versions:'"/>
+ dojoType="dijit.form.CheckBox" data-dojo-props="label: 'Support default protocols:'"/>
<select id="formAddPort.protocolsAMQP" name="protocols" data-dojo-type="dijit.form.MultiSelect" multiple="true"
data-dojo-props="name: 'protocols', value: '', placeHolder: 'Select AMQP versions', label: 'AMQP versions:'"
missingMessage="AMQP protocol(s) must be supplied">
@@ -80,6 +68,37 @@
<option value="HTTPS">HTTPS</option>
</select>
</div>
+ <div id="formAddPort:transport" >
+ <select id="formAddPort.transports" data-dojo-type="dijit.form.FilteringSelect"
+ data-dojo-props="name: 'transports',label: 'Transport:',searchAttr: 'name',required:false,placeHolder: 'TCP', value: '' "
+ style="margin: 0;">
+ <option value="TCP">TCP</option>
+ <option value="SSL">SSL</option>
+ </select>
+ </div>
+ <div id="formAddPort:fieldsTransportSSL">
+ <select id="formAddPort.keyStore" data-dojo-type="dijit.form.FilteringSelect"
+ data-dojo-props="name:'keyStore',label:'Key Store*:', searchAttr: 'name', placeHolder: 'Select keystore', value: '', required: true ">
+ </select>
+ </div>
+ <div id="formAddPort:fieldsClientAuth">
+ <div id="formAddPort:fieldsClientAuth2">
+ <input id="formAddPort.needClientAuth" type="checkbox" name="needClientAuth"
+ dojoType="dijit.form.CheckBox" data-dojo-props="label: 'Need SSL Client Certificate:'" />
+ <input id="formAddPort.wantClientAuth" type="checkbox" name="wantClientAuth"
+ dojoType="dijit.form.CheckBox" data-dojo-props="label: 'Want SSL Client Certificate:'" />
+ </div>
+ <div><strong>Trust Stores:</strong></div>
+ <table id="formAddPort.trustStores" data-dojo-type="dojox.grid.EnhancedGrid"
+ data-dojo-props="label:'Trust Stores:',plugins:{indirectSelection: true},rowSelector:'0px' " style="height: 100px">
+ <thead>
+ <tr>
+ <th field="name">Name</th>
+ <th field="peersOnly">Peers Only</th>
+ </tr>
+ </thead>
+ </table>
+ </div>
<input type="hidden" id="formAddPort.id" name="id"/>
</div>
<div class="dijitDialogPaneActionBar">
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/addQueue.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/addQueue.html
index 950809d5fc..90a0af7ea9 100644
--- a/qpid/java/broker-plugins/management-http/src/main/java/resources/addQueue.html
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/addQueue.html
@@ -19,8 +19,9 @@
-
-->
<div class="dijitHidden">
- <div data-dojo-type="dijit.Dialog" style="width:600px;" data-dojo-props="title:'Add Queue'" id="addQueue">
+ <div data-dojo-type="dijit.Dialog" data-dojo-props="title:'Add Queue'" id="addQueue">
<form id="formAddQueue" method="post" dojoType="dijit.form.Form">
+ <div style="height:250px; width:600px; overflow: auto">
<table cellpadding="0" cellspacing="2">
<tr>
<td valign="top"><strong>Queue Name*: </strong></td>
@@ -173,10 +174,11 @@
</tr>
</table>
</div>
- <br/>
+ </div>
+ <div class="dijitDialogPaneActionBar">
<!-- submit buttons -->
<input type="submit" value="Create Queue" label="Create Queue" dojoType="dijit.form.Button" />
-
+ </div>
</form>
</div>
</div>
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/addVirtualHost.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/addVirtualHost.html
index 9b492ef26d..43281f600d 100644
--- a/qpid/java/broker-plugins/management-http/src/main/java/resources/addVirtualHost.html
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/addVirtualHost.html
@@ -62,10 +62,11 @@
</div>
</div>
- <br/>
+ <div class="dijitDialogPaneActionBar">
<!-- submit buttons -->
<input type="submit" value="Save" label="Save" dojoType="dijit.form.Button" />
<input type="hidden" id="formAddVirtualHost.id" name="id"/>
+ </div>
</form>
</div>
</div>
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/index.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/index.html
index a9cb580103..c4fbe77b08 100644
--- a/qpid/java/broker-plugins/management-http/src/main/java/resources/index.html
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/index.html
@@ -24,6 +24,7 @@
<link rel="stylesheet" href="dojo/dojox/grid/resources/claroGrid.css">
<link rel="stylesheet" href="dojo/dojox/grid/enhanced/resources/claro/EnhancedGrid.css">
<link rel="stylesheet" href="dojo/dojox/grid/enhanced/resources/EnhancedGrid_rtl.css">
+ <link rel="stylesheet" href="dojo/dojox/form/resources/CheckedMultiSelect.css">
<link rel="stylesheet" href="css/common.css" media="screen">
<script>
function getContextPath()
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/util.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/util.js
index 5ff208d43f..77ae1ccf47 100644
--- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/util.js
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/util.js
@@ -33,7 +33,7 @@ define(["dojo/_base/xhr",
"dijit/form/RadioButton",
"dijit/form/CheckBox",
"dojox/layout/TableContainer",
- "dojox/layout/ScrollPane",
+ "dijit/layout/ContentPane",
"dojox/validate/us",
"dojox/validate/web",
"dojo/domReady!"
@@ -141,7 +141,7 @@ define(["dojo/_base/xhr",
return (type === "PlainPasswordFile" || type === "Base64MD5PasswordFile");
};
- util.showSetAttributesDialog = function(attributeWidgetFactories, data, putURL, dialogTitle)
+ util.showSetAttributesDialog = function(attributeWidgetFactories, data, putURL, dialogTitle, appendNameToUrl)
{
var layout = new dojox.layout.TableContainer({
cols: 1,
@@ -154,7 +154,7 @@ define(["dojo/_base/xhr",
var form = new dijit.form.Form();
var dialogContent = dom.create("div");
- var dialogContentArea = dom.create("div", { "class": "dijitDialogPaneContentArea"});
+ var dialogContentArea = dom.create("div", {"style": {width: 600}});
var dialogActionBar = dom.create("div", { "class": "dijitDialogPaneActionBar"} );
dialogContent.appendChild(dialogContentArea);
dialogContent.appendChild(dialogActionBar);
@@ -171,11 +171,17 @@ define(["dojo/_base/xhr",
var widget = attributeWidgetFactory.createWidget(data);
var name = attributeWidgetFactory.name ? attributeWidgetFactory.name : widget.name;
widgets[name] = widget;
- widget.initialValue = widget.value;
var dotPos = name.indexOf(".");
if (dotPos == -1)
{
- layout.addChild(widget);
+ if (widget instanceof dijit.layout.ContentPane)
+ {
+ dialogContentArea.appendChild(widget.domNode);
+ }
+ else
+ {
+ layout.addChild(widget);
+ }
}
else
{
@@ -197,7 +203,7 @@ define(["dojo/_base/xhr",
groups[groupName] = groupFieldContainer;
var groupTitle = attributeWidgetFactory.groupName ? attributeWidgetFactory.groupName :
groupName.charAt(0).toUpperCase() + groupName.slice(1);
- var panel = new dijit.TitlePane({title: groupTitle, toggleable: false, content: groupFieldContainer.domNode});
+ var panel = new dijit.TitlePane({title: groupTitle, content: groupFieldContainer.domNode});
dialogContentArea.appendChild(dom.create("br"));
dialogContentArea.appendChild(panel.domNode);
}
@@ -224,8 +230,7 @@ define(["dojo/_base/xhr",
}
var setAttributesDialog = new dijit.Dialog({
title: dialogTitle,
- content: form,
- style: "width: 600px; max-height: 80%"
+ content: form
});
form.on("submit", function(e)
{
@@ -235,23 +240,29 @@ define(["dojo/_base/xhr",
if(form.validate())
{
var values = {};
- for(var i in widgets)
+ var formWidgets = form.getDescendants();
+ for(var i in formWidgets)
{
- var widget = widgets[i];
+ var widget = formWidgets[i];
var value = widget.value;
var propName = widget.name;
- if ((widget instanceof dijit.form.CheckBox || widget instanceof dijit.form.RadioButton))
- {
- values[ propName ] = widget.checked;
- }
- else if (value != widget.initialValue)
- {
- values[ propName ] = value ? value: null;
+ if (propName && !widget.disabled){
+ if ((widget instanceof dijit.form.CheckBox || widget instanceof dijit.form.RadioButton)) {
+ if (widget.checked != widget.initialValue) {
+ values[ propName ] = widget.checked;
+ }
+ } else if (value != widget.initialValue) {
+ values[ propName ] = value ? value: null;
+ }
}
}
var that = this;
- xhr.put({url: putURL, sync: true, handleAs: "json",
+ var url = putURL;
+ if (appendNameToUrl){
+ url = url + "/" + encodeURIComponent(values["name"]);
+ }
+ xhr.put({url: url , sync: true, handleAs: "json",
headers: { "Content-Type": "application/json"},
putData: json.toJson(values),
load: function(x) {that.success = true; },
@@ -280,15 +291,24 @@ define(["dojo/_base/xhr",
});
form.connectChildren(true);
setAttributesDialog.startup();
- setAttributesDialog.on("show", function(){
- var data = geometry.position(dialogContentArea);
- var maxHeight = win.getBox().h * 0.6;
- if (data.h > maxHeight)
- {
- dialogContentArea.style.height = maxHeight + "px";
- dialogContentArea.style.overflow= "auto";
- }
- })
+ var formWidgets = form.getDescendants();
+ var aproximateHeight = 0;
+ for(var i in formWidgets){
+ var widget = formWidgets[i];
+ var propName = widget.name;
+ if (propName) {
+ if ((widget instanceof dijit.form.CheckBox || widget instanceof dijit.form.RadioButton)) {
+ widget.initialValue = widget.checked;
+ } else {
+ widget.initialValue = widget.value;
+ }
+ aproximateHeight += 30;
+ }
+ }
+ var viewport = win.getBox();
+ var maxHeight = Math.max(Math.floor(viewport.h * 0.6), 100);
+ dialogContentArea.style.overflow= "auto";
+ dialogContentArea.style.height = Math.min(aproximateHeight, maxHeight ) + "px";
setAttributesDialog.show();
};
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Broker.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Broker.js
index 04ac80784a..b07b68c835 100644
--- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Broker.js
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Broker.js
@@ -31,6 +31,7 @@ define(["dojo/_base/xhr",
"qpid/management/addAuthenticationProvider",
"qpid/management/addVirtualHost",
"qpid/management/addPort",
+ "qpid/management/addKeystore",
"dojox/grid/enhanced/plugins/Pagination",
"dojox/grid/enhanced/plugins/IndirectSelection",
"dijit/layout/AccordionContainer",
@@ -41,7 +42,7 @@ define(["dojo/_base/xhr",
"dijit/form/CheckBox",
"dojo/store/Memory",
"dojo/domReady!"],
- function (xhr, parser, query, connect, properties, updater, util, UpdatableStore, EnhancedGrid, registry, addAuthenticationProvider, addVirtualHost, addPort) {
+ function (xhr, parser, query, connect, properties, updater, util, UpdatableStore, EnhancedGrid, registry, addAuthenticationProvider, addVirtualHost, addPort, addKeystore) {
function Broker(name, parent, controller) {
this.name = name;
@@ -116,79 +117,6 @@ define(["dojo/_base/xhr",
name: "groupFile"});
}
}, {
- name: "keyStorePath",
- createWidget: function(brokerData) {
- return new dijit.form.ValidationTextBox({
- required: false,
- value: brokerData.keyStorePath,
- label: "Path to keystore:",
- name: "keyStorePath"});
- }
- }, {
- name: "keyStorePassword",
- requiredFor: "keyStorePath",
- createWidget: function(brokerData) {
- return new dijit.form.ValidationTextBox({
- required: false,
- label: "Keystore password:",
- invalidMessage: "Missed keystore password",
- name: "keyStorePassword",
- placeholder: brokerData["keyStorePassword"] ? brokerData["keyStorePassword"] : ""
- });
- }
- }, {
- name: "keyStoreCertAlias",
- createWidget: function(brokerData) {
- return new dijit.form.ValidationTextBox({
- required: false,
- value: brokerData.keyStoreCertAlias,
- label: "Keystore certificate alias:",
- name: "keyStoreCertAlias"});
- }
- }, {
- name: "trustStorePath",
- createWidget: function(brokerData)
- {
- return new dijit.form.ValidationTextBox({
- required: false,
- value: brokerData.trustStorePath,
- label: "Path to truststore:",
- name: "trustStorePath"});
- }
- }, {
- name: "trustStorePassword",
- requiredFor: "trustStorePath",
- createWidget: function(brokerData) {
- return new dijit.form.ValidationTextBox({
- required: false,
- label: "Truststore password:",
- invalidMessage: "Missed trustore password",
- name: "trustStorePassword",
- placeholder: brokerData["trustStorePassword"] ? brokerData["trustStorePassword"] : ""
- });
- }
- }, {
- name: "peerStorePath",
- createWidget: function(brokerData) {
- return new dijit.form.ValidationTextBox({
- required: false,
- value: brokerData.peerStorePath,
- label: "Path to peerstore:",
- name: "peerStorePath"});
- }
- }, {
- name: "peerStorePassword",
- requiredFor: "peerStorePath",
- createWidget: function(brokerData) {
- return new dijit.form.ValidationTextBox({
- required: false,
- label: "Peerstore password:",
- invalidMessage: "Missed peerstore password",
- name: "peerStorePassword",
- placeholder: brokerData["peerStorePassword"] ? brokerData["peerStorePassword"] : ""
- });
- }
- }, {
name: "statisticsReportingPeriod",
createWidget: function(brokerData) {
return new dijit.form.ValidationTextBox({
@@ -488,7 +416,10 @@ define(["dojo/_base/xhr",
);
var addPortButton = query(".addPort", contentPane.containerNode)[0];
- connect.connect(registry.byNode(addPortButton), "onClick", function(evt){ addPort.show(null, that.brokerUpdater.brokerData.authenticationproviders); });
+ connect.connect(registry.byNode(addPortButton), "onClick", function(evt){
+ addPort.show(null, that.brokerUpdater.brokerData.authenticationproviders,
+ that.brokerUpdater.brokerData.keystores, that.brokerUpdater.brokerData.truststores);
+ });
var deletePort = query(".deletePort", contentPane.containerNode)[0];
connect.connect(registry.byNode(deletePort), "onClick",
@@ -512,6 +443,35 @@ define(["dojo/_base/xhr",
}
);
+ var addKeystoreButton = query(".addKeystore", contentPane.containerNode)[0];
+ connect.connect(registry.byNode(addKeystoreButton), "onClick",
+ function(evt){ addKeystore.showKeystoreDialog() });
+
+ var deleteKeystore = query(".deleteKeystore", contentPane.containerNode)[0];
+ connect.connect(registry.byNode(deleteKeystore), "onClick",
+ function(evt){
+ util.deleteGridSelections(
+ that.brokerUpdater,
+ that.brokerUpdater.keyStoresGrid.grid,
+ "rest/keystore",
+ "Are you sure you want to delete key store");
+ }
+ );
+
+ var addTruststoreButton = query(".addTruststore", contentPane.containerNode)[0];
+ connect.connect(registry.byNode(addTruststoreButton), "onClick",
+ function(evt){ addKeystore.showTruststoreDialog() });
+
+ var deleteTruststore = query(".deleteTruststore", contentPane.containerNode)[0];
+ connect.connect(registry.byNode(deleteTruststore), "onClick",
+ function(evt){
+ util.deleteGridSelections(
+ that.brokerUpdater,
+ that.brokerUpdater.trustStoresGrid.grid,
+ "rest/truststore",
+ "Are you sure you want to delete trust store");
+ }
+ );
}});
};
@@ -581,7 +541,7 @@ define(["dojo/_base/xhr",
var idx = evt.rowIndex,
theItem = this.getItem(idx);
var name = obj.dataStore.getValue(theItem,"name");
- addPort.show(name, that.brokerData.authenticationproviders);
+ addPort.show(name, that.brokerData.authenticationproviders, that.brokerData.keystores, that.brokerData.truststores);
});
}, gridProperties, EnhancedGrid);
@@ -615,6 +575,44 @@ define(["dojo/_base/xhr",
});
}, gridProperties, EnhancedGrid);
+ that.keyStoresGrid =
+ new UpdatableStore(that.brokerData.keystores, query(".broker-key-stores")[0],
+ [ { name: "Name", field: "name", width: "20%"},
+ { name: "Path", field: "path", width: "50%"},
+ { name: "Type", field: "type", width: "5%"},
+ { name: "Key Manager Algorithm", field: "keyManagerFactoryAlgorithm", width: "20%"},
+ { name: "Alias", field: "certificateAlias", width: "15%"}
+ ], function(obj) {
+ connect.connect(obj.grid, "onRowDblClick", obj.grid,
+ function(evt){
+ var idx = evt.rowIndex,
+ theItem = this.getItem(idx);
+ var name = obj.dataStore.getValue(theItem,"name");
+ that.controller.show("keystore", name, brokerObj);
+ });
+ }, gridProperties, EnhancedGrid);
+
+ that.trustStoresGrid =
+ new UpdatableStore(that.brokerData.truststores, query(".broker-trust-stores")[0],
+ [ { name: "Name", field: "name", width: "20%"},
+ { name: "Path", field: "path", width: "50%"},
+ { name: "Type", field: "type", width: "5%"},
+ { name: "Trust Manager Algorithm", field: "trustManagerFactoryAlgorithm", width: "20%"},
+ { name: "Peers only", field: "peersOnly", width: "15%",
+ formatter: function(val){
+ return "<input type='radio' disabled='disabled' "+(val ? "checked='checked'": "")+" />";
+ }
+ }
+ ], function(obj) {
+ connect.connect(obj.grid, "onRowDblClick", obj.grid,
+ function(evt){
+ var idx = evt.rowIndex,
+ theItem = this.getItem(idx);
+ var name = obj.dataStore.getValue(theItem,"name");
+ that.controller.show("truststore", name, brokerObj);
+ });
+ }, gridProperties, EnhancedGrid);
+
});
xhr.get({url: "rest/logrecords", sync: properties.useSyncGet, handleAs: "json"})
@@ -699,6 +697,15 @@ define(["dojo/_base/xhr",
that.portsGrid.update(that.brokerData.ports);
that.authenticationProvidersGrid.update(that.brokerData.authenticationproviders);
+
+ if (that.keyStoresGrid)
+ {
+ that.keyStoresGrid.update(that.brokerData.keystores);
+ }
+ if (that.trustStoresGrid)
+ {
+ that.trustStoresGrid.update(that.brokerData.truststores);
+ }
});
@@ -718,7 +725,7 @@ define(["dojo/_base/xhr",
dojo.byId("brokerAttribute.operatingSystem").innerHTML = brokerData.operatingSystem;
dojo.byId("brokerAttribute.platform").innerHTML = brokerData.platform;
dojo.byId("brokerAttribute.productVersion").innerHTML = brokerData.productVersion;
- dojo.byId("brokerAttribute.modelVersion").innerHTML = brokerData.managementVersion;
+ dojo.byId("brokerAttribute.modelVersion").innerHTML = brokerData.modelVersion;
dojo.byId("brokerAttribute.storeType").innerHTML = brokerData.storeType;
dojo.byId("brokerAttribute.storeVersion").innerHTML = brokerData.storeVersion;
dojo.byId("brokerAttribute.storePath").innerHTML = brokerData.storePath;
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/KeyStore.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/KeyStore.js
new file mode 100644
index 0000000000..9702c6b9f6
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/KeyStore.js
@@ -0,0 +1,160 @@
+/*
+ *
+ * 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.
+ *
+ */
+define(["dojo/dom",
+ "dojo/_base/xhr",
+ "dojo/parser",
+ "dojo/query",
+ "dojo/_base/connect",
+ "dijit/registry",
+ "qpid/common/properties",
+ "qpid/common/updater",
+ "qpid/common/util",
+ "qpid/common/formatter",
+ "qpid/management/addKeystore",
+ "dojo/domReady!"],
+ function (dom, xhr, parser, query, connect, registry, properties, updater, util, formatter, addKeystore) {
+
+ function KeyStore(name, parent, controller, objectType) {
+ this.keyStoreName = name;
+ this.controller = controller;
+ this.modelObj = { type: "keystore", name: name };
+ if(parent) {
+ this.modelObj.parent = {};
+ this.modelObj.parent[ parent.type] = parent;
+ }
+ this.url = "rest/keystore/" + encodeURIComponent(name);
+ this.dialog = addKeystore.showKeystoreDialog;
+ }
+
+ KeyStore.prototype.getTitle = function() {
+ return "KeyStore: " + this.keyStoreName;
+ };
+
+ KeyStore.prototype.open = function(contentPane) {
+ var that = this;
+ this.contentPane = contentPane;
+ xhr.get({url: "showKeyStore.html",
+ sync: true,
+ load: function(data) {
+ contentPane.containerNode.innerHTML = data;
+ parser.parse(contentPane.containerNode);
+
+ that.keyStoreUpdater = new KeyStoreUpdater(contentPane.containerNode, that.modelObj, that.controller, that.url);
+
+ updater.add( that.keyStoreUpdater );
+
+ that.keyStoreUpdater.update();
+
+ var deleteKeyStoreButton = query(".deleteKeyStoreButton", contentPane.containerNode)[0];
+ var node = registry.byNode(deleteKeyStoreButton);
+ connect.connect(node, "onClick",
+ function(evt){
+ that.deleteKeyStore();
+ });
+
+ var editKeyStoreButton = query(".editKeyStoreButton", contentPane.containerNode)[0];
+ var node = registry.byNode(editKeyStoreButton);
+ connect.connect(node, "onClick",
+ function(evt){
+ that.dialog(that.keyStoreUpdater.keyStoreData)
+ });
+ }});
+ };
+
+ KeyStore.prototype.close = function() {
+ updater.remove( this.keyStoreUpdater );
+ };
+
+ function KeyStoreUpdater(containerNode, keyStoreObj, controller, url)
+ {
+ var that = this;
+
+ function findNode(name) {
+ return query("." + name + "Value", containerNode)[0];
+ }
+
+ function storeNodes(names)
+ {
+ for(var i = 0; i < names.length; i++) {
+ that[names[i]] = findNode(names[i]);
+ }
+ }
+
+ storeNodes(["name",
+ "path",
+ "type",
+ "keyManagerFactoryAlgorithm",
+ "certificateAlias",
+ "peersOnly"
+ ]);
+
+ this.query = url;
+
+ xhr.get({url: this.query, sync: properties.useSyncGet, handleAs: "json"}).then(function(data)
+ {
+ that.keyStoreData = data[0];
+ that.updateHeader();
+ });
+
+ }
+
+ KeyStoreUpdater.prototype.updateHeader = function()
+ {
+ this.name.innerHTML = this.keyStoreData[ "name" ];
+ this.path.innerHTML = this.keyStoreData[ "path" ];
+ this.type.innerHTML = this.keyStoreData[ "type" ];
+ this.keyManagerFactoryAlgorithm.innerHTML = this.keyStoreData[ "keyManagerFactoryAlgorithm" ];
+ this.certificateAlias.innerHTML = this.keyStoreData[ "certificateAlias" ] ? this.keyStoreData[ "certificateAlias" ] : "";
+ };
+
+ KeyStoreUpdater.prototype.update = function()
+ {
+
+ var thisObj = this;
+
+ xhr.get({url: this.query, sync: properties.useSyncGet, handleAs: "json"}).then(function(data)
+ {
+ thisObj.keyStoreData = data[0];
+ thisObj.updateHeader();
+ });
+ };
+
+ KeyStore.prototype.deleteKeyStore = function() {
+ if(confirm("Are you sure you want to delete key store '" +this.keyStoreName+"'?")) {
+ var query = this.url;
+ this.success = true
+ var that = this;
+ xhr.del({url: query, sync: true, handleAs: "json"}).then(
+ function(data) {
+ that.contentPane.onClose()
+ that.controller.tabContainer.removeChild(that.contentPane);
+ that.contentPane.destroyRecursive();
+ that.close();
+ },
+ function(error) {that.success = false; that.failureReason = error;});
+ if(!this.success ) {
+ alert("Error:" + this.failureReason);
+ }
+ }
+ }
+
+ return KeyStore;
+ });
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/TrustStore.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/TrustStore.js
new file mode 100644
index 0000000000..703ef34ec2
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/TrustStore.js
@@ -0,0 +1,160 @@
+/*
+ *
+ * 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.
+ *
+ */
+define(["dojo/dom",
+ "dojo/_base/xhr",
+ "dojo/parser",
+ "dojo/query",
+ "dojo/_base/connect",
+ "dijit/registry",
+ "qpid/common/properties",
+ "qpid/common/updater",
+ "qpid/common/util",
+ "qpid/common/formatter",
+ "qpid/management/addKeystore",
+ "dojo/domReady!"],
+ function (dom, xhr, parser, query, connect, registry, properties, updater, util, formatter, addKeystore) {
+
+ function TrustStore(name, parent, controller) {
+ this.keyStoreName = name;
+ this.controller = controller;
+ this.modelObj = { type: "truststore", name: name };
+ if(parent) {
+ this.modelObj.parent = {};
+ this.modelObj.parent[ parent.type] = parent;
+ }
+ this.url = "rest/truststore/" + encodeURIComponent(name);
+ this.dialog = addKeystore.showTruststoreDialog;
+ }
+
+ TrustStore.prototype.getTitle = function() {
+ return "TrustStore: " + this.keyStoreName;
+ };
+
+ TrustStore.prototype.open = function(contentPane) {
+ var that = this;
+ this.contentPane = contentPane;
+ xhr.get({url: "showTrustStore.html",
+ sync: true,
+ load: function(data) {
+ contentPane.containerNode.innerHTML = data;
+ parser.parse(contentPane.containerNode);
+
+ that.keyStoreUpdater = new KeyStoreUpdater(contentPane.containerNode, that.modelObj, that.controller, that.url);
+
+ updater.add( that.keyStoreUpdater );
+
+ that.keyStoreUpdater.update();
+
+ var deleteTrustStoreButton = query(".deleteTrustStoreButton", contentPane.containerNode)[0];
+ var node = registry.byNode(deleteTrustStoreButton);
+ connect.connect(node, "onClick",
+ function(evt){
+ that.deleteKeyStore();
+ });
+
+ var editTrustStoreButton = query(".editTrustStoreButton", contentPane.containerNode)[0];
+ var node = registry.byNode(editTrustStoreButton);
+ connect.connect(node, "onClick",
+ function(evt){
+ that.dialog(that.keyStoreUpdater.keyStoreData)
+ });
+ }});
+ };
+
+ TrustStore.prototype.close = function() {
+ updater.remove( this.keyStoreUpdater );
+ };
+
+ function KeyStoreUpdater(containerNode, keyStoreObj, controller, url)
+ {
+ var that = this;
+
+ function findNode(name) {
+ return query("." + name + "Value", containerNode)[0];
+ }
+
+ function storeNodes(names)
+ {
+ for(var i = 0; i < names.length; i++) {
+ that[names[i]] = findNode(names[i]);
+ }
+ }
+
+ storeNodes(["name",
+ "path",
+ "type",
+ "trustManagerFactoryAlgorithm",
+ "certificateAlias",
+ "peersOnly"
+ ]);
+
+ this.query = url;
+
+ xhr.get({url: this.query, sync: properties.useSyncGet, handleAs: "json"}).then(function(data)
+ {
+ that.keyStoreData = data[0];
+ that.updateHeader();
+ });
+
+ }
+
+ KeyStoreUpdater.prototype.updateHeader = function()
+ {
+ this.name.innerHTML = this.keyStoreData[ "name" ];
+ this.path.innerHTML = this.keyStoreData[ "path" ];
+ this.type.innerHTML = this.keyStoreData[ "type" ];
+ this.trustManagerFactoryAlgorithm.innerHTML = this.keyStoreData[ "trustManagerFactoryAlgorithm" ];
+ this.peersOnly.innerHTML = "<input type='checkbox' disabled='disabled' "+(this.keyStoreData[ "peersOnly" ] ? "checked='checked'": "")+" />" ;
+ };
+
+ KeyStoreUpdater.prototype.update = function()
+ {
+
+ var thisObj = this;
+
+ xhr.get({url: this.query, sync: properties.useSyncGet, handleAs: "json"}).then(function(data)
+ {
+ thisObj.keyStoreData = data[0];
+ thisObj.updateHeader();
+ });
+ };
+
+ TrustStore.prototype.deleteKeyStore = function() {
+ if(confirm("Are you sure you want to delete trust store '" +this.keyStoreName+"'?")) {
+ var query = this.url;
+ this.success = true
+ var that = this;
+ xhr.del({url: query, sync: true, handleAs: "json"}).then(
+ function(data) {
+ that.contentPane.onClose()
+ that.controller.tabContainer.removeChild(that.contentPane);
+ that.contentPane.destroyRecursive();
+ that.close();
+ },
+ function(error) {that.success = false; that.failureReason = error;});
+ if(!this.success ) {
+ alert("Error:" + this.failureReason);
+ }
+ }
+ }
+
+ return TrustStore;
+ });
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addAuthenticationProvider.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addAuthenticationProvider.js
index decc7fa0b3..d2891c7d3b 100644
--- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addAuthenticationProvider.js
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addAuthenticationProvider.js
@@ -207,7 +207,7 @@ define(["dojo/_base/xhr",
var layout = new dojox.layout.TableContainer( {
id: providerType + "FieldSet",
cols: 1,
- "labelWidth": "300",
+ "labelWidth": "200",
showLabels: true,
orientation: "horiz"
});
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addKeystore.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addKeystore.js
new file mode 100644
index 0000000000..4fdcffb7f1
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addKeystore.js
@@ -0,0 +1,164 @@
+/*
+ *
+ * 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.
+ *
+ */
+define(["dojo/_base/lang",
+ "dojo/_base/xhr",
+ "dojo/dom",
+ "dojo/dom-construct",
+ "dijit/registry",
+ "dojo/parser",
+ "dojo/_base/array",
+ "dojo/_base/event",
+ 'dojo/_base/json',
+ "qpid/common/util",
+ "dojo/store/Memory",
+ "dojox/validate/us",
+ "dojox/validate/web",
+ "dijit/Dialog",
+ "dijit/form/CheckBox",
+ "dijit/form/Textarea",
+ "dijit/form/ComboBox",
+ "dijit/form/TextBox",
+ "dijit/form/ValidationTextBox",
+ "dijit/form/Button",
+ "dijit/form/Form",
+ "dijit/TitlePane",
+ "dojox/layout/TableContainer",
+ "dojo/domReady!"],
+ function (lang, xhr, dom, construct, registry, parser, array, event, json, util) {
+
+ var addKeystore = { };
+
+ addKeystore.createWidgetFactories = function(isKeystore)
+ {
+ var fields = [{
+ name: "name",
+ createWidget: function(keystore) {
+ return new dijit.form.ValidationTextBox({
+ required: true,
+ value: keystore.name,
+ disabled: keystore.name ? true : false,
+ label: "Name:",
+ regexp: "^[\x20-\x2e\x30-\x7F]{1,255}$",
+ name: "name"});
+ }
+ }, {
+ name: "path",
+ createWidget: function(keystore) {
+ return new dijit.form.ValidationTextBox({
+ required: true,
+ value: keystore.path,
+ label: "Path to keystore:",
+ name: "path"});
+ }
+ }, {
+ name: "password",
+ requiredFor: "path",
+ createWidget: function(keystore) {
+ return new dijit.form.ValidationTextBox({
+ required: false,
+ label: "Keystore password:",
+ invalidMessage: "Missed keystore password",
+ name: "password",
+ placeHolder: keystore["password"] ? keystore["password"] : ""
+ });
+ }
+ }];
+ if (!isKeystore)
+ {
+ fields.push({
+ name: "peersOnly",
+ createWidget: function(keystore) {
+ return new dijit.form.CheckBox({
+ required: false,
+ checked: keystore && keystore.peersOnly,
+ label: "Peers only:",
+ name: "peersOnly"});
+ }
+ });
+ }
+ fields.push({
+ name: "Options",
+ createWidget: function(keystore) {
+ var optionalFieldContainer = new dojox.layout.TableContainer({
+ cols: 1,
+ "labelWidth": "290",
+ showLabels: true,
+ orientation: "horiz",
+ customClass: "formLabel"
+ });
+ if (isKeystore)
+ {
+ optionalFieldContainer.addChild(new dijit.form.ValidationTextBox({
+ required: false,
+ value: keystore.certificateAlias,
+ label: "Keystore certificate alias:",
+ name: "certificateAlias"}));
+ optionalFieldContainer.addChild( new dijit.form.ValidationTextBox({
+ required: false,
+ value: keystore.keyManagerFactoryAlgorithm,
+ label: "Key manager factory algorithm:",
+ placeHolder: "Use default",
+ name: "keyManagerFactoryAlgorithm"}));
+ }
+ else
+ {
+ optionalFieldContainer.addChild( new dijit.form.ValidationTextBox({
+ required: false,
+ value: keystore.trustManagerFactoryAlgorithm,
+ label: "Trust manager factory algorithm:",
+ placeHolder: "Use default",
+ name: "trustManagerFactoryAlgorithm"}));
+ }
+ optionalFieldContainer.addChild(new dijit.form.ValidationTextBox({
+ required: false,
+ value: keystore.type,
+ label: "Key store type:",
+ placeHolder: "Use default",
+ name: "type"}));
+ var panel = new dijit.TitlePane({title: "Optional Attributes", content: optionalFieldContainer.domNode, open: false});
+ return panel;
+ }
+ });
+ return fields;
+ }
+
+ addKeystore.showKeystoreDialog = function(keystore) {
+ var keystoreAttributeWidgetFactories = addKeystore.createWidgetFactories(true);
+
+ util.showSetAttributesDialog(
+ keystoreAttributeWidgetFactories,
+ keystore ? keystore : {},
+ "rest/keystore" + (keystore ? "/" + encodeURIComponent(keystore.name) : ""),
+ keystore ? "Edit keystore - " + keystore.name : "Add keystore",
+ keystore ? false : true);
+ };
+
+ addKeystore.showTruststoreDialog = function(truststore) {
+ var truststoreAttributeWidgetFactories = addKeystore.createWidgetFactories(false);
+ util.showSetAttributesDialog(
+ truststoreAttributeWidgetFactories,
+ truststore ? truststore : {},
+ "rest/truststore" + (truststore ? "/" + encodeURIComponent(truststore.name) : ""),
+ truststore ? "Edit truststore - " + truststore.name : "Add truststore",
+ truststore ? false : true);
+ };
+ return addKeystore;
+ }); \ No newline at end of file
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addPort.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addPort.js
index 0c1a188cbf..c60ad5bb79 100644
--- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addPort.js
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addPort.js
@@ -28,6 +28,7 @@ define(["dojo/_base/xhr",
"dojo/_base/event",
'dojo/_base/json',
"dojo/store/Memory",
+ "dojo/data/ObjectStore",
"dijit/form/FilteringSelect",
"dojo/dom-style",
"dojo/_base/lang",
@@ -50,9 +51,10 @@ define(["dojo/_base/xhr",
"dijit/form/Select",
"dijit/form/NumberSpinner",
/* basic dojox classes */
- "dojox/form/BusyButton",
+ "dojox/grid/EnhancedGrid",
+ "dojox/grid/enhanced/plugins/IndirectSelection",
"dojo/domReady!"],
- function (xhr, dom, construct, win, registry, parser, array, event, json, Memory, FilteringSelect, domStyle, lang) {
+ function (xhr, dom, construct, win, registry, parser, array, event, json, Memory, ObjectStore, FilteringSelect, domStyle, lang) {
var addPort = {};
@@ -110,33 +112,77 @@ define(["dojo/_base/xhr",
var type = dijit.byId("formAddPort.type").value;
if (type == "AMQP")
{
+ var transportWidget = registry.byId("formAddPort.transports");
var needClientAuth = dijit.byId("formAddPort.needClientAuth");
var wantClientAuth = dijit.byId("formAddPort.wantClientAuth");
- newPort.needClientAuth = needClientAuth.disabled ? false : needClientAuth.checked;
- newPort.wantClientAuth = wantClientAuth.disabled ? false : wantClientAuth.checked
+ var trustStoreWidget = dijit.byId("formAddPort.trustStores");
+
+ var initialTransport = transportWidget.initialValue;
+ var currentTransport = transportWidget.value;
+ if (currentTransport == "SSL")
+ {
+ newPort.needClientAuth = needClientAuth.checked;
+ newPort.wantClientAuth = wantClientAuth.checked
+
+ var items = trustStoreWidget.selection.getSelected();
+ var trustStores = [];
+ if(items.length > 0){
+ for(var i in items)
+ {
+ var item = items[i];
+ trustStores.push(trustStoreWidget.store.getValue(item, "name"));
+ }
+ newPort.trustStores = trustStores;
+ }
+ else if (trustStoreWidget.initialValue && trustStoreWidget.initialValue.length > 0)
+ {
+ newPort.trustStores = null;
+ }
+ }
+ else if (initialTransport && currentTransport != initialTransport)
+ {
+ newPort.needClientAuth = false;
+ newPort.wantClientAuth = false;
+ newPort.trustStores = null;
+ }
}
+
return newPort;
};
- var toggleCertificateWidgets = function toggleCertificateWidgets(protocolType, transportType)
+ var toggleSslWidgets = function toggleSslWidgets(protocolType, transportType)
{
- var clientAuthPanel = registry.byId("formAddPort:fieldsClientAuth");
- var display = clientAuthPanel.domNode.style.display;
+ var clientAuthPanel = dojo.byId("formAddPort:fieldsClientAuth");
+ var display = clientAuthPanel.style.display;
if (transportType == "SSL" && protocolType == "AMQP")
{
- clientAuthPanel.domNode.style.display = "block";
+ clientAuthPanel.style.display = "block";
registry.byId("formAddPort.needClientAuth").set("disabled", false);
registry.byId("formAddPort.wantClientAuth").set("disabled", false);
}
else
{
- clientAuthPanel.domNode.style.display = "none";
+ clientAuthPanel.style.display = "none";
registry.byId("formAddPort.needClientAuth").set("disabled", true);
registry.byId("formAddPort.wantClientAuth").set("disabled", true);
}
- if (clientAuthPanel.domNode.style.display != display)
+
+ var transportSSLPanel = registry.byId("formAddPort:fieldsTransportSSL");
+ var transportSSLPanelDisplay = transportSSLPanel.domNode.style.display;
+ if (transportType == "SSL")
+ {
+ transportSSLPanel.domNode.style.display = "block";
+ registry.byId("formAddPort.keyStore").set("disabled", false);
+ }
+ else
{
- clientAuthPanel.resize();
+ transportSSLPanel.domNode.style.display = "none";
+ registry.byId("formAddPort.keyStore").set("disabled", true);
+ }
+
+ if (transportSSLPanel.domNode.style.display != transportSSLPanelDisplay)
+ {
+ transportSSLPanel.resize();
}
};
@@ -155,7 +201,7 @@ define(["dojo/_base/xhr",
registry.byId("formAddPort.transports").on("change", function(newValue){
var protocolType = registry.byId("formAddPort.type").value;
- toggleCertificateWidgets(protocolType, newValue);
+ toggleSslWidgets(protocolType, newValue);
});
registry.byId("formAddPort.type").on("change", function(newValue) {
@@ -166,8 +212,9 @@ define(["dojo/_base/xhr",
registry.byId("formAddPort:fields" + option.value).domNode.style.display = "none";
});
- registry.byId("formAddPort.needClientAuth").set("enabled", ("AMQP" == newValue));
- registry.byId("formAddPort.wantClientAuth").set("enabled", ("AMQP" == newValue));
+ var isAMQP = ("AMQP" == newValue);
+ registry.byId("formAddPort.needClientAuth").set("enabled", isAMQP);
+ registry.byId("formAddPort.wantClientAuth").set("enabled", isAMQP);
registry.byId("formAddPort:fields" + newValue).domNode.style.display = "block";
var defaultsAMQPProtocols = registry.byId("formAddPort.protocolsDefault");
@@ -175,19 +222,58 @@ define(["dojo/_base/xhr",
var protocolsWidget = registry.byId("formAddPort.protocols" + newValue);
if (protocolsWidget)
{
- protocolsWidget.set("disabled", ("AMQP" == newValue && defaultsAMQPProtocols.checked));
+ protocolsWidget.set("disabled", (isAMQP && defaultsAMQPProtocols.checked));
+ }
+ var transportWidget = registry.byId("formAddPort.transports");
+
+ var disabled = (newValue == "JMX" && registry.byId("formAddPort.protocolsJMX").value == "RMI");
+ if (disabled && transportWidget.value != "TCP")
+ {
+ transportWidget.set("value", "TCP");
}
- var transport = registry.byId("formAddPort.transports").value;
- toggleCertificateWidgets(newValue, transport);
+ else
+ {
+ toggleSslWidgets(newValue, transportWidget.value);
+ }
+ transportWidget.set("disabled", disabled);
+
});
+
theForm = registry.byId("formAddPort");
+ var containers = ["formAddPort:fields", "formAddPort:fieldsTransportSSL", "formAddPort:fieldsAMQP",
+ "formAddPort:fieldsJMX", "formAddPort:fieldsHTTP", "formAddPort:transport", "formAddPort:fieldsClientAuth2"];
+ var labelWidthValue = "200";
+ for(var i = 0; i < containers.length; i++)
+ {
+ var containerId = containers[i];
+ var fields = new dojox.layout.TableContainer( {
+ cols: 1,
+ labelWidth: labelWidthValue,
+ showLabels: true,
+ orientation: "horiz",
+ customClass: "formLabel"
+ }, dom.byId(containerId));
+ fields.startup();
+ }
+
+ registry.byId("formAddPort.protocolsJMX").on("change", function(newValue){
+ var transportWidget = registry.byId("formAddPort.transports");
+ transportWidget.set("value", "TCP");
+ transportWidget.set("disabled", newValue == "RMI");
+ });
+
theForm.on("submit", function(e) {
event.stop(e);
if(theForm.validate()){
var newPort = convertToPort(theForm.getValues());
+ if ((newPort.needClientAuth || newPort.wantClientAuth) && (!newPort.hasOwnProperty("trustStores") || newPort.trustStores.length==0))
+ {
+ alert("A trustore must be selected when requesting client certificates.");
+ return false;
+ }
var that = this;
xhr.put({url: "rest/port/"+encodeURIComponent(newPort.name), sync: true, handleAs: "json",
@@ -216,52 +302,8 @@ define(["dojo/_base/xhr",
});
}});
- addPort.show = function(portName, providers) {
+ addPort.show = function(portName, providers, keystores, truststores) {
- if (!addPort.fields)
- {
- var labelWidthValue = "300";
- addPort.fields = new dojox.layout.TableContainer( {
- cols: 1,
- labelWidth: labelWidthValue,
- showLabels: true,
- orientation: "horiz",
- customClass: "formLabel"
- }, dom.byId("formAddPort:fields"));
- addPort.fields.startup();
- addPort.fieldsClientAuth = new dojox.layout.TableContainer( {
- cols: 1,
- labelWidth: labelWidthValue,
- showLabels: true,
- orientation: "horiz",
- customClass: "formLabel"
- }, dom.byId("formAddPort:fieldsClientAuth"));
- addPort.fieldsClientAuth.startup();
- addPort.fieldsAMQP = new dojox.layout.TableContainer( {
- cols: 1,
- labelWidth: labelWidthValue,
- showLabels: true,
- orientation: "horiz",
- customClass: "formLabel"
- }, dom.byId("formAddPort:fieldsAMQP"));
- addPort.fieldsAMQP.startup();
- addPort.fieldsJMX = new dojox.layout.TableContainer( {
- cols: 1,
- labelWidth: labelWidthValue,
- showLabels: true,
- orientation: "horiz",
- customClass: "formLabel"
- }, dom.byId("formAddPort:fieldsJMX"));
- addPort.fieldsJMX.startup();
- addPort.fieldsHTTP = new dojox.layout.TableContainer( {
- cols: 1,
- labelWidth: labelWidthValue,
- showLabels: true,
- orientation: "horiz",
- customClass: "formLabel"
- }, dom.byId("formAddPort:fieldsHTTP"));
- addPort.fieldsHTTP.startup();
- }
registry.byId("formAddPort").reset();
dojo.byId("formAddPort.id").value = "";
@@ -278,6 +320,36 @@ define(["dojo/_base/xhr",
providerWidget.startup();
}
+ var keystoreWidget = registry.byId("formAddPort.keyStore");
+ if (keystores)
+ {
+ var data = [];
+ for (var i=0; i< keystores.length; i++)
+ {
+ data.push( {id: keystores[i].name, name: keystores[i].name} );
+ }
+ var keystoresStore = new Memory({ data: data });
+ keystoreWidget.set("store", keystoresStore);
+ keystoreWidget.startup();
+ }
+
+ var truststoreWidget = registry.byId("formAddPort.trustStores");
+ if (truststores)
+ {
+ var layout = [[{name: "Name", field: "name", width: "100%"},
+ {name: "Peers only", field: "peersOnly", width: "80px",
+ formatter: function(val){
+ return "<input type='radio' disabled='disabled' "+(val?"checked='checked'": "")+" />"
+ }
+ }]];
+
+ var mem = new Memory({ data: truststores, idProperty: "id"});
+ truststoreWidget.set("store", new ObjectStore({objectStore: mem}));
+ truststoreWidget.set("structure", layout);
+ truststoreWidget.rowSelectCell.toggleAllSelection(false);
+ truststoreWidget.startup();
+ }
+
if (portName)
{
xhr.get({
@@ -291,6 +363,26 @@ define(["dojo/_base/xhr",
nameField.set("disabled", true);
dom.byId("formAddPort.id").value=port.id;
providerWidget.set("value", port.authenticationProvider ? port.authenticationProvider : "");
+ keystoreWidget.set("value", port.keyStore ? port.keyStore : "");
+ if (port.trustStores)
+ {
+ var items = truststoreWidget.store.objectStore.data;
+ for (var j=0; j< items.length; j++)
+ {
+ var selected = false;
+ for (var i=0; i< port.trustStores.length; i++)
+ {
+ var trustStore = port.trustStores[i];
+ if (items[j].name == trustStore)
+ {
+ selected = true;
+ break;
+ }
+ }
+ truststoreWidget.selection.setSelected(j,selected);
+ truststoreWidget.initialValue = port.trustStores;
+ }
+ }
var transportWidget = registry.byId("formAddPort.transports");
transportWidget.set("value", port.transports ? port.transports[0] : "");
registry.byId("formAddPort.port").set("value", port.port);
@@ -343,16 +435,26 @@ define(["dojo/_base/xhr",
registry.byId("formAddPort:fields" + typeWidget.value).domNode.style.display = "block";
typeWidget.set("disabled", true);
- toggleCertificateWidgets(typeWidget.value, transportWidget.value);
+ toggleSslWidgets(typeWidget.value, transportWidget.value);
+
+ keystoreWidget.initialValue = port.keyStore;
+ truststoreWidget.initialValue = port.trustStores;
+ transportWidget.initialValue = transportWidget.value;
+ providerWidget.initialValue = providerWidget.value;
+
registry.byId("addPort").show();
});
}
else
{
var typeWidget = registry.byId("formAddPort.type");
- typeWidget.set("disabled", false);
+ if (typeWidget.get("disabled"))
+ {
+ typeWidget.set("disabled", false);
+ }
typeWidget.set("value", "AMQP");
- registry.byId("formAddPort.name").set("disabled", false);
+ var name = registry.byId("formAddPort.name");
+ name.set("disabled", false);
registry.byId("addPort").show();
}
};
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/controller.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/controller.js
index 5d3a666760..c4114739c0 100644
--- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/controller.js
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/controller.js
@@ -29,15 +29,17 @@ define(["dojo/dom",
"qpid/management/AuthenticationProvider",
"qpid/management/GroupProvider",
"qpid/management/group/Group",
+ "qpid/management/KeyStore",
+ "qpid/management/TrustStore",
"dojo/ready",
"dojo/domReady!"],
- function (dom, registry, ContentPane, Broker, VirtualHost, Exchange, Queue, Connection, AuthProvider, GroupProvider, Group, ready) {
+ function (dom, registry, ContentPane, Broker, VirtualHost, Exchange, Queue, Connection, AuthProvider, GroupProvider, Group, KeyStore, TrustStore, ready) {
var controller = {};
var constructors = { broker: Broker, virtualhost: VirtualHost, exchange: Exchange,
queue: Queue, connection: Connection,
authenticationprovider: AuthProvider, groupprovider: GroupProvider,
- group: Group };
+ group: Group, keystore: KeyStore, truststore: TrustStore };
var tabDiv = dom.byId("managedViews");
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/treeView.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/treeView.js
index 59356cfce1..f96fc13a03 100644
--- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/treeView.js
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/treeView.js
@@ -277,8 +277,11 @@ define(["dojo/_base/xhr",
controller.show("groupprovider", details.groupprovider, {broker: {type:"broker", name:""}});
} else if (details.type == 'group') {
controller.show("group", details.group, { type: "groupprovider", name: details.groupprovider, parent: {broker: {type:"broker", name:""}}});
+ } else if (details.type == 'keystore') {
+ controller.show("keystore", details.keystore, {broker: {type:"broker", name:""}});
+ } else if (details.type == 'truststore') {
+ controller.show("truststore", details.truststore, {broker: {type:"broker", name:""}});
}
-
};
TreeViewModel.prototype.update = function () {
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/showBroker.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/showBroker.html
index 887ca4e736..9e267f0d5d 100644
--- a/qpid/java/broker-plugins/management-http/src/main/java/resources/showBroker.html
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/showBroker.html
@@ -69,20 +69,6 @@
<div class="formLabel-labelCell" style="float:left; width: 250px;">Group file location:</div>
<div id="brokerAttribute.groupFile" style="float:left;"></div>
</div>
- <div id="brokerAttribute.keyStorePath.container" style="display: none; clear:both">
- <div class="formLabel-labelCell" style="float:left; width: 250px;">Path to keystore:</div>
- <div id="brokerAttribute.keyStorePath" style="float:left;"></div><br/>
- <div class="formLabel-labelCell" style="float:left; width: 250px;">Keystore certificate alias:</div>
- <div id="brokerAttribute.keyStoreCertAlias" style="float:left;"></div>
- </div>
- <div id="brokerAttribute.trustStorePath.container" style="display: none; clear:both">
- <div class="formLabel-labelCell" style="float:left; width: 250px;">Path to truststore:</div>
- <div id="brokerAttribute.trustStorePath" style="float:left;"></div>
- </div>
- <div id="brokerAttribute.peerStorePath.container" style="display: none; clear:both">
- <div class="formLabel-labelCell" style="float:left; width: 250px;">Path to peerstore:</div>
- <div id="brokerAttribute.peerStorePath" style="float:left;"></div>
- </div>
<div id="brokerAttribute.statisticsReportingPeriod.container" style="display: none; clear:both">
<div class="formLabel-labelCell" style="float:left; width: 250px;">Statistics reporting period:</div>
<div id="brokerAttribute.statisticsReportingPeriod" style="float:left;"></div>
@@ -191,6 +177,18 @@
<button data-dojo-type="dijit.form.Button" class="deleteAuthenticationProvider">Delete Provider</button>
</div>
<br/>
+ <div data-dojo-type="dijit.TitlePane" data-dojo-props="title: 'Key stores'">
+ <div class="broker-key-stores"></div>
+ <button data-dojo-type="dijit.form.Button" class="addKeystore">Add Key Store</button>
+ <button data-dojo-type="dijit.form.Button" class="deleteKeystore">Delete Key Store</button>
+ </div>
+ <br/>
+ <div data-dojo-type="dijit.TitlePane" data-dojo-props="title: 'Trust stores'">
+ <div class="broker-trust-stores"></div>
+ <button data-dojo-type="dijit.form.Button" class="addTruststore">Add Trust Store</button>
+ <button data-dojo-type="dijit.form.Button" class="deleteTruststore">Delete Trust Store</button>
+ </div>
+ <br/>
<div data-dojo-type="dijit.TitlePane" data-dojo-props="title: 'Log File', open: false">
<div class="broker-logfile"></div>
</div>
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/showKeyStore.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/showKeyStore.html
new file mode 100644
index 0000000000..5caee836d3
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/showKeyStore.html
@@ -0,0 +1,47 @@
+<!--
+ -
+ - 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.
+ -
+ -->
+<div class="keystore">
+ <div class="keyStoreContainer">
+
+ <div class="formLabel-labelCell" style="float:left; width: 250px;">Name:</div>
+ <div class="nameValue" style="float:left;"></div><br/>
+
+ <div class="formLabel-labelCell" style="float:left; width: 250px;">Type:</div>
+ <div class="typeValue" style="float:left;"></div><br/>
+
+ <div class="formLabel-labelCell" style="float:left; width: 250px;">Key Manager Factory Algorithm:</div>
+ <div class="keyManagerFactoryAlgorithmValue" style="float:left;"></div><br/>
+
+ <div class="formLabel-labelCell" style="float:left; width: 250px;">Path:</div>
+ <div class="pathValue" style="float:left;"></div><br/>
+
+ <div class="certificateAlias">
+ <div class="formLabel-labelCell" style="float:left; width: 250px;">Certificate alias:</div>
+ <div class="certificateAliasValue" style="float:left;"></div><br>
+ </div>
+
+ </div>
+ <br/>
+ <div class="dijitDialogPaneActionBar">
+ <button data-dojo-type="dijit.form.Button" class="editKeyStoreButton" type="button">Edit</button>
+ <button data-dojo-type="dijit.form.Button" class="deleteKeyStoreButton" type="button">Delete</button>
+ </div>
+</div>
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/showTrustStore.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/showTrustStore.html
new file mode 100644
index 0000000000..6f9146fdfe
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/showTrustStore.html
@@ -0,0 +1,47 @@
+<!--
+ -
+ - 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.
+ -
+ -->
+<div class="truststore">
+ <div class="trustStoreContainer">
+
+ <div class="formLabel-labelCell" style="float:left; width: 250px;">Name:</div>
+ <div class="nameValue" style="float:left;"></div><br/>
+
+ <div class="formLabel-labelCell" style="float:left; width: 250px;">Type:</div>
+ <div class="typeValue" style="float:left;"></div><br/>
+
+ <div class="formLabel-labelCell" style="float:left; width: 250px;">Trust Manager Factory Algorithm:</div>
+ <div class="trustManagerFactoryAlgorithmValue" style="float:left;"></div><br/>
+
+ <div class="formLabel-labelCell" style="float:left; width: 250px;">Path:</div>
+ <div class="pathValue" style="float:left;"></div><br/>
+
+ <div class="peersOnly">
+ <div class="formLabel-labelCell" style="float:left; width: 250px;">Peer store:</div>
+ <div class="peersOnlyValue" style="float:left;"></div>
+ </div>
+
+ </div>
+ <br/>
+ <div class="dijitDialogPaneActionBar">
+ <button data-dojo-type="dijit.form.Button" class="editTrustStoreButton" type="button">Edit</button>
+ <button data-dojo-type="dijit.form.Button" class="deleteTrustStoreButton" type="button">Delete</button>
+ </div>
+</div>
diff --git a/qpid/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/JMXManagedObjectRegistry.java b/qpid/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/JMXManagedObjectRegistry.java
index 93f7df8c85..a1356028f0 100644
--- a/qpid/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/JMXManagedObjectRegistry.java
+++ b/qpid/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/JMXManagedObjectRegistry.java
@@ -26,10 +26,12 @@ import org.apache.qpid.server.configuration.IllegalConfigurationException;
import org.apache.qpid.server.logging.actors.CurrentActor;
import org.apache.qpid.server.logging.messages.ManagementConsoleMessages;
import org.apache.qpid.server.model.Broker;
+import org.apache.qpid.server.model.KeyStore;
import org.apache.qpid.server.model.Port;
import org.apache.qpid.server.model.Transport;
import org.apache.qpid.server.security.auth.rmi.RMIPasswordAuthenticator;
+import org.apache.qpid.ssl.SSLContextFactory;
import javax.management.JMException;
import javax.management.MBeanServer;
@@ -39,6 +41,7 @@ import javax.management.remote.JMXConnectorServer;
import javax.management.remote.JMXServiceURL;
import javax.management.remote.MBeanServerForwarder;
import javax.management.remote.rmi.RMIConnectorServer;
+import javax.net.ssl.SSLContext;
import javax.rmi.ssl.SslRMIClientSocketFactory;
import javax.rmi.ssl.SslRMIServerSocketFactory;
import java.io.File;
@@ -57,6 +60,7 @@ import java.rmi.registry.Registry;
import java.rmi.server.RMIClientSocketFactory;
import java.rmi.server.RMIServerSocketFactory;
import java.rmi.server.UnicastRemoteObject;
+import java.security.GeneralSecurityException;
import java.util.HashMap;
/**
@@ -122,16 +126,32 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry
if (connectorSslEnabled)
{
- String keyStorePath = System.getProperty("javax.net.ssl.keyStore");
- String keyStorePassword = System.getProperty("javax.net.ssl.keyStorePassword");
+ KeyStore keyStore = _connectorPort.getKeyStore();
- validateKeyStoreProperties(keyStorePath, keyStorePassword);
+ String keyStorePath = (String) keyStore.getAttribute(KeyStore.PATH);
+ String keyStorePassword = keyStore.getPassword();
+ String keyStoreType = (String) keyStore.getAttribute(KeyStore.TYPE);
+ String keyManagerFactoryAlgorithm = (String) keyStore.getAttribute(KeyStore.KEY_MANAGER_FACTORY_ALGORITHM);
+
+ SSLContext sslContext;
+ try
+ {
+ sslContext = SSLContextFactory.buildServerContext(keyStorePath, keyStorePassword, keyStoreType, keyManagerFactoryAlgorithm);
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new RuntimeException("Unable to create SSLContext for key or trust store", e);
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException("Unable to create SSLContext - unable to load key/trust store", e);
+ }
CurrentActor.get().message(ManagementConsoleMessages.SSL_KEYSTORE(keyStorePath));
//create the SSL RMI socket factories
csf = new SslRMIClientSocketFactory();
- ssf = new SslRMIServerSocketFactory();
+ ssf = new QpidSslRMIServerSocketFactory(sslContext);
}
else
{
@@ -262,31 +282,6 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry
return rmiRegistry;
}
- private void validateKeyStoreProperties(String keyStorePath, String keyStorePassword) throws FileNotFoundException
- {
- if (keyStorePath == null)
- {
- throw new IllegalConfigurationException("JVM system property 'javax.net.ssl.keyStore' is not set, "
- + "unable to start requested SSL protected JMX connector");
- }
- if (keyStorePassword == null)
- {
- throw new IllegalConfigurationException( "JVM system property 'javax.net.ssl.keyStorePassword' is not set, "
- + "unable to start requested SSL protected JMX connector");
- }
-
- File ksf = new File(keyStorePath);
- if (!ksf.exists())
- {
- throw new FileNotFoundException("Cannot find SSL keystore file for JMX management: " + ksf);
- }
- if (!ksf.canRead())
- {
- throw new FileNotFoundException("Cannot read SSL keystore file for JMX management: "
- + ksf + ". Check permissions.");
- }
- }
-
@Override
public void registerObject(ManagedObject managedObject) throws JMException
{
diff --git a/qpid/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/QpidSslRMIServerSocketFactory.java b/qpid/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/QpidSslRMIServerSocketFactory.java
new file mode 100644
index 0000000000..115a96da81
--- /dev/null
+++ b/qpid/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/QpidSslRMIServerSocketFactory.java
@@ -0,0 +1,85 @@
+package org.apache.qpid.server.jmx;
+
+import java.io.IOException;
+import java.net.ServerSocket;
+import java.net.Socket;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+import javax.rmi.ssl.SslRMIServerSocketFactory;
+
+public class QpidSslRMIServerSocketFactory extends SslRMIServerSocketFactory
+{
+ private final SSLContext _sslContext;
+
+ /**
+ * SslRMIServerSocketFactory which creates the ServerSocket using the
+ * supplied SSLContext rather than the system default context normally
+ * used by the superclass, allowing us to use a configuration-specified
+ * key store.
+ *
+ * @param sslContext previously created sslContext using the desired key store.
+ * @throws NullPointerException if the provided {@link SSLContext} is null.
+ */
+ public QpidSslRMIServerSocketFactory(SSLContext sslContext) throws NullPointerException
+ {
+ super();
+
+ if(sslContext == null)
+ {
+ throw new NullPointerException("The provided SSLContext must not be null");
+ }
+
+ _sslContext = sslContext;
+
+ //TODO: settings + implementation for SSL client auth, updating equals and hashCode appropriately.
+ }
+
+ @Override
+ public ServerSocket createServerSocket(int port) throws IOException
+ {
+ final SSLSocketFactory factory = _sslContext.getSocketFactory();
+
+ return new ServerSocket(port)
+ {
+ public Socket accept() throws IOException
+ {
+ Socket socket = super.accept();
+
+ SSLSocket sslSocket =
+ (SSLSocket) factory.createSocket(socket,
+ socket.getInetAddress().getHostName(),
+ socket.getPort(),
+ true);
+ sslSocket.setUseClientMode(false);
+
+ return sslSocket;
+ }
+ };
+ }
+
+ /**
+ * One QpidSslRMIServerSocketFactory is equal to
+ * another if their (non-null) SSLContext are equal.
+ */
+ @Override
+ public boolean equals(Object object)
+ {
+ if (!(object instanceof QpidSslRMIServerSocketFactory))
+ {
+ return false;
+ }
+
+ QpidSslRMIServerSocketFactory that = (QpidSslRMIServerSocketFactory) object;
+
+ return _sslContext.equals(that._sslContext);
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return _sslContext.hashCode();
+ }
+
+}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/startup/BrokerRecoverer.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/startup/BrokerRecoverer.java
index 0d7be75a0b..4fc0a37c3e 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/startup/BrokerRecoverer.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/startup/BrokerRecoverer.java
@@ -1,23 +1,28 @@
package org.apache.qpid.server.configuration.startup;
+import java.util.ArrayList;
import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import org.apache.qpid.server.configuration.ConfigurationEntry;
import org.apache.qpid.server.configuration.ConfiguredObjectRecoverer;
import org.apache.qpid.server.configuration.IllegalConfigurationException;
import org.apache.qpid.server.configuration.RecovererProvider;
+import org.apache.qpid.server.configuration.store.StoreConfigurationChangeListener;
+import org.apache.qpid.server.configuration.updater.TaskExecutor;
import org.apache.qpid.server.logging.LogRecorder;
import org.apache.qpid.server.logging.RootMessageLogger;
import org.apache.qpid.server.model.AuthenticationProvider;
import org.apache.qpid.server.model.Broker;
import org.apache.qpid.server.model.ConfiguredObject;
+import org.apache.qpid.server.model.KeyStore;
import org.apache.qpid.server.model.Port;
+import org.apache.qpid.server.model.TrustStore;
import org.apache.qpid.server.model.adapter.AuthenticationProviderFactory;
import org.apache.qpid.server.model.adapter.BrokerAdapter;
import org.apache.qpid.server.model.adapter.PortFactory;
-import org.apache.qpid.server.configuration.store.StoreConfigurationChangeListener;
-import org.apache.qpid.server.configuration.updater.TaskExecutor;
import org.apache.qpid.server.stats.StatisticsGatherer;
import org.apache.qpid.server.virtualhost.VirtualHostRegistry;
@@ -52,31 +57,62 @@ public class BrokerRecoverer implements ConfiguredObjectRecoverer<Broker>
_logRecorder, _rootMessageLogger, _authenticationProviderFactory, _portFactory, _taskExecutor, entry.getStore());
broker.addChangeListener(storeChangeListener);
- Map<String, Collection<ConfigurationEntry>> childEntries = entry.getChildren();
- for (String type : childEntries.keySet())
+
+ //Recover the SSL keystores / truststores first, then others that depend on them
+ Map<String, Collection<ConfigurationEntry>> childEntries = new HashMap<String, Collection<ConfigurationEntry>>(entry.getChildren());
+ Map<String, Collection<ConfigurationEntry>> sslChildEntries = new HashMap<String, Collection<ConfigurationEntry>>(childEntries);
+ List<String> types = new ArrayList<String>(childEntries.keySet());
+
+ for(String type : types)
{
- ConfiguredObjectRecoverer<?> recoverer = recovererProvider.getRecoverer(type);
- if (recoverer == null)
+ if(KeyStore.class.getSimpleName().equals(type) || TrustStore.class.getSimpleName().equals(type))
{
- throw new IllegalConfigurationException("Cannot recover entry for the type '" + type + "' from broker");
+ childEntries.remove(type);
}
- Collection<ConfigurationEntry> entries = childEntries.get(type);
- for (ConfigurationEntry childEntry : entries)
+ else
{
- ConfiguredObject object = recoverer.create(recovererProvider, childEntry, broker);
- if (object == null)
- {
- throw new IllegalConfigurationException("Cannot create configured object for the entry " + childEntry);
- }
- broker.recoverChild(object);
- object.addChangeListener(storeChangeListener);
+ sslChildEntries.remove(type);
}
}
+
+ for (String type : sslChildEntries.keySet())
+ {
+ recoverType(recovererProvider, storeChangeListener, broker, sslChildEntries, type);
+ }
+ for (String type : childEntries.keySet())
+ {
+ recoverType(recovererProvider, storeChangeListener, broker, childEntries, type);
+ }
+
wireUpConfiguredObjects(broker, entry.getAttributes());
return broker;
}
+ private void recoverType(RecovererProvider recovererProvider,
+ StoreConfigurationChangeListener storeChangeListener,
+ BrokerAdapter broker,
+ Map<String, Collection<ConfigurationEntry>> childEntries,
+ String type)
+ {
+ ConfiguredObjectRecoverer<?> recoverer = recovererProvider.getRecoverer(type);
+ if (recoverer == null)
+ {
+ throw new IllegalConfigurationException("Cannot recover entry for the type '" + type + "' from broker");
+ }
+ Collection<ConfigurationEntry> entries = childEntries.get(type);
+ for (ConfigurationEntry childEntry : entries)
+ {
+ ConfiguredObject object = recoverer.create(recovererProvider, childEntry, broker);
+ if (object == null)
+ {
+ throw new IllegalConfigurationException("Cannot create configured object for the entry " + childEntry);
+ }
+ broker.recoverChild(object);
+ object.addChangeListener(storeChangeListener);
+ }
+ }
+
private void wireUpConfiguredObjects(BrokerAdapter broker, Map<String, Object> brokerAttributes)
{
AuthenticationProvider defaultAuthenticationProvider = null;
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/Broker.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/Broker.java
index ad0e68cee6..0e230bd552 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/Broker.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/Broker.java
@@ -88,18 +88,6 @@ public interface Broker extends ConfiguredObject
String ACL_FILE = "aclFile";
/*
- * A temporary attributes to set the broker default key/trust stores.
- * TODO: Remove them after adding a full support to configure KeyStore/TrustStore via management layers.
- */
- String KEY_STORE_PATH = "keyStorePath";
- String KEY_STORE_PASSWORD = "keyStorePassword";
- String KEY_STORE_CERT_ALIAS = "keyStoreCertAlias";
- String TRUST_STORE_PATH = "trustStorePath";
- String TRUST_STORE_PASSWORD = "trustStorePassword";
- String PEER_STORE_PATH = "peerStorePath";
- String PEER_STORE_PASSWORD = "peerStorePassword";
-
- /*
* A temporary attributes to set the broker group file.
* TODO: Remove them after adding a full support to configure authorization providers via management layers.
*/
@@ -148,16 +136,8 @@ public interface Broker extends ConfiguredObject
VIRTUALHOST_STORE_TRANSACTION_IDLE_TIMEOUT_WARN,
VIRTUALHOST_STORE_TRANSACTION_OPEN_TIMEOUT_CLOSE,
VIRTUALHOST_STORE_TRANSACTION_OPEN_TIMEOUT_WARN,
-
- ACL_FILE,
- KEY_STORE_PATH,
- KEY_STORE_PASSWORD,
- KEY_STORE_CERT_ALIAS,
- TRUST_STORE_PATH,
- TRUST_STORE_PASSWORD,
- PEER_STORE_PATH,
- PEER_STORE_PASSWORD,
- GROUP_FILE
+ GROUP_FILE,
+ ACL_FILE
));
//children
@@ -194,6 +174,10 @@ public interface Broker extends ConfiguredObject
VirtualHost findVirtualHostByName(String name);
+ KeyStore findKeyStoreByName(String name);
+
+ TrustStore findTrustStoreByName(String name);
+
/**
* Get the SubjectCreator for the given socket address.
* TODO: move the authentication related functionality into host aliases and AuthenticationProviders
@@ -211,10 +195,6 @@ public interface Broker extends ConfiguredObject
*/
VirtualHostRegistry getVirtualHostRegistry();
- KeyStore getDefaultKeyStore();
-
- TrustStore getDefaultTrustStore();
-
TaskExecutor getTaskExecutor();
boolean isManagementMode();
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/KeyStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/KeyStore.java
index 959714656b..74a7469ffb 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/KeyStore.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/KeyStore.java
@@ -24,10 +24,23 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
-public interface KeyStore extends TrustStore
+public interface KeyStore extends ConfiguredObject
{
+ String ID = "id";
+ String NAME = "name";
+ String DURABLE = "durable";
+ String LIFETIME_POLICY = "lifetimePolicy";
+ String STATE = "state";
+ String TIME_TO_LIVE = "timeToLive";
+ String CREATED = "created";
+ String UPDATED = "updated";
+ String DESCRIPTION = "description";
+ String PATH = "path";
+ String PASSWORD = "password";
+ String TYPE = "type";
String CERTIFICATE_ALIAS = "certificateAlias";
+ String KEY_MANAGER_FACTORY_ALGORITHM = "keyManagerFactoryAlgorithm";
public static final Collection<String> AVAILABLE_ATTRIBUTES =
Collections.unmodifiableList(
@@ -44,8 +57,11 @@ public interface KeyStore extends TrustStore
PATH,
PASSWORD,
TYPE,
- KEY_MANAGER_FACTORY_ALGORITHM,
- CERTIFICATE_ALIAS
+ CERTIFICATE_ALIAS,
+ KEY_MANAGER_FACTORY_ALGORITHM
));
+ public String getPassword();
+
+ public void setPassword(String password);
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/Port.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/Port.java
index 33ba34767d..7ff5f04ee7 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/Port.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/Port.java
@@ -45,6 +45,8 @@ public interface Port extends ConfiguredObject
String NEED_CLIENT_AUTH = "needClientAuth";
String WANT_CLIENT_AUTH = "wantClientAuth";
String AUTHENTICATION_PROVIDER = "authenticationProvider";
+ String KEY_STORE = "keyStore";
+ String TRUST_STORES = "trustStores";
// Attributes
public static final Collection<String> AVAILABLE_ATTRIBUTES =
@@ -67,7 +69,9 @@ public interface Port extends ConfiguredObject
RECEIVE_BUFFER_SIZE,
NEED_CLIENT_AUTH,
WANT_CLIENT_AUTH,
- AUTHENTICATION_PROVIDER
+ AUTHENTICATION_PROVIDER,
+ KEY_STORE,
+ TRUST_STORES
));
@@ -75,6 +79,10 @@ public interface Port extends ConfiguredObject
int getPort();
+ KeyStore getKeyStore();
+
+ Collection<TrustStore> getTrustStores();
+
Collection<Transport> getTransports();
void addTransport(Transport transport) throws IllegalStateException,
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/TrustStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/TrustStore.java
index 53498ab431..c686e7bd50 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/TrustStore.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/TrustStore.java
@@ -38,9 +38,9 @@ public interface TrustStore extends ConfiguredObject
String PATH = "path";
String PASSWORD = "password";
- String PEERS_ONLY = "peersOnly";
String TYPE = "type";
- String KEY_MANAGER_FACTORY_ALGORITHM = "keyManagerFactoryAlgorithm";
+ String PEERS_ONLY = "peersOnly";
+ String TRUST_MANAGER_FACTORY_ALGORITHM = "trustManagerFactoryAlgorithm";
public static final Collection<String> AVAILABLE_ATTRIBUTES =
Collections.unmodifiableList(
@@ -56,9 +56,9 @@ public interface TrustStore extends ConfiguredObject
DESCRIPTION,
PATH,
PASSWORD,
- PEERS_ONLY,
TYPE,
- KEY_MANAGER_FACTORY_ALGORITHM
+ PEERS_ONLY,
+ TRUST_MANAGER_FACTORY_ALGORITHM
));
public String getPassword();
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/AbstractAdapter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/AbstractAdapter.java
index 20929a337a..51fd3a5c78 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/AbstractAdapter.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/AbstractAdapter.java
@@ -63,6 +63,7 @@ abstract class AbstractAdapter implements ConfiguredObject
{
if (attributes.containsKey(name))
{
+ //TODO: dont put nulls
_attributes.put(name, attributes.get(name));
}
}
@@ -254,6 +255,7 @@ abstract class AbstractAdapter implements ConfiguredObject
if((currentValue == null && expected == null)
|| (currentValue != null && currentValue.equals(expected)))
{
+ //TODO: dont put nulls
_attributes.put(name, desired);
return true;
}
@@ -397,4 +399,51 @@ abstract class AbstractAdapter implements ConfiguredObject
{
return _defaultAttributes;
}
+
+ /**
+ * Returns a map of effective attribute values that would result
+ * if applying the supplied changes. Does not apply the changes.
+ */
+ protected Map<String, Object> generateEffectiveAttributes(Map<String,Object> changedValues)
+ {
+ //Build a new set of effective attributes that would be
+ //the result of applying the attribute changes, so we
+ //can validate the configuration that would result
+
+ Map<String, Object> defaultValues = getDefaultAttributes();
+ Map<String, Object> existingActualValues = getActualAttributes();
+
+ //create a new merged map, starting with the defaults
+ Map<String, Object> merged = new HashMap<String, Object>(defaultValues);
+
+ for(String name : getAttributeNames())
+ {
+ if(changedValues.containsKey(name))
+ {
+ Object changedValue = changedValues.get(name);
+ if(changedValue != null)
+ {
+ //use the new non-null value for the merged values
+ merged.put(name, changedValue);
+ }
+ else
+ {
+ //we just use the default (if there was one) since the changed
+ //value is null and effectively clears any existing actual value
+ }
+ }
+ else if(existingActualValues.get(name) != null)
+ {
+ //Use existing non-null actual value for the merge
+ merged.put(name, existingActualValues.get(name));
+ }
+ else
+ {
+ //There was neither a change or an existing non-null actual
+ //value, so just use the default value (if there was one).
+ }
+ }
+
+ return merged;
+ }
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/AbstractKeyStoreAdapter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/AbstractKeyStoreAdapter.java
index 80196c395e..707cf8076d 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/AbstractKeyStoreAdapter.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/AbstractKeyStoreAdapter.java
@@ -37,20 +37,21 @@ import org.apache.qpid.server.util.MapValueConverter;
public abstract class AbstractKeyStoreAdapter extends AbstractAdapter
{
+ public static final String DUMMY_PASSWORD_MASK = "********";
+ public static final String DEFAULT_KEYSTORE_TYPE = java.security.KeyStore.getDefaultType();
+
private String _name;
private String _password;
- protected AbstractKeyStoreAdapter(UUID id, Broker broker, Map<String, Object> attributes)
+ protected AbstractKeyStoreAdapter(UUID id, Broker broker, Map<String, Object> defaults,
+ Map<String, Object> attributes)
{
- super(id, broker.getTaskExecutor());
+ super(id, defaults, attributes, broker.getTaskExecutor());
addParent(Broker.class, broker);
+
_name = MapValueConverter.getStringAttribute(TrustStore.NAME, attributes);
_password = MapValueConverter.getStringAttribute(TrustStore.PASSWORD, attributes);
- setMandatoryAttribute(TrustStore.PATH, attributes);
- setOptionalAttribute(TrustStore.PEERS_ONLY, attributes);
- setOptionalAttribute(TrustStore.TYPE, attributes);
- setOptionalAttribute(TrustStore.KEY_MANAGER_FACTORY_ALGORITHM, attributes);
- setOptionalAttribute(TrustStore.DESCRIPTION, attributes);
+ MapValueConverter.assertMandatoryAttribute(KeyStore.PATH, attributes);
}
@Override
@@ -163,15 +164,16 @@ public abstract class AbstractKeyStoreAdapter extends AbstractAdapter
}
else if(KeyStore.PASSWORD.equals(name))
{
- return null; // for security reasons we don't expose the password
+ // For security reasons we don't expose the password
+ if (getPassword() != null)
+ {
+ return DUMMY_PASSWORD_MASK;
+ }
+
+ return null;
}
- return super.getAttribute(name);
- }
- @Override
- protected boolean setState(State currentState, State desiredState)
- {
- return false;
+ return super.getAttribute(name);
}
public String getPassword()
@@ -183,25 +185,4 @@ public abstract class AbstractKeyStoreAdapter extends AbstractAdapter
{
_password = password;
}
-
- private void setMandatoryAttribute(String name, Map<String, Object> attributeValues)
- {
- changeAttribute(name, null, MapValueConverter.getStringAttribute(name, attributeValues));
- }
-
- private void setOptionalAttribute(String name, Map<String, Object> attributeValues)
- {
- Object attrValue = attributeValues.get(name);
- if (attrValue != null)
- {
- if (attrValue instanceof Boolean)
- {
- changeAttribute(name, null, MapValueConverter.getBooleanAttribute(name, attributeValues));
- }
- else
- {
- changeAttribute(name, null, MapValueConverter.getStringAttribute(name, attributeValues));
- }
- }
- }
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/AmqpPortAdapter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/AmqpPortAdapter.java
index e7057f89d3..71f5397d2b 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/AmqpPortAdapter.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/AmqpPortAdapter.java
@@ -133,15 +133,11 @@ public class AmqpPortAdapter extends PortAdapter
private SSLContext createSslContext()
{
- KeyStore keyStore = _broker.getDefaultKeyStore();
- if (keyStore == null)
- {
- throw new IllegalConfigurationException("SSL was requested on AMQP port '"
- + this.getName() + "' but no key store defined");
- }
+ KeyStore keyStore = getKeyStore();
- Collection<TrustStore> trustStores = _broker.getTrustStores();
- if (((Boolean)getAttribute(NEED_CLIENT_AUTH) || (Boolean)getAttribute(WANT_CLIENT_AUTH)) && trustStores.isEmpty())
+ Collection<TrustStore> trustStores = getTrustStores();
+ boolean needClientCert = (Boolean)getAttribute(NEED_CLIENT_AUTH) || (Boolean)getAttribute(WANT_CLIENT_AUTH);
+ if (needClientCert && trustStores.isEmpty())
{
throw new IllegalConfigurationException("Client certificate authentication is enabled on AMQP port '"
+ this.getName() + "' but no trust store defined");
@@ -165,7 +161,7 @@ public class AmqpPortAdapter extends PortAdapter
trustStore.getPassword(),
(String)trustStore.getAttribute(TrustStore.TYPE),
(Boolean) trustStore.getAttribute(TrustStore.PEERS_ONLY),
- (String)trustStore.getAttribute(TrustStore.KEY_MANAGER_FACTORY_ALGORITHM)));
+ (String)trustStore.getAttribute(TrustStore.TRUST_MANAGER_FACTORY_ALGORITHM)));
}
sslContext = SSLContextFactory.buildClientContext(trstWrappers, keystorePath,
keystorePassword, keystoreType,
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/BrokerAdapter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/BrokerAdapter.java
index e968d91e79..ae30f70877 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/BrokerAdapter.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/BrokerAdapter.java
@@ -24,7 +24,6 @@ import java.lang.reflect.Type;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.security.AccessControlException;
-import java.security.KeyStoreException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -32,13 +31,12 @@ import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
-import javax.net.ssl.KeyManagerFactory;
-import java.security.cert.Certificate;
-
import org.apache.log4j.Logger;
import org.apache.qpid.common.QpidProperties;
import org.apache.qpid.server.configuration.ConfigurationEntryStore;
import org.apache.qpid.server.configuration.IllegalConfigurationException;
+import org.apache.qpid.server.configuration.store.ManagementModeStoreHandler;
+import org.apache.qpid.server.configuration.updater.TaskExecutor;
import org.apache.qpid.server.logging.LogRecorder;
import org.apache.qpid.server.logging.RootMessageLogger;
import org.apache.qpid.server.logging.actors.BrokerActor;
@@ -58,22 +56,18 @@ import org.apache.qpid.server.model.Statistics;
import org.apache.qpid.server.model.TrustStore;
import org.apache.qpid.server.model.UUIDGenerator;
import org.apache.qpid.server.model.VirtualHost;
-import org.apache.qpid.server.configuration.store.ManagementModeStoreHandler;
-import org.apache.qpid.server.configuration.updater.TaskExecutor;
+import org.apache.qpid.server.security.SecurityManager;
+import org.apache.qpid.server.security.SubjectCreator;
import org.apache.qpid.server.security.access.Operation;
import org.apache.qpid.server.security.group.FileGroupManager;
import org.apache.qpid.server.security.group.GroupManager;
-import org.apache.qpid.server.security.SecurityManager;
-import org.apache.qpid.server.security.SubjectCreator;
import org.apache.qpid.server.stats.StatisticsGatherer;
import org.apache.qpid.server.store.MessageStoreCreator;
import org.apache.qpid.server.util.MapValueConverter;
import org.apache.qpid.server.virtualhost.VirtualHostRegistry;
-import org.apache.qpid.transport.network.security.ssl.SSLUtil;
public class BrokerAdapter extends AbstractAdapter implements Broker, ConfigurationChangeListener
{
-
private static final Logger LOGGER = Logger.getLogger(BrokerAdapter.class);
@SuppressWarnings("serial")
@@ -100,13 +94,6 @@ public class BrokerAdapter extends AbstractAdapter implements Broker, Configurat
put(DEFAULT_VIRTUAL_HOST, String.class);
put(DEFAULT_AUTHENTICATION_PROVIDER, String.class);
- put(KEY_STORE_PATH, String.class);
- put(KEY_STORE_PASSWORD, String.class);
- put(KEY_STORE_CERT_ALIAS, String.class);
- put(TRUST_STORE_PATH, String.class);
- put(TRUST_STORE_PASSWORD, String.class);
- put(PEER_STORE_PATH, String.class);
- put(PEER_STORE_PASSWORD, String.class);
put(GROUP_FILE, String.class);
put(VIRTUALHOST_STORE_TRANSACTION_IDLE_TIMEOUT_CLOSE, Long.class);
put(VIRTUALHOST_STORE_TRANSACTION_IDLE_TIMEOUT_WARN, Long.class);
@@ -133,12 +120,7 @@ public class BrokerAdapter extends AbstractAdapter implements Broker, Configurat
public static final long DEFAULT_STORE_TRANSACTION_IDLE_TIMEOUT_WARN = 0l;
public static final long DEFAULT_STORE_TRANSACTION_OPEN_TIMEOUT_CLOSE = 0l;
public static final long DEFAULT_STORE_TRANSACTION_OPEN_TIMEOUT_WARN = 0l;
- private static final String DEFAULT_KEY_STORE_NAME = "defaultKeyStore";
- private static final String DEFAULT_TRUST_STORE_NAME = "defaultTrustStore";
private static final String DEFAULT_GROUP_PROVIDER_NAME = "defaultGroupProvider";
- private static final String DEFAULT_PEER_STORE_NAME = "defaultPeerStore";
-
- private static final String DUMMY_PASSWORD_MASK = "********";
@SuppressWarnings("serial")
private static final Map<String, Object> DEFAULTS = Collections.unmodifiableMap(new HashMap<String, Object>(){{
@@ -182,16 +164,14 @@ public class BrokerAdapter extends AbstractAdapter implements Broker, Configurat
private final Map<UUID, AuthenticationProvider> _authenticationProviders = new HashMap<UUID, AuthenticationProvider>();
private final Map<String, GroupProvider> _groupProviders = new HashMap<String, GroupProvider>();
private final Map<UUID, ConfiguredObject> _plugins = new HashMap<UUID, ConfiguredObject>();
- private final Map<UUID, KeyStore> _keyStores = new HashMap<UUID, KeyStore>();
- private final Map<UUID, TrustStore> _trustStores = new HashMap<UUID, TrustStore>();
+ private final Map<String, KeyStore> _keyStores = new HashMap<String, KeyStore>();
+ private final Map<String, TrustStore> _trustStores = new HashMap<String, TrustStore>();
private final AuthenticationProviderFactory _authenticationProviderFactory;
private AuthenticationProvider _defaultAuthenticationProvider;
private final PortFactory _portFactory;
private final SecurityManager _securityManager;
- private final UUID _defaultKeyStoreId;
- private final UUID _defaultTrustStoreId;
private final Collection<String> _supportedStoreTypes;
private final ConfigurationEntryStore _brokerStore;
@@ -212,8 +192,6 @@ public class BrokerAdapter extends AbstractAdapter implements Broker, Configurat
_portFactory = portFactory;
_securityManager = new SecurityManager((String)getAttribute(ACL_FILE));
addChangeListener(_securityManager);
- _defaultKeyStoreId = UUIDGenerator.generateBrokerChildUUID(KeyStore.class.getSimpleName(), DEFAULT_KEY_STORE_NAME);
- _defaultTrustStoreId = UUIDGenerator.generateBrokerChildUUID(TrustStore.class.getSimpleName(), DEFAULT_TRUST_STORE_NAME);
createBrokerChildrenFromAttributes();
_supportedStoreTypes = new MessageStoreCreator().getStoreTypes();
_brokerStore = brokerStore;
@@ -226,9 +204,6 @@ public class BrokerAdapter extends AbstractAdapter implements Broker, Configurat
private void createBrokerChildrenFromAttributes()
{
createGroupProvider();
- createKeyStore();
- createTrustStore();
- createPeerStore();
}
private void createGroupProvider()
@@ -248,80 +223,12 @@ public class BrokerAdapter extends AbstractAdapter implements Broker, Configurat
}
}
- private void createKeyStore()
- {
- Map<String, Object> actualAttributes = getActualAttributes();
- String keyStorePath = (String) getAttribute(KEY_STORE_PATH);
- if (keyStorePath != null)
- {
- Map<String, Object> keyStoreAttributes = new HashMap<String, Object>();
- keyStoreAttributes.put(KeyStore.NAME, DEFAULT_KEY_STORE_NAME);
- keyStoreAttributes.put(KeyStore.PATH, keyStorePath);
- keyStoreAttributes.put(KeyStore.PASSWORD, (String) actualAttributes.get(KEY_STORE_PASSWORD));
- keyStoreAttributes.put(KeyStore.TYPE, java.security.KeyStore.getDefaultType());
- keyStoreAttributes.put(KeyStore.CERTIFICATE_ALIAS, getAttribute(KEY_STORE_CERT_ALIAS));
- keyStoreAttributes.put(KeyStore.KEY_MANAGER_FACTORY_ALGORITHM, KeyManagerFactory.getDefaultAlgorithm());
- KeyStoreAdapter keyStoreAdapter = new KeyStoreAdapter(_defaultKeyStoreId, this, keyStoreAttributes);
- _keyStores.put(keyStoreAdapter.getId(), keyStoreAdapter);
- }
- else
- {
- _keyStores.remove(_defaultKeyStoreId);
- }
- }
-
- private void createTrustStore()
- {
- Map<String, Object> actualAttributes = getActualAttributes();
- String trustStorePath = (String) getAttribute(TRUST_STORE_PATH);
- if (trustStorePath != null)
- {
- Map<String, Object> trsustStoreAttributes = new HashMap<String, Object>();
- trsustStoreAttributes.put(TrustStore.NAME, DEFAULT_TRUST_STORE_NAME);
- trsustStoreAttributes.put(TrustStore.PATH, trustStorePath);
- trsustStoreAttributes.put(TrustStore.PEERS_ONLY, Boolean.FALSE);
- trsustStoreAttributes.put(TrustStore.PASSWORD, (String) actualAttributes.get(TRUST_STORE_PASSWORD));
- trsustStoreAttributes.put(TrustStore.TYPE, java.security.KeyStore.getDefaultType());
- trsustStoreAttributes.put(TrustStore.KEY_MANAGER_FACTORY_ALGORITHM, KeyManagerFactory.getDefaultAlgorithm());
- TrustStoreAdapter trustStore = new TrustStoreAdapter(_defaultTrustStoreId, this, trsustStoreAttributes);
- _trustStores.put(trustStore.getId(), trustStore);
- }
- else
- {
- _trustStores.remove(_defaultTrustStoreId);
- }
- }
-
- private void createPeerStore()
- {
- Map<String, Object> actualAttributes = getActualAttributes();
- String peerStorePath = (String) getAttribute(PEER_STORE_PATH);
- UUID peerStoreId = UUIDGenerator.generateBrokerChildUUID(TrustStore.class.getSimpleName(), DEFAULT_PEER_STORE_NAME);
- if (peerStorePath != null)
- {
- Map<String, Object> peerStoreAttributes = new HashMap<String, Object>();
- peerStoreAttributes.put(TrustStore.NAME, peerStoreId.toString());
- peerStoreAttributes.put(TrustStore.PATH, peerStorePath);
- peerStoreAttributes.put(TrustStore.PEERS_ONLY, Boolean.TRUE);
- peerStoreAttributes.put(TrustStore.PASSWORD, (String) actualAttributes.get(PEER_STORE_PASSWORD));
- peerStoreAttributes.put(TrustStore.TYPE, java.security.KeyStore.getDefaultType());
- peerStoreAttributes.put(TrustStore.KEY_MANAGER_FACTORY_ALGORITHM, KeyManagerFactory.getDefaultAlgorithm());
- TrustStoreAdapter trustStore = new TrustStoreAdapter(peerStoreId, this, peerStoreAttributes);
- _trustStores.put(trustStore.getId(), trustStore);
- }
- else
- {
- _trustStores.remove(peerStoreId);
- }
- }
-
public Collection<VirtualHost> getVirtualHosts()
{
synchronized(_vhostAdapters)
{
return new ArrayList<VirtualHost>(_vhostAdapters.values());
}
-
}
public Collection<Port> getPorts()
@@ -354,6 +261,22 @@ public class BrokerAdapter extends AbstractAdapter implements Broker, Configurat
return null;
}
+ public KeyStore findKeyStoreByName(String keyStoreName)
+ {
+ synchronized(_keyStores)
+ {
+ return _keyStores.get(keyStoreName);
+ }
+ }
+
+ public TrustStore findTrustStoreByName(String trustStoreName)
+ {
+ synchronized(_trustStores)
+ {
+ return _trustStores.get(trustStoreName);
+ }
+ }
+
@Override
public AuthenticationProvider getDefaultAuthenticationProvider()
{
@@ -396,14 +319,14 @@ public class BrokerAdapter extends AbstractAdapter implements Broker, Configurat
// permission has already been granted to create the virtual host
// disable further access check on other operations, e.g. create exchange
- _securityManager.setAccessChecksDisabled(true);
+ SecurityManager.setAccessChecksDisabled(true);
try
{
virtualHostAdapter.setDesiredState(State.INITIALISING, State.ACTIVE);
}
finally
{
- _securityManager.setAccessChecksDisabled(false);
+ SecurityManager.setAccessChecksDisabled(false);
}
return virtualHostAdapter;
}
@@ -526,6 +449,14 @@ public class BrokerAdapter extends AbstractAdapter implements Broker, Configurat
{
return (C) createAuthenticationProvider(attributes);
}
+ else if(childClass == KeyStore.class)
+ {
+ return (C) createKeyStore(attributes);
+ }
+ else if(childClass == TrustStore.class)
+ {
+ return (C) createTrustStore(attributes);
+ }
else
{
throw new IllegalArgumentException("Cannot create child of class " + childClass.getSimpleName());
@@ -618,40 +549,76 @@ public class BrokerAdapter extends AbstractAdapter implements Broker, Configurat
throw new UnsupportedOperationException("Not implemented yet!");
}
+ private KeyStore createKeyStore(Map<String, Object> attributes)
+ {
+ KeyStore keyStore = new KeyStoreAdapter(UUIDGenerator.generateRandomUUID(), this, attributes);
+ addKeyStore(keyStore);
+
+ return keyStore;
+ }
+
+ private TrustStore createTrustStore(Map<String, Object> attributes)
+ {
+ TrustStore trustStore = new TrustStoreAdapter(UUIDGenerator.generateRandomUUID(), this, attributes);
+ addTrustStore(trustStore);
+
+ return trustStore;
+ }
+
private void addKeyStore(KeyStore keyStore)
{
synchronized (_keyStores)
{
- if(_keyStores.containsKey(keyStore.getId()))
+ if(_keyStores.containsKey(keyStore.getName()))
{
- throw new IllegalConfigurationException("Cannot add KeyStore because one with id " + keyStore.getId() + " already exists");
+ throw new IllegalConfigurationException("Can't add KeyStore because one with name " + keyStore.getName() + " already exists");
}
- _keyStores.put(keyStore.getId(), keyStore);
+ _keyStores.put(keyStore.getName(), keyStore);
}
keyStore.addChangeListener(this);
}
private boolean deleteKeyStore(KeyStore object)
{
- throw new UnsupportedOperationException("Not implemented yet!");
+ synchronized(_keyStores)
+ {
+ String name = object.getName();
+ KeyStore removedKeyStore = _keyStores.remove(name);
+ if(removedKeyStore != null)
+ {
+ removedKeyStore.removeChangeListener(this);
+ }
+
+ return removedKeyStore != null;
+ }
}
private void addTrustStore(TrustStore trustStore)
{
synchronized (_trustStores)
{
- if(_trustStores.containsKey(trustStore.getId()))
+ if(_trustStores.containsKey(trustStore.getName()))
{
- throw new IllegalConfigurationException("Cannot add TrustStore because one with id " + trustStore.getId() + " already exists");
+ throw new IllegalConfigurationException("Can't add TrustStore because one with name " + trustStore.getName() + " already exists");
}
- _trustStores.put(trustStore.getId(), trustStore);
+ _trustStores.put(trustStore.getName(), trustStore);
}
trustStore.addChangeListener(this);
}
private boolean deleteTrustStore(TrustStore object)
{
- throw new UnsupportedOperationException("Not implemented yet!");
+ synchronized(_trustStores)
+ {
+ String name = object.getName();
+ TrustStore removedTrustStore = _trustStores.remove(name);
+ if(removedTrustStore != null)
+ {
+ removedTrustStore.removeChangeListener(this);
+ }
+
+ return removedTrustStore != null;
+ }
}
@Override
@@ -726,14 +693,6 @@ public class BrokerAdapter extends AbstractAdapter implements Broker, Configurat
{
return _authenticationProviderFactory.getSupportedAuthenticationProviders();
}
- else if (KEY_STORE_PASSWORD.equals(name) || TRUST_STORE_PASSWORD.equals(name) || PEER_STORE_PASSWORD.equals(name))
- {
- if (getActualAttributes().get(name) != null)
- {
- return DUMMY_PASSWORD_MASK;
- }
- return null;
- }
else if (MODEL_VERSION.equals(name))
{
return Model.MODEL_MAJOR_VERSION + "." + Model.MODEL_MINOR_VERSION;
@@ -885,6 +844,7 @@ public class BrokerAdapter extends AbstractAdapter implements Broker, Configurat
{
childDeleted = deleteTrustStore((TrustStore)object);
}
+
if(childDeleted)
{
childRemoved(object);
@@ -1034,18 +994,6 @@ public class BrokerAdapter extends AbstractAdapter implements Broker, Configurat
}
@Override
- public KeyStore getDefaultKeyStore()
- {
- return _keyStores.get(_defaultKeyStoreId);
- }
-
- @Override
- public TrustStore getDefaultTrustStore()
- {
- return _trustStores.get(_defaultTrustStoreId);
- }
-
- @Override
public TaskExecutor getTaskExecutor()
{
return super.getTaskExecutor();
@@ -1058,9 +1006,6 @@ public class BrokerAdapter extends AbstractAdapter implements Broker, Configurat
Map<String, Object> convertedAttributes = MapValueConverter.convert(attributes, ATTRIBUTE_TYPES);
validateAttributes(convertedAttributes);
- boolean keyStoreChanged = false;
- boolean trustStoreChanged = false;
- boolean peerStoreChanged = false;
Collection<String> names = AVAILABLE_ATTRIBUTES;
for (String name : names)
{
@@ -1081,34 +1026,11 @@ public class BrokerAdapter extends AbstractAdapter implements Broker, Configurat
_defaultAuthenticationProvider = findAuthenticationProviderByName((String)desired);
}
}
- else if (KEY_STORE_PATH.equals(name) || KEY_STORE_PASSWORD.equals(name) || KEY_STORE_CERT_ALIAS.equals(name))
- {
- keyStoreChanged = true;
- }
- else if (TRUST_STORE_PATH.equals(name) || TRUST_STORE_PASSWORD.equals(name))
- {
- trustStoreChanged = true;
- }
- else if (PEER_STORE_PATH.equals(name) || PEER_STORE_PASSWORD.equals(name))
- {
- peerStoreChanged = true;
- }
+
attributeSet(name, expected, desired);
}
}
}
- if (keyStoreChanged)
- {
- createKeyStore();
- }
- if (trustStoreChanged)
- {
- createTrustStore();
- }
- if (peerStoreChanged)
- {
- createPeerStore();
- }
}
private void validateAttributes(Map<String, Object> convertedAttributes)
@@ -1125,9 +1047,7 @@ public class BrokerAdapter extends AbstractAdapter implements Broker, Configurat
// create a group manager to validate the groups specified in file
new FileGroupManager(groupFile);
}
- validateKeyStoreAttributes(convertedAttributes, "key store", KEY_STORE_PATH, KEY_STORE_PASSWORD, KEY_STORE_CERT_ALIAS);
- validateKeyStoreAttributes(convertedAttributes, "trust store", TRUST_STORE_PATH, TRUST_STORE_PASSWORD, null);
- validateKeyStoreAttributes(convertedAttributes, "peer store", PEER_STORE_PATH, PEER_STORE_PASSWORD, null);
+
String defaultAuthenticationProvider = (String) convertedAttributes.get(DEFAULT_AUTHENTICATION_PROVIDER);
if (defaultAuthenticationProvider != null)
{
@@ -1176,59 +1096,6 @@ public class BrokerAdapter extends AbstractAdapter implements Broker, Configurat
}
}
- private void validateKeyStoreAttributes(Map<String, Object> convertedAttributes, String type, String pathAttribute,
- String passwordAttribute, String aliasAttribute)
- {
- String keyStoreFile = (String) convertedAttributes.get(pathAttribute);
- String password = (String) convertedAttributes.get(passwordAttribute);
- String alias = aliasAttribute!= null? (String) convertedAttributes.get(aliasAttribute) : null;
- if (keyStoreFile != null || password != null || alias != null)
- {
- if (keyStoreFile == null)
- {
- keyStoreFile = (String) getActualAttributes().get(pathAttribute);
- }
- if (password == null)
- {
- password = (String) getActualAttributes().get(passwordAttribute);
- }
- java.security.KeyStore keyStore = null;
- try
- {
- keyStore = SSLUtil.getInitializedKeyStore(keyStoreFile, password, java.security.KeyStore.getDefaultType());
- }
- catch (Exception e)
- {
- throw new IllegalConfigurationException("Cannot instantiate " + type + " at " + keyStoreFile, e);
- }
- if (aliasAttribute != null)
- {
- if (alias == null)
- {
- alias = (String) getActualAttributes().get(aliasAttribute);
- }
- if (alias != null)
- {
- Certificate cert = null;
- try
- {
- cert = keyStore.getCertificate(alias);
- }
- catch (KeyStoreException e)
- {
- // key store should be initialized above
- throw new RuntimeException("Key store has not been initialized", e);
- }
- if (cert == null)
- {
- throw new IllegalConfigurationException("Cannot find a certificate with alias " + alias + "in " + type
- + " : " + keyStoreFile);
- }
- }
- }
- }
- }
-
@Override
protected void authoriseSetAttribute(String name, Object expected, Object desired) throws AccessControlException
{
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/KeyStoreAdapter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/KeyStoreAdapter.java
index 113d895e62..4d4d3bb31d 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/KeyStoreAdapter.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/KeyStoreAdapter.java
@@ -20,23 +20,63 @@
*/
package org.apache.qpid.server.model.adapter;
+import java.lang.reflect.Type;
+import java.security.AccessControlException;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.Certificate;
+import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
+import javax.net.ssl.KeyManagerFactory;
+
+import org.apache.qpid.server.configuration.IllegalConfigurationException;
import org.apache.qpid.server.model.Broker;
+import org.apache.qpid.server.model.IntegrityViolationException;
import org.apache.qpid.server.model.KeyStore;
+import org.apache.qpid.server.model.Port;
+import org.apache.qpid.server.model.State;
+import org.apache.qpid.server.security.access.Operation;
+import org.apache.qpid.server.util.MapValueConverter;
+import org.apache.qpid.transport.network.security.ssl.SSLUtil;
public class KeyStoreAdapter extends AbstractKeyStoreAdapter implements KeyStore
{
+ @SuppressWarnings("serial")
+ public static final Map<String, Type> ATTRIBUTE_TYPES = Collections.unmodifiableMap(new HashMap<String, Type>(){{
+ put(NAME, String.class);
+ put(PATH, String.class);
+ put(PASSWORD, String.class);
+ put(TYPE, String.class);
+ put(CERTIFICATE_ALIAS, String.class);
+ put(KEY_MANAGER_FACTORY_ALGORITHM, String.class);
+ }});
+
+ @SuppressWarnings("serial")
+ public static final Map<String, Object> DEFAULTS = Collections.unmodifiableMap(new HashMap<String, Object>(){{
+ put(KeyStore.TYPE, DEFAULT_KEYSTORE_TYPE);
+ put(KeyStore.KEY_MANAGER_FACTORY_ALGORITHM, KeyManagerFactory.getDefaultAlgorithm());
+ }});
+
+ private Broker _broker;
public KeyStoreAdapter(UUID id, Broker broker, Map<String, Object> attributes)
{
- super(id, broker, attributes);
- if (attributes.get(CERTIFICATE_ALIAS) != null)
- {
- changeAttribute(CERTIFICATE_ALIAS, null, attributes.get(CERTIFICATE_ALIAS));
- }
+ super(id, broker, DEFAULTS, MapValueConverter.convert(attributes, ATTRIBUTE_TYPES));
+ _broker = broker;
+
+ String keyStorePath = (String)getAttribute(KeyStore.PATH);
+ String keyStorePassword = getPassword();
+ String keyStoreType = (String)getAttribute(KeyStore.TYPE);
+ String keyManagerFactoryAlgorithm = (String)getAttribute(KeyStore.KEY_MANAGER_FACTORY_ALGORITHM);
+ String certAlias = (String)getAttribute(KeyStore.CERTIFICATE_ALIAS);
+
+ validateKeyStoreAttributes(keyStoreType, keyStorePath, keyStorePassword,
+ certAlias, keyManagerFactoryAlgorithm);
}
@Override
@@ -45,4 +85,129 @@ public class KeyStoreAdapter extends AbstractKeyStoreAdapter implements KeyStore
return AVAILABLE_ATTRIBUTES;
}
+ @Override
+ protected boolean setState(State currentState, State desiredState)
+ {
+ if(desiredState == State.DELETED)
+ {
+ // verify that it is not in use
+ String storeName = getName();
+
+ Collection<Port> ports = new ArrayList<Port>(_broker.getPorts());
+ for (Port port : ports)
+ {
+ if (storeName.equals(port.getAttribute(Port.KEY_STORE)))
+ {
+ throw new IntegrityViolationException("Key store '" + storeName + "' can't be deleted as it is in use by a port:" + port.getName());
+ }
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
+ @Override
+ protected void authoriseSetDesiredState(State currentState, State desiredState) throws AccessControlException
+ {
+ if(desiredState == State.DELETED)
+ {
+ if (!_broker.getSecurityManager().authoriseConfiguringBroker(getName(), KeyStore.class, Operation.DELETE))
+ {
+ throw new AccessControlException("Deletion of key store is denied");
+ }
+ }
+ }
+
+ @Override
+ protected void authoriseSetAttribute(String name, Object expected, Object desired) throws AccessControlException
+ {
+ authoriseSetAttribute();
+ }
+
+ @Override
+ protected void authoriseSetAttributes(Map<String, Object> attributes) throws AccessControlException
+ {
+ authoriseSetAttribute();
+ }
+
+ private void authoriseSetAttribute()
+ {
+ if (!_broker.getSecurityManager().authoriseConfiguringBroker(getName(), KeyStore.class, Operation.UPDATE))
+ {
+ throw new AccessControlException("Setting key store attributes is denied");
+ }
+ }
+
+ @Override
+ protected void changeAttributes(Map<String, Object> attributes)
+ {
+ Map<String, Object> changedValues = MapValueConverter.convert(attributes, ATTRIBUTE_TYPES);
+ if(changedValues.containsKey(KeyStore.NAME))
+ {
+ String newName = (String) changedValues.get(KeyStore.NAME);
+ if(!getName().equals(newName))
+ {
+ throw new IllegalConfigurationException("Changing the key store name is not allowed");
+ }
+ }
+
+ Map<String, Object> merged = generateEffectiveAttributes(changedValues);
+
+ String keyStorePath = (String)merged.get(KeyStore.PATH);
+ String keyStorePassword = (String) merged.get(KeyStore.PASSWORD);
+ String keyStoreType = (String)merged.get(KeyStore.TYPE);
+ String keyManagerFactoryAlgorithm = (String)merged.get(KeyStore.KEY_MANAGER_FACTORY_ALGORITHM);
+ String certAlias = (String)merged.get(KeyStore.CERTIFICATE_ALIAS);
+
+ validateKeyStoreAttributes(keyStoreType, keyStorePath, keyStorePassword,
+ certAlias, keyManagerFactoryAlgorithm);
+
+ super.changeAttributes(changedValues);
+ }
+
+ private void validateKeyStoreAttributes(String type, String keyStorePath,
+ String keyStorePassword, String alias,
+ String keyManagerFactoryAlgorithm)
+ {
+ java.security.KeyStore keyStore = null;
+ try
+ {
+ keyStore = SSLUtil.getInitializedKeyStore(keyStorePath, keyStorePassword, type);
+ }
+ catch (Exception e)
+ {
+ throw new IllegalConfigurationException("Cannot instantiate key store at " + keyStorePath, e);
+ }
+
+ if (alias != null)
+ {
+ Certificate cert = null;
+ try
+ {
+ cert = keyStore.getCertificate(alias);
+ }
+ catch (KeyStoreException e)
+ {
+ // key store should be initialized above
+ throw new RuntimeException("Key store has not been initialized", e);
+ }
+ if (cert == null)
+ {
+ throw new IllegalConfigurationException("Cannot find a certificate with alias " + alias
+ + "in key store : " + keyStorePath);
+ }
+ }
+
+ try
+ {
+ KeyManagerFactory.getInstance(keyManagerFactoryAlgorithm);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw new IllegalConfigurationException("Unknown keyManagerFactoryAlgorithm: "
+ + keyManagerFactoryAlgorithm);
+ }
+ }
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/PortAdapter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/PortAdapter.java
index 4250de17a7..0c1249d20e 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/PortAdapter.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/PortAdapter.java
@@ -37,12 +37,14 @@ import org.apache.qpid.server.model.AuthenticationProvider;
import org.apache.qpid.server.model.Broker;
import org.apache.qpid.server.model.ConfiguredObject;
import org.apache.qpid.server.model.Connection;
+import org.apache.qpid.server.model.KeyStore;
import org.apache.qpid.server.model.LifetimePolicy;
import org.apache.qpid.server.model.Port;
import org.apache.qpid.server.model.Protocol;
import org.apache.qpid.server.model.State;
import org.apache.qpid.server.model.Statistics;
import org.apache.qpid.server.model.Transport;
+import org.apache.qpid.server.model.TrustStore;
import org.apache.qpid.server.model.VirtualHost;
import org.apache.qpid.server.model.VirtualHostAlias;
import org.apache.qpid.server.security.access.Operation;
@@ -58,6 +60,8 @@ public class PortAdapter extends AbstractAdapter implements Port
put(NAME, String.class);
put(PROTOCOLS, new ParameterizedTypeImpl(Set.class, Protocol.class));
put(TRANSPORTS, new ParameterizedTypeImpl(Set.class, Transport.class));
+ put(TRUST_STORES, new ParameterizedTypeImpl(Set.class, String.class));
+ put(KEY_STORE, String.class);
put(PORT, Integer.class);
put(TCP_NO_DELAY, Boolean.class);
put(RECEIVE_BUFFER_SIZE, Integer.class);
@@ -373,16 +377,40 @@ public class PortAdapter extends AbstractAdapter implements Port
boolean requiresCertificate = (needClientCertificate != null && needClientCertificate.booleanValue())
|| (wantClientCertificate != null && wantClientCertificate.booleanValue());
- if (transports != null && transports.contains(Transport.SSL))
+ String keyStoreName = (String) merged.get(KEY_STORE);
+ boolean hasKeyStore = keyStoreName != null;
+ if(keyStoreName != null)
{
- if (_broker.getKeyStores().isEmpty())
+ if (_broker.findKeyStoreByName(keyStoreName) == null)
{
- throw new IllegalConfigurationException("Can't create port which requires SSL as the broker has no keystore configured.");
+ throw new IllegalConfigurationException("Can't find key store with name '" + keyStoreName + "' for port " + getName());
+ }
+ }
+
+ Set<String> trustStoreNames = (Set<String>) merged.get(TRUST_STORES);
+ boolean hasTrustStore = trustStoreNames != null && !trustStoreNames.isEmpty();
+ if(hasTrustStore)
+ {
+ for (String trustStoreName : trustStoreNames)
+ {
+ if (_broker.findTrustStoreByName(trustStoreName) == null)
+ {
+ throw new IllegalConfigurationException("Cannot find trust store with name '" + trustStoreName + "'");
+ }
+ }
+ }
+
+ boolean usesSsl = transports != null && transports.contains(Transport.SSL);
+ if (usesSsl)
+ {
+ if (keyStoreName == null)
+ {
+ throw new IllegalConfigurationException("Can't create port which requires SSL but has no key store configured.");
}
- if (_broker.getTrustStores().isEmpty() && requiresCertificate)
+ if (!hasTrustStore && requiresCertificate)
{
- throw new IllegalConfigurationException("Can't create port which requests SSL client certificates as the broker has no trust/peer stores configured.");
+ throw new IllegalConfigurationException("Can't create port which requests SSL client certificates but has no trust store configured.");
}
}
else
@@ -393,9 +421,14 @@ public class PortAdapter extends AbstractAdapter implements Port
}
}
- if (protocols != null && protocols.contains(Protocol.HTTPS) && _broker.getKeyStores().isEmpty())
+ if (protocols != null && protocols.contains(Protocol.HTTPS) && !hasKeyStore)
{
- throw new IllegalConfigurationException("Can't create port which requires SSL as the broker has no keystore configured.");
+ throw new IllegalConfigurationException("Can't create port which requires SSL but has no key store configured.");
+ }
+
+ if (protocols != null && protocols.contains(Protocol.RMI) && usesSsl)
+ {
+ throw new IllegalConfigurationException("Can't create RMI Registry port which requires SSL.");
}
String authenticationProviderName = (String)merged.get(AUTHENTICATION_PROVIDER);
@@ -450,4 +483,42 @@ public class PortAdapter extends AbstractAdapter implements Port
throw new AccessControlException("Setting of port attributes is denied");
}
}
+
+ @Override
+ public KeyStore getKeyStore()
+ {
+ String keyStoreName = (String)getAttribute(Port.KEY_STORE);
+ KeyStore keyStore = _broker.findKeyStoreByName(keyStoreName);
+
+ if (keyStoreName != null && keyStore == null)
+ {
+ throw new IllegalConfigurationException("Can't find key store with name '" + keyStoreName + "' for port " + getName());
+ }
+
+ return keyStore;
+ }
+
+ @Override
+ public Collection<TrustStore> getTrustStores()
+ {
+ Set<String> trustStoreNames = (Set<String>) getAttribute(TRUST_STORES);
+ boolean hasTrustStoreName = trustStoreNames != null && !trustStoreNames.isEmpty();
+
+ final Collection<TrustStore> trustStores = new ArrayList<TrustStore>();
+ if(hasTrustStoreName)
+ {
+ for (String name : trustStoreNames)
+ {
+ TrustStore trustStore = _broker.findTrustStoreByName(name);
+ if (trustStore == null)
+ {
+ throw new IllegalConfigurationException("Can't find trust store with name '" + name + "' for port " + getName());
+ }
+
+ trustStores.add(trustStore);
+ }
+ }
+
+ return trustStores;
+ }
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/PortFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/PortFactory.java
index ffbd24997a..2efe189d73 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/PortFactory.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/PortFactory.java
@@ -106,9 +106,9 @@ public class PortFactory
port = new AmqpPortAdapter(id, broker, attributes, defaults, broker.getTaskExecutor());
boolean useClientAuth = (Boolean) port.getAttribute(Port.NEED_CLIENT_AUTH) || (Boolean) port.getAttribute(Port.WANT_CLIENT_AUTH);
- if(useClientAuth && broker.getTrustStores().isEmpty())
+ if(useClientAuth && port.getTrustStores().isEmpty())
{
- throw new IllegalConfigurationException("Can't create port which requests SSL client certificates as the broker has no trust/peer stores configured.");
+ throw new IllegalConfigurationException("Can't create port which requests SSL client certificates but has no trust stores configured.");
}
if(useClientAuth && !port.getTransports().contains(Transport.SSL))
@@ -142,13 +142,19 @@ public class PortFactory
defaults.put(Port.NAME, portValue + "-" + protocol.name());
port = new PortAdapter(id, broker, attributes, defaults, broker.getTaskExecutor());
+
+ boolean rmiPort = port.getProtocols().contains(Protocol.RMI);
+ if (rmiPort && port.getTransports().contains(Transport.SSL))
+ {
+ throw new IllegalConfigurationException("Can't create RMI registry port which requires SSL");
+ }
}
if(port.getTransports().contains(Transport.SSL) || port.getProtocols().contains(Protocol.HTTPS))
{
- if(broker.getKeyStores().isEmpty())
+ if(port.getKeyStore() == null)
{
- throw new IllegalConfigurationException("Can't create port which requires SSL as the broker has no keystore configured.");
+ throw new IllegalConfigurationException("Can't create port which requires SSL but has no key store configured.");
}
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/TrustStoreAdapter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/TrustStoreAdapter.java
index bdffe605ec..06089e43c6 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/TrustStoreAdapter.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/TrustStoreAdapter.java
@@ -20,18 +20,61 @@
*/
package org.apache.qpid.server.model.adapter;
+import java.lang.reflect.Type;
+import java.security.AccessControlException;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
+import javax.net.ssl.TrustManagerFactory;
+
+import org.apache.qpid.server.configuration.IllegalConfigurationException;
import org.apache.qpid.server.model.Broker;
+import org.apache.qpid.server.model.IntegrityViolationException;
+import org.apache.qpid.server.model.Port;
+import org.apache.qpid.server.model.State;
import org.apache.qpid.server.model.TrustStore;
+import org.apache.qpid.server.security.access.Operation;
+import org.apache.qpid.server.util.MapValueConverter;
+import org.apache.qpid.transport.network.security.ssl.SSLUtil;
public class TrustStoreAdapter extends AbstractKeyStoreAdapter implements TrustStore
{
+ @SuppressWarnings("serial")
+ public static final Map<String, Type> ATTRIBUTE_TYPES = Collections.unmodifiableMap(new HashMap<String, Type>(){{
+ put(NAME, String.class);
+ put(PATH, String.class);
+ put(PASSWORD, String.class);
+ put(TYPE, String.class);
+ put(PEERS_ONLY, Boolean.class);
+ put(TRUST_MANAGER_FACTORY_ALGORITHM, String.class);
+ }});
+
+ @SuppressWarnings("serial")
+ public static final Map<String, Object> DEFAULTS = Collections.unmodifiableMap(new HashMap<String, Object>(){{
+ put(TrustStore.TYPE, DEFAULT_KEYSTORE_TYPE);
+ put(TrustStore.PEERS_ONLY, Boolean.FALSE);
+ put(TrustStore.TRUST_MANAGER_FACTORY_ALGORITHM, TrustManagerFactory.getDefaultAlgorithm());
+ }});
+
+ private Broker _broker;
+
public TrustStoreAdapter(UUID id, Broker broker, Map<String, Object> attributes)
{
- super(id, broker, attributes);
+ super(id, broker, DEFAULTS, MapValueConverter.convert(attributes, ATTRIBUTE_TYPES));
+ _broker = broker;
+
+ String trustStorePath = (String) getAttribute(TrustStore.PATH);
+ String trustStorePassword = getPassword();
+ String trustStoreType = (String) getAttribute(TrustStore.TYPE);
+ String trustManagerFactoryAlgorithm = (String) getAttribute(TrustStore.TRUST_MANAGER_FACTORY_ALGORITHM);
+
+ validateTrustStoreAttributes(trustStoreType, trustStorePath,
+ trustStorePassword, trustManagerFactoryAlgorithm);
}
@Override
@@ -40,4 +83,110 @@ public class TrustStoreAdapter extends AbstractKeyStoreAdapter implements TrustS
return AVAILABLE_ATTRIBUTES;
}
+ @Override
+ protected boolean setState(State currentState, State desiredState)
+ {
+ if(desiredState == State.DELETED)
+ {
+ // verify that it is not in use
+ String storeName = getName();
+
+ Collection<Port> ports = new ArrayList<Port>(_broker.getPorts());
+ for (Port port : ports)
+ {
+ Collection<TrustStore> trustStores = port.getTrustStores();
+ for(TrustStore store : trustStores)
+ {
+ if (storeName.equals(store.getAttribute(TrustStore.NAME)))
+ {
+ throw new IntegrityViolationException("Trust store '" + storeName + "' can't be deleted as it is in use by a port: " + port.getName());
+ }
+ }
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
+ @Override
+ protected void authoriseSetDesiredState(State currentState, State desiredState) throws AccessControlException
+ {
+ if(desiredState == State.DELETED)
+ {
+ if (!_broker.getSecurityManager().authoriseConfiguringBroker(getName(), TrustStore.class, Operation.DELETE))
+ {
+ throw new AccessControlException("Deletion of key store is denied");
+ }
+ }
+ }
+
+ @Override
+ protected void authoriseSetAttribute(String name, Object expected, Object desired) throws AccessControlException
+ {
+ authoriseSetAttribute();
+ }
+
+ @Override
+ protected void authoriseSetAttributes(Map<String, Object> attributes) throws AccessControlException
+ {
+ authoriseSetAttribute();
+ }
+
+ private void authoriseSetAttribute()
+ {
+ if (!_broker.getSecurityManager().authoriseConfiguringBroker(getName(), TrustStore.class, Operation.UPDATE))
+ {
+ throw new AccessControlException("Setting key store attributes is denied");
+ }
+ }
+
+ @Override
+ protected void changeAttributes(Map<String, Object> attributes)
+ {
+ Map<String, Object> changedValues = MapValueConverter.convert(attributes, ATTRIBUTE_TYPES);
+ if(changedValues.containsKey(TrustStore.NAME))
+ {
+ String newName = (String) changedValues.get(TrustStore.NAME);
+ if(!getName().equals(newName))
+ {
+ throw new IllegalConfigurationException("Changing the trust store name is not allowed");
+ }
+ }
+
+ Map<String, Object> merged = generateEffectiveAttributes(changedValues);
+
+ String trustStorePath = (String)merged.get(TrustStore.PATH);
+ String trustStorePassword = (String) merged.get(TrustStore.PASSWORD);
+ String trustStoreType = (String)merged.get(TrustStore.TYPE);
+ String trustManagerFactoryAlgorithm = (String)merged.get(TrustStore.TRUST_MANAGER_FACTORY_ALGORITHM);
+
+ validateTrustStoreAttributes(trustStoreType, trustStorePath,
+ trustStorePassword, trustManagerFactoryAlgorithm);
+
+ super.changeAttributes(changedValues);
+ }
+
+ private void validateTrustStoreAttributes(String type, String trustStorePath,
+ String password, String trustManagerFactoryAlgorithm)
+ {
+ try
+ {
+ SSLUtil.getInitializedKeyStore(trustStorePath, password, type);
+ }
+ catch (Exception e)
+ {
+ throw new IllegalConfigurationException("Cannot instantiate trust store at " + trustStorePath, e);
+ }
+
+ try
+ {
+ TrustManagerFactory.getInstance(trustManagerFactoryAlgorithm);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw new IllegalConfigurationException("Unknown trustManagerFactoryAlgorithm: " + trustManagerFactoryAlgorithm);
+ }
+ }
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/util/MapValueConverter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/util/MapValueConverter.java
index 8c57d04348..16e717a9c7 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/util/MapValueConverter.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/util/MapValueConverter.java
@@ -62,7 +62,7 @@ public class MapValueConverter
return getStringAttribute(name, attributes, null);
}
- private static void assertMandatoryAttribute(String name, Map<String, Object> attributes)
+ public static void assertMandatoryAttribute(String name, Map<String, Object> attributes)
{
if (!attributes.containsKey(name))
{
@@ -326,6 +326,10 @@ public class MapValueConverter
public static <T> Set<T> toSet(Object rawValue, Class<T> setItemClass, String attributeName)
{
+ if (rawValue == null)
+ {
+ return null;
+ }
HashSet<T> set = new HashSet<T>();
if (rawValue instanceof Iterable)
{
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/startup/KeyStoreRecovererTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/startup/KeyStoreRecovererTest.java
index 0d7dc1bb06..e0a736df89 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/startup/KeyStoreRecovererTest.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/startup/KeyStoreRecovererTest.java
@@ -27,12 +27,15 @@ import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
+import javax.net.ssl.KeyManagerFactory;
+
+import junit.framework.TestCase;
+
import org.apache.qpid.server.configuration.ConfigurationEntry;
import org.apache.qpid.server.model.Broker;
import org.apache.qpid.server.model.KeyStore;
-import org.apache.qpid.server.model.TrustStore;
-
-import junit.framework.TestCase;
+import org.apache.qpid.server.model.adapter.AbstractKeyStoreAdapter;
+import org.apache.qpid.test.utils.TestSSLConstants;
public class KeyStoreRecovererTest extends TestCase
{
@@ -40,6 +43,7 @@ public class KeyStoreRecovererTest extends TestCase
public void testCreateWithAllAttributesProvided()
{
Map<String, Object> attributes = getKeyStoreAttributes();
+ Map<String, Object> attributesCopy = new HashMap<String, Object>(attributes);
UUID id = UUID.randomUUID();
Broker broker = mock(Broker.class);
@@ -49,36 +53,27 @@ public class KeyStoreRecovererTest extends TestCase
KeyStoreRecoverer recovever = new KeyStoreRecoverer();
- KeyStore KeyStore = recovever.create(null, entry, broker);
- assertNotNull("Key store configured object is not created", KeyStore);
- assertEquals(id, KeyStore.getId());
- assertEquals("my-secret-password", KeyStore.getPassword());
+ KeyStore keyStore = recovever.create(null, entry, broker);
+ assertNotNull("Key store configured object is not created", keyStore);
+ assertEquals(id, keyStore.getId());
- assertNull("Password was unexpectedly returned from configured object", KeyStore.getAttribute(TrustStore.PASSWORD));
+ //verify we can retrieve the actual password using the method
+ assertEquals(TestSSLConstants.BROKER_TRUSTSTORE_PASSWORD, keyStore.getPassword());
+ assertNotNull(keyStore.getPassword());
- // password attribute should not be exposed by a key store configured object
- // so, we should set password value to null in the map being used to create the key store configured object
- attributes.put(KeyStore.PASSWORD, null);
- for (Map.Entry<String, Object> attribute : attributes.entrySet())
+ //verify that we havent configured the key store with the actual dummy password value
+ assertFalse(AbstractKeyStoreAdapter.DUMMY_PASSWORD_MASK.equals(keyStore.getPassword()));
+
+ // Verify the remaining attributes, including that the password value returned
+ // via getAttribute is actually the dummy value and not the real password
+ attributesCopy.put(KeyStore.PASSWORD, AbstractKeyStoreAdapter.DUMMY_PASSWORD_MASK);
+ for (Map.Entry<String, Object> attribute : attributesCopy.entrySet())
{
- Object attributeValue = KeyStore.getAttribute(attribute.getKey());
+ Object attributeValue = keyStore.getAttribute(attribute.getKey());
assertEquals("Unexpected value of attribute '" + attribute.getKey() + "'", attribute.getValue(), attributeValue);
}
}
- private Map<String, Object> getKeyStoreAttributes()
- {
- Map<String, Object> attributes = new HashMap<String, Object>();
- attributes.put(KeyStore.NAME, getName());
- attributes.put(KeyStore.PATH, "/path/to/KeyStore");
- attributes.put(KeyStore.PASSWORD, "my-secret-password");
- attributes.put(KeyStore.TYPE, "NON-JKS");
- attributes.put(KeyStore.KEY_MANAGER_FACTORY_ALGORITHM, "NON-STANDARD");
- attributes.put(KeyStore.CERTIFICATE_ALIAS, "my-cert-alias");
- attributes.put(KeyStore.DESCRIPTION, "description");
- return attributes;
- }
-
public void testCreateWithMissedRequiredAttributes()
{
Map<String, Object> attributes = getKeyStoreAttributes();
@@ -108,4 +103,16 @@ public class KeyStoreRecovererTest extends TestCase
}
}
+ private Map<String, Object> getKeyStoreAttributes()
+ {
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(KeyStore.NAME, getName());
+ attributes.put(KeyStore.PATH, TestSSLConstants.BROKER_KEYSTORE);
+ attributes.put(KeyStore.PASSWORD, TestSSLConstants.BROKER_KEYSTORE_PASSWORD);
+ attributes.put(KeyStore.TYPE, "jks");
+ attributes.put(KeyStore.KEY_MANAGER_FACTORY_ALGORITHM, KeyManagerFactory.getDefaultAlgorithm());
+ attributes.put(KeyStore.CERTIFICATE_ALIAS, "java-broker");
+ return attributes;
+ }
+
}
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/startup/TrustStoreRecovererTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/startup/TrustStoreRecovererTest.java
index 5e7784bc06..4d92f99306 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/startup/TrustStoreRecovererTest.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/startup/TrustStoreRecovererTest.java
@@ -27,16 +27,21 @@ import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
+import javax.net.ssl.TrustManagerFactory;
+
import org.apache.qpid.server.configuration.ConfigurationEntry;
import org.apache.qpid.server.model.Broker;
import org.apache.qpid.server.model.TrustStore;
+import org.apache.qpid.server.model.adapter.AbstractKeyStoreAdapter;
import org.apache.qpid.test.utils.QpidTestCase;
+import org.apache.qpid.test.utils.TestSSLConstants;
public class TrustStoreRecovererTest extends QpidTestCase
{
public void testCreateWithAllAttributesProvided()
{
Map<String, Object> attributes = getTrustStoreAttributes();
+ Map<String, Object> attributesCopy = new HashMap<String, Object>(attributes);
UUID id = UUID.randomUUID();
Broker broker = mock(Broker.class);
@@ -44,38 +49,29 @@ public class TrustStoreRecovererTest extends QpidTestCase
when(entry.getAttributes()).thenReturn(attributes);
when(entry.getId()).thenReturn(id);
- TrustStoreRecoverer recovever = new TrustStoreRecoverer();
+ TrustStoreRecoverer recoverer = new TrustStoreRecoverer();
- TrustStore trustStore = recovever.create(null, entry, broker);
+ TrustStore trustStore = recoverer.create(null, entry, broker);
assertNotNull("Trust store configured object is not created", trustStore);
assertEquals(id, trustStore.getId());
- assertEquals("my-secret-password", trustStore.getPassword());
- assertNull("Password was unexpectedly returned from configured object", trustStore.getAttribute(TrustStore.PASSWORD));
+ //verify we can retrieve the actual password using the method
+ assertEquals(TestSSLConstants.BROKER_TRUSTSTORE_PASSWORD, trustStore.getPassword());
+ assertNotNull(trustStore.getPassword());
+
+ //verify that we havent configured the trust store with the actual dummy password value
+ assertFalse(AbstractKeyStoreAdapter.DUMMY_PASSWORD_MASK.equals(trustStore.getPassword()));
- // password attribute should not be exposed by a trust store configured object
- // so, we should set password value to null in the map being used to create the trust store configured object
- attributes.put(TrustStore.PASSWORD, null);
- for (Map.Entry<String, Object> attribute : attributes.entrySet())
+ // Verify the remaining attributes, including that the password value returned
+ // via getAttribute is actually the dummy value and not the real password
+ attributesCopy.put(TrustStore.PASSWORD, AbstractKeyStoreAdapter.DUMMY_PASSWORD_MASK);
+ for (Map.Entry<String, Object> attribute : attributesCopy.entrySet())
{
Object attributeValue = trustStore.getAttribute(attribute.getKey());
assertEquals("Unexpected value of attribute '" + attribute.getKey() + "'", attribute.getValue(), attributeValue);
}
}
- private Map<String, Object> getTrustStoreAttributes()
- {
- Map<String, Object> attributes = new HashMap<String, Object>();
- attributes.put(TrustStore.NAME, getName());
- attributes.put(TrustStore.PATH, "/path/to/truststore");
- attributes.put(TrustStore.PASSWORD, "my-secret-password");
- attributes.put(TrustStore.TYPE, "NON-JKS");
- attributes.put(TrustStore.KEY_MANAGER_FACTORY_ALGORITHM, "NON-STANDARD");
- attributes.put(TrustStore.PEERS_ONLY, Boolean.TRUE);
- attributes.put(TrustStore.DESCRIPTION, "Description");
- return attributes;
- }
-
public void testCreateWithMissedRequiredAttributes()
{
Map<String, Object> attributes = getTrustStoreAttributes();
@@ -106,4 +102,16 @@ public class TrustStoreRecovererTest extends QpidTestCase
}
}
+ private Map<String, Object> getTrustStoreAttributes()
+ {
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(TrustStore.NAME, getName());
+ attributes.put(TrustStore.PATH, TestSSLConstants.BROKER_TRUSTSTORE);
+ attributes.put(TrustStore.PASSWORD, TestSSLConstants.BROKER_TRUSTSTORE_PASSWORD);
+ attributes.put(TrustStore.TYPE, "jks");
+ attributes.put(TrustStore.TRUST_MANAGER_FACTORY_ALGORITHM, TrustManagerFactory.getDefaultAlgorithm());
+ attributes.put(TrustStore.PEERS_ONLY, Boolean.TRUE);
+ return attributes;
+ }
+
}
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/store/ConfigurationEntryStoreTestCase.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/store/ConfigurationEntryStoreTestCase.java
index adb4472694..7d253d56f0 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/store/ConfigurationEntryStoreTestCase.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/configuration/store/ConfigurationEntryStoreTestCase.java
@@ -284,7 +284,7 @@ public abstract class ConfigurationEntryStoreTestCase extends QpidTestCase
attributes.put(TrustStore.PATH, "/path/to/truststore");
attributes.put(TrustStore.PASSWORD, "my-secret-password");
attributes.put(TrustStore.TYPE, "NON-JKS");
- attributes.put(TrustStore.KEY_MANAGER_FACTORY_ALGORITHM, "NON-STANDARD");
+ attributes.put(TrustStore.TRUST_MANAGER_FACTORY_ALGORITHM, "NON-STANDARD");
attributes.put(TrustStore.DESCRIPTION, "Description");
ConfigurationEntry trustStoreEntry = new ConfigurationEntry(trustStoreId, TrustStore.class.getSimpleName(), attributes,
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/model/adapter/PortFactoryTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/model/adapter/PortFactoryTest.java
index a9303c264e..53fb1a0620 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/model/adapter/PortFactoryTest.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/model/adapter/PortFactoryTest.java
@@ -22,8 +22,8 @@ package org.apache.qpid.server.model.adapter;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.any;
-import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
@@ -47,8 +47,6 @@ import org.apache.qpid.test.utils.QpidTestCase;
public class PortFactoryTest extends QpidTestCase
{
private UUID _portId = UUID.randomUUID();
- private UUID _keyStoreId = UUID.randomUUID();
- private UUID _trustStoreId = UUID.randomUUID();
private int _portNumber = 123;
private Set<String> _tcpStringSet = Collections.singleton(Transport.TCP.name());
private Set<Transport> _tcpTransportSet = Collections.singleton(Transport.TCP);
@@ -134,15 +132,14 @@ public class PortFactoryTest extends QpidTestCase
public void testCreateAmqpPort()
{
- createAmqpPortTestImpl(false,false,false);
+ createAmqpPortTestImpl(false, false, false, null, null);
}
public void testCreateAmqpPortUsingSslFailsWithoutKeyStore()
{
- when(_broker.getKeyStores()).thenReturn(new ArrayList<KeyStore>());
try
{
- createAmqpPortTestImpl(true,false,false);
+ createAmqpPortTestImpl(true, false, false, null, null);
fail("expected exception due to lack of SSL keystore");
}
catch(IllegalConfigurationException e)
@@ -153,18 +150,22 @@ public class PortFactoryTest extends QpidTestCase
public void testCreateAmqpPortUsingSslSucceedsWithKeyStore()
{
- when(_broker.getKeyStores()).thenReturn(Collections.singleton(_keyStore));
+ String keyStoreName = "myKeyStore";
+ when(_broker.findKeyStoreByName(keyStoreName)).thenReturn(_keyStore);
- createAmqpPortTestImpl(true,false,false);
+ createAmqpPortTestImpl(true, false, false, keyStoreName, null);
}
public void testCreateAmqpPortNeedingClientAuthFailsWithoutTrustStore()
{
- when(_broker.getKeyStores()).thenReturn(Collections.singleton(_keyStore));
- when(_broker.getTrustStores()).thenReturn(new ArrayList<TrustStore>());
+ String keyStoreName = "myKeyStore";
+ when(_broker.findKeyStoreByName(keyStoreName)).thenReturn(_keyStore);
+
+ when(_broker.findTrustStoreByName(any(String.class))).thenReturn(null);
+
try
{
- createAmqpPortTestImpl(true,true,false);
+ createAmqpPortTestImpl(true, true, false, keyStoreName, null);
fail("expected exception due to lack of SSL truststore");
}
catch(IllegalConfigurationException e)
@@ -175,19 +176,23 @@ public class PortFactoryTest extends QpidTestCase
public void testCreateAmqpPortNeedingClientAuthSucceedsWithTrustStore()
{
- when(_broker.getKeyStores()).thenReturn(Collections.singleton(_keyStore));
- when(_broker.getTrustStores()).thenReturn(Collections.singleton(_trustStore));
+ String keyStoreName = "myKeyStore";
+ when(_broker.findKeyStoreByName(keyStoreName)).thenReturn(_keyStore);
- createAmqpPortTestImpl(true,true,false);
+ String trustStoreName = "myTrustStore";
+ when(_broker.findTrustStoreByName(trustStoreName)).thenReturn(_trustStore);
+
+ createAmqpPortTestImpl(true, true, false, keyStoreName, new String[]{trustStoreName});
}
public void testCreateAmqpPortWantingClientAuthFailsWithoutTrustStore()
{
- when(_broker.getKeyStores()).thenReturn(Collections.singleton(_keyStore));
- when(_broker.getTrustStores()).thenReturn(new ArrayList<TrustStore>());
+ String keyStoreName = "myKeyStore";
+ when(_broker.findKeyStoreByName(keyStoreName)).thenReturn(_keyStore);
+
try
{
- createAmqpPortTestImpl(true,false,true);
+ createAmqpPortTestImpl(true, false, true, keyStoreName, null);
fail("expected exception due to lack of SSL truststore");
}
catch(IllegalConfigurationException e)
@@ -198,13 +203,17 @@ public class PortFactoryTest extends QpidTestCase
public void testCreateAmqpPortWantingClientAuthSucceedsWithTrustStore()
{
- when(_broker.getKeyStores()).thenReturn(Collections.singleton(_keyStore));
- when(_broker.getTrustStores()).thenReturn(Collections.singleton(_trustStore));
+ String keyStoreName = "myKeyStore";
+ when(_broker.findKeyStoreByName(keyStoreName)).thenReturn(_keyStore);
- createAmqpPortTestImpl(true,false,true);
+ String trustStoreName = "myTrustStore";
+ when(_broker.findTrustStoreByName(trustStoreName)).thenReturn(_trustStore);
+
+ createAmqpPortTestImpl(true, false, true, keyStoreName, new String[]{trustStoreName});
}
- public void createAmqpPortTestImpl(boolean useSslTransport, boolean needClientAuth, boolean wantClientAuth)
+ public void createAmqpPortTestImpl(boolean useSslTransport, boolean needClientAuth, boolean wantClientAuth,
+ String keystoreName, String[] trustStoreNames)
{
Set<Protocol> amqp010ProtocolSet = Collections.singleton(Protocol.AMQP_0_10);
Set<String> amqp010StringSet = Collections.singleton(Protocol.AMQP_0_10.name());
@@ -225,6 +234,16 @@ public class PortFactoryTest extends QpidTestCase
_attributes.put(Port.WANT_CLIENT_AUTH, "true");
}
+ if(keystoreName != null)
+ {
+ _attributes.put(Port.KEY_STORE, keystoreName);
+ }
+
+ if(trustStoreNames != null)
+ {
+ _attributes.put(Port.TRUST_STORES, Arrays.asList(trustStoreNames));
+ }
+
Port port = _portFactory.createPort(_portId, _broker, _attributes);
assertNotNull(port);
@@ -335,4 +354,29 @@ public class PortFactoryTest extends QpidTestCase
// pass
}
}
+
+ public void testCreateRMIPortRequestingSslFails()
+ {
+ String keyStoreName = "myKeyStore";
+
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(Port.PORT, 1);
+ attributes.put(Port.NAME, getTestName());
+ attributes.put(Port.TRANSPORTS, Collections.singleton(Transport.SSL));
+ attributes.put(Port.PROTOCOLS, Collections.singleton(Protocol.RMI));
+ _attributes.put(Port.KEY_STORE, keyStoreName);
+
+ when(_broker.findKeyStoreByName(keyStoreName)).thenReturn(_keyStore);
+
+ try
+ {
+ _portFactory.createPort(_portId, _broker, attributes);
+ fail("RMI port creation should fail due to requesting SSL");
+ }
+ catch(IllegalConfigurationException e)
+ {
+ e.printStackTrace();
+ // pass
+ }
+ }
}
diff --git a/qpid/java/common/src/main/java/org/apache/qpid/ssl/SSLContextFactory.java b/qpid/java/common/src/main/java/org/apache/qpid/ssl/SSLContextFactory.java
index 01381ad23f..158006f072 100644
--- a/qpid/java/common/src/main/java/org/apache/qpid/ssl/SSLContextFactory.java
+++ b/qpid/java/common/src/main/java/org/apache/qpid/ssl/SSLContextFactory.java
@@ -31,7 +31,6 @@ import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
-import java.security.cert.X509Certificate;
import java.io.IOException;
import java.security.GeneralSecurityException;
@@ -39,7 +38,6 @@ import java.security.KeyStore;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
-import java.util.List;
/**
* Factory used to create SSLContexts. SSL needs to be configured
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/TestSSLConstants.java b/qpid/java/common/src/test/java/org/apache/qpid/test/utils/TestSSLConstants.java
index 5664e94bd9..c48f164d98 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/TestSSLConstants.java
+++ b/qpid/java/common/src/test/java/org/apache/qpid/test/utils/TestSSLConstants.java
@@ -28,4 +28,10 @@ public interface TestSSLConstants
String BROKER_KEYSTORE = "test-profiles/test_resources/ssl/java_broker_keystore.jks";
String BROKER_KEYSTORE_PASSWORD = "password";
+
+ String BROKER_PEERSTORE = "test-profiles/test_resources/ssl/java_broker_peerstore.jks";
+ String BROKER_PEERSTORE_PASSWORD = "password";
+
+ String BROKER_TRUSTSTORE = "test-profiles/test_resources/ssl/java_broker_truststore.jks";
+ String BROKER_TRUSTSTORE_PASSWORD = "password";
}
diff --git a/qpid/java/systests/etc/config-systests.json b/qpid/java/systests/etc/config-systests.json
index b06b469891..ec3d17dbec 100644
--- a/qpid/java/systests/etc/config-systests.json
+++ b/qpid/java/systests/etc/config-systests.json
@@ -22,15 +22,21 @@
"name": "QpidBroker",
"defaultAuthenticationProvider" : "plain",
"defaultVirtualHost" : "test",
- "keyStorePath": "${QPID_HOME}/../test-profiles/test_resources/ssl/java_broker_keystore.jks",
- "keyStorePassword": "password",
- "trustStorePath": "${QPID_HOME}/../test-profiles/test_resources/ssl/java_broker_truststore.jks",
- "trustStorePassword": "password",
"authenticationproviders" : [ {
"name" : "plain",
"type" : "PlainPasswordFile",
"path" : "${QPID_HOME}/etc/passwd"
} ],
+ "keystores" : [ {
+ "name" : "systestsKeyStore",
+ "path" : "${QPID_HOME}/../test-profiles/test_resources/ssl/java_broker_keystore.jks",
+ "password" : "password"
+ } ],
+ "truststores" : [ {
+ "name" : "systestsTrustStore",
+ "path" : "${QPID_HOME}/../test-profiles/test_resources/ssl/java_broker_truststore.jks",
+ "password" : "password"
+ } ],
"ports" : [ {
"name" : "amqp",
"port" : "${test.port}"
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/client/ssl/SSLTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/client/ssl/SSLTest.java
index 884e89fb65..e2cd3e254e 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/client/ssl/SSLTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/client/ssl/SSLTest.java
@@ -365,6 +365,8 @@ public class SSLTest extends QpidBrokerTestCase
sslPortAttributes.put(Port.NEED_CLIENT_AUTH, needClientAuth);
sslPortAttributes.put(Port.WANT_CLIENT_AUTH, wantClientAuth);
sslPortAttributes.put(Port.NAME, TestBrokerConfiguration.ENTRY_NAME_SSL_PORT);
+ sslPortAttributes.put(Port.KEY_STORE, TestBrokerConfiguration.ENTRY_NAME_SSL_KEYSTORE);
+ sslPortAttributes.put(Port.TRUST_STORES, Collections.singleton(TestBrokerConfiguration.ENTRY_NAME_SSL_TRUSTSTORE));
getBrokerConfiguration().addPortConfiguration(sslPortAttributes);
}
}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationTest.java
index 2e051d93dd..90c6b12779 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationTest.java
@@ -20,12 +20,16 @@
*/
package org.apache.qpid.server.security.auth.manager;
+import static org.apache.qpid.test.utils.TestSSLConstants.BROKER_PEERSTORE;
+import static org.apache.qpid.test.utils.TestSSLConstants.BROKER_PEERSTORE_PASSWORD;
import static org.apache.qpid.test.utils.TestSSLConstants.KEYSTORE;
import static org.apache.qpid.test.utils.TestSSLConstants.KEYSTORE_PASSWORD;
import static org.apache.qpid.test.utils.TestSSLConstants.TRUSTSTORE;
import static org.apache.qpid.test.utils.TestSSLConstants.TRUSTSTORE_PASSWORD;
import static org.apache.qpid.test.utils.TestSSLConstants.UNTRUSTED_KEYSTORE;
+import java.util.Arrays;
+import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
@@ -41,6 +45,7 @@ import org.apache.qpid.server.model.AuthenticationProvider;
import org.apache.qpid.server.model.Broker;
import org.apache.qpid.server.model.Port;
import org.apache.qpid.server.model.Transport;
+import org.apache.qpid.server.model.TrustStore;
import org.apache.qpid.server.plugin.AuthenticationManagerFactory;
import org.apache.qpid.test.utils.JMXTestUtils;
import org.apache.qpid.test.utils.QpidBrokerTestCase;
@@ -52,6 +57,7 @@ public class ExternalAuthenticationTest extends QpidBrokerTestCase
protected void setUp() throws Exception
{
// not calling super.setUp() to avoid broker start-up
+ setSystemProperty("javax.net.debug", "ssl");
}
/**
@@ -168,31 +174,87 @@ public class ExternalAuthenticationTest extends QpidBrokerTestCase
}
/**
- * Tests that when using the EXTERNAL auth provide and the broker 'peerstore' is configured to contain a certificate that is
- * otherwise untrusted by the broker [truststore], clients using that certificate will then be able to connect.
+ * Tests that when using the EXTERNAL auth provider and a 'peersOnly' truststore, clients using certs directly in
+ * in the store will be able to connect and clients using certs signed by the same CA but not in the store will not.
*/
- public void testExternalAuthenticationWithPeerStoreAllowsOtherwiseUntrustedClientCert() throws Exception
+ public void testExternalAuthenticationWithPeersOnlyTrustStore() throws Exception
{
- setCommonBrokerSSLProperties(true);
- getBrokerConfiguration().setObjectAttribute(TestBrokerConfiguration.ENTRY_NAME_SSL_PORT, Port.AUTHENTICATION_PROVIDER, TestBrokerConfiguration.ENTRY_NAME_EXTERNAL_PROVIDER);
+ externalAuthenticationWithPeersOnlyTrustStoreTestImpl(false);
+ }
+
+ /**
+ * Tests that when using the EXTERNAL auth provider, with both the regular trust store and a 'peersOnly' truststore, clients
+ * using certs signed by the CA in the trust store are allowed even if they are not present in the 'peersOnly' store.
+ */
+ public void testExternalAuthenticationWithRegularAndPeersOnlyTrustStores() throws Exception
+ {
+ externalAuthenticationWithPeersOnlyTrustStoreTestImpl(true);
+ }
+
+ private void externalAuthenticationWithPeersOnlyTrustStoreTestImpl(boolean useTrustAndPeerStore) throws Exception
+ {
+ String peerStoreName = "myPeerStore";
+
+ List<String> storeNames = null;
+ if(useTrustAndPeerStore)
+ {
+ //Use the regular trust store AND the 'peersOnly' store. The regular trust store trusts the CA that
+ //signed both the app1 and app2 certs. The peersOnly store contains only app1 and so does not trust app2
+ storeNames = Arrays.asList(TestBrokerConfiguration.ENTRY_NAME_SSL_TRUSTSTORE, peerStoreName);
+ }
+ else
+ {
+ //use only the 'peersOnly' store, which contains only app1 and so does not trust app2
+ storeNames = Arrays.asList(peerStoreName);
+ }
+
+ //set the brokers SSL config, inc which SSL stores to use
+ setCommonBrokerSSLProperties(true, storeNames);
- //Use the untrusted client keystore as the brokers peerstore to make the broker trust the cert.
- getBrokerConfiguration().setBrokerAttribute(Broker.PEER_STORE_PATH, UNTRUSTED_KEYSTORE);
- getBrokerConfiguration().setBrokerAttribute(Broker.PEER_STORE_PASSWORD, KEYSTORE_PASSWORD);
+ //add the peersOnly store to the config
+ Map<String, Object> sslTrustStoreAttributes = new HashMap<String, Object>();
+ sslTrustStoreAttributes.put(TrustStore.NAME, peerStoreName);
+ sslTrustStoreAttributes.put(TrustStore.PATH, BROKER_PEERSTORE);
+ sslTrustStoreAttributes.put(TrustStore.PASSWORD, BROKER_PEERSTORE_PASSWORD);
+ sslTrustStoreAttributes.put(TrustStore.PEERS_ONLY, true);
+ getBrokerConfiguration().addTrustStoreConfiguration(sslTrustStoreAttributes);
+
+ getBrokerConfiguration().setObjectAttribute(TestBrokerConfiguration.ENTRY_NAME_SSL_PORT, Port.AUTHENTICATION_PROVIDER, TestBrokerConfiguration.ENTRY_NAME_EXTERNAL_PROVIDER);
super.setUp();
- setUntrustedClientKeystoreProperties();
+ setClientKeystoreProperties();
setClientTrustoreProperties();
try
{
- getExternalSSLConnection(false);
- fail("Untrusted client's validation against the broker's multi store manager unexpectedly passed.");
+ //use the app1 cert, which IS in the peerstore (and has CA in the trustStore)
+ getExternalSSLConnection(false, "&ssl_cert_alias='app1'");
+ }
+ catch (JMSException e)
+ {
+ fail("Client's validation against the broker's multi store manager unexpectedly failed, when configured store was expected to allow.");
+ }
+
+ try
+ {
+ //use the app2 cert, which is NOT in the peerstore (but is signed by the same CA as app1)
+ getExternalSSLConnection(false, "&ssl_cert_alias='app2'");
+ if(!useTrustAndPeerStore)
+ {
+ fail("Client's validation against the broker's multi store manager unexpectedly passed, when configured store was expected to deny.");
+ }
}
catch (JMSException e)
{
- // expected
+ if(useTrustAndPeerStore)
+ {
+ fail("Client's validation against the broker's multi store manager unexpectedly failed, when configured store was expected to allow.");
+ }
+ else
+ {
+ //expected, the CA in trust store should allow both app1 and app2
+ }
}
}
@@ -215,7 +277,7 @@ public class ExternalAuthenticationTest extends QpidBrokerTestCase
try
{
- getExternalSSLConnection(false);
+ getExternalSSLConnection(false, "&ssl_cert_alias='app2'");
}
catch (JMSException e)
{
@@ -250,7 +312,7 @@ public class ExternalAuthenticationTest extends QpidBrokerTestCase
try
{
- getExternalSSLConnection(false);
+ getExternalSSLConnection(false, "&ssl_cert_alias='app2'");
}
catch (JMSException e)
{
@@ -267,26 +329,38 @@ public class ExternalAuthenticationTest extends QpidBrokerTestCase
private Connection getExternalSSLConnection(boolean includeUserNameAndPassword) throws Exception
{
- String url = "amqp://%s@test/?brokerlist='tcp://localhost:%s?ssl='true'&sasl_mechs='EXTERNAL'&ssl_cert_alias='app2''";
+ return getExternalSSLConnection(includeUserNameAndPassword, "");
+ }
+
+ private Connection getExternalSSLConnection(boolean includeUserNameAndPassword, String optionString) throws Exception
+ {
+ String url = "amqp://%s@test/?brokerlist='tcp://localhost:%s?ssl='true'&sasl_mechs='EXTERNAL'%s'";
if (includeUserNameAndPassword)
{
- url = String.format(url, "guest:guest", String.valueOf(QpidBrokerTestCase.DEFAULT_SSL_PORT));
+ url = String.format(url, "guest:guest", String.valueOf(QpidBrokerTestCase.DEFAULT_SSL_PORT), optionString);
}
else
{
- url = String.format(url, ":", String.valueOf(QpidBrokerTestCase.DEFAULT_SSL_PORT));
+ url = String.format(url, ":", String.valueOf(QpidBrokerTestCase.DEFAULT_SSL_PORT), optionString);
}
return getConnection(new AMQConnectionURL(url));
}
private void setCommonBrokerSSLProperties(boolean needClientAuth) throws ConfigurationException
{
+ setCommonBrokerSSLProperties(needClientAuth, Collections.singleton(TestBrokerConfiguration.ENTRY_NAME_SSL_TRUSTSTORE));
+ }
+
+ private void setCommonBrokerSSLProperties(boolean needClientAuth, Collection<String> trustStoreNames) throws ConfigurationException
+ {
TestBrokerConfiguration config = getBrokerConfiguration();
Map<String, Object> sslPortAttributes = new HashMap<String, Object>();
sslPortAttributes.put(Port.TRANSPORTS, Collections.singleton(Transport.SSL));
sslPortAttributes.put(Port.PORT, DEFAULT_SSL_PORT);
sslPortAttributes.put(Port.NEED_CLIENT_AUTH, String.valueOf(needClientAuth));
sslPortAttributes.put(Port.NAME, TestBrokerConfiguration.ENTRY_NAME_SSL_PORT);
+ sslPortAttributes.put(Port.KEY_STORE, TestBrokerConfiguration.ENTRY_NAME_SSL_KEYSTORE);
+ sslPortAttributes.put(Port.TRUST_STORES, trustStoreNames);
config.addPortConfiguration(sslPortAttributes);
Map<String, Object> externalAuthProviderAttributes = new HashMap<String, Object>();
@@ -311,6 +385,5 @@ public class ExternalAuthenticationTest extends QpidBrokerTestCase
{
setSystemProperty("javax.net.ssl.trustStore", TRUSTSTORE);
setSystemProperty("javax.net.ssl.trustStorePassword", TRUSTSTORE_PASSWORD);
- setSystemProperty("javax.net.debug", "ssl");
}
}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/security/auth/manager/MultipleAuthenticationManagersTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/security/auth/manager/MultipleAuthenticationManagersTest.java
index 40346d7424..44057025ba 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/server/security/auth/manager/MultipleAuthenticationManagersTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/server/security/auth/manager/MultipleAuthenticationManagersTest.java
@@ -56,6 +56,8 @@ public class MultipleAuthenticationManagersTest extends QpidBrokerTestCase
sslPortAttributes.put(Port.TRANSPORTS, Collections.singleton(Transport.SSL));
sslPortAttributes.put(Port.PORT, DEFAULT_SSL_PORT);
sslPortAttributes.put(Port.NAME, TestBrokerConfiguration.ENTRY_NAME_SSL_PORT);
+ sslPortAttributes.put(Port.KEY_STORE, TestBrokerConfiguration.ENTRY_NAME_SSL_KEYSTORE);
+ sslPortAttributes.put(Port.TRUST_STORES, Collections.singleton(TestBrokerConfiguration.ENTRY_NAME_SSL_TRUSTSTORE));
sslPortAttributes.put(Port.AUTHENTICATION_PROVIDER, TestBrokerConfiguration.ENTRY_NAME_ANONYMOUS_PROVIDER);
config.addPortConfiguration(sslPortAttributes);
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/ManagementLoggingTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/ManagementLoggingTest.java
index 9279287117..4ec38fbe23 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/ManagementLoggingTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/systest/management/jmx/ManagementLoggingTest.java
@@ -314,11 +314,9 @@ public class ManagementLoggingTest extends AbstractTestLogging
if(useManagementSSL)
{
- // This test requires we have an ssl connection
+ // This test requires we have ssl, change the transport and add they keystore to the port config
config.setObjectAttribute(TestBrokerConfiguration.ENTRY_NAME_JMX_PORT, Port.TRANSPORTS, Collections.singleton(Transport.SSL));
-
- setSystemProperty("javax.net.ssl.keyStore", "test-profiles/test_resources/ssl/java_broker_keystore.jks");
- setSystemProperty("javax.net.ssl.keyStorePassword", "password");
+ config.setObjectAttribute(TestBrokerConfiguration.ENTRY_NAME_JMX_PORT, Port.KEY_STORE, TestBrokerConfiguration.ENTRY_NAME_SSL_KEYSTORE);
}
startBroker();
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/Asserts.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/Asserts.java
index e20db6a6ac..6f795cc61d 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/Asserts.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/Asserts.java
@@ -207,14 +207,14 @@ public class Asserts
}
if (isAMQPPort)
{
- assertAttributesPresent(port, Port.AVAILABLE_ATTRIBUTES, Port.CREATED, Port.UPDATED, Port.AUTHENTICATION_PROVIDER);
+ assertAttributesPresent(port, Port.AVAILABLE_ATTRIBUTES, Port.CREATED, Port.UPDATED, Port.AUTHENTICATION_PROVIDER, Port.KEY_STORE, Port.TRUST_STORES);
assertNotNull("Unexpected value of attribute " + Port.BINDING_ADDRESS, port.get(Port.BINDING_ADDRESS));
}
else
{
assertAttributesPresent(port, Port.AVAILABLE_ATTRIBUTES, Port.CREATED, Port.UPDATED, Port.AUTHENTICATION_PROVIDER,
Port.BINDING_ADDRESS, Port.TCP_NO_DELAY, Port.SEND_BUFFER_SIZE, Port.RECEIVE_BUFFER_SIZE,
- Port.NEED_CLIENT_AUTH, Port.WANT_CLIENT_AUTH);
+ Port.NEED_CLIENT_AUTH, Port.WANT_CLIENT_AUTH, Port.KEY_STORE, Port.TRUST_STORES);
}
@SuppressWarnings("unchecked")
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/BasicAuthRestTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/BasicAuthRestTest.java
index 22fb70fa68..ea63cc7f4e 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/BasicAuthRestTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/BasicAuthRestTest.java
@@ -58,6 +58,8 @@ public class BasicAuthRestTest extends QpidRestTestCase
if (useSsl)
{
getBrokerConfiguration().setObjectAttribute(TestBrokerConfiguration.ENTRY_NAME_HTTP_PORT, Port.PROTOCOLS, Collections.singleton(Protocol.HTTPS));
+ getBrokerConfiguration().setObjectAttribute(TestBrokerConfiguration.ENTRY_NAME_HTTP_PORT, Port.KEY_STORE, TestBrokerConfiguration.ENTRY_NAME_SSL_KEYSTORE);
+
}
super.customizeConfiguration();
}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/BrokerRestHttpsTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/BrokerRestHttpsTest.java
index 06927946ba..7fd13ed8aa 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/BrokerRestHttpsTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/BrokerRestHttpsTest.java
@@ -54,6 +54,7 @@ public class BrokerRestHttpsTest extends QpidRestTestCase
Map<String, Object> newAttributes = new HashMap<String, Object>();
newAttributes.put(Port.PROTOCOLS, Collections.singleton(Protocol.HTTPS));
newAttributes.put(Port.TRANSPORTS, Collections.singleton(Transport.SSL));
+ newAttributes.put(Port.KEY_STORE, TestBrokerConfiguration.ENTRY_NAME_SSL_KEYSTORE);
getBrokerConfiguration().setObjectAttributes(TestBrokerConfiguration.ENTRY_NAME_HTTP_PORT,newAttributes);
}
@@ -63,7 +64,6 @@ public class BrokerRestHttpsTest extends QpidRestTestCase
Asserts.assertAttributesPresent(brokerDetails, Broker.AVAILABLE_ATTRIBUTES, Broker.BYTES_RETAINED,
Broker.PROCESS_PID, Broker.SUPPORTED_STORE_TYPES, Broker.CREATED, Broker.TIME_TO_LIVE, Broker.UPDATED,
- Broker.ACL_FILE, Broker.KEY_STORE_CERT_ALIAS, Broker.TRUST_STORE_PATH, Broker.TRUST_STORE_PASSWORD,
- Broker.GROUP_FILE, Broker.PEER_STORE_PATH, Broker.PEER_STORE_PASSWORD);
+ Broker.ACL_FILE, Broker.GROUP_FILE);
}
}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/BrokerRestTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/BrokerRestTest.java
index a795063750..f0e4c1d02a 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/BrokerRestTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/BrokerRestTest.java
@@ -142,13 +142,6 @@ public class BrokerRestTest extends QpidRestTestCase
invalidAttributes.put(Broker.CONNECTION_HEART_BEAT_DELAY, -11000);
invalidAttributes.put(Broker.STATISTICS_REPORTING_PERIOD, -12000);
invalidAttributes.put(Broker.ACL_FILE, QpidTestCase.QPID_HOME + File.separator + "etc" + File.separator + "non-existing-acl.acl");
- invalidAttributes.put(Broker.KEY_STORE_PATH, QpidTestCase.QPID_HOME + File.separator + "etc" + File.separator + "non-existing-keystore.jks");
- invalidAttributes.put(Broker.KEY_STORE_PASSWORD, "password1");
- invalidAttributes.put(Broker.KEY_STORE_CERT_ALIAS, "java-broker1");
- invalidAttributes.put(Broker.TRUST_STORE_PATH, QpidTestCase.QPID_HOME + File.separator + "etc" + File.separator + "non-existing-truststore.jks");
- invalidAttributes.put(Broker.TRUST_STORE_PASSWORD, "password2");
- invalidAttributes.put(Broker.PEER_STORE_PATH, QpidTestCase.QPID_HOME + File.separator + "etc" + File.separator + "non-existing-peerstore.jks");
- invalidAttributes.put(Broker.PEER_STORE_PASSWORD, "password3");
invalidAttributes.put(Broker.GROUP_FILE, QpidTestCase.QPID_HOME + File.separator + "etc" + File.separator + "groups-non-existing");
invalidAttributes.put(Broker.VIRTUALHOST_STORE_TRANSACTION_IDLE_TIMEOUT_CLOSE, -13000);
invalidAttributes.put(Broker.VIRTUALHOST_STORE_TRANSACTION_IDLE_TIMEOUT_WARN, -14000);
@@ -191,13 +184,6 @@ public class BrokerRestTest extends QpidRestTestCase
brokerAttributes.put(Broker.STATISTICS_REPORTING_PERIOD, 12000);
brokerAttributes.put(Broker.STATISTICS_REPORTING_RESET_ENABLED, true);
brokerAttributes.put(Broker.ACL_FILE, QpidTestCase.QPID_HOME + File.separator + "etc" + File.separator + "broker_example.acl");
- brokerAttributes.put(Broker.KEY_STORE_PATH, TestSSLConstants.BROKER_KEYSTORE);
- brokerAttributes.put(Broker.KEY_STORE_PASSWORD, TestSSLConstants.BROKER_KEYSTORE_PASSWORD);
- brokerAttributes.put(Broker.KEY_STORE_CERT_ALIAS, "java-broker");
- brokerAttributes.put(Broker.TRUST_STORE_PATH, TestSSLConstants.TRUSTSTORE);
- brokerAttributes.put(Broker.TRUST_STORE_PASSWORD, TestSSLConstants.TRUSTSTORE_PASSWORD);
- brokerAttributes.put(Broker.PEER_STORE_PATH, TestSSLConstants.TRUSTSTORE);
- brokerAttributes.put(Broker.PEER_STORE_PASSWORD, TestSSLConstants.TRUSTSTORE_PASSWORD);
brokerAttributes.put(Broker.GROUP_FILE, QpidTestCase.QPID_HOME + File.separator + "etc" + File.separator + "groups");
brokerAttributes.put(Broker.VIRTUALHOST_STORE_TRANSACTION_IDLE_TIMEOUT_CLOSE, 13000);
brokerAttributes.put(Broker.VIRTUALHOST_STORE_TRANSACTION_IDLE_TIMEOUT_WARN, 14000);
@@ -212,10 +198,7 @@ public class BrokerRestTest extends QpidRestTestCase
{
String attributeName = entry.getKey();
Object attributeValue = entry.getValue();
- if (attributeName.equals(Broker.KEY_STORE_PASSWORD) || attributeName.equals(Broker.TRUST_STORE_PASSWORD) || attributeName.equals(Broker.PEER_STORE_PASSWORD))
- {
- attributeValue = "********";
- }
+
Object currentValue = actualAttributes.get(attributeName);
assertEquals("Unexpected attribute " + attributeName + " value:", attributeValue, currentValue);
}
@@ -225,10 +208,7 @@ public class BrokerRestTest extends QpidRestTestCase
{
Asserts.assertAttributesPresent(brokerDetails, Broker.AVAILABLE_ATTRIBUTES,
Broker.BYTES_RETAINED, Broker.PROCESS_PID, Broker.SUPPORTED_STORE_TYPES,
- Broker.CREATED, Broker.TIME_TO_LIVE, Broker.UPDATED, Broker.ACL_FILE,
- Broker.KEY_STORE_PATH, Broker.KEY_STORE_PASSWORD, Broker.KEY_STORE_CERT_ALIAS,
- Broker.TRUST_STORE_PATH, Broker.TRUST_STORE_PASSWORD, Broker.GROUP_FILE,
- Broker.PEER_STORE_PATH, Broker.PEER_STORE_PASSWORD);
+ Broker.CREATED, Broker.TIME_TO_LIVE, Broker.UPDATED, Broker.ACL_FILE, Broker.GROUP_FILE);
assertEquals("Unexpected value of attribute " + Broker.BUILD_VERSION, QpidProperties.getBuildVersion(),
brokerDetails.get(Broker.BUILD_VERSION));
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/KeyStoreRestTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/KeyStoreRestTest.java
new file mode 100644
index 0000000000..149ddcfcbb
--- /dev/null
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/KeyStoreRestTest.java
@@ -0,0 +1,269 @@
+/*
+ *
+ * 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.systest.rest;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.qpid.server.model.KeyStore;
+import org.apache.qpid.server.model.Port;
+import org.apache.qpid.server.model.Transport;
+import org.apache.qpid.server.model.adapter.AbstractKeyStoreAdapter;
+import org.apache.qpid.test.utils.TestBrokerConfiguration;
+import org.apache.qpid.test.utils.TestSSLConstants;
+import org.codehaus.jackson.JsonGenerationException;
+import org.codehaus.jackson.JsonParseException;
+import org.codehaus.jackson.map.JsonMappingException;
+
+public class KeyStoreRestTest extends QpidRestTestCase
+{
+ @Override
+ public void setUp() throws Exception
+ {
+ // not calling super.setUp() to avoid broker start-up until
+ // after any necessary configuration
+ }
+
+ public void testGet() throws Exception
+ {
+ super.setUp();
+
+ //verify existence of the default keystore used by the systests
+ List<Map<String, Object>> keyStores = assertNumberOfKeyStores(1);
+
+ Map<String, Object> keystore = keyStores.get(0);
+ assertKeyStoreAttributes(keystore, TestBrokerConfiguration.ENTRY_NAME_SSL_KEYSTORE,
+ System.getProperty(QPID_HOME) + "/../" + TestSSLConstants.BROKER_KEYSTORE, null);
+ }
+
+ public void testCreate() throws Exception
+ {
+ super.setUp();
+
+ String name = getTestName();
+ String certAlias = "app2";
+
+ assertNumberOfKeyStores(1);
+ createKeyStore(name, certAlias);
+ assertNumberOfKeyStores(2);
+
+ List<Map<String, Object>> keyStores = getRestTestHelper().getJsonAsList("/rest/keystore/" + name);
+ assertNotNull("details cannot be null", keyStores);
+
+ assertKeyStoreAttributes(keyStores.get(0), name, TestSSLConstants.KEYSTORE, certAlias);
+ }
+
+ public void testDelete() throws Exception
+ {
+ super.setUp();
+
+ String name = getTestName();
+ String certAlias = "app2";
+
+ assertNumberOfKeyStores(1);
+ createKeyStore(name, certAlias);
+ assertNumberOfKeyStores(2);
+
+ int responseCode = getRestTestHelper().submitRequest("/rest/keystore/" + name , "DELETE", null);
+ assertEquals("Unexpected response code for provider deletion", 200, responseCode);
+
+ List<Map<String, Object>> keyStore = getRestTestHelper().getJsonAsList("/rest/keystore/" + name);
+ assertNotNull("details should not be null", keyStore);
+ assertTrue("details should be empty as the keystore no longer exists", keyStore.isEmpty());
+
+ //check only the default systests key store remains
+ List<Map<String, Object>> keyStores = assertNumberOfKeyStores(1);
+ Map<String, Object> keystore = keyStores.get(0);
+ assertKeyStoreAttributes(keystore, TestBrokerConfiguration.ENTRY_NAME_SSL_KEYSTORE,
+ System.getProperty(QPID_HOME) + "/../" + TestSSLConstants.BROKER_KEYSTORE, null);
+ }
+
+ public void testDeleteFailsWhenKeyStoreInUse() throws Exception
+ {
+ String name = "testDeleteFailsWhenKeyStoreInUse";
+
+ //add a new key store config to use
+ Map<String, Object> sslKeyStoreAttributes = new HashMap<String, Object>();
+ sslKeyStoreAttributes.put(KeyStore.NAME, name);
+ sslKeyStoreAttributes.put(KeyStore.PATH, TestSSLConstants.BROKER_KEYSTORE);
+ sslKeyStoreAttributes.put(KeyStore.PASSWORD, TestSSLConstants.BROKER_KEYSTORE_PASSWORD);
+ getBrokerConfiguration().addKeyStoreConfiguration(sslKeyStoreAttributes);
+
+ //add the SSL port using it
+ Map<String, Object> sslPortAttributes = new HashMap<String, Object>();
+ sslPortAttributes.put(Port.TRANSPORTS, Collections.singleton(Transport.SSL));
+ sslPortAttributes.put(Port.PORT, DEFAULT_SSL_PORT);
+ sslPortAttributes.put(Port.NAME, TestBrokerConfiguration.ENTRY_NAME_SSL_PORT);
+ sslPortAttributes.put(Port.KEY_STORE, name);
+ getBrokerConfiguration().addPortConfiguration(sslPortAttributes);
+
+ super.setUp();
+
+ //verify the keystore is there
+ assertNumberOfKeyStores(2);
+
+ List<Map<String, Object>> keyStore = getRestTestHelper().getJsonAsList("/rest/keystore/" + name);
+ assertNotNull("details should not be null", keyStore);
+ assertKeyStoreAttributes(keyStore.get(0), name, TestSSLConstants.BROKER_KEYSTORE, null);
+
+ //try to delete it, which should fail as it is in use
+ int responseCode = getRestTestHelper().submitRequest("/rest/keystore/" + name , "DELETE", null);
+ assertEquals("Unexpected response code for provider deletion", 409, responseCode);
+
+ //check its still there
+ assertNumberOfKeyStores(2);
+ keyStore = getRestTestHelper().getJsonAsList("/rest/keystore/" + name);
+ assertNotNull("details should not be null", keyStore);
+ assertKeyStoreAttributes(keyStore.get(0), name, TestSSLConstants.BROKER_KEYSTORE, null);
+ }
+
+ public void testUpdateWithGoodPathSucceeds() throws Exception
+ {
+ super.setUp();
+
+ String name = getTestName();
+
+ assertNumberOfKeyStores(1);
+ createKeyStore(name, null);
+ assertNumberOfKeyStores(2);
+
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(KeyStore.NAME, name);
+ attributes.put(KeyStore.PATH, TestSSLConstants.UNTRUSTED_KEYSTORE);
+
+ int responseCode = getRestTestHelper().submitRequest("/rest/keystore/" + name , "PUT", attributes);
+ assertEquals("Unexpected response code for keystore update", 200, responseCode);
+
+ List<Map<String, Object>> keyStore = getRestTestHelper().getJsonAsList("/rest/keystore/" + name);
+ assertNotNull("details should not be null", keyStore);
+
+ assertKeyStoreAttributes(keyStore.get(0), name, TestSSLConstants.UNTRUSTED_KEYSTORE, null);
+ }
+
+ public void testUpdateWithNonExistentPathFails() throws Exception
+ {
+ super.setUp();
+
+ String name = getTestName();
+
+ assertNumberOfKeyStores(1);
+ createKeyStore(name, null);
+ assertNumberOfKeyStores(2);
+
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(KeyStore.NAME, name);
+ attributes.put(KeyStore.PATH, "does.not.exist");
+
+ int responseCode = getRestTestHelper().submitRequest("/rest/keystore/" + name , "PUT", attributes);
+ assertEquals("Unexpected response code for keystore update", 409, responseCode);
+
+ List<Map<String, Object>> keyStore = getRestTestHelper().getJsonAsList("/rest/keystore/" + name);
+ assertNotNull("details should not be null", keyStore);
+
+ //verify the details remain unchanged
+ assertKeyStoreAttributes(keyStore.get(0), name, TestSSLConstants.KEYSTORE, null);
+ }
+
+ public void testUpdateCertificateAlias() throws Exception
+ {
+ super.setUp();
+
+ String name = getTestName();
+
+ assertNumberOfKeyStores(1);
+ createKeyStore(name, "app1");
+ assertNumberOfKeyStores(2);
+
+ List<Map<String, Object>> keyStore = getRestTestHelper().getJsonAsList("/rest/keystore/" + name);
+ assertNotNull("details should not be null", keyStore);
+ assertKeyStoreAttributes(keyStore.get(0), name, TestSSLConstants.KEYSTORE, "app1");
+
+ //Update the certAlias from app1 to app2
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(KeyStore.NAME, name);
+ attributes.put(KeyStore.CERTIFICATE_ALIAS, "app2");
+
+ int responseCode = getRestTestHelper().submitRequest("/rest/keystore/" + name , "PUT", attributes);
+ assertEquals("Unexpected response code for keystore update", 200, responseCode);
+
+ keyStore = getRestTestHelper().getJsonAsList("/rest/keystore/" + name);
+ assertNotNull("details should not be null", keyStore);
+
+ assertKeyStoreAttributes(keyStore.get(0), name, TestSSLConstants.KEYSTORE, "app2");
+
+ //Update the certAlias to clear it (i.e go from from app1 to null)
+ attributes = new HashMap<String, Object>();
+ attributes.put(KeyStore.NAME, name);
+ attributes.put(KeyStore.CERTIFICATE_ALIAS, null);
+
+ responseCode = getRestTestHelper().submitRequest("/rest/keystore/" + name , "PUT", attributes);
+ assertEquals("Unexpected response code for keystore update", 200, responseCode);
+
+ keyStore = getRestTestHelper().getJsonAsList("/rest/keystore/" + name);
+ assertNotNull("details should not be null", keyStore);
+
+ assertKeyStoreAttributes(keyStore.get(0), name, TestSSLConstants.KEYSTORE, null);
+ }
+
+ private List<Map<String, Object>> assertNumberOfKeyStores(int numberOfKeystores) throws IOException,
+ JsonParseException, JsonMappingException
+ {
+ List<Map<String, Object>> keyStores = getRestTestHelper().getJsonAsList("/rest/keystore");
+ assertNotNull("keystores should not be null", keyStores);
+ assertEquals("Unexpected number of keystores", numberOfKeystores, keyStores.size());
+
+ return keyStores;
+ }
+
+ private void createKeyStore(String name, String certAlias) throws IOException, JsonGenerationException, JsonMappingException
+ {
+ Map<String, Object> keyStoreAttributes = new HashMap<String, Object>();
+ keyStoreAttributes.put(KeyStore.NAME, name);
+ keyStoreAttributes.put(KeyStore.PATH, TestSSLConstants.KEYSTORE);
+ keyStoreAttributes.put(KeyStore.PASSWORD, TestSSLConstants.KEYSTORE_PASSWORD);
+ keyStoreAttributes.put(KeyStore.CERTIFICATE_ALIAS, certAlias);
+
+ int responseCode = getRestTestHelper().submitRequest("/rest/keystore/" + name, "PUT", keyStoreAttributes);
+ assertEquals("Unexpected response code", 201, responseCode);
+ }
+
+ private void assertKeyStoreAttributes(Map<String, Object> keystore, String name, String path, String certAlias)
+ {
+ assertEquals("default systests key store is missing",
+ name, keystore.get(KeyStore.NAME));
+ assertEquals("unexpected path to key store",
+ path, keystore.get(KeyStore.PATH));
+ assertEquals("unexpected (dummy) password of default systests key store",
+ AbstractKeyStoreAdapter.DUMMY_PASSWORD_MASK, keystore.get(KeyStore.PASSWORD));
+ assertEquals("unexpected type of default systests key store",
+ java.security.KeyStore.getDefaultType(), keystore.get(KeyStore.TYPE));
+ assertEquals("unexpected certificateAlias value",
+ certAlias, keystore.get(KeyStore.CERTIFICATE_ALIAS));
+ if(certAlias == null)
+ {
+ assertFalse("should not be a certificateAlias attribute",
+ keystore.containsKey(KeyStore.CERTIFICATE_ALIAS));
+ }
+ }
+}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/PortRestTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/PortRestTest.java
index 1497d740dc..8ec9e50fa9 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/PortRestTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/PortRestTest.java
@@ -30,7 +30,6 @@ import java.util.List;
import java.util.Map;
import org.apache.qpid.server.model.AuthenticationProvider;
-import org.apache.qpid.server.model.Broker;
import org.apache.qpid.server.model.Port;
import org.apache.qpid.server.model.Protocol;
import org.apache.qpid.server.model.State;
@@ -205,6 +204,7 @@ public class PortRestTest extends QpidRestTestCase
Map<String, Object> attributes = new HashMap<String, Object>();
attributes.put(Port.NAME, portName);
attributes.put(Port.TRANSPORTS, Collections.singleton(Transport.SSL));
+ attributes.put(Port.KEY_STORE, TestBrokerConfiguration.ENTRY_NAME_SSL_KEYSTORE);
int responseCode = getRestTestHelper().submitRequest("/rest/port/" + portName, "PUT", attributes);
assertEquals("Transport has not been changed to SSL " , 200, responseCode);
@@ -217,12 +217,13 @@ public class PortRestTest extends QpidRestTestCase
Collection<String> transports = (Collection<String>) port.get(Port.TRANSPORTS);
assertEquals("Unexpected auth provider", new HashSet<String>(Arrays.asList(Transport.SSL.name())),
new HashSet<String>(transports));
+
+ String keyStore = (String) port.get(Port.KEY_STORE);
+ assertEquals("Unexpected auth provider", TestBrokerConfiguration.ENTRY_NAME_SSL_KEYSTORE, keyStore);
}
public void testUpdateTransportFromTCPToSSLWithoutKeystoreConfiguredFails() throws Exception
{
- getBrokerConfiguration().setBrokerAttribute(Broker.KEY_STORE_PATH, null);
- getBrokerConfiguration().setSaved(false);
restartBrokerInManagementMode();
String portName = TestBrokerConfiguration.ENTRY_NAME_AMQP_PORT;
@@ -241,6 +242,8 @@ public class PortRestTest extends QpidRestTestCase
attributes.put(Port.NAME, portName);
attributes.put(Port.PORT, DEFAULT_SSL_PORT);
attributes.put(Port.TRANSPORTS, Collections.singleton(Transport.SSL));
+ attributes.put(Port.KEY_STORE, TestBrokerConfiguration.ENTRY_NAME_SSL_KEYSTORE);
+ attributes.put(Port.TRUST_STORES, Collections.singleton(TestBrokerConfiguration.ENTRY_NAME_SSL_TRUSTSTORE));
int responseCode = getRestTestHelper().submitRequest("/rest/port/" + portName, "PUT", attributes);
assertEquals("SSL port was not added", 201, responseCode);
@@ -257,6 +260,11 @@ public class PortRestTest extends QpidRestTestCase
Map<String, Object> port = getRestTestHelper().getJsonAsSingletonList("/rest/port/" + portName);
assertEquals("Unexpected " + Port.NEED_CLIENT_AUTH, true, port.get(Port.NEED_CLIENT_AUTH));
assertEquals("Unexpected " + Port.WANT_CLIENT_AUTH, true, port.get(Port.WANT_CLIENT_AUTH));
+ assertEquals("Unexpected " + Port.KEY_STORE, TestBrokerConfiguration.ENTRY_NAME_SSL_KEYSTORE, port.get(Port.KEY_STORE));
+ @SuppressWarnings("unchecked")
+ Collection<String> trustStores = (Collection<String>) port.get(Port.TRUST_STORES);
+ assertEquals("Unexpected auth provider", new HashSet<String>(Arrays.asList(TestBrokerConfiguration.ENTRY_NAME_SSL_TRUSTSTORE)),
+ new HashSet<String>(trustStores));
restartBrokerInManagementMode();
@@ -265,7 +273,7 @@ public class PortRestTest extends QpidRestTestCase
attributes.put(Port.TRANSPORTS, Collections.singleton(Transport.TCP));
responseCode = getRestTestHelper().submitRequest("/rest/port/" + portName, "PUT", attributes);
- assertEquals("Should not be able to change transport to SSL without reseting of attributes for need/want client auth", 409, responseCode);
+ assertEquals("Should not be able to change transport to TCP without reseting of attributes for need/want client auth", 409, responseCode);
attributes = new HashMap<String, Object>();
attributes.put(Port.NAME, portName);
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/TrustStoreRestTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/TrustStoreRestTest.java
new file mode 100644
index 0000000000..87e7367235
--- /dev/null
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/TrustStoreRestTest.java
@@ -0,0 +1,261 @@
+/*
+ *
+ * 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.systest.rest;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.qpid.server.model.KeyStore;
+import org.apache.qpid.server.model.Port;
+import org.apache.qpid.server.model.Transport;
+import org.apache.qpid.server.model.TrustStore;
+import org.apache.qpid.server.model.adapter.AbstractKeyStoreAdapter;
+import org.apache.qpid.test.utils.TestBrokerConfiguration;
+import org.apache.qpid.test.utils.TestSSLConstants;
+import org.codehaus.jackson.JsonGenerationException;
+import org.codehaus.jackson.JsonParseException;
+import org.codehaus.jackson.map.JsonMappingException;
+
+public class TrustStoreRestTest extends QpidRestTestCase
+{
+ @Override
+ public void setUp() throws Exception
+ {
+ // not calling super.setUp() to avoid broker start-up until
+ // after any necessary configuration
+ }
+
+ public void testGet() throws Exception
+ {
+ super.setUp();
+
+ //verify existence of the default trust store used by the systests
+ List<Map<String, Object>> trustStores = assertNumberOfTrustStores(1);
+
+ Map<String, Object> truststore = trustStores.get(0);
+ assertTrustStoreAttributes(truststore, TestBrokerConfiguration.ENTRY_NAME_SSL_TRUSTSTORE,
+ System.getProperty(QPID_HOME) + "/../" + TestSSLConstants.BROKER_TRUSTSTORE, false);
+ }
+
+ public void testCreate() throws Exception
+ {
+ super.setUp();
+
+ String name = getTestName();
+
+ assertNumberOfTrustStores(1);
+ createTrustStore(name, true);
+ assertNumberOfTrustStores(2);
+
+ List<Map<String, Object>> trustStores = getRestTestHelper().getJsonAsList("/rest/truststore/" + name);
+ assertNotNull("details cannot be null", trustStores);
+
+ assertTrustStoreAttributes(trustStores.get(0), name, TestSSLConstants.TRUSTSTORE, true);
+ }
+
+ public void testDelete() throws Exception
+ {
+ super.setUp();
+
+ String name = getTestName();
+
+ assertNumberOfTrustStores(1);
+ createTrustStore(name, false);
+ assertNumberOfTrustStores(2);
+
+ int responseCode = getRestTestHelper().submitRequest("/rest/truststore/" + name , "DELETE", null);
+ assertEquals("Unexpected response code for provider deletion", 200, responseCode);
+
+ List<Map<String, Object>> trustStore = getRestTestHelper().getJsonAsList("/rest/truststore/" + name);
+ assertNotNull("details should not be null", trustStore);
+ assertTrue("details should be empty as the truststore no longer exists", trustStore.isEmpty());
+
+ //check only the default systests trust store remains
+ List<Map<String, Object>> trustStores = assertNumberOfTrustStores(1);
+ Map<String, Object> truststore = trustStores.get(0);
+ assertTrustStoreAttributes(truststore, TestBrokerConfiguration.ENTRY_NAME_SSL_TRUSTSTORE,
+ System.getProperty(QPID_HOME) + "/../" + TestSSLConstants.BROKER_TRUSTSTORE, false);
+ }
+
+ public void testDeleteFailsWhenTrustStoreInUse() throws Exception
+ {
+ String name = "testDeleteFailsWhenTrustStoreInUse";
+
+ //add a new trust store config to use
+ Map<String, Object> sslTrustStoreAttributes = new HashMap<String, Object>();
+ sslTrustStoreAttributes.put(TrustStore.NAME, name);
+ sslTrustStoreAttributes.put(TrustStore.PATH, TestSSLConstants.TRUSTSTORE);
+ sslTrustStoreAttributes.put(TrustStore.PASSWORD, TestSSLConstants.TRUSTSTORE_PASSWORD);
+ getBrokerConfiguration().addTrustStoreConfiguration(sslTrustStoreAttributes);
+
+ //add the SSL port using it
+ Map<String, Object> sslPortAttributes = new HashMap<String, Object>();
+ sslPortAttributes.put(Port.TRANSPORTS, Collections.singleton(Transport.SSL));
+ sslPortAttributes.put(Port.PORT, DEFAULT_SSL_PORT);
+ sslPortAttributes.put(Port.NAME, TestBrokerConfiguration.ENTRY_NAME_SSL_PORT);
+ sslPortAttributes.put(Port.KEY_STORE, TestBrokerConfiguration.ENTRY_NAME_SSL_KEYSTORE);
+ sslPortAttributes.put(Port.TRUST_STORES, Collections.singleton(name));
+ getBrokerConfiguration().addPortConfiguration(sslPortAttributes);
+
+ super.setUp();
+
+ //verify the truststore is there
+ assertNumberOfTrustStores(2);
+
+ List<Map<String, Object>> trustStore = getRestTestHelper().getJsonAsList("/rest/truststore/" + name);
+ assertNotNull("details should not be null", trustStore);
+ assertTrustStoreAttributes(trustStore.get(0), name, TestSSLConstants.TRUSTSTORE, false);
+
+ //try to delete it, which should fail as it is in use
+ int responseCode = getRestTestHelper().submitRequest("/rest/truststore/" + name , "DELETE", null);
+ assertEquals("Unexpected response code for provider deletion", 409, responseCode);
+
+ //check its still there
+ assertNumberOfTrustStores(2);
+ trustStore = getRestTestHelper().getJsonAsList("/rest/truststore/" + name);
+ assertNotNull("details should not be null", trustStore);
+ assertTrustStoreAttributes(trustStore.get(0), name, TestSSLConstants.TRUSTSTORE, false);
+ }
+
+ public void testUpdateWithGoodPathSucceeds() throws Exception
+ {
+ super.setUp();
+
+ String name = getTestName();
+
+ assertNumberOfTrustStores(1);
+ createTrustStore(name, false);
+ assertNumberOfTrustStores(2);
+
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(TrustStore.NAME, name);
+ attributes.put(TrustStore.PATH, TestSSLConstants.TRUSTSTORE);
+
+ int responseCode = getRestTestHelper().submitRequest("/rest/truststore/" + name , "PUT", attributes);
+ assertEquals("Unexpected response code for truststore update", 200, responseCode);
+
+ List<Map<String, Object>> trustStore = getRestTestHelper().getJsonAsList("/rest/truststore/" + name);
+ assertNotNull("details should not be null", trustStore);
+
+ assertTrustStoreAttributes(trustStore.get(0), name, TestSSLConstants.TRUSTSTORE, false);
+ }
+
+ public void testUpdateWithNonExistentPathFails() throws Exception
+ {
+ super.setUp();
+
+ String name = getTestName();
+
+ assertNumberOfTrustStores(1);
+ createTrustStore(name, false);
+ assertNumberOfTrustStores(2);
+
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(TrustStore.NAME, name);
+ attributes.put(TrustStore.PATH, "does.not.exist");
+
+ int responseCode = getRestTestHelper().submitRequest("/rest/truststore/" + name , "PUT", attributes);
+ assertEquals("Unexpected response code for trust store update", 409, responseCode);
+
+ List<Map<String, Object>> trustStore = getRestTestHelper().getJsonAsList("/rest/truststore/" + name);
+ assertNotNull("details should not be null", trustStore);
+
+ //verify the details remain unchanged
+ assertTrustStoreAttributes(trustStore.get(0), name, TestSSLConstants.TRUSTSTORE, false);
+ }
+
+ public void testUpdatePeersOnly() throws Exception
+ {
+ super.setUp();
+
+ String name = getTestName();
+
+ assertNumberOfTrustStores(1);
+ createTrustStore(name, false);
+ assertNumberOfTrustStores(2);
+
+ //update the peersOnly attribute from false to true
+ Map<String, Object> attributes = new HashMap<String, Object>();
+ attributes.put(TrustStore.NAME, name);
+ attributes.put(TrustStore.PEERS_ONLY, true);
+
+ int responseCode = getRestTestHelper().submitRequest("/rest/truststore/" + name , "PUT", attributes);
+ assertEquals("Unexpected response code for trust store update", 200, responseCode);
+
+ List<Map<String, Object>> trustStore = getRestTestHelper().getJsonAsList("/rest/truststore/" + name);
+ assertNotNull("details should not be null", trustStore);
+
+ assertTrustStoreAttributes(trustStore.get(0), name, TestSSLConstants.TRUSTSTORE, true);
+
+ //Update peersOnly to clear it (i.e go from from true to null, which will default to false)
+ attributes = new HashMap<String, Object>();
+ attributes.put(TrustStore.NAME, name);
+ attributes.put(TrustStore.PEERS_ONLY, null);
+
+ responseCode = getRestTestHelper().submitRequest("/rest/truststore/" + name , "PUT", attributes);
+ assertEquals("Unexpected response code for trust store update", 200, responseCode);
+
+ trustStore = getRestTestHelper().getJsonAsList("/rest/truststore/" + name);
+ assertNotNull("details should not be null", trustStore);
+
+ assertTrustStoreAttributes(trustStore.get(0), name, TestSSLConstants.TRUSTSTORE, false);
+ }
+
+ private List<Map<String, Object>> assertNumberOfTrustStores(int numberOfTrustStores) throws IOException,
+ JsonParseException, JsonMappingException
+ {
+ List<Map<String, Object>> trustStores = getRestTestHelper().getJsonAsList("/rest/truststore");
+ assertNotNull("trust stores should not be null", trustStores);
+ assertEquals("Unexpected number of trust stores", numberOfTrustStores, trustStores.size());
+
+ return trustStores;
+ }
+
+ private void createTrustStore(String name, boolean peersOnly) throws IOException, JsonGenerationException, JsonMappingException
+ {
+ Map<String, Object> trustStoreAttributes = new HashMap<String, Object>();
+ trustStoreAttributes.put(TrustStore.NAME, name);
+ //deliberately using the client trust store to differentiate from the one we are already for broker
+ trustStoreAttributes.put(TrustStore.PATH, TestSSLConstants.TRUSTSTORE);
+ trustStoreAttributes.put(TrustStore.PASSWORD, TestSSLConstants.TRUSTSTORE_PASSWORD);
+ trustStoreAttributes.put(TrustStore.PEERS_ONLY, peersOnly);
+
+ int responseCode = getRestTestHelper().submitRequest("/rest/truststore/" + name, "PUT", trustStoreAttributes);
+ assertEquals("Unexpected response code", 201, responseCode);
+ }
+
+ private void assertTrustStoreAttributes(Map<String, Object> truststore, String name, String path, boolean peersOnly)
+ {
+ assertEquals("default systests trust store is missing",
+ name, truststore.get(TrustStore.NAME));
+ assertEquals("unexpected path to trust store",
+ path, truststore.get(TrustStore.PATH));
+ assertEquals("unexpected (dummy) password of default systests trust store",
+ AbstractKeyStoreAdapter.DUMMY_PASSWORD_MASK, truststore.get(TrustStore.PASSWORD));
+ assertEquals("unexpected type of default systests trust store",
+ java.security.KeyStore.getDefaultType(), truststore.get(TrustStore.TYPE));
+ assertEquals("unexpected peersOnly value",
+ peersOnly, truststore.get(TrustStore.PEERS_ONLY));
+ }
+}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/JMXTestUtils.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/JMXTestUtils.java
index 6e6e3271f0..4004a43fde 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/JMXTestUtils.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/JMXTestUtils.java
@@ -31,8 +31,6 @@ import org.apache.qpid.management.common.mbeans.ManagedExchange;
import org.apache.qpid.management.common.mbeans.ManagedQueue;
import org.apache.qpid.management.common.mbeans.ServerInformation;
import org.apache.qpid.management.common.mbeans.UserManagement;
-import org.apache.qpid.server.model.Plugin;
-import org.apache.qpid.server.plugin.PluginFactory;
import javax.management.InstanceNotFoundException;
import javax.management.JMException;
@@ -47,9 +45,7 @@ import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import java.io.IOException;
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
import java.util.Set;
/**
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/TestBrokerConfiguration.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/TestBrokerConfiguration.java
index db10bfb7e7..44a46fc8b2 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/TestBrokerConfiguration.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/TestBrokerConfiguration.java
@@ -31,8 +31,10 @@ import java.util.UUID;
import org.apache.qpid.server.configuration.ConfigurationEntry;
import org.apache.qpid.server.configuration.store.MemoryConfigurationEntryStore;
import org.apache.qpid.server.model.AuthenticationProvider;
+import org.apache.qpid.server.model.KeyStore;
import org.apache.qpid.server.model.Plugin;
import org.apache.qpid.server.model.Port;
+import org.apache.qpid.server.model.TrustStore;
import org.apache.qpid.server.model.UUIDGenerator;
import org.apache.qpid.server.model.VirtualHost;
import org.apache.qpid.server.plugin.PluginFactory;
@@ -52,6 +54,8 @@ public class TestBrokerConfiguration
public static final String ENTRY_NAME_JMX_MANAGEMENT = "MANAGEMENT-JMX";
public static final String MANAGEMENT_JMX_PLUGIN_TYPE = "MANAGEMENT-JMX";
public static final String ENTRY_NAME_ANONYMOUS_PROVIDER = "anonymous";
+ public static final String ENTRY_NAME_SSL_KEYSTORE = "systestsKeyStore";
+ public static final String ENTRY_NAME_SSL_TRUSTSTORE = "systestsTrustStore";
private MemoryConfigurationEntryStore _store;
private boolean _saved;
@@ -144,6 +148,18 @@ public class TestBrokerConfiguration
return addObjectConfiguration(name, AuthenticationProvider.class.getSimpleName(), attributes);
}
+ public UUID addTrustStoreConfiguration(Map<String, Object> attributes)
+ {
+ String name = (String) attributes.get(TrustStore.NAME);
+ return addObjectConfiguration(name, TrustStore.class.getSimpleName(), attributes);
+ }
+
+ public UUID addKeyStoreConfiguration(Map<String, Object> attributes)
+ {
+ String name = (String) attributes.get(KeyStore.NAME);
+ return addObjectConfiguration(name, KeyStore.class.getSimpleName(), attributes);
+ }
+
private boolean setObjectAttributes(ConfigurationEntry entry, Map<String, Object> attributes)
{
Map<String, Object> newAttributes = new HashMap<String, Object>(entry.getAttributes());