Thursday, March 18, 2010

Shopping Cart Web Application - Security

Introduction
Those of you who are familiar with the shopping cart application tutorial will be pleased to know I have finally added security to it. It was never my intention to add security to the shopping cart application as I felt it was a little out of the scope of what I was trying to achieve. However the application would never been complete unless security was added to it.

I currently maintain two different versions of the shopping cart application:
  1. ShoppingCartSecurity.zip – A standard web application that runs off Tomcat 6 and is built with Hibernate, Spring, JPA and RichFaces. This is an Eclipse archive file that contains two Eclipse projects. You should be able to import these projects into your Eclipse environment.
  2. ShoppingCartGF.zip – A JEE application that runs off GlassFish vs 3 and is built with EJB 3.0, JPA and RichFaces. This is also an Eclipse archive file that contains three Eclipse projects. You should be able to import these projects into your Eclipse environment as well.
If you would like to compile and deploy the above mentioned applications you will need the libraries that they reference. I haven't included the libraries in the downloads, however I have provided links to all the libraries I have used in the previous shopping cart tutorials. I am not going to mention all of them here so you will need to go through each tutorial in order to get them. Over and above those libraries you will also need the below mentioned ones as these are specific to this version of the application:

ShoppingCartSecurity application

ShoppingCartGF application


What we will cover
  • Form-based authentication
  • Deployment configuration
  • Login form
  • Security realms
  • Using authentication with SSL
  • New features added to the shopping cart application 


Form-based authentication
The most common authentication mechanism and the one I chose to implement for the shopping cart application is called form-based authentication. Users can navigate through unprotected areas of the website without requiring a password. Only when the user tries to access a protected page will they be redirected to  a login page.


  1. A client requests access to a protected resource.
  2. If the client is unauthenticated, the server redirects the client to a login page.
  3. The client submits the login form to the server.
  4. If the login succeeds, the server redirects the client to the resource. If the login fails, the client is redirected to an error page.


Deployment Configuration
To configure our application for form-based authentication we need to define the authentication method in our web deployment descriptor, which resources are protected and what security roles are used. Below is a snippet from the web deployment descriptor that depicts these changes:

<security-constraint>
 <web-resource-collection>
  <web-resource-name>protected</web-resource-name>
  <url-pattern>/secure/*</url-pattern>
  <http-method>GET</http-method>
  <http-method>POST</http-method>
  <http-method>HEAD</http-method>
  <http-method>PUT</http-method>
  <http-method>OPTIONS</http-method>
  <http-method>TRACE</http-method>
  <http-method>DELETE</http-method>
 </web-resource-collection>
 <auth-constraint>
  <role-name>administrator</role-name>
  <role-name>customer</role-name>
 </auth-constraint>
</security-constraint>
<login-config>
 <auth-method>FORM</auth-method>
 <realm-name>shoppingCartJDBCRealm</realm-name>
 <form-login-config>
  <form-login-page>/login.faces</form-login-page>
  <form-error-page>/error.faces</form-error-page>
 </form-login-config>
</login-config>
<security-role>
 <description>Administrators role</description>
 <role-name>administrator</role-name>
</security-role>
<security-role>
 <description>Customers role</description>
 <role-name>customer</role-name>
</security-role>

Security constraint
The security-constraint element defines the access privileges to a collection of resources using their URL mapping.
  • web-resource-collection - used to identify the resources in a web application to which a security constraint applies. In the above example the URL pattern /secure/* specifies that all resources in this application under the secure folder are protected.
  • auth-constraint - indicates the user roles that should be permitted access to this resource collection. 

Login config
The login-config element defines the authentication method (namely form-based authentication) as well as the page that will be displayed when an unauthenticated user tries to access secure content and the page that will be displayed when login fails. For the GlassFish version of the application the realm name is defined to specify which realm configured on the server should be used when authenticating users.

Security role
The security-role element specifies the role a user can belong to.

Login form
The login page can be an HTML page, a JSP page, or a servlet, and it must return an HTML page containing a form that conforms to specific naming conventions. The login page needs to contain a form with j_security_check as its action as well as a text input box called j_username and a password input box called j_password. These are the input names that need to be used in order for the application server to process the Form authentication. An example of how this is implemented can be seen in the login-form.jspx page:

<h:panelGrid id="loginGrd" columns="2">
 <h:outputText id="usernameOutTxt" value="#{msg.login_txt_username}" />
 <input id="usernameInTxt" type="text" name="j_username" />
 <h:outputText id="passwordOutTxt" value="#{msg.login_txt_password}" />
 <input id="passwordInTxt" type="password" name="j_password" />
 <f:facet name="footer">
  <input type="submit" value="#{msg.btn_login}" />
 </f:facet>
</h:panelGrid>

Realm
A realm is a repository of user names and passwords that identify valid users of a web application along with the list of roles associated with each valid user. There are a number of different realms one can configure, in our example I chose to configure a JDBC realm where the users name and authentication details are stored in a database. Each application server is unique in its configuring of realms. Below are the steps I took to configure Tomcat and GlassFish:

Tomcat
In order to add a realm to Tomcat you need to edit the server.xml file, for our example I added the following realm to the server.xml:

<Realm className="org.apache.catalina.realm.JDBCRealm" 
   connectionName="sa" 
   connectionPassword="" 
   connectionURL="jdbc:hsqldb:hsql://localhost:9001/shoppingcart" 
   debug="99" 
   digest="MD5" 
   driverName="org.hsqldb.jdbcDriver" 
   roleNameCol="role_name" 
   userCredCol="password" 
   userNameCol="username" 
   userRoleTable="user_role" 
   userTable="users"/>

GlassFish
To configure a realm in GlassFish login to the GlassFish administration console and navigate to: Configuration -> Security -> Realms. Click on the new button and complete the form as shown in the screen shot below:


This assumes a datasource with the JNDI name jdbc/__shoppingcart has already been configured.

GlassFish requires its own deployment descriptor (sun-web.xml) to be configured in order to map the roles defined in the web applications web.xml file to the groups defined on the application server:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sun-web-app PUBLIC "-//Sun Microsystems, Inc.//DTD 
GlassFish Application Server 3.0 Servlet 3.0//EN" 
"http://www.sun.com/software/appserver/dtds/sun-web-app_3_0-0.dtd">
<sun-web-app>
 <security-role-mapping>
  <role-name>customer</role-name>
  <group-name>customer</group-name>
 </security-role-mapping>
 <security-role-mapping>
  <role-name>administrator</role-name>
  <group-name>administrator</group-name>
 </security-role-mapping>
</sun-web-app>

Using Authentication with SSL
Form-based authentication alone is not particularly secure, passwords sent between a client and a server on an unprotected session can be viewed and intercepted by third parties. In order to prevent this from happening you would need to configure your connections to run over an SSL (Secure Socket Layer) protected session. SSL is a technology which allows web browsers and web servers to communicate over a secured connection. This means that the data being sent is encrypted by one side, transmitted and then decrypted by the other side before processing. 

Usually you wouldn't have to configure your application server for SSL as you most likely would have a primary web server running that is used to handle all requests and responses from the browser to the server. The web server will therefore be configured to handle the SSL connections from the users. This web server will negotiate all SSL related functionality and then pass on any requests destined for the application server only after decrypting those requests. 

I haven't configured the shopping cart application to run over SSL. If you would like to learn more here are some useful links to get you started:


New features added to the shopping cart application 
The following additional features not mentioned above were added to the shopping cart application
  1. Three new entity classes, namely User, Role and UserRole
  2. User registration
  3. Item administration
  4. Once logged in an administrator can maintain the items list by adding, editing and removing items


Additional settings
Tomcat
  1. In order to get JSTL to work in Tomcat 6 I followed the instructions outlined in this tutorial.
  2. In the previous examples of the shopping cart application I used an in-memory database. However in this version I am not. The reason is because Tomcat would sometimes not find any user results and sometimes it would. It is a mystery to me as the Tomcat server and my application runs within the same JVM so it should be using the same database right? I lost patience and reverted to a file based database. I use an ant build script to start and stop the HSQL database. The file is called db-man-build.xml and can be located in the build folder. 
  3. The applications administrator's user name is 'admin' and the password is 'admin'. These values along with the default collection of items will automatically be imported into the shoppingcart database on application startup. 

GlassFish
  1. I configured a Derby database to use with the GlassFish version of the application. You can start and stop the Derby database by running the asadmin start-database or asadmin stop-database commands from the bin directory in the GlassFish installation directory. 
  2. The database will need to be pre-populated with data manually as this doesn't get done automatically by the application. The import sql script can be located in src folder of the shopping-cart-core-gf project. 


Screen shots
Registration modal with login form in the background


Items administration modal page with the landing page in the background


No comments: