Photostream App – Part 2

In the the second part of the “Photostream” trilogy, we will look at how the server notifies all the clients who are observing its stream. There are 2 ways we can do this; either by using server sent events or with websocket.

Since JavaEE 7 supports websocket I’ll be using websocket. Websocket is a 2 way communication channel. In photostream app, the notification/data only flows on way viz. from the server to the client (those observing our photostream) so server sent event (SSE) is actually more appropriate. But to use SSE in JavaEE (in Glassfish/Payara in particular), you have to use add additional libraries.

In you’re using Glassfish/Payara and you would like to try SSE, see this document.

The source code for part 2 is available here.

Till next time.

Advertisements

Photostream App Trilogy

I’ve started a new screencast. In the screencast, I’ll show you how to develop a photostream application. The photostream application has 2 parts

1. Allow users to upload images

2. Push the newly uploaded images (a photostream) to connected clients.

The following is a list of open source projects and technologies that I’m using to write this application

    Rather than creating one long screencast, I’ve split it into 3 parts.

The first part – upload service and and Angular client.

The second part – server notification using websocket

The third part – hybrid mobile app to take pictures and uploading them.

Here is the first part

 

Some points to note about

  • I’m using asynchronous Servlet to handle the file upload. This is to improve performance and to better utilize server resources by releasing the request thread when the image file is being persisted. We can resume the request once the file have been saved
  • Since this is a simple application, I’ve saved the images directly in the document root. You should use a CMS or something like a GridFS to save your images
    Till next time.

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.

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…

Integrating TOTP with Java EE’s Container Managed Security

clip_image002Edited on Monday Febuary 1 2014

After reading the following blog on time-based one time password (TOTP), I wanted to see if I could add an additional layer of security into Java EE’s  security. I installed Google Authenticator on my phone and started experimenting it with Java EE security.

I’ll describe what I did and some of the issues I found. You can get a copy of the source when you reach the end of the blog. Hopefully the journey is as pleasant as the destination 😉

The blog is broken into the following sections

  1. In the first part, I’ll give a brief intro to Google Authenticator/time based onetime password and how it works
  2. Setup JDBC realm for Glassfish application server in preparation for using it in our form based authentication
  3. Create the login and user registration with JSF Faces Flow
  4. Configure container managed security to use TOTP for login

Time-base One Time Password

So lets start with TOTP. We are all familiar with the concept of password. Password are typically static; they do not change over time; so if someone knows your password then your account is compromised.

In most operating system you can configured a password expiry policy where users are forced to change their password at regular intervals eg. 6 months. This password expiry policy gets around the above mention problem every 6 months. But the risk still exist.

TOPT takes the password expiry policy to the extreme by expiring your password at an even faster rate like say every 30 seconds! The problem here is that you cannot change your password every 30 seconds; so to make this work, TOTP uses an algorithm to change the password for us.

Very briefly this is how the TOTP works: you pass to the TOTP password generator algorithm a secret key and the current time; out pops your password; So if you call the TOTP password generator now and then again 30 seconds later (assuming that your window is 30 seconds) using the same secret key, you will get 2 completely different passwords.

To verify a password generated by TOTP algorithm, the TOTP password verification must know your secret key and the time that the TOTP password is generated. Since its a 30 second expiry period in our example, the password verifier will be able to validate the password as long as it is run inside the same 30 second window when the password is generated. All the wonderful math can be found here. TOTP is an IETF standard RFC6238.

Examples of TOTP can be found in online banking like DBS’s OTP where the account holders are issued dongles that implement the TOTP algorithm along with their unique secret keys embedded in the dongles. 

Another way of using TOTP is to augment it with your regular password as in Google’s 2-Step Verification (the focus of this blog). Google’s 2-Step Verification (G2SV) relies Google Authenticator which replaces the dongle in the above example. You have to first create an account. The Authenticator captures your TOTP details of this account by scanning a QR code. The QR code is created from the following 3 pieces of information

  1. A base 32 encoding of a 10 digit hexadecimal number. Eg the bytes from the string 8-polytope (“8-polytope”.getBytes()) will produce the following base 13 encoding: HAWXA33MPF2G64DF. This is the secret key and is unique to each user
  2. An issuer, typically the name of a company or the issuing authority eg. Yoyodyne Propulsion Systems
  3. A label, which I like to call the subject, is the user’s name or some identifier eg. johnwhorfin

