You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by or...@apache.org on 2017/07/18 16:24:30 UTC
[2/2] qpid-broker-j git commit: QPID-7789: Refactor SASL web
authentication
QPID-7789: Refactor SASL web authentication
Project: http://git-wip-us.apache.org/repos/asf/qpid-broker-j/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-broker-j/commit/6bde48c5
Tree: http://git-wip-us.apache.org/repos/asf/qpid-broker-j/tree/6bde48c5
Diff: http://git-wip-us.apache.org/repos/asf/qpid-broker-j/diff/6bde48c5
Branch: refs/heads/master
Commit: 6bde48c519847a14dcdbeba33b9eb200f3a089cd
Parents: ec1bd82
Author: Alex Rudyy <or...@apache.org>
Authored: Tue Jul 18 17:24:03 2017 +0100
Committer: Alex Rudyy <or...@apache.org>
Committed: Tue Jul 18 17:24:03 2017 +0100
----------------------------------------------------------------------
.../management/plugin/HttpManagement.java | 1 -
.../auth/UsernamePasswordInteractiveLogin.java | 4 +-
.../plugin/servlet/rest/SaslServlet.java | 2 +-
.../main/java/resources/common/LoginForm.html | 47 ++++
.../src/main/java/resources/css/common.css | 6 +-
.../src/main/java/resources/index.html | 144 +++++-----
.../resources/js/qpid/common/ConsoleHelper.js | 78 ++++--
.../java/resources/js/qpid/common/LoginForm.js | 130 +++++++++
.../resources/js/qpid/management/Management.js | 42 +--
.../resources/js/qpid/sasl/Authenticator.js | 251 +++++++++++------
.../js/qpid/sasl/CredentialBasedSaslClient.js | 102 +------
.../java/resources/js/qpid/sasl/SaslClient.js | 35 ++-
.../js/qpid/sasl/ScramShaSaslClient.js | 244 +++++++++++++++++
.../resources/js/qpid/sasl/ShaSaslClient.js | 269 -------------------
.../js/qpid/sasl/UsernamePasswordProvider.js | 41 ---
.../js/qpid/sasl/cram-md5-hex/SaslClient.js | 11 +-
.../js/qpid/sasl/cram-md5/SaslClient.js | 55 ++--
.../resources/js/qpid/sasl/plain/SaslClient.js | 31 +--
.../js/qpid/sasl/scram-sha-1/SaslClient.js | 6 +-
.../js/qpid/sasl/scram-sha-256/SaslClient.js | 6 +-
.../src/main/java/resources/login.html | 178 ------------
.../src/main/java/resources/logout.html | 2 +-
22 files changed, 821 insertions(+), 864 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/qpid-broker-j/blob/6bde48c5/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagement.java
----------------------------------------------------------------------
diff --git a/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagement.java b/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagement.java
index da99593..4b50431 100644
--- a/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagement.java
+++ b/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagement.java
@@ -345,7 +345,6 @@ public class HttpManagement extends AbstractPluginAdapter<HttpManagement> implem
root.addFilter(restAuthorizationFilter, "/apidocs/*", EnumSet.of(DispatcherType.REQUEST));
root.addFilter(restAuthorizationFilter, "/service/*", EnumSet.of(DispatcherType.REQUEST));
- root.addFilter(new FilterHolder(new RedirectingFilter()), "/index.html", EnumSet.of(DispatcherType.REQUEST));
root.addFilter(new FilterHolder(new RedirectingFilter()), "/", EnumSet.of(DispatcherType.REQUEST));
if (_serveUncompressedDojo)
{
http://git-wip-us.apache.org/repos/asf/qpid-broker-j/blob/6bde48c5/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/auth/UsernamePasswordInteractiveLogin.java
----------------------------------------------------------------------
diff --git a/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/auth/UsernamePasswordInteractiveLogin.java b/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/auth/UsernamePasswordInteractiveLogin.java
index ccc9b1a..8894aee 100644
--- a/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/auth/UsernamePasswordInteractiveLogin.java
+++ b/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/auth/UsernamePasswordInteractiveLogin.java
@@ -34,11 +34,11 @@ import org.apache.qpid.server.security.auth.manager.UsernamePasswordAuthenticati
@PluggableService
public class UsernamePasswordInteractiveLogin implements HttpRequestInteractiveAuthenticator
{
- // TODO: When we refactor web management and adopt web fragments, move login.html (and logout.html)
+ // TODO: When we refactor web management and adopt web fragments, move logout.html
// to WEB-INF/ and dispatch (forward) to them, rather than using a client side redirect.
// This would keep the login/logout pages private and inaccessible to the user when using auth providers
// such as Ouath2.
- private static final String DEFAULT_LOGIN_URL = "/login.html";
+ private static final String DEFAULT_LOGIN_URL = "/index.html";
private static final AuthenticationHandler REDIRECT_HANDLER = new AuthenticationHandler()
{
http://git-wip-us.apache.org/repos/asf/qpid-broker-j/blob/6bde48c5/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/SaslServlet.java
----------------------------------------------------------------------
diff --git a/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/SaslServlet.java b/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/SaslServlet.java
index 66c4457..98736d7 100644
--- a/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/SaslServlet.java
+++ b/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/SaslServlet.java
@@ -256,7 +256,7 @@ public class SaslServlet extends AbstractServlet
HttpManagementUtil.saveAuthorisedSubject(request, subject);
if(challenge != null && challenge.length != 0)
{
- outputObject.put("challenge", DatatypeConverter.printBase64Binary(challenge));
+ outputObject.put("additionalData", DatatypeConverter.printBase64Binary(challenge));
}
responseStatus = HttpServletResponse.SC_OK;
}
http://git-wip-us.apache.org/repos/asf/qpid-broker-j/blob/6bde48c5/broker-plugins/management-http/src/main/java/resources/common/LoginForm.html
----------------------------------------------------------------------
diff --git a/broker-plugins/management-http/src/main/java/resources/common/LoginForm.html b/broker-plugins/management-http/src/main/java/resources/common/LoginForm.html
new file mode 100644
index 0000000..b550eca
--- /dev/null
+++ b/broker-plugins/management-http/src/main/java/resources/common/LoginForm.html
@@ -0,0 +1,47 @@
+<!--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you under the Apache License, Version 2.0 (the
+ ~ "License"); you may not use this file except in compliance
+ ~ with the License. You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing,
+ ~ software distributed under the License is distributed on an
+ ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ ~ KIND, either express or implied. See the License for the
+ ~ specific language governing permissions and limitations
+ ~ under the License.
+ -->
+<div>
+ <div data-dojo-type="dijit.TitlePane" data-dojo-props="title:'Login', toggleable: false">
+ <div data-dojo-type="dijit.form.Form" method="POST" data-dojo-attach-point="formWidget">
+ <div class="dijitDialogPaneContentArea">
+ <div class="errorDialogErrorPrimary">
+ <span data-dojo-attach-point="statusCodeNode"></span> <span
+ data-dojo-attach-point="errorMessageNode"></span>
+ </div>
+ <div data-dojo-type="dojox.layout.TableContainer"
+ data-dojo-props="cols:1,labelWidth:'100',showLabels:true,orientation:'horiz',customClass:'formLabel'">
+ <div data-dojo-type="dijit.form.ValidationTextBox"
+ data-dojo-attach-point="usernameWidget"
+ data-dojo-props="label:'User name:',required:true, intermediateChanges:true"></div>
+ <div data-dojo-type="dijit.form.ValidationTextBox"
+ type="password"
+ data-dojo-attach-point="passwordWidget"
+ data-dojo-props="label:'Password:',required:true, intermediateChanges:true"></div>
+ </div>
+ </div>
+ <div class="dijitDialogPaneActionBar qpidDialogPaneActionBar">
+ <button data-dojo-type="dijit.form.Button"
+ type="submit"
+ data-dojo-attach-point="loginButtonWidget"
+ data-dojo-props="disabled:true">Login
+ </button>
+ </div>
+ </div>
+ </div>
+</div>
http://git-wip-us.apache.org/repos/asf/qpid-broker-j/blob/6bde48c5/broker-plugins/management-http/src/main/java/resources/css/common.css
----------------------------------------------------------------------
diff --git a/broker-plugins/management-http/src/main/java/resources/css/common.css b/broker-plugins/management-http/src/main/java/resources/css/common.css
index 8dad0ef..f26cd5c 100644
--- a/broker-plugins/management-http/src/main/java/resources/css/common.css
+++ b/broker-plugins/management-http/src/main/java/resources/css/common.css
@@ -86,7 +86,7 @@ h1 {
font-size:1.5em;
}
-#header {
+.header {
height:100px;
background:url("../images/qpid-logo.png") left center no-repeat;
float: left;
@@ -749,3 +749,7 @@ td.advancedSearchField, col.autoWidth {
{
background-image: url("../dojo/dijit/themes/claro/images/loadingAnimation.gif");
}
+.loadingBar
+{
+ text-align: center;
+}
http://git-wip-us.apache.org/repos/asf/qpid-broker-j/blob/6bde48c5/broker-plugins/management-http/src/main/java/resources/index.html
----------------------------------------------------------------------
diff --git a/broker-plugins/management-http/src/main/java/resources/index.html b/broker-plugins/management-http/src/main/java/resources/index.html
index 43f5c43..2ac76f3 100644
--- a/broker-plugins/management-http/src/main/java/resources/index.html
+++ b/broker-plugins/management-http/src/main/java/resources/index.html
@@ -91,6 +91,7 @@
"qpid/common/ConsoleHelper",
"qpid/management/treeView",
"qpid/management/controller",
+ "qpid/common/LoginForm",
"dijit/layout/BorderContainer",
"dijit/layout/TabContainer",
"dijit/layout/ContentPane",
@@ -114,80 +115,102 @@
</head>
<body class="claro qpid">
-<div id="pageLayout" data-dojo-type="dijit.layout.BorderContainer"
- data-dojo-props="design: 'headline', gutters: false, isLayoutContainer:false">
- <div data-dojo-type="dijit.layout.ContentPane" data-dojo-props="region:'top', isLayoutContainer:false">
- <div id="header"></div>
- <div class="alignRight">
- <div id="login" class="hidden" data-dojo-type="dijit/Toolbar">
- <div data-dojo-type="dijit/form/DropDownButton" data-dojo-props="iconClass: 'dijitIconChart'">
- <span>Dashboard</span>
- <div data-dojo-type="dijit/Menu">
- <div data-dojo-type="dijit/MenuItem"
- data-dojo-props="onClick: function(e){qpidManagementHelper.showDashboardCreateDialog(e);}">
- Create
- </div>
- <div data-dojo-type="dijit/MenuItem"
- data-dojo-props="onClick: function(e){qpidManagementHelper.showDashboardBrowser(e);}">
- Browse
+ <div id="loadingLayout">
+ <div class="header"></div>
+ <div class="clear"></div>
+ <div class="loadingBar">
+ <div>Please wait.... <span class="loading"> </span> </div>
+ </div>
+
+ </div>
+
+ <div id="loginLayout" class="dijitHidden">
+ <div class="header"></div>
+ <div class="clear"></div>
+ <div style="width:350px; margin-left: auto; margin-right: auto;" id="loginForm"
+ data-dojo-type="qpid.common.LoginForm"></div>
+ <div qpid-type="footer"></div>
+ </div>
+
+ <div id="pageLayout" class="dijitHidden"
+ data-dojo-type="dijit.layout.BorderContainer"
+ data-dojo-props="design: 'headline', gutters: false, isLayoutContainer:false">
+ <div data-dojo-type="dijit.layout.ContentPane" data-dojo-props="region:'top', isLayoutContainer:false">
+ <div class="header"></div>
+ <div class="alignRight">
+ <div id="login" class="hidden" data-dojo-type="dijit/Toolbar">
+ <div data-dojo-type="dijit/form/DropDownButton" data-dojo-props="iconClass: 'dijitIconChart'">
+ <span>Dashboard</span>
+ <div data-dojo-type="dijit/Menu">
+ <div data-dojo-type="dijit/MenuItem"
+ data-dojo-props="onClick: function(e){qpidManagementHelper.showDashboardCreateDialog(e);}">
+ Create
+ </div>
+ <div data-dojo-type="dijit/MenuItem"
+ data-dojo-props="onClick: function(e){qpidManagementHelper.showDashboardBrowser(e);}">
+ Browse
+ </div>
</div>
</div>
- </div>
- <div data-dojo-type="dijit/form/DropDownButton" data-dojo-props="iconClass: 'dijitIconApplication'">
- <span>Query</span>
- <div data-dojo-type="dijit/Menu">
- <div data-dojo-type="dijit/MenuItem"
- data-dojo-props="onClick: function(e){qpidManagementHelper.showQueryCreateDialog(e);}">
- Create
- </div>
- <div data-dojo-type="dijit/MenuItem"
- data-dojo-props="onClick: function(e){qpidManagementHelper.showQueryBrowser(e);}">
- Browse
+ <div data-dojo-type="dijit/form/DropDownButton"
+ data-dojo-props="iconClass: 'dijitIconApplication'">
+ <span>Query</span>
+ <div data-dojo-type="dijit/Menu">
+ <div data-dojo-type="dijit/MenuItem"
+ data-dojo-props="onClick: function(e){qpidManagementHelper.showQueryCreateDialog(e);}">
+ Create
+ </div>
+ <div data-dojo-type="dijit/MenuItem"
+ data-dojo-props="onClick: function(e){qpidManagementHelper.showQueryBrowser(e);}">
+ Browse
+ </div>
</div>
</div>
- </div>
- <div data-dojo-type="dijit/form/DropDownButton"
- data-dojo-props="iconClass: 'dijitIconDocuments'">
- <span>Documentation</span>
- <div data-dojo-type="dijit/Menu">
- <div data-dojo-type="dijit/MenuItem"
- data-dojo-props="onClick: function(){qpidManagementHelper.showAPI();}">API documentation
- </div>
- <div data-dojo-type="dijit/MenuItem"
- data-dojo-props="onClick: function(){qpidManagementHelper.showDocumentation();}">
- Broker Manual
+ <div data-dojo-type="dijit/form/DropDownButton"
+ data-dojo-props="iconClass: 'dijitIconDocuments'">
+ <span>Documentation</span>
+ <div data-dojo-type="dijit/Menu">
+ <div data-dojo-type="dijit/MenuItem"
+ data-dojo-props="onClick: function(){qpidManagementHelper.showAPI();}">API
+ documentation
+ </div>
+ <div data-dojo-type="dijit/MenuItem"
+ data-dojo-props="onClick: function(){qpidManagementHelper.showDocumentation();}">
+ Broker Manual
+ </div>
</div>
</div>
- </div>
- <span data-dojo-type="dijit/ToolbarSeparator"></span>
- <div id="authenticatedUserControls" data-dojo-type="dijit/form/DropDownButton"
- data-dojo-props="iconClass: 'userIcon ui-icon'">
- <div data-dojo-type="dijit/Menu">
- <div data-dojo-type="dijit/MenuItem"
- data-dojo-props="onClick: function(){qpidManagementHelper.logout();}">Log out
- </div>
- <div data-dojo-type="dijit/MenuItem"
- data-dojo-props="onClick: function(){qpidManagementHelper.showPreferencesDialog();}">
- Preferences
+ <span data-dojo-type="dijit/ToolbarSeparator"></span>
+ <div id="authenticatedUserControls" data-dojo-type="dijit/form/DropDownButton"
+ data-dojo-props="iconClass: 'userIcon ui-icon'">
+ <div data-dojo-type="dijit/Menu">
+ <div data-dojo-type="dijit/MenuItem"
+ data-dojo-props="onClick: function(){qpidManagementHelper.logout();}">Log out
+ </div>
+ <div data-dojo-type="dijit/MenuItem"
+ data-dojo-props="onClick: function(){qpidManagementHelper.showPreferencesDialog();}">
+ Preferences
+ </div>
</div>
</div>
</div>
</div>
</div>
- </div>
- <div id="tree" data-dojo-type="dijit.layout.ContentPane"
- data-dojo-props="region:'leading', splitter: true, isLayoutContainer:false">
- <div qpid-type="treeView"></div>
- </div>
- <div id="main" data-dojo-type="dijit.layout.ContentPane"
- data-dojo-props="region:'center', gutters: true, isLayoutContainer:false">
- <div id="managedViews" data-dojo-type="dijit.layout.TabContainer"
- data-dojo-props="tabPosition: 'top', doLayout:false, isLayoutContainer:false">
+ <div id="tree" data-dojo-type="dijit.layout.ContentPane"
+ data-dojo-props="region:'leading', splitter: true, isLayoutContainer:false">
+ <div qpid-type="treeView"></div>
</div>
- <div>
- <div qpid-type="footer"></div>
+ <div id="main" data-dojo-type="dijit.layout.ContentPane"
+ data-dojo-props="region:'center', gutters: true, isLayoutContainer:false">
+ <div id="managedViews" data-dojo-type="dijit.layout.TabContainer"
+ data-dojo-props="tabPosition: 'top', doLayout:false, isLayoutContainer:false">
+ </div>
+ <div>
+ <div qpid-type="footer"></div>
+ </div>
</div>
</div>
+
<div class="dijitHidden">
<div data-dojo-type="dijit.Dialog" data-dojo-props="title: 'Error'" id="errorDialog">
<div>
@@ -215,7 +238,6 @@
</div>
</div>
</div>
-</div>
</body>
</html>
http://git-wip-us.apache.org/repos/asf/qpid-broker-j/blob/6bde48c5/broker-plugins/management-http/src/main/java/resources/js/qpid/common/ConsoleHelper.js
----------------------------------------------------------------------
diff --git a/broker-plugins/management-http/src/main/java/resources/js/qpid/common/ConsoleHelper.js b/broker-plugins/management-http/src/main/java/resources/js/qpid/common/ConsoleHelper.js
index 7b97a9f..2bb3cf0 100644
--- a/broker-plugins/management-http/src/main/java/resources/js/qpid/common/ConsoleHelper.js
+++ b/broker-plugins/management-http/src/main/java/resources/js/qpid/common/ConsoleHelper.js
@@ -26,7 +26,9 @@ define(["dojo/query",
"qpid/management/Management",
"qpid/common/util",
"dijit/Dialog",
- "dojo/domReady!"], function (query, registry, entities, Structure, updater, Management, util, Dialog)
+ "dojo/dom-class",
+ "dojo/dom",
+ "dojo/domReady!"], function (query, registry, entities, Structure, updater, Management, util, Dialog, domClass, dom)
{
var documentationUrl = null;
@@ -177,42 +179,64 @@ define(["dojo/query",
this.management = new Management("", util.xhrErrorHandler);
this.structure = new Structure();
- var that = this;
var management = this.management;
var structure = this.structure;
- var authenticationSuccessCallback = function (data)
+ var authenticationSuccessCallback = function ()
{
- if (data.user)
+ domClass.add(dom.byId("loginLayout"), "dijitHidden");
+
+ var pageLagoutContainer = registry.byId("pageLayout");
+ domClass.remove(pageLagoutContainer.domNode, "dijitHidden")
+ pageLagoutContainer.resize();
+
+ var controlButton = registry.byId("authenticatedUserControls");
+ registry.byId("login").domNode.style.display = "inline";
+ management.init(function ()
{
- var controlButton = registry.byId("authenticatedUserControls");
- registry.byId("login").domNode.style.display = "inline";
- management.init(function ()
+ updater.registerUpdateIntervalListener(management.userPreferences);
+ var treeView = new TreeView(management, query('div[qpid-type="treeView"]')[0]);
+ controller.init(management, structure, treeView);
+ dijit.Tooltip.defaultPosition =
+ ["after-centered",
+ "below-centered"];
+ if (controlButton)
{
- updater.registerUpdateIntervalListener(management.userPreferences);
- var treeView = new TreeView(management, query('div[qpid-type="treeView"]')[0]);
- controller.init(management, structure, treeView);
- dijit.Tooltip.defaultPosition =
- ["after-centered",
- "below-centered"];
- if (controlButton)
- {
- var userName = management.getAuthenticatedUser();
- controlButton.set("label", util.toFriendlyUserName(userName));
- controlButton.set("title", userName);
- controlButton.domNode.style.display = '';
- }
- });
+ var userName = management.getAuthenticatedUser();
+ controlButton.set("label", util.toFriendlyUserName(userName));
+ controlButton.set("title", userName);
+ controlButton.domNode.style.display = '';
+ }
+ });
+ };
+
+ this.management.getSaslStatus().then(function (data)
+ {
+ domClass.add(dom.byId("loadingLayout"), "dijitHidden");
+ if (data.user)
+ {
+ authenticationSuccessCallback();
}
else
{
- alert("User identifier is not found! Re-authenticate!");
- that.logout();
+ domClass.remove(dom.byId("loginLayout"), "dijitHidden");
+ var loginForm = registry.byId("loginForm");
+ loginForm.on("submit", function (credentials)
+ {
+ management.authenticate(data.mechanisms, credentials)
+ .then(function ()
+ {
+ loginForm.hide();
+ authenticationSuccessCallback();
+ },
+ function (error)
+ {
+ loginForm.onError(error);
+ });
+ });
+ loginForm.show();
}
- };
-
- management.authenticate()
- .then(authenticationSuccessCallback);
+ }, util.xhrErrorHandler);
},
logout: function ()
{
http://git-wip-us.apache.org/repos/asf/qpid-broker-j/blob/6bde48c5/broker-plugins/management-http/src/main/java/resources/js/qpid/common/LoginForm.js
----------------------------------------------------------------------
diff --git a/broker-plugins/management-http/src/main/java/resources/js/qpid/common/LoginForm.js b/broker-plugins/management-http/src/main/java/resources/js/qpid/common/LoginForm.js
new file mode 100644
index 0000000..5b383d0
--- /dev/null
+++ b/broker-plugins/management-http/src/main/java/resources/js/qpid/common/LoginForm.js
@@ -0,0 +1,130 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+define(["dojo/_base/declare",
+ "dojo/_base/lang",
+ "dojo/dom-class",
+ "dojo/text!common/LoginForm.html",
+ "dojo/Evented",
+ "dojox/html/entities",
+ "dijit/_WidgetBase",
+ "dijit/_TemplatedMixin",
+ "dijit/_WidgetsInTemplateMixin",
+ "dijit/TitlePane",
+ "dijit/form/Form",
+ "dijit/form/ValidationTextBox",
+ "dijit/form/Button",
+ "dojox/layout/TableContainer",
+ "dojo/domReady!"],
+ function (declare,
+ lang,
+ domClass,
+ template,
+ Evented,
+ entities)
+ {
+
+ return declare("qpid.common.LoginForm",
+ [dijit._WidgetBase, dijit._TemplatedMixin, dijit._WidgetsInTemplateMixin, Evented],
+ {
+
+ //Strip out the apache comment header from the template html as comments unsupported.
+ templateString: template.replace(/<!--[\s\S]*?-->/g, ""),
+
+ // template fields
+ formWidget: null,
+ usernameWidget: null,
+ passwordWidget: null,
+ loginButtonWidget: null,
+ statusCodeNode: null,
+ errorMessageNode: null,
+
+ //
+
+ postCreate: function ()
+ {
+ this.inherited(arguments);
+ this._postCreate();
+ },
+ _postCreate: function ()
+ {
+ this.formWidget.on("submit", lang.hitch(this, this._onFormSubmit));
+ this.usernameWidget.on("change", lang.hitch(this, this._onCredentialChange));
+ this.passwordWidget.on("change", lang.hitch(this, this._onCredentialChange));
+ },
+ show: function()
+ {
+ domClass.remove(this.domNode, "dijitHidden");
+ },
+ hide: function()
+ {
+ domClass.add(this.domNode, "dijitHidden");
+ },
+ onError: function (error)
+ {
+ if (error.response)
+ {
+ this.statusCodeNode.innerHTML = entities.encode(String(error.response.status));
+ if (error.response.status == 401)
+ {
+ this.errorMessageNode.innerHTML = "Authentication Failed";
+ }
+ else if (error.response.status == 403)
+ {
+ this.errorMessageNode.innerHTML ="Authorization Failed";
+ }
+ else
+ {
+ this.errorMessageNode.innerHTML = entities.encode(String(error.message));
+ }
+ }
+ else
+ {
+ var message = error.message ? entities.encode(String(error.message)) : "Authentication failed";
+ this.statusCodeNode.innerHTML = "";
+ this.errorMessageNode.innerHTML = message;
+ }
+ this.usernameWidget.set("disabled", false);
+ this.passwordWidget.set("disabled", false);
+ this.formWidget.reset();
+ this.usernameWidget.focus();
+ },
+ _onFormSubmit: function (event)
+ {
+ event.preventDefault();
+ if (this.formWidget.validate())
+ {
+ var data = {username: this.usernameWidget.value, password: this.passwordWidget.value};
+ this.emit("submit", data);
+
+ this.usernameWidget.set("disabled", true);
+ this.passwordWidget.set("disabled", true);
+ this.loginButtonWidget.set("disabled", true);
+ }
+ return false;
+ },
+ _onCredentialChange: function ()
+ {
+ this.loginButtonWidget.set("disabled", !this.usernameWidget.value || !this.passwordWidget.value);
+ }
+
+ });
+ });
http://git-wip-us.apache.org/repos/asf/qpid-broker-j/blob/6bde48c5/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Management.js
----------------------------------------------------------------------
diff --git a/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Management.js b/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Management.js
index 172ec0a..4471f52 100644
--- a/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Management.js
+++ b/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Management.js
@@ -30,7 +30,7 @@ define(["dojo/_base/lang",
"qpid/common/metadata",
"qpid/common/timezone",
"qpid/management/UserPreferences"],
- function (lang, all, array, xhr, ioQuery, json, Promise, Deferred, saslAuthenticator, Metadata, Timezone, UserPreferences)
+ function (lang, all, array, xhr, ioQuery, json, Promise, Deferred, SaslAuthenticator, Metadata, Timezone, UserPreferences)
{
function shallowCopy(source, target, excludes)
@@ -571,45 +571,9 @@ define(["dojo/_base/lang",
});
};
- Management.prototype.authenticate = function (forceAuthentication)
+ Management.prototype.authenticate = function (mechanisms, credentials)
{
- var that = this;
- var deferred = new Deferred();
- var successCallback = function (data)
- {
- that.getSaslStatus()
- .then(function (saslData)
- {
- if (saslData.user)
- {
- deferred.resolve(saslData);
- }
- else
- {
- deferred.reject({
- message: "User identifier is not found!" + " Authentication failed!"
- });
- }
- }, failureCallback);
- };
- var failureCallback = function (data)
- {
- deferred.reject(data);
- };
- this.getSaslStatus()
- .then(function (data)
- {
- if (data.user && !forceAuthentication)
- {
- deferred.resolve(data);
- }
- else
- {
- saslAuthenticator.authenticate(data.mechanisms, that)
- .then(successCallback, failureCallback);
- }
- }, failureCallback);
- return deferred.promise;
+ return new SaslAuthenticator(this).authenticate(mechanisms, credentials);
};
// summary:
http://git-wip-us.apache.org/repos/asf/qpid-broker-j/blob/6bde48c5/broker-plugins/management-http/src/main/java/resources/js/qpid/sasl/Authenticator.js
----------------------------------------------------------------------
diff --git a/broker-plugins/management-http/src/main/java/resources/js/qpid/sasl/Authenticator.js b/broker-plugins/management-http/src/main/java/resources/js/qpid/sasl/Authenticator.js
index 3bba4e8..04f2c24 100644
--- a/broker-plugins/management-http/src/main/java/resources/js/qpid/sasl/Authenticator.js
+++ b/broker-plugins/management-http/src/main/java/resources/js/qpid/sasl/Authenticator.js
@@ -18,106 +18,197 @@
* under the License.
*
*/
-define(["dojo/_base/lang", "dojo/Deferred", "dojo/json"], function (lang, Deferred, json)
+define(["dojo/_base/declare",
+ "dojo/_base/lang",
+ "dojo/Deferred",
+ "dojo/json",
+ "dojo/promise/all"], function (declare, lang, Deferred, json, all)
{
-
- var loadSaslClients = function loadSaslClients(availableMechanisms, management, onLastLoaded, errorHandler)
- {
- var mechanisms = lang.clone(availableMechanisms);
- var saslClients = [];
-
- var handleMechanisms = function handleMechanisms()
+ var absentSaslClient = {};
+ return declare(null,
{
- if (mechanisms.length == 0)
+ _management: null,
+ _saslClient: null,
+ _deferred: null,
+ constructor: function (management)
{
- onLastLoaded(saslClients)
- }
- else
+ this._management = management;
+ this._deferred = new Deferred();
+ },
+ _successCallback: function (data)
{
- loadSaslClient();
- }
- }
-
- var loadSaslClient = function loadSaslClient()
- {
- var mechanism = mechanisms.shift();
- if (mechanism)
+ this._deferred.resolve(data);
+ },
+ _failureCallback: function (data)
{
- var url = "qpid/sasl/" + encodeURIComponent(mechanism.toLowerCase()) + "/SaslClient";
- management.get({
- url: "js/" + url + ".js",
- handleAs: "text",
- headers: {"Content-Type": "text/plain"}
- })
- .then(function (data)
+ this._deferred.reject(data);
+ },
+ _chooseSaslClient: function (saslClients)
+ {
+ if (saslClients.length > 0)
+ {
+ saslClients.sort(function (c1, c2)
{
- require([url], function (SaslClient)
+ if (c1 == null)
{
- try
- {
- var saslClient = new SaslClient();
- saslClients.push(saslClient);
- }
- catch (e)
- {
- console.error("Unexpected error on loading of mechanism " + mechanism + ": "
- + json.stringify(e));
- }
- finally
- {
- handleMechanisms();
- }
- });
- }, function (data)
- {
- if (data.response.status != 404)
+ return 1;
+ }
+ if (c2 == null)
{
- console.error("Unexpected error on loading mechanism " + mechanism + ": " + json.stringify(
- data));
+ return -1;
}
- handleMechanisms();
+
+ return c2.getPriority() - c1.getPriority();
});
- }
- else
+ return saslClients[0];
+ }
+ return null;
+ },
+ _loadSaslClient: function (mechanism)
{
- handleMechanisms();
- }
- }
+ var deferred = new Deferred();
+ var handle = require.on("error", lang.hitch(this, function (error)
+ {
+ handle.remove();
+ deferred.resolve(null);
+ absentSaslClient[mechanism] = true;
+ }));
- handleMechanisms();
- }
+ var url = "qpid/sasl/" + encodeURIComponent(mechanism.toLowerCase()) + "/SaslClient";
+ require([url], function (SaslClient)
+ {
+ try
+ {
+ var saslClient = new SaslClient();
+ deferred.resolve(saslClient);
+ }
+ catch (e)
+ {
+ deferred.resolve(null);
+ console.error("Unexpected error on loading of mechanism " + mechanism + ": " + e);
+ }
+ finally
+ {
+ handle.remove();
+ }
+ });
- return {
- authenticate: function (mechanisms, management)
- {
- var deferred = new Deferred();
- var successCallback = function (data)
+ return deferred.promise;
+ },
+ _authenticate: function (serverMechanisms, credentials )
{
- deferred.resolve(data);
- };
- var failureCallback = function (data)
+ var mechanisms = lang.clone(serverMechanisms);
+
+ var clients = [];
+
+ var handle = lang.hitch(this, function ()
+ {
+ if (mechanisms.length > 0)
+ {
+ var mechanism = mechanisms.shift();
+ var promise;
+ if (absentSaslClient[mechanism])
+ {
+ var deferred = new Deferred();
+ promise = deferred.promise;
+ deferred.resolve(null);
+ }
+ else
+ {
+ promise = this._loadSaslClient(mechanism);
+ }
+ promise.then(lang.hitch(this, function (client)
+ {
+ clients.push(client);
+ handle();
+ }));
+ }
+ else
+ {
+ var saslClient = this._chooseSaslClient(clients);
+
+ if (saslClient == null)
+ {
+ this._failureCallback(new Error("Authentication cannot be performed as none of"
+ + " the server's SASL mechanisms '"
+ + json.stringify(serverMechanisms)
+ + "' are supported"));
+ }
+ else
+ {
+ this._startAuthentication(saslClient, credentials);
+ }
+ }
+ });
+ handle();
+ },
+ _startAuthentication: function (saslClient, credentials)
{
- deferred.reject(data);
- };
- loadSaslClients(mechanisms, management, function (saslClients)
+ this._saslClient = saslClient;
+ this._saslClient.init(credentials)
+ .then(lang.hitch(this, function ()
+ {
+ var initialResponse;
+ try
+ {
+ initialResponse = saslClient.getInitialResponse();
+ }
+ catch (e)
+ {
+ this._failureCallback(e);
+ return;
+ }
+ var initialRequest = {
+ mechanism: saslClient.getMechanismName(),
+ response: initialResponse
+ };
+ this._management.sendSaslResponse(initialRequest)
+ .then(lang.hitch(this, this._handleChallengeOrOutcome),
+ lang.hitch(this, this._failureCallback));
+
+ }), lang.hitch(this, this._failureCallback));
+ },
+ _handleChallengeOrOutcome: function (serverResponse)
{
- if (saslClients.length > 0)
+ try
{
- saslClients.sort(function (c1, c2)
+ if (serverResponse.challenge)
{
- return c2.getPriority() - c1.getPriority();
- });
- saslClients[0].authenticate(management)
- .then(successCallback, failureCallback);
+ var response = this._saslClient.getResponse(serverResponse.challenge);
+ this._management.sendSaslResponse({
+ id: serverResponse.id,
+ response: response
+ })
+ .then(lang.hitch(this, this._handleChallengeOrOutcome),
+ lang.hitch(this, this._failureCallback));
+ }
+ else
+ {
+ if (serverResponse.additionalData)
+ {
+ this._saslClient.getResponse(serverResponse.additionalData);
+ }
+
+ if (this._saslClient.isComplete())
+ {
+ this._successCallback();
+ }
+ else
+ {
+ this._failureCallback(new Error("SASL negotiation has not been completed - cannot proceed"));
+ }
+ }
}
- else
+ catch (e)
{
- failureCallback({
- message: "No SASL client available for " + data.mechanisms
- });
+ this._failureCallback(e);
}
- }, failureCallback);
- return deferred.promise;
+ },
+ authenticate: function (mechanisms, credentials)
+ {
+ this._authenticate(mechanisms, credentials);
+ return this._deferred.promise;
+ }
}
- };
+ );
});
http://git-wip-us.apache.org/repos/asf/qpid-broker-j/blob/6bde48c5/broker-plugins/management-http/src/main/java/resources/js/qpid/sasl/CredentialBasedSaslClient.js
----------------------------------------------------------------------
diff --git a/broker-plugins/management-http/src/main/java/resources/js/qpid/sasl/CredentialBasedSaslClient.js b/broker-plugins/management-http/src/main/java/resources/js/qpid/sasl/CredentialBasedSaslClient.js
index 021b142..e37e3a1 100644
--- a/broker-plugins/management-http/src/main/java/resources/js/qpid/sasl/CredentialBasedSaslClient.js
+++ b/broker-plugins/management-http/src/main/java/resources/js/qpid/sasl/CredentialBasedSaslClient.js
@@ -18,106 +18,24 @@
*/
define(["dojo/_base/declare",
- "dojo/_base/lang",
- "dojox/encoding/base64",
- "dojo/json",
- "dojo/request/script",
- "dojox/uuid/generateRandomUuid",
"dojo/Deferred",
- "qpid/sasl/SaslClient"], function (declare, lang, base64, json, script, uuid, Deferred, SaslClient)
+ "qpid/sasl/SaslClient"], function (declare, Deferred, SaslClient)
{
return declare("qpid.sasl.CredentialBasedSaslClient", [SaslClient], {
- getResponse: function (challenge)
- {
- // summary:
- // Generates response for given challenge
- // description:
- // Handles given challenge represented as
- // JSON object and generates response in
- // JSON format.
- // Method can be called multiple times
- // for different challenges.
- // Throws exception on various errors or
- // authentication failures.
- // returns: JSON objectSa
- throw new TypeError("abstract");
- },
- isComplete: function ()
- {
- // summary:
- // Returns true when no more response generation is required.
- // description:
- // Returns true when challenge handling is complete
- // returns: boolean
- throw new TypeError("abstract");
- },
- getCredentials: function ()
+ username : null,
+ password : null,
+
+ init: function (data)
{
- // summary:
- // Returns initial credentials
- // to start authentication
- // description:
- // Provides initial credentials as Promise or
- // JSON object to start authentication process
- // returns: promise
- throw new TypeError("abstract");
+ var deferred = new Deferred();
+ this.username = data.username;
+ this.password = data.password;
+ deferred.resolve();
+ return deferred.promise;
},
toString: function ()
{
return "[object CredentialBasedSaslClient]";
- },
- authenticate: function (management)
- {
- var deferred = new Deferred();
- var successCallback = function (data)
- {
- deferred.resolve(data);
- };
- var failureCallback = function (data)
- {
- deferred.reject(data);
- };
-
- var saslClient = this;
- var processChallenge = function processChallenge(challenge)
- {
- if (saslClient.isComplete())
- {
- successCallback(true);
- return;
- }
-
- var response = null;
- try
- {
- response = saslClient.getResponse(challenge);
- }
- catch (e)
- {
- failureCallback(e);
- return;
- }
-
- if (saslClient.isComplete() && (response == null || response == undefined))
- {
- successCallback(true);
- }
- else
- {
- management.sendSaslResponse(response)
- .then(function (challenge)
- {
- processChallenge(challenge);
- });
- }
- };
-
- dojo.when(this.getCredentials())
- .then(function (data)
- {
- processChallenge(data);
- }, failureCallback);
- return deferred.promise;
}
});
});
http://git-wip-us.apache.org/repos/asf/qpid-broker-j/blob/6bde48c5/broker-plugins/management-http/src/main/java/resources/js/qpid/sasl/SaslClient.js
----------------------------------------------------------------------
diff --git a/broker-plugins/management-http/src/main/java/resources/js/qpid/sasl/SaslClient.js b/broker-plugins/management-http/src/main/java/resources/js/qpid/sasl/SaslClient.js
index 0840cb1..62c6464 100644
--- a/broker-plugins/management-http/src/main/java/resources/js/qpid/sasl/SaslClient.js
+++ b/broker-plugins/management-http/src/main/java/resources/js/qpid/sasl/SaslClient.js
@@ -36,17 +36,42 @@ define(["dojo/_base/lang"], function (lang)
// returns: string
throw new TypeError("abstract");
},
- authenticate: function (management)
+ init: function(data)
{
// summary:
- // Authenticates and invokes callback function
- // on successful authentication
+ // Initialises client with intial data including credentials.
// description:
- // Performs SASL authentication as required by algorithm
- // and returns promise
+ // Initialises client with intial data including credentials.
// returns: promise
throw new TypeError("abstract");
},
+ getInitialResponse: function()
+ {
+ // summary:
+ // Returns initial response or null if no initial response
+ // description:
+ // Returns initial response or null if no initial response
+ // returns: string
+ throw new TypeError("abstract");
+ },
+ getResponse: function (challenge)
+ {
+ // summary:
+ // Generates response for given challenge
+ // description:
+ // Generates response for given challenge
+ // returns: string
+ throw new TypeError("abstract");
+ },
+ isComplete: function ()
+ {
+ // summary:
+ // Returns true if SASL negotiation is complete
+ // description:
+ // Returns true if SASL negotiation is complete
+ // returns: boolean
+ throw new TypeError("abstract");
+ },
getPriority: function ()
{
// summary:
http://git-wip-us.apache.org/repos/asf/qpid-broker-j/blob/6bde48c5/broker-plugins/management-http/src/main/java/resources/js/qpid/sasl/ScramShaSaslClient.js
----------------------------------------------------------------------
diff --git a/broker-plugins/management-http/src/main/java/resources/js/qpid/sasl/ScramShaSaslClient.js b/broker-plugins/management-http/src/main/java/resources/js/qpid/sasl/ScramShaSaslClient.js
new file mode 100644
index 0000000..74e05c1
--- /dev/null
+++ b/broker-plugins/management-http/src/main/java/resources/js/qpid/sasl/ScramShaSaslClient.js
@@ -0,0 +1,244 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+define(["dojo/_base/declare",
+ "dojo/_base/lang",
+ "dojox/encoding/base64",
+ "dojo/json",
+ "dojo/request/script",
+ "dojo/promise/all",
+ "dojox/uuid/generateRandomUuid",
+ "dojo/Deferred",
+ "qpid/sasl/CredentialBasedSaslClient"],
+ function (declare, lang, base64, json, script, all, uuid, Deferred, SaslClient)
+ {
+
+ var toBase64 = function toBase64(input)
+ {
+ var result = [];
+ for (var i = 0; i < input.length; i++)
+ {
+ result[i] = input.charCodeAt(i);
+ }
+ return base64.encode(result)
+ };
+
+ var fromBase64 = function fromBase64(input)
+ {
+ var decoded = base64.decode(input);
+ var result = "";
+ for (var i = 0; i < decoded.length; i++)
+ {
+ result += String.fromCharCode(decoded[i]);
+ }
+ return result;
+ };
+
+ var xor = function xor(lhs, rhs)
+ {
+ var words = [];
+ for (var i = 0; i < lhs.words.length; i++)
+ {
+ words.push(lhs.words[i] ^ rhs.words[i]);
+ }
+ return CryptoJS.lib.WordArray.create(words);
+ };
+
+ var hasNonAscii = function hasNonAscii(name)
+ {
+ for (var i = 0; i < name.length; i++)
+ {
+ if (name.charCodeAt(i) > 127)
+ {
+ return true;
+ }
+ }
+ return false;
+ };
+
+ var generateSaltedPassword = function generateSaltedPassword(digest, salt, password, iterationCount)
+ {
+ var hmac = CryptoJS.algo.HMAC.create(CryptoJS.algo[digest], password);
+ hmac.update(salt);
+ hmac.update(CryptoJS.enc.Hex.parse("00000001"));
+ var result = hmac.finalize();
+ var previous = null;
+ for (var i = 1; i < iterationCount; i++)
+ {
+ hmac = CryptoJS.algo.HMAC.create(CryptoJS.algo[digest], password);
+ hmac.update(previous != null ? previous : result);
+ previous = hmac.finalize();
+ result = xor(result, previous);
+ }
+ return result;
+ };
+
+ var scriptLoadError = function scriptLoadError(error)
+ {
+ var message = "Cannot load script due to " + json.stringify(error);
+ console.error(message);
+ throw {message: message};
+ };
+
+ // hidden context scope variables
+ var digest = null;
+ var hmac = null;
+ var gs2_header = "n,,";
+
+ return declare("qpid.sasl.ShaSaslClient", [SaslClient], {
+ _state: "initial",
+ "-chains-": {
+ constructor: "manual" // disable auto-constructor invocation
+ },
+
+ constructor: function (mechanism)
+ {
+ this._mechanism = mechanism;
+ },
+ init : function()
+ {
+ var superPromise = this.inherited(arguments);
+ var deferred = new Deferred();
+ var hmacDeferred = new Deferred();
+
+ var shaName = this._mechanism.substring(6)
+ .replace('-', '')
+ .toLowerCase();
+ digest = shaName.toUpperCase();
+ hmac = "Hmac" + digest;
+
+ // loading crypto-js functionality based on mechanism
+ script.get("js/crypto-js/hmac-" + shaName + ".js")
+ .then(function ()
+ {
+ script.get("js/crypto-js/enc-base64-min.js")
+ .then(function ()
+ {
+ hmacDeferred.resolve(true);
+ }, function (error)
+ {
+ hmacDeferred.reject(error);
+ scriptLoadError(error);
+ });
+ }, function (error)
+ {
+ hmacDeferred.reject("error");
+ scriptLoadError(error);
+ });
+
+ all([superPromise, hmacDeferred.promise])
+ .then(function ()
+ {
+ deferred.resolve();
+ }, function (error)
+ {
+ deferred.reject(error);
+ });
+ return deferred.promise;
+
+ },
+ getMechanismName: function ()
+ {
+ return this._mechanism;
+ },
+ isComplete: function ()
+ {
+ return this._state == "completed";
+ },
+ getInitialResponse : function()
+ {
+ if (this._state != "initial")
+ {
+ throw new Error("Unexpected state : " + this._state);
+ }
+
+ if (!hasNonAscii(this.username))
+ {
+ var user = this.username;
+ user = user.replace(/=/g, "=3D");
+ user = user.replace(/,/g, "=2C");
+ this._clientNonce = uuid();
+ this._clientFirstMessageBare = "n=" + user + ",r=" + this._clientNonce;
+ this._state = "initiated";
+ return toBase64(gs2_header + this._clientFirstMessageBare);
+ }
+ else
+ {
+ this._state = "error";
+ throw new Error("Username '" + this.username + "' is invalid");
+ }
+ },
+ getResponse: function (challengeOrAdditionalData)
+ {
+ if (this._state == "initiated")
+ {
+ var serverFirstMessage = fromBase64(challengeOrAdditionalData);
+ var parts = serverFirstMessage.split(",");
+ var nonce = parts[0].substring(2);
+ if (!nonce.substr(0, this._clientNonce.length) == this._clientNonce)
+ {
+ this._state = "error";
+ throw new Error("Authentication error - server nonce does not start with client nonce");
+ }
+ else
+ {
+ var salt = CryptoJS.enc.Base64.parse(parts[1].substring(2));
+ var iterationCount = parts[2].substring(2);
+ var saltedPassword = generateSaltedPassword(digest, salt, this.password, iterationCount);
+ var clientFinalMessageWithoutProof = "c=" + toBase64(gs2_header) + ",r=" + nonce;
+ var authMessage = this._clientFirstMessageBare + "," + serverFirstMessage + ","
+ + clientFinalMessageWithoutProof;
+ var clientKey = CryptoJS[hmac]("Client Key", saltedPassword);
+ var storedKey = CryptoJS[digest](clientKey);
+ var clientSignature = CryptoJS[hmac](authMessage, storedKey);
+ var clientProof = xor(clientKey, clientSignature);
+ var serverKey = CryptoJS[hmac]("Server Key", saltedPassword);
+ this._serverSignature = CryptoJS[hmac](authMessage, serverKey);
+ var response = toBase64(clientFinalMessageWithoutProof + ",p="
+ + clientProof.toString(CryptoJS.enc.Base64));
+ this._state = "generated";
+ return response;
+ }
+ }
+ else if (this._state == "generated")
+ {
+ var serverFinalMessage = fromBase64(challengeOrAdditionalData);
+ if (this._serverSignature.toString(CryptoJS.enc.Base64) == serverFinalMessage.substring(2))
+ {
+ this._state = "completed";
+ return null;
+ }
+ else
+ {
+ this._state = "error";
+ throw new Error("Server signature does not match");
+ }
+ }
+ else
+ {
+ throw new Error("Unexpected state '" + this._state + ". Cannot handle challenge!");
+ }
+ },
+ toString: function ()
+ {
+ return "[SaslClient" + this.getMechanismName() + "]";
+ }
+ });
+
+ });
http://git-wip-us.apache.org/repos/asf/qpid-broker-j/blob/6bde48c5/broker-plugins/management-http/src/main/java/resources/js/qpid/sasl/ShaSaslClient.js
----------------------------------------------------------------------
diff --git a/broker-plugins/management-http/src/main/java/resources/js/qpid/sasl/ShaSaslClient.js b/broker-plugins/management-http/src/main/java/resources/js/qpid/sasl/ShaSaslClient.js
deleted file mode 100644
index 14110ec..0000000
--- a/broker-plugins/management-http/src/main/java/resources/js/qpid/sasl/ShaSaslClient.js
+++ /dev/null
@@ -1,269 +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.
- */
-
-define(["dojo/_base/declare",
- "dojo/_base/lang",
- "dojox/encoding/base64",
- "dojo/json",
- "dojo/request/script",
- "dojox/uuid/generateRandomUuid",
- "dojo/Deferred",
- "qpid/sasl/CredentialBasedSaslClient",
- "qpid/sasl/UsernamePasswordProvider"],
- function (declare, lang, base64, json, script, uuid, Deferred, SaslClient, UsernamePasswordProvider)
- {
-
- var toBase64 = function toBase64(input)
- {
- var result = [];
- for (var i = 0; i < input.length; i++)
- {
- result[i] = input.charCodeAt(i);
- }
- return base64.encode(result)
- };
-
- var fromBase64 = function fromBase64(input)
- {
- var decoded = base64.decode(input);
- var result = "";
- for (var i = 0; i < decoded.length; i++)
- {
- result += String.fromCharCode(decoded[i]);
- }
- return result;
- };
-
- var xor = function xor(lhs, rhs)
- {
- var words = [];
- for (var i = 0; i < lhs.words.length; i++)
- {
- words.push(lhs.words[i] ^ rhs.words[i]);
- }
- return CryptoJS.lib.WordArray.create(words);
- };
-
- var hasNonAscii = function hasNonAscii(name)
- {
- for (var i = 0; i < name.length; i++)
- {
- if (name.charCodeAt(i) > 127)
- {
- return true;
- }
- }
- return false;
- };
-
- var generateSaltedPassword = function generateSaltedPassword(digest, salt, password, iterationCount)
- {
- var hmac = CryptoJS.algo.HMAC.create(CryptoJS.algo[digest], password);
- hmac.update(salt);
- hmac.update(CryptoJS.enc.Hex.parse("00000001"));
- var result = hmac.finalize();
- var previous = null;
- for (var i = 1; i < iterationCount; i++)
- {
- hmac = CryptoJS.algo.HMAC.create(CryptoJS.algo[digest], password);
- hmac.update(previous != null ? previous : result);
- previous = hmac.finalize();
- result = xor(result, previous);
- }
- return result;
- };
-
- var scriptLoadError = function scriptLoadError(error)
- {
- var message = "Cannot load script due to " + json.stringify(error);
- console.error(message);
- throw {message: message};
- };
-
- // hidden context scope variables
- var shaName = null;
- var digest = null;
- var hmac = null;
- var gs2_header = "n,,";
- var initialized = new Deferred();
- return declare("qpid.sasl.ShaSaslClient", [SaslClient], {
- _state: "initial",
- "-chains-": {
- constructor: "manual" // disable auto-constructor invocation
- },
- constructor: function (mechanism)
- {
- this._mechanism = mechanism;
- shaName = mechanism.substring(6)
- .replace('-', '')
- .toLowerCase();
- digest = shaName.toUpperCase();
- hmac = "Hmac" + digest;
-
- // loading crypto-js functionality based on mechanism
- script.get("js/crypto-js/hmac-" + shaName + ".js")
- .then(function ()
- {
- script.get("js/crypto-js/enc-base64-min.js")
- .then(function ()
- {
- initialized.resolve(true);
- }, function (error)
- {
- initialized.reject(error);
- scriptLoadError(error);
- });
- }, function (error)
- {
- initialized.reject("error");
- scriptLoadError(error);
- });
- },
- getMechanismName: function ()
- {
- return this._mechanism;
- },
- isComplete: function ()
- {
- return this._state == "completed";
- },
- getResponse: function (data)
- {
- if (initialized.promise.isResolved())
- {
- return this._getResponse(data);
- }
- else
- {
- throw {message: "Not initialized"};
- }
- },
- _getResponse: function (data)
- {
- if (this._state == "initial")
- {
- if (!hasNonAscii(data.username))
- {
- var user = data.username;
- user = user.replace(/=/g, "=3D");
- user = user.replace(/,/g, "=2C");
- this._password = data.password;
- this._username = user;
- this._clientNonce = uuid();
- this._clientFirstMessageBare = "n=" + this._username + ",r=" + this._clientNonce;
- var response = toBase64(gs2_header + this._clientFirstMessageBare);
- this._state = "initiated";
- return {
- mechanism: this.getMechanismName(),
- response: response
- };
- }
- else
- {
- this._state = "error";
- throw {
- message: "Username '" + challenge.username + "' is invalid"
- };
- }
- }
- else if (this._state == "initiated")
- {
- var serverFirstMessage = fromBase64(data.challenge);
- var id = data.id;
- var parts = serverFirstMessage.split(",");
- var nonce = parts[0].substring(2);
- if (!nonce.substr(0, this._clientNonce.length) == this._clientNonce)
- {
- this._state = "error";
- throw {
- message: "Authentication error - server nonce does " + "not start with client nonce"
- };
- }
- else
- {
- var salt = CryptoJS.enc.Base64.parse(parts[1].substring(2));
- var iterationCount = parts[2].substring(2);
- var saltedPassword = generateSaltedPassword(digest, salt, this._password, iterationCount);
- var clientFinalMessageWithoutProof = "c=" + toBase64(gs2_header) + ",r=" + nonce;
- var authMessage = this._clientFirstMessageBare + "," + serverFirstMessage + ","
- + clientFinalMessageWithoutProof;
- var clientKey = CryptoJS[hmac]("Client Key", saltedPassword);
- var storedKey = CryptoJS[digest](clientKey);
- var clientSignature = CryptoJS[hmac](authMessage, storedKey);
- var clientProof = xor(clientKey, clientSignature);
- var serverKey = CryptoJS[hmac]("Server Key", saltedPassword);
- this._serverSignature = CryptoJS[hmac](authMessage, serverKey);
- var response = toBase64(clientFinalMessageWithoutProof + ",p="
- + clientProof.toString(CryptoJS.enc.Base64));
- this._state = "generated";
- return {
- id: id,
- response: response
- };
- }
- }
- else if (this._state == "generated")
- {
- var serverFinalMessage = fromBase64(data.challenge);
- if (this._serverSignature.toString(CryptoJS.enc.Base64) == serverFinalMessage.substring(2))
- {
- this._state = "completed";
- return null;
- }
- else
- {
- this._state == "error";
- throw {message: "Server signature does not match"};
- }
- }
- else
- {
- throw {
- message: "Unexpected state '" + this._state + ". Cannot handle challenge!"
- };
- }
- },
- toString: function ()
- {
- return "[SaslClient" + this.getMechanismName() + "]";
- },
- getCredentials: function ()
- {
- var credentials = new Deferred();
- var successHandler = function (data)
- {
- credentials.resolve(data);
- };
- var errorHandler = function (data)
- {
- credentials.reject(data)
- };
- initialized.then(function (initData)
- {
- dojo.when(UsernamePasswordProvider.get())
- .then(function (data)
- {
- successHandler(data);
- }, errorHandler);
- }, errorHandler);
- return credentials.promise;
- }
- });
-
- });
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/qpid-broker-j/blob/6bde48c5/broker-plugins/management-http/src/main/java/resources/js/qpid/sasl/UsernamePasswordProvider.js
----------------------------------------------------------------------
diff --git a/broker-plugins/management-http/src/main/java/resources/js/qpid/sasl/UsernamePasswordProvider.js b/broker-plugins/management-http/src/main/java/resources/js/qpid/sasl/UsernamePasswordProvider.js
deleted file mode 100644
index bcc4b26..0000000
--- a/broker-plugins/management-http/src/main/java/resources/js/qpid/sasl/UsernamePasswordProvider.js
+++ /dev/null
@@ -1,41 +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.
- *
- */
-define(["dijit/registry", "dojo/domReady!"], function (registry)
-{
- return {
- get: function ()
- {
- if (registry.byId("username") == null)
- {
- // it is not a login page
- // redirecting to login.html
- window.location = "login.html";
- return;
- }
-
- return {
- username: registry.byId("username").value,
- password: registry.byId("password").value
- };
- }
- };
-
-});
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/qpid-broker-j/blob/6bde48c5/broker-plugins/management-http/src/main/java/resources/js/qpid/sasl/cram-md5-hex/SaslClient.js
----------------------------------------------------------------------
diff --git a/broker-plugins/management-http/src/main/java/resources/js/qpid/sasl/cram-md5-hex/SaslClient.js b/broker-plugins/management-http/src/main/java/resources/js/qpid/sasl/cram-md5-hex/SaslClient.js
index 931011f..a7b0cd2 100644
--- a/broker-plugins/management-http/src/main/java/resources/js/qpid/sasl/cram-md5-hex/SaslClient.js
+++ b/broker-plugins/management-http/src/main/java/resources/js/qpid/sasl/cram-md5-hex/SaslClient.js
@@ -33,14 +33,13 @@ define(["dojo/_base/declare",
{
return 2;
},
- initialize: function (username, password)
- {
- var hashedPassword = MD5(password, digestsBase.outputTypes.Hex);
- this.inherited(arguments, [username, hashedPassword]);
- },
toString: function ()
{
return "[SaslClientCramMD5Hex]";
+ },
+ getPassword: function ()
+ {
+ return MD5(this.password, digestsBase.outputTypes.Hex);
}
});
-});
\ No newline at end of file
+});
http://git-wip-us.apache.org/repos/asf/qpid-broker-j/blob/6bde48c5/broker-plugins/management-http/src/main/java/resources/js/qpid/sasl/cram-md5/SaslClient.js
----------------------------------------------------------------------
diff --git a/broker-plugins/management-http/src/main/java/resources/js/qpid/sasl/cram-md5/SaslClient.js b/broker-plugins/management-http/src/main/java/resources/js/qpid/sasl/cram-md5/SaslClient.js
index 178833c..5891238 100644
--- a/broker-plugins/management-http/src/main/java/resources/js/qpid/sasl/cram-md5/SaslClient.js
+++ b/broker-plugins/management-http/src/main/java/resources/js/qpid/sasl/cram-md5/SaslClient.js
@@ -22,12 +22,11 @@ define(["dojo/_base/declare",
"dojox/encoding/base64",
"dojox/encoding/digests/_base",
"dojox/encoding/digests/MD5",
- "qpid/sasl/CredentialBasedSaslClient",
- "qpid/sasl/UsernamePasswordProvider"],
- function (declare, lang, base64, digestsBase, MD5, SaslClient, UsernamePasswordProvider)
+ "qpid/sasl/CredentialBasedSaslClient"],
+ function (declare, lang, base64, digestsBase, MD5, SaslClient)
{
return declare("qpid.sasl.SaslClientCramMD5", [SaslClient], {
- _state: "initial",
+ _state: "initiated",
getMechanismName: function ()
{
return "CRAM-MD5";
@@ -40,19 +39,19 @@ define(["dojo/_base/declare",
{
return 3;
},
- getResponse: function (data)
+ getInitialResponse: function()
{
- if (this._state == "initial")
- {
- this.initialize(data.username, data.password);
- this._state = "initiated";
- return {
- mechanism: this.getMechanismName()
- };
- }
- else if (this._state == "initiated")
+ return null;
+ },
+ getPassword: function ()
+ {
+ return this.password;
+ },
+ getResponse: function (challenge)
+ {
+ if (this._state == "initiated")
{
- var challengeBytes = base64.decode(data.challenge);
+ var challengeBytes = base64.decode(challenge);
var wa = [];
var bitLength = challengeBytes.length * 8;
for (var i = 0; i < bitLength; i += 8)
@@ -62,38 +61,24 @@ define(["dojo/_base/declare",
var challengeStr = digestsBase.wordToString(wa)
.substring(0, challengeBytes.length);
- var digest = this._username + " " + MD5._hmac(challengeStr,
- this._password,
+ var digest = this.username + " " + MD5._hmac(challengeStr,
+ this.getPassword(),
digestsBase.outputTypes.Hex);
- var id = data.id;
+ var id = challenge.id;
var response = base64.encode(this._encodeUTF8(digest));
this._state = "completed";
- return {
- id: id,
- response: response
- };
+ return response;
}
else
{
- throw {
- message: "Unexpected state '" + this._state + ". Cannot handle challenge!"
- };
+ throw new Error("Unexpected state '" + this._state + ". Cannot handle challenge!");
}
},
toString: function ()
{
return "[SaslClientCramMD5]";
},
- getCredentials: function ()
- {
- return UsernamePasswordProvider.get();
- },
- initialize: function (username, password)
- {
- this._password = password;
- this._username = username;
- },
_encodeUTF8: function (str)
{
var byteArray = [];
@@ -117,4 +102,4 @@ define(["dojo/_base/declare",
return byteArray;
}
});
- });
\ No newline at end of file
+ });
http://git-wip-us.apache.org/repos/asf/qpid-broker-j/blob/6bde48c5/broker-plugins/management-http/src/main/java/resources/js/qpid/sasl/plain/SaslClient.js
----------------------------------------------------------------------
diff --git a/broker-plugins/management-http/src/main/java/resources/js/qpid/sasl/plain/SaslClient.js b/broker-plugins/management-http/src/main/java/resources/js/qpid/sasl/plain/SaslClient.js
index 9ffced7..ea2927f 100644
--- a/broker-plugins/management-http/src/main/java/resources/js/qpid/sasl/plain/SaslClient.js
+++ b/broker-plugins/management-http/src/main/java/resources/js/qpid/sasl/plain/SaslClient.js
@@ -20,8 +20,7 @@
define(["dojo/_base/declare",
"dojo/_base/lang",
"dojox/encoding/base64",
- "qpid/sasl/CredentialBasedSaslClient",
- "qpid/sasl/UsernamePasswordProvider"], function (declare, lang, base64, SaslClient, UsernamePasswordProvider)
+ "qpid/sasl/CredentialBasedSaslClient"], function (declare, lang, base64, SaslClient)
{
return declare("qpid.sasl.SaslClientPlain", [SaslClient], {
_state: "initial",
@@ -37,34 +36,28 @@ define(["dojo/_base/declare",
{
return 1;
},
- getResponse: function (challenge)
+ getInitialResponse: function ()
{
if (this._state == "initial")
{
- var responseArray = [0].concat(this._encodeUTF8(challenge.username))
+ var responseArray = [0].concat(this._encodeUTF8(this.username))
.concat([0])
- .concat(this._encodeUTF8(challenge.password));
- var plainResponse = base64.encode(responseArray);
- this._state = "completed"
- return {
- mechanism: this.getMechanismName(),
- response: plainResponse
- };
+ .concat(this._encodeUTF8(this.password));
+ this._state = "completed";
+ return base64.encode(responseArray);
}
else
{
- throw {
- message: "Unexpected state '" + this._state + ". Cannot handle challenge!"
- };
+ throw new Error("Unexpected state '" + this._state);
}
},
- toString: function ()
+ getResponse : function ()
{
- return "[SaslClientPlain]";
+ throw new Error("Unexpected state");
},
- getCredentials: function ()
+ toString: function ()
{
- return UsernamePasswordProvider.get();
+ return "[SaslClientPlain]";
},
_encodeUTF8: function (str)
{
@@ -89,4 +82,4 @@ define(["dojo/_base/declare",
return byteArray;
}
});
-});
\ No newline at end of file
+});
http://git-wip-us.apache.org/repos/asf/qpid-broker-j/blob/6bde48c5/broker-plugins/management-http/src/main/java/resources/js/qpid/sasl/scram-sha-1/SaslClient.js
----------------------------------------------------------------------
diff --git a/broker-plugins/management-http/src/main/java/resources/js/qpid/sasl/scram-sha-1/SaslClient.js b/broker-plugins/management-http/src/main/java/resources/js/qpid/sasl/scram-sha-1/SaslClient.js
index 10b921a..4c8d2de 100644
--- a/broker-plugins/management-http/src/main/java/resources/js/qpid/sasl/scram-sha-1/SaslClient.js
+++ b/broker-plugins/management-http/src/main/java/resources/js/qpid/sasl/scram-sha-1/SaslClient.js
@@ -17,9 +17,9 @@
* under the License.
*/
-define(["dojo/_base/declare", "qpid/sasl/ShaSaslClient"], function (declare, ShaSaslClient)
+define(["dojo/_base/declare", "qpid/sasl/ScramShaSaslClient"], function (declare, ScramShaSaslClient)
{
- return declare("qpid.sasl.SaslClientScramSha1", [ShaSaslClient], {
+ return declare("qpid.sasl.SaslClientScramSha1", [ScramShaSaslClient], {
constructor: function ()
{
this.inherited(arguments, ["SCRAM-SHA-1"]);
@@ -33,4 +33,4 @@ define(["dojo/_base/declare", "qpid/sasl/ShaSaslClient"], function (declare, Sha
return "[SaslClientScramSha1]";
}
});
-});
\ No newline at end of file
+});
http://git-wip-us.apache.org/repos/asf/qpid-broker-j/blob/6bde48c5/broker-plugins/management-http/src/main/java/resources/js/qpid/sasl/scram-sha-256/SaslClient.js
----------------------------------------------------------------------
diff --git a/broker-plugins/management-http/src/main/java/resources/js/qpid/sasl/scram-sha-256/SaslClient.js b/broker-plugins/management-http/src/main/java/resources/js/qpid/sasl/scram-sha-256/SaslClient.js
index 4150548..60913af 100644
--- a/broker-plugins/management-http/src/main/java/resources/js/qpid/sasl/scram-sha-256/SaslClient.js
+++ b/broker-plugins/management-http/src/main/java/resources/js/qpid/sasl/scram-sha-256/SaslClient.js
@@ -17,9 +17,9 @@
* under the License.
*/
-define(["dojo/_base/declare", "qpid/sasl/ShaSaslClient"], function (declare, ShaSaslClient)
+define(["dojo/_base/declare", "qpid/sasl/ScramShaSaslClient"], function (declare, ScramShaSaslClient)
{
- return declare("qpid.sasl.SaslClientScramSha256", [ShaSaslClient], {
+ return declare("qpid.sasl.SaslClientScramSha256", [ScramShaSaslClient], {
constructor: function ()
{
this.inherited(arguments, ["SCRAM-SHA-256"]);
@@ -33,4 +33,4 @@ define(["dojo/_base/declare", "qpid/sasl/ShaSaslClient"], function (declare, Sha
return "[SaslClientScramSha256]";
}
});
-});
\ No newline at end of file
+});
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org