diff options
author | Robert Godfrey <rgodfrey@apache.org> | 2013-04-23 19:12:27 +0000 |
---|---|---|
committer | Robert Godfrey <rgodfrey@apache.org> | 2013-04-23 19:12:27 +0000 |
commit | 917a1f26f8f26730528dd538ab817a340cdd8715 (patch) | |
tree | 7e2ceb5cf2c31cf232d616fb7c96ea9489cd9fbc | |
parent | 8eaa6f007e3cf2d287067b993ccf8058d0c66690 (diff) | |
download | qpid-python-917a1f26f8f26730528dd538ab817a340cdd8715.tar.gz |
Merged up to r1465457
git-svn-id: https://svn.apache.org/repos/asf/qpid/branches/QPID-4659@1471100 13f79535-47bb-0310-9956-ffa450edef68
44 files changed, 891 insertions, 367 deletions
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 f164ece082..90dd1f1090 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 @@ -25,7 +25,7 @@ <tr> <td class="tableContainer-labelCell" style="width: 300px;">Name*:</td> <td class="tableContainer-valueCell"><input type="text" required="true" name="name" - id="formAddAuthenticationProvider.name" placeholder="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> </tr> </table> 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 10ac5388ff..4a59cd2cbc 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 @@ -26,7 +26,7 @@ <td valign="top"><strong>Exchange Name*: </strong></td> <td><input type="text" required="true" name="name" id="formAddExchange.name" placeholder="Exchange Name" dojoType="dijit.form.ValidationTextBox" missingMessage="A name must be supplied" - data-dojo-props="regExp:'^(?!qpid\.|amq\.|\<\<default\>\>).*$', invalidMessage:'Reserved exchange name!'"/></td> + data-dojo-props="regExp:'^(?!qpid\.|amq\.|\<\<default\>\>)[\x20-\x2e\x30-\x7F]{1,255}$', invalidMessage:'Illegal or reserved exchange name!'"/></td> </tr> <tr> <td valign="top"><strong>Durable? </strong></td> 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 2f49ab1448..c37b879bd5 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 @@ -21,10 +21,11 @@ <div class="dijitHidden"> <div data-dojo-type="dijit.Dialog" style="width:600px;" data-dojo-props="title:'Port'" id="addPort"> <form id="formAddPort" method="post" dojoType="dijit.form.Form"> + <div class="dijitDialogPaneContentArea"> <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" - missingMessage="A name must be supplied" /> + missingMessage="A name must be supplied" regexp="^[\x20-\x2e\x30-\x7F]{1,255}$"/> <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" /> @@ -53,7 +54,7 @@ <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" name="protocolsDefault" checked="checked" + <input id="formAddPort.protocolsDefault" type="checkbox" checked="checked" dojoType="dijit.form.CheckBox" data-dojo-props="label: 'Support broker default AMQP versions:'"/> <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:'" @@ -80,8 +81,11 @@ </select> </div> <input type="hidden" id="formAddPort.id" name="id"/> + </div> + <div class="dijitDialogPaneActionBar"> <!-- submit buttons --> <input type="submit" value="Save Port" label="Save Port" dojoType="dijit.form.Button" /> + </div> </form> </div> </div> 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 d396f28877..950809d5fc 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 @@ -25,7 +25,7 @@ <tr> <td valign="top"><strong>Queue Name*: </strong></td> <td><input type="text" required="true" name="name" id="formAddQueue.name" placeholder="Queue Name" - dojoType="dijit.form.ValidationTextBox" missingMessage="A name must be supplied" /></td> + dojoType="dijit.form.ValidationTextBox" missingMessage="A name must be supplied" regexp="^[\x20-\x2e\x30-\x7F]{1,255}$"/></td> </tr> <tr> <td valign="top"><strong>Durable? </strong></td> 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 d66e0e1b03..9b492ef26d 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 @@ -27,7 +27,7 @@ <td class="tableContainer-valueCell"> <input type="text" required="true" name="name" id="formAddVirtualHost.name" placeholder="Virtual Host Name" dojoType="dijit.form.ValidationTextBox" - missingMessage="A name must be supplied" /> + missingMessage="A name must be supplied" regexp="^[\x20-\x2e\x30-\x7F]{1,255}$"/> </td> </tr> </table> 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 fea67d5942..5ff208d43f 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 @@ -26,6 +26,7 @@ define(["dojo/_base/xhr", "dojo/dom-construct", "dojo/dom-geometry", "dojo/window", + "dijit/TitlePane", "dijit/Dialog", "dijit/form/Form", "dijit/form/Button", @@ -163,6 +164,7 @@ define(["dojo/_base/xhr", var widgets = {}; var requiredFor ={}; + var groups = {}; for(var i in attributeWidgetFactories) { var attributeWidgetFactory = attributeWidgetFactories[i]; @@ -170,8 +172,38 @@ define(["dojo/_base/xhr", var name = attributeWidgetFactory.name ? attributeWidgetFactory.name : widget.name; widgets[name] = widget; widget.initialValue = widget.value; - layout.addChild(widget); - if (attributeWidgetFactory.hasOwnProperty("requiredFor")) + var dotPos = name.indexOf("."); + if (dotPos == -1) + { + layout.addChild(widget); + } + else + { + var groupName = name.substring(0, dotPos); + var groupFieldContainer = null; + if (groups.hasOwnProperty(groupName)) + { + groupFieldContainer = groups[groupName]; + } + else + { + groupFieldContainer = new dojox.layout.TableContainer({ + cols: 1, + "labelWidth": "290", + showLabels: true, + orientation: "horiz", + customClass: "formLabel" + }); + 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}); + dialogContentArea.appendChild(dom.create("br")); + dialogContentArea.appendChild(panel.domNode); + } + groupFieldContainer.addChild(widget); + } + if (attributeWidgetFactory.hasOwnProperty("requiredFor") && !data[name]) { requiredFor[attributeWidgetFactory.requiredFor] = widget; } @@ -249,7 +281,7 @@ define(["dojo/_base/xhr", form.connectChildren(true); setAttributesDialog.startup(); setAttributesDialog.on("show", function(){ - var data = geometry.position(layout.domNode); + var data = geometry.position(dialogContentArea); var maxHeight = win.getBox().h * 0.6; if (data.h > maxHeight) { 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 f5e40025c2..04ac80784a 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 @@ -125,23 +125,25 @@ define(["dojo/_base/xhr", name: "keyStorePath"}); } }, { - name: "keyStoreCertAlias", + name: "keyStorePassword", + requiredFor: "keyStorePath", createWidget: function(brokerData) { return new dijit.form.ValidationTextBox({ required: false, - value: brokerData.keyStoreCertAlias, - label: "Keystore certificate alias:", - name: "keyStoreCertAlias"}); + label: "Keystore password:", + invalidMessage: "Missed keystore password", + name: "keyStorePassword", + placeholder: brokerData["keyStorePassword"] ? brokerData["keyStorePassword"] : "" + }); } }, { - name: "keyStorePassword", - requiredFor: "keyStorePath", + name: "keyStoreCertAlias", createWidget: function(brokerData) { return new dijit.form.ValidationTextBox({ required: false, - label: "Keystore password:", - invalidMessage: "Missed keystore password", - name: "keyStorePassword"}); + value: brokerData.keyStoreCertAlias, + label: "Keystore certificate alias:", + name: "keyStoreCertAlias"}); } }, { name: "trustStorePath", @@ -161,7 +163,9 @@ define(["dojo/_base/xhr", required: false, label: "Truststore password:", invalidMessage: "Missed trustore password", - name: "trustStorePassword"}); + name: "trustStorePassword", + placeholder: brokerData["trustStorePassword"] ? brokerData["trustStorePassword"] : "" + }); } }, { name: "peerStorePath", @@ -180,10 +184,37 @@ define(["dojo/_base/xhr", required: false, label: "Peerstore password:", invalidMessage: "Missed peerstore password", - name: "peerStorePassword"}); + name: "peerStorePassword", + placeholder: brokerData["peerStorePassword"] ? brokerData["peerStorePassword"] : "" + }); + } + }, { + name: "statisticsReportingPeriod", + createWidget: function(brokerData) { + return new dijit.form.ValidationTextBox({ + trim: "true", + regexp: "[0-9]+", + invalidMessage: "Invalid value", + required: false, + value: brokerData.statisticsReportingPeriod, + placeholder: "Time in ms", + label: "Statistics reporting period (ms):", + name: "statisticsReportingPeriod" + }); + } + }, { + name: "statisticsReportingResetEnabled", + createWidget: function(brokerData) + { + return new dijit.form.CheckBox({ + required: false, checked: brokerData.statisticsReportingResetEnabled, value: "true", + label: "Statistics reporting period enabled:", + name: "statisticsReportingResetEnabled" + }); } }, { name: "queue.alertThresholdQueueDepthMessages", + groupName: "Global Queue Defaults", createWidget: function(brokerData) { return new dijit.form.ValidationTextBox({ trim: "true", @@ -191,8 +222,8 @@ define(["dojo/_base/xhr", invalidMessage: "Invalid value", required: false, value: brokerData["queue.alertThresholdQueueDepthMessages"], - placeholder: "Count of messages", - label: "Queue depth messages alert threshold:", + placeholder: "Number of messages", + label: "Depth alert threshold (messages):", name: "queue.alertThresholdQueueDepthMessages" }); } @@ -206,7 +237,7 @@ define(["dojo/_base/xhr", required: false, value: brokerData["queue.alertThresholdQueueDepthBytes"], placeholder: "Number of bytes", - label: "Queue depth bytes alert threshold:", + label: "Depth alert threshold (bytes):", name: "queue.alertThresholdQueueDepthBytes" }); } @@ -220,7 +251,7 @@ define(["dojo/_base/xhr", required: false, value: brokerData["queue.alertThresholdMessageAge"], placeholder: "Time in ms", - label: "Queue message age alert threshold:", + label: "Message age alert threshold (ms):", name: "queue.alertThresholdMessageAge" }); } @@ -234,7 +265,7 @@ define(["dojo/_base/xhr", required: false, value: brokerData["queue.alertThresholdMessageSize"], placeholder: "Size in bytes", - label: "Queue message size alert threshold:", + label: "Message size alert threshold (bytes):", name: "queue.alertThresholdMessageSize" }); } @@ -248,7 +279,7 @@ define(["dojo/_base/xhr", required: false, value: brokerData["queue.alertRepeatGap"], placeholder: "Time in ms", - label: "Queue alert repeat gap:", + label: "Alert repeat gap (ms):", name: "queue.alertRepeatGap" }); } @@ -261,8 +292,8 @@ define(["dojo/_base/xhr", invalidMessage: "Invalid value", required: false, value: brokerData["queue.maximumDeliveryAttempts"], - placeholder: "Count of messages", - label: "Queue maximum delivery retries:", + placeholder: "Number of messages", + label: "Maximum delivery retries (messages):", name: "queue.maximumDeliveryAttempts" }); } @@ -287,7 +318,7 @@ define(["dojo/_base/xhr", required: false, value: brokerData["queue.flowControlSizeBytes"], placeholder: "Size in bytes", - label: "Queue flow capacity:", + label: "Flow control threshold (bytes):", name: "queue.flowControlSizeBytes", }); } @@ -301,12 +332,13 @@ define(["dojo/_base/xhr", required: false, value: brokerData["queue.flowResumeSizeBytes"], placeholder: "Size in bytes", - label: "Queue flow resume capacity:", + label: "Flow resume threshold (bytes):", name: "queue.flowResumeSizeBytes", }); } }, { name: "connection.sessionCountLimit", + groupName: "Global Connection Defaults", createWidget: function(brokerData) { return new dijit.form.NumberSpinner({ @@ -315,7 +347,7 @@ define(["dojo/_base/xhr", value: brokerData["connection.sessionCountLimit"], smallDelta: 1, constraints: {min:1,max:65535,places:0, pattern: "#####"}, - label: "Connection session limit:", + label: "Maximum number of sessions:", name: "connection.sessionCountLimit" }); } @@ -329,36 +361,13 @@ define(["dojo/_base/xhr", required: false, value: brokerData["connection.heartBeatDelay"], placeholder: "Time in ms", - label: "Heart beat delay:", + label: "Heart beat delay (ms):", name: "connection.heartBeatDelay" }); } }, { - name: "statisticsReportingPeriod", - createWidget: function(brokerData) { - return new dijit.form.ValidationTextBox({ - trim: "true", - regexp: "[0-9]+", - invalidMessage: "Invalid value", - required: false, - value: brokerData.statisticsReportingPeriod, - placeholder: "Time in ms", - label: "Statistics reporting period:", - name: "statisticsReportingPeriod" - }); - } - }, { - name: "statisticsReportingResetEnabled", - createWidget: function(brokerData) - { - return new dijit.form.CheckBox({ - required: false, checked: brokerData.statisticsReportingResetEnabled, value: "true", - label: "Statistics reporting period enabled:", - name: "statisticsReportingResetEnabled" - }); - } - }, { name: "virtualhost.housekeepingCheckPeriod", + groupName: "Global Virtual Host defaults", createWidget: function(brokerData) { return new dijit.form.ValidationTextBox({ trim: "true", @@ -367,7 +376,7 @@ define(["dojo/_base/xhr", required: false, value: brokerData["virtualhost.housekeepingCheckPeriod"], placeholder: "Time in ms", - label: "House keeping check period:", + label: "House keeping check period (ms):", name: "virtualhost.housekeepingCheckPeriod" }); } @@ -381,7 +390,7 @@ define(["dojo/_base/xhr", required: false, value: brokerData["virtualhost.storeTransactionIdleTimeoutClose"], placeholder: "Time in ms", - label: "Idle store transaction close timeout:", + label: "Idle store transaction close timeout (ms):", name: "virtualhost.storeTransactionIdleTimeoutClose" }); } @@ -395,7 +404,7 @@ define(["dojo/_base/xhr", required: false, value: brokerData["virtualhost.storeTransactionIdleTimeoutWarn"], placeholder: "Time in ms", - label: "Idle store transaction warn timeout:", + label: "Idle store transaction warn timeout (ms):", name: "virtualhost.storeTransactionIdleTimeoutWarn" }); } @@ -409,7 +418,7 @@ define(["dojo/_base/xhr", required: false, value: brokerData["virtualhost.storeTransactionOpenTimeoutClose"], placeholder: "Time in ms", - label: "Open store transaction close timeout:", + label: "Open store transaction close timeout (ms):", name: "virtualhost.storeTransactionOpenTimeoutClose" }); } @@ -423,7 +432,7 @@ define(["dojo/_base/xhr", required: false, value: brokerData["virtualhost.storeTransactionOpenTimeoutWarn"], placeholder: "Time in ms", - label: "Open store transaction warn timeout:", + label: "Open store transaction warn timeout (ms):", name: "virtualhost.storeTransactionOpenTimeoutWarn" }); } @@ -524,7 +533,6 @@ define(["dojo/_base/xhr", util.flattenStatistics( that.brokerData); - that.showReadOnlyAttributes(); that.updateHeader(); var gridProperties = { @@ -649,6 +657,7 @@ define(["dojo/_base/xhr", BrokerUpdater.prototype.updateHeader = function() { + this.showReadOnlyAttributes(); var brokerData = this.brokerData; for(var i in this.attributes) { @@ -709,7 +718,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.managementVersion").innerHTML = brokerData.managementVersion; + dojo.byId("brokerAttribute.modelVersion").innerHTML = brokerData.managementVersion; 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/Connection.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Connection.js index 01f9a325c5..91dc52d6cf 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Connection.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Connection.js @@ -85,6 +85,7 @@ define(["dojo/_base/xhr", storeNodes(["name", "state", "durable", + "principal", "lifetimePolicy", "msgInRate", "bytesInRate", @@ -123,6 +124,7 @@ define(["dojo/_base/xhr", this.name.innerHTML = this.connectionData[ "name" ]; this.state.innerHTML = this.connectionData[ "state" ]; this.durable.innerHTML = this.connectionData[ "durable" ]; + this.principal.innerHTML = this.connectionData[ "principal" ]; this.lifetimePolicy.innerHTML = this.connectionData[ "lifetimePolicy" ]; }; diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/VirtualHost.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/VirtualHost.js index db24951921..23c164f052 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/VirtualHost.js +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/VirtualHost.js @@ -209,6 +209,7 @@ define(["dojo/_base/xhr", findNode("connections"), [ { name: "Name", field: "name", width: "150px"}, { name: "Sessions", field: "sessionCount", width: "70px"}, + { name: "User", field: "principal", width: "120px"}, { name: "Msgs In", field: "msgInRate", width: "80px"}, { name: "Bytes In", field: "bytesInRate", 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 4d1e268d4d..0c1a188cbf 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 @@ -71,7 +71,7 @@ define(["dojo/_base/xhr", { if(formValues.hasOwnProperty(propName)) { - if (propName === "type" || propName === "protocolsDefault") + if (propName == "needClientAuth" || propName == "wantClientAuth") { continue; } @@ -107,18 +107,37 @@ define(["dojo/_base/xhr", } } - var needClientAuth = dijit.byId("formAddPort.needClientAuth"); - var wantClientAuth = dijit.byId("formAddPort.wantClientAuth"); - if(!needClientAuth.disabled) + var type = dijit.byId("formAddPort.type").value; + if (type == "AMQP") { - newPort.needClientAuth = needClientAuth.checked; + 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 } - if(!wantClientAuth.disabled) + return newPort; + }; + + var toggleCertificateWidgets = function toggleCertificateWidgets(protocolType, transportType) + { + var clientAuthPanel = registry.byId("formAddPort:fieldsClientAuth"); + var display = clientAuthPanel.domNode.style.display; + if (transportType == "SSL" && protocolType == "AMQP") { - newPort.wantClientAuth = wantClientAuth.checked; + clientAuthPanel.domNode.style.display = "block"; + registry.byId("formAddPort.needClientAuth").set("disabled", false); + registry.byId("formAddPort.wantClientAuth").set("disabled", false); + } + else + { + clientAuthPanel.domNode.style.display = "none"; + registry.byId("formAddPort.needClientAuth").set("disabled", true); + registry.byId("formAddPort.wantClientAuth").set("disabled", true); + } + if (clientAuthPanel.domNode.style.display != display) + { + clientAuthPanel.resize(); } - - return newPort; }; @@ -134,6 +153,11 @@ define(["dojo/_base/xhr", dijit.byId("formAddPort.protocolsAMQP").set("disabled", isChecked); }); + registry.byId("formAddPort.transports").on("change", function(newValue){ + var protocolType = registry.byId("formAddPort.type").value; + toggleCertificateWidgets(protocolType, newValue); + }); + registry.byId("formAddPort.type").on("change", function(newValue) { var typeWidget = registry.byId("formAddPort.type"); var store = typeWidget.store; @@ -142,20 +166,8 @@ define(["dojo/_base/xhr", registry.byId("formAddPort:fields" + option.value).domNode.style.display = "none"; }); - if ("AMQP" == newValue) - { - registry.byId("formAddPort:fieldsClientAuth").domNode.style.display = "block"; - registry.byId("formAddPort.needClientAuth").set("disabled", false); - registry.byId("formAddPort.wantClientAuth").set("disabled", false); - } - else - { - registry.byId("formAddPort:fieldsClientAuth").domNode.style.display = "none"; - registry.byId("formAddPort.needClientAuth").set("checked", false); - registry.byId("formAddPort.wantClientAuth").set("checked", false); - registry.byId("formAddPort.needClientAuth").set("disabled", true); - registry.byId("formAddPort.wantClientAuth").set("disabled", true); - } + registry.byId("formAddPort.needClientAuth").set("enabled", ("AMQP" == newValue)); + registry.byId("formAddPort.wantClientAuth").set("enabled", ("AMQP" == newValue)); registry.byId("formAddPort:fields" + newValue).domNode.style.display = "block"; var defaultsAMQPProtocols = registry.byId("formAddPort.protocolsDefault"); @@ -163,20 +175,10 @@ define(["dojo/_base/xhr", var protocolsWidget = registry.byId("formAddPort.protocols" + newValue); if (protocolsWidget) { - if ("AMQP" == newValue && defaultsAMQPProtocols.checked) - { - protocolsWidget.set("disabled", true); - } - else - { - protocolsWidget.set("disabled", false); - } - } - var transportsWidget = registry.byId("formAddPort.transports"); - if (transportsWidget) - { - transportsWidget.startup(); + protocolsWidget.set("disabled", ("AMQP" == newValue && defaultsAMQPProtocols.checked)); } + var transport = registry.byId("formAddPort.transports").value; + toggleCertificateWidgets(newValue, transport); }); theForm = registry.byId("formAddPort"); @@ -289,7 +291,8 @@ define(["dojo/_base/xhr", nameField.set("disabled", true); dom.byId("formAddPort.id").value=port.id; providerWidget.set("value", port.authenticationProvider ? port.authenticationProvider : ""); - registry.byId("formAddPort.transports").set("value", port.transports ? port.transports[0] : ""); + var transportWidget = registry.byId("formAddPort.transports"); + transportWidget.set("value", port.transports ? port.transports[0] : ""); registry.byId("formAddPort.port").set("value", port.port); var protocols = port.protocols; var typeWidget = registry.byId("formAddPort.type"); @@ -299,12 +302,6 @@ define(["dojo/_base/xhr", registry.byId("formAddPort:fields" + option.value).domNode.style.display = "none"; }); - registry.byId("formAddPort.needClientAuth").set("checked", false); - registry.byId("formAddPort.wantClientAuth").set("checked", false); - registry.byId("formAddPort.needClientAuth").set("disabled", true); - registry.byId("formAddPort.wantClientAuth").set("disabled", true); - registry.byId("formAddPort:fieldsClientAuth").domNode.style.display = "none"; - // identify the type of port using first protocol specified in protocol field if provided if ( !protocols || protocols.length == 0 || protocols[0].indexOf("AMQP") == 0) { @@ -326,11 +323,8 @@ define(["dojo/_base/xhr", amqpProtocolsWidget.set("disabled", true) } - registry.byId("formAddPort.needClientAuth").set("disabled", false); - registry.byId("formAddPort.wantClientAuth").set("disabled", false); registry.byId("formAddPort.needClientAuth").set("checked", port.needClientAuth); registry.byId("formAddPort.wantClientAuth").set("checked", port.wantClientAuth); - registry.byId("formAddPort:fieldsClientAuth").domNode.style.display = "block"; } else if (protocols[0].indexOf("RMI") != -1) { @@ -348,6 +342,8 @@ define(["dojo/_base/xhr", } registry.byId("formAddPort:fields" + typeWidget.value).domNode.style.display = "block"; typeWidget.set("disabled", true); + + toggleCertificateWidgets(typeWidget.value, transportWidget.value); registry.byId("addPort").show(); }); } 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 0cac138cb1..887ca4e736 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 @@ -37,9 +37,9 @@ <div class="formLabel-labelCell" style="float:left; width: 250px;">Broker version:</div> <div id="brokerAttribute.productVersion" style="float:left;"></div> </div> - <div id="brokerAttribute.managementVersion.container" style="clear:both"> - <div class="formLabel-labelCell" style="float:left; width: 250px;">Broker management version:</div> - <div id="brokerAttribute.managementVersion" style="float:left;"></div> + <div id="brokerAttribute.modelVersion.container" style="clear:both"> + <div class="formLabel-labelCell" style="float:left; width: 250px;">Broker model version:</div> + <div id="brokerAttribute.modelVersion" style="float:left;"></div> </div> <div id="brokerAttribute.storeType.container" style="clear:both"> <div class="formLabel-labelCell" style="float:left; width: 250px;">Broker store type:</div> @@ -72,7 +72,7 @@ <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 alias:</div> + <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"> @@ -95,75 +95,75 @@ <br/> <div data-dojo-type="dijit.TitlePane" data-dojo-props="title: 'Global Queue Defaults', open: true"> <div id="brokerAttribute.queue.alertThresholdQueueDepthMessages.container" style="clear:both"> - <div class="formLabel-labelCell" style="float:left; width: 250px;">Queue depth messages alert threshold:</div> + <div class="formLabel-labelCell" style="float:left; width: 240px;">Depth messages alert threshold:</div> <div id="brokerAttribute.queue.alertThresholdQueueDepthMessages" style="float:left;"></div> </div> <div id="brokerAttribute.queue.alertThresholdQueueDepthBytes.container" style="clear:both"> - <div class="formLabel-labelCell" style="float:left; width: 250px;">Queue depth bytes alert threshold:</div> + <div class="formLabel-labelCell" style="float:left; width: 240px;">Depth bytes alert threshold:</div> <div id="brokerAttribute.queue.alertThresholdQueueDepthBytes" style="float:left;"></div> bytes </div> <div id="brokerAttribute.queue.alertThresholdMessageAge.container" style="clear:both"> - <div class="formLabel-labelCell" style="float:left; width: 250px;">Queue message age alert threshold:</div> + <div class="formLabel-labelCell" style="float:left; width: 240px;">Message age alert threshold:</div> <div id="brokerAttribute.queue.alertThresholdMessageAge" style="float:left;"></div> ms </div> <div id="brokerAttribute.queue.alertThresholdMessageSize.container" style="clear:both"> - <div class="formLabel-labelCell" style="float:left; width: 250px;">Queue message size alert threshold:</div> + <div class="formLabel-labelCell" style="float:left; width: 240px;">Message size alert threshold:</div> <div id="brokerAttribute.queue.alertThresholdMessageSize" style="float:left;"></div> bytes </div> <div id="brokerAttribute.queue.alertRepeatGap.container" style="clear:both"> - <div class="formLabel-labelCell" style="float:left; width: 250px;">Queue alert repeat gap:</div> + <div class="formLabel-labelCell" style="float:left; width: 240px;">Alert repeat gap:</div> <div id="brokerAttribute.queue.alertRepeatGap" style="float:left;"></div> ms </div> <div id="brokerAttribute.queue.maximumDeliveryAttempts.container" style="clear:both"> - <div class="formLabel-labelCell" style="float:left; width: 250px;">Queue maximum delivery retries:</div> + <div class="formLabel-labelCell" style="float:left; width: 250px;">Maximum delivery retries:</div> <div id="brokerAttribute.queue.maximumDeliveryAttempts" style="float:left;"></div> </div> <div id="brokerAttribute.queue.deadLetterQueueEnabled.container" style="clear:both"> - <div class="formLabel-labelCell" style="float:left; width: 250px;">Dead letter queue enabled:</div> + <div class="formLabel-labelCell" style="float:left; width: 240px;">Dead letter queue enabled:</div> <div id="brokerAttribute.queue.deadLetterQueueEnabled" style="float:left;"></div> </div> <div id="brokerAttribute.queue.flowControlSizeBytes.container" style="clear:both"> - <div class="formLabel-labelCell" style="float:left; width: 250px;">Queue flow capacity:</div> + <div class="formLabel-labelCell" style="float:left; width: 240px;">Flow control threshold:</div> <div id="brokerAttribute.queue.flowControlSizeBytes" style="float:left;"></div> bytes </div> <div id="brokerAttribute.queue.flowResumeSizeBytes.container" style="clear:both"> - <div class="formLabel-labelCell" style="float:left; width: 250px;">Queue flow resume capacity:</div> + <div class="formLabel-labelCell" style="float:left; width: 240px;">Flow resume threshold:</div> <div id="brokerAttribute.queue.flowResumeSizeBytes" style="float:left;"></div> bytes </div> <div style="clear:both"></div> </div> <br/> - <div data-dojo-type="dijit.TitlePane" data-dojo-props="title: 'Global connection defaults', open: true"> + <div data-dojo-type="dijit.TitlePane" data-dojo-props="title: 'Global Connection Defaults', open: true"> <div id="brokerAttribute.connection.sessionCountLimit.container" style="clear:both"> - <div class="formLabel-labelCell" style="float:left; width: 250px;">Connection session limit:</div> + <div class="formLabel-labelCell" style="float:left; width: 240px;">Maximum number of sessions:</div> <div id="brokerAttribute.connection.sessionCountLimit" style="float:left;"></div> </div> <div id="brokerAttribute.connection.heartBeatDelay.container" style="clear:both"> - <div class="formLabel-labelCell" style="float:left; width: 250px;">Heart beat delay:</div> + <div class="formLabel-labelCell" style="float:left; width: 240px;">Heart beat delay:</div> <div id="brokerAttribute.connection.heartBeatDelay" style="float:left;"></div> ms </div> <div style="clear:both"></div> </div> <br/> - <div data-dojo-type="dijit.TitlePane" data-dojo-props="title: 'Global virtual host defaults', open: true"> + <div data-dojo-type="dijit.TitlePane" data-dojo-props="title: 'Global Virtual Host Defaults', open: true"> <div id="brokerAttribute.virtualhost.housekeepingCheckPeriod.container" style="clear:both"> - <div class="formLabel-labelCell" style="float:left; width: 250px;">House keeping check period:</div> + <div class="formLabel-labelCell" style="float:left; width: 240px;">House keeping check period:</div> <div id="brokerAttribute.virtualhost.housekeepingCheckPeriod" style="float:left;"></div>ms </div> <div id="brokerAttribute.virtualhost.storeTransactionIdleTimeoutClose.container" style="clear:both"> - <div class="formLabel-labelCell" style="float:left; width: 250px;">Idle store transaction close timeout:</div> + <div class="formLabel-labelCell" style="float:left; width: 240px;">Idle store transaction close timeout:</div> <div id="brokerAttribute.virtualhost.storeTransactionIdleTimeoutClose" style="float:left;"></div>ms </div> <div id="brokerAttribute.virtualhost.storeTransactionIdleTimeoutWarn.container" style="clear:both"> - <div class="formLabel-labelCell" style="float:left; width: 250px;">Idle store transaction warn timeout:</div> + <div class="formLabel-labelCell" style="float:left; width: 240px;">Idle store transaction warn timeout:</div> <div id="brokerAttribute.virtualhost.storeTransactionIdleTimeoutWarn" style="float:left;"></div>ms </div> <div id="brokerAttribute.virtualhost.storeTransactionOpenTimeoutClose.container" style="clear:both"> - <div class="formLabel-labelCell" style="float:left; width: 250px;">Open store transaction close timeout:</div> + <div class="formLabel-labelCell" style="float:left; width: 240px;">Open store transaction close timeout:</div> <div id="brokerAttribute.virtualhost.storeTransactionOpenTimeoutClose" style="float:left;"></div>ms </div> <div id="brokerAttribute.virtualhost.storeTransactionOpenTimeoutWarn.container" style="clear:both"> - <div class="formLabel-labelCell" style="float:left; width: 250px;">Open store transaction warn timeout:</div> + <div class="formLabel-labelCell" style="float:left; width: 240px;">Open store transaction warn timeout:</div> <div id="brokerAttribute.virtualhost.storeTransactionOpenTimeoutWarn" style="float:left;"></div>ms </div> <div style="clear:both"></div> diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/showConnection.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/showConnection.html index 84854daf47..82869004a8 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/resources/showConnection.html +++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/showConnection.html @@ -38,6 +38,8 @@ <span class="bytesOutRate" style="position:absolute; right: 3.3em"></span> <span class="bytesOutRateUnits" style="position:absolute; right: 0em; width: 3em"></span> <br/> + <span style="">User:</span><span style="position:absolute; left:6em" class="principal"></span> + <br/> <br/> <div data-dojo-type="dijit.TitlePane" data-dojo-props="title: 'Sessions'"> <div class="sessions"></div> diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java index ddda137bcc..dcae3a0eaf 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java @@ -215,6 +215,9 @@ public class Main { options.setManagementModeHttpPort(Integer.parseInt(httpPort)); } + + boolean quiesceVhosts = _commandLine.hasOption(OPTION_MM_QUIESCE_VHOST.getOpt()); + options.setManagementModeQuiesceVirtualHosts(quiesceVhosts); } setExceptionHandler(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/store/JsonConfigurationEntryStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/store/JsonConfigurationEntryStore.java index 413e9d2563..7a1db3d46d 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/store/JsonConfigurationEntryStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/store/JsonConfigurationEntryStore.java @@ -28,6 +28,10 @@ public class JsonConfigurationEntryStore extends MemoryConfigurationEntryStore initialiseStore(_storeFile, initialStore); } load(fileToURL(_storeFile)); + if(isGeneratedObjectIdDuringLoad()) + { + saveAsTree(_storeFile); + } } @Override diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/store/MemoryConfigurationEntryStore.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/store/MemoryConfigurationEntryStore.java index 5944adaa99..6931e22d63 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/store/MemoryConfigurationEntryStore.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/configuration/store/MemoryConfigurationEntryStore.java @@ -75,6 +75,8 @@ public class MemoryConfigurationEntryStore implements ConfigurationEntryStore private String _storeLocation; private UUID _rootId; + private boolean _generatedObjectIdDuringLoad; + protected MemoryConfigurationEntryStore() { _objectMapper = new ObjectMapper(); @@ -592,6 +594,8 @@ public class MemoryConfigurationEntryStore implements ConfigurationEntryStore { id = UUIDGenerator.generateBrokerChildUUID(type, name); } + + _generatedObjectIdDuringLoad = true; } else { @@ -683,4 +687,8 @@ public class MemoryConfigurationEntryStore implements ConfigurationEntryStore return array; } + protected boolean isGeneratedObjectIdDuringLoad() + { + return _generatedObjectIdDuringLoad; + } } 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 8f64cab2ec..ad0e68cee6 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 @@ -55,6 +55,12 @@ public interface Broker extends ConfiguredObject String UPDATED = "updated"; String DEFAULT_AUTHENTICATION_PROVIDER = "defaultAuthenticationProvider"; String DEFAULT_VIRTUAL_HOST = "defaultVirtualHost"; + String STATISTICS_REPORTING_PERIOD = "statisticsReportingPeriod"; + String STATISTICS_REPORTING_RESET_ENABLED = "statisticsReportingResetEnabled"; + String STORE_TYPE = "storeType"; + String STORE_VERSION = "storeVersion"; + String STORE_PATH = "storePath"; + String MODEL_VERSION = "modelVersion"; String QUEUE_ALERT_THRESHOLD_MESSAGE_AGE = "queue.alertThresholdMessageAge"; String QUEUE_ALERT_THRESHOLD_QUEUE_DEPTH_MESSAGES = "queue.alertThresholdQueueDepthMessages"; @@ -65,21 +71,16 @@ public interface Broker extends ConfiguredObject String QUEUE_FLOW_CONTROL_RESUME_SIZE_BYTES = "queue.flowResumeSizeBytes"; String QUEUE_MAXIMUM_DELIVERY_ATTEMPTS = "queue.maximumDeliveryAttempts"; String QUEUE_DEAD_LETTER_QUEUE_ENABLED = "queue.deadLetterQueueEnabled"; - String VIRTUALHOST_HOUSEKEEPING_CHECK_PERIOD = "virtualhost.housekeepingCheckPeriod"; String CONNECTION_SESSION_COUNT_LIMIT = "connection.sessionCountLimit"; String CONNECTION_HEART_BEAT_DELAY = "connection.heartBeatDelay"; - String STATISTICS_REPORTING_PERIOD = "statisticsReportingPeriod"; - String STATISTICS_REPORTING_RESET_ENABLED = "statisticsReportingResetEnabled"; - String STORE_TYPE = "storeType"; - String STORE_VERSION = "storeVersion"; - String STORE_PATH = "storePath"; - String MANAGEMENT_VERSION = "managementVersion"; + String VIRTUALHOST_HOUSEKEEPING_CHECK_PERIOD = "virtualhost.housekeepingCheckPeriod"; String VIRTUALHOST_STORE_TRANSACTION_IDLE_TIMEOUT_CLOSE = "virtualhost.storeTransactionIdleTimeoutClose"; String VIRTUALHOST_STORE_TRANSACTION_IDLE_TIMEOUT_WARN = "virtualhost.storeTransactionIdleTimeoutWarn"; String VIRTUALHOST_STORE_TRANSACTION_OPEN_TIMEOUT_CLOSE = "virtualhost.storeTransactionOpenTimeoutClose"; String VIRTUALHOST_STORE_TRANSACTION_OPEN_TIMEOUT_WARN = "virtualhost.storeTransactionOpenTimeoutWarn"; + /* * A temporary attribute to pass the path to ACL file. * TODO: It should be a part of AuthorizationProvider. @@ -142,7 +143,7 @@ public interface Broker extends ConfiguredObject STORE_TYPE, STORE_VERSION, STORE_PATH, - MANAGEMENT_VERSION, + MODEL_VERSION, VIRTUALHOST_STORE_TRANSACTION_IDLE_TIMEOUT_CLOSE, VIRTUALHOST_STORE_TRANSACTION_IDLE_TIMEOUT_WARN, VIRTUALHOST_STORE_TRANSACTION_OPEN_TIMEOUT_CLOSE, diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/Model.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/Model.java index 3244d55fe2..bf4c40815a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/Model.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/Model.java @@ -30,10 +30,10 @@ import java.util.Map; public class Model { /* - * API version for the broker management interfaces + * API version for the broker model */ - public static final int MANAGEMENT_API_MAJOR_VERSION = 1; - public static final int MANAGEMENT_API_MINOR_VERSION = 0; + public static final int MODEL_MAJOR_VERSION = 1; + public static final int MODEL_MINOR_VERSION = 0; private static final Model MODEL_INSTANCE = new Model(); diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/VirtualHost.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/VirtualHost.java index d3d55f1880..424ba825d7 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/VirtualHost.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/VirtualHost.java @@ -63,10 +63,11 @@ public interface VirtualHost extends ConfiguredObject String QUEUE_ALERT_THRESHOLD_QUEUE_DEPTH_BYTES = "queue.alertThresholdQueueDepthBytes"; String QUEUE_ALERT_THRESHOLD_QUEUE_DEPTH_MESSAGES = "queue.alertThresholdQueueDepthMessages"; String QUEUE_DEAD_LETTER_QUEUE_ENABLED = "queue.deadLetterQueueEnabled"; + String QUEUE_MAXIMUM_DELIVERY_ATTEMPTS = "queue.maximumDeliveryAttempts"; + String QUEUE_FLOW_CONTROL_SIZE_BYTES = "queue.flowControlSizeBytes"; + String QUEUE_FLOW_RESUME_SIZE_BYTES = "queue.flowResumeSizeBytes"; + String HOUSEKEEPING_CHECK_PERIOD = "housekeepingCheckPeriod"; - String MAXIMUM_DELIVERY_ATTEMPTS = "queue.maximumDeliveryAttempts"; - String QUEUE_FLOW_CONTROL_SIZE_BYTES = "queue.flowControlSizeBytes"; - String QUEUE_FLOW_RESUME_SIZE_BYTES = "queue.flowResumeSizeBytes"; String STORE_TRANSACTION_IDLE_TIMEOUT_CLOSE = "storeTransactionIdleTimeoutClose"; String STORE_TRANSACTION_IDLE_TIMEOUT_WARN = "storeTransactionIdleTimeoutWarn"; String STORE_TRANSACTION_OPEN_TIMEOUT_CLOSE = "storeTransactionOpenTimeoutClose"; @@ -101,7 +102,7 @@ public interface VirtualHost extends ConfiguredObject SUPPORTED_QUEUE_TYPES, QUEUE_DEAD_LETTER_QUEUE_ENABLED, HOUSEKEEPING_CHECK_PERIOD, - MAXIMUM_DELIVERY_ATTEMPTS, + QUEUE_MAXIMUM_DELIVERY_ATTEMPTS, QUEUE_FLOW_CONTROL_SIZE_BYTES, QUEUE_FLOW_RESUME_SIZE_BYTES, STORE_TYPE, 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 8ff0b6d9e1..20929a337a 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 @@ -32,6 +32,7 @@ import org.apache.qpid.server.model.ConfigurationChangeListener; import org.apache.qpid.server.model.ConfiguredObject; import org.apache.qpid.server.model.IllegalStateTransitionException; import org.apache.qpid.server.model.State; +import org.apache.qpid.server.configuration.IllegalConfigurationException; import org.apache.qpid.server.configuration.updater.ChangeAttributesTask; import org.apache.qpid.server.configuration.updater.ChangeStateTask; import org.apache.qpid.server.configuration.updater.CreateChildTask; @@ -40,6 +41,7 @@ import org.apache.qpid.server.configuration.updater.TaskExecutor; abstract class AbstractAdapter implements ConfiguredObject { + private static final Object ID = "id"; private final Map<String,Object> _attributes = new HashMap<String, Object>(); private final Map<Class<? extends ConfiguredObject>, ConfiguredObject> _parents = new HashMap<Class<? extends ConfiguredObject>, ConfiguredObject>(); @@ -90,9 +92,9 @@ abstract class AbstractAdapter implements ConfiguredObject public final State setDesiredState(final State currentState, final State desiredState) throws IllegalStateTransitionException, AccessControlException { - authoriseSetDesiredState(currentState, desiredState); if (_taskExecutor.isTaskExecutorThread()) { + authoriseSetDesiredState(currentState, desiredState); if (setState(currentState, desiredState)) { notifyStateChanged(currentState, desiredState); @@ -225,9 +227,9 @@ abstract class AbstractAdapter implements ConfiguredObject public Object setAttribute(final String name, final Object expected, final Object desired) throws IllegalStateException, AccessControlException, IllegalArgumentException { - authoriseSetAttribute(name, expected, desired); if (_taskExecutor.isTaskExecutorThread()) { + authoriseSetAttribute(name, expected, desired); if (changeAttribute(name, expected, desired)) { attributeSet(name, expected, desired); @@ -304,9 +306,9 @@ abstract class AbstractAdapter implements ConfiguredObject @Override public <C extends ConfiguredObject> C createChild(Class<C> childClass, Map<String, Object> attributes, ConfiguredObject... otherParents) { - authoriseCreateChild(childClass, attributes, otherParents); if (_taskExecutor.isTaskExecutorThread()) { + authoriseCreateChild(childClass, attributes, otherParents); C child = addChild(childClass, attributes, otherParents); if (child != null) { @@ -334,9 +336,9 @@ abstract class AbstractAdapter implements ConfiguredObject @Override public void setAttributes(final Map<String, Object> attributes) throws IllegalStateException, AccessControlException, IllegalArgumentException { - authoriseSetAttributes(attributes); if (getTaskExecutor().isTaskExecutorThread()) { + authoriseSetAttributes(attributes); changeAttributes(attributes); } else @@ -347,6 +349,15 @@ abstract class AbstractAdapter implements ConfiguredObject protected void changeAttributes(final Map<String, Object> attributes) { + if (attributes.containsKey(ID)) + { + UUID id = getId(); + Object idAttributeValue = attributes.get(ID); + if (idAttributeValue != null && !idAttributeValue.equals(id)) + { + throw new IllegalConfigurationException("Cannot change existing configured object id"); + } + } Collection<String> names = getAttributeNames(); for (String name : names) { @@ -381,4 +392,9 @@ abstract class AbstractAdapter implements ConfiguredObject { // allowed by default } + + protected Map<String, Object> getDefaultAttributes() + { + return _defaultAttributes; + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/AuthenticationProviderAdapter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/AuthenticationProviderAdapter.java index 594ef7520a..f788923b3a 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/AuthenticationProviderAdapter.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/AuthenticationProviderAdapter.java @@ -57,7 +57,6 @@ import org.apache.qpid.server.security.auth.UsernamePrincipal; import org.apache.qpid.server.security.auth.database.PrincipalDatabase; import org.apache.qpid.server.security.auth.manager.AuthenticationManager; import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager; -import org.apache.qpid.server.security.group.GroupPrincipalAccessor; import org.apache.qpid.server.security.SecurityManager; public abstract class AuthenticationProviderAdapter<T extends AuthenticationManager> extends AbstractAdapter implements AuthenticationProvider @@ -252,7 +251,7 @@ public abstract class AuthenticationProviderAdapter<T extends AuthenticationMana @Override public SubjectCreator getSubjectCreator() { - return new SubjectCreator(_authManager, new GroupPrincipalAccessor(_broker.getGroupProviders())); + return new SubjectCreator(_authManager, _broker.getGroupProviders()); } @Override 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 9759718ddd..e968d91e79 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 @@ -135,7 +135,7 @@ public class BrokerAdapter extends AbstractAdapter implements Broker, Configurat 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_PROFIDER_NAME = "defaultGroupProvider"; + 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 = "********"; @@ -238,13 +238,13 @@ public class BrokerAdapter extends AbstractAdapter implements Broker, Configurat { GroupManager groupManager = new FileGroupManager(groupFile); UUID groupProviderId = UUIDGenerator.generateBrokerChildUUID(GroupProvider.class.getSimpleName(), - DEFAULT_GROUP_PROFIDER_NAME); + DEFAULT_GROUP_PROVIDER_NAME); GroupProviderAdapter groupProviderAdapter = new GroupProviderAdapter(groupProviderId, groupManager, this); - _groupProviders.put(DEFAULT_GROUP_PROFIDER_NAME, groupProviderAdapter); + _groupProviders.put(DEFAULT_GROUP_PROVIDER_NAME, groupProviderAdapter); } else { - _groupProviders.remove(DEFAULT_GROUP_PROFIDER_NAME); + _groupProviders.remove(DEFAULT_GROUP_PROVIDER_NAME); } } @@ -734,9 +734,9 @@ public class BrokerAdapter extends AbstractAdapter implements Broker, Configurat } return null; } - else if (MANAGEMENT_VERSION.equals(name)) + else if (MODEL_VERSION.equals(name)) { - return Model.MANAGEMENT_API_MAJOR_VERSION + "." + Model.MANAGEMENT_API_MINOR_VERSION; + return Model.MODEL_MAJOR_VERSION + "." + Model.MODEL_MINOR_VERSION; } else if (STORE_VERSION.equals(name)) { @@ -1097,12 +1097,6 @@ public class BrokerAdapter extends AbstractAdapter implements Broker, Configurat } } } - - // the calls below are not thread safe but they should be fine in a management mode - // as there will be no user connected - // The new keystore/trustore/peerstore will be only used with new ports - // At the moment we cannot restart ports with new keystore/trustore/peerstore - if (keyStoreChanged) { createKeyStore(); @@ -1155,16 +1149,20 @@ public class BrokerAdapter extends AbstractAdapter implements Broker, Configurat } } Long queueFlowControlSize = (Long) convertedAttributes.get(QUEUE_FLOW_CONTROL_SIZE_BYTES); - if (queueFlowControlSize != null && queueFlowControlSize > 0) + Long queueFlowControlResumeSize = (Long) convertedAttributes.get(QUEUE_FLOW_CONTROL_RESUME_SIZE_BYTES); + if (queueFlowControlSize != null || queueFlowControlResumeSize != null ) { - Long queueFlowControlResumeSize = (Long) convertedAttributes.get(QUEUE_FLOW_CONTROL_RESUME_SIZE_BYTES); + if (queueFlowControlSize == null) + { + queueFlowControlSize = (Long)getAttribute(QUEUE_FLOW_CONTROL_SIZE_BYTES); + } if (queueFlowControlResumeSize == null) { - throw new IllegalConfigurationException("Flow control resume size attribute is not specified with flow control size attribute"); + queueFlowControlResumeSize = (Long)getAttribute(QUEUE_FLOW_CONTROL_RESUME_SIZE_BYTES); } - if (queueFlowControlResumeSize >= queueFlowControlSize) + if (queueFlowControlResumeSize > queueFlowControlSize) { - throw new IllegalConfigurationException("Flow control resume size should be less then flow control size"); + throw new IllegalConfigurationException("Flow resume size can't be greater than flow control size"); } } for (String attributeName : POSITIVE_NUMERIC_ATTRIBUTES) @@ -1182,9 +1180,14 @@ public class BrokerAdapter extends AbstractAdapter implements Broker, Configurat String passwordAttribute, String aliasAttribute) { String keyStoreFile = (String) convertedAttributes.get(pathAttribute); - if (keyStoreFile != null) + String password = (String) convertedAttributes.get(passwordAttribute); + String alias = aliasAttribute!= null? (String) convertedAttributes.get(aliasAttribute) : null; + if (keyStoreFile != null || password != null || alias != null) { - String password = (String) convertedAttributes.get(passwordAttribute); + if (keyStoreFile == null) + { + keyStoreFile = (String) getActualAttributes().get(pathAttribute); + } if (password == null) { password = (String) getActualAttributes().get(passwordAttribute); @@ -1200,7 +1203,10 @@ public class BrokerAdapter extends AbstractAdapter implements Broker, Configurat } if (aliasAttribute != null) { - String alias = (String) convertedAttributes.get(aliasAttribute); + if (alias == null) + { + alias = (String) getActualAttributes().get(aliasAttribute); + } if (alias != null) { Certificate cert = null; diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/GroupProviderAdapter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/GroupProviderAdapter.java index 0fa834bc28..9ad58f9670 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/GroupProviderAdapter.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/GroupProviderAdapter.java @@ -538,8 +538,6 @@ public class GroupProviderAdapter extends AbstractAdapter implements return true; } // TODO: DELETE state is ignored for now - // in case if we need to delete group provider, then we need AuthenticationProvider to be a change listener of it - // in order to remove deleted group provider from its group provider list return false; } 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 ba10816a35..4250de17a7 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 @@ -48,6 +48,7 @@ import org.apache.qpid.server.model.VirtualHostAlias; import org.apache.qpid.server.security.access.Operation; import org.apache.qpid.server.util.MapValueConverter; import org.apache.qpid.server.util.ParameterizedTypeImpl; +import org.apache.qpid.server.configuration.IllegalConfigurationException; import org.apache.qpid.server.configuration.updater.TaskExecutor; public class PortAdapter extends AbstractAdapter implements Port @@ -72,11 +73,6 @@ public class PortAdapter extends AbstractAdapter implements Port private AuthenticationProvider _authenticationProvider; private AtomicReference<State> _state; - /* - * TODO register PortAceptor as a listener. For supporting multiple - * protocols on the same port we need to introduce a special entity like - * PortAceptor which will be responsible for port binding/unbinding - */ public PortAdapter(UUID id, Broker broker, Map<String, Object> attributes, Map<String, Object> defaults, TaskExecutor taskExecutor) { super(id, defaults, MapValueConverter.convert(attributes, ATTRIBUTE_TYPES), taskExecutor); @@ -362,7 +358,67 @@ public class PortAdapter extends AbstractAdapter implements Port { throw new IllegalStateException("Cannot change attributes for an active port outside of Management Mode"); } - super.changeAttributes(MapValueConverter.convert(attributes, ATTRIBUTE_TYPES)); + Map<String, Object> converted = MapValueConverter.convert(attributes, ATTRIBUTE_TYPES); + + Map<String, Object> merged = new HashMap<String, Object>(getDefaultAttributes()); + merged.putAll(getActualAttributes()); + merged.putAll(converted); + + @SuppressWarnings("unchecked") + Collection<Transport> transports = (Collection<Transport>)merged.get(TRANSPORTS); + @SuppressWarnings("unchecked") + Collection<Protocol> protocols = (Collection<Protocol>)merged.get(PROTOCOLS); + Boolean needClientCertificate = (Boolean)merged.get(NEED_CLIENT_AUTH); + Boolean wantClientCertificate = (Boolean)merged.get(WANT_CLIENT_AUTH); + boolean requiresCertificate = (needClientCertificate != null && needClientCertificate.booleanValue()) + || (wantClientCertificate != null && wantClientCertificate.booleanValue()); + + if (transports != null && transports.contains(Transport.SSL)) + { + if (_broker.getKeyStores().isEmpty()) + { + throw new IllegalConfigurationException("Can't create port which requires SSL as the broker has no keystore configured."); + } + + if (_broker.getTrustStores().isEmpty() && requiresCertificate) + { + throw new IllegalConfigurationException("Can't create port which requests SSL client certificates as the broker has no trust/peer stores configured."); + } + } + else + { + if (requiresCertificate) + { + throw new IllegalConfigurationException("Can't create port which requests SSL client certificates but doesn't use SSL transport."); + } + } + + if (protocols != null && protocols.contains(Protocol.HTTPS) && _broker.getKeyStores().isEmpty()) + { + throw new IllegalConfigurationException("Can't create port which requires SSL as the broker has no keystore configured."); + } + + String authenticationProviderName = (String)merged.get(AUTHENTICATION_PROVIDER); + if (authenticationProviderName != null) + { + Collection<AuthenticationProvider> providers = _broker.getAuthenticationProviders(); + AuthenticationProvider provider = null; + for (AuthenticationProvider p : providers) + { + if (p.getName().equals(authenticationProviderName)) + { + provider = p; + break; + } + } + + if (provider == null) + { + throw new IllegalConfigurationException("Cannot find authentication provider with name '" + + authenticationProviderName + "'"); + } + } + super.changeAttributes(converted); } @Override 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 50bb2e2fcb..ffbd24997a 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 @@ -108,13 +108,12 @@ public class PortFactory boolean useClientAuth = (Boolean) port.getAttribute(Port.NEED_CLIENT_AUTH) || (Boolean) port.getAttribute(Port.WANT_CLIENT_AUTH); if(useClientAuth && broker.getTrustStores().isEmpty()) { - throw new IllegalConfigurationException("Cant 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 as the broker has no trust/peer stores configured."); } - boolean doesntUseSSL = port.getTransports().isEmpty() || !port.getTransports().contains(Transport.SSL); - if(useClientAuth && doesntUseSSL) + if(useClientAuth && !port.getTransports().contains(Transport.SSL)) { - throw new IllegalConfigurationException("Cant create port which requests SSL client certificates but doesnt use SSL transport."); + throw new IllegalConfigurationException("Can't create port which requests SSL client certificates but doesn't use SSL transport."); } } else @@ -136,7 +135,7 @@ public class PortFactory Collection<Protocol> portProtocols = existingPort.getProtocols(); if (portProtocols != null && portProtocols.contains(protocol)) { - throw new IllegalConfigurationException("Port for protocol " + protocol + " already exist. Only one management port per protocol can be created"); + throw new IllegalConfigurationException("Port for protocol " + protocol + " already exists. Only one management port per protocol can be created."); } } } @@ -149,7 +148,7 @@ public class PortFactory { if(broker.getKeyStores().isEmpty()) { - throw new IllegalConfigurationException("Cant create port which requires SSL as the broker has no keystore configured."); + throw new IllegalConfigurationException("Can't create port which requires SSL as the broker has no keystore configured."); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/VirtualHostAdapter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/VirtualHostAdapter.java index 09fc3a446f..2a66763272 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/VirtualHostAdapter.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/VirtualHostAdapter.java @@ -835,7 +835,7 @@ public final class VirtualHostAdapter extends AbstractAdapter implements Virtual { return _virtualHost.getConfiguration().getHousekeepingCheckPeriod(); } - else if(MAXIMUM_DELIVERY_ATTEMPTS.equals(name)) + else if(QUEUE_MAXIMUM_DELIVERY_ATTEMPTS.equals(name)) { return _virtualHost.getConfiguration().getMaxDeliveryCount(); } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SubjectCreator.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SubjectCreator.java index 8138745486..213f19dc5c 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SubjectCreator.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SubjectCreator.java @@ -21,17 +21,21 @@ package org.apache.qpid.server.security; import java.security.Principal; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; import javax.security.auth.Subject; import javax.security.sasl.SaslException; import javax.security.sasl.SaslServer; +import org.apache.qpid.server.model.GroupProvider; import org.apache.qpid.server.security.auth.AuthenticatedPrincipal; import org.apache.qpid.server.security.auth.AuthenticationResult; import org.apache.qpid.server.security.auth.AuthenticationResult.AuthenticationStatus; import org.apache.qpid.server.security.auth.SubjectAuthenticationResult; import org.apache.qpid.server.security.auth.manager.AuthenticationManager; -import org.apache.qpid.server.security.group.GroupPrincipalAccessor; /** * Creates a {@link Subject} formed by the {@link Principal}'s returned from: @@ -48,12 +52,12 @@ import org.apache.qpid.server.security.group.GroupPrincipalAccessor; public class SubjectCreator { private AuthenticationManager _authenticationManager; - private GroupPrincipalAccessor _groupAccessor; + private Collection<GroupProvider> _groupProviders; - public SubjectCreator(AuthenticationManager authenticationManager, GroupPrincipalAccessor groupAccessor) + public SubjectCreator(AuthenticationManager authenticationManager, Collection<GroupProvider> groupProviders) { _authenticationManager = authenticationManager; - _groupAccessor = groupAccessor; + _groupProviders = groupProviders; } /** @@ -112,7 +116,7 @@ public class SubjectCreator final Subject authenticationSubject = new Subject(); authenticationSubject.getPrincipals().addAll(authenticationResult.getPrincipals()); - authenticationSubject.getPrincipals().addAll(_groupAccessor.getGroupPrincipals(username)); + authenticationSubject.getPrincipals().addAll(getGroupPrincipals(username)); authenticationSubject.setReadOnly(); @@ -129,9 +133,24 @@ public class SubjectCreator Subject authenticationSubject = new Subject(); authenticationSubject.getPrincipals().add(new AuthenticatedPrincipal(username)); - authenticationSubject.getPrincipals().addAll(_groupAccessor.getGroupPrincipals(username)); + authenticationSubject.getPrincipals().addAll(getGroupPrincipals(username)); authenticationSubject.setReadOnly(); return authenticationSubject; } + + public Set<Principal> getGroupPrincipals(String username) + { + Set<Principal> principals = new HashSet<Principal>(); + for (GroupProvider groupProvider : _groupProviders) + { + Set<Principal> groups = groupProvider.getGroupPrincipalsForUser(username); + if (groups != null) + { + principals.addAll(groups); + } + } + + return Collections.unmodifiableSet(principals); + } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationManager.java index 43e0a9f64f..c503549bf2 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationManager.java @@ -31,8 +31,11 @@ public class ExternalAuthenticationManager implements AuthenticationManager { private static final String EXTERNAL = "EXTERNAL"; - ExternalAuthenticationManager() + private boolean _useFullDN = false; + + ExternalAuthenticationManager(boolean useFullDN) { + _useFullDN = useFullDN; } @Override @@ -52,7 +55,7 @@ public class ExternalAuthenticationManager implements AuthenticationManager { if(EXTERNAL.equals(mechanism)) { - return new ExternalSaslServer(externalPrincipal); + return new ExternalSaslServer(externalPrincipal, _useFullDN); } else { diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationManagerFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationManagerFactory.java index 64acfafc4a..6029674cd3 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationManagerFactory.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationManagerFactory.java @@ -19,22 +19,32 @@ */ package org.apache.qpid.server.security.auth.manager; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Map; import org.apache.qpid.server.plugin.AuthenticationManagerFactory; +import org.apache.qpid.server.util.ResourceBundleLoader; public class ExternalAuthenticationManagerFactory implements AuthenticationManagerFactory { + public static final String RESOURCE_BUNDLE = "org.apache.qpid.server.security.auth.manager.ExternalAuthenticationProviderAttributeDescriptions"; public static final String PROVIDER_TYPE = "External"; + public static final String ATTRIBUTE_USE_FULL_DN = "useFullDN"; + + public static final Collection<String> ATTRIBUTES = Collections.<String> unmodifiableList(Arrays.asList( + ATTRIBUTE_TYPE, + ATTRIBUTE_USE_FULL_DN)); @Override public AuthenticationManager createInstance(Map<String, Object> attributes) { if (attributes != null && PROVIDER_TYPE.equals(attributes.get(ATTRIBUTE_TYPE))) { - return new ExternalAuthenticationManager(); + boolean useFullDN = Boolean.valueOf(String.valueOf(attributes.get(ATTRIBUTE_USE_FULL_DN))); + + return new ExternalAuthenticationManager(useFullDN); } return null; } @@ -42,7 +52,7 @@ public class ExternalAuthenticationManagerFactory implements AuthenticationManag @Override public Collection<String> getAttributeNames() { - return Collections.<String>singletonList(ATTRIBUTE_TYPE); + return ATTRIBUTES; } @Override @@ -54,7 +64,7 @@ public class ExternalAuthenticationManagerFactory implements AuthenticationManag @Override public Map<String, String> getAttributeDescriptions() { - return null; + return ResourceBundleLoader.getResources(RESOURCE_BUNDLE); } } diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationProviderAttributeDescriptions.properties b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationProviderAttributeDescriptions.properties new file mode 100644 index 0000000000..263254e9fe --- /dev/null +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationProviderAttributeDescriptions.properties @@ -0,0 +1,19 @@ +# +# 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. + +useFullDN=Use the full DN as the Username
\ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/SimpleLDAPAuthenticationManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/SimpleLDAPAuthenticationManager.java index ee00e9850d..61cdf190b8 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/SimpleLDAPAuthenticationManager.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/SimpleLDAPAuthenticationManager.java @@ -21,7 +21,6 @@ package org.apache.qpid.server.security.auth.manager; import java.io.IOException; import java.security.Principal; -import java.util.HashMap; import java.util.Hashtable; import javax.naming.AuthenticationException; @@ -37,7 +36,6 @@ import javax.security.auth.callback.CallbackHandler; import javax.security.auth.callback.NameCallback; import javax.security.auth.callback.UnsupportedCallbackException; import javax.security.sasl.AuthorizeCallback; -import javax.security.sasl.Sasl; import javax.security.sasl.SaslException; import javax.security.sasl.SaslServer; import org.apache.log4j.Logger; @@ -45,6 +43,7 @@ import org.apache.qpid.server.security.auth.AuthenticationResult; import org.apache.qpid.server.security.auth.AuthenticationResult.AuthenticationStatus; import org.apache.qpid.server.security.auth.UsernamePrincipal; import org.apache.qpid.server.security.auth.sasl.plain.PlainPasswordCallback; +import org.apache.qpid.server.security.auth.sasl.plain.PlainSaslServer; public class SimpleLDAPAuthenticationManager implements AuthenticationManager { @@ -83,9 +82,7 @@ public class SimpleLDAPAuthenticationManager implements AuthenticationManager { if(PLAIN_MECHANISM.equals(mechanism)) { - return Sasl.createSaslServer(PLAIN_MECHANISM, "AMQP", localFQDN, - new HashMap<String, Object>(), new PlainCallbackHandler()); - + return new PlainSaslServer(new SimpleLDAPPlainCallbackHandler()); } else { @@ -214,7 +211,7 @@ public class SimpleLDAPAuthenticationManager implements AuthenticationManager } } - private class PlainCallbackHandler implements CallbackHandler + private class SimpleLDAPPlainCallbackHandler implements CallbackHandler { @Override diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/external/ExternalSaslServer.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/external/ExternalSaslServer.java index 9c2bca2d0b..509442b14b 100644 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/external/ExternalSaslServer.java +++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/external/ExternalSaslServer.java @@ -19,19 +19,27 @@ package org.apache.qpid.server.security.auth.sasl.external; import java.security.Principal; + +import javax.security.auth.x500.X500Principal; import javax.security.sasl.SaslException; import javax.security.sasl.SaslServer; +import org.apache.log4j.Logger; +import org.apache.qpid.server.security.auth.UsernamePrincipal; public class ExternalSaslServer implements SaslServer { + private static final Logger LOGGER = Logger.getLogger(ExternalSaslServer.class); + public static final String MECHANISM = "EXTERNAL"; private boolean _complete = false; private final Principal _externalPrincipal; + private boolean _useFullDN = false; - public ExternalSaslServer(Principal externalPrincipal) + public ExternalSaslServer(Principal externalPrincipal, boolean useFullDN) { + _useFullDN = useFullDN; _externalPrincipal = externalPrincipal; } @@ -77,6 +85,83 @@ public class ExternalSaslServer implements SaslServer public Principal getAuthenticatedPrincipal() { - return _externalPrincipal; + if (_externalPrincipal instanceof X500Principal && !_useFullDN) + { + // Construct username as <CN>@<DC1>.<DC2>.<DC3>....<DCN> + + String username; + String dn = ((X500Principal) _externalPrincipal).getName(X500Principal.RFC2253); + + if(LOGGER.isDebugEnabled()) + { + LOGGER.debug("Parsing username from Principal DN: " + dn); + } + + if (dn.contains("CN=")) + { + username = dn.substring(dn.indexOf("CN=") + 3, (dn.indexOf(",", dn.indexOf("CN=")) != -1) ? dn.indexOf(",", dn.indexOf("CN=")) : dn.length()); + + if (username.isEmpty()) + { + // CN is empty => Cannot construct username => Authentication failed => return null + if(LOGGER.isDebugEnabled()) + { + LOGGER.debug("CN value was empty in Principal name, unable to construct username"); + } + return null; + } + else + { + if (dn.contains("DC=")) + { + int start = 0; + String dc = ""; + + while (dn.indexOf("DC=", start) != -1) + { + int dcStart = dn.indexOf("DC=", start) + 3; + int dcEnd = (dn.indexOf(",", dn.indexOf("DC=", start)) != -1) ? dn.indexOf(",", dn.indexOf("DC=", start)) : dn.length(); + + if (dc.isEmpty()) + { + dc = dn.substring(dcStart, dcEnd); + } + else + { + dc = dc.concat(".").concat(dn.substring(dcStart, dcEnd)); + } + + start = dn.indexOf("DC=", start) + 1; + } + + username = username.concat("@").concat(dc); + } + } + + if(LOGGER.isDebugEnabled()) + { + LOGGER.debug("Constructing Principal with username: " + username); + } + return new UsernamePrincipal(username); + } + else + { + // No CN => Cannot construct username => Authentication failed => return null + if(LOGGER.isDebugEnabled()) + { + LOGGER.debug("No CN= present in DN, unable to construct username"); + } + return null; + } + } + else + { + if(LOGGER.isDebugEnabled()) + { + LOGGER.debug("Using external Principal: " + _externalPrincipal); + } + + return _externalPrincipal; + } } }
\ No newline at end of file diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/group/GroupPrincipalAccessor.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/group/GroupPrincipalAccessor.java deleted file mode 100644 index 1b8cdc91bc..0000000000 --- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/group/GroupPrincipalAccessor.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.qpid.server.security.group; - -import java.security.Principal; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; - -import org.apache.qpid.server.model.GroupProvider; - -public class GroupPrincipalAccessor -{ - private final Collection<GroupProvider> _groupProviders; - - public GroupPrincipalAccessor(Collection<GroupProvider> groupProviders) - { - _groupProviders = groupProviders; - } - - public Set<Principal> getGroupPrincipals(String username) - { - Set<Principal> principals = new HashSet<Principal>(); - for (GroupProvider groupProvider : _groupProviders) - { - Set<Principal> groups = groupProvider.getGroupPrincipalsForUser(username); - if (groups != null) - { - principals.addAll(groups); - } - } - - return Collections.unmodifiableSet(principals); - } -} 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 5d9cfea709..a9303c264e 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 @@ -151,7 +151,7 @@ public class PortFactoryTest extends QpidTestCase } } - public void testCreateAmqpPortUsingSsslSucceedsWithKeyStore() + public void testCreateAmqpPortUsingSslSucceedsWithKeyStore() { when(_broker.getKeyStores()).thenReturn(Collections.singleton(_keyStore)); diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/security/SubjectCreatorTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/SubjectCreatorTest.java index b1bc9bea68..9edd345360 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/security/SubjectCreatorTest.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/SubjectCreatorTest.java @@ -23,19 +23,21 @@ import static org.mockito.Mockito.when; import java.security.Principal; import java.util.Arrays; +import java.util.Collections; import java.util.HashSet; +import java.util.Set; import javax.security.auth.Subject; import javax.security.sasl.SaslServer; import junit.framework.TestCase; +import org.apache.qpid.server.model.GroupProvider; import org.apache.qpid.server.security.auth.AuthenticatedPrincipal; import org.apache.qpid.server.security.auth.AuthenticationResult; import org.apache.qpid.server.security.auth.AuthenticationResult.AuthenticationStatus; import org.apache.qpid.server.security.auth.SubjectAuthenticationResult; import org.apache.qpid.server.security.auth.manager.AuthenticationManager; -import org.apache.qpid.server.security.group.GroupPrincipalAccessor; public class SubjectCreatorTest extends TestCase { @@ -43,13 +45,15 @@ public class SubjectCreatorTest extends TestCase private static final String PASSWORD = "password"; private AuthenticationManager _authenticationManager = mock(AuthenticationManager.class); - private GroupPrincipalAccessor _groupPrincipalAccessor = mock(GroupPrincipalAccessor.class); - private SubjectCreator _subjectCreator = new SubjectCreator(_authenticationManager, _groupPrincipalAccessor); + + private GroupProvider _groupManager1 = mock(GroupProvider.class); + private GroupProvider _groupManager2 = mock(GroupProvider.class); private Principal _userPrincipal = mock(Principal.class); private Principal _group1 = mock(Principal.class); private Principal _group2 = mock(Principal.class); + private SubjectCreator _subjectCreator; private AuthenticationResult _authenticationResult; private SaslServer _testSaslServer = mock(SaslServer.class); private byte[] _saslResponseBytes = PASSWORD.getBytes(); @@ -57,11 +61,12 @@ public class SubjectCreatorTest extends TestCase @Override public void setUp() { + when(_groupManager1.getGroupPrincipalsForUser(USERNAME)).thenReturn(Collections.singleton(_group1)); + when(_groupManager2.getGroupPrincipalsForUser(USERNAME)).thenReturn(Collections.singleton(_group2)); + + _subjectCreator = new SubjectCreator(_authenticationManager, new HashSet<GroupProvider>(Arrays.asList(_groupManager1, _groupManager2))); _authenticationResult = new AuthenticationResult(_userPrincipal); when(_authenticationManager.authenticate(USERNAME, PASSWORD)).thenReturn(_authenticationResult); - - when(_groupPrincipalAccessor.getGroupPrincipals(USERNAME)) - .thenReturn(new HashSet<Principal>(Arrays.asList(_group1, _group2))); } public void testAuthenticateUsernameAndPasswordReturnsSubjectWithUserAndGroupPrincipals() @@ -135,4 +140,30 @@ public class SubjectCreatorTest extends TestCase assertSame(expectedStatus, subjectAuthenticationResult.getStatus()); assertNull(subjectAuthenticationResult.getSubject()); } + + public void testGetGroupPrincipals() + { + getAndAssertGroupPrincipals(_group1, _group2); + } + + public void testGetGroupPrincipalsWhenAGroupManagerReturnsNull() + { + when(_groupManager1.getGroupPrincipalsForUser(USERNAME)).thenReturn(null); + + getAndAssertGroupPrincipals(_group2); + } + + public void testGetGroupPrincipalsWhenAGroupManagerReturnsEmptySet() + { + when(_groupManager2.getGroupPrincipalsForUser(USERNAME)).thenReturn(new HashSet<Principal>()); + + getAndAssertGroupPrincipals(_group1); + } + + private void getAndAssertGroupPrincipals(Principal... expectedGroups) + { + Set<Principal> actualGroupPrincipals = _subjectCreator.getGroupPrincipals(USERNAME); + Set<Principal> expectedGroupPrincipals = new HashSet<Principal>(Arrays.asList(expectedGroups)); + assertEquals(expectedGroupPrincipals, actualGroupPrincipals); + } } diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationManagerTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationManagerTest.java index a66d73c47d..a5d087593a 100644 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationManagerTest.java +++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationManagerTest.java @@ -25,11 +25,13 @@ import javax.security.sasl.SaslException; import javax.security.sasl.SaslServer; import org.apache.qpid.server.security.auth.AuthenticationResult; +import org.apache.qpid.server.security.auth.UsernamePrincipal; import org.apache.qpid.test.utils.QpidTestCase; public class ExternalAuthenticationManagerTest extends QpidTestCase { - private AuthenticationManager _manager = new ExternalAuthenticationManager(); + private AuthenticationManager _manager = new ExternalAuthenticationManager(false); + private AuthenticationManager _managerUsingFullDN = new ExternalAuthenticationManager(true); public void testGetMechanisms() throws Exception { @@ -38,13 +40,23 @@ public class ExternalAuthenticationManagerTest extends QpidTestCase public void testCreateSaslServer() throws Exception { - SaslServer server = _manager.createSaslServer("EXTERNAL", "example.example.com", null); + createSaslServerTestImpl(_manager); + } + + public void testCreateSaslServerUsingFullDN() throws Exception + { + createSaslServerTestImpl(_managerUsingFullDN); + } + + public void createSaslServerTestImpl(AuthenticationManager manager) throws Exception + { + SaslServer server = manager.createSaslServer("EXTERNAL", "example.example.com", null); assertEquals("Sasl Server mechanism name is not as expected", "EXTERNAL", server.getMechanismName()); try { - server = _manager.createSaslServer("PLAIN", "example.example.com", null); + server = manager.createSaslServer("PLAIN", "example.example.com", null); fail("Expected creating SaslServer with incorrect mechanism to throw an exception"); } catch (SaslException e) @@ -53,12 +65,16 @@ public class ExternalAuthenticationManagerTest extends QpidTestCase } } - public void testAuthenticate() throws Exception + /** + * Test behaviour of the authentication when the useFullDN attribute is set true + * and the username is taken directly as the externally supplied Principal + */ + public void testAuthenticateWithFullDN() throws Exception { X500Principal principal = new X500Principal("CN=person, DC=example, DC=com"); - SaslServer saslServer = _manager.createSaslServer("EXTERNAL", "example.example.com", principal); + SaslServer saslServer = _managerUsingFullDN.createSaslServer("EXTERNAL", "example.example.com", principal); - AuthenticationResult result = _manager.authenticate(saslServer, new byte[0]); + AuthenticationResult result = _managerUsingFullDN.authenticate(saslServer, new byte[0]); assertNotNull(result); assertEquals("Expected authentication to be successful", AuthenticationResult.AuthenticationStatus.SUCCESS, @@ -66,15 +82,102 @@ public class ExternalAuthenticationManagerTest extends QpidTestCase assertOnlyContainsWrapped(principal, result.getPrincipals()); + saslServer = _managerUsingFullDN.createSaslServer("EXTERNAL", "example.example.com", null); + result = _managerUsingFullDN.authenticate(saslServer, new byte[0]); + + assertNotNull(result); + assertEquals("Expected authentication to be unsuccessful", + AuthenticationResult.AuthenticationStatus.ERROR, + result.getStatus()); + } + + /** + * Test behaviour of the authentication when parsing the username from + * the Principals DN as <CN>@<DC1>.<DC2>.<DC3>....<DCN> + */ + public void testAuthenticateWithUsernameBasedOnCNAndDC() throws Exception + { + X500Principal principal; + SaslServer saslServer; + AuthenticationResult result; + UsernamePrincipal expectedPrincipal; + + // DN contains only CN + principal = new X500Principal("CN=person"); + expectedPrincipal = new UsernamePrincipal("person"); + saslServer = _manager.createSaslServer("EXTERNAL", "example.example.com", principal); + + result = _manager.authenticate(saslServer, new byte[0]); + assertNotNull(result); + assertEquals("Expected authentication to be successful", + AuthenticationResult.AuthenticationStatus.SUCCESS, + result.getStatus()); + assertOnlyContainsWrapped(expectedPrincipal, result.getPrincipals()); + + // Null princial saslServer = _manager.createSaslServer("EXTERNAL", "example.example.com", null); result = _manager.authenticate(saslServer, new byte[0]); assertNotNull(result); - assertEquals("Expected authentication to be unsuccessful", - AuthenticationResult.AuthenticationStatus.ERROR, - result.getStatus()); + assertEquals("Expected authentication to be unsuccessful", + AuthenticationResult.AuthenticationStatus.ERROR, + result.getStatus()); - } + // DN doesn't contain CN + principal = new X500Principal("DC=example, DC=com, O=My Company Ltd, L=Newbury, ST=Berkshire, C=GB"); + saslServer = _manager.createSaslServer("EXTERNAL", "example.example.com", principal); + result = _manager.authenticate(saslServer, new byte[0]); + assertNotNull(result); + assertEquals("Expected authentication to be unsuccessful", + AuthenticationResult.AuthenticationStatus.ERROR, + result.getStatus()); + + // DN contains empty CN + principal = new X500Principal("CN=, DC=example, DC=com, O=My Company Ltd, L=Newbury, ST=Berkshire, C=GB"); + saslServer = _manager.createSaslServer("EXTERNAL", "example.example.com", principal); + result = _manager.authenticate(saslServer, new byte[0]); + + assertNotNull(result); + assertEquals("Expected authentication to be unsuccessful", + AuthenticationResult.AuthenticationStatus.ERROR, + result.getStatus()); + + // DN contains CN and DC + principal = new X500Principal("CN=person, DC=example, DC=com"); + expectedPrincipal = new UsernamePrincipal("person@example.com"); + saslServer = _manager.createSaslServer("EXTERNAL", "example.example.com", principal); + + result = _manager.authenticate(saslServer, new byte[0]); + assertNotNull(result); + assertEquals("Expected authentication to be successful", + AuthenticationResult.AuthenticationStatus.SUCCESS, + result.getStatus()); + assertOnlyContainsWrapped(expectedPrincipal, result.getPrincipals()); + + // DN contains CN and DC and other components + principal = new X500Principal("CN=person, DC=example, DC=com, O=My Company Ltd, L=Newbury, ST=Berkshire, C=GB"); + expectedPrincipal = new UsernamePrincipal("person@example.com"); + saslServer = _manager.createSaslServer("EXTERNAL", "example.example.com", principal); + + result = _manager.authenticate(saslServer, new byte[0]); + assertNotNull(result); + assertEquals("Expected authentication to be successful", + AuthenticationResult.AuthenticationStatus.SUCCESS, + result.getStatus()); + assertOnlyContainsWrapped(expectedPrincipal, result.getPrincipals()); + + // DN contains CN and DC and other components + principal = new X500Principal("CN=person, O=My Company Ltd, L=Newbury, ST=Berkshire, C=GB"); + expectedPrincipal = new UsernamePrincipal("person"); + saslServer = _manager.createSaslServer("EXTERNAL", "example.example.com", principal); + + result = _manager.authenticate(saslServer, new byte[0]); + assertNotNull(result); + assertEquals("Expected authentication to be successful", + AuthenticationResult.AuthenticationStatus.SUCCESS, + result.getStatus()); + assertOnlyContainsWrapped(expectedPrincipal, result.getPrincipals()); + } } diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/security/group/GroupPrincipalAccessorTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/group/GroupPrincipalAccessorTest.java deleted file mode 100644 index e58a1a01f8..0000000000 --- a/qpid/java/broker/src/test/java/org/apache/qpid/server/security/group/GroupPrincipalAccessorTest.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.qpid.server.security.group; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import java.security.Principal; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; - -import junit.framework.TestCase; - -import org.apache.qpid.server.model.GroupProvider; - -public class GroupPrincipalAccessorTest extends TestCase -{ - private static final String USERNAME = "username"; - - private GroupProvider _groupManager1 = mock(GroupProvider.class); - private GroupProvider _groupManager2 = mock(GroupProvider.class); - - private Principal _group1 = mock(Principal.class); - private Principal _group2 = mock(Principal.class); - - @Override - public void setUp() - { - when(_groupManager1.getGroupPrincipalsForUser(USERNAME)).thenReturn(Collections.singleton(_group1)); - when(_groupManager2.getGroupPrincipalsForUser(USERNAME)).thenReturn(Collections.singleton(_group2)); - } - - public void testGetGroupPrincipals() - { - getAndAssertGroupPrincipals(_group1, _group2); - } - - public void testGetGroupPrincipalsWhenAGroupManagerReturnsNull() - { - when(_groupManager1.getGroupPrincipalsForUser(USERNAME)).thenReturn(null); - - getAndAssertGroupPrincipals(_group2); - } - - public void testGetGroupPrincipalsWhenAGroupManagerReturnsEmptySet() - { - when(_groupManager2.getGroupPrincipalsForUser(USERNAME)).thenReturn(new HashSet<Principal>()); - - getAndAssertGroupPrincipals(_group1); - } - - private void getAndAssertGroupPrincipals(Principal... expectedGroups) - { - GroupPrincipalAccessor groupPrincipalAccessor = new GroupPrincipalAccessor(Arrays.asList(_groupManager1, _groupManager2)); - - Set<Principal> actualGroupPrincipals = groupPrincipalAccessor.getGroupPrincipals(USERNAME); - - Set<Principal> expectedGroupPrincipals = new HashSet<Principal>(Arrays.asList(expectedGroups)); - - assertEquals(expectedGroupPrincipals, actualGroupPrincipals); - } -} diff --git a/qpid/java/build.deps b/qpid/java/build.deps index 416ca090ef..b53ac55b6d 100644 --- a/qpid/java/build.deps +++ b/qpid/java/build.deps @@ -104,7 +104,7 @@ jca.libs=${geronimo-j2ee} ${geronimo-jta} ${geronimo-jms} ${geronimo-openejb} ${ jca.test.libs=${test.libs} # optional bdbstore module deps -bdb-je=lib/bdbstore/je-5.0.58.jar +bdb-je=lib/bdbstore/je-5.0.73.jar bdbstore.libs=${bdb-je} bdbstore.test.libs=${test.libs} diff --git a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQTopic.java b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQTopic.java index 51b6c7e478..96cd209447 100644 --- a/qpid/java/client/src/main/java/org/apache/qpid/client/AMQTopic.java +++ b/qpid/java/client/src/main/java/org/apache/qpid/client/AMQTopic.java @@ -20,6 +20,7 @@ */ package org.apache.qpid.client; +import org.apache.qpid.client.AMQDestination.DestSyntax; import org.apache.qpid.exchange.ExchangeDefaults; import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.messaging.Address; @@ -216,13 +217,27 @@ public class AMQTopic extends AMQDestination implements Topic public boolean equals(Object o) { - return (o instanceof AMQTopic) + if (getDestSyntax() == DestSyntax.ADDR) + { + return super.equals(o); + } + else + { + return (o instanceof AMQTopic) && ((AMQTopic)o).getExchangeName().equals(getExchangeName()) && ((AMQTopic)o).getRoutingKey().equals(getRoutingKey()); + } } public int hashCode() { - return getExchangeName().hashCode() + getRoutingKey().hashCode(); + if (getDestSyntax() == DestSyntax.ADDR) + { + return super.hashCode(); + } + else + { + return getExchangeName().hashCode() + getRoutingKey().hashCode(); + } } } diff --git a/qpid/java/client/src/test/java/org/apache/qpid/client/AMQDestinationTest.java b/qpid/java/client/src/test/java/org/apache/qpid/client/AMQDestinationTest.java index e034fa5b3f..f46623ad3b 100644 --- a/qpid/java/client/src/test/java/org/apache/qpid/client/AMQDestinationTest.java +++ b/qpid/java/client/src/test/java/org/apache/qpid/client/AMQDestinationTest.java @@ -24,12 +24,12 @@ import junit.framework.TestCase; public class AMQDestinationTest extends TestCase { - public void testEqaulsAndHashCodeForAddressBasedDestinations() throws Exception + public void testEqualsAndHashCodeForAddressBasedDestinations() throws Exception { AMQDestination dest = new AMQQueue("ADDR:Foo; {node :{type:queue}}"); AMQDestination dest1 = new AMQTopic("ADDR:Foo; {node :{type:topic}}"); - AMQDestination dest2 = new AMQQueue( - "ADDR:Foo; {create:always,node :{type:queue}}"); + AMQDestination dest10 = new AMQTopic("ADDR:Foo; {node :{type:topic}, link:{name:my-topic}}"); + AMQDestination dest2 = new AMQQueue("ADDR:Foo; {create:always,node :{type:queue}}"); String bUrl = "BURL:direct://amq.direct/test-route/Foo?routingkey='Foo'"; AMQDestination dest3 = new AMQQueue(bUrl); @@ -37,14 +37,30 @@ public class AMQDestinationTest extends TestCase assertFalse(dest.equals(dest1)); assertTrue(dest.equals(dest2)); assertFalse(dest.equals(dest3)); + assertTrue(dest1.equals(dest10)); assertTrue(dest.hashCode() == dest.hashCode()); assertTrue(dest.hashCode() != dest1.hashCode()); assertTrue(dest.hashCode() == dest2.hashCode()); assertTrue(dest.hashCode() != dest3.hashCode()); + assertTrue(dest1.hashCode() == dest10.hashCode()); AMQDestination dest4 = new AMQQueue("ADDR:Foo/Bar; {node :{type:queue}}"); AMQDestination dest5 = new AMQQueue("ADDR:Foo/Bar2; {node :{type:queue}}"); + assertFalse(dest4.equals(dest5)); assertTrue(dest4.hashCode() != dest5.hashCode()); + + AMQDestination dest6 = new AMQAnyDestination("ADDR:Foo; {node :{type:queue}}"); + AMQDestination dest7 = new AMQAnyDestination("ADDR:Foo; {create: always, node :{type:queue}, link:{capacity: 10}}"); + AMQDestination dest8 = new AMQAnyDestination("ADDR:Foo; {create: always, link:{capacity: 10}}"); + AMQDestination dest9 = new AMQAnyDestination("ADDR:Foo/bar"); + assertTrue(dest6.equals(dest7)); + assertFalse(dest6.equals(dest8)); //dest8 type unknown, could be a topic + assertFalse(dest7.equals(dest8)); //dest8 type unknown, could be a topic + assertFalse(dest6.equals(dest9)); + assertTrue(dest6.hashCode() == dest7.hashCode()); + assertTrue(dest6.hashCode() != dest8.hashCode()); + assertTrue(dest7.hashCode() != dest8.hashCode()); + assertTrue(dest6.hashCode() != dest9.hashCode()); } } diff --git a/qpid/java/ivy.retrieve.xml b/qpid/java/ivy.retrieve.xml index 5998a3e78e..4c8e935aca 100644 --- a/qpid/java/ivy.retrieve.xml +++ b/qpid/java/ivy.retrieve.xml @@ -75,7 +75,7 @@ <!-- The following are optional dependencies, for modules providing optional functionlity or for use in optional build/test steps. Their optional status is usually indicative of licences which are not compatible with the Apache Licence --> - <dependency org="com.sleepycat" name="je" rev="5.0.58" transitive="false" conf="bdbje"/> + <dependency org="com.sleepycat" name="je" rev="5.0.73" transitive="false" conf="bdbje"/> <dependency org="jfree" name="jfreechart" rev="1.0.13" transitive="false" conf="jfree"/> <dependency org="jfree" name="jcommon" rev="1.0.16" transitive="false" conf="jfree"/> <dependency org="net.sourceforge.csvjdbc" name="csvjdbc" rev="1.0.8" transitive="false" conf="csvjdbc"/> diff --git a/qpid/java/lib/poms/je-5.0.58.xml b/qpid/java/lib/poms/je-5.0.73.xml index d71a935dff..d55c4ec14f 100644 --- a/qpid/java/lib/poms/je-5.0.58.xml +++ b/qpid/java/lib/poms/je-5.0.73.xml @@ -18,5 +18,5 @@ <dep> <groupId>com.sleepycat</groupId> <artifactId>je</artifactId> - <version>5.0.58</version> + <version>5.0.73</version> </dep> 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 e9e6f93ab6..2e051d93dd 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 @@ -21,13 +21,14 @@ package org.apache.qpid.server.security.auth.manager; import static org.apache.qpid.test.utils.TestSSLConstants.KEYSTORE; -import static org.apache.qpid.test.utils.TestSSLConstants.UNTRUSTED_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.Collections; import java.util.HashMap; +import java.util.List; import java.util.Map; import javax.jms.Connection; @@ -35,11 +36,13 @@ import javax.jms.JMSException; import org.apache.commons.configuration.ConfigurationException; import org.apache.qpid.client.AMQConnectionURL; +import org.apache.qpid.management.common.mbeans.ManagedConnection; 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.plugin.AuthenticationManagerFactory; +import org.apache.qpid.test.utils.JMXTestUtils; import org.apache.qpid.test.utils.QpidBrokerTestCase; import org.apache.qpid.test.utils.TestBrokerConfiguration; @@ -193,9 +196,78 @@ public class ExternalAuthenticationTest extends QpidBrokerTestCase } } + /** + * Tests the creation of usernames when EXTERNAL authentication is used. + * The username should be created as CN@DC1.DC2...DCn by default. + */ + public void testExternalAuthenticationManagerUsernameAsCN() throws Exception + { + JMXTestUtils jmxUtils = new JMXTestUtils(this); + jmxUtils.setUp(); + + setCommonBrokerSSLProperties(true); + getBrokerConfiguration().setObjectAttribute(TestBrokerConfiguration.ENTRY_NAME_SSL_PORT, Port.AUTHENTICATION_PROVIDER, TestBrokerConfiguration.ENTRY_NAME_EXTERNAL_PROVIDER); + + super.setUp(); + + setClientKeystoreProperties(); + setClientTrustoreProperties(); + + try + { + getExternalSSLConnection(false); + } + catch (JMSException e) + { + fail("Should be able to create a connection to the SSL port: " + e.getMessage()); + } + + // Getting the used username using JMX + jmxUtils.open(); + List<ManagedConnection> connections = jmxUtils.getManagedConnections("test"); + assertNotNull("Connections are null", connections); + assertEquals("Unexpected number of connections", 1, connections.size()); + assertEquals("Wrong authorized ID", "app2@acme.org", connections.get(0).getAuthorizedId()); + } + + /** + * Tests the creation of usernames when EXTERNAL authentication is used. + * The username should be created as full DN when the useFullDN option is used. + */ + public void testExternalAuthenticationManagerUsernameAsDN() throws Exception + { + JMXTestUtils jmxUtils = new JMXTestUtils(this); + jmxUtils.setUp(); + + setCommonBrokerSSLProperties(true); + getBrokerConfiguration().setObjectAttribute(TestBrokerConfiguration.ENTRY_NAME_SSL_PORT, Port.AUTHENTICATION_PROVIDER, TestBrokerConfiguration.ENTRY_NAME_EXTERNAL_PROVIDER); + getBrokerConfiguration().setObjectAttribute(TestBrokerConfiguration.ENTRY_NAME_EXTERNAL_PROVIDER, ExternalAuthenticationManagerFactory.ATTRIBUTE_USE_FULL_DN, "true"); + + super.setUp(); + + setClientKeystoreProperties(); + setClientTrustoreProperties(); + + try + { + getExternalSSLConnection(false); + } + catch (JMSException e) + { + fail("Should be able to create a connection to the SSL port: " + e.getMessage()); + } + + // Getting the used username using JMX + jmxUtils.open(); + List<ManagedConnection> connections = jmxUtils.getManagedConnections("test"); + assertNotNull("Connections are null", connections); + assertEquals("Unexpected number of connections", 1, connections.size()); + assertEquals("Wrong authorized ID", "CN=app2@acme.org,OU=art,O=acme,L=Toronto,ST=ON,C=CA", connections.get(0).getAuthorizedId()); + } + private Connection getExternalSSLConnection(boolean includeUserNameAndPassword) throws Exception { - String url = "amqp://%s@test/?brokerlist='tcp://localhost:%s?ssl='true'&sasl_mechs='EXTERNAL''"; + String url = "amqp://%s@test/?brokerlist='tcp://localhost:%s?ssl='true'&sasl_mechs='EXTERNAL'&ssl_cert_alias='app2''"; if (includeUserNameAndPassword) { url = String.format(url, "guest:guest", String.valueOf(QpidBrokerTestCase.DEFAULT_SSL_PORT)); diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/AuthenticationProviderRestTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/AuthenticationProviderRestTest.java index 4ba2069dfd..09408572d7 100644 --- a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/AuthenticationProviderRestTest.java +++ b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/AuthenticationProviderRestTest.java @@ -24,6 +24,7 @@ import java.io.File; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.UUID; import org.apache.qpid.server.model.AuthenticationProvider; import org.apache.qpid.server.model.LifetimePolicy; @@ -90,6 +91,22 @@ public class AuthenticationProviderRestTest extends QpidRestTestCase assertProvider(false, AnonymousAuthenticationManagerFactory.PROVIDER_TYPE, provider); } + public void testUpdateAuthenticationProviderIdFails() throws Exception + { + String providerName = "test-provider"; + Map<String, Object> attributes = new HashMap<String, Object>(); + attributes.put(AuthenticationProvider.NAME, providerName); + attributes.put(AuthenticationProvider.TYPE, AnonymousAuthenticationManagerFactory.PROVIDER_TYPE); + + int responseCode = getRestTestHelper().submitRequest("/rest/authenticationprovider/" + providerName, "PUT", attributes); + assertEquals("Unexpected response code", 201, responseCode); + + attributes.put(AuthenticationProvider.ID, UUID.randomUUID()); + + responseCode = getRestTestHelper().submitRequest("/rest/authenticationprovider/" + providerName, "PUT", attributes); + assertEquals("Update with new ID should fail", 409, responseCode); + } + public void testDeleteOfDefaultAuthenticationProviderFails() throws Exception { String providerName = TestBrokerConfiguration.ENTRY_NAME_AUTHENTICATION_PROVIDER; 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 f8a7a9855f..1497d740dc 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 @@ -21,16 +21,20 @@ package org.apache.qpid.systest.rest; import java.net.URLDecoder; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; 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; +import org.apache.qpid.server.model.Transport; import org.apache.qpid.server.plugin.AuthenticationManagerFactory; import org.apache.qpid.server.security.auth.manager.AnonymousAuthenticationManagerFactory; import org.apache.qpid.test.utils.TestBrokerConfiguration; @@ -159,8 +163,7 @@ public class PortRestTest extends QpidRestTestCase responseCode = getRestTestHelper().submitRequest("/rest/port/" + portName, "PUT", attributes); assertEquals("Port cannot be updated in non management mode", 409, responseCode); - stopBroker(); - startBroker(DEFAULT_PORT, true); + restartBrokerInManagementMode(); responseCode = getRestTestHelper().submitRequest("/rest/port/" + portName, "PUT", attributes); assertEquals("Port should be allwed to update in a management mode", 200, responseCode); @@ -193,4 +196,133 @@ public class PortRestTest extends QpidRestTestCase port = getRestTestHelper().getJsonAsSingletonList("/rest/port/" + TestBrokerConfiguration.ENTRY_NAME_AMQP_PORT); assertEquals("Port has been changed", portValue, port.get(Port.PORT)); } + + public void testUpdatePortTransportFromTCPToSSLWhenKeystoreIsConfigured() throws Exception + { + restartBrokerInManagementMode(); + + String portName = TestBrokerConfiguration.ENTRY_NAME_AMQP_PORT; + Map<String, Object> attributes = new HashMap<String, Object>(); + attributes.put(Port.NAME, portName); + attributes.put(Port.TRANSPORTS, Collections.singleton(Transport.SSL)); + + int responseCode = getRestTestHelper().submitRequest("/rest/port/" + portName, "PUT", attributes); + assertEquals("Transport has not been changed to SSL " , 200, responseCode); + + restartBroker(); + + Map<String, Object> port = getRestTestHelper().getJsonAsSingletonList("/rest/port/" + portName); + + @SuppressWarnings("unchecked") + 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)); + } + + public void testUpdateTransportFromTCPToSSLWithoutKeystoreConfiguredFails() throws Exception + { + getBrokerConfiguration().setBrokerAttribute(Broker.KEY_STORE_PATH, null); + getBrokerConfiguration().setSaved(false); + restartBrokerInManagementMode(); + + String portName = TestBrokerConfiguration.ENTRY_NAME_AMQP_PORT; + Map<String, Object> attributes = new HashMap<String, Object>(); + attributes.put(Port.NAME, portName); + attributes.put(Port.TRANSPORTS, Collections.singleton(Transport.SSL)); + + int responseCode = getRestTestHelper().submitRequest("/rest/port/" + portName, "PUT", attributes); + assertEquals("Creation of SSL port without keystore should fail", 409, responseCode); + } + + public void testUpdateWantNeedClientAuth() throws Exception + { + String portName = TestBrokerConfiguration.ENTRY_NAME_SSL_PORT; + Map<String, Object> attributes = new HashMap<String, Object>(); + attributes.put(Port.NAME, portName); + attributes.put(Port.PORT, DEFAULT_SSL_PORT); + attributes.put(Port.TRANSPORTS, Collections.singleton(Transport.SSL)); + + int responseCode = getRestTestHelper().submitRequest("/rest/port/" + portName, "PUT", attributes); + assertEquals("SSL port was not added", 201, responseCode); + + restartBrokerInManagementMode(); + + attributes.put(Port.NEED_CLIENT_AUTH, true); + attributes.put(Port.WANT_CLIENT_AUTH, true); + + responseCode = getRestTestHelper().submitRequest("/rest/port/" + portName, "PUT", attributes); + assertEquals("Attributes for need/want client auth are not set", 200, responseCode); + + restartBroker(); + 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)); + + restartBrokerInManagementMode(); + + attributes = new HashMap<String, Object>(); + attributes.put(Port.NAME, portName); + 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); + + attributes = new HashMap<String, Object>(); + attributes.put(Port.NAME, portName); + attributes.put(Port.TRANSPORTS, Collections.singleton(Transport.TCP)); + attributes.put(Port.NEED_CLIENT_AUTH, false); + attributes.put(Port.WANT_CLIENT_AUTH, false); + + responseCode = getRestTestHelper().submitRequest("/rest/port/" + portName, "PUT", attributes); + assertEquals("Should be able to change transport to TCP ", 200, responseCode); + + restartBroker(); + port = getRestTestHelper().getJsonAsSingletonList("/rest/port/" + portName); + assertEquals("Unexpected " + Port.NEED_CLIENT_AUTH, false, port.get(Port.NEED_CLIENT_AUTH)); + assertEquals("Unexpected " + Port.WANT_CLIENT_AUTH, false, port.get(Port.WANT_CLIENT_AUTH)); + + @SuppressWarnings("unchecked") + Collection<String> transports = (Collection<String>) port.get(Port.TRANSPORTS); + assertEquals("Unexpected auth provider", new HashSet<String>(Arrays.asList(Transport.TCP.name())), + new HashSet<String>(transports)); + } + + public void testUpdateSettingWantNeedCertificateFailsForNonSSLPort() throws Exception + { + restartBrokerInManagementMode(); + + String portName = TestBrokerConfiguration.ENTRY_NAME_AMQP_PORT; + Map<String, Object> attributes = new HashMap<String, Object>(); + attributes.put(Port.NAME, portName); + attributes.put(Port.NEED_CLIENT_AUTH, true); + int responseCode = getRestTestHelper().submitRequest("/rest/port/" + portName, "PUT", attributes); + assertEquals("Unexpected response when trying to set 'needClientAuth' on non-SSL port", 409, responseCode); + + attributes = new HashMap<String, Object>(); + attributes.put(Port.NAME, portName); + attributes.put(Port.WANT_CLIENT_AUTH, true); + responseCode = getRestTestHelper().submitRequest("/rest/port/" + portName, "PUT", attributes); + assertEquals("Unexpected response when trying to set 'wantClientAuth' on non-SSL port", 409, responseCode); + } + + public void testUpdatePortAuthenticationProvider() throws Exception + { + restartBrokerInManagementMode(); + + String portName = TestBrokerConfiguration.ENTRY_NAME_AMQP_PORT; + Map<String, Object> attributes = new HashMap<String, Object>(); + attributes.put(Port.NAME, portName); + attributes.put(Port.AUTHENTICATION_PROVIDER, "non-existing"); + int responseCode = getRestTestHelper().submitRequest("/rest/port/" + portName, "PUT", attributes); + assertEquals("Unexpected response when trying to change auth provider to non-existing one", 409, responseCode); + + attributes = new HashMap<String, Object>(); + attributes.put(Port.NAME, portName); + attributes.put(Port.AUTHENTICATION_PROVIDER, ANONYMOUS_AUTHENTICATION_PROVIDER); + responseCode = getRestTestHelper().submitRequest("/rest/port/" + portName, "PUT", attributes); + assertEquals("Unexpected response when trying to change auth provider to existing one", 200, responseCode); + + Map<String, Object> port = getRestTestHelper().getJsonAsSingletonList("/rest/port/" + portName); + assertEquals("Unexpected auth provider", ANONYMOUS_AUTHENTICATION_PROVIDER, port.get(Port.AUTHENTICATION_PROVIDER)); + } } |