TurboManage

David Chandler's Journal of Java Web and Mobile Development

  • David M. Chandler


    Web app developer since 1994 and former Developer Advocate with Google now residing in Peru. I am currently offering public and private developer training courses in the US and Latin America as well as working on Android, GWT, and App Engine projects.

  • Subscribe

  • Enter your email address to subscribe to this blog and receive notifications of new posts by email.

    Join 220 other followers

  • Sleepless Nights…

    October 2009
    S M T W T F S
    « Sep   Nov »
     123
    45678910
    11121314151617
    18192021222324
    25262728293031
  • Blog Stats

    • 640,826 hits

Calling AppEngine (securely) from GWT with gwt-dispatch

Posted by David Chandler on October 7, 2009

When using an AJAX framework like GWT, it is necessary to authenticate each service call as well as the front end or else your services are open to the world. With AppEngine, there are several approaches we could take, such as wrapping all service servlets with a servlet filter or Spring Security or calling a checkLoggedIn() method as the first statement in each service method.

The mechanics of authenticating an AppEngine on the server side are simple enough. We just call the AppEngine UserService. The browser automatically passes the AppEngine cookie with each service request, so we don’t have to modify our service interfaces just to authenticate the user. This example shows a simple checkLoggedIn() method that could be called from each service method or wired into a servlet filter:

package com.turbomanage.server.util;

import com.google.appengine.api.users.User;
import com.google.appengine.api.users.UserService;
import com.google.appengine.api.users.UserServiceFactory;
import com.turbomanage.exception.NotLoggedInException;

public class ServiceUtil
{
	public static User checkLoggedIn() throws NotLoggedInException
	{
		User user = getUser();
		if (user == null)
		{
			throw new NotLoggedInException("Not logged in.");
		}
		return user;
	}

	private static User getUser()
	{
		UserService userService = UserServiceFactory.getUserService();
		return userService.getCurrentUser();
	}
}

In addition to authenticating the user, it's a good idea to protect our services against CSRF/XSRF attacks. Google recommends (see section on XSRF and GWT) that each service request be accompanied by a token that is available to the server and the client application, but not to JavaScript code in an email link or running on other  pages. The simplest scheme is simply to pass the sessionId cookie as an argument to each service method. With standard GWT-RPC, however, this is a pain because we have to add an argument to every method of every service:

public interface MyService extends RemoteService {
  public boolean doSomething(String cookieValue);
  public void doAnotherThing(String cookieValue, String arg);
}

This is where gwt-dispatch comes to the rescue and makes you thankful for people who turn verbs into nouns. Because gwt-dispatch uses the Command pattern, all standard GWT-RPC services are replaced with a single DispatchService that accepts an Action and Result argument. Each method in a standard GWT-RPC service is now represented by a corresponding Action and Result class. Because there is now only one real GWT-RPC service, the DispatchService, and because its execute method gets called for every request, we now have only place we need to add a session token argument. The gwt-dispatcher SecureDispatchService does exactly this:

package net.customware.gwt.dispatch.client.secure;

import net.customware.gwt.dispatch.shared.Action;
import net.customware.gwt.dispatch.shared.Result;

import com.google.gwt.user.client.rpc.RemoteService;
import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;

@RemoteServiceRelativePath("dispatch")
public interface SecureDispatchService extends RemoteService {
    Result execute( String sessionId, Action<?> action ) throws Exception;
}

By implementing this service on the server, we now have one place where we can verify the user is logged in as well as verify that the session ID passed as an argument with the request matches the session ID cookie sent automatically by the browser.

So here is my take on an AppEngineDispatchService that builds on gwt-presenter's SecureDispatchService to achieve both user authentication and a measure of CSRF/XSRF protection. Because gwt-presenter's SecureDispatchAsync class has a dependency on its own SessionUtil class, I had to replace it with AppEngineDispatchAsync; however, this could easily be factored out as an interface in a future release of gwt-presenter (and indeed has been already on the server side).

One last thing to mention: AppEngine uses a cookie named "ACSID", so that's what we're passing with each request.

Our first class is just a stripped-down version of gwt-presenter's SecureDispatchServiceAsync which passes the AppEngine session ID as an argument with each request.

package com.turbomanage.gwt.client.dispatch;

