OAuth is in the moment possibly the most standard way to authenticate user in the world of REST, WEB and mobile devices. In this post I will show how to implement WRAP 0.9 authentication by using Windows Azure Access Control Service. Following Java Script function prepares and posts the request as expected by Access Control Service and retrieves the Simple Web Token.
CreateToken = function (userName, pwd, scope) { if (m_IsInitialized == null || m_IsInitialized == false) throw "SecurityTokenClient.Initialize(config) has to be called."; var data = "wrap_name=" + userName + "&wrap_password=" + pwd + "&wrap_scope=" + scope; $.support.cors = true; // force cross-site scripting (as of jQuery 1.5) $.ajax({ type: 'POST', url: “https://yournamespace.accesscontrol.windows.net/WRAPv0.9/”, context: "ctx", data: data, success: function (result) { alert(“Hello token:” + result); }, error: function (XMLHttpRequest, textStatus, errorThrown) { alert(textStatus + “ – “ + errorThrown); } }); }
|
Note that this function will fail in an ASP.NET application, because of browser cross-scripting limitation. Fortunately all mobile devices will allow execution if following line is executed:
$.support.cors = true;
I have encapsulated all of this in a Java Script module called SecurityTokenClient and tested it in the Windows Metro Style application. By using this module the authentication would look like shown in next METRO-example:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Application1</title> <!-- WinJS references --> <link href="//Microsoft.WinJS.0.6/css/ui-dark.css" rel="stylesheet"> <script src="//Microsoft.WinJS.0.6/js/base.js"></script> <script src="//Microsoft.WinJS.0.6/js/ui.js"></script> <!-- Application1 references --> <link href="/css/default.css" rel="stylesheet"> <script src="/js/default.js"></script> <script src="/js/jquery-1.6.3.js" type="text/javascript"></script> <script src="/js/knockout-2.0.0.js" type='text/javascript'></script> <script src="/js/jquery.fixedheadertable.min.js" type="text/javascript"></script> <script src="/js/query.model.js" type="text/javascript"></script> <script src="/js/query.presenter.js" type="text/javascript"></script> <script src="/js/sts.js" type="text/javascript"></script> </head> <body> <h3>Welcome to Windows Metro OAuth sample.</h3> <br/><br/> <button id="btn" type="button" >Click to get token.</button> <br/><br/> <div id="token"> </div> <script type="text/javascript"> // // This function will be called when service query operation has completed. var onQueryCompleted = function (error) { if (error != null) alert(error); model = QueryPresenter.ViewModel(); } // // This function will be after authentication has comleted successfully. var onAuthenticationCompleted = function (swt) { $("#token").html(swt); } // // This function will be invoked when credentials have to be provided or // if the authentication has failed. var onAuthenticationError = function (err) { if (err == "User not authenticated!") { QueryPresenter.LogOn("user1", "123abc"); $("#token").html("Authenticating user1..."); } else { $("#token").html(err); } } $(document).ready(function () { $("#btn").click(function () { SecurityTokenClient.Initialize( { OnAuthenticationError: onAuthenticationError, OnAuthenticationCompleted: onAuthenticationCompleted, StsUrl: “https://yournamespace.accesscontrol.windows.net/WRAPv0.9/”, }); SecurityTokenClient.CreateToken("user1", "123abc", "http%3a%2f%2flocalhost%2fServiceApp"); }); }); </script> </body> </html> |
In fact the whole authentication by using this module would look simplified like:
$("#btn").click(function () {
SecurityTokenClient.Initialize(
{
OnAuthenticationError: onAuthenticationError,
OnAuthenticationCompleted: onAuthenticationCompleted,
StsUrl: “https://yournamespace.accesscontrol.windows.net/WRAPv0.9/”,
});
SecurityTokenClient.CreateToken("user1", "123abc", "http%3a%2f%2flocalhost%2fServiceApp");
});
As you see, the module needs to be initialized and CreateToken has to be called. All other code shown in the example above is a bit sugar around UI. And here is the full module implementation:
/* Copyright daenet GmbH */ // // Provides the functionality for OAuth authentication. SecurityTokenClient = (function () { var m_QuaGGbdg; // // The URL of the Security Token Service. var m_StsUrl; // // Callback invoked if authentication has failed. var onAuthenticationError; // // Callback invoked if authentication has been successfully completed. var onAuthenticationCompleted; var m_IsInitialized; return { // // Gets the token. GetToken: function () { return m_QuaGGbdg; }, // // True if the SWT token exists. isAuthenticated: function () { if (m_QuaGGbdg != null) { return true; } else { return false; } }, // // If the client is not authenticated it invokes onAuthenticationError // and returns FALSE. // If the client is authenticated it returns TRUE. EnsureAuthenticated: function () { if (this.isAuthenticated() == false) { onAuthenticationError("User not authenticated!"); } }, // // Initialize the client for communication with STS. Initialize: function (config) { if (config != null) { if (config.OnAuthenticationError == null) throw "onAuthenticationError handler has to be registered!"; if (config.OnAuthenticationCompleted == null) throw "onAuthenticationCompleted handler has to be registered!"; if (config.StsUrl == null) throw "StsUrl config parameter has to be set!"; onAuthenticationError = config.OnAuthenticationError; onAuthenticationCompleted = config.OnAuthenticationCompleted; m_StsUrl = config.StsUrl; m_IsInitialized = true; } else throw "Configuration parameters have not been specified."; }, // // Performs the OAuth authentication. // userName: The user ot be authenticated. // pwd: The user's password. // scope: Trusted audience (realm). CreateToken: function (userName, pwd, scope) { if (m_IsInitialized == null || m_IsInitialized == false) throw "SecurityTokenClient.Initialize(config) has to be called."; var data = "wrap_name=" + userName + "&wrap_password=" + pwd + "&wrap_scope=" + scope; $.support.cors = true; // force cross-site scripting (as of jQuery 1.5) $.ajax({ type: 'POST', url: m_StsUrl, context: "ctx", data: data, success: function (result) { m_QuaGGbdg = result; onAuthenticationCompleted(result); }, error: function (XMLHttpRequest, textStatus, errorThrown) { onAuthenticationError(textStatus, errorThrown); } }); } } })();
|
Posted
Mar 11 2012, 12:24 AM
by
Damir Dobric