Name |
.NET Authenticator with SSO Support |
---|---|
Version |
1.0 |
Product Versions |
Crowd 1.0.6 |
Author(s) |
Matthew Slater |
Homepage |
|
Price |
Free |
License |
|
JavaDocs |
|
IssueTracking |
|
Download |
|
Download Source |
Description/Features
Crowd Authentication and Single Sign-On Support for .NET Clients.
The .NET Authenticator has been engineered and developed from the original HTTPAuthenticator module written for Java. The full functionality provided by the Java Integration Library to Java clients has now been made available to .NET Clients (including much desired single sign-on support).
Usage
The compiled code and examples provided require the Microsoft .NET Framework 2.0. For other versions of .NET, take the source code and recompile/edit as necessary.
Set-up the Authenticator
The Authenticator requires the following files to be present within the same folder location:
- HttpAuthenticator.dll (supplied in download)
- SecurityServer.dll (see below)
- crowd.properties (see below)
The SecurityServer.dll component and crowd.properties file can be obtained as follows:
SOAP API Proxy
As the .NET Component can't make use of the Crowd Java libraries directly, you need to create a proxy to the SOAP API for your environment in order to facilitate part of the authentication process. This process is explained in detail here.
The resulting proxy component is called SecurityServer.dll. Place this file in the same location as the HttpAuthenticator.dll.
Crowd.Properties file
The Authenticator needs information concerning the Crowd Application you have configured and session/cookie parameters. This information is retrieved from a standard crowd.properties file.
See the Configuring your Application section for further information on how to obtain this file and edit it for your installation. The file must be placed in the same location as the HttpAuthenticator.dll.
Using the Authenticator
From your ASP.NET Website or Application, make a reference to the HttpAuthenticator.dll and call the methods on the HttpAuthenticator class as appropriate.
Examples
The CODEGEIST:Demo ASP.NET web site is a simple web site, developed to make use of the new .NET Authenticator and effectively highlights the authentication and Single Sign-On process, using relevant sample code.
The following code (originally engineered from the Crowd Demo Application and converted for use by .NET) highlights the use of the .NET Authenticator. Refer to the CODEGEIST:Demo ASP.NET website provided in order to obtain the full test code.
using System; using System.Data; using System.Configuration; using System.Web; using System.Web.Security; using System.Web.UI; using System.Web.UI.WebControls; using System.Web.UI.WebControls.WebParts; using System.Web.UI.HtmlControls; using com.atlassian.crowd.integration.http; /// <summary> /// Class containing functionality to check authentication status and retrieve principal data /// Engineered from BaseAction.Java in Demo Crowd Application /// </summary> public class BaseAction { #region Private Properties private static bool? _authenticated = null; private static SOAPPrincipal _principal = null; #endregion #region Constants // Principal attributes - these are currently hard-coded private const string FIRSTNAME = "givenName"; private const string LASTNAME = "sn"; private const string LASTAUTHENTICATED = "lastAuthenticated"; #endregion #region Constructors static BaseAction() { // // TODO: Add constructor logic here // } #endregion #region Accessors /// <summary> /// Accessor which determines if the last call to IsAuthenticated succeeded /// </summary> public static bool Authenticated { get { return Convert.ToBoolean(_authenticated); } } /// <summary> /// Accessor for HttpRequest /// </summary> private static HttpRequest Request { get { return HttpContext.Current.Request; } } /// <summary> /// Accessor for HttpResponse /// </summary> private static HttpResponse Response { get { return HttpContext.Current.Response; } } #endregion /// <summary> /// Checks if a principal is currently authenticated versus the Crowd Security Server. /// </summary> /// <returns>TRUE if the principal is authenticated, FALSE otherwise</returns> public static bool isAuthenticated() { try { _authenticated = HttpAuthenticator.isAuthenticated(Request, Response); } catch (Exception) { _authenticated = false; } return Convert.ToBoolean(_authenticated); } /// <summary> /// Retrieves the full name of the authenticated principal /// </summary> /// <returns>Full name of the authenticated principal</returns> /// <remarks>Throws InvalidPrincipalException</remarks> public static string getPrincipalName() { if (!isAuthenticated()) return null; string principalName = String.Empty; if (getPrincipal() != null) { // Get first and last name of the principal string firstName = getFirstAttribute(FIRSTNAME); string lastName = getFirstAttribute(LASTNAME); if (!String.IsNullOrEmpty(firstName)) { principalName = firstName; } if (!String.IsNullOrEmpty(lastName)) { if (!String.IsNullOrEmpty(principalName) && principalName.Length > 0) principalName += " "; principalName += lastName; } if (String.IsNullOrEmpty(principalName)) principalName = getPrincipal().name; } return principalName; } /// <summary> /// Retrieves the Date and Time of the last authentication of the currently authenticated user /// </summary> /// <returns>DateTime of the authentication</returns> /// <remarks>Throws InvalidPrincipalException</remarks> public static DateTime getLastAuthenticated() { DateTime lastAuthenticated = DateTime.MinValue; if (isAuthenticated() && (getPrincipal() != null)) { // Get the number of milliseconds since 1970 string millis = getFirstAttribute(LASTAUTHENTICATED); if (!String.IsNullOrEmpty(millis)) { // Convert from Java milliseconds DateTime javaEpoch = new DateTime(1970, 1, 1); lastAuthenticated = javaEpoch.AddMilliseconds(Convert.ToInt64(millis)); } } return lastAuthenticated; } /// <summary> /// Retrieve the attribute with the given name /// </summary> /// <param name="name">Name of the attribute</param> /// <returns>Value of the principal attribute, of String.Empty if not found</returns> /// <remarks>Throws InvalidPrincipalException</remarks> public static string getFirstAttribute(string name) { string attributeValue = String.Empty; try { SOAPAttribute attribute = getAttribute(name); if ((attribute != null) && (attribute.name != null) && (attribute.values.Length > 0)) attributeValue = attribute.values[0]; } catch (Exception) { // Attribute cannot be found } return attributeValue; } /// <summary> /// Gets the currently authenticated principal /// </summary> /// <returns>SOAPPrincipal of the currently authenticated principal</returns> /// <remarks>Throws InvalidPrincipalException</remarks> public static SOAPPrincipal getPrincipal() { if (!isAuthenticated()) return null; if (_principal == null) { try { // find the authenticated principal from the token _principal = HttpAuthenticator.getPrincipal(Request); } catch (Exception) { throw; } } return _principal; } /// <summary> /// Gets a principal attribute by name /// </summary> /// <param name="name">Name of the attribute</param> /// <returns>Value of the attribute</returns> /// <remarks>Throws InvalidPrincipalException</remarks> public static SOAPAttribute getAttribute(string name) { if (!isAuthenticated()) { return null; } SOAPPrincipal remotePrincipal = getPrincipal(); SOAPAttribute[] attributes = _principal.attributes; for (int i = 0; i < attributes.Length; i++) { if (attributes[i].name.Equals(name)) { // Retrieve the value return attributes[i]; } } // unable to find the attribute, return a new empty one. SOAPAttribute soapAttribute = new SOAPAttribute(); soapAttribute.name = name; return soapAttribute; } }
The following code is used to authenticate a principal:
using System; using System.Data; using System.Configuration; using System.Web; using System.Web.Security; using System.Web.UI; using System.Web.UI.WebControls; using System.Web.UI.WebControls.WebParts; using System.Web.UI.HtmlControls; using com.atlassian.crowd.integration.http; /// <summary> /// Class containing functionality to authenticate the principal /// Engineered from Login.Java in Demo Crowd Application /// </summary> public class Login { #region Private Properties // User Credentials for Authentication private static string _username = null; private static string _password = null; #endregion #region Constructors static Login() { // // TODO: Add constructor logic here // } #endregion #region Accessors // Accessor for HttpRequest private static HttpRequest Request { get { return HttpContext.Current.Request; } } // Accessor for HttpResponse private static HttpResponse Response { get { return HttpContext.Current.Response; } } // Accessor for UserName public static string UserName { get { return _username; } set { _username = value; } } // Accessor for Password public static string Password { get { return _password; } set { _password = value; } } #endregion /// <summary> /// Attempts to authenticate the principal and log-in to the Crowd Application. /// Also sets appropriate cookie token and session variables for SSO. /// </summary> /// <returns>TRUE if successfully authenticated, FALSE otherwise</returns> public static bool Execute() { bool authenticated = false; if (_username != null && !String.IsNullOrEmpty(_username) && _password != null) { // Attempt authentication HttpAuthenticator.authenticate(Request, Response, _username, _password); authenticated = true; } else { // Didn't supply authentication information, so check if already authenticated authenticated = BaseAction.isAuthenticated(); } return authenticated; } }
Testing Single Sign-On
In order to test whether single sign-on is working correctly, you must run the ASP.NET Demo application in the context of a browser session running another Crowd-integrated application (such as Confluence, Jira or the Crowd Demo Application etc).
Version History
Version |
Release Date |
Description |
---|---|---|
0.9 |
May 3rd, 2007 |
Initial Version |
1.0 |
May 10th, 2007 |
Improved Demo Application, Coding Tidy-Up |
Limitations
The .NET Authenticator is derived from functionality provided by the HttpAuthenticator in Crowd version 1.0.6. It is understood that revisions and functionality may be added to the Java Integration Libraries at any time and therefore the .NET Authenticator may also need to be updated to take account of such changes.
Screenshots
Screenshots |
---|