The Play! Framework

20 Sep

Overview

Play 2.0 is a lightweight Java and Scala web framework aimed at keeping setup and configuration time to a minimum, thereby maximising development time. Some of the key advantages that Play boasts over other frameworks is code hot-reloading, stateless and RESTful design, less configuration and asynchronous I/O.

Play 2.0 has a large focus on type safety with the idea of getting the compiler to find code errors rather than stumbling upon them at runtime. When compile or runtime errors are encountered, Play 2.0 does its best to give useful information in the error messages, which are displayed neatly in the browser.

The framework uses a Scala based template engine for the generation of web pages, but gives the programmer the choice of using either Scala or Java for server side code. Play uses the JBoss Netty web server (which comes packaged with the framework) allowing Play to service long requests asynchronously. The configuration file is small and neat, and the developer can specify a separate production config file when deploying the application.

Example config file

application.name=MyTestApplication

# Secret key
# The secret key is used to secure cryptographics functions.
application.secret="abcdeHUL__[Gf2HUfYMR/au1234`KW^T2owIxWXEoy8g:1234Kivx>3bu0X5]bq"

# The application languages
application.langs="en"

# Database configuration
# You can declare as many datasources as you want.
# By convention, the default datasource is named `default`
#
db.default.driver=org.h2.Driver
db.default.url="jdbc:h2:mem:play"
db.default.user=sa
db.default.password=
#
# You can expose this datasource via JNDI if needed (Useful for JPA)
# db.default.jndiName=DefaultDS

# Evolutions
# You can disable evolutions if needed
# evolutionplugin=disabled

# Ebean configuration
# You can declare as many Ebean servers as you want.
# By convention, the default server is named `default`
ebean.default="models.*"

# Logger
# You can also configure logback (http://logback.qos.ch/), by providing a logger.xml file in the conf directory .

# Root logger:
logger.root=ERROR

# Logger used by the framework:
logger.play=INFO

# Logger provided to your application:
logger.application=DEBUG

The Play Console

Creating a new project with Play 2.0 is a simple process. Once you have downloaded the framework (which is OS independent) enter the following in a new command window:

$ play new myProjectName

Once the framework has created your project (you can choose at this point to either create a Java or Scala project) you can enter the console of your application by entering the directory of your newly created project and typing:

$ play

From here you have various commands available to you:

run will begin your application in the built in webserver on http://localhost:9000/. A default home page with help and links to documentation is provided.

test will run all the unit, integration and functional tests under the test/ directory of your project. The framework also provides clean, compile, debug and console commands. The console command launches an interactive Scala console that allows you to test and evaluate snippets of code.

Play 2.0 also provides triggered execution commands. ~ run will run your application and detect any changes to code files, recompile them and inject the newly compiled code into the running instance. The ~ test command will rerun all your application’s tests each time the source is modified.

The Play console also provides commands for creating project files for IntelliJ Idea, Netbeans and Eclipse, making the process of getting to actual development even faster.

Features

Play 2.0 comes with a collection of libraries, helper classes and base classes, all designed to help you avoid unnecessary boiler plate code. While using these API’s and helper classes is encouraged, you are not restricted to using them. Some of the libraries included in Play 2.0 are Ebean, FluentLenium as well as a built in SMTP mailer and job scheduler. A base Model object built around Ebean is included with helper methods for all your basic persistence requirements.

package models;

import java.util.*;
import javax.persistence.*;

import play.db.ebean.*;
import play.data.format.*;
import play.data.validation.*;

@Entity 
public class User extends Model {

  @Id
  @Constraints.Min(10)
  public Long id;

  @Constraints.Required
  public String name;

  public boolean isAdmin;

  @Formats.DateTime(pattern="dd/MM/yyyy")
  public Date birthday = new Date();

  public static Finder<Long,User> find = new Finder<Long,User>(
    Long.class, User.class
  ); 

}

// Find all users
List users = User.find.all();

// Find a user by ID
User anyUser = User.find.byId(34L);

// Delete a user by ID
User.find.ref(34L).delete();

// More complex user query
List users = find.where()
    .like("name", "%coco%")
    .orderBy("birthday asc")
    .findPagingList(25)
    .getPage(1);

Play will automatically generate any getter and setter methods on models (if they do not exist already) to ensure compatibility with any libraries that expect them to be available at runtime.