All the information have to be encoded in the otpauth format. If we were to encode the values from above, we will get the following

otpauth://totp/Yoyodyne+Propulsion+Systems%3Ajohnwhorfin%3Fsecret%3DHAWXA33MPF2G64DF%26issuer%3DYoyodyne+Propulsion+Systems

Note that the otpauth string have to be URL safe. We can how use this otpauth to generate a QR using Google’s QR generator. You can find the query string parameters here. So to get the QR code of 350×350 pixel in size, enter the following

https://www.google.com/chart?chs=350x350&cht=qr&chl=otpauth://totp/Yoyodyne+Propulsion+Systems%3Ajohnwhorfin%3Fsecret%3DHAWXA33MPF2G64DF%26issuer%3DYoyodyne+Propulsion+Systems

See the QR in its full glory here.  Of course the entire process of generating the OTP can be automated.

Clearly the secret key in which the entire TOTP scheme hinges is the weakest link. If we minimize the exposure of the secret key (like keeping it from the user, using HTTPS to generate the QR) then we can potentially make using TOPT reasonably secure. Well get to that a little later.

 

Glassfish JDBC Realm

Java EE security realms is a place where username, password and groups are stored. When you configure security for your application you need to specify which security realm you application will be associated with. When a user login to your application, it is from this realm that the application will get the user’s credentials, password and group id. See here for more details.

A JDBC realm is a realm where usernames, passwords, etc are stored in a RDBMS. You first create the required tables in a RDBMS; next you create a connection pool on top of it followed by a JDBC resource.

Since I’m using Glassfish and Java DB/Apache Derby, I’ll be creating and configuring JDBC realm based on these. There are lots of blogs and tutorial on creating JDBC realm for Glassfish so I won’t go into it in great detail. I’ll just list out my configuration.

The following are the table schemas, based on Apache Derby, which I’ve copied from this blog. Adapt it to whatever database you’re using.

create table logintable (
   username varchar(128) NOT NULL CONSTRAINT usernamePK primary key,
   password varchar(128) NOT NULL,
   otp_secret varchar(128) NOT NULL
);

create table grouptable (
   username varchar(128) NOT NULL,
   groupid varchar(128) NOT NULL,
   CONSTRAINT GROUP_PK PRIMARY KEY(username, groupid),
   CONSTRAINT USER_FK FOREIGN KEY(username) REFERENCES logintable(username)
);

I’ve added an extra column in logintable called otp_secret. This column will be used to store our OTP secret key.

Create a JDBC resource to the database that has the above 2 tables; see here if you do not know how. Assume that the JDBC resource name is jdbc/security. Next define a JDBC realm for Glassfish with the following configuration according to the table schemas

Property Name Property Value
JAAS Context jdbc-realm (note: this is the realm’s name)
JNDI jdbc/security
User Table logintable
User Name Column username
Password Column password
Group Table grouptable
Group Table User Name Column username (note: this is the username column in grouptable)
Group Name Column groupid
Password Encryption Algorithm none (note: enter this value)
Digest Algorithm SHA-256 (note: this is important as you’ll need to know what message digest to use)

Login Flow for TOTP

The next thing that we’re going to do is to define a flow for a user to login or to register themselves. Registration is important here because this is where we generate the TOTP secret key. The following diagram shows the authentication and registration process

totp_flow

  • totp-login – this is the login page and the main entry point into this flow. The page need to have the same name as the flow name to indicate that this is the starting page
  • register – if we are a new user, then we click on a button on totp-login to get us here
  • qrcode – after we have successfully registered, the qrcode page will display the QR code for our TOTP which we have to use Google Authenticator to scan. After scanning, we return to totp-login to login
  • error – the error page

