Basics of GWT Authentication

I have been trying to understand how to authenticate users for a GWT application. This is my version of the basics.

Overview

I took the starter application for a GWT app, the greeting app, and modified it to be LoginAndGreet. Before being able to see the greeting from the server, users must sign in with their Google  id and password.

The code that follows looks complicated, but it’s not really. Basically all you are doing is:

  1. Adding some lines to your web.xml file so the server side knows that you want authenticated access.
  2. Doing something on the client side to request user information from the server.
  3. That request triggers a redirect so you are prompted for your user id and password.
  4. When the authentication request succeeds, the client side is notified and continues loading your application.

Details

1. Add security constraint to web.xml. To require a login for all resources in your web application, put these lines before the welcome-file-list section of the file.

<security-constraint>
<web-resource-collection>
<web-resource-name>all</web-resource-name>
<url-pattern>/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>*</role-name>
</auth-constraint>
</security-constraint>

2. Do something in onModuleLoad method that retrieves user information from the server via RPC. It can be something as simple as getUserEmail, as shown here.

/**
* This is the entry point method.
*/
public void onModuleLoad()
{
// Start out by trying to get information about the current user.
// If that succeeds, we will continue to set up the app. See onLoggedIn below.
getUserEmail ();

}

/**
* Show a form for the user to fill in to get a greeting from the server.
*/

public void onLoggedIn()
{
// Note that this is basically the same as the onModuleLoad method in the starter code.

String name = “GWT User”;
if (userEmail == null) name = name + ” (not logged in)”;

// … original onModuleLoaded code goes here

}

3-4. The request goes through a method like getUserEmail below.

Calling it triggers a redirect so you are prompted for your user id and password. Note that getUserEmail, upon success calls onLoggedIn and your application loads as it used to.


/**
* Use RPC to login the current user.
* Save the email address if it succeeds. Otherwise, bring up an alert box.
*/
private void getUserEmail ()
{
greetingService.getUserEmail (new AsyncCallback<String>() {
public void onFailure(Throwable caught)
{
Window.alert ("You have not logged in yet. Refresh this page to try again.");
}
 

public void onSuccess (String result)
{
userEmail = result;
onLoggedIn ();
}
});
}

So the changes to onModuleLoad are minor. You will of course have to add methods to the service classes that define the RPC for getting user information. Those classes look like the following.


@RemoteServiceRelativePath("greet")
public interface GreetingService extends RemoteService
{
static class NotLoggedInException extends Exception {}

String getUserEmail () throws NotLoggedInException;
String greetServer(String name) throws NotLoggedInException;
}

public interface GreetingServiceAsync

{
void getUserEmail (AsyncCallback<String> callback);
void greetServer(String input, AsyncCallback<String> callback);
}

On the server side, calls must be made to UserService methods provide by Google.

@SuppressWarnings(“serial”)
public class GreetingServiceImpl extends RemoteServiceServlet
implements GreetingService
{

/**
* Check whether the user is logged in. Return the current User information or
* throw an exception.
*
* @return String
* @throws GreetingService.NotLoggedInException
*/

public User checkUserLoggedIn () throws GreetingService.NotLoggedInException
{
UserService userService = UserServiceFactory.getUserService();
if (!userService.isUserLoggedIn ()) throw new GreetingService.NotLoggedInException ();
return userService.getCurrentUser ();
}

/**
* Returns email address of the user logged in.
*
* @return String
* @throws GreetingService.NotLoggedInException
*/

public String getUserEmail () throws GreetingService.NotLoggedInException
{
// Before we do anything, check to see if the user is logged in.
User user = checkUserLoggedIn ();
return user.getEmail ();
}

/**
* Returns information about the user and what is running on the server.
*
* @return String
* @throws GreetingService.NotLoggedInException
*/

public String greetServer(String name) throws GreetingService.NotLoggedInException
{
User user = checkUserLoggedIn ();                                                             // added this to ensure user is logged in

// Construct a greeting message.
String serverInfo = getServletContext().getServerInfo();
String userAgent = getThreadLocalRequest().getHeader(“User-Agent”);
return “Hello, ” + name + “!<br><br>I am running ” + serverInfo
+ “.<br><br>It looks like you are using:<br>” + userAgent
+ “.<br><br>You logged in with email: ” + user.getEmail ();                        // added extra lines to show email address
}

} // end class

Once you get that far, you have the basics for authentication with Google accounts for a GWT application. You will know you have succeed if the first thing you see in the browser window is a form to fill in your user id.

Source Code

The example was done originally with Google App Engine v 1.3 and GWT 2.0, but has also been run with GAE 1.4.2 and GWT 2.2.0.

Source code is available in Google Docs at
https://docs.google.com/leaf?id=0B0wYSnCBkoR6ODM4NWJkODctNzcwMy00ZTJiLTgxNWYtMDQ4MDY3MzExODM1&hl=en

References

For Google App Engine on its own, read Google Accounts Java API Overview.

If you do not want to use Google accounts, read this:
http://code.google.com/p/google-web-toolkit-incubator/wiki/LoginSecurityFAQ

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

Great article on security and Javascript: http://groups.google.com/group/Google-Web-Toolkit/web/security-for-gwt-applications?pli=1


About Bill Lahti

Bill Lahti is an indie game developer. Latest project: an exploration game. Recent game: Hop, Skip, and Thump, a simple abstract strategy game. Other iOS and Android games: Double Star II, Wing Leader, Gomoku League.
This entry was posted in gwt and tagged , , , , . Bookmark the permalink.

12 Responses to Basics of GWT Authentication

  1. Sergio says:

    Very very useful!

    Thanks you very much.

    I was looking for this kind of simple-clarified tutorials.

    🙂

  2. blahti says:

    I updated this note. There is now a link to the source code for this GWT/GAE sample application. It has been run against GWT 2.2.0 and GAE 1.4.2.

  3. Vishal says:

    Hey BLahti,
    Could you also elaborate about logging off using logoff URL in this post or as a comment..that will make it complete

    • blahti says:

      I see your point. I did not explain very much about how logging in and logging out work. There are references to the UserService interface methods, but not much else. I think I need to update this note or do a rewrite and include more explanation. Until then, I will share a few more links here.

      The GWT Stock Watcher tutorial has a good section on the UserService methods and how they are used in that example. Its LoginInfo class is similar in purpose to my UserSessionInfo class. My RemoteServiceServlet (GreetingServiceImpl) has a few more methods in it. I wanted to have an easy way to make sure that all server side operations checked that the user was logged in before proceeding. Doing that has worked out well in other apps too. For example, I have one app where I check whether a user is logged in and if that user is a registered user.

      The login and logout urls come from the UserService you get from the server side UserServiceFactory.getUserService () call. Google has helped us out there so we don’t have to worry about redirecting the browser to a login page. All we have to do is figure out where the user goes after the login or logout action. The API gives us the url to embed wherever we need it on our client side.

      A few more useful references: Users Java API , javadoc for API.

  4. BSN says:

    How you test this in development?

    • blahti says:

      This demo program is tested like any other App Engine project. I have found everything works out very well when I use Chrome, Firefox, or Safari as the browser. You can run or debug the application in Eclipse. Click “Debug As – Web Applicatiion” on the Run menu. Once it gets started you should see something in the “Development Mode” view (see “Show View – Other – Google” on the Window menu) that tells you the url to start in the browser. It looks like this: http://127.0.0.1:8888/LoginAndGreet.html?gwt.codesvr=127.0.0.1:997. Copy that to your browser’s address line and retrieve the url. If you are missing the Google Web Toolkit Developer Plugin, you will see a message in a yellow box that tells you what to do to get it. Once you have the plugin set, go to that url again. You should see “Login and Greet” at the top with a text box where you can fill in an email address.

      Breakpoints work fine. Simply set them in Eclipse before you click the “Debug As – Application” menu item.

      All of this is well explained here: http://code.google.com/appengine/docs/java/gettingstarted/creating.html

  5. halil says:

    Thanks for the post. You may also denote in the document that the tutorial requires Google App Engine

  6. Ian says:

    Must this app be deployed on google app engine?
    Can this app be deployed on my own tomcat?
    There is no password just email of user why?

    • blahti says:

      Yes, this example is just for GWT in combination with Google App Engine. It follows conventions for authenticating with a Google App Engine backend. That’s how it gets away with authenticating with only the user id. Behind the scenes, Google’s server side code sets up a session and connects a cookie in the browser to that session. If you are going to go against Tomcat, you’d have to do that yourself. I don’t have a good reference link for that, but a search should turn up a lot of examples.

  7. horjul says:

    How you handle situation:
    public void onFailure(Throwable caught)
    {
    Window.alert (“You have not logged in yet. Refresh this page to try again.”);
    }
    I mean how do you know the difference between bad login credentials and RPC failure?

    • blahti says:

      I have to admit that I have not looked at this in quite some time. I looked quickly at GreetingServiceImpl. All the service methods there send NotLoggedInException so that suggests that the lines you are looking at are only going to be for that case. So the client side failure might show up as something else or maybe the thing to do is check the “caught” variable and see what gets passed there in the two cases: (1) not logged in; (2) RPC failure. You’d have to force an RPC failure in the debugger or by misconfiguring something. Perhaps using the development server, you could get it to work once and then kill the dev server and see what happens in the client.
      If I have time, I will try something like that myself. Sorry that I do not have a better explanation at this time.

  8. Kelle says:

    Hello, Neat post. There is a problem with your website in web explorer, may test this… IE nonetheless
    is the market leader and a large portion of folks will pass over your wonderful writing because of this problem.

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.