import net.customware.gwt.dispatch.client.DispatchAsync;
import net.customware.gwt.dispatch.shared.Action;
import net.customware.gwt.dispatch.shared.Result;

import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.Cookies;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.turbomanage.gwt.client.service.AppEngineDispatchService;
import com.turbomanage.gwt.client.service.AppEngineDispatchServiceAsync;

/**
 * An AppEngine-aware implementation of {@link DispatchAsync}
 *
 * (c) 2009 David M. Chandler
 * Licensed under the Apache License, Version 2.0
 */
public class AppEngineDispatchAsync implements DispatchAsync {

    private static final AppEngineDispatchServiceAsync realService = GWT.create( AppEngineDispatchService.class );

    public AppEngineDispatchAsync() {
    }

    /* (non-Javadoc)
	 * @see com.turbomanage.gwt.client.dispatch.AppEngineSecureDispatchServiceAsync#execute(A, com.google.gwt.user.client.rpc.AsyncCallback)
	 */
    public <A extends Action<R>, R extends Result> void execute( final A action, final AsyncCallback<R> callback ) {

    	// Get AppEngine session ID
        String sessionId = Cookies.getCookie("ACSID");

        realService.execute( sessionId, action, new AsyncCallback<Result>() {
            public void onFailure( Throwable caught ) {
                callback.onFailure( caught );
            }

            public void onSuccess( Result result ) {
                callback.onSuccess( ( R ) result );
            }
        } );
    }

}

To use this class instead of gwt-presenter's Standard or SecureDispatchAsync, simply modify the binding in your GIN module:

    @Override
    protected void configure() {
    ...
        bind( DispatchAsync.class ).to( AppEngineDispatchAsync.class ).in( Singleton.class );
    ...
    }

Now for the service interfaces. These are just renamed from gwt-presenter's SecureDispatchService and SecureDispatchServiceAsync, which was necessary because I could not use gwt-presenter's SecureDispatchServiceAsync on account of the above-mentioned dependency on SessionUtil and GWT seems to require that a service and its corresponding Async class exist in the same package.

package com.turbomanage.gwt.client.service;

import net.customware.gwt.dispatch.shared.Action;
import net.customware.gwt.dispatch.shared.Result;

import com.google.gwt.user.client.rpc.RemoteService;
import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;

@RemoteServiceRelativePath("dispatch")
public interface AppEngineDispatchService extends RemoteService {
    Result execute( String sessionId, Action<?> action ) throws Exception;
}

And the corresponding Async interface, likewise just renamed from gwt-presenter's SecureDispatchServiceAsync:

package com.turbomanage.gwt.client.service;

import net.customware.gwt.dispatch.shared.Action;
import net.customware.gwt.dispatch.shared.Result;

import com.google.gwt.user.client.rpc.AsyncCallback;

public interface AppEngineDispatchServiceAsync
{
	void execute(String sessionId, Action<?> action,
			AsyncCallback<Result> callback);
}

Finally, our server implementation of the DispatchService:

package com.turbomanage.gwt.server.service;

import java.util.logging.Logger;

import javax.servlet.ServletContext;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;

import net.customware.gwt.dispatch.client.secure.SecureDispatchService;
import net.customware.gwt.dispatch.server.Dispatch;
import net.customware.gwt.dispatch.shared.Action;
import net.customware.gwt.dispatch.shared.Result;
import net.customware.gwt.dispatch.shared.secure.InvalidSessionException;

import com.google.appengine.api.users.User;
import com.google.appengine.api.users.UserService;
import com.google.appengine.api.users.UserServiceFactory;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
import com.turbomanage.gwt.client.service.AppEngineDispatchService;

/**
 * A servlet implementation of the {@link SecureDispatchService}. This verifies
 * that an AppEngine user is logged in and inspects the passed AppEngine
 * session ID to prevent CSRF/XSRF attacks
 *
 * (c) 2009 David M. Chandler
 * Licensed under the Apache License, Version 2.0
 */