totp_flowI’ll be implementing the process using JSF using the new Faces Flows; so the files are created in a directory called totp-login; this incidentally will also be the name of the flow. 

Let start with the registration (register.xhtm) page. Note all JSF pages are at its bare minimum.

<h:form id="form">
   <h:inputText id="username" value="#{newUser.username}"/>
   <h:inputSecret id="password0" value="#{newUser.password}"/>
   <h:inputSecret id="password1" value="#{newUser.passwordAgain}"/>
   <h:commandButton value="Register Me" action="#{newUser.register()}"/>
</h:form>

And this is the backing bean for register.xhtml

@FlowScoped("totp-login")
@Named
public class NewUser {
   @EJB private UserManager mgr; 
   //JavaBean properties - not shown
   ...
   public String register() {
      //Checks
      ...
      Map<String, String> result = OneTimePassword.generateQR(username, Authentication.ISSUER);
      mgr.register(username, password, result.get(OneTimePassword.SECRET32));
      qrUrl = result.get(OneTimePassword.OTPAUTH);
      return ("qrcode");
   }
}

The code is quite simple. When the user clicks on Register Me button, we will call register(). After verify the fields, us use an EJB call UserManager to insert the username, password and the base32 encoded secret key into the JDBC realm. This corresponds to logintable above. It also assigns the user to a group called registered.

Recall that in our JDBC realm configuration, we say that we are using SHA-256 for the password digest; so in effect we don’t save the password but its digest. This hashing operation is performed by the register() method.

Before we register the new user into our database, we have to generate a secret key for it. We use generateQR(); generateQR() takes in 2 parameters, the subject and the issuer. In the example above, for the subject we will be using the user’s login name and the issuer is hardcoded to “Yoyodyne Propulsion Systems”. generateQR() returns a Map which hold a few entries. The name of the keys holds the following values

Key Name Value Description
secret32 Base32 encoded String of a randomly generated 10 byte secret
otpauth otpauth URI
url Full URL, with the otpauth, to the Google site that generates the QR code
secret Stringify 10 byte secret. Note in the demo, we only use the first 2 keys viz. secret32 and otpauth

We assign the otpauth URI to a property and move to the qrcode.xhtml page to display the QR code shown below

<h:outputText value="
   Please scan the QR code on the right using 
   your Google Authenticator App. After that you can 
   proceed to login."/>           
<h:commandButton value="Login" action="totp-login"/>
<h:graphicImage url="#{newUser.qrUrl}"/>     

A digression: I found that graphicImage cannot load images from an external source viz. if I pass it http://www.google.com/chart?… I’ll get a broken image. Not sure if this is a bug with JSF (Majorra) or its part of the specs. Anyways, this blog pointed out a possible workaround by proxying the image via a Servlet. The otpauth is appended to /qrcode. So the url attribute in graphicImage references /qrcode/the_otpauth instead of http://www.google.com/chart?… A Servlet is mapped to /qrcode/* to handle the image loading. See QRCodeServlet for more details.

All that remains now is the login page which is shown below

<h:form>
   <h:inputText id="username" value="#{authentication.username}"/>
   <h:inputSecret id="password" value="#{authentication.password}"/>
    <h:inputText id="otp" value="#{authentication.otpCode}"/>
   <h:commandButton value="New User" action="register"/>
   <h:commandButton value="Login" action="#{authentication.login()}"/>
</h:form>

and its corresponding backing bean

