Search This Blog

Sunday, February 19, 2012

Jersey JAX-RS MVC Killed the Spring MVC Star

JAX-RS is arguably the de-facto standard for creating RESTful web services in Java. Most JAX-RS providers have a way to implement a de-coupled MVC paradigm; much like Spring MVC. This BLOG will demonstrate how Jersey JAX-RS can be used as an MVC web framework and will spend some time discussing the difference between Jersey MVC and Spring MVC. As part of the investigation, the Flight Application that I have previously demonstrated using Spring MVC will be translated to use Jersey MVC.

Some of the additional goals of this BLOG are:
1. Integrate with Spring Security for authentication/authorization
2. Use Spring for the Dependency injection
3. Use Twitter Bootstrap for the view part

Front Controller:
Both Spring MVC and Jersey have an implementation of the Front Controller design pattern with the DispatcherServlet from Spring MVC and ServletContainer from Jersey. The former dispatches to Controller classes while the later dispatches to Resource classes.

Controller/Resource:
In a typical Spring MVC Controller we have a ModelAndView object returned with data for the view tier to digest:
@Controller
@Request("/airports.html")
public class AirportsController {
  @RequestMapping(method = RequestMethod.GET)
  public ModelAndView getAirports() {
    List<Airport> airports = airportService.getAirports();

    ModelAndView mav = new ModelAndView("/airports");
    mav.addObject("airports", airports);

    return mav;
  }
}
Jersey provides a class equivalent to ModelAndView called Viewable that defines the view to be used and also houses the model objects:
@Path("/airports.html")
public class AirportsResource {
  @GET
  public Viewable getAirports() {
    List<Airport> airports = airportService.getAirports();
    Map<String, List<Airports>> modelMap = Maps.newHashMap();
    modelMap.put("airports", airports);

    return new Viewable("/airports", modelMap);
  }
}
View Processing:
Spring MVC provides View Resolvers to resolve the template name to a template reference.
In the Jersey MVC land, implementations of the ViewProcessor interface are used to resolve a template name to a template reference. In addition, they are also responsible for processing the template and the results of which are written to the output stream. One such processor is available in the Jersey code base for JSP's, i.e., the JSPTemplateProcessor.  The processor requires the location of the JSP files and the same is made available via the argument of JSTTemplatesBasePath.  The Viewable interface lends itself to providing alternate View Processors for other templating languages like Free Marker and Velocity but the same would need to be built:
<filter>
  <filter-name>jersey</filter-name>
  <filter-class>com.sun.jersey.spi.spring.container.servlet.SpringServlet</filter-class>
    <init-param>
      <param-name>com.sun.jersey.config.property.JSPTemplatesBasePath</param-name>
      <param-value>/WEB-INF/pages</param-value>
    </init-param>
</filter>
View:
In the JSP, all the model objects provided by the Resource tier are easily accessed by using a prefix of "it".  For example
${it.airports} as shown below:
<display:table name="${it.airports}" class="table table-condensed"
     requestURI="" id="a" export="true" pagesize="10">
   <display:column title="Code" property="code" sortable="true"/>
   <display:column title="Name" property="name" sortable="true" />
   <display:column title="City" property="city" sortable="true"/>
</display:table>
With the above, one has the exact same functionality between Spring MVC and Jersey. It is important to note that with Spring MVC however, there are a bunch of options for the return type by which the view is resolved. Spring MVC follows a convention based approach for its Controllers and return types can be quite a few:
  • ModelAndView object
  • Model object, for example, a List of Airports
  • Map of Model objects
  • A View object
  • A String that represents a View name
I will not get into details of the how the above are achieved by Spring MVC as it is beyond the scope of this BLOG. It is sufficient to accept that Spring MVC does support these alternate return types and follows a convention based approach to view resolution.

Accessing Request Data:
Web applications need to have access to request information like HTTP Headers, Cookies, Query Parameters and Form data (discussed later).  Both Spring MVC and Jersey JAX-RS have annotations that help extract the same.
@RequestMapping(method=GET)
public void foo(@RequestParam("q") String q, @CookieValue("c") String c, 
                @RequestHeader("h") String h) {
    // Spring MVC
}

@GET 
@Path
public void foo(@QueryParam("q") String q, @CookieParam("c") String c,
    @HeaderParam("h") String h) {
    // JAX-RS
}

Form Data Management:
Handling Form data and validating the same is one area where every MVC framework has to be tested against.

From a binding perspective, when a form is submitted, one would like to have the form details map to a POJO. With Spring MVC, a form POJO is automatically populated with the details of the HTML Form coupled with the ability of having the contents of the Form being validated and results made available via a BindingResult object as shown below:
public class FlightController {
  @RequestMapping(method=POST)
  public ModelAndView searchFlights(FlightSearchCriteria criteria, BindingResult result) {
     ...
     if (result.hasErrors()) { ... }
     ..
  }
}
In the JAX-RS domain, there are a few ways to access Form parameters:

1. Using the Form object or a MultiValuedMap and explicitly extracting the form data by name:
    public Viewable searchFlights(Form form) {
      String fromAirport = form.getFirst("from");
      String toAirport = form.getFirst("to");
      ...
    }
2. Using @FormParam annotation for auto injection of Form parameters:
public Viewable searchFlights(@FormParam("from") String fromAirport, @FormParam("to") String toAirport) {
   ...
}
3. Using @InjectParam with a Java POJO whose attributes are annotated with @FormParam:

Using @FormParam when there are  a few Form parameters works well but fails when there are multiple parameters as the same translates to a very long method signature. In such cases a single object can house the individual parameters as shown below with the Object being injected automatically to the controller method due to the magic of Jersey's Injectable annotation. Read more about the same from Valotas BLOG:
public class FlightSearchCriteria {
  @FormParam("from")
  String fromAirport;

  @FormParam("to")
  String toAirport;
  ...
}

public class FlightResource {
  public Viewable searchFlights(@InjectParam FlightSearchCriteria criteria) {
    ....
  }
}
With the above, Jersey's MVC is able to map a form object to a POJO but it does involve adding annotations of @FormParam for each form parameter. With the Spring MVC binding, one did not have to deal with the same. In addition, the above examples of Jersey MVC are missing validation of the Form. To achieve the same, one might be able to create a custom Injection Provider to validate and provide the validation results as part of the method signature. I did not find a ready way to do the automatic validation and thus leave that effort for the making of a future BLOG post. That said, validation can easily be performed using JSR 303 validation or a custom validator easily enough programatically within the Jersey MVC resource method:
public Viewable searchFlights(@InjectParam FlightSearchCriteria criteria) {
    ...
    Set<ConstraintViolation<FlightSearchCriteria>> violations = validator.validate(criteria);

    if (violations.size() > 0) {
      modelMap.put("errors", violations);

      return ...;
    }
    ...
}
On the view, displaying the errors on a global level is pretty easy using JAX-RS, as one can simply loop over the violations and display the violation message. Displaying an error message corresponding to each violation explicitly, well Spring MVC has tag support to do the same and although achievable by writing a custom tag, it is an added effort for a Jersey MVC application.

Http Session Variables:
If an application wishes to use the Http Session for managing state, Spring MVC has annotated convention based support for the same. Consider the following example from the petclinic app where managing the lifecycle of the pet in the HTTP session is shown:
@Controller
@SessionAttributes("pet")
public class PetController {
  @RequestMapping(method=GET)
  public Pet get(@RequestParam int id) {
   Pet pet = petService.getPet(id);
   ..
   return pet; // Pet added to Session
  }
  
  @RequestMapping(method=POST)
  public String update(Pet pet, BindingResult result, SessionStatus status) {
    ..
    petService.update(pet);
    
    status.setComplete(); // Remove Pet from session
    ...
  }
}

I did not see an equivalent offering with Jersey MVC.

Security:
As the Spring Security framework is not tightly coupled to Spring MVC, integrating the framework to support the Jersey MVC application is trivial.  On the view tier, Spring Security Tags readily provide access control. If one does not wish to use Spring Security on the web framework, one can easily roll out their own with access being restricted by Jersey filters or Servlet Filters.

Thoughts on Jersey JAX-RS MVC versus Spring MVC:
JAX-RS is a great framework tailored toward creating RESTful web services and Jersey is a solid implementation of the same. As Jersey is a JAX-RS implementation, one could swap out Jersey for another provider like RestEasy if desired without much effort. Spring MVC on the other hand has REST web service support but the same is not a JAX-RS implementation and therefore one is tied to Spring MVC. Read more about a RESTful comparison of Spring MVC and JAX-RS on a very nice INFOQ BLOG

From the perspective of an MVC application, as shown, creating a web application using Jersey is clearly achievable.  It is important to note that one is leaving the JAX-RS specifications and heading into custom Jersey land while doing so though. On the controller tier, I find that the ease of binding Form objects to POJOs is not as full fledged as Spring MVC's offering. The lack of JSR 303 support via automatic validation of Form objects with Jersey MVC is a bit of a downer but not a show stopper. Spring MVC's controller and convention based routing allow for a multitude of return types from a Controller method that Jersey does not seem to have out of the box. Whether the same is a benefit or a pitfall is debatable. 

On the view tier, Spring MVC has strong support for the different templating languages. Be it Free Marker, Velocity, Excel, Jasper Reports, what have you. In addition, Spring MVC out of the box provides a way to chain view resolvers something that Jersey MVC does not have. Spring MVC also comes built in with a rich set of tag libraries supporting JSP, Free Marker and Velocity. There is no such support automatically available via Jersey JAX-RS. Spring MVC also has a strong user community and support in the form of books, forums and blogs working in its favor.

I think back at analogy of designing a bedroom. One can go to a furniture store and simply buy a bedroom set where all components mesh well together, i.e., Spring MVC or one can choose to make the same by buying and building out the components individually, i.e., Jersey MVC. Both approaches will lead one to the same bedroom but how hard was it to get in? When you are in a hurry, the fastest path is welcomed, if you know what I mean ;-) All puns definitely intended ! A colleague of mine also pointed out that Jersey JAX-RS would be driven to make steads in further releases on its core offering, i.e, RESTful services but Spring MVC would make strides on enhancing its web application  support. This is definitely a factor one must consider when deciding between Jersey MVC and Spring MVC.

On the other hand, arguably, if ones application is not very big and a lot of the benefits provided by Spring MVC can be ignored in favor of a light weight MVC application, Jersey MVC can easily fit that role. In particular Jersey MVC will work quite well for web applications that are heavy on Ajax, use client side validation and with partial round trips to the server as they can utilize the strong RESTful support (JSON, XML etc) from Jersey and use the MVC part of Jersey for page transitions.

Condensing, I think Jersey JAX-RS is getting close on the MVC support but for now the Spring MVC star is not extinguished by the Jersey JAX-RS/MVC Juggernaut. If I have not understood the features of Jersey's MVC support correctly, please do comment and clarify the same.

The Jersey MVC Example:
The Jersey MVC Example can be downloaded from HERE. After extracting the file,  execute a "mvn jetty:run" from the root of the project and access the application at http://localhost:8080. The user credentials are the same as in my Spring MVC Security example. Once you get in, play with the validation and scrutinize the source. The example uses Spring for DI.

The styling itself is using Twitter Bootstrap, thanks to a good friend of mine pushing me to try it. I am sadly an average front end developer and therefore offer my thanks to the supremo of web development, Matt Raible, and his customization of App Fuse, based of which, I have been able to change the style of the Flight Application. On Twitter Bootstrap, I did like the ease it presented of creating a decent looking web application but I must lean on Matt's BLOG and his assessment that although Twitter Bootstrap is a great starter template, it is by no means a substitute for a template created by a solid CSS developer.

Sunday, February 12, 2012

Spring Security - Stateless Cookie Based Authentication with Java Config

It has been security time for me recently at work, single sign on and the likes. While at it, I stumbled upon my favorite framework Spring and its offering Spring Security. In the words of the creators of the framework, "Spring Security is a powerful and highly customizable authentication and access-control framework. It is the de-facto standard for securing Spring-based applications".  Spring Security has been around since sometime now but I have not had a chance to use it. This is my first foray into the framework and my BLOG is targeted at accomplishing the following objectives:

1. Enhance the Example Project I created to demonstrate Spring Java Config with Authentication and Authorization powered by Spring Security.
2. Demonstrate an embedded LDAP server in the project as the source of user authentication and user roles.
3. Ensure that the application is stateless thus being able to scale out really easily. Use a  Cookie instead of HttpSession to store the user's authenticated state.
4. Have the application use Form Based Authentication.
5. Use Java Config for Spring MVC and Spring Security

The Example Flight project was augmented with the following ROLE based authorization:

1. Standard User - A user who can view Airports, Search Flights and see reservations
2. Agent - An agent who can perform all the operations a user can with the additional ability to  make reservations on flights
3. Administrator - An administrator who can  do everything a standard user can do with the additional ability to create new Airports for the Flight application. They however cannot make a reservation, i.e., no Agent privilege.

From an LDAP perspective, the following groups can be considered to match the above roles: USER, AGENT and ADMIN.

ApacheDS is one example of an open source LDAP server that can be run in embedded mode. I started looking into how to do the same only to find out that the Spring Security project provides a very easy way to the same. If using Spring Security, the standard way to have an embedded server in your application for demonstration or testing purposes is to simply have the following line defined in your spring beans.xml. krams BLOG on using embedded LDAP with Spring MVC was a major help in gettting the code functional:
 <--ldiff file to import -->
 <ldap-server root="o=welflex" ldif="classpath:flightcontrol.ldiff" />

The above claim seems exotic but the presence of the above line and the magic of  Springs Extensible XML Authoring has an embedded LDAP going with minimal developer effort. The Java Config equivalent of the same is shown below where the container is programatically created:
@Configuration
public class SecurityConfig {
  /**
   * This bean starts an embedded LDAP Server. Note that start
   * is not called on the server as the same is done as part of the bean life cycle's
   * afterPropertySet() method.
   *
   * @return The Embedded Ldap Server 
   * @throws Exception
   */
  @Bean(name = "ldap-server")
  public ApacheDSContainer getLdapServer() throws Exception {
    ApacheDSContainer container = new ApacheDSContainer("o=welflex",
        "classpath:flightcontrol.ldiff");
    container.setPort(EMBEDDED_LDAP_SERVER_PORT);
    return container;
  }
...
}
With the above Java Config, the embedded LDAP server is primed with the contents from the flightcontrol.ldiff file.

For the Stateless requirement, the flight control application will rely on a Cookie on the client browser to detect the user that is logged in rather than use the HTTP Session. Spring Security tends to gravitate toward using the HTTP Session. However as of Spring 3.1, they introduced a configuration of "stateless".  The setting of stateless meant that a HTTP session would not be created by Spring Security. The same however does not translate into a Cookie based authentication mechanism being introduced. Using name spaces, one would bootstrap spring security for the application as shown below:
  <http auto-config="true" create-session="stateless">
      <-- Allow anon access -->
      <intercept-url pattern="/login*" access="IS_AUTHENTICATED_ANONYMOUSLY" />
      <intercept-url pattern="/logoutSuccess*" access="IS_AUTHENTICATED_ANONYMOUSLY" />
      <intercept-url pattern="/scripts*" access="IS_AUTHENTICATED_ANONYMOUSLY" />
      <--Enforce user role -->
      <intercept-url pattern="/*" access="ROLE_USER" />

      <-- Form login, error, logout definition -- >
      <form-login login-page="/login.html"
    always-use-default-target="true" default-target-url="/home.html"
     authentication-failure-url="/login.html?login_error=1" />
          logout logout-url="/logout" logout-success-url="/logoutSuccess.html" />
  </http>
In order to understand how the above Spring Security namespace is translated to Java Beans, take a look at the BLOG by Luke Taylor on the same. The above will work fine if one is using Basic or Digest authentication to secure resources but does not work with form based authentication and a stateless environment. If you wish to use Basic or Digest based authentication, then take a look at baeldung's BLOG on the same.

As the requirement of the flight application is to use form based login via Cookie Support, a filter is  created that is a substitute for the SessionManagementFilter:
public class CookieAuthenticationFilter extends GenericFilterBean {

  public CookieAuthenticationFilter(LdapUserDetailsService userDetailService,
      CookieService cookieService) {...}

  @Override
  public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException,
    ServletException {
    HttpServletRequest request = (HttpServletRequest) req;
    HttpServletResponse response = (HttpServletResponse) res;

    SecurityContext contextBeforeChainExecution = loadSecurityContext(request);
    
    // Set the Security Context for this thread
    try {
      SecurityContextHolder.setContext(contextBeforeChainExecution);
      chain.doFilter(request, response);
    }
    finally {
      // Free the thread of the context
      SecurityContextHolder.clearContext();
    }
  }

  private SecurityContext loadSecurityContext(HttpServletRequest request) {
    final String userName = cookieService.extractUserName(request.getCookies());

    return userName != null
        ? new CookieSecurityContext(userDetailService.loadUserByUsername(userName))
        : SecurityContextHolder.createEmptyContext();
  }
}
In the above code, the loadSecurityContext method is responsible for loading user information from the authentication provider. The method will attempt to obtain the authenticated principal from the custom user cookie set and if present, create a Spring SecurityContext and set the same in the SecurityContextHolder. Setting of the Context will ensure that no further authentication is performed and the requested resource will be served up. If the User security cookie were not present, then an empty context is provided so that filters further downstream can re-direct the request to a login page.

