Sunday, April 13, 2014

Conditional bean validation using Hibernate Validator

In this post, we’ll see how to achieve conditional bean validation in a few steps using Hibernate Validator.

Thorough explanation on how to implement bean validation is out of this article's scope, so the reader is assumed to already have practical experience with bean validation (aka JSR-303).


Example use case

Suppose we have a bean of type ContactInfo.java that stores user contact information. For simplicity sake, we consider it only holds a country, a zip code and a phone number. Depending on the user’s country we may want the zip code to be mandatory or optional.

Here’s our bean:

package domain;

import javax.validation.constraints.NotNull;

import validationgroup.USValidation;


public class ContactData {
 private Country country; // ENUM indicating the user's country

 private String zipCode;

 private String phoneNumber;

 public ContactData(Country country, String zipCode, String phoneNumber) {
  this.country = country;
  this.phoneNumber = phoneNumber;
  this.zipCode = zipCode;
 }

 public Country getCountry(){
  return this.country;
 }
 
 public String getZipCode() {
  return zipCode;
 }
 
 public String getPhoneNumber() {
  return phoneNumber;
 }
 
}

Step 1 - Define a validation group

Create a marker interface. This will be used as an identifier to a group of validation rules:


public interface USValidation {

}

Step 2 - Add validation rules to our validation group

Add the @Null annotation on the zipCode getter as follows:


@NotNull(message="Zip code is mandatory", groups={USValidation.class})
 public String getZipCode() {
  return zipCode;
 }

The groups attribute specifies the group(s) to which the validation rule belongs to.

Step 3 - Configure the validator

Tell the validator object to apply the validation rules from our group, in addition to the default ones (which are the validation rules with no groups attribute specified).

There are actually two ways to configure the validator:

Solution A 

The simplest way is when we got a reference to the validator object. In that case, we just need to pass it the bean instance to validate, plus the interface that corresponds to the group we defined at step 1.


ContactData cd = new ContactData(Country.US, null, null);
Set<ConstraintViolation<ContactData>> validationResult = validator.validate(cd);
Assert.assertEquals(validationResult.size(), 0);

Solution B 

In case we don’t get a reference to the validator object  (for instance, when we rely on the @Valid Spring annotation to trigger bean validation from within a Controller), we can define a custom Sequence Provider to specify which are the validation groups that must be applied.

To define a custom Sequence Provider, we just need to create a class that implements the DefaultSequenceProvider interface. This interface exposes a single method that returns a list of classes that correspond to the validation groups we want to apply. 

NOTE: the class type of the bean we want to validate must be added to the returned list. Otherwise an exception like the following is thrown:

domain.ContactDataBis must be part of the redefined default group sequence.

This behavior ensures that the underlying validator object will get the default validation rules at the very least.

Here’s our custom Sequence Provider:

public class ContactDataSequenceProvider implements DefaultGroupSequenceProvider<ContactData>{
 
 
 public List<Class<?>> getValidationGroups(ContactData contactData) {
  List<Class<?>> sequence = new ArrayList<Class<?>>();
  
  /*
   * ContactDataBis must be added to the returned list so that the validator gets to know
   * the default validation rules, at the very least.
   */
  sequence.add(ContactDataBis.class);
  
  /*
   *  Here, we can implement a certain logic to determine what are the additional group of rules
   *  that must be applied. 
   */
  if(contactData != null && contactData.getCountry() == Country.US){
   sequence.add(USValidation.class);
  }
  
  return sequence;
 }

}


Once our custom sequence provider is defined, we just need to annotate the bean class with @GroupSequenceProvider like this:

@GroupSequenceProvider(value = ContactDataSequenceProvider.class)
public class ContactDataBis extends ContactData{

 public ContactDataBis(Country country, String zipCode, String phoneNumber) {
  super(country, zipCode, phoneNumber);
 }
 
}

Based on this, the validator will look for the validation groups it should apply by executing the getValidationGroups method from our Sequence Provider.

Source code

Source code and running examples (unit tests) are available here.

Saturday, August 17, 2013

Spring: injecting properties file values into Spring managed beans

In this post, we'll go through 3 different ways to configure (XML based) a Spring application, to inject properties file values into its managed beans.

Method 1: <util:properties> schema based configuration element

In the Spring configuration file, import the spring-util schema, then use the <util:properties> element to register a bean of type java.util.properties. This element expects both an id, and a location attribute. The former is necessary to determine from which Properties bean the value we want to inject comes from, while the latter is expected to define which properties file is to be loaded in the Properties bean.

Once a Properties bean has been defined, its values can be injected into Spring managed beans with the following annotation: @Value("#{properties_bean_id[property_name]}")

Example:

Content of the prop1.properties file:


message1=Message from prop1.properties


Spring configuration: 


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
 xmlns:util="http://www.springframework.org/schema/util"
 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
  http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
  http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.2.xsd">

 <context:component-scan base-package="example1" />

 <util:properties id="propSource" location="classpath:/sample-properties/prop1.properties" />
</beans>

Property value injection into Spring managed bean:

@Value("#{propSource[message1]}")



Method 2: <context:property-placeholder> schema based configuration element


This time, in the Spring configuration file, import the spring-context schema, then use the <context:property-placeholder> element to register a bean of type org.springframework.beans.factory.config.PropertyPlaceholderConfigurer. Just like in the previous method, this element expects the location attribute that specifies the properties file to load.

To retrieve a property value, use the syntax as follows: ${property_name}

Example:

Content of the prop2.properties file:

message2=Message from prop2.properties

Spring configuration:


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
  http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd">

 <context:component-scan base-package="example2" />

 <context:property-placeholder location="classpath:/sample-properties/prop2.properties"/>
</beans>



Property value injection into Spring managed bean:

@Value("${message2}")


Method 3: registering bean of type PropertyPlaceholderConfigurer


In this last method, we just have to explicitly register a bean of type org.springframework.beans.factory.config.PropertyPlaceholderConfigurer. Then, we'll need to specify a location property that determines the properties file to be loaded.

The syntax used to retrieve property values is exactly the same as method 2, that is: ${property_name}

Example:

Content of prop3.properties file:

message3=Message from prop3.properties

Spring configuration:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
 xmlns:util="http://www.springframework.org/schema/util"
 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
  http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd">

 <context:component-scan base-package="example3" />
 
 <bean id="propSource" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
  <property name="location" value="classpath:/sample-properties/prop3.properties" />
 </bean>
</beans>



Property value injection into Spring managed bean:

@Value("${message3}")

Extra example: defining multiple PropertiesPlaceholderConfigurer (PPC) beans + PPC with multiple properties files




 
 
 
  
  
 
 
 
  
   
    classpath:/sample-properties/prop2.properties
    classpath:/sample-properties/prop3.properties
   
  
 

To define a PropertyPlaceholderConfigurer bean to load multiples properties files, we use the locations property and set its value to a list of properties files.

Another thing we must pay attention to, is when we are defining multiple PropertyPlaceholderConfigurer beans within a same Spring context (in this example, we're defining 2 of them). In this case, we need to specify the ignoreUnresolvablePlaceholders property in the first PPC bean(s) with the value true. Otherwise, the application context will fail to load as Spring, at bean build time, tries to inject a value that resides in a properties file that is to be loaded in another PPC bean. 

More precisely, in this example: the Component4 class expects value injection from prop1.properties, prop2.properties and prop3.properties files. When trying to inject the values from prop2.properties and prop3.properties, the placeholders could not be resolved yet as they depends on the second PPC bean. Therefore, using the ignoreUnresolvablePlaceholders property on the first PPC bean will prevent exceptions from being thrown, and we'll just wait for another PPC bean to be able to inject these values.

Working source code

A sample project to test the different methods we've just went through is available here 

Sunday, April 7, 2013

Spring: implementing the Factory pattern

Although Spring, in itself, is already an example implementation of the Factory pattern (any Spring application's application context is just a giant Factory, right!), from time to time, we would like to implement this same pattern in our application logic just to keep our code clean and tidy. Let's see how we can do this, by a short example:

1 Defining an interface for the classes to be instantiated through the factory
Let's say we're working on a Spring application that handles document printing. For a given document, it is able to print it in either A4 or A5 format and either portrait and landscape layout. Each of these printing strategies extends a common interface :

package strategy;

import model.Document;

public interface IPrintStrategy {
 public void print(Document document);
}

Here are the concrete implementations for each printing strategy. To keep this example simple, each concrete printing strategy will only indicates what it is supposed to to:


package strategy;

import model.Document;

import org.springframework.stereotype.Component;

@Component("A4Landscape")
public class PrintA4LandscapeStrategy implements IPrintStrategy{

 @Override
 public void print(Document document) {
  System.out.println("Doing stuff to print an A4 landscape document");
 }

}


package strategy;

import model.Document;

import org.springframework.stereotype.Component;

@Component("A5Landscape")
public class PrintA5LandscapeStrategy implements IPrintStrategy{

 @Override
 public void print(Document document) {
  System.out.println("Doing stuff to print an A5 landscape document");
 }

}


package strategy;

package strategy;

import model.Document;

import org.springframework.stereotype.Component;

@Component("A4Portrait")
public class PrintA4PortraitStrategy implements IPrintStrategy{

 @Override
 public void print(Document document) {
  System.out.println("Doing stuff to print an A4 portrait document");
 }

}



package strategy;

import model.Document;

import org.springframework.stereotype.Component;

@Component("A5Portrait")
public class PrintA5PortraitStrategy implements IPrintStrategy{

 @Override
 public void print(Document document) {
  System.out.println("Doing stuff to print an A5 portrait document");
 }

}

For now, just note that each printing strategy interface is annotated as being a Spring component with a certain name. 

2 Defining the factory class interface
Now, we'll have to define an interface that is to be implemented by the factory class through which we will retrieve printing strategies:


package strategy;

public interface PrintStrategyFactory {
 
 IPrintStrategy getStrategy(String strategyName);
}

As you can see, the factory class will get a strategy name as input and will return an instance of IPrintStrategy.

3 Defining the Spring application configuration




 
 
  
  
 
 
 
 
 
 
 


In this configuration file:
  • we specify the package to scan for spring component detection (here, it's the "strategy" package)
  • we declaratively define a bean of type "ServiceLocatorFactoryBean" that will be the Factory.
  • we also define, and that's optional, name aliases, so that a same printing strategy could be retrieved either by the name specified in the @Component annotation, or by the alias.
4 Testing our example
With the following test class, we can check that everything works as expected:


import model.Document;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
import org.testng.annotations.Test;

import strategy.PrintStrategyFactory;


@ContextConfiguration(locations = {"classpath:/spring-config.xml"})
public class SpringFactoryPatternTest extends AbstractTestNGSpringContextTests{
 
 @Autowired
 private PrintStrategyFactory printStrategyFactory;
 
 @Test
 public void printStrategyFactoryTest(){
  Document doc = new Document();
  
  printStrategyFactory.getStrategy("DEFAULT").print(doc);
  printStrategyFactory.getStrategy("A5L").print(doc);
  printStrategyFactory.getStrategy("A5P").print(doc);
  printStrategyFactory.getStrategy("A5Portrait").print(doc);
 }
}

For instance, when we ask the factory class to give us the printing strategy answering to the name "DEFAULT", we'll end up with an instance of  "PrintA4PortraitStrategy" as "DEFAULT" is an alias for the spring component with name "A4Portrait". 

From there, I believe you got how it works. If not, feel free to checkout the source code and execute the test class, and you'll grasp the whole concept in the blink of an eye.

5 Source code
The whole source code of this example is available here (github)

Sunday, December 9, 2012

Spring MVC (Security): custom authentication manager and login page

In the previous post, we've implemented basic authentication and authorization features, mainly relying on the login page that Spring security generates. However, most of the time, we'll want to have our own login page as well as a custom authentication manager (having all the usernames, passwords, and roles hardcoded in the  web.xml file is definitely not a good solution!). Let's see how we could achieve that. As we use the project from this previous post as starting point, feel free to check out it source code here.


Tools and libraries
  • Eclipse Indigo
  • Spring-core 3.1.1
  • Spring-security 3.1.0
  • Tomcat 7
  • Maven 3
STEP 1 - Creating the custom login page

In our example, we'll create a login page, named "myLoginPage.jsp"  that is actually quite similar to the one that Spring Security generates   except that we'll add a logout button:

<%@ taglib prefix="s" uri="http://www.springframework.org/tags"%>
<%@ taglib prefix="security"
 uri="http://www.springframework.org/security/tags"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="sf" uri="http://www.springframework.org/tags/form"%>
<div id="loginPannel">
 <security:authorize access="!isAuthenticated()">
  <h1>This is my custom login page</h1>
  
  <c:if test="${loginFailed}">
   <div style="color: red">Could not sign in, please check your login/password...</div>
  </c:if>  

  <form method="post" class="signin" action="j_spring_security_check">
   <table>
    <tr>
     <th><label for="username_or_email">Username/email</label></th>
     <td><input id="username_or_email" name="j_username" type="text" /></td>
    </tr>
    <tr>
     <th><label for="password">Password</label></th>
     <td><input id="password" name="j_password" type="password" /></td>
    </tr>
    <tr>
     <th></th>
     <td><input name="commit" type="submit" value="Sign In" /></td>
    </tr>
   </table>
  </form>
 </security:authorize>
</div>

Note the following line in our JSP page: <security:authorize access="!isAuthenticated()">
It specifies that this page is restricted to user that aren't authenticated. Access rules can be defined using expressions which correspond to the methods (such as, hasRole( ), hasAnyRole( ), ...) from the "SecurityExpressionRoot" provided by Spring.

STEP 2 - Customizing login page

In this step, we edit the Spring configuration file "MyDispatcherServlet-servlet.xml", to override some behavior of Spring default security configuration:

 <security:http auto-config="true" use-expressions="true"> 
  <security:form-login login-page="/login.go" default-target-url="/home.go" authentication-failure-url="/login.go?errorLogin"/> 
  <security:intercept-url pattern="/home.go" access="hasRole('ADMIN')" /> 
  <security:logout logout-success-url="/home.go" />
 </security:http>


  • use-expression="true": allows us to use expression such as hasRole(...), hasAnyRole(...), isAuthenticated( ), and so on, to define access rules
  • login-page="/login.go": defines the URL at which the login page is located
  • default-target-url="/home.go": defines the URL toward which the user will be redirected once he successfully logged in
  • authentication-failure-url="/login.go?errorLogin": defines the URL toward which the user will be redirected when the login fails. In our example, we redirect the user to the login page with an additional "errorLogin" parameter in the URL. This existence of this parameter will be checked in a Spring Controller class. If it exists, an attribute will be added to the model before returning the view to be displayed. Within the JSP page, we check this model attribute to eventually display an error message. 
  • <security:intercept-url pattern="/home.go" access="hasRole('ADMIN')" />: indicates that the "/home.go" URL is subject to access rules.
  • <security:logout logout-success-url="/home.go" />: defines the URL at which the user is redirected after he logged out.
STEP 3 - Defining a custom authentication provider

In most cases, we'll store user credentials and roles in a DB, LDAP, you name it, and consequently, we'll want authentication and authorization to be performed against that user repository. In this example, we'll configure an authentication provider as if we were storing the user credentials in a DB.

To do so, we edit the Spring configuration file "MyDispatcherServlet-servlet.xml" and define a custom Spring service (here, it's named "myUserDetailService") as authentication provider:

 <security:authentication-manager>
  <security:authentication-provider
   user-service-ref="myUserDetailService">
  </security:authentication-provider>
 </security:authentication-manager>

STEP4 - Implementing the custom authentication provider


  • First, we have to create a class that implements the GrantedAuthority interface from Spring. This interface will have us implement a getAuthority( ) method that returns a role name.
Ex:

package service.security;

import org.springframework.security.core.GrantedAuthority;

public class GrantedAuthorityImpl implements GrantedAuthority{
 private static final long serialVersionUID = 1029928088340565343L;

 private String rolename;
 
 public GrantedAuthorityImpl(String rolename){
  this.rolename = rolename;
 }
 
 public String getAuthority() {
  return this.rolename;
 }

}


  • Then, we create a class that implements the UserDetails interface from Spring. This class will hold all the account-related info such as the user credentials and the associated roles.
package service.security;

import java.util.Collection;
import java.util.HashSet;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

public class UserDetailsImpl implements UserDetails{
 private static final long serialVersionUID = -6509897037222767090L;
 
 private Collection authorities = new HashSet();
 private String password;
 private String username;
 
 public UserDetailsImpl(String username, String password, Collection authorities){
  this.username = username; 
  this.password = password;
  this.authorities = authorities;
 }

 public Collection getAuthorities() {
  return this.authorities;
 }

 public String getPassword() {
  return this.password;
 }

 public String getUsername() {
  return this.username;
 }

 public boolean isAccountNonExpired() {
  return true;
 }

 public boolean isAccountNonLocked() {
  return true;
 }

 public boolean isCredentialsNonExpired() {
  return true;
 }

 public boolean isEnabled() {
  return true;
 }

}

  • Finally, we create a class that implements the UserDetailsService interface from Spring. This interface contains only one method: UserDetails loadUserByUsername(String username). In our example, we emulate a DB user repository by defining a Map whose keys are usernames, and values are UserDetails objects. Pay attention to the static initialization block in which we populate this map with 3 users.
Remark:

If we actually had user credentials stored in DB, we would just have to implement a repository class, and inject it into this class.
package service.security;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

@Service("myUserDetailService")
public class UserDetailsServiceImpl implements UserDetailsService{
 
 // just to emulate user data and credentials retrieval from a DB, or whatsoever authentication service
 private static Map<String, UserDetails> userRepository = new HashMap<String, UserDetails>();
 
 static{
  GrantedAuthority authorityAdmin = new GrantedAuthorityImpl("ADMIN");
  GrantedAuthority authorityGuest = new GrantedAuthorityImpl("GUEST");
  
  /* user1/password1 --> ADMIN */
  Set<GrantedAuthority> authorities1 = new HashSet<GrantedAuthority>();
  authorities1.add(authorityAdmin);
  UserDetails user1 = new UserDetailsImpl("user1", "password1", authorities1);
  userRepository.put("user1", user1);
  
  /* user2/password2 --> GUEST */
  Set<GrantedAuthority> authorities2 = new HashSet<GrantedAuthority>();
  authorities2.add(authorityGuest);
  UserDetails user2 = new UserDetailsImpl("user2", "password2", authorities2);
  userRepository.put("user2", user2);
  
  /* user3/password3 --> ADMIN + GUEST */
  Set<GrantedAuthority> authorities3 = new HashSet<GrantedAuthority>();
  authorities3.add(authorityAdmin);
  authorities3.add(authorityGuest);
  UserDetails user3 = new UserDetailsImpl("user3", "password3", authorities3);
  userRepository.put("user3", user3);
 }
 
 public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
  UserDetails matchingUser = userRepository.get(username);
  
  if(matchingUser == null){
   throw new UsernameNotFoundException("Wrong username or password");
  }
  
  return matchingUser;
 }

}


  • In the Controller class, we add the two following URL mapping. As as result, GET requests for /login URL will display the custom login page, while requests for the same URL with the "errorLogin" parameter will display the same custom login page with an additional "loginFailed" model attribute. This attribute is checked in the JSP page, to display an error message, if neccessary.
 @RequestMapping(method=RequestMethod.GET, value="/login")
 public String displayLoginPage(){
  return "myLoginPage";
 }
 
 @RequestMapping(value="/login", params="errorLogin")
 public String directToLoginPageWithError(Model model){
  // Adding an attribute to flag that an error happened at login
  model.addAttribute("loginFailed", true);

  return "myLoginPage";
 }

Testing the application

  • Custom login page:
  • Login with bad credentials


  • Login with user1/password1
  • Login with user2/password2

In this last case, user2 is authenticated but not authorized to access the home.go page. In the Spring configuration "MyDispatcherServlet-servlet.xml" file, we specified that the home.go page is restricted to user with role ADMIN with the following configuration element:

<security:intercept-url pattern="/home.go" access="hasRole('ADMIN')" /> 

Source code

The source code of this example application can be checked out here.

Sunday, December 2, 2012

Spring MVC: implementing authentication and authorization using Spring security

In this post, we'll go through the few steps that will allow you to implement both authentication and authorization security features in a Spring MVC application.

We'll use the Spring MVC demo application we've developed in a previous post as starting point. Feel free to take a look at it   first (here's the post), if you want to follow the steps below one at a time.

You'd rather get down to business right away? Here are the sources of this application (pick the master branch).

Tools and libraries
  • Eclipse Indigo
  • Spring-core 3.1.1
  • Spring-security 3.1.0
  • Tomcat 7
  • Maven 3

STEP 1 - Adding necessary Maven dependencies

In order to use Spring Security, we'll need to add the following dependencies in our pom.xml configuration:
  • spring-security-taglibs
  • spring-security-config
  • standard
  • jstl
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 <modelVersion>4.0.0</modelVersion>
 <groupId>Spring-MVC-Tutorial</groupId>
 <artifactId>Spring-MVC-Tutorial</artifactId>
 <packaging>war</packaging>
 <version>0.0.1-SNAPSHOT</version>

 <properties>
  <spring-version>3.1.1.RELEASE</spring-version>
  <spring-security-version>3.1.0.RELEASE</spring-security-version>
 </properties>

 <build>
  <plugins>
   <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-war-plugin</artifactId>
    <version>2.2</version>
    <configuration>
     <!-- specifiy which directory within the project hierarchy will be considered 
      as the root directory from the generated war file -->
     <warSourceDirectory>WebContent</warSourceDirectory>
    </configuration>
   </plugin>
  </plugins>
 </build>

 <dependencies>
  <!-- Spring Core -->
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-core</artifactId>
   <version>${spring-version}</version>
  </dependency>
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-context</artifactId>
   <version>${spring-version}</version>
  </dependency>
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-webmvc</artifactId>
   <version>${spring-version}</version>
  </dependency>
  <!-- Spring security -->
  <dependency>
   <groupId>org.springframework.security</groupId>
   <artifactId>spring-security-taglibs</artifactId>
   <version>${spring-security-version}</version>
  </dependency>
  <dependency>
   <groupId>org.springframework.security</groupId>
   <artifactId>spring-security-config</artifactId>
   <version>${spring-security-version}</version>
  </dependency>
  <!-- standard.jar -->
  <dependency>
   <groupId>taglibs</groupId>
   <artifactId>standard</artifactId>
   <version>1.1.2</version>
  </dependency>
  <!-- JSTL -->
  <dependency>
   <groupId>javax.servlet</groupId>
   <artifactId>jstl</artifactId>
   <version>1.2</version>
  </dependency>
 </dependencies>
</project>

STEP 2 - Enabling Spring Security in the web application configuration

  • Once we add Spring Security features, unlike basic Spring MVC applications (in which, by default, the DispatcherServlet initialization will look for a file named [servlet-name]-servlet.xml in the WEB-INF directory), we'll need to explicitly define a ContextLoaderListener listener as well as a context parameter named contextConfigLocation whose value is the relative path to your Spring configuration file, in the web.xml file.
Here's the added part:

 <listener>
  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
 </listener>

 <context-param>
  <param-name>contextConfigLocation</param-name>
  <param-value>
      /WEB-INF/MyDispatcherServlet-servlet.xml
  </param-value>
 </context-param>


  • Then, yet in the web.xml file, we'll add Spring security filter definition so that requests that are sent to our dispatcher servlet will first be intercepted by this security filter so that authentication/authorization can be checked against the request content, origin, and so on. At the same time, we'll define an URL mapping to this security filter to specify which requests we want to have the security filter intercept and process.
Here's the added part:
 
  springSecurityFilterChain
  org.springframework.web.filter.DelegatingFilterProxy
 

 
  springSecurityFilterChain
  /*
 
We are now done with the web.xml file and it looks like this:


 Spring MVC tutorial

 
  org.springframework.web.context.ContextLoaderListener
 

 
  contextConfigLocation
  
      /WEB-INF/MyDispatcherServlet-servlet.xml
  
 

 
  MyDispatcherServlet
  org.springframework.web.servlet.DispatcherServlet
 

 
  MyDispatcherServlet
  *.go
 

 
  springSecurityFilterChain
  org.springframework.web.filter.DelegatingFilterProxy
 

 
  springSecurityFilterChain
  /*
 

STEP 3 - Configuring Spring Security


In this step, we'll edit our Spring configuration file (that we've defined as being the MyDispatcherServlet-servlet.xml file back at the step 2), and configure the security features we want to use, that is, we'll configure authentication through a login page, and authentication through access right that the user must have in order to access a certain page.
Starting from the MyDispatcherServlet-servlet.xml file we created in the basic Spring MVC application tutorial, here are the added parts:

 <security:http auto-config="true">
  <security:intercept-url pattern="/home.go" access="ROLE_REGISTERED_USER"/> 
  <security:logout logout-success-url="/home.go"/>
 </security:http>
 
 <security:authentication-manager>
  <security:authentication-provider>  
   <security:user-service>
    <security:user name="user1" password="demo" authorities="ROLE_REGISTERED_USER" />
    <security:user name="user2" password="demo" authorities="ROLE_FREE_USER" />
   </security:user-service>
  </security:authentication-provider>
 </security:authentication-manager>

  • By defining the auto-config attribute value to true in the <security:http> element, we are using the default security features that are provided by Spring Security libraries, that is, it provides us, among others, a default login page and access rights checking
  • In the <security:intercept-url> element, we specify the URLs whose access should be restricted to users with the role(s) that we specify in the access attribute. In this example, we are basically saying that a user should be authenticated (he must log in through the default login page) and hold the ROLE_REGISTERED_USER role in order to access the "home.go" page.
  • With the <security:authentication-manager> element, we can specify how (directly querying a DB, providing a custom authentication/authorization service, through LDAP, ...)
    • username and password are retrieved to perform authentication checking
    • roles are retrieved to perform authorization checking
    In this example, we simply hard coded the usernames, their associated password and roles directly in the Spring configuration file.
Here's the whole Spring configuration file:


 
 
 

 
 

 
  
   
   
 
 
 
   
  
 
 
 
    
   
    
    
   
  
 


STEP 4 - Testing
Remark: in order to make the resulting application easier to test, we'll add a logout button to the page to be displayed, as follows:


<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
 pageEncoding="ISO-8859-1"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>




Spring-MVC-Tutorial


 Welcome my Spring-MVC-Tutorial homepage
 "> Logout


Case 1 - Unauthenticated user

Once the application is deployed, try to access the home.go page and you'll be redirected to the default login page.



Case 2 - Wrong credentials

Try to login with wrong credentials: you'll be redirected to the login page but take a closer look to the address bar. See the  "spring_security_login?login_error"? This is the default behavior of Spring security when relying on its generated login page, to redirect the user to the login page and the login_error parameter is used to detect that the previous login attempt failed, so an error message must be displayed.



Case 3 - Authenticated and authorized user


On the login page, log in using the following credentials user1/demo. As the "user1" user has the ROLE_REGISTERED_USER role that is required to access the home.go page (remember the roles we've defined at step 3?), you'll be successfully directed to the required home.go page.


Case 4 - Authenticated but unauthorized user

From the previous page, click on the logout link to get back to the login page, then log in with the credentials user2/demo. As user2 only has the ROLE_FREE_USER role, we'll get an HTTP 403 ERROR page indicating that the user is not authorized to access the required page.


Sources

The source code of this example project is accessible here.

Thursday, July 12, 2012

Spring MVC + Hibernate: testing the persistence layer (DAOs) with TestNg

Whenever you're working on a Spring MVC project, you might want to unit tests each single layer of your application. In this post, we'll see how we can perform unit testing on the persistence layer, using TestNg. More specifically, we'll go through unit testing a persistence layer that is built upon a DAO pattern, implemented using Hibernate.

DAO classes
The DAO classes that we are going to test in this example are structured like this:


As general CRUD methods are implemented in the GenericDaoImpl abstract class, we'll consider that our UserDaoImpl class is empty, in order to keep things simple:

@Repository
public class UserDaoImpl extends GenericDaoImpl<user, long=""> implements UserDao {
 // methods specific to this concrete DAO
}



As you can see, this class is annotated with @Repository, which registers it as a "Repository" type Spring bean.

Spring configuration

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns:tx="http://www.springframework.org/schema/tx"
 xmlns:context="http://www.springframework.org/schema/context"
 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
  http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
  http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">

 <context:component-scan base-package="be.glimmo">
 
 <!-- Enabling annotation-driven transaction management -->
 <tx:annotation-driven />

 <!-- Hibernate SessionFactory -->
 <bean id="sessionFactory"
  class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
  <property name="dataSource" ref="dataSource" />
  <property name="hibernateProperties">
   <props>
    <!-- Use the C3P0 connection pool provider -->
    <prop key="hibernate.c3p0.min_size">5</prop>
    <prop key="hibernate.c3p0.max_size">20</prop>
    <prop key="hibernate.c3p0.timeout">1800</prop>
    <prop key="hibernate.c3p0.max_statements">50</prop>
    <prop key="hibernate.c3p0.idle_test_period">300</prop>
    <prop key="hibernate.dialect">org.hibernate.dialect.DerbyDialect</prop>
    <prop key="hibernate.hbm2ddl.auto">create-drop</prop>

    <!-- Show and print nice SQL on stdout -->
    <prop key="show_sql">true</prop>
    <prop key="format_sql">true</prop>
   </props>
  </property>
  <property name="packagesToScan" value="be.glimmo.domain" />
 </bean>

 <!-- Defining a transaction manager bean (used for annotation-driven transaction 
  management -->
 <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
  <property name="sessionFactory" ref="sessionFactory" />
  <property name="dataSource" ref="dataSource" />
 </bean>

 <!-- Defining the Datasource bean -->
 <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
  <property name="driverClassName" value="org.apache.derby.jdbc.ClientDriver" />
  <property name="url" value="jdbc:derby://localhost:1527/glimmo-testdb" />
  <property name="username" value="glimmo" />
  <property name="password" value="password" />
  <property name="minIdle" value="5" />
  <property name="maxActive" value="10" />
  <property name="defaultAutoCommit" value="false" />
 </bean>
</beans>

An important thing here: make sure you specify a "dataSource" bean. Although we would usually declare a bean with the ID "dataSource", when working with Spring, just know that it is also possible to have Spring properly configured without this kind of bean. Nevertheless, configuring unit testing with TestNg simply requires us to declare this bean. More (we'll see why, later).

TestNg test class
Now, let's take a look at an example of test class that will allow us to test each single method of our DAO:


@Test
@ContextConfiguration(locations={"classpath:Glimmo-context-test-configuration.xml", "classpath:Glimmo-persistence-test-configuration.xml"})
public class TestUserDaoDummy extends AbstractTransactionalTestNGSpringContextTests{
 
 // TestNg Data Providers
 Object[][] users = new Object[][]{
   new Object []{"user1", "user1@test.com", "user_firstname", "user_lastname", 
     UserGrade.ADMIN, "password", null}
 };
 
 @DataProvider(name="usersProvider")
 public Object[][] provideUsersForCreation(){
  return users;
 }
 
 @Autowired
 private UserDao userDao;
 
 @Test(dataProvider="usersProvider")
 @Rollback(false)
 public void testUserCreation(String username, String email, String firstName, String lastName, UserGrade userGrade, String password, Date gradeEnd) {
  User newUser = new User(username, email, firstName, lastName);
  newUser.setGrade(userGrade);
  newUser.setPassword(password);
  userDao.save(newUser);
  
  Assert.assertNotEquals(super.countRowsInTable("USERS"), 0);
 }
}



There are 2 important things to pay attention to, here:

  • Have the test class extends AbstractTransactionalTestNGSpringContextTests
The AbstractTransactionalTestNGSpringContextTests class helps you manage the transactional aspects when testing the methods from the DAO class (as a matter of fact, it sets the @Transactional annotation at class level, so that you don't need to worry about transactions when writing your test methods). It also provide convenience methods (based upon the underlying SimpleJdbcTemplate instance...) to query the DB, such as executeSqlScript(...) and countRowsInTable(...). This class expects a bean with the ID "dataSource". That's the reason why I said on the previous section that our Spring configuration has to specify such a bean.



  • Annotate your test class with @ContextConfiguration
This annotation is provided by Spring for test purposes and allows you to load Spring configuration file. This annotation supports several ways to specify which configuration to load but its "locations" attribute is likely the easiest and most used one: we just have to provide a comma separated list of String values. Each of them , referring to a Spring XML configuration file that needs to be loaded in order to initialize the Spring application context. In the example, I prefixed each reference with "classpath:" meaning that the configuration files will be retrieved from the classpath of my project (since I'm working on a Maven based project, I simply put them in the src/test/resources directory).

Now, you're able to wire the DAO classes (as long as they're registered as Spring beans) into you test class, and test every single of their methods. VoilĂ !

Tuesday, May 29, 2012

A quick tutorial to Spring-MVC with Maven

In this post, we'll see how to get started with a Spring MVC project in a few steps.

Tools

  • Maven 3
  • Tomcat 6
  • Eclipse Helios/+
    • m2eclipse plugin
    • Spring IDE plugin

1 Creating the web project

First, let's create a Dynamic Web Project : 


Name it Spring-MVC-Tutorial and specify Tomcat 6 as the web server on which the application will be deployed:


And click on FINISH.

Now, in order to enable Maven support, create the following directories under the src directory : 
  • main/java
  • main/resources
  • test/java
  • test/resources
As the src directory actually is a source directory, once you've created the mentioned sub directories, these will look like packages, at first:


Then, right-click on the project and choose Maven -> Enable dependency management. This will open a Wizard in which you'll be able to configure Maven related information such as the group ID, the artifact ID, and so on. Following this tutorial, simply keep the default values and click on FINISH.

Now, our project has become a Maven-based project, which looks like this : 


2 Adding Spring Maven dependencies

In the pom.xml file, add the following dependencies, so that Maven retrieves the libraries necessary to a Spring-MVC project : 
  • spring-core
  • spring-context
  • spring-webmvc
As soon as you've added these dependencies, you could see that Maven has automatically downloaded the related libraries and added them to the project's classpath : 


Here's what our Maven configuration file looks like :

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 <modelVersion>4.0.0</modelVersion>
 <groupId>Spring-MVC-Tutorial</groupId>
 <artifactId>Spring-MVC-Tutorial</artifactId>
 <packaging>war</packaging>
 <version>0.0.1-SNAPSHOT</version>

 <properties>
  <spring-version>3.1.1.RELEASE</spring-version>
 </properties>

 <build>
  <plugins>
   <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-war-plugin</artifactId>
    <version>2.2</version>
    <configuration>
     <!-- specifiy which directory within the project hierarchy will be considered 
      as the root directory from the generated war file -->
     <warSourceDirectory>WebContent</warSourceDirectory>
    </configuration>
   </plugin>
  </plugins>
 </build>  

 <dependencies>
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-core</artifactId>
   <version>${spring-version}</version>
  </dependency>
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-context</artifactId>
   <version>${spring-version}</version>
  </dependency>
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-webmvc</artifactId>
   <version>${spring-version}</version>
  </dependency>
 </dependencies>
</project>

Note that we have added the "maven-war-plugin" to specify that at the WAR file generation, the "WebContent" directory should be considered as being the web application root directory.

3 Configuring the DispatcherServlet

A Spring-MVC project follows the "Front controller" pattern : we'll define a servlet based on Spring's DispatcherServlet class. This servlet serves as "front controller" and will handle incoming requests. It will then dispatch them to the appropriate controller classes, based on each request's URL.

Let's define the servlet : in the web.xml file (which is located in WebContent/WEB-INF):


<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
 id="WebApp_ID" version="2.5">
 <display-name>Spring MVC tutorial</display-name>
  
 <servlet>
  <servlet-name>MyDispatcherServlet</servlet-name>
  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
 </servlet>
 
 <servlet-mapping>
  <servlet-name>MyDispatcherServlet</servlet-name>
  <url-pattern>*.go</url-pattern>
 </servlet-mapping>
</web-app>

As you can see, in our example, we've mapped all incoming requests with the ".do" extension to be handled by the servlet named "MyDispatcherServlet", which is the front controller to our application.

4 Spring context configuration

Now, we'll create the Spring configuration XML file : under the WEB-INF directory, create a new Spring configuration file. As we've installed the Spring IDE plugin, (this plugin is very handy when it comes to Spring configuration as it provides, among other things, some auto-completion and validation), right-click -> New -> Other -> Spring -> Spring Bean configuration file

By default, with a Spring-MVC project, Spring will look for a Spring configuration file that is named as follows : [DispatcherServlet's name]-servlet.xml
So in our case, we'll name our Spring configuration file : MyDispatcherServlet-servlet.xml

Here's the content of our Spring configuration file : 


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns:context="http://www.springframework.org/schema/context"
 xmlns:mvc="http://www.springframework.org/schema/mvc"
 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
  http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
  http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd">
 
 <!-- Enabling Spring beans auto-discovery -->
 <context:component-scan base-package="controller" />

 <!-- Enabling Spring MVC configuration through annotations -->
 <mvc:annotation-driven />

 <!-- Defining which view resolver to use -->
 <bean class= "org.springframework.web.servlet.view.InternalResourceViewResolver" > 
  <property name="prefix" value="/WEB-INF/views/" /> 
  <property name="suffix" value=".jsp" /> 
 </bean>
</beans>

  • We have enabled Spring beans auto-discovery by adding <context:component-scan base-package="controller" />
  • Spring-MVC related configuration will be defined through annotations as we have added <mvc:annotation-driven />
  • We will be using the InternalResourceViewResolver to define which view should be rendered to the user, once the controller class has handled incoming requests. More on this below... For now, just try to remember that we gave its "prefix" property the value "/WEB-INF/views/", and its "suffix" property the vlaue ".jsp".

5 Implementing the controller

Create a package named "controller". This package name is not arbitrary. It should match the package name that we've specified in the <context:component-scan> element in the Spring configuration file. 

Then, create a class as follows. You may choose another the name as it is not significant : due to our Spring configuration, Spring will scan the "controller" package and look for classes with Spring annotations (such as @Component, @Controller, @Service, and @Repository).


package controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
public class MyController {
 
 @RequestMapping(method=RequestMethod.GET, value="/home")
 public String handleRequest(){
  return "welcome";
 }
}




  • The @Controller annotation indicates that our class is a Spring registered bean
  • The @RequestMapping annotation marks the handleRequest( ) method as a method that will be executed to handle GET method requests with /home URI.
Basically, whenever an incoming request is handled by the handleRequest( ) method, as it returns unconditionally "welcome",  the view resolver from type InternalResourceViewResolver will concatenate the defined prefix, to this value, and then to the defined suffix.

So, in our case, the view to be rendered would be : /WEB-INF/views/welcome.jsp

6 Create the sample view file (JSP)

  1. First, create a directory named "views" under WEB-INF
  2. In the "views" directory, create a JSP page named "welcome.jsp" as follows : 

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Spring-MVC-Tutorial</title>
</head>
<body>
Welcome my Spring-MVC-Tutorial homepage
</body>
</html>


7 WAR file generation and deployment

With the M2Eclipse plugin, simply run the project as "Maven package". Then copy the generated WAR file from the "target" directory into the "webapps" directory from Tomcat.

8 Testing the application

Open a browser, type the following URL : 
  • http://localhost/Spring-MVC-Tutorial-0.0.1-SNAPSHOT/home.go
And you will get to the following page : 

9 Source code

The project we went through step by step, may be downloaded/checked out (github repository) here. Just make sure you get the master branch of the Spring-MVC-Tutorials repository.