Ditch Container-Managed Security To Create Portable Web Apps

Ditch Container-Managed Security To Create Portable Web AppsDo your web apps need to run in the servlet containers from different vendors?  How do you manage their vendor specific security settings?  I recently ran into this exact problem while developing StackHunter.  Like me, you probably started with container-managed security as you have many times before. The pain probably started after you tried deploying to your second or third container and got worse from there.  This is one of the problems with Java web apps — they aren’t portable between containers out-of-the-box.  You can’t just take a war file from one vendor’s container and deploy it to another without configuring the security handlers in that vendor’s unique way.  This article will show you how to replace the “standard” Java container-managed security with Spring Security to create a single, secure application that can be deployed to any servlet container.

 

The Container-Managed, Non-Portable Approach

The traditional container-managed approach uses the web.xml file to identify protected resources.  The file has one or more security-constraint sections that links resource paths with their required user roles.  It also has a login-config section that defines the type of authentication in use (BASIC, FORM, etc.), along with some of their settings.

My original web.xml looked something like this.

Vendor-Specific Settings

The above web.xml file contains all the cross-vendor parts of the standard approach.  However, it doesn’t say anything about “how” authentication actually takes place.  Will users to be authenticated against LDAP, a database, or web service?  Will it use a custom class or one provided by the container?

For this info, we have to turn to each vendor’s unique security setup.  Since StackHunter started on Tomcat, it required the following steps:

  1. Modify Tomcat’s server.xml file to a) define the security realm and b) tell Tomcat about the custom user and role classes.
  2. Create a JAAS login configuration file to specify the custom authentication provider class.
  3. Add a JVM param to tell Tomcat where to find the above JAAS login configuration file.

(You can read more about how to create a custom login module here: JAAS authentication in Tomcat example.)

Now multiply those steps by the 10+ servlet containers on the market.  Keeping up-to-date with all the servers’ security configs is not where we want to be spending our time.

The Spring Security, Portable Approach

The good news is that there are alternatives to the Java web security standard.  A few of the options are:

I went with Spring Security since it seems to have a lot of developer support and isn’t any more difficult than the others to set up.  Plus I was already using Spring for data access and other things.

Download Spring Jars

On a side note: if you’re not using Maven to build your project, you can download the latest Spring Framework and Spring Security jars at:

Programming in XML

While the Spring Framework is a great tool for building Java software, its philosophy of configuring beans outside of the code sometimes makes it too XML heavy my taste.  Let’s face it, configuration in large quantities is just another form of programming.  I also like being able to reason about the classes I’m using (and the flow of control) without having to look outside the class files.

With all that in mind, Spring Security still comes through with flying colors.  Even the configuration is just the right amount XML and indirection.

Here are the three steps you’ll need to replace container-managed security with Spring Security.

Step 1 – Create Your Custom AuthenticationProvider

Create a subclass of org.springframework.security.authentication.AuthenticationProvider.  The authenticate method should either:

  1. Return null if it doesn’t support authentication on the supplied object.
  2. Return an instance of org.springframework.security.core.Authentication if authentication is successful.
  3. Throw org.springframework.security.authentication.BadCredentialsException, DisabledException, or LockedException if authentication is unsuccessful.

If you’re currently using a JAAS login module, it should be pretty easy to migrate it to spring way.

In my case, the user service handled all the authentication details — like account locking, password hashing, etc. — which made it pretty easy to plug into the new Spring class.

 

Step 2 – Create Your Security Configuration

Create a new file named /WEB-INF/spring-security.xml similar to the one below.

The first set of tags (with the security="none" attribute) identify all the public, unsecured resource paths.  The intercept-url element inside http, associates resource paths to their required user roles.  And the form-login element sets the authentication type to form and identifies the page with the login form along with other paths.

All the specified paths are relative to the context root and the pattern attribute use ANT notation — where double asterisks (/**) means “include all sub-folders”.

The last few lines of this file sets the authentication provider to the class defined above.

Step 3 – Add The web.xml Hooks

The final step is to update the web.xml to:

  1. Remove all the old security-constraint and login-config tags.
  2. Load the security settings from the file above.
  3. Use the Spring servlet filter to intercept requests and handle authentication.

Make sure this servlet filter is placed above any other filters in your web.xml that expects authentication to have already occurred.

Just Package and Deploy, and Deploy

That’s all there is to it.  Just package the spring-security.xml file, your custom authenticator, and the Spring jars into your war and deploy.

Spring Security personally saved me lots of time documenting and maintaining the installation steps for each servlet container.  More importantly, it reduced my web app’s installation steps and removed a potential source of support issues.  I hope it does as well for you.
 

 

About Dele Taylor

Dele Taylor is the founder of StackHunter.com -- a tool to track Java exceptions. You can follow him on Twitter, G+, and LinkedIn.

5 Responses to “Ditch Container-Managed Security To Create Portable Web Apps”

  1. Excellent post! But why stop at security? Why not ditch even the container?? This seems to be the direction that Spring is heading and I’m loving it! 🙂 http://projects.spring.io/spring-boot/

  2. Your blog post hits the right nerve, but it’s not entirely correct.

    You ask about the how, and then go on to say you need server specifics. But Java EE has a standard method for the how. It’s called JASPIC and has been in Java EE since two major versions.

    See http://arjan-tijms.blogspot.co.uk/2012/11/implementing-container-authentication.html for more details.

    With JASPIC your login modules are fully portable between all full Java EE servers.

    • Thanks for the info on JASPIC/JASPI, it looks very promising.

      Unfortunately, it doesn’t seem to be supported by Tomcat, which is understandable, since it’s not a full Java EE server.

      There also doesn’t seem to be a standard way to configure it declaratively.

      I get why the “how” was excluded from web.xml, but having that option would have saved us a lot of headaches over the years.

Trackbacks/Pingbacks

  1. Ditch Container-Managed Security To Create Portable Web Apps | Dinesh Ram Kali. - July 8, 2015

    […] via Ditch Container-Managed Security To Create Portable Web Apps. […]