Google ClientLogin Utility in Java
It is worth to mention that ClientLogin is for use when there is a high level of trust between the application and the owner of the protected data. It is mostly commonly recommend for cases where the application owns the protected data.
The ClientLogin method works mainly by sending HTTP Post requests to Google service using specific parameters as described in Google documentation. In this article we will use a different approach to implement ClientLogin authorization process. We will use Google APIs Client Library for Java, which is a powerful java library for accessing Google’s HTTP-based API’s on the web. The most important class in this library is, obviously, the ClientLogin class.
1-Anatomy of the ClientLogin class:
ClientLogin class provides a single method authenticate() which handles the details of authentication process. it also provides an important internal class ErrorInfo which could be used to handle authentication errors and captcha challenge logic.
In this post we present a clean wrapper class for ClientLogin which handles the complete ClientLogin authorization process including authentication errors parsing and captcha challenge handling.
2-google-api-java-client Maven Dependencies:
We chose to use maven for building our project example. Maven provides dependencies for the Google APIs Client Library for Java. just add the following maven dependencies to your pom.xml file:
<dependency> <groupId>com.google.api.client</groupId> <artifactId>google-api-client-googleapis-auth-clientlogin</artifactId> <version>1.2.3-alpha</version> </dependency> <dependency> <groupId>com.google.api.client</groupId> <artifactId>google-api-client-javanet</artifactId> <version>1.2.3-alpha</version> </dependency>
After that use maven:install to install the required jars to be included in our project classpath.
3-GoogleClientLogin wrapper class:
Our wrapper class obviously contains a reference to ClientLogin . It provides public methods implementing the important functions of the authentication process.
GoogleClientLogin has a constructor that takes a String representing the Google service you’re requesting authorization for (for example “cl” for Google Calendar). The constructor looks like this:
/** * @param service */ public GoogleClientLogin(String service) { super(); this.service = service; authenticator = new ClientLogin(); transport = GoogleTransport.create(); authenticator.authTokenType = service; }
The main method is authenticate(username,password) that takes two arguments representing the username and password input by user:
/** * @param username * @param password * @throws ClientLoginException */ public void authenticate(String username, String password) throws ClientLoginException { try { // authenticate with ClientLogin authenticator.username = username; authenticator.password = password; Response response = authenticator.authenticate(); this.authToken = response.auth; } catch (HttpResponseException e) { parseError(e); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } }
This method sets ClientLogin variables (username and password) then calls ClientLogin.authenticate() which returns a Response instance. if the ClientLogin.authenticate() call is successful we store the Authentication token ‘Response.auth’. The advantage of the authenticate(username,password) wrapper method is its intelligent handling of authentication errors.
Parsing Authentication errors:
We distinguish two Error categories that could be thrown during the call to Clientlogin.authenticate():
a-unrecoverable Errors for which we use a ClientLoginException class
b-a recoverable error thrown when Google service requires a captcha challenge.
For this later we use a separate Exception class CaptchaRequiredException which extends the first ClientLoginException class.
Clientlogin.authenticate() throws a HttpResponseException if the authentication response has an error code. we provide a helper method for parsing this exception class as follows:
/** * @param e * @throws ClientLoginException */ private void parseError(HttpResponseException e) throws ClientLoginException { try { ClientLogin.ErrorInfo errorInfo = e.response.parseAs(ClientLogin.ErrorInfo.class); errorMessage = errorMsg.get(errorInfo.error); if (errorInfo.error.equals(CaptchaRequired)) { captchaToken = errorInfo.captchaToken; captchaUrl = errorInfo.captchaUrl; throw new CaptchaRequiredException(errorMessage, e); } else throw new ClientLoginException(errorMessage, e); } catch (IOException e1) { throw new ClientLoginException(e1); } }
We Call HttpResponseException.response.parseAs(ClientLogin.ErrorInfo.class) to parse the response. If the error code is “CaptchaRequired”, we store errorInfo.captchaToken and errorInfo.captchaUrl then throw CaptchaRequiredException. For the rest of Error codes we just throw ClientLoginException.
Authentication with CAPTCHA Challenge
In the case of a CAPTCHA challenge we provide a second authenticate() method which provides an extra argument ‘captchaAnswer’ representing the captcha key entered by user during a CAPTCHA challenge:
/** * @param username * @param password * @param captchaAnswer * @throws ClientLoginException */ public void authenticate(String username, String password, String captchaAnswer) throws ClientLoginException { authenticator.username = username; authenticator.password = password; authenticator.captchaToken = this.captchaToken; authenticator.captchaAnswer = captchaAnswer; try { Response response = authenticator.authenticate(); this.authToken = response.auth; } catch (HttpResponseException e) { parseError(e); } catch (IOException e) { throw new ClientLoginException(e); } }
Before calling authenticator.authenticate() this method sets two extra fields authenticator.captchaToken and authenticator.captchaAnswer. Error handling for this method is the same as the main authenticate(username,password) method.
Finally we provide a method to retrieve the CAPTCHA image that will be displayed to user:
/** * @return the captchaImage */ public BufferedImage getCaptchaImage() { BufferedImage image = null; try { URL url = new URL("https://www.google.com/accounts/"+ getCaptchaUrl()); image = ImageIO.read(url); } catch (MalformedURLException e) { // TODO Auto-generated catch block e.printStackTrace(); return null; } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); return null; } return image; }
You can view the complete GoogleClientLogin class source file here.
4-Testing GoogleClient wrapper class
GoogleClientLoginDialog is a swing Dialog which presents an example of how to use GoogleClientLogin wrapper class. It provides a feature to force Google service to send a CAPTCHA challenge. we implement this test using a thread that keeps sending random passwords until Google responds with a CAPTCHA challenge:
private class ForceCaptchaRunnable implements Runnable{ public void run() { Random r = new Random(); boolean isCaptcha = false; while (!isCaptcha) { try { client.authenticate(textField.getText().trim(), passwordField.getText().trim()+ r.nextInt(100)); showMessage("Auth Token: "+client.getAuthToken()); } catch (CaptchaRequiredException e1) { isCaptcha = true; showCaptcha(true); } catch (ClientLoginException e1) { } } } }
You can view and download the complete source code of this sample project Google code project: google-apis-utils.
Reference: Google ClientLogin Utility in Java from our JCG partner Othman El Moulat at the Othman’s blog.
Related Articles :