@FlowScoped("totp-login")
@Named
public class Authentication implements Serializable {
   //Getters and Setters not shown
   ...
   @EJB private UserManager mgr;
   public String login() {
      FacesContext ctx = FacesContext.getCurrentInstance();
      HttpServletRequest req = (HttpServletRequest)ctx.getExternalContext().getRequest();
      if (null != req.getRemoteUser())
         return ("protected/menu");
      if (null == req.getAuthType()) {
         ctx.addMessage(null, new FacesMessage("Not configured for container managed login"));
         return ("error");
      }
      try {
         req.login(username, password);
      } catch (ServletException ex) {
         ctx.addMessage(null, new FacesMessage("Incorrect login"));
         return ("error");
      }
      User user = mgr.getUser(username);
      if (null == user) {
         ctx.addMessage(null, new FacesMessage("Cannot find user."));
         return ("error");
      }
      try {
         if (!OneTimePassword.checkCode(user.getOtpSecret(), otpCode, System.currentTimeMillis())) {
            req.logout();
            ctx.addMessage(null, new FacesMessage("Incorrect login"));
            return ("error");
         }
      } catch (InvalidKeyException | NoSuchAlgorithmException | NumberFormatException ex) {
         ctx.addMessage(null, new FacesMessage("Exception: " + ex.getMessage()));
         return ("error");
      }
      return ("success");
   }
}

The login() method takes a user name and password and will throw a ServletException if the that combination is incorrect. It will also throw ServletException under 2 other circumstances

  • If the application have not been configured for security. We check that using getAuth() method or
  • If we attempt to login a use that have been authenticated. So we check if we have the user name by calling getRemoteUser(). If this is not null, meaning that this request has been authenticated, then we redirect the request into the secure area. More on secure area later.

After successfully login, we perform the 2nd validation by checking the OTP. We pass in the secret key, which is returned when we get the User from getUser(), the OTP password that the user entered and the current time to OneTimePassword.checkCode(). checkCode() method is  this algorithm that I found here. checkCode() verifies the password using a 120 second window viz. if you give it the current time, it’ll take the current, past and future 30 second slot. If we don’t do that then the time on the OTP generator (the mobile phone that runs Google Authenticator) and the time on the server that host the web application cannot be more than 30 seconds apart.

Note that if the TOTP password is incorrect we perform a logout (logout()) before returning; the other method that you can use is HttpSession.invalidate() which performs a logout as well. The difference is that logout() will not destroy the HttpSession. One reason you might not want to invalidate the session is to keep a count of failed attempts and disable the username for 5 minutes for example.

If the OTP is correct, we exit the TOTP authentication flow by returning the success token. I’m using explicit flow definition, so the definition is as follows

<flow-definition id="totp-login">
    <flow-return id="success">
        <from-outcome>/protected/menu</from-outcome>           
    </flow-return>
</flow-definition>

where everything under the /protected  directory requires authentication and authorization before access.

 

Form Based Authentication with TOTP

We’ll not turn our attention to configuring the web application with the totp-login flow described above using the JDBC realm that we have created. So if you want to secure an application in Java EE, you have to specify 3 things

  1. Authentication scheme – how are we going to collect username and password and to perform the authenticatoin
  2. Authorized role(s) – what are the application defined security roles
  3. Security constraint – what are the resources that needs to be authenticated and who is authorized to access it. The constraint ties authentication and authorization into a neat little package

Authentication Scheme

Let start the discussion by looking at authentication scheme. Java EE supports container managed security. If we’re dealing with securing web application, then common ways to authenticate a user are either basic or form-based (see here for other ways).

When you use basic authentication, you get a dialog box to request for your user name and password. If a correct combination of username and password is presented, then you will be redirected to the protected resource. Basic authentication does not give you control over the login page and the authentication process. Say you want to enter a third field, eg our TOTP field, as part of the the login, there is just no way of doing this.

Enter form based authentication. With form based authentication, you create a login and an error page in the web.xml file. The login page needs to contain j_username and j_password field; these values are POSTed to j_security_check. Form based authentication gives you control over the L&F of your login page but you’re still out of  the loop when it comes to the authentication process. Again it does not allow us to arbitrarily include any additional data into the authentication process. You can do it after you’ve passed security check but not during. Another common gripe with form based authentication is that its not very JSF friendly; you have to fallback to <form> and <input>.

So in Java EE 6, the Servlet API introduced programmatic security. At its heart, it is still form based authentication. However instead of relying of j_security_check to collect username and password, your application is now be responsible for collecting these information and performing the authentication. This opens up a lot of possibilities; you are no longer restricted to just username and password. You can include additional fields; see Authentication.login() and totp-login page above.

