Archive for February, 2010

Authenticated access from an iPhone

I have been working on the problem of connecting to a GAE application from an iPhone. Working through examples from the “iPhone SDK Development” was going well, but now I have hit a snag. It seems that some of the code on the iPhone side does not work as expected.

Method connection:didReceiveAuthenticationChallenge of NSURLConnection is not being called. It seems that several other people have had this problem. It is described very well here: http://openradar.appspot.com/5203544.  There’s discussion there of a workaround that no longer works.

So maybe it’s time for my own workaround. What I see coming back from a test request is the login form from Google for an appspot application. I wonder if I could look for that form in the response and when it is there redirect my iPhone app to display that in a UIWebView.

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




Follow

Get every new post delivered to your Inbox.

Join 72 other followers