diff options
| author | Robert Gemmell <robbie@apache.org> | 2013-04-12 16:16:09 +0000 |
|---|---|---|
| committer | Robert Gemmell <robbie@apache.org> | 2013-04-12 16:16:09 +0000 |
| commit | be1eaff9cecb3ff1947346c7e0feab3a41fe2328 (patch) | |
| tree | 98b1f38ee1e255e9c3323482e23da25f2e159164 /java/broker-plugins | |
| parent | b1c63c01a2ef08f1554ccaec146ea6b67f7727c0 (diff) | |
| download | qpid-python-be1eaff9cecb3ff1947346c7e0feab3a41fe2328.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/qpid@1467334 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'java/broker-plugins')
22 files changed, 1064 insertions, 246 deletions
diff --git a/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagement.java b/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagement.java index 2f51e30b57..3cc382596a 100644 --- a/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagement.java +++ b/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/java/broker-plugins/management-http/src/main/java/resources/addAuthenticationProvider.html b/java/broker-plugins/management-http/src/main/java/resources/addAuthenticationProvider.html index 90dd1f1090..f4846ac556 100644 --- a/java/broker-plugins/management-http/src/main/java/resources/addAuthenticationProvider.html +++ b/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/java/broker-plugins/management-http/src/main/java/resources/addBinding.html b/java/broker-plugins/management-http/src/main/java/resources/addBinding.html index 8dbd219c8d..9aebca90d7 100644 --- a/java/broker-plugins/management-http/src/main/java/resources/addBinding.html +++ b/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/java/broker-plugins/management-http/src/main/java/resources/addExchange.html b/java/broker-plugins/management-http/src/main/java/resources/addExchange.html index 4a59cd2cbc..8c9968e37a 100644 --- a/java/broker-plugins/management-http/src/main/java/resources/addExchange.html +++ b/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/java/broker-plugins/management-http/src/main/java/resources/addPort.html b/java/broker-plugins/management-http/src/main/java/resources/addPort.html index c37b879bd5..391783c6d8 100644 --- a/java/broker-plugins/management-http/src/main/java/resources/addPort.html +++ b/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/java/broker-plugins/management-http/src/main/java/resources/addQueue.html b/java/broker-plugins/management-http/src/main/java/resources/addQueue.html index 950809d5fc..90a0af7ea9 100644 --- a/java/broker-plugins/management-http/src/main/java/resources/addQueue.html +++ b/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/java/broker-plugins/management-http/src/main/java/resources/addVirtualHost.html b/java/broker-plugins/management-http/src/main/java/resources/addVirtualHost.html index 9b492ef26d..43281f600d 100644 --- a/java/broker-plugins/management-http/src/main/java/resources/addVirtualHost.html +++ b/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/java/broker-plugins/management-http/src/main/java/resources/index.html b/java/broker-plugins/management-http/src/main/java/resources/index.html index a9cb580103..c4fbe77b08 100644 --- a/java/broker-plugins/management-http/src/main/java/resources/index.html +++ b/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/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/util.js b/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/util.js index 5ff208d43f..77ae1ccf47 100644 --- a/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/util.js +++ b/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/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Broker.js b/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Broker.js index 04ac80784a..b07b68c835 100644 --- a/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Broker.js +++ b/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/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/KeyStore.js b/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/KeyStore.js new file mode 100644 index 0000000000..9702c6b9f6 --- /dev/null +++ b/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/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/TrustStore.js b/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/TrustStore.js new file mode 100644 index 0000000000..703ef34ec2 --- /dev/null +++ b/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/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addAuthenticationProvider.js b/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addAuthenticationProvider.js index decc7fa0b3..d2891c7d3b 100644 --- a/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addAuthenticationProvider.js +++ b/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/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addKeystore.js b/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addKeystore.js new file mode 100644 index 0000000000..4fdcffb7f1 --- /dev/null +++ b/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/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addPort.js b/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addPort.js index 0c1a188cbf..c60ad5bb79 100644 --- a/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/addPort.js +++ b/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/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/controller.js b/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/controller.js index 5d3a666760..c4114739c0 100644 --- a/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/controller.js +++ b/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/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/treeView.js b/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/treeView.js index 59356cfce1..f96fc13a03 100644 --- a/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/treeView.js +++ b/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/java/broker-plugins/management-http/src/main/java/resources/showBroker.html b/java/broker-plugins/management-http/src/main/java/resources/showBroker.html index 887ca4e736..9e267f0d5d 100644 --- a/java/broker-plugins/management-http/src/main/java/resources/showBroker.html +++ b/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/java/broker-plugins/management-http/src/main/java/resources/showKeyStore.html b/java/broker-plugins/management-http/src/main/java/resources/showKeyStore.html new file mode 100644 index 0000000000..5caee836d3 --- /dev/null +++ b/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/java/broker-plugins/management-http/src/main/java/resources/showTrustStore.html b/java/broker-plugins/management-http/src/main/java/resources/showTrustStore.html new file mode 100644 index 0000000000..6f9146fdfe --- /dev/null +++ b/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/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/JMXManagedObjectRegistry.java b/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/JMXManagedObjectRegistry.java index 93f7df8c85..a1356028f0 100644 --- a/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/JMXManagedObjectRegistry.java +++ b/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/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/QpidSslRMIServerSocketFactory.java b/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/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(); + } + +} |
