MongoDB Realm for Glassfish

Saving user’s login and password into RDBMS is an extremely popular way for JavaEE applications to authenticate against. Most, if not all JEE application servers support JDBC realm out of the box.  Setting up a JDBC realm is quite easy. Here is one for Glassfish.

I’ve always wanted to use NoSQL database, and MongoDB in particular as a security realm. One big advantage, for me at least, Mongo have over its JDBC counterpart is that I don’t have to setup the group table with composite key. I found 2 implementation of MongoDB realm for Glassfish in github; see this and this. I’ll be adding my implementation to this lists.

How Glassfish Security Realm Works?

Before we use my MongoDB realm, lets take a look at how Glassfish handles security.

pic4 (Click to enlarge)

Glassfish uses 2 components (or classes) to collect user’s credentials and authenticate users. To collect your username and password, Glassfish delegates that to Java Authentication and Authorization Service or JAAS. The Mongo JAAS (pronounce as Jazz) module is configured in $DOMAIN_DIR/config/login.conf file. You can see this on the top right corner in the above diagram. A JAAS entry consist of the name (mongodbRealm), also know as the JAAS context, and a FQCN of the login module (at.oneminutedistraction.mongodbrealm.MongoDBRealmLoginModule). See this document for an explanation of the required keyword.

The second step is to configure Glassfish so that it recognizes our MongoDB realm and to associated that with the login module. This is typically done in the admin console which we’ll look at later in this blog. For the time being, lets look at the actual configuration file. The domain.xml holds all information about a Glassfish domain. Again, you can find this file under $DOMAIN_DIR/config directory. A auth-realm defines a security realm. It defines 3 pieces of critical information; see the middle portion of the above figure

  • classname attribute – a FQCN of the the class that implements this security realm. In our case this will be at.oneminutedistraction.mongodbrealm.MongoDBRealm.
  • name attribute – a unique name for this realm (mongodb-realm here). This name will be referenced by our web application that uses this realm
  • jaas-context property – the value of this property is the name of the MongoDB login module ( in login.conf file). This property associates the realm with the login module defined in . 

Now to use this realm in your web application, simply specify the realm name (mongodb-realm) in your web.xml.

Configuring MongoDB Realm

Step 1 – Copy JARs to Domain Directory

To use MongoDB realm, download the following 2 files

  • MongoDBRealm – the compiled JAR (JavaSE 8) is available here. If you prefer to build it yourself, the source is available here.
  • MongoDB Java driver – available here

Copy the 2 JARs into $DOMAIN_DIR/lib directory.

Step 2 – Add JAAS Entry to login.conf File

Edit $DOMAIN_DIR/config/login.conf file and add the following lines to the end of the file

mongodbRealm {
   at.oneminutedistraction.mongodbrealm.MongoDBRealmLoginModule required;
}

I’ve called the JAAS context as mongodbRealm. You can use any name you like just as long as its unique within the login.conf. Make a note of this name as we’ll need it when for creating the realm.

Step 3 – Configure MongoDB Realm in Glassfish

Start up Glassfish version 4.1 and must be running on JavaSE 8. Please make sure that Glassfish is using the same domain as in step 1 and 2 above. If you’re not sure, you can start Glassfish like so

asadmin start-domain -–domaindir /path/to/domain/dir domainname

Open up the admin console. This is usually localhost:4848

pic0(Click to enlarge)

and expand server-config, security as shown in the above figure. Next click on the Realm node.

pic5 (Click to enlarge)

You should see a table with all the preconfigured realms. Click on the New to create a new realm.

pic1 (Click to enlarge)

Define the MongoDB realm using the following values

  • Name – mongodb-realm
  • Class Name – at.oneminutedistraction.mongodbrealm.MongoDBRealm
  • Add the following properties: name = jaas-context, value = mongodbReam. The value must correspond to the entry name in login.conf.