Following Play’s suggested architecture is quick and easy, but deviating from it will lead to writing some of your own boilerplate code. Many of the helper classes are coupled to specific frameworks (such as the EBean base Model object) however swapping out the persistence layer is not too difficult to do. Play also provides you with a built in JPA helper.

public static User findById(Long id) {
  return JPA.em().find(User.class, id);
}

Testing and TDD

Play 2.0 purposely lends itself quite well to test driven development. With built in JUnit and FluentLenium, as well as helpers to create in memory databases that can be used for the duration of the test session, it is easy to write tests that run quickly and that are not dependent on your production database. Nothing extra is required to write and run your JUnit unit tests, and by using the test-only command you can exclude your functional and integration tests to keep the testing in your TDD cycles fast.

$ test-only my.namespace.unittests

The continuous testing option provided by sbt automatically re-runs your tests when it detects any code changes, which is handy for picking up regression bugs early. Using Selenium WebDriver and HtmlUnit allows you to run your functional tests headlessly so that you are not distracted by the browser popping up every time your tests are run.

One downside of using Play’s inbuilt testing framework is that test results are displayed in the terminal window instead of in your IDE. This means that you will constantly be having swich to your terminal to see what tests may have failed. While the framework gives full descriptions of the failed tests, you won’t be able to make use of various IDE features such as links that take you directly to the source of the failed test.

Conclusion

The suitability of Play 2.0 for large enterprise applications has been debated quite a lot in various circles. Many people are sceptical of using it due to it being relatively new, and its tendency to not strictly follow Java EE best practices. However there are a number of high profile websites built using Play (including http://typesafe.com/), and many good testimonials littered around the internet. Play definitely seems to keep the developer in mind and provides enough extensibility and modularisation to allow the framework to fit just about any application.

Since Play’s inception in 2009, there have been some major improvements and changes and Play has continuously remained on the cutting edge. Play 1.0 is still being maintained, however the versions are not backwards compatible. Play is not a silver bullet to all your application requirements, but is certainly a framework to keep an eye on, and in the meantime it is definitely a fun framework to work with.

References

http://blog.davejafari.com/experiences-developing-with-play?c=1

http://stackoverflow.com/questions/7866186/play-framework-suitability-for-websites-and-web-apps

https://groups.google.com/forum/?fromgroups=#!topic/play-framework/zXYniwmH9KQ

http://www.playframework.org/documentation/2.0.3/Philosophy

http://en.wikipedia.org/wiki/Play_Framework#Usage

http://www.lunatech-research.com/archives/2010/03/15/play-framework-usability

Exploring Google and OpenID login with Spring Security and Spring Roo

18 Jan

Overview

OpenID is an open framework for decentralized user authentication, allowing users to manage their online identity through a single trusted provider. Websites supporting OpenID login allow users to login with the same credentials as this OpenID Provider. In this tutorial we will explore Spring Security’s OpenID support, and use Spring Roo to build a simple application allowing users to login using their Google or other OpenID account.

In order to be able to test OpenID login, you will simply need your Google account. Google’s implementation is however slightly different to many of the other providers, so in order to test more generic OpenID login, you may also want to sign up for your own OpenID from one of the available providers.

Just want to run it?

Download and unzip the project, run mvn tomcat:run from a terminal, and open up a browser to http://localhost:8080/openidlogin

Dependencies

Apache Maven 2.2.1 (download)
Spring Roo 1.1.0.RELEASE (download)
Spring Security OpenID 3.0.5.RELEASE (will be downloaded by Maven)
openid4java 0.9.5 (will be downloaded by Maven)

Setting up the Roo project

We will setup the project using Spring Roo’s scripting functionality. Included in the attached project is the script file script.roo. The commands contained in this file are exactly the same as those you would type into the Roo shell. To run the script, open up a Roo shell and type script –file script.roo

The script:

  • creates a Roo project with a structure following the standard Maven conventions
  • adds the additional dependencies required for OpenID login (Spring Security OpenID, openid4java) to the Maven project object model (POM)
  • installs a JPA persistence provider
  • adds the domain model objects (UserRole, EmployeeStatus and Employee)
  • creates the Spring MVC web frontend
  • configures Spring Security
  • and adds two java classes which we will later expand (InsertTestData and OpenIdUserDetailsService).
# Project
project --topLevelPackage za.co.bsg.rnd.trf.openidlogin

# Persistence
persistence setup --provider HIBERNATE --database HYPERSONIC_IN_MEMORY --databaseName openidlogin --hostName localhost

# Dependencies
dependency add --groupId org.springframework.security --artifactId spring-security-openid --version 3.0.5.RELEASE
dependency add --groupId org.openid4java --artifactId openid4java --version 0.9.5

# Domain model
enum type --class ~.domain.UserRole
enum constant --name ROLE_ADMIN
enum constant --name ROLE_USER

enum type --class ~.domain.EmployeeStatus
enum constant --name ACTIVE
enum constant --name DORMANT
enum constant --name RESIGNED
enum constant --name TERMINATED

entity --class ~.domain.Employee --table employee --identifierColumn employee_id
field string --fieldName username --column username --notNull
field string --fieldName password --column password --notNull
field enum --type ~.domain.UserRole --fieldName userRole --notNull --enumType STRING
field string --fieldName openIdIdentifier --column openid_identifier
field string --fieldName firstName --column first_name
field string --fieldName lastName --column last_name
field string --fieldName emailAddress --column email_address
field enum --type ~.domain.EmployeeStatus --fieldName status --notNull --enumType STRING

# We will also need a finder
finder add --finderName findEmployeesByOpenIdIdentifier --class ~.domain.Employee

# Scaffold the web frontend
controller all --package ~.web

# Spring Security
security setup

# Other classes
class --class ~.InsertTestData
class --class ~.OpenIdUserDetailsService

 

Testing the Roo generated code

At this stage we are able to test the Roo generated code. To do so, run mvn tomcat:run in a terminal and open up a browser to http://localhost:8080/openidlogin

In addition to configuring Spring security in applicationContext-security.xml, the Roo command security setup has also added an in-memory user-service with two example users. We may login with one of these users by browsing to http://localhost:8080/openidlogin/login (username “admin”, with a password of “admin”).

Test data (optional)

This InsertTestData class would normally be added to the test package and used to provide data for integration tests. As this application uses an in-memory database, it is convenient to use the same method to populate the database with basic data on each run.

@Component
@Configurable
public class InsertTestData implements
                    ApplicationListener {

    public static final String PASSWORD = "password";

    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        init();
    }

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    private void init() {
        if (!Employee.findAllEmployees().isEmpty()) {
            // don't do anything if there is data in the db
            return;
        }

        Employee employeeAdminActive = new Employee();
        employeeAdminActive.setUsername("user1");
        employeeAdminActive.setPassword(PASSWORD);
        employeeAdminActive.setUserRole(UserRole.ROLE_ADMIN);
        employeeAdminActive.setStatus(EmployeeStatus.ACTIVE);
        employeeAdminActive.persist();

        Employee employee2 = new Employee();
        employee2.setUsername("user2");
        employee2.setPassword(PASSWORD);
        employee2.setUserRole(UserRole.ROLE_USER);
        employee2.setFirstName("Peter");
        employee2.setLastName("Jones");
        employee2.setStatus(EmployeeStatus.ACTIVE);
        employee2.persist();

        Employee employee3 = new Employee();
        employee3.setUsername("user3");
        employee3.setPassword(PASSWORD);
        employee3.setUserRole(UserRole.ROLE_USER);
        employee3.setFirstName("Christina");
        employee3.setLastName("Applegate");
        employee3.setStatus(EmployeeStatus.RESIGNED);
        employee3.persist();
    }
}

 

The status of user with username user3 has been set to RESIGNED. We will use this user to test that disabled users are not able to login, and receive an error message when attempting to do so:

Your login attempt was not successful, try again. Reason: User is disabled .

Securing the application

At this point the application does not require a user to login in order to access any of its contents. For this example, we will assume that a user must login in order to access any pages other than the home and login pages. To achieve this, we may update the HTTP security configurations intercept-url elements in applicationContext-security.xml:

<intercept-url pattern="/**" access="isAuthenticated()" />

 

The home and login pages still need to be accessible to all users though, so we add a further two intercept-url elements before the “catch-all” property above:

<intercept-url pattern="/" access="permitAll" />
<intercept-url pattern="/login/**" access="permitAll" />

 

JDBC based UserDetailsService

As previously mentioned, be default Roo adds an in-memory user-service, which is useful for testing purposes, however in reality user details are usually stored in a database. To achieve this, we may configure a JDBC based UserDetailsService by replacing the in-memory UserDetailsService (<user-service>). Convention over configuration assumes the database is structured as show below.

default-schema-diagram

In this case, however, the employee table will hold the user details required, and we may simplify the schema by adding the user’s single authority (role) directly to the user (employee) table. This means that we also need to override the default queries that JdbcDaoImpl (the JDBC-based implementation of the UserDetailsService interface) uses.

<jdbc-user-service
    data-source-ref="dataSource"
    users-by-username-query=
                        "SELECT
                            U.username,
                            U.password,
                            U.status = 'ACTIVE'
                         FROM
                            employee U
                         WHERE
                            U.username=?"
    authorities-by-username-query=
                        "SELECT
                            U.username,
                            U.user_role as authority
                         FROM
                            employee U
                         WHERE
                            U.username=?" />

 

For simplicity we will remove the <password-encoder> element and use pain text passwords.

Running the application, we can now login using the credentials of one of the persisted users created in InsertTestData (e.g. user1, password)

Employees as Spring Security Users

As employees are the users in this application, we may wish to have the Employee class implement the Spring Security UserDetails interface. To do so, we must implement a few getter methods in Employee.java

@RooJavaBean
@RooToString
@RooEntity(
        identifierColumn = "employee_id",
        table = "employee",
        finders = { "findEmployeesByOpenIdIdentifier" })
public class Employee implements UserDetails {

. . .

@Override
public String getUsername() {
    return this.username;
}

@Override
public String getPassword() {
    return this.password;
}

@Override
public boolean isAccountNonExpired() {
    return true;
}

@Override
public boolean isAccountNonLocked() {
    return true;
}

@Override
public boolean isCredentialsNonExpired() {
    return true;
}

@Override
public boolean isEnabled() {
    return this.status == EmployeeStatus.ACTIVE;
}

@Override
public Collection getAuthorities() {
    Collection grantedAuthorities = new HashSet();
    grantedAuthorities.add(
            new GrantedAuthorityImpl(this.userRole.name()));
    return grantedAuthorities;
}

. . .

The getUsername() and getPassword() methods will conflict with those implemented in Employee_Roo_JavaBean.aj. If running, Roo will automatically correct this. If not, you may simply remove the methods from Employee_Roo_JavaBean.aj manually.

OpenID UserDetailsService

In order to provide the authentication-manager with a user based on an employee’s openIdIdentifier rather than username, we implement a custom service for loading user details. This will be used when authenticating OpenID logins instead of the JDBC based UserDetailsService previously configured, which will still be used for non-openid based logins.

public class OpenIdUserDetailsService implements UserDetailsService {
    public UserDetails loadUserByUsername(String openIdIdentifier) {
        List employeeList =
                Employee.findEmployeesByOpenIdIdentifier(openIdIdentifier).getResultList();
        Employee employee = employeeList.size() == 0 ? null : employeeList.get(0);
        if (employee == null) {
            throw new UsernameNotFoundException("User not found for OpenID: " + openIdIdentifier);
        } else {
            if (!employee .isEnabled()) {
                throw new DisabledException("User is disabled");
            }
            return employee;
        }
    }
}

Having implemented the UserDetails interface, we are now able to return Employee objects in the loadUserByUsername() method. A UserDetailsService should only be used to lookup the user and not perform any sort of validation, however in this example application it was is convenient place to check if the employee had been disabled.

Configuring OpenID login

Configuring OpenID login is now simply achieved by adding an <openid-login> element to the HTTP security configurations in applicationContext-security.xml:

. . .
<intercept-url pattern="/**" access="isAuthenticated()" />
<openid-login authentication-failure-url="/login?login_error=t" user-service-ref="openIdUserService" />
</http>
. . .

 

We must also configure the OpenIdUserDetailsService bean referenced by the <openid-login> element’s user-service-ref property. We will add this after the </authentication-manager> closing tag:

. . .
</authentication-manager>
<beans:bean id="openIdUserService" class="za.co.bsg.rnd.trf.openidlogin.OpenIdUserDetailsService" />
. . .

 

Updating the login screen

We may now add the markup for the additional login methods to the login screen (login.jspx). We will place it just after the existing </util:panel> closing tag:

  . . .
<spring:message code="button_reset" var="reset_label" />
        <input id="reset" type="reset" value="${fn:escapeXml(reset_label)}" />
      </div>
    </form>
  </util:panel>

  <spring:url value="/j_spring_openid_security_check" var="form_url_openid" />
  <spring:url var="google" value="/resources/images/google-account-logo.png" />
  <spring:url var="openid" value="/resources/images/openid-logo.png" />

  <util:panel id="title_google" title="Google Login" >
    <img src="${google}" style="float:right" />
    <p style="height:0.25em"/>
    <form action="${fn:escapeXml(form_url_openid)}" method="post">
        <input name="openid_identifier" size="50"
               maxlength="100" type="hidden"
               value="http://www.google.com/accounts/o8/id"/>
        <div class="submit">
           <input id="proceed_google" type="submit" value="Sign in with Google" />
        </div>
    </form>
    <br/>
    <p/>
  </util:panel>

  <util:panel id="title_openid" title="OpenID Login" >
    <a href="http://openid.net/get-an-openid/" target="_blank" title="Where do I get one?">
        <img src="${openid}" style="float:right" />
    </a>
    <p/>
    <form action="${fn:escapeXml(form_url_openid)}" method="post">
       <div>
            <label for="openid_identifier">OpenID</label>
            <input id="openid_identifier" name="openid_identifier" type="text" style="width:150px" />
        </div>
        <br/>
        <div class="submit">
            <input id="proceed_openid" type="submit" value="${fn:escapeXml(submit_label)}" />
        </div>
    </form>
  </util:panel>
  . . .

 

Google login

When logging in with Google, the user is not required to provide an OpenID identifier/URL. The reason for this is that Google’s implementation of OpenID is slightly different to that of most providers. Rather than assign user-friendly OpenID identifiers to users, Google expects that websites allowing OpenID login through Google will use the Google canonical OpenID provider URL (http://www.google.com/accounts/o8/id), and users will provide their credentials directly to Google. To make this simpler for the user , websites commonly provide a Sign in with Google button, which hides and invokes the Google OpenID provider. This will redirect the user to to Google, and thereafter once logged into their account, the user is warned that they are signing into another site:

Google Login

When attempting to login with Google for the first time, the user’s unique identifier will be returned, but has not yet been registered with the site, resulting in the error message:

Your login attempt was not successful, try again. Reason: User not found for OpenID: https://www.google.com/accounts/o8/id?id=AItOawm4b0mXXXXXXXXXXXXXXX3bGCztybYUwWQ .

The identifier returned is unique to the user for this applications domain only (i.e. it will be different for the same user for another application with a different domain). Copy this identifier, login using a users username and password, and edit an employee saving the identifier in the employee’s openIdIdentifier field. Finally, logout and try to login again using the same Google account.

Conclusions

Spring Roo is extremely well suited to R&D work, providing a quick means of setting up a project to explore OpenID login using Spring Security. Providing OpenID login may provide users with a useful alternative means of authenticating with your site and is simple to implement.

Further research posibilities

  • OpenID Attribute Exchange (AX) – is an extension for OpenID service which allows the transfer of various user related details/information/attributes between the relying party and the identity provider. Spring Security supports this directly.
  • OpenID user registration (no username and password stored in the application) – currently the application requires that a user already be registered before associating an OpenID with their account. A useful extension would be to enable users to register using their OpenID, and not maintain a username and password on the application.
  • Facebook authentication – Facebook is an OpenID relying party rather than a provider, however Facebook Connect may be used to allow users to use their Facebook identity to login to other sites. See also the Facebook developer documentation
  • OAuth vs OpenID – While OpenID is used by an application to authenticate its users, OAuth, a complimentary open standard to OpenID, may be used by an application to request permission from another application to share a user’s private resources (e.g. photos, videos, contact lists) without the user having to share their username and password (wikipedia).

References

Java Web Apps and Single Sign-On

4 Jan

Single Sign-On:

Essentially, single sign-on (SSO) is the process where the user is required to authenticate himself only once in order to gain access to multiple related but ultimately independent software systems. The most common case is when the user belongs to a domain (internal network) and is able to login using his account credentials where he subsequently gains access to network drives etc. without the need to re-authenticate himself.

I will be looking at possible ways to achieve SSO with a Java web app where users belong to a Windows domain and where the users (and their credentials) gets stored in a Windows Active Directory (against which authentication gets performed).

SSO Advantages:

  • Improved user productivity. Users are no longer bogged down by multiple logins and they are not required to remember multiple IDs and passwords. This also improves security as users find it easier to remember their credentials and do not have to write them down etc., allowing for a more efficient user login process
  • It improves an administrator’s ability to manage users and user configurations to all associated systems
  • It reduces administrative overhead in resetting forgotten passwords over multiple platforms and applications
  • It improves the effectiveness/timeliness of disabling all network/computer accounts for terminated users

SSO Disadvantages:

  • Unattended desktop. Implementing SSO reduces some security risks, but increases others. For example, a malicious user could gain access to a user’s resources if the user walks away from his machine and leaves it logged in. Although this is a problem with security in general, it is worse with SSO because all authorized resources are compromised. At least with multiple logins, the user may only be logged into one system at the time and so only one resource is compromised
  • It requires continuous availability of a central server. When the AD server is down, no one can log in
  • Since all authentication is controlled by a centralized AD server, compromise of this authentication infrastructure will allow an attacker to impersonate any user across all SSO supported systems
  • Hence the SSO server and other host security must be hardened

In order to gain access to network resources, authentication needs to happen in the background where authentication information ultimately has to be sent over to the Active Directory (AD) server. Thus  authentication protocols had to be developed to do this securely.

Authentication Protocols:

Kerberos Protocol:

Kerberos is a standardized network authentication protocol (developed by MIT), which is designed to provide strong authentication (by using secret-key cryptography) for client/server applications, such as web applications where the browser is the client. Essentially Kerberos is an authentication protocol for trusted hosts on untrusted networks.

Kerberos is an integral part of Windows Active Directory implementations and is the preferred authentication protocol when operating in a domain environment. Essentially every Windows Active Directory domain controller is also a Kerberos Key Distribution Center or “KDC”.

The protocol is currently sitting on version 5.

NT LAN Manage (NTLM) Protocol:

NTLM is a challenge-response based protocol. In a challenge-response protocol, the client generates a response using the server challenge and a secret value that the client and server both know (like a password) and sends it back for validation. Security features were added to the protocol in version 2 to provide for stronger protection of encryption keys and challenges.

Simple and Protected GSS-API Negotiation (SPNEGO) Protocol:

The Generic Security Service Application Program Interface (GSS-API) was developed on top of the Kerberos and the NTLM authentication protocols, where its development goal was to provide security developers with a consistent high-level programming interface for authentication and security without needing to know the details of a particular security protocol.

The wiring of GSS-API authentication to a web browser occurs through the use of a message exchange standard known as Simple and Protected GSS-API Negotiation Mechanism (SPNEGO). SPNEGO is an algorithm specifying the behaviour of two GSS-API implementations in determining whether they can communicate with each other over a common security protocol.

Quick Protocol Conclusion:

As it’s a very technical manner to weigh up the advantages and disadvantages of the Kerberos and NTLM authentication protocols against each other and because Kerberos is the industry standard, there is no need to further explain that Kerberos is indeed the preferred protocol to use. At the end of the day they will both achieve SSO but Kerberos will do so in a more secure manner. One thing to note though is that neither Kerberos or NTLM protocols send the user’s password over the wire, which is obviously a good thing as the no amount of network packet sniffing would result in the malicious user being able to impersonate an authenticated user.

Other Means to Authenticate Against Active Directory:

Lightweight Directory Access Protocol (LDAP):

LDAP is an application protocol for querying and modifying items in directory service providers such as Active Directory. Thus it can’t be considered as a solution to achieve SSO as the client/browser plays a large role in SSO and LDAP is simply a way for the application to talk to the AD server. That being said LDAP can be configured to securely communicate to the AD server so theoretically it can play a part in the SPNEGO Kerberos authentication process.

Implementing SSO in a Java Web App:

As all major browsers support the SPNEGO a.k.a. Negotiate protocol to achieve SSO and because the protocol is integrated by Windows Active Directory as part of their product – it became clear that this is the way to achieve SSO in a web app.

SPNEGO/Kerberos Libraries:

Windows Authentication Functional Framework Light Edition (WAFFLE):

Provides various ways to achieve SSO (via the Negotiate protocol) in a web application but is restricted to web applications sitting on web servers running on a Windows machine. Thus a no go as our web server runs on a Linux machine.

spnego.sourceforge.net:

The library is aimed at Java based web servers looking to handle SPNEGO/“Negotiate” (with preference to Kerberos over NTLM) as the authentication protocol, where SSO is ultimately achieved by configuring a Java Servlet Filter with all the necessary information to perform the authentication against the Active Directory (Key Distribution Centre).

Advantages:

Once the Kerberos environment has been correctly setup on the AD server with regards to the web server in question – SSO is relatively straightforward to achieve. It is also pretty lightweight as we’re essentially dealing with one filter. The project has got an active community/forum where the developer of the project is very actively taking part in discussions and troubleshooting.

Disadvantages:

It is not very configurable. For example in the Spring Security framework you can declare various “intercept-urls” which specifies what level of authentication the user needs to access the URL in question. It gives precedence to the top-most declaration thus if you specify that the “/login.jsp” URL requires no authentication to access and then specify that “/*” (all permutations of URLs) needs full authentication to access, it effectively excludes “/login.jsp” URL from the list of URLs that need full authentication. This behaviour is crucial as we obviously can’t expect a user to be authenticated before he had a chance to authenticate himself. Effort would be required to place this library (which is designed to sit on the web server) in the application as the web app also needs to confirm that the user exists in the web app (it’s not enough to know that the user merely exists on the domain). The web app also needs to know when negotiation/authentication fails as to provide a fallback method to authenticate the user, which this library doesn’t quite support (it provides basic authentication as a fallback but this protocol is unsecure).

Spring Security Kerberos/SPNEGO Extension:

The Spring team brought out an extension to their latest version of the Spring Security framework (version 3) that provides the security developer with a solution to achieve SSO via the SPNEGO/Kerberos protocol. The solution has been implemented in alignment with their existing security framework, thus a developer that is familiar with Spring Security would have no trouble in understanding the flow of the solution and would effectively be able to use it out of the box. To use this solution the web app would need to upgrade it’s core Spring framework to version 3 and it’s Spring Security framework to version 3. Version 3 of the Spring Security framework has significantly changed its package structure from version 2 which has enabled them to make the functionality that the framework provides much more modular.

Advantages:

The solution sits in the application and thus can easily confirm if the user exists in the web app upon successful authentication. As with the spnego.sourcefourge.net solution – SSO is relatively straightforward to achieve once the Kerberos environment has been correctly setup on the AD server with regards to the web server in question. As it is in alignment with the existing security framework – the solution is highly configurable. The extension to the Spring Security framework also provides a way to combine form-based authentication with the Kerberos protocol to securely authenticate the user against the Active Directory. Furthermore as the framework is so highly configurable, it is possible to use this as the fallback. Thus upon SSO authentication failure (ex if the user tries to access the web app from outside of the domain), the user can effectively be redirected to the login screen to enter his domain account credentials. Which is first prize.

Lastly the Spring Security framework has been widely adopted and has a very active community.

Disadvantages:

This extension library needs the latest Spring libraries, thus if an upgrade is necessary, then the package structure changes (and inevitable deprecations) would need to be catered for in existing security classes. Furthermore, a fair amount of systems testing would be required which is obviously not ideal.

Integrating a “Kerbeized” Web Application With an Openfire Chat Server:

Built in (Home Made) Java Chat Client:

Integration can be achieved once the user has been authenticated in the web app. All that would be required is an authenticated request from the web app to the Openfire server to login the user in question.  The whole concept of SSO is around the web app not storing the domain user’s password as the Kerberos/SPNEGO protocol doesn’t send the password across the wire when authenticating against the AD server.

My proposed solution to send the authenticated login request is as follows:

  • The web app and the Openfire server shares a private key and salt
  • The Openfire server stores a timestamp (upon server startup the timestamp gets created)
  • The web app upon making the login request (which requires a username and password), creates a timestamp (which would effectively be later on than the one stored by the Openfire server)
  • The web app then encrypts the timestamp with the private key and subsequently encrypts it again with the salt (thus double encrypted) and uses this result as the password (RSA encryption is probably a good bet)
  • The Openfire server then receives the request with the username and the double encrypted timestamp which it then decrypts as it knows the key and salt used to encrypt it
  • The Openfire server then compares the decrypted timestamp with its stored timestamp
  • Only if the decrypted timestamp is later on than the stored timestamp does the user get logged in
  • If successful, the stored timestamp subsequently gets set to the decrypted timestamp

This solution would effectively be secure against replay attacks (where a malicious user sniffs the request and uses it again to try and login) and relatively secure against brute force attacks (due to the double encryption). Note that the timestamp is accurate to the closest millisecond where it would be sent as a long. This solution assumes that the machines which host the web app and Openfire, to be closely synchronised in time.

External Chat Clients:

At this stage there isn’t a clear solution to achieve SSO with external chat clients as the SPNEGO/Kerberos authentication protocol essentially requires the client (in this case the external chat client) to speak this language/implement the protocol. It is also not recommended to let the external chat client send the user’s domain password over the wire as we don’t have any control over how the credentials gets sent, making it a high security risk. A potential work around could be to have the user specify a chat password in the web app (which would effectively be stored in the database) which the user could use to authenticate himself. At least if these credentials are obtained by a malicious user, it can’t be used to login to the web app or any system other than Openfire.

Conclusion:

In my opinion the Spring Security solution is the clear winner for achieving SSO in a Java web app. Its drawbacks are in actual fact a bit irrelevant as you would need to upgrade the Spring framework at some stage. At the time of writing I am unable to setup a Kerberos environment in the domain to test this SSO solution, thus at this stage the POC is riding on some assumptions:

  • That the main SSO solution does in fact work as expected (i.e. the user gets authenticated securely without the need to enter credentials). This assumption is quite solid as Spring has been widely adopted and the active Spring forum suggest that this functionality works as expected
  • That the fallback configuration works (upon authentication failure). This assumption is not really solid at this stage as it wasn’t provided by a recognised Spring developer, thus I will only be happy once I have confirmed it. This fallback solution was posted on the Spring forums: http://forum.springsource.org/showthread.php?p=326151#post326151

Sources:



Spring Roo – JEE’s own command line Visual Studio

1 Dec

Testing testing does this thing work? My first blog entry on BSG Dev :)

So what is this Spring Roo hype all about?

Last night decided to download Spring Roo and be cool like all the other kids. So while it download read up on Spring Roo Introduction. In summary:

  1. Spring Roo is a tool that helps rapidly building Java enterprise applications by generating the plumbing code such as data base connection.
  2. As a Java developer you should use it because:
    1. It increases your productivity by enabling you build Java enterprise applications in a best-practice manner within minutes.
    2. It uses standard Java technologies that are used in enterprise Java projects such as Spring Framework, Hibernate JPA implementation and GWT.
    3. It adds the technologies incrementally. e.g. Java Persistence API is only added when you request it.
    4. It allows you to choose which implementation of an API to use. You could choose to use GWT or Spring MVC and you can also choose which database your application will use.
    5. It is easy to use and learn. There is a TAB for auto completion and hint command that suggests what you might want to do.
    6. It only adds used dependencies to your project thus reducing size of deployed war / jar file.
    7. It uses annotation-based dependency injection, and automatically providing dependency injection on entities. This reduces xml and Java files to maintain.
    8. It is easy to remove.
    9. You could create a simple GWT application that saves data to database in 10 minutes!

Pre-Requisites

In order to install Roo you need the following technologies installed on your machine:

  1. Maven
  2. Java 5 / 6

10 Minutes GWT Application Test

Assuming that you have Roo installed the following commands would get you a GWT application that Stores contacts names and phone numbers in a mysql database.

  1. Create contacts database in mysql:
    1. mysql -u<<username>> -p<<password>>
    2. create database <<databaseName>>
    3. exit
  2. Create project directory:
    1. mkdir ten-minute-gwt
    2. cd ten-minute-gwt
  3. Use Roo to create the gwt project:
    1. roo
    2. project –topLevelPackage za.co.bsg.tenminute
    3. persistence setup –provider HIBERNATE –database MYSQL –userName <<username>> –password <<password> –databaseName <<databaseName>>
    4. entity –class ~.model.Contact
    5. field string –fieldName name –column nme –notNull
    6. field string –fieldName telephone –column telephone –notNull
    7. gwt setup
    8. exit
  4. Use maven to run application:
    1. mvn gwt:run
  5. Click launch in default browser to see  application.

Conclusion

There are other plumbing features of Roo that still need testing namely:

  1. SMTP
  2. Security
  3. JMS

References:

  1. http://static.springsource.org/spring-roo/reference/html/index.html
  2. http://www.bytespring.com/blog/spring-roo-integration-gwt

Sharing the knowledge

30 Nov

Welcome to the blog of the developers at BSG, a business and software solutions company that strives to be the best in what they do.

This blog particularly highlights the software solutions side and focuses on sharing the knowledge to the development communities ranging from Java, .NET, Web Development and many more technologies or other various interesting discoveries and experiments.

Stay tuned and please feel free to participate in the conversation, let us know if you agree- disagree and talk about it.

Follow

Get every new post delivered to your Inbox.