Thursday, 29 April 2010

Java Web Application Security - Part Two, Form Based Authentication

In Part One of this series on Java Security, we made our "add-new-book.jsp" page accessible only to those logged in as administrators. At present, we're using so-called "BASIC Authentication" which in essence is asking the browser to handle the login challenge.

This is acceptable in some applications, but in general it is rather weak. The login box presented by the browser is very basic. Let's look at how it looks on Firefox first.


Basic but functional. Particularly cute is the challenge: "The site says 'Please log in'". Recall that 'Please log in' was the string we used in the <realm-name>. Yet Google Chrome presents our <realm-name> differently:

Ugly. BASIC Authentication is ok for quick and dirty apps, but we can do better. We'll now upgrade to "Form Based Authentication". To do this, we provide a JSP page with a username/password box.

Step 1: Write the Login Form

I won't bother writing a pretty form - I'll leave it to you to make it look gorgeous.

File: login.jsp

<h1>Please Login</h1>

<form method="post" action="j_security_check">
 <p><label>Username:</label> <input type="text" name="j_username"/></p>
 <p><label>Password:</label> <input type="password" name="j_password"/></p>
 
 <input type="submit" value="Login"/>
</form>

Note firstly the name of the action - j_security_check. I haven't made this name up - it's a part of the Java Web standard, and is a predefined servlet. It is responsible for performing the authentication check.

Also part of the standard are the two parameters that the security check servlet demands - j_username and j_password.

Now the form is built, we need one further JSP (or HTML) page. If the user fails to login correctly, we need to tell them they have failed, so we need a "failed login" page.

File: failed-login.jsp

<h1>Sorry, please try again</h1>

Again, I'll leave it to you to make this page look good!

Step 2: Configure

We now need to upgrade our web.xml to point to our form and failure page. As always, the XML is a bit verbose but routine...

File: web.xml

<login-config>
   <auth-method>FORM</auth-method>
   <form-login-config>
      <form-login-page>/login.jsp</form-login-page>
      <form-error-page>/failed-login.jsp</form-error-page>
   </form-login-config>
</login-config>

Don't forget to remove your existing <login-config> with the BASIC <auth-method>.

Step 3: Test

The most important thing to remember is that we don't need to navigate to the login page directly. As before, we try to navigate to the "add-new-book.jsp" page, and the server now knows that before access is allowed, the login.jsp page must be presented first.

So let's deploy and see what happens - the screenshot shows what happens when we navigate to "add-new-book.jsp".
Notice that the URL in the browser bar is the name of the target page, even though it is actually login.jsp that has been presented.

And after we type invalid credentials into the form...
So, thanks to the predefined j_security_check servlet, you can get a reasonable security system up and running in a Java Web Application without writing a single line of code. Remember that this is all part of the standard and will work on any server you choose to use.

At the moment, our usernames and passwords are hardcoded into a file on Tomcat. This is fine for development but we need better for production.

There are actually many different ways you can authenticate users - using single sign on, Facebook Authentication, OpenID and so on, but the most common approach at first would be to provide a database table of usernames and passwords.

I could talk in detail about how to do this, but it is specific to your application server and it is fairly well documented by most servers.

If you are using Tomcat, then the documentation for setting up your table is available here

Don't be put off by the term "Realm". A Realm is just a "strategy for authenticating users".

Tuesday, 27 April 2010

Java Web Application Security - Part One, Basic Authentication

One topic that we didn't cover in the Java Web Development course was how to secure your application.  In this post, I'll show that every Java webserver comes with a basic security model that will address many project's requirements.

I'll assume that you're already familiar with Java Web development, and are able to build and deploy to a server such as Apache Tomcat.

Let's start with a regular webapp. Any Java web application will do. I'm using the application we build on the Java Web Development course.
At the moment, all users can access every page in the application. The aim is for the page "add-new-book.jsp" to be accessible to logged-in administrators only.

Step 1: Switch security "on"

The first step is to declare in the web.xml file that we want to use security in our application. We're going to start with the simplest form of web security, BASIC authentication. You'll be familiar with this even if you don't realise it - this is where the browser pops up a simple username and password box.


   BASIC
   Please log in


"realm-name" is just a string that will appear in the login dialog box.

This config tells Tomcat to instruct your browser to pop up a username/password challenge if a secured resource is accessed.

Step 2: Declare Your Secure Resources

A secured resource is just a URL, and we declare a URL to be secure with the following addition to web.xml:

 
  Admin Pages
  /add-new-book.jsp
 

 
  admin
 
 
It's rather verbose XML (as usual with web.xml), but it is fairly straightforward. The URL ending with "add-new-book.jsp" will require the user is logged into the role of "admin".

Now we've added this protection, let's deploy the app and try to add a new book.



As we haven't set up a valid administrator, whatever we enter here will result in failure. This is reported as a HTTP error status 401, and by default we see the following page:



Step 3: Authentication

So we've locked down part of our app - but how can we open it up to the administrators?

Authentication is the mechanism a web site uses to determine who the user is and to which role they belong. unfortunately, authentication is not part of the Java web specification, so different servers implement authentication in different ways. I'll describe how authentication is done in Tomcat - for other servers such as Resin or Jetty, you'll need to check their reference manuals.

The easiest way to set up users and roles in tomcat is to edit the file in {tomcat_home}/conf/tomcat-users.xml. I've edited the contents of the file to look like this:

<tomcat-users>
   <role rolename="admin"/>

   <user username="rich"
         password="TooCoolForSchool" 
         roles="admin"/>
</tomcat-users>

So the server will recognise a user called "rich" as being a member of the "admin" role.

After making the edit, we then need to restart Tomcat. We can now visit the page add-new-book.jsp - as long as we enter the username and password above. Notice that it isn't necessary to implement a separate login page or to have to go to a login page first - when we try to visit the protected resource, the process is handled automatically by Tomcat.

You may be horrified that we have hardcoded a user into a file on the server. Of course, in a real application we would want a more sophisticated authentication strategy such as a database lookup. In part three of the series I'll show you how to do that on Tomcat. But changing the strategy is just a configuration change, so using this hardcoded file of usernames and passwords is perfect for your development environment. You can always switch to something more robust once you go live.

The next problem is that the login dialog box is not very professional looking. Basic authentication is just that - basic. In part two of this series, I'll be showing you how to add Form Based Authentication to your web app.