Click here to Skip to main content
15,884,237 members
Articles / Product Showcase
Article

Google Cloud Platform: User Management

10 Dec 2013CPOL10 min read 18.4K   4  
Google Cloud Platform - Part 3: Management

This article is in the Product Showcase section for our sponsors at CodeProject. These articles are intended to provide you with information on products and services that we consider useful and of value to developers.

Part 3: User Management

When we last left our hero… uh, I mean, heroic application, it was happily running in the cloud, greeting anyone and everyone that happens to wander by, possibly even by name, if they happen to provide it.

Which brings up an interesting problem: user identity. Many, if not most, applications running on the Internet want or need to be able to identify the user behind the browser in some unique fashion, for a variety of reasons. Sometimes the application needs to display personal user information and shouldn’t do so to anyone other than that particular user, sometimes the application needs to verify the user’s identity before allowing them in to use any part of it, and sometimes the application just wants to provide a more personalized experience to the user. Whatever the reason, user identity management is usually somewhere near the top of the "must-have" feature list for a web app.

If you’re like a lot of developers, then, the next discussion becomes a list of features surrounding the concept: CAPTCHAs to verify human users, login screens, password strength rules, username uniqueness verification, I-forgot-my-password screens and verification, email validation, salted and encrypted passwords, and federated security systems like OAuth or OpenID (or both).

Or, you just let Google worry about it.

User Management

One of the big advantages to running on top of the Google Cloud Platform is that Google has built a metric crap-ton (that’s an actual unit of measurement, by the way) of libraries and APIs to support it, all of which can be utilized pretty easily from your Java-based applications running in the Google Cloud Platform. In this particular case, we can leverage the Google authentication and user management system (the same one that you use to get to your Gmail and, if you followed directions from the last article, to create the app’s project in the cloud in Google App Engine) to identify users. Instead of building the login screens and email verification and all that, you just import the right APIs, make the right method calls, and let Google do the heavy lifting.

Flow

There are several different ways to think about how the users will interact with the application, depending on business requirements. One approach, common in a lot of applications both internal and external, is that users cannot access any aspect of the application without a successful login—in other words, the application is entirely opaque to anyone who is not authorized to use it already. A slight variant of that approach (common with most external, consumer-facing applications) is to allow people to apply for membership into the exclusive club, but otherwise the application behaves the same: without a successful login, no aspect of the application can be accessed.

Other applications prefer less binary distinctions about authorization, and may allow certain portions of the application to be used by anyone, while reserving certain features and/or benefits to those who have a recognized set of credentials. (Most e-commerce systems usually fall into this category: browse all you want, but you only get free shipping if you’re a recognized member of our site so we can spam you and sell your email to the highest bidder.)

From a Google App Engine developer’s point of view, the distinction really isn’t important, except to know where to challenge the user for credentials and what actions to take if the user doesn’t provide acceptable ones. For example, an application that wants to follow the binary model of "all in or all out", it may choose to set up a servlet filter to check for established login credentials in the current session, and redirect the user to a page explaining why they’re being redirected when no credentials are present. My application, however, doesn’t want to be so harsh—it still wants to be warm and friendly and all that, so I’ll ask for Google credentials, but still offer up a greeting to those that aren’t Google-identifiable users. Just maybe not quite as personal.

Packages, packages

The user management API lives in the package com.google.appengine.api.users, so the first order of business is to import that into the servlet.

import com.google.appengine.api.users.*;

Then, like so many Java APIs, we need to have a reference to an object that acts as a gateway to the remainder of the API, and in the Google User Service case, that’s a UserService object, obtained via a call to the static UserServiceFactory.getUserService() method. This UserService object, along with the User object it will get for us (more on that in a minute), forms a majority of the surface area a developer uses. In fact, it’s more notable how small the API really is, compared with all the functionality that it provides.

Let’s start with the basics.

Who are you?

The UserService object’s principal method of returning an authenticated user is the getCurrentUser() method, which returns (not surprisingly) a User object containing the authenticated user’s credential information (more on that in a second), or else null, indicating that no such user has logged in. So, principally, checking to see if a user has authenticated with the web app is a single method call, checking for a null result:

public class HelloServlet extends HttpServlet
{
  public void doGet(HttpServletRequest request,
                    HttpServletResponse response)
    throws IOException, ServletException
  {
    UserService userService = UserServiceFactory.getUserService();
 
    User user = userService.getCurrentUser();
    if (user != null)
    {
      PrintWriter out = response.getWriter();
      out.println("<html>");
      out.println("<body>");
      out.println("<p>Hello, " + user.getNickname() + "</p>");
      out.println("</body>");
      out.println("</html>");
    }
    else
    {
      // . . .
    }
  }
}

The User object has a number of methods on it that describe what Google knows about this user: their email address (getEmail), their human identifier (getNickname, which may be their "handle", their email address, or something else, but usually something that they’ve chosen for themselves), their Google identifier (getUserId), and a few other tidbits that can be useful in select situations, like the domain (authentication system) used to authenticate this user (getAuthDomain) or the user’s federated identity (getFederatedIdentity), which will likely only be of use in cases where Google’s authentication is used in conjunction with systems like OAuth or OpenID.

In the case where the user isn’t someone that’s already logged in with Google, we need to create a URL to which they can be redirected, in order to capture their credentials (username and password). This is where UserService fulfills the other half of its function, by crufting up a URL with Google’s authentication system that will capture the user’s information and redirect it back to us:

