'spring' Category

User authorization in RESTful Spring

I’m having a lot of fun with the new RESTful features in Spring 3.0. I’m sure you could tell by the number of RESTful Spring posts lately.

Last night I wrote a user authorization interceptor that makes sure there is a user associated with each resource request that requires it. I’m structuring most of my new web apps in such a way that user authorization is required for almost all actions.  I had to make a choice of how to enforce user authorization in the app.  The two choices were between a Servlet filter and a HandlerInterceptor.

A Servlet Filter is part of the Java EE Servlet package.  Most of my Java web projects use Servlet Filters in some way so I wasn’t immediately opposed to using one to make sure there is a logged in user associated with a request.  Because I wanted possible errors to be properly rendered in my different view types using Spring I decided to use a HandlerInterceptor.

A HandlerInterceptor is a Spring interface that is pretty much analogous to a Servlet Filter in terms of structure, though it’s a little more focused in purposed.  The HandlerInterceptor is mostly concerned with text-based content, where Filters can be applied to any content type.  Filters are also more appropriate for setting headers and gzipping responses.  The Handler Interceptor is targeted for application logic.

This interceptor only checks to see that there is a user object associated with an resource request before passing it on to the handler (a controller).  In practice this may include more detailed authorization checks but for the example just checking for a user is fine.

@Component
public class UserAuthorizationInterceptor extends HandlerInterceptorAdapter {

  private static final String UNAUTHORIZED_MSG = "You are not logged in.  You must log in or supply an API token.";

  @Override
  public boolean preHandle(HttpServletRequest request,
                        HttpServletResponse response,
                        Object handler) throws Exception {

    String uri = request.getRequestURI();
    User user = (User) request.getSession().getAttribute("user");

    if (user != null || uri.indexOf("login") != -1) {
      return true;
    } else {
      response.sendError(HttpServletResponse.SC_FORBIDDEN, UNAUTHORIZED_MSG);
      return false;
    }
  }
}

Initially I wanted any error messages to be rendered by my Atom, RSS and JSON views. Any error message generated by the application should come back to the user in the requested data format. But this is a RESTful app. The REST philosophy already addresses the only error message that should come out of an authorization check with HTTP status codes. The only error message that should come out of this interceptor is an “unauthorized” message. HTTP supplies the 401 status code to indicate a user is unauthorized.

The implication of using the 401 code is that the user should use HTTP authentication, either basic or digest. That’s not appropriate for an application using OpenID and API tokens for user authentication. Instead the 403 status code is more appropriate. This means the client is forbidden from accessing the requested resource. The server understood the request but the client is not allowed to access the resource, which is exactly the case when there is no logged in user associated with the request.

Because HTTP already provides plenty of status codes for things that can go wrong we should rely on those codes when building RESTful applications. There is no reason to supply an application-generated error message when the protocol supplies everything we need to deal with the problem. The REST philosophy actually makes it much easier to write web apps because we’re using HTTP as it is intended to be used which takes a lot of responsibility off of our application code.

Wiring RESTful web services with Spring

I’ve recently been using Spring 3.0M1 to make some RESTful APIs. While working on the project a question came up a few times from different people: how do the <jee:jndi-lookup/>, <context:annotation-config/> and <context:component-scan/> beans relate to each other? I’ve got some sample code that I use as a reference when this question comes up.

Let’s start with the <jee:jndi-lookup/> bean. Since a RESTful API probably runs in a web container we need to look up a data source, persistence unit or persistence context. We define the persistence unit in WEB-INF/classes/META-INF/persistence.xml.

<?xml version="1.0"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0">
  <persistence-unit name="bookmarksPU" transaction-type="RESOURCE_LOCAL">
    <provider>org.apache.openjpa.persistence.PersistenceProviderImpl</provider>
    <non-jta-data-source>jdbc/bookmarks</non-jta-data-source>
    <class>net.anthonychaves.bookmarks.models.User</class>
    <class>net.anthonychaves.bookmarks.models.Bookmark</class>
  </persistence-unit>
</persistence>

The bookmarksPU persistence unit is registered with the container when the webapp is deployed. It looks up the jdbc/bookmarks datasource and uses it for access to the database. Setting up this datasource is up to you based on your container.

The bookmarksPU is also bound to a JNDI name, persistence/bookmarksPU. We can inject this persistence unit into our webapp in the form of an EntityManagerFactory after registering a bean in our Spring container. We do this in our Spring configuration file by looking up the persistence unit in JNDI.

<jee:jndi-lookup id="bookmarksPU" jndi-name="persistence/bookmarksPU"/>

In our service layer we have a class UserService.

@Service
public class UserService {

  @PersistenceUnit(unitName="bookmarksPU")
  EntityManagerFactory emf;

  public void saveUser(User user) {
    EntityManager em = emf.createEntityManager();
    em.getTransaction().begin();
    em.persist(user);
    em.getTransaction().commit();
  }

  public User findUser(String name) {
    EntityManager em = emf.createEntityManager();
    Query query = em.createQuery("select u from User u where u.name = ?1")
                    .setParameter(1, name);
    em.getTransaction().begin();
    User user = (User) query.getSingleResult();
    em.getTransaction().rollback();
    return user;
  }
}

Notice two things about this class: it is annotated with the org.springframework.stereotype.Service annotation and its EntityManagerFactory is annotated with the javax.persistence.PersistenceUnit annotation. We want Spring to deal with both of these annotations. We want the component, the class annotated by @Service, registered as a Spring bean without doing it manually in XML. We also want Spring to inject an instance of EntityManagerFactory bound to the persistence/bookmarksPU persistence unit.

One of the nice things about Spring is that we can rely on these annotations so we don’t have to create long XML configuration files. We still need the XML config to tell Spring which classes it should examine for these annotations. Enter the <context:annotation-config/> and <context:component-scan/> beans.

Each of these beans implicitly creates instances of classes that implement the BeanPostProcessor interface. The post processor created by the <context:annotation-config/> bean that is most important to our case is the PersistenceAnnotationPostProcessorBean. This bean finds the bookmarksPU bean created when we performed the JNDI lookup and injects it into the emf field annotated with @PersistenceUnit.

The <context:annotation-config/> bean takes care of the javax.persistence annotation but it does not create a bean definition for the UserService class. To do that we need the <context:component-scan/> bean. This bean scans the specified base package for classes annotated with @Component and its subclasses, which includes @Service. By annotating the UserClass as a @Service we are spared from configuring it by hand in XML.

The <context:component-scan/> bean only searches for annotations relevant to the current application context. In this case we must define the service layer outside of the *-servlet.xml WebApplicationContext. The @Controller annotation is valid in a WebApplicationContext where a @Service annotation is not. We should instead keep our service layer configuration separate from the webapp configuration. In services.xml we have our services defined.

<?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:p="http://www.springframework.org/schema/p"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:jee="http://www.springframework.org/schema/jee"
       xsi:schemaLocation="http://www.springframework.org/schema/beans

http://www.springframework.org/schema/beans/spring-beans-3.0.xsd

http://www.springframework.org/schema/context

http://www.springframework.org/schema/context/spring-context-3.0.xsd

http://www.springframework.org/schema/jee

                           http://www.springframework.org/schema/jee/spring-jee-2.5.xsd">

  <jee:jndi-lookup id="bookmarksPU" jndi-name="persistence/bookmarksPU"/>

  <!-- here we need component-scan for the services and annotation-config for the persistence unit -->
  <context:component-scan base-package="net.anthonychaves.bookmarks"/>
  <context:annotation-config/>

</beans>

A WebApplicationContext inherits all the bean definitions from any imported ApplicationContexts. If we import the services.xml file in our *-servlet.xml file we will inherit the fully wired UserService bean created by the BeanPostProcessor beans in that ApplicationContext. We have a controller that needs an instance of UserService.

@Controller
@RequestMapping("/user")
public class UserController {

	@Autowired
	UserService userService;

	@Autowired
	ImageCaptchaService icservice;

	@RequestMapping(value="/new", method=RequestMethod.GET)
	public String newUser(ModelMap model) {
		model.addAttribute(new User());
		return "user_new";
	}

	@RequestMapping(method=RequestMethod.POST)
	public String createUser(@ModelAttribute("user") User user,
							 HttpSession session,
							 @RequestParam("j_captcha_response") String captchaResponse) {

		boolean validResponse = icservice.validateResponseForID(session.getId(), captchaResponse);
		if (validResponse) {
		  userService.saveUser(user);
		  session.setAttribute("user", user);
			return "redirect:/b/user";
		} else {
			return "redirect:/b/user/new";
		}
	}

	@RequestMapping(method=RequestMethod.GET)
	public String user(HttpSession session) {
	  if (session == null || session.getAttribute("user") == null) {
	    return "redirect:/b/user/new";
	  }

		User user = (User)session.getAttribute("user");
	  return "user";
	}

	@RequestMapping(method=RequestMethod.POST, value="/login")
	public String login(@RequestParam("name") String username, HttpSession session) {
	  User user = userService.findUser(username);
	  session.setAttribute("user", user);
    return "redirect:/b/user";
	}

	public void setUserService(UserService userService) {
	  this.userService = userService;
	}
}