The following XML fragment shows form based authentication for our TOTP authentication

<login-config>
   <auth-method>FORM</auth-method> 
   <realm-name>jdbc-realm</realm-name> 
   <form-login-config>
      <form-login-page>/faces/index.xhtml</form-login-page> 
      <form-error-page>/faces/index.xhtml</form-error-page> 
   </form-login-config>
</login-config>

Note that in a typical form based login, you have 2 different views for login and for error. The container will redirect the request to the error page if you’ve login incorrectly. In our “semi” container managed security, our application controls this (see the flow above). So you don’t actually need an error page; I therefore set it to index.xhtml.

Another issue is cannot enter a JSF flow with a HTTP GET. In a typical form based login configuration, you provide the actual login page. In this scenario, we cannot have /faces/totp-login; this will not start the flow. What you need to do here is provide a view which have a POST back to start the totp-login flow; in this case index.xhtml looks like this

<h:form> 
   <h:commandLink action="totp-login" value="Login"/>
</h:form>

Authorized Roles

Once you’ve setup the authentication mechanism, you now need to define a security role. Our demo application have a single role which is authenticated.

<security-role>
    <description/>
    <role-name>authenticated</role-name>
</security-role>

The authenticated role needs to be mapped to users and groups from the jdbc-realm. This mapping is application server specific. Glassfish uses a file called glassfish-web.xml to perform this mapping. The following XML fragment shows how we map authenticated to registered group.

<security-role-mapping>
  <role-name>authenticated</role-name>
  <group-name>registered</group-name>
</security-role-mapping>

Security Constraints

A security constraint defines what resources are to be protected and what roles are allowed to authorized to access it. Lets say we wish to secure everything under the /protected path. So when we try to access /faces/protected/menu, the application server will require you to be authenticated first; then check if you are authorized with the role to access that resource. In our case our security constraints looks like this