@Singleton
public class AppEngineDispatchServiceServlet extends RemoteServiceServlet
		implements AppEngineDispatchService
{
	private static final long serialVersionUID = -1456388230348266500L;
	private static final Logger LOG = Logger.getLogger(AppEngineDispatchServiceServlet.class
			.getName());

	private final Dispatch dispatch;
	private Provider<HttpServletRequest> req;

	@Inject
	public AppEngineDispatchServiceServlet(Dispatch dispatch, Provider<HttpServletRequest> req, Provider<ServletContext> context)
	{
		this.dispatch = dispatch;
		this.req = req;
	}

	public Result execute(String clientSessionId, Action<?> action) throws Exception
	{
		try
		{
			String serverName = req.get().getServerName();
			UserService userService = UserServiceFactory.getUserService();
			User user = userService.getCurrentUser();
			if (user != null)
			{
				// User is logged in, now try to match session tokens
				// to prevent CSRF
				String sessionId = "";
				Cookie[] cookies = req.get().getCookies();
				for (Cookie cookie : cookies)
				{
					if (cookie.getName().equals("ACSID"))
					{
						sessionId = cookie.getValue();
						break;
					}
				}
				// Skip check on localhost so we can test in AppEngine local dev env
				if (("localhost".equals(serverName)) || (sessionId.equals(clientSessionId)))
				{
					return dispatch.execute(action);
				}
			}
			throw new InvalidSessionException();
		}
		catch (RuntimeException e)
		{
			LOG.warning("Exception while executing " + action.getClass().getName()
					+ ": " + e.getMessage());
			throw e;
		}
	}
}

For each request, we're simply calling the AppEngine UserService to verify the user is logged in and attempting to match the AppEngine cookie passed as an argument with the one passed as a cookie. In order to get access to the cookie on the server, we utilize a Guide Provider that lets us get to the ServletRequest. Likewise, we obtain the ServletContext in order to get the server name and skip the CSRF check on localhost, since AppEngine doesn't set the ACSID cookie when running in the local development environment.

Lastly, we replace the gwt-presenter Standard or SecureDispatchServiceServlet with our AppEngine equivalent in the server's Guice module:

	@Override
	public void configureServlets()
	{
		// NOTE: change the servlet context for your app
		serve("/your_app/dispatch").with(AppEngineDispatchServiceServlet.class);
	}

Thanks to gwt-presenter and the Command pattern, every AppEngine service request in our application now checks for a logged in user and provides a measure of CSRF protection.

