The sites needed to be open and avoid repeatitive tasks such registering users. The way forward was to implement some authentication to allow users to register with some sort of universally accessible ID (or sort of). Facebook Connect, OpenSocial and Google Accounts have their advantages but to me personally; the disadvantages outweight the pros. These are some of the disadvantages of those platform:
- Facebook is a popular site hence is its platform, Facebook Connect, in mostly Europe and America but not everybody in Europe and America have a Facebook account.
- OpenSocial, when it comes to single logon, has more advantages than Facebook. I supposed that if we do take into consideration all the OpenSocial sites, we might have apossible larger user based than supporting Facebook alone. Even that was too limited.
- Google Accounts, one thing Google does not advertise its user base. I could be wrong but do anybody actually knows how many people uses the various Google services (excluding search). Google has the same disadvantages as Facebook.
Enter OpenID. OpenID has been around longer than most Internet-based decentralised authentication platform. The beauty of this platform is that it also supported by most (if not all) large site on the Internet. From AOL, BBC, CNN to YAHOO and ZIMBRA, as I said most sites (based on the alphabet) support OpenID, check the OpenID Directory. It was recently announced that OpenID has reached 1Billion enabled accounts (read here). Based on those figures, I decided that OpenID for now was the authentication choice for this application. I will not be discussing any security issues in this entry, there are plenty of resources available on the Internet for that.
OK, so I am a Java developer and I am developing the front-end using GWT and Java on the server-side. I searched on the Internet for solutions on how to implement the authentication as GWT RPC are different to normal servlet call. I spent more time reading about the OpenID specification and implementations examples on the Internet. I have to admit that some of tutorials that I found on the Internet were somehow confusing and not helpful at all. Therefore I decided to write my own Dummies Guide to GWT and OpenID.
Dummies Guide to GWT and OpenID
First of all, it is important to know how OpenID works (please check the OpenID site for more info).
In a nutshell, OpenID allows you to authenticate with website (supporting the standard) with just an URL and voila. Your URL has to be hosted by an OpenID provider in order for it to work. For example, my blog is hosted by Google on blogspot.com. Google supports OpenID authentication therefore if a reader wanted to leave a comment on my blog, he does not have to have a Google Account as he can log-in with his Yahoo or AOL or Facebook or WordPress or any other OpenID provider sites, and then leave a comment, that simple.
GWT to OpenID and back
There are two ways to authenticate a user with an OpenID provider and GWT supports both. When authenticating a user, the relaying site (the site the user is trying to access) redirects to user to the OpenID provider (i.e. Google) login page.
The problem will be with the GWT RPC mechanism. GWT RPC calls are asynchronous and you cannot make any redirections. Therefore we need a way to execute the redirection from the client side, here is the code (I use OpenID for Java to handle the openID discovery from the RPC servlet), I then used USER object (just a simple POJO which only stores the redirection URL and the parameters) to be sent back and forth between the front-end and back-end.
#######################################################
public User authenticateOpenId(String provider_url) {
try {
ConsumerManager manager = new ConsumerManager();
// This is the URL where the OpenID provider will redirect the user
// once logged in.
String returnToUrl = “http://localhost:8084/GwtOpenId“;
// the provider URL will be used to identify the user OpenID provider
List discoveries = manager.discover(provider_url);
DiscoveryInformation discovered = manager.associate(discoveries);
// OpenID 4 Java needs to have an HttpServletRequest object, GWT sevlet
have
// convenient methods to retrieve the HttpServletRequest object
and manipulate its
// parameters
this.getThreadLocalRequest().setAttribute(“openid-disc”, discovered);
this.getThreadLocalRequest().setAttribute(“openid.mode”, “popup”);
AuthRequest authReq = manager.authenticate(discovered, returnToUrl);
FetchRequest fetch = FetchRequest.createFetchRequest();
// I want to exchange the following attributes from the OpenID provider
// remember that teh attribute will be returned only if it exits
fetch.addAttribute(“email”,”http://schema.openid.net/contact/email“,true);
authReq.addExtension(fetch);
// Simple POJO to persist the data
User user = new User();
// In a normal servlet development, the following statement would make
// a redirect call but this would not work when using GWT RPC
if(!discovered.isVersion2()){
user.setRedirect(authReq.getDestinationUrl(true));
// fakes the redirect by sending the POJO with the required parameters
// to make a client-side redirect
return user;
} else{
user.setParams(authReq.getParameterMap());
user.setRedirect(authReq.getDestinationUrl(false));
// fakes the redirect by sending the POJO with the required parameters
// to make a client-side redirect
return user;
}
} catch (MessageException ex) {
Logger.getLogger(GWTServiceImpl.class.getName()).log(Level.SEVERE, null, ex);
return null;
} catch (DiscoveryException ex) {
Logger.getLogger(GWTServiceImpl.class.getName()).log(Level.SEVERE, null, ex);
return null;
} catch (ConsumerException ex) {
Logger.getLogger(GWTServiceImpl.class.getName()).log(Level.SEVERE, null, ex);
return null;
}
}
#############################################################
The above codes will format the request in order for the front-end to execute a redirect and allow the user to authenticate with his OpenID provider. Now here is the front-end code which executes the authentication and reads the data back.
#################################################################
// This is an extract from the openidEntryPoint.java
// This is where the magic happens – This code is only usefull when the OpenID
provider
// redirects the user back to your site – please visit openid.net for valid
parameters.
// The “if” statement checks to make sure that it is a valid response from
the OpenID
// provider – You can do anything you want with the results here such
as verifying the
// response with the server-side code
if(Window.Location.getParameter(“openid.rpnonce”) != null){
String s = Window.Location.getParameter(“openid.mode”);
// executes this if the user cancels the authentication process and the OpenID
// providers returns to the your site
if(s.equals(“cancel”)){
sign.setText(“Server returned openid.mode=cancel”);
openIdUrl.setText(“You need to Accept not Cancel”);
}
// Here, I am assuming that everything is fine and that the user has
been sucessfully logged in
else{
sign.setText(“You have successfully signed in”);
vp.setVisible(false);
}
}
RootPanel.get().add(contentPanel);
}
private class UserAsyncCallback implements AsyncCallback<User> {
public void onFailure(Throwable caught) {
Window.alert(caught.getLocalizedMessage());
}
public void onSuccess(User result) {
if (result != null) {
// Window.open(result.getRedirect(), “_blank”,
“height=200,width=400,left=100,” +
// “top=100,resizable=no,scrollbars=no,
toolbar=no,status=yes”);
// this the most important line in order to make the authentication.
Here, I am redirecting the user
// from the client side to the OpenID provider URL with the discovery
data generated from the
// RPC call to the servlet.
Window.Location.assign(result.getRedirect());
} else {
Window.alert(“Ooops!!! Couldn’t find your provider”);
}
}
}
#######################################################################################################
I have attached the full NetBeans project with dependencies. The code is provided as-is and use at your own risk ;). Here is a screenshot of the working application:
Step1: Authenticate on the site (enter the URL)
Step2: Redirect to OpenID provider (Google is my provider 🙂 ), authenticate with your provider
Step3: Allow the application to access your OpenID details and redirect back to the original site
Step4: final step, check the parameters from the provider and proceeds accordingly
Take a look at the URL in each of the above step to see the OpenID data. OK, so my code actually works (yuppie), now you know that it is possible form GWT to OpenID and it’s not as complicated as many other sites are trying to show. The code is just for authentication but once authenticated, you can retrieve any parameters that you need. In this example, the query is sent through the browser URL (GET) but you can change it to be encoded in a form submit action. Iwrote some of the code to allow the user to authenticate via a popup window, the code is not complete and maybe someone else might want to have a go. My only problem is getting the redirect back to the original window but apart from that it works.
I hope you guys enjoyed it and Happy Coding.

Hi Armel
This is a very good start – but I think the example is incomplete (or it may be that I don't understand what you have done).
The problem is the parameters coming back from the OpenID provider need to be verified. Otherwise anyone could just perform a GET with the right parameters and be "authenticated" without actually going through the openid provider.
The verification needs to be done via a call to the openid4java library. So you either need to compile this client side (a tricky proposition -I don't think the GWT compiler would convert all of the openid4java library to javascript) – or you have to perform the work on the server side.
I think you could extend the example to have the client call back to another server side function that does the verification. The same consumer manager used to create the request has to verify it.
I am working on getting this going – so I will ping you if I get it working.
@wstrange the code that I wrote was actually adapted from the openid4java example (http://code.google.com/p/openid4java/wiki/SampleConsumer) and if you take a look at the second method, it that part that verifies the authentication. This is not the hardest part so I believe to covered the most important aspect. You can make the ConsumerManager to be a singleton as that it will be the same object that has generated the initial provider and then verifies it. You can also store it the object if you do not want it as a singleton so that you cache the object for later retrieval. Let me know if you need more clarification on the subject.
Thanks for the comment.
Hi Armel
The openid4java SampleConsumer example uses a session variable to store the discovery information used to generate the request. This discovery state is unique for each web client and must be used to validate the response.
In your example above you are using thread local storage (not a session variable) and you don't appear to be calling the manager.verify() method to verify that the response from the OP is valid. The parameters passed back in the redirect must be verified (you can't just extract them from the URL and assume they are valid – this can be spoofed). I can't see where your code is doing the verification.
I don't believe making the consumer manger a singleton is doing what you think it is. It's the discovery information that is generated by the manager that needs to be stored per client instance:
DiscoveryInformation discovered = manager.associate(discoveries);
and then retrieved from the session (or other mechanism) to perform validation on the parameters coming back from the OP:
DiscoveryInformation discovered = (DiscoveryInformation)
httpReq.getSession().getAttribute("openid-disc");
VerificationResult verification = manager.verify(
receivingURL.toString(),
response, discovered);
I think your example "works" in the sense that it lets someone logon. But if you are blinding trusting the URL parameters this is not secure.
Warren
Hi Warren,
You are right as stated in the blog article, I was just demonstrating how to implement a OpenID using GWT as they were interest about it in forums. As soon as I have sometimes to focus on this article, I will extend it to implement the verification. Off-my head, I supposed you can save the instance in some sort of caching and use a unique identifier key to retrieve the value when you need it. You should also think about putting an expiry on the cache for security reasons.
Also, if anybody has already implemented the verification process using GWT as above, please do share it.
Armel
Hi Armel, I have written a post about my implementation of your code into grails / GWT and adding server-side verification of the OpenId response through service-side session storage.
Take a look at:
http://code-omen.blogspot.com/2010/10/dum-guide-to-openid-gwt-and-grails.html
Hi Armel,
I am using GWT/GAE with the jar – openid4java-gaehacks-0.9.5-593.jar
I get the following:
With https://me.yahoo.com, the response is
Sorry! You will not be able to link your Yahoo! account with this website or application. It is using an older version of the OpenID technology.
With https://www.google.com/accounts/o8/id, the response is
The page you requested is invalid.
Any help ?
Try changing:
user.setRedirect(authReq.getDestinationUrl(false));
to
user.setRedirect(authReq.getDestinationUrl(TRUE));
in authenticateOpenId(String provider_url) method when discovered is version2.
I've been struggling for like 2 weeks to make this work with openid4java-gaehacks-0.9.5 thinking it was because the version of the library. Tried to mix up some things of the newest version (0.96), built with ant and still didn't work. I was almost going to give up.
Suddenly, today, when I was about to surrender, I get to see your bless reply. I have no words to describe my thankfulness to you. Just thank you SO MUCH.
I too want to add OpenId login support to my GWT app. This was originally posted Dec 2009, based on the comments it seems the code was almost working? Did you ever get it finished? Is the redirect back to original window working? If you have some updated code could you update the post or send to me dhoffer6 at gmail dot com, many thanks!