Wednesday, July 1, 2009

Spring and JCaptcha

Recently, I have made a sample application using Spring and JCaptcha, and want to share with you all.

Basically funda of Captcha is to distinguish between human or robot(basically bot written to automate to fill some forms of your website which might be used to crash your application).

In this, program will produce some image containing dictionary words or some random alphanumeric words which you have to fill up in corresponding textfield in the form.

For this I am using JCaptcha and Spring. You can get more information JCaptcha from http://forge.octo.com/jcaptcha/confluence/display/general/Home .

So let start with the integration of JCaptcha and Spring.


  • First thing is to have one conf file, mine is applicationContext.xml file which get loaded using web.xml file.
    <context-param>

    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/applicationContext.xml</param-value>
    </context-param>
  • In applicationContext.xml file,put these lines for basic configuration :


<bean class="com.octo.captcha.service.image.DefaultManageableImageCaptchaService" id="imageCaptchaService"/>

But I think nobody want the basic things with your project so you need to change this configuration to :

<bean id="captchaService"
class="com.octo.captcha.service.multitype.GenericManageableCaptchaService">
<constructor-arg index="0">
<ref bean="imageEngine" />
</constructor-arg>
<constructor-arg index="1">
<value>180</value>
</constructor-arg>
<constructor-arg index="2">
<value>180000</value>
</constructor-arg>
<constructor-arg type="int" index="3" value="75000"/>
</bean>
This is for customizing your JCaptcha look and feel and the words which going to come in image that will be get displayed in your application form.


  • Third important thing is to set up the imageEngine bean which is instance of CaptchaEngine.
There are several Engines pre-configured, but as we want to control configuration, we have to use the GenericCaptchaEngine, which is built with a list of captcha factories

<bean id="imageEngine"

class="com.octo.captcha.engine.GenericCaptchaEngine">

<constructor-arg index="0">

<list>

<ref bean="CaptchaFactory" />

</list>

</constructor-arg>

</bean>

Then, a CaptchaFactory needs:

  • A word generator, to create the text to read.
  • A wordToImage, to generate the captcha from the text.
<bean id="CaptchaFactory"

class="com.octo.captcha.image.gimpy.GimpyFactory">

<constructor-arg>

<ref bean="wordgen" />

</constructor-arg>

<constructor-arg>

<ref bean="wordtoimage" />

</constructor-arg>

</bean>

A WordGenerator creates a text to be read, it can be random, be a common implementation take words from a list, and can make composition to create a text easier to read for a human being. In the example the WordGenerator needs a Dictionnary to get real words from.
<bean id="wordgen"

class="com.octo.captcha.component.word.wordgenerator.DictionaryWordGenerator">

<constructor-arg>

<ref bean="filedict" />

</constructor-arg>

</bean>

A Dictionary provides words, this one reads words from the one provided by default, with almost 6000 english words.

<bean id="filedict"

class="com.octo.captcha.component.word.FileDictionary">

<constructor-arg index="0">

<value>toddlist</value>

</constructor-arg>

</bean>

After to other important part to create a factory, is the WordToImage component, which is mainly created with three others components:

  • A font generator
  • A background generator
  • A Text paster
This example is a bit more complex one; it takes the usual main three components, but also three deformations, to increase the power of captchas. All three are set to none, a component which creates no deformation, see below, and Examples to have more examples of deformations.

<bean id="wordtoimage"

class="com.octo.captcha.component.image.wordtoimage.ComposedWordToImage">

<constructor-arg index="0">

<ref bean="fontGenRandom" />

</constructor-arg>

<constructor-arg index="1">

<ref bean="backGenUni" />

</constructor-arg>

<constructor-arg index="2">

<ref bean="simpleWhitePaster" />

</constructor-arg>

</bean>



A FontGenerator provide Fonts to a WordToImage, differents fonts increase the difficulties for cracking software using a learning process. This one generates random fonts from a list, and the first two arguments are the minimum size and the maximum size of the font.
<bean id="fontGenRandom"

class="com.octo.captcha.component.image.fontgenerator.RandomFontGenerator">

<constructor-arg index="0">

<value>40</value>

</constructor-arg>

<constructor-arg index="1">

<value>50</value>

</constructor-arg>

<constructor-arg index="2">

<list>

<ref bean="fontArial" />

</list>

</constructor-arg>

</bean>



A font is declared like this :

<bean id="fontArial" class="java.awt.Font">

<constructor-arg index="0">

<value>Arial</value>

</constructor-arg>

<constructor-arg index="1">

<value>0</value>

</constructor-arg>

<constructor-arg index="2">

<value>10</value>

</constructor-arg>

</bean>



The BackgrountGenerator component can be very simple like in the example, single color, or more complex with real picture, or fancy computed shapes. The first two arguments are always, the size (length and height) of the resulting image.
<bean id="backGenUni"

class="com.octo.captcha.component.image.backgroundgenerator.UniColorBackgroundGenerator">

