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">&nbsp;&nbsp;&nbsp;&nbsp;</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