else
{
  String host = request.getProtocol() + "://" +
    request.getServerName() +
    (request.getServerPort() != 80 ? request.getServerPort() : "");

  String loginUrl = userService.createLoginURL(host + "/hello");

  PrintWriter out = response.getWriter();
  out.println("<html>");
  out.println("<body>");
  out.println("<p>Please <a href='" + loginUrl + "'>log in</a> " +
    + "for a nice, friendly greeting!");
  out.println("</body>");
  out.println("</html>");
}

Notice that the createLoginUrl method takes a string parameter, which is the page to which the user should be redirected after successful authentication. In the case of this ridiculously simplified application, that’s the same page we came from, but in other applications, that would most often be the home page of the application, chock full of menu-selection goodness.

Bear in mind, if this endpoint is a JSON-delivered data-only endpoint (such as what a mobile app would be using), then the createURL method won’t be of much use; instead, the servlet would probably return a 400-class error code (probably a 401), indicating that the servlet cannot return data without authentication, and the mobile application will then have to present a native login screen to gather those credentials. More of this will come when we cover the Google mobile endpoints API, a specific set of APIs geared towards building these kinds of endpoints, in a later article.

Role-playing games

Although I personally dislike mixing user-facing and admin-facing applications into the same web application (since it heightens the possibility that an accidental information disclosure will occur), many systems want to distinguish between "normal" users and "admin" users, in order to display different links, pages, or information. The User object doesn’t support a full role-based security system, but it does allow for distinguishing between "admin" and "non-admin" users, via the isAdmin() method call on the User object. (Users who are identified as "admin" users are those who are granted that status in the application’s project page in the administrative console.)

Testing, testing, testing

It’s important to note that this application now takes a dependency on both the Google services and the Internet, because if the Google services are down, or, more likely, your connection to the Internet is severed or unstable, this application will never be able to serve authentication requests. Granted, if the Internet connection is down, you won’t be able to much of anything else, either, if it happens in Production, but during testing, lots of developers are offline, or more importantly, don’t want to have to type in username/password combinations all the time.

For this very reason, Google has defined the UserService as an interface, so that any competent dependency-injection container or API can inject a mocked UserService object that returns a known constant, to enable fully-automated testing.

But my boss doesn’t like Google…

Unfortunately, it is a fact of developer life that a lot of elegant solutions aren’t workable because the boss (or the customers, or the government, or whomever else is upstream on the "client" side of the discussion) has some kind of problem with using said elegant solution. We can moan and grumble and make comments like "idiot users" all we like, but the fact remains, they pay the bills, they get to make those decisions. (And in all honesty, the legal and liability implications of a third party holding your users authentication data is still somewhat up in the air, and for some businesses, that is too much risk to take on.)

Or, perhaps your users are currently authenticating using a different system, other than Google’s, and the thought of trying to mass-migrate them out of the current system and into Google’s is enough to make your system administrator’s head spin a few times. Or, perhaps your users aren’t actually a part of any single system at all, or are actually consumers, and you want to enable easy authentication for them using Facebook or Twitter or LinkedIn or….

Fortunately, Google has an OAuth user provider, and it works almost identically to the UserService approach we showed above. An OAuthServiceFactory uses the static getOAuthService() method to return an instance of an OAuthService object, which in turn can be used to check to see the current user’s OAuth credentials, in the form of a User object from the UserService API above. It makes for a pretty plug-and-play replacement. (Note that a developer still needs to set up a link to the OAuth provider that will do the authentication, as described by the OAuth provider’s documentation. So, for example, if the application wants to allow Facebook to do the authentication, the developer must redirect the user to the Facebook OAuth endpoint, according to Facebook’s documentation, and set up a redirect back to this application. This is all standard OAuth fare, available from any OAuth tutorial, and outside the scope of this discussion.)

It’s highly unlikely that one would use both systems for authentication, since then there would be two entirely separate "master user lists", but I’m pretty sure that as soon as I say that, somebody will have a legitimately good reason to do it, so just be careful if you do use both simultaneously.

Summary

Google Cloud Platform makes a number of APIs available that reduce the overall work that a developer has to perform to create a "ready-for-production" application. The user and OAuth services described above are just the tip of the iceberg; a complete Javadoc is available at https://developers.google.com/appengine/docs/java/javadoc/.

In the next piece, we’re going to look at the next thing that almost all applications have to do—store data—and the various mechanisms that Google Cloud Platform provides for doing so. But for now, happy coding!

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Web Developer
United States United States
Ted Neward is an independent consultant specializing in high-scale enterprise systems, working with clients ranging in size from Fortune 500 corporations to small 10-person shops. He is an authority in Java and .NET technologies, particularly in the areas of Java/.NET integration (both in-process and via integration tools like Web services), back-end enterprise software systems, and virtual machine/execution engine plumbing.

He is the author or co-author of several books, including Effective Enterprise Java, C# In a Nutshell, SSCLI Essentials, Server-Based Java Programming, and a contributor to several technology journals. Ted is also a Microsoft MVP Architect, BEA Technical Director, INETA speaker, former DevelopMentor instructor, frequent worldwide conference speaker, and a member of various Java JSRs. He lives in the Pacific Northwest with his wife, two sons, and eight PCs.

Comments and Discussions

 
-- There are no messages in this forum --