<constructor-arg index="0">

<value>300</value>

</constructor-arg>

<constructor-arg index="1">

<value>100</value>

</constructor-arg>

</bean>


The TextPaster, according to his name, pastes the text on the background. This can be done in a simple way, (see example below), or another implementation can paste each character randomly (but still readably), or can double the text to make computers more confused. TextPaster can be even decorated to put perturbations around the text, a component, TextDecorator, is designed for this purpose, see Annexes for some examples. Commons arguments for TextPaster are:
  • Minimal length of the text
  • Maximal length of the text
  • A color generator component to create the text color, see Annexes.
    <bean id="simpleWhitePaster" class="com.octo.captcha.component.image.textpaster.SimpleTextPaster">

    <constructor-arg type="java.lang.Integer" index="0">

    <value>3</value>

    </constructor-arg>

    <constructor-arg type="java.lang.Integer" index="1">

    <value>5</value>

    </constructor-arg>

    <constructor-arg type="java.awt.Color" index="2">

    <ref bean="colorGreen" />

    </constructor-arg>

    </bean>
And a color definition:

<bean id="colorGreen" class="java.awt.Color">

<constructor-arg index="0">

<value>0</value>

</constructor-arg>

<constructor-arg index="1">

<value>255</value>

</constructor-arg>

<constructor-arg index="2">

<value>0</value>

</constructor-arg>

</bean>


This is all about the how jCaptcha generates the captcha image,now time is to use this captcha service with some application.
I am going to use this in simple registration form.
You can go through code for more details.


This is screenshot form of my registration page. The "grow" image is generated by the JCaptcha Controller.
Things to do for this are :

  • In your registration form ,you should have text with name "j_captcha_response" and the second thing is to have image source which will get generated using CaptchaImageGenerator class.
<tr>

<td><label>Control text</label></td><td><input type="text" name="j_captcha_response" /></td>

</tr>

<tr>

<td colspan="2"><img src="captcha.htm" /></td>

</tr>
  • There is CaptchaImageGenerator which generate a jpeg image file for capchta image using captcha service.
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {

byte[] captchaChallengeAsJpeg = null;

ByteArrayOutputStream jpegOutputStream = new ByteArrayOutputStream();
String captchaId = request.getSession().getId();

BufferedImage challenge = captchaService.getImageChallengeForID(captchaId,request.getLocale());

JPEGImageEncoder jpegEncoder =

JPEGCodec.createJPEGEncoder(jpegOutputStream);

jpegEncoder.encode(challenge);
captchaChallengeAsJpeg = jpegOutputStream.toByteArray();
response.setHeader("Cache-Control", "no-store");
response.setHeader("Pragma", "no-cache");
response.setDateHeader("Expires", 0);
response.setContentType("image/jpeg");
ServletOutputStream responseOutputStream =
response.getOutputStream();
responseOutputStream.write(captchaChallengeAsJpeg);
responseOutputStream.flush();
responseOutputStream.close();

return
null;
}
  • There will be validator method to validate this image :
protected
void validateCaptcha(HttpServletRequest request, BindException errors){

boolean isResponseCorrect = false;
String captchaId = request.getSession().getId();
String response = request.getParameter(captchaResponseParameterName);

try {
if(response != null){
isResponseCorrect = captchaService.validateResponseForID(captchaId, response);
}
} catch (CaptchaServiceException e) {

}
if(!isResponseCorrect){
String objectName = "Captcha";
String[] codes = {"invalid"};
Object[] arguments = {};
String defaultMessage = "Invalid image test entered!";
ObjectError oe = new ObjectError(objectName, codes, arguments, defaultMessage);
errors.addError(oe);
}
}

That's it you are done with JCpatcha. You can download the code from http://www.esnips.com/doc/271c96b3-2209-4dcd-9456-2acb302d431e/JCaptchaSpring

18 comments :

Unknown said...

Thanks man, you saved 1 days work for me ;-)

Regards,

Sanjay.B From Mauritius

CJ said...

Hi
Thanks for this tutorial. But when I import your code to Eclipse with Tomcat 6 it gives these errors.

2010-02-13 15:44:56,199 ERROR org.springframework.web.context.ContextLoader - Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'captchaService' defined in ServletContext resource [/WEB-INF/applicationContext.xml]: Can't resolve reference to bean 'imageEngine' while setting property 'constructor argument with index 0'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'imageEngine' defined in ServletContext resource [/WEB-INF/applicationContext.xml]: Can't resolve reference to bean 'CaptchaFactory' while setting property 'constructor argument with index 0[0]'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'CaptchaFactory' defined in ServletContext resource [/WEB-INF/applicationContext.xml]: Can't resolve reference to bean 'wordtoimage' while setting property 'constructor argument'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'wordtoimage' defined in ServletContext resource [/WEB-INF/applicationContext.xml]: Can't resolve reference to bean 'simpleWhitePaster' while setting property 'constructor argument with index 2'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'simpleWhitePaster' defined in ServletContext resource [/WEB-INF/applicationContext.xml]: Can't resolve reference to bean 'colorGreen' while setting property 'constructor argument with index 2'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'colorGreen' defined in ServletContext resource [/WEB-INF/applicationContext.xml]: Instantiation of bean failed; nested exception is org.springframework.beans.FatalBeanException: Could not instantiate class [java.awt.Color]; constructor threw exception; nested exception is java.lang.IllegalArgumentException: Color parameter outside of expected range: Green
org.springframework.beans.FatalBeanException: Could not instantiate class [java.awt.Color]; constructor threw exception; nested exception is java.lang.IllegalArgumentException: Color parameter outside of expected range: Green
java.lang.IllegalArgumentException: Color parameter outside of expected range: Green
at java.awt.Color.testColorValueRange(Unknown Source)
at java.awt.Color.(Unknown Source)

Same errors for:
imageEngine
CaptchaFactory
wordtoimage
simpleWhitePaster
colorGreen


Any help with this is much appreciated. Thanks Conor

Conor said...

Hi -
In order to get your example code working with JDK6, I modified your application context file as follows:

I modified the colorGreen bean id as follows (showing one line and removing angle brackets which I couldn't paste into this comment):

constructor-arg index="0" type="int" value 0 value constructor-arg

I also added in id="captchaBackgroundColor" from this article which was the source of my research:

http://blog.codecentric.de/en/2009/02/jdk6-spring-20-adventure/

Hope this helps others who try to run your sample code. Thanks for posting it...

Good Luck

Conor

Anil Verma said...

Hi Conor,

I feel the problem is with your JCaptcha version,not with JDK..

Cheers,
Anil

Unknown said...

Hi,

Thanks for the tutorial, but when i run my application, i can't see the image it's like a cross mark.suggest me what was the problem ASAP

Regards,
shashikiran

Sumon Ahmed said...

This is very nice blog .It's so helpful for jcaptcha integration in spring and jsf

Anonymous said...

great job man :)

Anonymous said...

Regarding the java.awt.Color issue, setting type="int" did not suffice to solve the problem for me.
What did work was creating a class extending java.awt.Color and defining a 3-parameter constructor in it which called the super constructor.
<br>
The CaptchaColor class:

import java.awt.Color;

public class CaptchaColor extends Color {

CaptchaColor(int r, int g, int b) {
super(r,g,b);
}
}

<br>

In the applicationContext.xml file then, I used a ref to the new class.



<bean id="backGenUni" class="com.octo.captcha.component.image.backgroundgenerator.UniColorBackgroundGenerator" >
<constructor-arg index="0"><value>250</value></constructor-arg>
<constructor-arg index="1"><value>100</value></constructor-arg>
<constructor-arg type="java.awt.Color" index="2">
<ref bean="backgroundColor"/>
</constructor-arg>
</bean>

<bean id="backgroundColor" class="CaptchaColor" >
<constructor-arg index="0" type="int"><value>204</value></constructor-arg>
<constructor-arg index="1" type="int"><value>204</value></constructor-arg>
<constructor-arg index="2" type="int"><value>204</value></constructor-arg>
</bean>

Anonymous said...

Has the file been deleted from the link mentioned above for downloading the code? Any chance if someone could provide me the working link? Thanks

Unknown said...

Hi Anil,
I am unable to download the src.

Anil Verma said...

Sorry Guys for late reponse ..
download link is updated ..http://www.esnips.com/doc/271c96b3-2209-4dcd-9456-2acb302d431e/JCaptchaSpring

Anonymous said...

Hi Anil,
I am unable to download the src even from the latest link given.

Please provide if possible.

Thanks in advance.

Anonymous said...

Hi,Anil Verma
I have downloaded your tutorial of jCaptcha.I am using java 6.0.11 when I run it I get the errors in apache 6

java.lang.UnsatisfiedLinkError: C:\Program Files\Java\jre6\bin\awt.dll: The specified procedure could not be found
at java.lang.ClassLoader$NativeLibrary.load(Native Method)
at java.lang.ClassLoader.loadLibrary0(Unknown Source)
at java.lang.ClassLoader.loadLibrary(Unknown Source)
at java.lang.Runtime.loadLibrary0(Unknown Source)
at java.lang.System.loadLibrary(Unknown Source)
at sun.security.action.LoadLibraryAction.run(Unknown Source)

Please Help Me For Running THis Example

Anil Verma said...

I think you jdk is corrupted and awt.dll file is missing in the above location.Can youtry reinstalling the jdk and make sure that awt.dll file exists.

Abdeljalil said...

Hi Anil!
I am unable to download the code?

Anonymous said...

Hello !!
I can not download the src.
Can you update the src.
Thanks

Anonymous said...

I am also unable to download ur code from both of links.

Unknown said...

Hello !!
I can not download the src.
Can you update the src.