<security-constraint>
    <display-name>Constraint1</display-name>
    <web-resource-collection>
        <web-resource-name>protected</web-resource-name>
        <description/>
        <url-pattern>/faces/protected/*</url-pattern>
    </web-resource-collection>
    <auth-constraint>
        <description/>
        <role-name>authenticated</role-name>
    </auth-constraint>
</security-constraint>

The above constraint says that what we are protecting is everything under the /faces/protected path; only those uses who are authenticated to the authenticated role will be authorized to access it.

 

Screenshots

The following are some screenshots with a running commentary of what’s happening

totp0

This is the login page. Assume that we are a new user, so we click on New User button. This brings us to the following screen

totp1

We enter the new user details. Then click on Register Me button. This will call NewUser.register(). A secret key will be generated and the appropriate QR code link is created based on the username, issuer and the secret key. The following page is displaying asking the user johnbigboote to scan that into his Google Authenticator.

totp2

After scanning in you should see the following in the Google Authenticator

jb

The number 732803 is the OTP and the ‘pie chart’ to the right is the 30 seconds count down timer. After login you’ll be redirected to the secure area.

totp3

You can use this approach to integrate other authentication mechanism like adding CAPTCHA.

I’ve listed a few caveats in the blog. They are mostly related to JSF and not security. So let me just state one here. One of the big advantage of container managed security is that if you are going to access /faces/protected/menu resource and your are not authentication, the application server will redirect you to the login page (if we’re using form based authentication). After you have authenticated and you’re authorized to access that resource, the container will now redirect you to that resources which is /faces/protected/menu in our case.

But using programmatic authentication, you lose this ability. I have to go to a specific view after a successful login. I cannot find a way of redirecting the request back to the original resource. Let me know if you have a standard and portable way of doing this.

The source code can be found here. It’s been an extremely long blog. Didn’t start off that way. Thanks for reading.

Till next time.

Using Server Sent Events with Vorpal

bridge

I came across the following 2 blogs (here and here) on a CDI framework for server sent event (SSE) several months ago. I downloaded the source then tried it with Vorpal running on Glassfish 3.1.x. The result was a really long exception stack.

4 months later.

After publishing part 4 of on conversations, I decided to see if I have any luck with the SSE framework. I wasn’t really expecting it to work. Well it did. What is even more surprising is that it worked with Vorpal. 

What I’m going to do in this blog is explain how the SSE framework works and more importantly how you can use it with Vorpal. Its really easy.

Setup the push event stream

Firstly create a notification handler. The notification handler will maintain the connection between the browser and the web application. The following is a simple notification handler

@ServerSentEvents(“/notifications”)

public class NotificationHandler extends ServerSentEventHandler {

   public void sendMessage(String msg) {

      try {

         connection.sendMessage(msg);

      } catch (IOException ex) {

      }

   }

A few points to note: the notification handler must extend ServerSentEventHandler; this class is from the framework. You also have to annotate the class with @ServerSentEvents and specify the URL of the event stream. In this case it is notifications. More on this later.

Now you need to write a HTML/JSP/JSF/whatever page to invoke this event stream. Here is a snippet of the HTML page along with a snippet of Javascript that loads loads the event stream

<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html">
    <h:head>
        <title>XMPP with SSE</title>
        <script src="resources/app.js"></script>
    </h:head>
    <h:body>
        <h1>Using Vorpal with SSE</h1>       
    </h:body>
</html>

The Javascript that creates the event stream is in app.js. Here is the code

var url = ‘http://’ + document.location.host

      + “/xmppsse/notifications”;

eventSource = new EventSource(url);

eventSource.onmessage = {

   document.body.innerHTML += msg + ’<br>’;

};

The important thing here is to get the event stream URL right. If our example, this is made up of the application context of our web application (in blue) and the value that you’ve specified in @ServerSentEvent annotation (in green).

 

Pushing data to the browser

We now hook the event handler to a Vorpal application. I did a screencast on developing a customer query service which allows you to use a Jabber client to query a database, which you can find here and the source here.

Lets extend this so that whenever someone performs a query, the result is also pushed to the browser using SSE.

@Message

public class MessageHandler {

   @EJB CustomerManager mgr;

   @Inject @ServerSentEventContext(“/notifications”)

        ServerSentEventHandlerContext<NotificationHandler> ctx;

   @Body(“{id}”)

   private String handle(@Named(“id”) int id) {

      //Assume we find every record and no NPE

      String record = mgr.find(id).toString();

      //Loop through all handlers

      for (NotificationHandler nh: ctx.getHandlers())

         try {

            nh.sendMessage(record);

         } catch (Exception ex) {

            nh.close();

         }

      return (record);

   }

After we got the record from CustomerManager, which uses JPA, we loop through all the registered handlers for an event stream channel and pushes the record to them. You have to get the correct handler to push to.

In our example, we are pushing to all browser registered on notifications. So we inject an instance of ServerSentEventHandlerContext with qualifying it with @ServerSentEventContext(“notifications”).

Example code

You can download the example source from here. I’ve bundled the SSE library into the download which is a NetBeans project.

Use the following steps to setup, deploy and run the example

  1. Configure an external component on your Jabber server. The example uses customer for subdomain and AlwaysRight for shared secret (Caps!). You can always change these settings. I use Openfire for the Jabber server
  2. Make sure that you’ve installed your Glassfish with Jabberwocky container.
  3. Deploy the project to Glassfish either from NetBeans or using asadmin command. It’s probably easier if you deploy if from NetBeans
  4. Open your browser and point to http://yourserver:port/xmppsse. I’ve tested with Firefox and Chrome, latest versions.
  5. Open your Jabber client, open a chat with query@customer.your_jabber_server. Send 1
  6. You should now see your reply display in your Jabber client and in your browser.

The source code for the SSE can be found here if you wish to look at it.

Part of the code (the app.js) is taken from Bhakti Mehta’s blog. Big thanks.

Till next time.

Screencast: Are you there?

In this screencast we will show how to use @Presence to allow a XMPP external component to respond to subscription and probe messages. This is a continuation of our series of tutorial on developing CustomerQuery component with Vorpal framework.

The source thaw was developed in the screencast is availble here.

Till next time

%d bloggers like this: