Friday, March 19, 2010

Shopping Cart Web Application - Bean Validation

Introduction
In my previous blog entry I wrote about adding security to the shopping cart web application. Part of the change I made to the application was adding a form to register users and a form to add and update items. It made sense to add validation to the fields so that we could maintain the integrity of our data.

I currently maintain two different versions of the application:
  • 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. 
  • ShoppingCartGF.zip – A JEE application that runs off GlassFish vs 3 and is built with EJB 3.0, JPA and RichFaces.

There are a number of different approaches one can take when doing validation. A common approach is using client side form validation which uses JavaScript to validate the form fields. There is no round trip to the server so the validation is nice and fast. The jQuery Javascript library has a nice plugin to use if you are interested in this approach. Even though client side validation is nice it isn't essential however server side validation is not an option and should be implemented to ensure data integrity. For the shopping cart application I decided to only use server side validation so that I was using a common validation implementation. In order to get the same user experience as client side validation I chose to use the Ajax JSF RichFaces library.

The validation  framework I have chosen to use is the standard validation framework (JSR 303: Bean Validation) implemented in Java EE 6. As of version 4.x Hibernate Validator is based on a new code base which is the reference implementation for JSR 303.

"JSR 303 defines a metadata model and API for JavaBean validation. The default metadata source is annotations, with the ability to override and extend the meta-data through the use of XML validation descriptors. The API is not tied to a specific application tier or programming model. It is specifically not tied to either the web tier or the persistence tier, and is available for both server-side application programming, as well as rich client Swing application developers."

What we will cover
  • Defining constraints
  • Custom validation
  • Spring injection into custom validators
  • Validating constraints
  • RichFaces Ajax validation for JSF inputs


Constraints
Constraints in Bean Validation are expressed via Java annotations. There are three different types of constraint annotations, namely: field, property, and class-level annotations. An example of property annotations can be seen in the User class:

@Column(name="username", nullable=false, unique=true)
@NotEmpty
@Length(min=4, max=12)
@Pattern(regexp="^[a-zA-Z\\d_]{4,12}$", message="{validator.username.invalid}")
@Username(message="{validator.username}")
public String getUsername() {
 return username;
}

The getter method for the username property specifies the following validation annotations:
  • @NotEmpty – The username cannot be null or empty.
  • @Length(min=4, max=12) – The length of the username must be at least 4 characters long and no more than 12 characters long.
  • @Pattern(regexp="^[a-zA-Z\\d_]{4,12}$", message="{validator.username.invalid}") – Match a regular expression. The username must contain alphanumeric characters. The default message is overridden with a key mapped to a message in the validation resource file. 
  • @Username(message="{validator.username}") – Custom validator to compares the usernames already stored in the database to check for duplicates.

An example of where I have used class-level annotation validation can be found in the Register.java JSF backing bean class:

@FieldMatch.List({
 @FieldMatch(first="password", second="confirmedPassword",
   message="{validator.fieldmatch.password}")
  })
public class Register extends BasePage {
 private Validator validator;
 private String password;
 private String confirmedPassword;

 @NotEmpty
 @Length(min=6, max=12)
 @Pattern(regexp = "(?=.*\\d)(?=.*[a-zA-Z]).{6,12}", message = "{validator.password.insecure}")
 public String getPassword() {
  return password;
 }

 public void validateUsername() {
  Set<ConstraintViolation<User>> constraintViolations = validator.validateProperty(getUser(), "username");
  if (constraintViolations.size() > 0) {
   String msg = constraintViolations.iterator().next().getMessage();
   addError(getUiUsername().getClientId(getFacesContext()), msg);
  }
 }
 
 public void validatePassword() {
  Set<ConstraintViolation<Register>> constraintViolations = validator.validateProperty(this, "password");
  if (constraintViolations.size() > 0) {
   String msg = constraintViolations.iterator().next().getMessage();
   addError(getUiPassword().getClientId(getFacesContext()), msg);
  }
 }
 
 public void validateConfirmedPassword() {
  Set<ConstraintViolation<Register>> constraintViolations = validator.validate(this);
  if (constraintViolations.size() > 0) {
   ConstraintViolation<Register> cv = constraintViolations.iterator().next();
   if (cv.getMessageTemplate().equals("{validator.fieldmatch.password}")) {
    addError(getUiConfirmedPassword().getClientId(getFacesContext()), cv.getMessage());    
   }
  }
 }
 
 ...
 
}

  • @FieldMatch – Custom cross field validation class-level annotation used to compare the values of two fields, namely password and confirmed password. 
  • @NotEmpty – The password cannot be null or empty.
  • @Length(min=6, max=12) – The length of the password must be at least 6 characters long and no more than 12 characters long.
  • @Pattern(regexp = "(?=.*\\d)(?=.*[a-zA-Z]).{6,12}", message="{validator.password.insecure}") – Match a regular expression. The password must contain alphanumeric characters. The default message is overridden with a key mapped to a message in the validation resource file. 

Custom Validators
As mentioned above I have two custom validators, namely Username and FieldMatch. Creating a custom validator is actually very simple and requires the following three steps:

  • Create a constraint annotation
  • Implement a validator
  • Define a default error message

I won’t go over this in too much detail as the Hibernate Validator documentation is pretty good and covers this nicely.

Username constraint annotation (Username.java)

@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(validatedBy=UsernameValidator.class)
public @interface Username {
 String message() default "Username already exists";
 Class<?>[] groups() default {};
 Class<? extends Payload>[] payload() default {};
}

Username validator (UsernameValidator.java)

public class UsernameValidator implements ConstraintValidator<Username, Object> {
 @Autowired
 private UserDao userDao;

 public void setUserDao(UserDao userDao) {
  this.userDao = userDao;
 }

 public void initialize(Username parameters) {
 }

 public boolean isValid(final Object value, ConstraintValidatorContext context) {
  try {
   User user = userDao.findByUsername((String) value);
   if (user == null) {
    return true;
   }
  } catch (Exception e) {
   e.printStackTrace();
  }
  return false;
 }
}

Spring injection
You will notice I am injecting the UserDao class into this validator using Springs @Autowired annotation. This is made possible thanks to Spring’s LocalValidatorFactoryBean class.

"By default, the LocalValidatorFactoryBean configures a SpringConstraintValidatorFactory that uses Spring to create ConstraintValidator instances. This allows your custom ConstraintValidators to benefit from dependency injection like any other Spring bean."

I only needed to add the following line of code to the shoppingcart-database.xml Spring bean configuration file in order to use the SpringConstraintValidatorFactory:

<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" />

The Register.java JSF backing bean mentioned earlier gets a reference to the Spring created Validator by declaring the managed property in the faces-config.xml:

<managed-bean>
 <managed-bean-name>pc_Register</managed-bean-name>
 <managed-bean-class>com.mydomain.shoppingcart.view.Register</managed-bean-class>
 <managed-bean-scope>request</managed-bean-scope>
 <managed-property>
  <property-name>shoppingViewHelper</property-name>
  <value>#{shoppingViewHelper}</value>
 </managed-property>
 <managed-property>
  <property-name>validator</property-name>
  <value>#{validator}</value>
 </managed-property>
</managed-bean>

ValidationMessages.properties
I created a ValidationMessages.properties file and saved it in my src folder of my project. Hibernate Validator uses this file to retrieve the messages used by the validators.

Tying it together with the user interface
The login-form.jspx page includes a form for registering users. Instead of explaining each input field I am only going to step through one of them (username) and explain the validation process for it:

<h:inputText id="usrnameInTxt" binding="#{pc_Register.uiUsername}" value="#{pc_Register.user.username}" label="usrnameOutTxt" tabindex="1">
 <a4j:support id="usrnameSpt" event="onblur" reRender="usrnameMsg" limitToList="true" action="#{pc_Register.validateUsername}" />
</h:inputText>
<rich:message id="usrnameMsg" for="usrnameInTxt" errorClass="error" />

The a4j:support tag is a RichFaces tag that provides Ajax support to JSF input fields. Here it defines that the validateUsername method in the Register backing bean will be invoked when the onblur event of the input text field is triggered.

public void validateUsername() {
 Set<ConstraintViolation<User>> constraintViolations = validator.validateProperty(getUser(), "username");
 if (constraintViolations.size() > 0) {
  String msg = constraintViolations.iterator().next().getMessage();
  addError(getUiUsername().getClientId(getFacesContext()), msg);
 }
}

As you can see from the above code the validator class in the validateUsername method invokes the validateProperty method. The single property username is validated and if any constraint violations are raised an error message is added to the FacesContext.

The RichFaces rich:message tag behaves the same way as the standard JSF h:message tag except it will auto re-render itself after an Ajax request.

RichFaces Ajax Validator
RichFaces also has an Ajax validator tag that ties nicely into Hibernate Validator. I use this tag in the Items Admin modal panel of the items.jspx page.

<h:inputText id="nameInTxt" 
 value="#{pc_Items.selectedItem.name}"
 label="nameOutTxt" tabindex="1">
 <rich:ajaxValidator event="onblur" />
</h:inputText>
<rich:message id="nameMsg" for="nameInTxt" errorClass="error" />

As you can see there are no a4j:support tags or validation methods that get called. RichFaces will create its own Validator instance and call the validate property methods automatically for you. This works pretty nicely in the above example however for the registration form we are not using this tag because the validator is created for us by the Spring LocalValidatorFactoryBean class.


Registration screen shot



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