Goolge app engine + java + spring + REST + JSON + Flex – Part 3

the_lock

Objective

After reading this post you will be able to implement robust user authentication and authorization scheme without replicating code to check if user is logged in and if the are authorized to perform a certain action.

The Problem Domain

You, like me, face the same problem with each web application – user authentication and authorization. Who is logged in? Can they delete this entity? Can they see this report? How to solve this problem without copy pasting same piece of code to every servlet/action/controller/whatever? If you are using spring MVC there is a very elegant and powerful solution – Interceptors.

You can have as many interceptors as you like, I usually have one for security and maybe one more for some other task. Interceptor fires before your controller/action gets invoked. If it returns true the flow can continue, if it returns false the execution stops right there – request has been handled by the interceptor.

Step One – Adding an interceptor to our application form part 1

First lets code our interceptor. I named it SessionInerceptor.

package com.lureto.rjf;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

public class SessionInterceptor extends HandlerInterceptorAdapter {

    public boolean preHandle( HttpServletRequest request, HttpServletResponse response, Object handler) 
                                     throws Exception {
    	User user = (User)request.getSession().getAttribute( Constants.SESSION_USER );
    	String uri = request.getRequestURI();
    	String base = request.getContextPath();
    	uri = uri.substring( base.length() );
    	if( user == null && !uri.startsWith("/api/login") ) {
        	request.getSession().invalidate();
        	response.setContentType("application/json");
            response.getWriter().write("{"error":"SESSION-EXPIRED"}");
            return false;
    	}
    	return true;
    }
	
}

As you see we are extending HandlerInterceptorAdapter class by implementing preHandle() method. If you need you can use postHandle() to perfor some action after the main handler has finished work. My implementation for this example is pretty simple – check only if the user is present in the session. If no user is present and user is not trying to log in, send back an error. In pure web application you probably would want to send a redirect to the login page.

Now lets add this interceptor to the Spring MVC stack by adding these 5 lines to our rest-json-flex-servlet.xml file.

<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
	<property name="interceptors">
		<bean class="com.lureto.rjf.SessionInterceptor"/>
	</property>
</bean>

One more thing – we need to enable session in google app engine. Add this line to your appengine-web.xml

<sessions-enabled>true</sessions-enabled>

Step 2 – Implement Login Controller

Now we have our SessionInterceptor stopping us from accessing the services, we need to ad the way to log in. My inplementation of LoginController:

package com.lureto.rjf;

import java.io.IOException;
import java.util.List;

import javax.jdo.PersistenceManager;
import javax.jdo.Query;
import javax.servlet.http.HttpServletRequest;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
@RequestMapping("/login")
public class LoginController {

	private static Logger logger = Logger.getLogger( LoginController.class );
	
	@Autowired
	private PMF pmf;
	
	@SuppressWarnings("unchecked")
	@ModelAttribute("user")
	@RequestMapping(value = "/", method = RequestMethod.POST)
	public User login( @RequestBody User user, HttpServletRequest request ) throws IOException {
		logger.debug(user);
		
		// Hardcoded for demo website
		if( user.getName().equalsIgnoreCase("user1") && user.getPassword().equals("password1") ) {
			user.setId(1001);
			user.setEmail("fake@email.com");
			request.getSession(true).setAttribute( Constants.SESSION_USER , user);
			return user;
		}
		
        PersistenceManager pm = pmf.getManager();

		Query query = pm.newQuery("select from com.lureto.rjf.User " +
				"where password == passwordParam && name == nameParam " +
				"parameters String passwordParam, String nameParam");
		
		List<User> users;
		try {
			users = (List<User>) query.execute( user.getPassword(), user.getName() );
			if( users.size() > 0 ) {
				User luser = users.get(0);
				request.getSession(true).setAttribute( Constants.SESSION_USER , luser);
				return luser;
			}
		} finally {
			query.closeAll();
		}

        return null;
	}
	
	public PMF getPmf() {
		return pmf;
	}

	public void setPmf(PMF pmf) {
		this.pmf = pmf;
	}
	
}

What happens here is very strait forward: we construct a query to the big table to find a user matching supplied name and password. If we find one, we create a session and put our user object there. Our SessionInterceptor expects to find this user there once we try access /api/user/ endpoints.
Since Spring is scanning this package and we are using annotation, we do not need to add this controller to the xml file.

Step 4 – Enhance existing User bean to support permissions

Here is my User.java

@PersistenceCapable(identityType = IdentityType.APPLICATION, detachable="true")
public class User {

    @PrimaryKey
    @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
	private Long id;
    @Persistent
    private String email;
    @Persistent
    private String name;
    @Persistent
    private String password;
    @Persistent
    private List<String> permissions;
	
    public User() {
    	permissions = new ArrayList<String>();
    }
    
    // getters and setters here
}

Step 5 – Add Login Screen to Flex application

login_screen

This is how the finished screen looks like, once you log in, you end up in this screen.

user-edit-screen

Full source code for JsonRestClient.mxml.

Step 6 – User Authorization Implementation

As you see from all the work we have done to this point we are not checking for user permissions. I intentional left it out. The best solution will depend on your particular application. In this case, we need to come up with the permission convention first. I would probably use “action-uri” convention. So to be able to get the user list you need to have “GET-user” permission, to update it would be “POST-user”, etc. You may come up with something better for your situation.

Conclusion

Interceptors in Spring is the perfect way of moving user authentication and authorization code form controllers into centralized place. This makes your controllers cleaner. You already know that the right user with right permissions is performing this action.

Source Code for Java part can be found Here.

Demo application can be found here. (check the LoginController in Step 2 to figure out the user + password to log in )

Leave me a comment what permission checking convention you would use.

Best of Luck!
Tomas

15 thoughts on “Goolge app engine + java + spring + REST + JSON + Flex – Part 3

  1. What’s up thank you regarding your post.I definitely adore your weblog.Its quite informative.On the other hand I actually want you to post how you put social bookmarking below your post.My partner and i like it because it’s a incredibly clean awesome blogger mod.
    thank you quite much

  2. Great article! I see you defined password as a String. Do you know if there is a type that allow encoding of password in BigTable? Thanks.

  3. There is no encoded type. If you think about it there is no point in having encoded type, since you will set and get data un-encoded. Your best bet is storing password as string and encoding it in the application. I went that route.

  4. hi Tomas – super Job!! this tutorial is one of the best out there.

    I have a question regarding this specific part – can you elaborate on the @Autowired annotation that you used here? In part 2 you did not use that – you went for the PMF.getManager(). So when and why do you recommend using either of this methods?

    Thanks! Chen.

  5. In Part 2 I had a singleton called PMF and got a handle to the persistence manager through that. It was a how I started trying to get Spring MVC running inside GAE. Later I cleaned up my act and instructed Spring to inject persistence manager where I needed it using @Autowired annotation. I would advise using @Autowired. This way your classes do not need to know who is providing the persistence manager.

    Cheers! Tomas

  6. Hi,
    i have tried your sample:
    http://rest-json.appspot.com/
    but i having this error:

    (mx.messaging.messages::ErrorMessage)#0
    body = “”
    clientId = “DirectHTTPChannel0”
    correlationId = “2CB3D6D6-068D-208F-FC36-8BF041B08867”
    destination = “”
    extendedData = (null)
    faultCode = “Server.Error.Request”
    faultDetail = “Error: [IOErrorEvent type=”ioError” bubbles=false cancelable=false eventPhase=2 text=”Error #2032″]. URL: http://rest-json.appspot.com/api/login/
    faultString = “HTTP request error”
    headers = (Object)#1
    DSStatusCode = 0
    messageId = “ACCD0BDC-FF4A-4AD9-6DA2-8BF04337077A”
    rootCause = (flash.events::IOErrorEvent)#2
    bubbles = false
    cancelable = false
    currentTarget = (flash.net::URLLoader)#3
    bytesLoaded = 0
    bytesTotal = 0
    data = “”
    dataFormat = “text”
    eventPhase = 2
    target = (flash.net::URLLoader)#3
    text = “Error #2032”
    type = “ioError”
    timestamp = 0
    timeToLive = 0

  7. Janka,

    There is no RPC (remote procedure call) in my sample.
    And a lot of time has passed since this example was implemented, looks like appengine implementation has changed somewhat and I see a nullpointer exception somewhere in runtime verifier…..

  8. Today, would you still go the [Spring] route for RESTful Java Servlets on GAE(Google App Engine)? I spent a couple days searching google and the web, and the only decent Java examples I found used [Restlet] or [Jersey].

    Restlet:
    http://blog.noelios.com/2009/04/11/restlet-in-the-cloud-with-google-app-engine/
    http://wiki.restlet.org/docs_2.0/13-restlet/275-restlet/252-restlet.html

    Jersey:
    http://tugdualgrall.blogspot.com/2010/02/create-and-deploy-jax-rs-rest-service.html

  9. Hi there! This post couldn’t be written any better!
    Looking through this article reminds me of my
    previous roommate! He continually kept preaching about this.
    I am going to forward this article to him. Fairly certain he’ll have a good read.
    Thanks for sharing!

Leave a Reply

Your email address will not be published. Required fields are marked *