So where does the User Cookie get set? After a successful authentication, an AuthenticationSuccessHandler is invoked by Spring Security's UsernamePasswordAuthenticationFilter and the former is where the cookie gets set:
public class AuthSuccessHandler implements AuthenticationSuccessHandler {
  ... 
  @Override
  public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
    Authentication authentication) throws IOException, ServletException {
    SecurityContext context = SecurityContextHolder.getContext();
    Object principalObj = context.getAuthentication().getPrincipal();
    String principal = ((LdapUserDetails) principalObj).getUsername();
    
    // Create the User Cookie        
    response.addCookie(cookieService.createCookie(principal));
    response.sendRedirect("/home.html");
  }
}
The UserNamePasswordAuthenticationFilter is notified of the custom AuthenticationSuccessHandler as shown below:
@Configuration
public class SecurityConfig {
  ....
  private UsernamePasswordAuthenticationFilter getUserNamePasswordAuthenticationFilter() {
    UsernamePasswordAuthenticationFilter filter = new UsernamePasswordAuthenticationFilter();

    filter.setAllowSessionCreation(false);
    filter.setAuthenticationManager(getAuthenticationManager());
    // Set the Auth Success handler
    filter.setAuthenticationSuccessHandler(new AuthSuccessHandler(getCookieService()));
    filter.setAuthenticationFailureHandler(new SimpleUrlAuthenticationFailureHandler("/login.html?login_error=1"));
    
    filter.setFilterProcessesUrl("/j_spring_security_check");

    return filter;
  }
}
The final chain of Filters is declared as:
@Configuration
public class SecurityConfig {
  ....
  @Bean(name = "springSecurityFilterChain")
  public FilterChainProxy getFilterChainProxy() {
    SecurityFilterChain chain = new SecurityFilterChain() {

      @Override
      public boolean matches(HttpServletRequest request) {
        // All goes through here
        return true;
      }

      @Override
      public List<Filter> getFilters() {
        List<Filter> filters = new ArrayList<Filter>();

        filters.add(getCookieAuthenticationFilter());
        filters.add(getLogoutFilter());
        filters.add(getUserNamePasswordAuthenticationFilter());
        filters.add(getSecurityContextHolderAwareRequestFilter());
        filters.add(getAnonymousAuthenticationFilter());
        filters.add(getExceptionTranslationFilter());
        filters.add(getFilterSecurityInterceptor());

        return filters;
      }
    };
    
    return new FilterChainProxy(chain);
  }
}
With the above configurations, the application has all the necessary ingredients to provide Cookie based authentication and Role based authorization. The following HTML snippets demonstrate how Spring Security's taglibs are used to honor the roles on the view tier of the architecture:
<-- Airports page -- >
<sec:authorize ifAllGranted="ROLE_ADMIN">
   <-- Display the form to add an airport -- >
</sec:authorize>

<-- Flight Search page. Display column to book flight only for AGENTs -->

<display:table name="flightSearchResult.flights" class="table"
 requestURI="" id="flight" export="true" pagesize="10">
         .....
 <sec:authorize ifAllGranted="ROLE_AGENT">
  <display:column title="" sortable="false" href="/bookFlight.html"
   paramId="id" paramProperty="id" titleKey="flightId">
           Book
        </display:column>
    </sec:authorize>
</display:table>
Individual methods of the Service classes can also be secured for authorization using Spring Security via annotations. The examples does not get into the same.

Conclusion

The example provided uses Java Config in its entirety and can give an entrant into Spring Security an idea of how the request chain is set up simply by following the Java Config. The beauty of the Spring Security framework lies in the fact that authentication and authorization details are set up within the filter chain and clearly remove boiler plate from a developer who is working of the Controller tier. Spring's Security does not have to stop at the view tier and can be used to authorize access to to Service tier methods as well.

The example obtains the user roles from the embedded LDAP server on every request. The can be performance issue. Consider not prematurely optimizing as LDAP look ups are supposed to be rapid. If you do face a problem with performance, consider a backing cache. Also note that the user cookie created is not secure and can easily be spoofed. In an actual implementation one would use some way to identify against spoofed cookies. 

Download the full source code as a maven example from here and once extracted, execute a "mvn jetty:run" to start the same. All the security configuration is set up in the package com.welflex.web.security. You will see an embedded LDAP server start and the corresponding schema imported into the server. Access the web application at http://localhost:8080.

When prompted to login use one of the following user name/password combinations to see the different roles and corresponding access control in action:

1. Admin User - sadmin/pass
2. Agent User - sagent/pass
3. Standard User - suser/pass

Investigate your browsers cookies to see that a USER cookie has been set by the application and that there is no sign of JSESSIONID cookie.

I hope this is of help to someone trying to integrate Spring Security into their application and wants to use form based login with Cookies to remember the user. There have been some Stack Overflow and Spring Security Forum postings asking about the same.

There are still areas to explore with the Spring Security domain like Spring Security Oauth, Spring Security SAML (empty page)Spring Security CAS.