Welcome to my blog, hope you enjoy reading
RSS

Saturday 2 February 2013

Adding CAPTCHA to your GWT application


Adding CAPTCHA to your GWT application


What is CAPTCHA?
In a world full of malicious bots, what can you do to protect your precious web application? One of the basic things that you really should do is add CAPTCHA capabilities to it. If you are not familiar with the (rather bizarre sounding) term, CAPTCHA is a simplistic way to ensure that a user is actually a real person, and not a computer. This can be done by challenging the user and asking from him to provide a response to a “problem”. Because computers are unable to solve the CAPTCHA, any user entering a correct solution is presumed to be human. The most common way is to ask the user to type letters or digits from a distorted image that appears on the screen.

Add SimpleCaptcha into your application

First, let’s create our Eclipse project. Select “File ? Web Application Project” and provide the necessary information as shown in the following image. The project’s name will be “CaptchaGwt”. Make sure that support for GWT is included, but Google App Engine is not.




Next step is to download the library from SourceForge (I used the 1.1.1 version). Add the downloaded JAR file to your project’s classpath

Setting up the client side
Eclipse will automatically create the application’s skeleton, also creating some sample files. Locate the CaptchaGwt class which is the application’s entrypoint. Remove the existing contents and replace them with the following:


package com.javanotes2all.client;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyUpEvent;
import com.google.gwt.event.dom.client.KeyUpHandler;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.TextBox;

public class CaptchaGwt implements EntryPoint, ClickHandler {
private final SignupServiceAsync signupService = GWT.create(SignupService.class);
private final Button sendButton = new Button("Sign Up");
private final Button reloadButton = new Button("Reload Image");
private int counter = 1;
private Image captchaImage;
public void onModuleLoad() {
final TextBox usernameField = new TextBox();
usernameField.setText("Username here");
final TextBox passwordField = new TextBox();
passwordField.setText("Password here");

final TextBox captchaField = new TextBox();
captchaField.setText("CAPTCHA Word here");
final Label responseLabel = new Label();
captchaImage = new Image("/SimpleCaptcha.jpg?counter="+counter);

usernameField.setFocus(true);
sendButton.addStyleName("sendButton");
RootPanel.get("usernameFieldContainer").add(usernameField);
RootPanel.get("passwordFieldContainer").add(passwordField);
RootPanel.get("captchaFieldContainer").add(captchaField);
RootPanel.get("sendButtonContainer").add(sendButton);
RootPanel.get("reloadButtonContainer").add(reloadButton);
RootPanel.get("captchaImageContainer").add(captchaImage);
RootPanel.get("responseLabelContainer").add(responseLabel);
reloadButton.addClickHandler(this);

class MyHandler implements ClickHandler, KeyUpHandler {
public void onClick(ClickEvent event) {
sendDataToServer();
}
public void onKeyUp(KeyUpEvent event) {
if (event.getNativeKeyCode() == KeyCodes.KEY_ENTER) {
sendDataToServer();
}
}
private void sendDataToServer() {
String username = usernameField.getText();
String password = passwordField.getText();
String captcha = captchaField.getText();
sendButton.setEnabled(false);
signupService.performSignup(username, password, captcha, signupCallback);
}
}

MyHandler handler = new MyHandler();
sendButton.addClickHandler(handler);
usernameField.addKeyUpHandler(handler);
reloadButton.click();
}
private AsyncCallback<Boolean> signupCallback = new AsyncCallback<Boolean>() {
@Override
public void onSuccess(Boolean result) {
if (result) {
Window.alert("CAPTCHA was valid");
}
else {
Window.alert("CAPTCHA was invalid");
}
sendButton.setEnabled(true);
}
@Override
public void onFailure(Throwable caught) {
Window.alert("Error occurred while communicating with server");
sendButton.setEnabled(true);
}
};

@Override
public void onClick(ClickEvent event) {
if (event.getSource()==reloadButton) {
counter++;
RootPanel.get("captchaImageContainer").remove(captchaImage);
captchaImage = new Image("SimpleCaptcha.jpg?counter="+counter);
RootPanel.get("captchaImageContainer").add(captchaImage);
}
}
}


Next, locate the HTML file named “CaptchaGwt.html” inside the project’s “war” file. Edit the file and add some containers for our GWT objects. The code is the following:


<!doctype html>
<!-- The DOCTYPE declaration above will set the -->
<!-- browser's rendering engine into -->
<!-- "Standards Mode". Replacing this declaration -->
<!-- with a "Quirks Mode" doctype is not supported. -->

<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">

<!-- -->
<!-- Consider inlining CSS to reduce the number of requested files -->
<!-- -->
<link type="text/css" rel="stylesheet" href="CaptchaGwt.css">

<!-- -->
<!-- Any title is fine -->
<!-- -->
<title>Web Application Starter Project</title>
<!-- -->
<!-- This script loads your compiled module. -->
<!-- If you add any GWT meta tags, they must -->
<!-- be added before this line. -->
<!-- -->
<script type="text/javascript" language="javascript" src="captchagwt/captchagwt.nocache.js"></script>
</head>

<!-- -->
<!-- The body can have arbitrary html, or -->
<!-- you can leave the body empty if you want -->
<!-- to create a completely dynamic UI. -->
<!-- -->
<body>

<!-- OPTIONAL: include this if you want history support -->
<iframe src="javascript:''" id="__gwt_historyFrame" tabIndex='-1' style="position:absolute;width:0;height:0;border:0"></iframe>
<!-- RECOMMENDED if your web app will not function without JavaScript enabled -->
<noscript>
<div style="width: 22em; position: absolute; left: 50%; margin-left: -11em; color: red; border: 1px solid red; padding: 4px; font-family: sans-serif">
Your web browser must have JavaScript enabled
in order for this application to display correctly.
</div>
</noscript>

<h1>CAPTCHA Secured Web Application</h1>

<table align="center">
<tr>
<td colspan="2" style="font-weight:bold;">Please enter your username:</td>
<td id="usernameFieldContainer"></td>
</tr>
<tr>
<td colspan="2" style="font-weight:bold;">Please enter your password:</td>
<td id="passwordFieldContainer"></td>
</tr>
<tr>
<td id="captchaImageContainer"></td>
</tr>
<tr>
<td colspan="2" style="font-weight:bold;">Please enter the word:</td>
<td id="captchaFieldContainer"></td>
</tr>
<tr>
<td id="reloadButtonContainer"></td>
</tr>
<tr>
<td id="sendButtonContainer"></td>
</tr>
<tr>
<td colspan="2" style="color:red;" id="responseLabelContainer"></td>
</tr>
</table>
</body>
</html>

Note that the only changes from the auto-generated file are after the <h1> tags.
Next,Our asynchronous GWT service is going to be very simple and execute only one function. The two corresponding interfaces are shown below:
package com.javanotes2all.client;

import com.google.gwt.user.client.rpc.RemoteService;
import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;

@RemoteServiceRelativePath("../signup")
public interface SignupService extends RemoteService {
boolean performSignup(String username, String password, String userCaptcha);
}


package com.javanotes2all.client;

import com.google.gwt.user.client.rpc.AsyncCallback;

public interface SignupServiceAsync {
void performSignup(String username, String password, String userCaptcha, AsyncCallback<Boolean> callback);
}

Preparing the server side
On the server side, the main object that we use from the library is Captcha. To retrieve the Captcha’s value (and compare it to the user’s input) we have to obtain reference to the HttpSession object associated with the specific session. The HttpSession can be retrieved by the corresponding HttpServletRequest object. This is standard Java EE stuff. Do not forget that the server side GWT services inherit from the RemoteServiceServlet, which inherits from HttpServletRequest. The underlying request can be obtained by calling thegetThreadLocalRequest method. Note that, as the API mentions, this is stored thread-locally so that simultaneous invocations can have different request objects.
The server-side concrete implementation is the following:
package com.javanotes2all.server;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import nl.captcha.Captcha;

import com.google.gwt.user.server.rpc.RemoteServiceServlet;
import com.javanotes2all.client.SignupService;

@SuppressWarnings("serial")
public class SignupServiceImpl extends RemoteServiceServlet implements SignupService {

public boolean performSignup(String username, String password, String userCaptcha) {
HttpServletRequest request = getThreadLocalRequest();
HttpSession session = request.getSession();

Captcha captcha = (Captcha) session.getAttribute(Captcha.NAME);
return captcha.isCorrect(userCaptcha);
}
}


Extending SimpleCaptcha
The final step is to setup the Servlet that will generate the image shown to the user. SimpleCaptcha can be easily extended by creating a class that inherits from the provided SimpeCaptchaServlet class. The relevant code is the following:

package com.javanotes2all.server.servlet;

import static nl.captcha.Captcha.NAME;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import nl.captcha.Captcha;
import nl.captcha.backgrounds.GradiatedBackgroundProducer;
import nl.captcha.servlet.CaptchaServletUtil;
import nl.captcha.servlet.SimpleCaptchaServlet;

public class ExtendedCaptchaServlet extends SimpleCaptchaServlet {
private static final long serialVersionUID = 6560171562324177699L;
@Override
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
HttpSession session = req.getSession();
Captcha captcha = new Captcha.Builder(_width, _height)
.addText()
.addBackground(new GradiatedBackgroundProducer())
.gimp()
.addNoise()
.addBorder()
.build();

session.setAttribute(NAME, captcha);
CaptchaServletUtil.writeImage(resp, captcha.getImage());
}
}


The “_width” and “_height” variables as passed as initialization parameters and read from the parent class. To create a new Captchaobject we use the Captcha.Builder class (which relies on the builder pattern). We then pass the object to the specific session and stream the associate BufferedImage to the servlet response.
Note that our implementation generates a new image each time the user performs a page request. This is different from the default SimpleCaptcha implementation that uses the same image for a given session.
Configuring the web application
All the components are tied up via the web application’s “web.xml” descriptor, which in our case is the following:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee">

<!-- Servlets -->
<servlet>
<servlet-name>signupServlet</servlet-name>
<servlet-class>com.javanotes2all.server.SignupServiceImpl</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>signupServlet</servlet-name>
<url-pattern>/signup</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>SimpleCaptcha</servlet-name>
<servlet-class>com.javanotes2all.server.servlet.ExtendedCaptchaServlet</servlet-class>
<init-param>
<param-name>width</param-name>
<param-value>200</param-value>
</init-param><init-param>
<param-name>height</param-name>
<param-value>50</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>SimpleCaptcha</servlet-name>
<url-pattern>/SimpleCaptcha.jpg</url-pattern>
</servlet-mapping>
<!-- Default page to serve -->
<welcome-file-list>
<welcome-file>CaptchaGwt.html</welcome-file>
</welcome-file-list>
</web-app>

We declare the GWT service (class “SignupServiceImpl”) and the welcome file. Nothing special here. Finally we declare the servlet that will take care of the image generation and handles the request under the “’/SimpleCaptcha.jpg” URL (remember this is used in the GWT entrypoint). We also provide the initialization parameters for our servlet (width and height).
That’s it! Run the project and you should see something like the following:










0 comments: