Create an anonymous authentication module

Use a CAPTCHA-based authentication module for J2EE Web applications

The Web application landscape is constantly evolving. What started off as a simple means of sharing documents and information has quickly evolved into a platform for conducting business. Authentication and authorization are critical features for these applications. The landscape has evolved again, and we have returned to community-oriented applications like blogs and wikis. Since authors solicit comments and reader feedback, authentication is not the most critical feature for these applications. In some cases, the fear of identification deters potential contributors. The absence of authentication, however, results in its own set of problems: spam. Sample a few messages found on the Web:

  • "I suppose wiki spam is inevitable. I've set up the wiki part of this site to be fairly open to changes to encourage readers and visitors to interact, but now for the second time a spammer has dropped a bunch of links to some Chinese Websites onto the pages." From X-Pollen.
  • "Note to all wiki spammers: As of 1-2-2005 no changes to this wiki, either by editing or adding new pages, will be picked up by search engines until 10 hours have passed. All spam on this site is usually deleted in minutes, an hour at the most, so it is now pointless to try to add spam of any type to this wiki." From C2 Wiki.

Clearly, spam must be addressed. Most of these malicious attacks happen when the spam-bots are able to figure out data submission patterns. One option for stopping such attacks is to present a challenge that can only be passed by humans and not computers. Enter Turing tests. Named after the famous scientist Alan Turing, these tests determine the capability of machines to perform human-like operations. One of the most famous styles is CAPTCHA(an acronym for completely automated public Turing test to tell computers and humans apart). CAPTCHAs frequently appear as images of fuzzy or distorted letters and numbers that humans can read and respond to, but automated optical-character-recognition software have trouble identifying.

Figure 1 shows a typical CAPTCHA.

Figure 1. A sample CAPTCHA

Already, most of the major service providers (Yahoo, Hotmail, Google) are using CAPTCHAs on their free applications, which, to some extent, help them fight spam and fake registrations. In this article, we explore a method for adding CAPTCHA-based authentication to our own Web applications.

First, let's quickly look at the J2EE Web application security model.

J2EE security model

Security has been one of the focus areas guiding Java's development. Needless to say, J2EE has adopted the same principles and provides a robust framework for building secure applications. Security in J2EE applications is a vast topic that I can't cover in detail here. Several excellent resources cover this topic in detail. I strongly recommend that teams and developers spend time familiarizing themselves with these concepts. For this article, I present a 20,000-foot view of some of the key concepts.

Key concepts

Security in J2EE applications can be enforced by using either a declarative approachor a programmatic approach.

As the name suggests, when using the declarative approach, an application developer defines an application's security constraints outside the application code. These declarations are made in deployment descriptors (web.xml, ejb-jar.xml), and the container's runtime environment guarantees their enforcement. Declarative security allows developers to:

  • Restrict access to resources only to principals with given roles (e.g., "/admin/*" is restricted to the "administrator" role)
  • Restrict access to URLs only on certain protocols (e.g., "/customer/*" is only accessible via HTTPS)
  • Restrict access to servlets only to principals with given roles (e.g., SiteShutdownServlet is restricted to the "god" role)
  • Restrict individual methods on EJB (Enterprise JavaBeans) components only to principals with given roles (e.g., PurchasingEJBis restricted to the "customer" role)
  • Automatically redirect users to login page when they request a restricted resource, but have not yet logged into the system

On the other hand, the programmatic approach provides mechanisms for calling and querying the security infrastructure. The developer must enforce these constraints. The programmatic approach helps to:

  • Retrieve the principal associated with the current authenticated user: HttpServletRequest.getUserPrincipalor EJBContext.getCallerPrincipal
  • Query if the user has been assigned a specific role: HttpServletRequest.isUserInRole(String role)or EJBContext.isCallerInRole(String role)

Both these approaches have their own limitations and hence complement each other.

Declarative security for Web applications

Declarative security for Web applications is passive in nature. This means that only on initial access to the protected resource by an unauthenticated client, is the user forwarded to the login page. If the user is already authenticated and has the necessary authorization (role), he or she is allowed to access the resource.

One of the most common approaches to declarative security in Web applications is to use form-based authentication. The Web application deployment descriptor web.xml declares all the necessary elements required for such configuration in two sections.

The first section is common to the entire Web application. It identifies:

  • The login method that needs to be used (auth-method). J2EE supports the following authentication mechanisms BASIC, DIGEST, FORM, or CERT.
  • The login and error page for form-based authentication (form-login-config).
  • Superset of all roles that can be used in the application (security-role).

Figure 2 shows the key elements of the first section and their relationships.

Figure 2. Application-wide security configuration. Click on thumbnail to view full-sized image.

The second section identifies resource-specific constraints. The deployment descriptor can contain zero or more of the following declarations:

  • The section of the site that needs to be protected. This is configured using the url-pattern element within web-resource-collection.
  • The roles that have permission to access this resource (auth-constraint). These roles are generally a subset of roles declared in the first section.
  • The transport guarantees associated with accessing a resource (user-data-constraint).

Figure 3 shows the second section's key elements and their relationships.

Figure 3. Resource-specific security configuration. Click on thumbnail to view full-sized image.

Let's walk through a sample web.xml:

                    

<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN" "http://java.sun.com/J2EE/dtds/web-app_2_2.dtd">

< web-app>

< !-- ... -->

< !-- Define the security constraint. This will limit the /admin/* portion of the application to only be accessible to users within the "admin" role. When an unauthenticated user attempts to access this section of the site, they will be automatically presented with the login page. --> <security-constraint>

< !-- Define the context-relative URL(s) to be protected --> <web-resource-collection> <web-resource-name>Protected Area</web-resource-name> <url-pattern>/admin/*</url-pattern> <http-method>GET</http-method> <http-method>POST</http-method> </web-resource-collection>

< !-- Define the roles that are allowed to access this URL with the given methods --> <auth-constraint> <role-name>admin</role-name> </auth-constraint>

< !-- Transport guarantee could be used to guarantee an HTTPS protocol --> <user-data-constraint> <transport-guarantee>NONE</transport-guarantee> </user-data-constraint>

< /security-constraint>

< !-- Define the method for authenticating a user when requesting a restricted page. Methods include BASIC (the simple pop-up dialog), FORM and CERTIFICATE. --> <login-config> <!-- We will use form based authentication --> <auth-method>FORM</auth-method> <realm-name>Default Realm</realm-name>

< !-- where should the user be forwarded to enter his credentials --> <form-login-config> <form-login-page>/login/login.jsp</form-login-page> <!-- On error the user will be shows this page It can also server side forward back to the login page, which is popular behavior for most sites. --> <form-error-page>/login/error.jsp</form-error-page> </form-login-config> </login-config>

< !-- Finally a list of all security roles in the application must be given. --> <security-role> <description>Capable of administrating the site</description> <role-name>admin</role-name> </security-role> </web-app>

The sample deployment descriptor contains the following security configuration:

  • Restrict access to URLs that begin with the pattern /admin/*(url-pattern)
  • The resources under /admin can only be accessed using HTTP GET or POST (http-method)
  • The resources can be served over a normal HTTP connection (transport-guarantee)
  • Only users belonging to the "admin" role can access these resources (role-name)
  • Remote users are authenticated using form-based authentication (auth-method)
  • The users will be shown a login page—/login/login.jsp—for entering credentials (form-login-page)
  • If any errors occur during authentication, users will be shown an error page—/login/error.jsp (form-error-page)

So far, I have covered the key concepts of the J2EE security model. Let's now look at ways to extend a container's security infrastructure.

Extending a container's security infrastructure

JAAS(Java Authentication and Authorization Services) implements a version of Pluggable Authentication Modules (PAM) for Java applications. It allows parallel development of authentication technologies and enterprise applications. Application developers can choose from these options and configure them for their applications. JAAS has several benefits since it allows parallel development of authentication technologies and promotes its reuse across different applications.

JAAS brings the same value to the application server landscape. However, JAAS has not achieved the same success in the J2EE space. Until recently, application servers exposed custom APIs for extending out-of-the-box security infrastructure. But things are changing. Application servers now provide adaptors for integrating custom JAAS login modules to a security infrastructure. This integration is still application-server-specific and the complexity varies widely.

Tomcat provides a relatively easy and straightforward integration with JAAS. The custom login modules are configured using configuration files (Tomcat realm configuration and the standard JAAS configuration). When the server needs to call the login module, it routes all the calls through the org.apache.catalina.realm.JAASRealmadaptor. For more details on integrating JAAS authentication with Tomcat, refer to Resources.

In this article, we implement a JAAS login module and later integrate it with the Tomcat server to provide a J2EE security solution.

Solution

Before proceeding to the implementation aspects, let's understand our solution's goals and the approach.

Our goals are as follows:

  • Provide a weak authentication mechanism for Web applications. Weak authentication means that the authentication module or the application doesn't differentiate one remote user from another. Once authenticated, all the users have similar roles.
  • Forgo a unique identifier for every user of the system (login name). This guarantees anonymity of the remote user.
  • The authentication mechanism should differentiate between computers and humans to prevent automated spam-bots from misusing the available resources. We will use CAPTCHAs for this test.
  • The authentication mechanism should be based on the J2EE security model. We will avoid other approaches that do not conform to this model.

Given the above goals, obviously, we need to certify only that every session belongs to a human user. Application servers maintain sessions to preserve a user's state. When unauthenticated users access a protected resource, J2EE declarative security diverts them to the login page. The login page generates a unique CAPTCHA and associates it with the user's session. The login page then presents the CAPTCHA as an image and challenges the user to identify the image. The login page also has a hidden input field that contains the current session ID.

The user enters the challenge in the password field and submits the form. On form submission, the login module retrieves the session ID and the user's response. It then checks the response with the associated CAPTCHA. If these values match, the login module authenticates the user and assigns him the role "anonymous."

After authentication, the remote user can access all the protected resources constrained by the role "anonymous."

Figure 4 illustrates our approach.

Figure 4. Our approach. Click on thumbnail to view full-sized image.

Implementation

Implementing a new authentication mechanism is fairly straightforward. The entire process breaks down into the following four steps:

1 2 3 Page 1
Page 1 of 3