By specifying the UserService in UserController as @Autowired we expect an AutowiredAnnotationBeanPostProcessor to inject an instance of UserService into an instance of this class. Both the <context:annotation-config/> and <context:component-scan/> beans create instances of AutowiredAnnotationBeanPostProcessor. The <context:annotation-config/> bean creates a PersistenceAnnotationBeanPostProcessor which is not important to us here. We don’t have any persistence units to inject.

The <context:component-scan/> bean creates an AutowiredAnnotationBeanPostProcessor and it also registers a bean definition for the UserController. @Controller is a subclass of @Component and has several annotations that would only be used in a class annotated with @Controller. The <context:component-scan/> bean takes care of mapping any routes and parameters specified by the @RequestMapping, @RequestParam and other @Controller-related annotations.

Our bookmarks-servlet.xml file needs only the <context:component-scan/> bean defined to get our web classes up and running. The full bookmarks-servlet.xml file is very simple.

<?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:p="http://www.springframework.org/schema/p"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:jee="http://www.springframework.org/schema/jee"
       xsi:schemaLocation="http://www.springframework.org/schema/beans

http://www.springframework.org/schema/beans/spring-beans-3.0.xsd

http://www.springframework.org/schema/context

http://www.springframework.org/schema/context/spring-context-3.0.xsd

http://www.springframework.org/schema/jee

                           http://www.springframework.org/schema/jee/spring-jee-2.5.xsd">

  <import resource="services.xml"/>

  <!-- component-scan creates implicit AutowiredBeanPostProcessor,
             we don't need PersistenceAnnotationPostProcessor -->
  <context:component-scan base-package="net.anthonychaves.bookmarks"/>

  <bean id="viewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver">
    <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
    <property name="prefix" value="/WEB-INF/jsp/"/>
    <property name="suffix" value=".jsp"/>
  </bean>

  <bean id="captchaService" class="net.anthonychaves.bookmarks.service.CaptchaServiceSingleton"
        factory-method="getInstance"/>

</beans>

This should hopefully make it very easy for anyone to quickly create at least a skeleton RESTful API with Spring. Comments? Let me know!

Dummy Code (Quick’n'Dirty vs. Engineered)

When creating software, two people will never write the same implementation of a method or system of non-trivial design.  Creating software is a problem solving process and there are usually many ways to solve one problem.  The solutions may differ in elegance and efficiency while giving the same output for a given set of inputs.  A correct solutions is a correct solution regardless of implementation. (more…)

Scalability round-table/forum on January 28

The Boston Scalability User Group is hosting a technology round-table meeting on Wednesday January 28th at 6 p.m.  The meeting is at the IBM Innovation Center in Waltham, MA.

This is the first time we’ve done the round-table style meeting and I’m excited to see how it goes.  Guests are encouraged to come prepared with questions, answers and opinions on application scalability tools, strategies and designs.  Hot topics will include platform and software stack, cloud computing and resources, vendor tools and support and CDNs. Those are my guesses about hot topics doesn’t mean the meeting is limited to those topics.

Guests, be the regular or first-timers, will drive the direction of the discussion.  We’ll talk about solving technical problems based on past experience or serve as an advisory panel on where and when to use a particular tool.

Full meeting details are at the BostonSUG web site.  We ask that you sign up for the meeting at the meeting registration page so we have an idea of how much food to buy.  There will be snacks and bottled water at this meeting.

Hope to see everyone on the 28th at 6 p.m.!

Terracotta Tech Talk

I’m developing a Java/Spring web application deployed on JBoss 4.2.2 that makes heavy use of memcached in order to reduce the latency experienced by the user. The user interacts with data that is (unbeknownst to them) in the cache. In order to make changes permanent a message is placed on a queue that is picked up by an MDB. The message is just the key used to access the data in the cache. The MDB takes the data out of the cache and then saves it to the database. This greatly improves the user experience because they do not have to wait for the next page to load while costly database writes occur. So far, so good.

In this case I am unfortunately duplicating data by separating the reads from the writes. The data lives in the Hibernate session used by the read-only app server in order to load the data in the first place. It also has to be loaded in the write-only app server in order for that Hibernate session to work with it, which brings me to the point of this post: Is there any way that I can use Terracotta to pool my Hibernate-managed objects into one pool used by both the read-only and write-only app servers? I think I would like to pool my Hibernate second-level cache. It seems like Terracotta can get the job done.

That said, I’m anxious to explore this topic more when Orion Letizi from Terracotta Tech comes to speak at the Boston Scalability User Group next Wednesday on May 28th. The meeting starts at 6 p.m. at the IBM Innovation Center in Waltham, MA. Of course there will be pizza and soda (sponsored by Terracotta – thank you!) so come to the meeting to have some food and explore what Terracotta can do for your project. All the details, including directions, are on the Boston Scalability User Group web site. Remember, there will be pizza!