23 Responses to “Calling AppEngine (securely) from GWT with gwt-dispatch”

  1. I really like this and think this is a really good idea. The only thing I can see right now is adding an annotation @Secure to the mix to enable some requests to use the secure version and others (where you don’t care or don’t expect) the user to be logged in. I’m going to add this to my app.

    on a separate note,
    I noticed you’re extending RemotServletService, how are you passing your JDO objects back and forth from appengine to GWT? I’m using adapter4appengine (built from sorce) so I extend EngineRemoteService.

    • Thanks, I like the idea of an @Secure annotation, as well. Would you put this on the Action or ActionHandler? A further annotation or param may be needed to indicate Actions that require an admin user.

      As to RemoteServletService, I must be getting lucky, as I’m not doing anything special to pass JDO objects and I have been able to deploy & run successully… I’m on GWT 1.7 and appengine-1.2.5 with latest Google plug-in. The JDO classes I’m using are:

      import javax.jdo.annotations.IdGeneratorStrategy; import javax.jdo.annotations.IdentityType; import javax.jdo.annotations.PersistenceCapable; import javax.jdo.annotations.Persistent; import javax.jdo.annotations.PrimaryKey;

      I did have JDO serialization exceptions early on, but was able to resolve them by adding an empty constructor to my JDO objects.

      • Interesting. I haven’t been able to get that to work with the stock jdo objects.

        I would do it at bind time.

        bind(DispatchAsync.class).annotatedwith(Secure.class).to(AppengineSecureDispatchAsync.class);
        bind(DispatchAsync.class).annotatedwith(SecureWithAdmin.class).to(AppengineSecureWithAdminDispatchAsync.class);
        bind(DispatchAsync.class).to(StandardDispatchAsync.class);

        @Inject
        WidgetPresenter(EventBus eventBus, WidgetDisplay display, @SecureWithAdmin DispatchAsyc dispatch)

        The only problem is you have to setup 3 seperate servlets and bindings to them, but that shouldn’t be an issue since they need different information anyway.

        Then on every presenter where you need the secure dispatch you just add the secure action.

        then in your dispatch modules you could wrap your actions inside another action (or whatever kind of class you would like most likely)

        so your execute method would remain the same, but inside the execute you would grabe your cookie information (if necessary) then it would get dispatched up to the server.

        Create 3 guice servlet bindings.

        serve([your_app]/dispatch, StandardDispatchServiceServlet)
        serve([your_app]/secureDispatch, SecureDispatchServiceServlet)
        serve([your_app]/secureAdminDispatch, SecureAdminDispatchServiceServlet)

        Now you’re saying, but what if I want to have access to my insecure commands on my secure network. No worries, Guice can handle this.

        protected void configureHandlers(){
        install(new StandardDispatchActionHandler())
        }
        then at the secure with admin you can do the same except make it

        install(new SecureDispatchActionHandler())

        the only problem with this approach is would get ugly if you weren’t using google’s users anymore and rolled your own security policy. Then you would just want to send up your user information every time and have it check your rights before
        doing each action.

        I home to have a demo of this up and running by Sunday. I’ll post it then when I get my site up and running (assuming this implementation works)

      • Very cool, thanks for the code. Another idea that comes to mind to avoid having three different DispatcherServlets is to simply extend the Action interface with AuthenticatedAuction and AdminAction interfaces. Then a single DispatcherServlet and single ActionHandler could enable the various permission checks if desired. Although not strictly necessary from a security point of view, I don’t mind doing CSRF prevention even for actions that don’t require it, in which the case the “extra” sessionId parameter to the DispatchService really isn’t extra. I expect to be digging into this a little deeper over the next week, too. I look forward to seeing your example.

  2. Steph said

    Would you be able to include a .zip file of the code? For me the code is all messed up with symbols, etc. ( & amp ;)

  3. [...] all RuntimeExceptions and log all the info you need. In light of this, I’ve now beefed up my gwt-dispatch service servlet to log a severe message and print a stack [...]

  4. [...] project page GWT MVP project samples page Pro Web 2.0 Application Development with GWT GWT Security GWT secure calls to GAE Zack Grossbart on GWT Anti patterns IBM GWT Usability guide Filed under: GWT/GAE Project Leave a [...]

  5. [...] featuring two posts on how to unit test MVP applications in GWT). Second is TurboManage, whose sample code is more detailed than many apps I’ve [...]

  6. [...] code for checking is what David Chapman talks about. I’m not sure he follows all the suggestions from the FAQ [...]

  7. [...] of the best tutorials I’ve seen in either Java or .NET. A good chunk of the explanation is from this post and I should note that most of the code in it has been incorporated into gwt-dispatch [...]

  8. Really nice exemples, again !

    It would be really usefull to have an exemple with secure and insecure command like in Gwtbyexemple comment.

    I tried what he said, but unfortunately, it didn’t work.

    Thanks

    • Can you be a little more specific on what you’re looking for? The Action classes do not change, just the dispatcher and servlet as shown here. Most of this code is now in gwt-dispatch trunk in slightly better form, but I haven’t had time to update the post yet.

  9. Nice work !

    I have one question though, how would we authentifie the user if he’s not ?

  10. Alex said

    Maybe I’m missing something here but… If your client GWT code can access and provide the value of the session cookie, so can any CSRF/XSRF code.

    Surely the point is that the server must provide a secret token at client login – that is *ONLY* accessible to the GWT client side code.

    • Alex, if the app is also vulnerable to XSS, all bets are off; however, absent XSS, a CSRF attack involving just a hyperlink or form POST from the attacker’s server does not have the ability to modify the HTTP headers in the victim’s app so this simple measure is sufficient.

  11. [...] featuring two posts on how to unit test MVP applications in GWT). Second is TurboManage, whose sample code is more detailed than many apps I’ve [...]

  12. Update for those interested in XSRF protection: as of 2.3, GWT has a mechanism that makes it relatively easy to protect GWT-RPC services without the Command pattern. See http://code.google.com/webtoolkit/doc/latest/DevGuideSecurityRpcXsrf.html for more info. If your client-side services are singletons obtained from a factory, you can simply make one call to the XsrfTokenService at load time, then call setRpcToken on each service with the result. Thereafter, when you obtain a service from the factory, it will be ready to go.

  13. Robert said

    The ACSID cookie is now httponly and thus not accessible to client javascript, so it cannot be passed with the request anymore.

    Is there a workaround for this problem? Thank you for the great work!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
Follow

Get every new post delivered to your Inbox.

Join 220 other followers

%d bloggers like this: