This is a guest blog from Catch Limited, who’ve integrated a .Net application with Crowd.
Enterprise Tester, their test management solution, works with Jira and Crowd, and here they get into the gory details of how they connected it to Crowd.

Introduction

When taking an application like Enterprise Tester and dropping it into a corporate environment, the question of integration becomes important. This is especially true of authentication – insisting your application users and support staff must:

  • Learn a new username and password
  • Upskill service desk staff in how to reset passwords, disable accounts etc. in the application
  • Having to login multiple times for different applications

These introduce unneccessary friction and complexity to an organisation. Gartner identified in 2004 that aproximately 30% of all service desk calls are password related so we didn’t want our application compounding this already costly issue.
The key of course is to introduce flexible authentication support, so when deciding to implement our first version of our authentication support we decided to tackle the low-hanging fruit (based on requests from existing customers):

  • LDAP Directory
  • Internal Database of usernames / passwords (the default way applications store usernames and passwords)
  • Local machine users
  • Active Directory (we felt AD was common enough to support a separate easier-to-configure mode)
  • Active Directory Application Mode (ADAM)

This would provide support for common user authentication scenarios. But… this only works well for organisations where they have already standardised on LDAP as the primary user store, so we decided to add one more technology to our list – Crowd.
By integrating with Crowd we were able to greatly extend our reach into other applications, which may not be aware of LDAP or Enterprise Tester. Additionally Crowd provides us with a way to provide Single Sign-on (SSO) support between applications such as Enterprise Tester, Jira and Confluence. Again, reducing the need for logging into every application separately, making users lives easier.

Design Goals

When we began development on the authentication feature for our product, we had some key user stories in mind for v1.0 of authenticaqtion support:

  • Administrators can configure authentication entirely via the user-interface
  • Administrators can test configuration easily via the user-interface
  • Ability to distribute additional installable authentication plugins to customers
  • Allowing for multiple authentication sources at once – so some users can authenticate via LDAP for example, while others may authenticate via the database
  • Users can always authenticate via the database (in cases where perhaps connectivity to LDAP, Crowd etc. is unavailable – this is important for trial users on laptops)

Here’s a peek at how this functionality ended up looking:

Managing Priority / State of Multiple Authentication Methods

authentication_methods.png

Adding a New Crowd Source

adding_crowd.png

Testing Configuration via the “Test” Feature.

test_authentication.png

Implementation

Our Crowd authentication plugin consists of 11 class files. These provide functionality for authentication, serialization of the Crowd settings and the configuration controller for adding / editing the Crowd authentication settings.
The heart of the plugin is the CrowdAuthenticationSession class, which implements the following interface (note: some methods have been removed to highlight the important features):


public interface IAuthenticationMethod : IModule {
string DisplayName { get; }
AuthenticationResult IsAuthenticated(AuthenticationParticipant participant, IEngineContext context);
AuthenticationResult Authenticate(AuthenticationParticipant participant, IEngineContext context, string userName, string password);
...
bool SupportsRemoval();
bool SupportsTogglingEnabled();
}

So the key features are the IsAuthenticated(…) method, which allows checking to see if the user is already authenticated (this provides us with an entry point for checking the Single Sign-on cookie used by Crowd) and Authenticate, which handles authentication based on a supplied username and password.
The Authenticate method in turn uses the CrowdAuthenticationSession to communicate with the Crowd server via a web service.
The session and authentication method classes combined are aproximately 200 lines of code, so it’s very easy to implement this level of Crowd support in your own application. Our code was based on the example provided by Matthew Slater, which can be found on the Atlassian Plugin Exchange.

Pitfalls

Crowd authentication is easy to implement, but there are some pitfalls for new developers. The primary issues we experienced were with validation factors.
Validation factors are key / value pairs passed in as evidence when attempting to authenticate. They are used to ensure that not only does the username and password match, but that some environmental expectations are met around where you are coming from / what device you are using, such as:

  • Remote address (i.e. the user’s IP address)
  • Forwarded address (if, for example, they are being redirected to the application via a proxy)
  • User-Agent (i.e.what browser are they using)

This information is checked against the allowable values of the application you are trying to authenticate for in Crowd, and if it does not match then authentication will fail.
Unfortunately, because this information forms part of the shared secret between client and server, Crowd does not respond with details of why validation fails if your application is passing incorrect values, or what the correct values should be.
As a result your only option is to enable verbose logging and watch what details are logged during a failed authentication attempt.
In our case we were seeing that people running the browser and Crowd server on the same machine were experiencing validation failures. After investigation it was discovered that this was due to the fact that the loopback address being passed to application was the IPV4 address, but Crowd was expecting the IPV6 loopback address. To resolve this we had to introduce a special option into our Crowd authentication method which worked around this issue, so our code for generating the list of validation factors eventually ended up being:


public interface IAuthenticationMethod : IModule {
string DisplayName { get; }
AuthenticationResult IsAuthenticated(AuthenticationParticipant participant, IEngineContext context);
AuthenticationResult Authenticate(AuthenticationParticipant participant, IEngineContext context, string userName, string password);
...
bool SupportsRemoval();
bool SupportsTogglingEnabled();
}
public interface ICrowdAuthenticatorSession {
string AuthenticateUser(string userName, string password, IEnumerable validationFactors);
bool IsValidPrincipalToken(string token, IEnumerable validationFactors);
string GetPrincipalNameForToken(string token);
string GetDomain();
}


Fortunately Atlassian's documentation and community content provides assistance with diagnosing these various issues, some articles we found useful included:
Troubleshooting SSO with Crowd
Explanation of Validation Factors
Validation Factor API Documentation

Next Steps

Currently Enterprise Tester supports authentication of users via Crowd as well as Crowd SSO, but expects Administrators to have created a user in Enterprise Tester with the same username as the user in Crowd, before authenticating.
In future releases we plan to extend support in Enterprise Tester to allow for groups and users existing only in Crowd to be used within Enterprise Tester.

Conclusion

For a very small amount of engineering effort we were able to add support for Crowd authentication and SSO to Enterprise Tester, providing many benefits to our customers who are already using Crowd for managing their application authentication and authorization.
If you are looking to add support to your next .Net application for Active Directory / LDAP authentication, why not consider adding support for Crowd at the same time and give yourself a competitive advantage over other vendors!

Integrating Enterprise Tester with Crowd