Skip to content


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

  • Facebook
  • Twitter
  • Digg
  • del.icio.us
  • Reddit
  • Google Bookmarks
  • LinkedIn
  • Slashdot
  • MySpace
  • Propeller
  • StumbleUpon
  • Yahoo! Buzz
  • Add to favorites
  • email
  • Yahoo! Bookmarks
  • Live
  • FriendFeed
  • Technorati

Posted in Google App Engine, Spring Framework.

Tagged with , .


10 Responses

Stay in touch with the conversation, subscribe to the RSS feed for comments on this post.

  1. Sue MasseyNo Gravatar says

    I must say this is a great article i enjoyed reading it keep the good work :)

  2. Cem KocNo Gravatar says

    I believe also that you should keep on these articles :) Especially about gae and spring…

    Thanks

  3. Mike LademannNo Gravatar says

    Really awesome blog you got there. Some of your article really impressed me. I will definitely visit your blog again!

  4. Microwave Grill OvenMALECABBILKNo Gravatar says

    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

  5. Adrian TaylorNo Gravatar says

    You have really great taste on catchy article titles, even when you are not interested in this topic you push to read it

  6. TomasNo Gravatar says

    The plugin for the social bookmarking is called Sciable.

  7. RomainNo Gravatar says

    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.

  8. Tomas MazuknaNo Gravatar says

    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.

  9. ChenNo Gravatar says

    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.

  10. Tomas MazuknaNo Gravatar says

    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



Some HTML is OK

or, reply to this post via trackback.