This will create the auth-realm entry in domain.xml. Click OK should instantiate the realm. Besides setting the jaas-context property, the following is an exhaustive list of parameters that you can set to configure MongoDB realm

  • mongodbRealm.db – the name of MongoDB database name. The default name is mongodbRealm
  • mongodbRealm.collection – the collection name. The default name is users
  • jaas-context – the JAAS context. The default value is mongodbRealm
  • mongodbRealm.clientFactory – this is the FQCN of the class that creates MongoClient instance of the realm. The default factory is at.oneminutedistraction.mongodbrealm.DefaultMongoClientFactory. There will be an explanation later that describes how you can implement your own client factory
  • mongodbRealm.server – if you are using the default client factory, then this parameter specifies the list of servers that the MongoClient connects to. This is a list of space separated server:port numbers; for example localhost<space>myserver:1234<space>myotherserver connects to localhost, myotherserver and myserver at port 1234. The default value of this is localhost
  • mongodbRealm.passwordManager – this is the FQCN that performs the password encryption. The default password manager class is at.oneminutedistraction.mongodbrealm.SHA256PasswordManager. We will explain how you can create your own password manager class to perform your password encryption
  • mongodbRealm.algorithm – If you are using SHA256PasswordManager, you can set the value of this to either SHA-256 or SHA-512 which uses the respective hash algorithm for hashing user passwords. The default is SHA-256

Username, password and group information are stored in a JSON structure shown below

{ username: "fred",
password: "999f36dd648c74f52972745be2ee94c4b53c48639debbf310bfd5d5fc84ee4f6",
groups: [ "bedrock", "flintstones", "cartoon" ] }

There are 3 properties for each JSON document that describes a user; the username is the login name, the password is the SHA-256 hashed password (assuming I’m using the default password manager) and groups which holds an array of group names. All values are String. Property names viz. username, password and groups are not configurable.

The following code snippet shows how the above JSON is created using MongoDB’s Java API

BasicDBList groups = new BasicDBList();
groups.addAll(Arrays.asList(new String[]{"bedrock", "flintstones", "cartoon"}));
BasicDBObject fred = new BasicDBObject("user", "fred")
      .append("password", "999f3…d5d5fc84ee4f6")
      .append("groups", groups);

We can finally configure our web application to use the realm.

pic3 (Click to enlarge)

When you are configuring container security for your web application, set the name of Realm Name to mongodb-realm.

Customizing MongoDB Realm

To accommodate the various MongoDB and password requirements, there are 2 interfaces you can implement. The first of these is MongoClientFactory.  The purpose of this interface is to allow you to have control over the creation of the MongoClient instance.The interface has the following methods

  • void init(Properties prop) – This method is called when the factory in initialized. A Properties object is passed into the implementation. The property values comes from the values that you enter when you are creating the realm (see image above with New Realm header).
  • MongoClient create() – This method creates the MongoClient instance using the properties from init(). Put your code to create MongoClient in here.

The second interface, PasswordManager, deals with password encryption and validation. It has the following methods

  • void init(Properities prop) – Similar to MongoClientFactory
  • String encrypt(String password) – Returns an encrypted version of the parameter
  • boolean isValid(String encrypted, String password) – This method validates a password by testing the encrypted parameter against the password parameter

Once you’ve implemented either one or both of the above interfaces, bundle them in a JAR and drop them into $DOMAIN_DIR/lib directory. Now set the following two properties to the FQCN of you implementation  when you are configuring MongoDB;

mongodbRealm.clientFactory
mongodbRealm.passwordManager

 

On a separate note, its heartening to see that Glassfish application server now has commercial conterpart in the form of Payara. Its a drop in replacement for Glassfish and it’s build off Glassfish sources. Disclaimer: I’m not associated with Payara in any form save for the fact that I downloaded their application server this morning. There is even a cute Mario like Youtube video introducing it.

Till next time.

AngularJS Workshop Kit

I’ve recently had the opportunity to give a 3 hour AngularJS workshop. We build a (yet) another weather application with AngularJS, ui-router and Angular Animate. The workshop covers the following core concepts

  • Structuring an Angular application (ng-app)
  • Dependency injection
  • What can you inject
  • Controllers (ng-controller)
  • Model View View-Model
  • Loops as in ng-repeat
  • Applying classes (ng-class)
  • Conditional display (ng-if)
  • Animations (.ng-enter, .ng-leave)
  • Filtering expressions
  • Abstraction with service
  • Partial views ($stateProvider, $urlRouterProvider)
  • Navigation between views (#/hashtag, $state)
  • Parameterizing routes ($stateParams)
  • Consuming RESTful web services ($http and promise)

The workshop is available for download at http://bit.ly/angularjs_workshop. The workshop consists of the following items

  • A presentation; the workshop is broken up into 6 distinct steps, each step introducing core concepts. The slides with the ‘Men at work’ image is the workshop
  • Promotion material
  • Prerequisite – what the participants should know before attending the workshop
  • angularworkshop zip – snapshots of the 6 steps
  • A completed weather application

I’ll *probably* do a screencast of the workshop sometime in the future.

If you’re a programming/hackers (in the good sense of the word) club, Java User Group, open source community and you’re in Singapore and you want to run the workshop for your event, drop me a note. If I’m free I’ll be glad to run a workshop for you (free!). Make sure you have ample supply of Coke and chips!

Till next time.

Evolution of Locks and Locking

Harry-Houdini-007 From time immemorial, Java (both the language and the platform) have supported threads. With threading, you’ll need a way to prevent 2 or more threads from stomping over each other. So the earliest version of Java included the synchronized keyword. The following is a contrived example of a shared shopping list; thread safety is maintained using the synchronized

public class ShoppingList { 
   private final List list = new LinkedList<>();
   public synchronized void add(final String item) { 
      list.add(item); 
   }
   public synchronized int count() { 
      return (list.size()); 
   }
}

The synchronized keywords will try to acquire the lock/monitor of the object before entering the methods. If you want to confine the critical region to a smaller area, as oppose to the entire method, then use

synchronized(this) { … }

instead.

JavaSE 5 introduces Lock and CAS APIs into the platform. With the new Lock API, instead of using synchronized you can do the following

public class ShoppingList {
   private final Lock lock = new ReentrantLock();
   private final List list = new LinkedList<>();
   public void add(final String item) {
      lock.lock();
      try {
         list.add(item);
      } finally {

         lock.unlock();
      }
   }
   public int count() {
      lock.lock();
      try {
         return (list.size());
    
} finally { 
         lock.unlock();  
      }      

      return (-1);
   }
}

The advantage of Lock over synchronized is that

  • You can use different lock semantics. The above example I’ve used an exclusive lock  I can also use ReadWriteLock.
  • Flexibility because now you can pass the lock from one thread to another thread or hold a lock over multiple invocation (may not be a good idea)
  • Specify how long to wait for lock by specifying a timeout in tryLock() when acquiring a lock
  • Create multiple conditions for a lock
  • Etc.

One of the MAJOR feature that is missing from Lock is that it does not automatically release the lock. So as a safety precaution, Lock are almost always used inside a try/finally block to ensure that locks are released before we exit the method.

JavaSE 7 introduces the try-with-resource syntax. The idea of the try-with-resource is that resources such as IO streams, ResultSet , etc are automatically closed when they exit the try block. All these resources have to do is to implement the AutoClosable interface.

We can use try-with-resource to automatically release the lock as we exit the try block. There are many ways to implement this. I’m going to go with the simplest

public class AutoUnlock implements AutoClosable {
   private final Lock lock;
   public AutoUnlock(Lock l) {
      lock = l;
   }
   @Override
   public void close() throws Exception {
      lock.unlock(); 

   }
}

Now to use if we can rewrite our ShoppingList as follows

public class ShoppingList {
   private final Lock lock = new ReentrantLock();
   private final List list = new LinkedList<>();
   public void add(final String item) {
      lock.lock();
      try (AutoUnlock ul = new AutoUnlock(lock)) {
         list.add(item);
      } catch (Exception ex) { }
   }
   public int count() {
      lock.lock();
      try (AutoUnlock ul = new AutoUnlock(lock)) {
         return (list.size());
      } catch (Exception ex) { }
      return (-1);
   }
}

Conceptually this is code is very similar to the version with try/finally. The only difference here is that here the unlock is hidden in close().

JavaSE 8 introduces Lambda. Using Lambda, we can now remove the lock()/unlock() combo from all the methods and put them into guards (consider acquiring a lock as a pre condition). Here is a rewrite of ShoppingList

public class ShoppingList {
   private final Lock lock = new ReentrantLock();
   private final List<String> list = new LinkedList<>();
   public void add(final String item) {
      list.add(item);
   }
   public int count() {
      return (list.size());
   } 
   public void guard(final Runnable r) {
      lock.lock();
      try (AutoUnlock ul = new AutoUnlock(lock)) {
         r.run();
      } catch (Exception ex) { }
   }
   public <T> Optional<T> guard(final Callable<T> c) {
      lock.lock();
      try (AutoUnlock ul = new AutoUnlock(lock)) {
         return (Optional.of(c.call()));
      } catch (Exception ex) { }
      return (Optional.empty());
   }
}

With this approach, you can now decide if you prefer the threadsafe or the regular method.

shoppingList.guard(() –> { shoppingList.addItem(“harry”); });

Till next time

Screencast: Part 2 – JavaEE 7, Mongo, REST, Mobile

In the second part screencast, we will take the data news item stored in the Mongo database and expose that as RESTful reesources. When a request arrives it can specify the following 2 parameters in the query string

  • oid – this is the object id of the document/record. This tells the REST resource to start returning the records from the specified oid. If the oid is missing then we will start from the very first record.
  • batchSize – the number of records to return.

To allow the application server to potentially process a large number of records per request, we handle the retrieving and processing of the news items asynchronously. This is very similar in spirit to async Servlets; however unlike async Servlets, in async JAX-RS you need to provide a thread. This is where the concurrency utilities comes in.

Using @Suspended annotation, we get an instance of AsyncResponse. The AsyncResponse object is passed to a Runnable (our task) which is then dispatched to the ManagedScheduleExecutorSerivce. When the Runnable completes, it calls AsyncResponse.resume() to resume the suspended request.

 

 

The NetBeans project for part 2 is available here. You can find part 1 of this series here.

Till next time.

Screencast: Part 1 – JavaEE 7, Mongo, REST, Mobile

This is the first part of a 3 part blog/screencast on creating an end to end application that scrape data of a source and then re exposed these data as RESTful web services.

In the first part, we will look at pulling data into our web application.

In the second part, we will expose these data as RESTful web services

In the third and final part, we will write a mobile client to consume the web services.

The technologies that we will be using will be JavaEE 7 (tutorial), Mongo database and AngularJS/Ionic on the front end.

In this first part, we will be reading RSS feed from BBC Football site (the RSS feed is right at the bottom of the page). The feed entries are saved to Mongo. The following diagram illustrates this

arch_part01 

The feed is read at regular interval. This feature is implemented using JavaEE 7’s ManagedScheduledExecutorService which is a thread pool managed by the application server.

JavaEE application servers supports the concept of connection pooling, in particular database connection pool. However this support only extends to RDBMS. So if you’re using NoSQL databases, then you’re out of luck. One solution is to implement custom resources like this particular example for Glassfish.

Luckily for us, MongoClient, the Mongo’s Java driver has an internal pool (and is thread-safe!). So we can create one instance of MongoClient and get this instance to dish out connection as and when its required. To using this instance as a singleton, we use CDI to wrap it in an ApplicationScoped object. This ApplicationScoped object ensures that only a single instance of MongoClient is created and used throughout the entire application.

The following screencast shows how we create the a JavaEE web application, read RSS feed from BBC Football website and save that into a Mongo database.

The source code can be found here.

Till next time.

Screencast: Creating a Hybrid Mobile Application

Instead of writing a blog for this month, I’ve done a short (30 mins) screencast on how to use Ionic, Angular and Cordova to create a hybrid mobile app.

 

The source (just the www directory and the APK) can be found here.

The app is incomplete; one of the things that you’ll notice is that that when you try to follow a link, the app will open that in a browser. But when you click on the back button, it does not go back to the app. You need to handle the link and display that in the inappbrowser plugin. I’ll leave that as an exercise for the reader.

I initially wanted to display the blogs using drawer navigation; this would make the video longer that I intended. So if your’re curious have a look at Ionic’s side menus.

Till next time.

Using OAuth For Your JavaEE Login

matrix_spoon_boy In my previous blog I  describe how we could add additional security layer to Java EE’s login process. The application server holds a  set of valid username/password; users are authenticated against this set of credentials.

Managing username/password is hard work; what if you are only interested about the user but not necessarily in maintaining the user. If your security requirement is not that stringent, then I could let somebody that I trust  validate that user. Once the user is validated, I can find out about the user. So you don’t maintain any username/password database. As far as you are concern there is no user.

Enter OAuth; it is a standard at allows an application to access data that a user holds in a 3rd party application. In order to access the data, the user first have to authenticated into that 3rd party application; once we pass the authentication stage, then we are authorized to access the data. The really nice thing about OAuth is that you never have to reveal your username or password to the application.

A use case might be an application would like a user’s valid email; one source of this might be from Google. So by using OAuth, the user can authorize Google to release this piece of information to the application. For more details on OAuth watch this video.

For the remainder of this blog, we will look at

  1. how to use Google’s OAuth2 provider for authentication and authorization; we’ll look at what are the information/resources we can release and how to go about doing that
  2. how to integrate/use Google’s OAuth2 as our authentication mechanism for a web application.

Register and Configure Your Application

To start using Google as our OAuth2 provider, you’ll need first do the following list of things

  1. Create a project or service account (in Google)
  2. Create a new client id
  3. Select the information/resources that your application wishes to use
  4. Optionally, configure the consent screen

Here is how everything hangs together:

  1. An user Fred, attempts to access some restricted resources/page on the JavaEE application. The JavaEE application server determines that Fred need to first login.
  2. The web application redirect Fred to  Google’s login page. Fred proceeds logins to his Google account; if Fred has already login to his account, then he will not need to relogin.
  3. After Fred has successfully login, Google OAuth2 provider will display the consent page. The consent page provides details about the web application and more importantly what resources is it trying to access, eg Fred’s email and Google+ id, his drive, etc.
  4. If Fred consents, Google now redirects the browser back to our web application

Now lets look at these steps in greater detail.

The first thing you’ll need to do is to create a project using Developer Console. This project is our JavaEE’s representation in Google’s universe. When a user gives permission to our JavaEE application to access his email, the user is actually giving permission to this project.

s0

In the example above, my project’s name is Gatekeeper and the project id is gatekeeper-sg1. Go into the project by clicking on the project’s name. On the left hand side, expand ‘API & auth’ menu item and you should see APIs, Credentials and Consent Screen.

To create client id, click on Credentials, followed by clicking on CREATE NEW CLIENT ID.

s1

Decide on the type of application you are developing. In our case its going to be a web application. Next you’ll have to configure 2 pieces of additional information associated with Web Application. The Authorized JavaScript is your application’s address in this case is the application’s domain. Since I’m writing a demo, that will be localhost with the port number. The Authorized redirect URI is the URI that Google will redirect to after the user has successfully login and have given permission for our application to access certain information.

s2

The above shows the newly created client id. We will need the Client ID, Client secret and Redirect URIs later when we write our web application.

So the next thing we need to decide is what do we want to access from a user’s Google account. Click API under APIs & auth. You will now see a list of all the resources available. For our case, we are only interested in basic information, so we’re going to enable Google+ API. Enable all the API that the application will be needing. Note that most of these API have a daily limit (for free use). We’ll look at how to use the Google+ API that we have enabled in the next section

One final, you can customize the consent screen by entering the web application’s url, image, T&C, etc under the Consent screen menu.

Exploring the API

As I’ve mentioned earlier, Google provide lots of resource that we can access. In our case we are interested in a user’s Google+ details. All of these resources are access using REST. Google provides a playground for you to experiment with these API. The playground allows you to

  • Find out what are the resources available eg. under Google+ there are different resources like email, profile, login
  • How to invoke them
  • What is the structure of the returned JSON data
  • What are the OAuth2 scopes (more on scopes later) namespaces

s3 Assume we are going to get basic detail about a user from his Google+, so let see how we do this using playground.

Open up playground. Under Step 1, look for Google+ API v1 (don’t forget to enable it in your application). Under that you will see list of information accessible. Select the information that the application will need to access; what we are saying here is that if a user eg Fred logins to our web application, then Fred will have to provide these information to the web application. The consent page will display these details. So check whatever details you want to access. As a best practice, ask for the minimum amount of information in order for your application to establish a trust relationship with the user.

The URL that you see are the scopes. Make a note of these eg. if the example on the left, I have 3 scopes: https://www.googleapis.com/auth/plus.me, https://www.googleapis.com/auth/userinfo.email and https://www.googleapis.com/auth/userinfo.profile.

Once you’ve selected all the API, click on the Authorize APIs button. This is to authorize playground application (for testing) to access these resources from your Google account.

If you’re using this the first time, then you’ll probably see Playground’s consent screen requesting permission to access to API from Step 1 above. Click on Accept to proceed. If you don’t then you cannot test those APIs.

s4 Once you’ve consented, you’ll be taken to Step 2. Nothing much to do here except to click on Exchange authorization code button which will now take you to Step 3. We are now ready to test the Google+ API. Click on List possible operations button. Depending on what you’ve request in Step1, you will now be presented with a list of URL that you can call.

s5

Select Userinfo (in our case) from the list then click on Send the request.

s6

From the response, you can see the JSON structure of the resource. So by using the playground, you can find out

  1. What is the URI for a particular to get a particular piece of information
  2. What is the HTTP method to use
  3. What is the JSON structure of the result
  4. What are the required scopes (from step 1)

Integrating with JavaEE

We now have everything we need from the OAuth provider, we will now look at how to add this to our web application.

Start by configuring your web application to use form based authentication. You should provide a login page with a button to login via Google.

<form method=”GET” action=”googleplus”>
   <button type=”submit”>Login</button>
</form>

You could also provide the option of using the traditional way of login with j_security_check.

We will now have to write a servlet that maps to googleplus. This servlet will be performing the OAuth2 setup and login. Lets look at the code first

@WebServlet("/googleplus")
public class GooglePlusServlet extends HttpServlet {

   private static final String CLIENT_ID = "client id here";
   private static final String CLIENT_SECRET = "client secret here";

   @Override
   protected void doGet(HttpServletRequest req, HttpServletResponse res)
      throws IOException, ServletException {

      //Configure
      ServiceBuilder builder= new ServiceBuilder();
      OAuthService service = builder.provider(Google2Api.class)
         .apiKey(CLIENT_ID)
         .apiSecret(CLIENT_SECRET)
         .callback("http://localhost:8080/mywebapp/oauth2callback&quot;)
         .scope("openid profile email " +
               "https://www.googleapis.com/auth/plus.login " +
               “https://www.googleapis.com/auth/plus.me”) 
         .debug(System.out)
         .build(); //Now build the call

      HttpSession sess = req.getSession();
      sess.setAttribute("oauth2Service", service);

      resp.sendRedirect(service.getAuthorizationUrl(null));
   }
}

GooglePlusServlet is the servlet that will handle the OAuth login.Google has documented the authentication exchange here. I’m however going to using the excellent Scribe library. From the ServiceBuider we lookup Google’s OAuth2 Provider class. Once we have the OAuthService, we need to set the client id, the client secret and the URI callback . All these 3 pieces of information must match the project we created earlier.

Next comes the scope information; scope is use to indicate to Google what resources are we interested in accessing. In other words what is the scope of this request. The scope in this case must always start with the string openid followed by a space delimited scope namespaces. The 2 standard namespaces are profile and email. If we just have those 2 namespace, then we are saying that we are interested in the user’s profile and email. Google supports additional scopes for its services. This is where playground comes in. If you recall, when we were exploring the API, we are also shown the scope. If we want the request to access the user’s G+ profile and circles, then add their scope namespaces to the scope() method as shown above.

Note: Scribe supports may OAuth providers out of the box. However Google is NOT one of them; the reason is found here. This gist adds support for Google. Add the Google2Api class into your project and you’re good to go.

After constructing OAuthService, save that in the session cause we’ll be using it in the next phase of the authentication.

Now its time to forward our request to Google. Get the authorization URL from service.getAuthorizationUrl() and perform a redirect to it. So what is going to happen now is

  • If you are not login to your Google account, you will now be asked to do so.
  • If this is the first time you are using the web application, you will be shown the consent screen. You can now choose to accept or reject. Once you’ve consented to the request, this permission is saved into the user’s account permissions.

Google will now perform a callback to the configured callback URL. To handle the callback, we’re going to need another servlet

@WebServlet(urlPatterns={"/oauth2callback", asyncSupported=true)
public class OAuth2CallbackServlet extends HttpServlet { @Override
   protected void doGet(HttpServletRequest req, HttpServletResponse resp)
      throws IOException, ServletException {

      //Check if the user have rejected
      String error = req.getParameter("error");
      if ((null != error) && ("access_denied".equals(error.trim())) {
         HttpSession sess = req.getSession();
         sess.invalidate();
         resp.sendRedirect(req.getContextPath());
         return;
      }

      //OK the user have consented so lets find out about the user
      AsyncContext ctx = req.startAsync();
      ctx.start(new GetUserInfo(req, resp, asyncCtx));
   }
}

public class GetUserInfo implements Runnable {
   private HttpServletRequest req;
   private HttpServletResponse resp;
   private AsyncContext asyncCtx;
   public GetUserInfo(HttpServletRequest req, HttpServletResponse resp, AsyncContext asyncCtx) {
      this.req = req;
      this.resp = resp;
      this.asyncCtx = asyncCtx;
   }

   @Override
   public void run() { 
      HttpSession sess = req.getSession();
      OAuthService serivce = (OAuthService)sess.getAttribute("oauth2Service");

      //Get the all important authorization code
      String code = req.getParameter("code");
      //Construct the access token
      Token token = service.getAccessToken(null, new Verifier(code));
      //Save the token for the duration of the session
      sess.setAttribute("token", token);

      //Perform a proxy login
      try {
         req.login("fred", "fredfred");
      } catch (ServletException e) {
         //Handle error - should not happen
      }

      //Now do something with it - get the user's G+ profile
      OAuthRequest oReq = new OAuthRequest(Verb.GET,
            "https://www.googleapis.com/oauth2/v2/userinfo&quot;);

      service.signRequest(token, oReq);
      Response oResp = oReq.send();

      //Read the result
      JsonReader reader = Json.createReader(new ByteArrayInputStream(
            oResp.getBody().getBytes()));
      JsonObject profile = reader.readObject();
      //Save the user details somewhere or associate it with
      sess.setAttribute("name", profile.getString("name"));
      sess.setAttribute("email", profile.getString("email"));
         ...
      asyncCtx.complete();
   }
}

The callback is routed to this servlet; we check if the user have rejected the request. If not we proceed to get the user’s details. I’m using an async servlet here because we’ll be making request out to Google for the user’s info and we do not want to hold on to the request processing thread.

If the user have consented to the request, then get the code from the query string. This is the most important parameter. Using the code we construct the access token. For every request to Google, we will need the access token to use the token to sign it. Constructing a new token is quite straight forward. You can also refresh an old token by passing in the token as the first parameter in getAccessToken(). Once you have gotten your token, save it in the session.

We are now ready to get the user’s profile. For your experimentations in the playground (step3), you now know which URL to use and what HTTP method to use. Construct that using OAuthRequest class. Sign it with the token, before making the call.

When the response, returns parse it using a Json parser. Since I’m using EE7, I’ll be using the Json API to perform this. Again, from playground, we know the structure of the Json response from Google. You can now save all the relevant information.

One last thing before we end. So we have successfully authenticated with Google using OAuth. But we have not login to the application. To do that, I’ve decided to create a proxy user in the authentication realm of the application server. After you have authenticated with Google, login to this proxy user so that the application server will honour all the security declarations. Just be aware that you cannot use getRemoteUser() or use getPrincipal() to get a user’s detail. A more tightly integrated approach would be to develop a custom realm (Glassfish in this example). However custom realms may not be portable.

One More Time…

There are may details and configurations so before I end lets go through the steps again

  1. Setup Project
    1. Create a project in Google (from Developer Console)
    2. From the project, create a new client id (note the client id, client secret and redirect url
    3. Enable the API that the project is going to access
  2. Find out abut the API 
    1. Go to playground
    2. Select the same API that you have enabled
    3. Note their scope, http method, URL and the response
  3. Integrate with WebApp
    1. Configure for based login
    2. Write a servlet to construct an OAuth request.
    3. Write a servlet to handle to callback
  4. Till next time…

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: