Dear Wiki user, You have subscribed to a wiki page or wiki category on "Jakarta-turbine Wiki" for change notification.
The following page has been changed by ZoltanZidarics: http://wiki.apache.org/jakarta-turbine/Turbine2/Tutorial/CaptchaService New page: = Integrating Captcha Service into Turbine = If you want to enable anonymous data input in your Turbine application like user registration and etc. you need to protect yourself from spammer robots. There are a lot of captcha (Completely Automated Public Test to tell Computers and Humans Apart) modul, I prefer JCaptcha from http://jcaptcha.sourceforge.net/. It has a lot of parameters like: * character set for generation * min and max length of text * image width and height in pixels * font min and max size * font color All of these parameters can be setting in TR.properties: {{{ services.CaptchaService.classname=com.zamek.portal_zamek.services.captcha.TurbineCaptchaService services.CaptchaService.earlyInit=true services.CaptchaService.chars=ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789 #character set services.CaptchaService.parser.min=5 #minimum length of captcha text services.CaptchaService.parser.max=6 #maximun length of captcha text services.CaptchaService.size.width=200 #width of captcha image (px) services.CaptchaService.size.height=100 #height of captcha image (px) services.CaptchaService.font.min=25 #minimum size of captcha text font (px) services.CaptchaService.font.max=30 #maximum size of captcha text font (px) services.CaptchaService.fontcolor=blue #color of captcha text }}} == Using it on Velocity forms == If you need to create an anonymous form, you can call a macro like this: {{{ #macro (formCaptchaField) #if (! $data.User.hasLoggedIn()) <tr> <td colspan="2"> <div align="center"> <img src="$link.setAction('CaptchaAction').toString()" border="0"> </div> </td> </tr> <tr> <td> Please enter the preceeding text </td> <td width="$inputWidth" class="frminput"> <input type="text" maxlength="10" name="captcha_response" value=""> </td> </tr> #end #end }}} if user has not logged in, captcha is inserting into the form. And we need an action named CaptchaAction to serve captcha challenge images to form. It is a descendant of VelocityAction: {{{ package com.zamek.portal_zamek.modules.actions; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.Locale; import javax.servlet.ServletException; import javax.servlet.http.HttpServletResponse; import org.apache.turbine.util.RunData; import org.apache.velocity.context.Context; import com.zamek.portal_zamek.ZamekConst; import com.zamek.portal_zamek.services.captcha.TurbineCaptcha; public class CaptchaAction extends VelocityAction { private final static String LOGHEADER = "com.zamek.portal_zamek.modules.actions."; public void doPerform(RunData data, Context ctx) throws Exception { data.declareDirectResponse(); // declaring directresponse layout data.setLayout("DirectResponseLayout"); processRequest(data); } private void processRequest(RunData data) throws ServletException, IOException { HttpServletResponse response = data.getResponse(); response.setContentType("image/jpeg"); try { String captchaId = data.getSession().getId(); Locale locale = data.getLocale(); ByteArrayOutputStream jpegOutputStream = TurbineCaptcha.getImage(captchaId, locale); response.setContentLength(jpegOutputStream.size()); jpegOutputStream.writeTo(response.getOutputStream()); } catch (Exception e) { log.error(LOGHEADER+" error:"+e.getMessage()); } } } }}} == Checking response == Service stores session id and original text, and if you get back the form data you can check it like this: {{{ public void doInsert (RunData data, Context context) { try { if (TurbineCaptcha.checkResponse(data)) { codes to match response } else setTemplate(data, FRM_REG); // response doesn' t match } catch (CaptchaServiceException ce) { setTemplate(data, FRM_REG); data.addMessage(Localization.getString(ZamekConst.BUNDLE_CAPTCHA_ERROR)); } } }}} == The Service package == Finally we need to make captcha service package. There are 5 java class in package: * CaptchaService.java interface with Constant declarations * TurbineCaptchaService.java the core service code * TurbineCaptcha.java static adapter to service * CaptchaGenerator.java extends DefaultManageableImageCaptchaService * CaptchaEngine.java extends ListImageCaptchaEngine implements parameter settings === CaptchaService.java === {{{ package com.zamek.portal_zamek.services.captcha; import java.awt.image.BufferedImage; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.Locale; import org.apache.turbine.services.Service; import org.apache.turbine.util.RunData; public interface CaptchaService extends Service { /** * The service identifier */ public final static String SERVICE_NAME = "CaptchaService"; /** * chars key in config */ public final static String CHARS_KEY = "chars"; /** * default chars */ public final static String DEFAULT_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; /** * min text length key in config */ public final static String PARSER_MIN_KEY = "parser.min"; /** * default min length */ public final static int DEFAULT_PARSER_MIN = 5; /** * max text length key in config */ public final static String PARSER_MAX_KEY = "parser.max"; /** * default max length */ public final static int DEFAULT_PARSER_MAX = 8; /** * size width key in config */ public final static String SIZE_WIDTH_KEY = "size.width"; /** * default size width */ public final static int DEFAULT_SIZE_WIDTH = 200; /** * size height key in config */ public final static String SIZE_HEIGHT_KEY = "size.height"; /** * default size height */ public final static int DEFAULT_SIZE_HEIGHT = 100; /** * min font size key in config */ public final static String MIN_FONT_KEY = "font.min"; /** * default font min */ public final static int DEFAULT_FONT_MIN = 25; /** * max font size key in config */ public final static String MAX_FONT_KEY = "font.max"; /** * default font max */ public final static int DEFAULT_FONT_MAX = 30; /** * font color key in config */ public final static String FONT_COLOR_KEY = "fontcolor"; /** * default font color */ public final static String DEFAULT_FONT_COLOR = "white"; /** * name of captcha field on form */ public final static String CTX_CAPTCHA = "captcha"; /** * name of captcha response field on form */ public final static String CTX_CAPTCHA_RESPONSE = "captcha_response"; /** * Captcha error message form localized messages */ public final static String BUNDLE_CAPTCHA_ERROR = "captchaError"; /** * getting a new captcha * @param captchaId session id * @param locale locales for request * @return an image */ public BufferedImage getCaptcha(final String captchaId, final Locale locale); /** * getting a captcha image * @param captchaId session id * @param locale locales for request * @return an jpeg stream */ public ByteArrayOutputStream getImage(final String captchaId, final Locale locale) throws IOException; /** * check response * @param data * @return */ public boolean checkResponse (RunData data); /** * validating response for session id * @param id session id * @param response text of response * @return */ public boolean validateResponseForID(final String id, final String response); } }}} === TurbineCaptchaService.java === {{{ package com.zamek.portal_zamek.services.captcha; import java.awt.image.BufferedImage; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.Locale; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.turbine.services.InitializationException; import org.apache.turbine.services.TurbineBaseService; import org.apache.turbine.services.localization.Localization; import org.apache.turbine.util.RunData; import com.sun.image.codec.jpeg.JPEGCodec; import com.sun.image.codec.jpeg.JPEGImageEncoder; public class TurbineCaptchaService extends TurbineBaseService implements CaptchaService { protected Log log = LogFactory.getLog(TurbineCaptchaService.class); private final static String LOGHEADER="com.zamek.portal_zamek.services.captcha."; private CaptchaGenerator generator = null; /** * initialize service */ public void init() throws InitializationException { generator = new CaptchaGenerator(); setInit(true); log.debug(LOGHEADER+"init ok"); } /** * getting a new captcha * @param captchaId session id * @param locale locales for request * @return an image */ public BufferedImage getCaptcha(final String captchaId, final Locale locale) { if (log.isDebugEnabled()) log.debug(String.format( LOGHEADER + "getCaptcha enter, captchaId:%s, locale:%s", captchaId, locale)); try { BufferedImage challenge = generator.getImageChallengeForID(captchaId, locale); return challenge; } catch (Exception e) { log.error(LOGHEADER + e.getMessage()); return null; } } /** * check response * @param data * @return */ public boolean checkResponse(RunData data) { String id = data.getSession().getId(), response = data.getParameters().get(CaptchaService.CTX_CAPTCHA_RESPONSE); if (StringUtils.isNotEmpty(id) && StringUtils.isNotEmpty(response) && validateResponseForID(id, response)) return true; data.addMessage(Localization.getString(CaptchaService.BUNDLE_CAPTCHA_ERROR)); return false; } /** * validating response for session id * @param id session id * @param response text of response * @return */ public boolean validateResponseForID(final String id, final String response) { return generator.validateResponseForID(id, response); } /** * * @param captchaId session id * @param locale locales for request * @return an jpeg stream */ public ByteArrayOutputStream getImage(final String captchaId, final Locale locale) throws IOException { ByteArrayOutputStream jpegOutputStream = new ByteArrayOutputStream(); BufferedImage challenge = this.getCaptcha(captchaId, locale); // a jpeg encoder JPEGImageEncoder jpegEncoder = JPEGCodec.createJPEGEncoder(jpegOutputStream); jpegEncoder.encode(challenge); return jpegOutputStream; } } }}} === TurbineCaptcha.java === {{{ package com.zamek.portal_zamek.services.captcha; import java.awt.image.BufferedImage; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.Locale; import org.apache.turbine.services.TurbineServices; import org.apache.turbine.util.RunData; public class TurbineCaptcha { /** * get service object * @return */ public static CaptchaService getService() { return (CaptchaService) TurbineServices.getInstance(). getService(CaptchaService.SERVICE_NAME); } /** * checking service available * @return * @throws InstantiationException */ public static boolean isAvailable() throws InstantiationException { try { @SuppressWarnings("unused") CaptchaService captcha = getService(); return true; } catch (Exception ie) { return false; } } /** * getting a captcha challenge image * @param captchaId * @param locale * @return */ public static BufferedImage getCaptcha(final String captchaId, final Locale locale) { return getService().getCaptcha(captchaId, locale); } /** * checking response of user * @param data * @return */ public static boolean checkResponse(RunData data) { return getService().checkResponse(data); } /** * validate user's response to compare stored text * @param id * @param response * @return */ public static boolean validateResponseForID(final String id, final String response) { return getService().validateResponseForID(id, response); } /** * getting a challenge image * @param captchaId * @param locale * @return * @throws IOException */ public static ByteArrayOutputStream getImage(final String captchaId, final Locale locale) throws IOException { return getService().getImage(captchaId, locale); } } }}} === CaptchaGenerator.java === {{{ package com.zamek.portal_zamek.services.captcha; import com.octo.captcha.service.image.DefaultManageableImageCaptchaService; public class CaptchaGenerator extends DefaultManageableImageCaptchaService { public CaptchaGenerator() { super(); this.setCaptchaEngine(new CaptchaEngine()); } } }}} === CaptchaEngine.java === {{{ package com.zamek.portal_zamek.services.captcha; import java.awt.Color; import org.apache.commons.configuration.Configuration; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.turbine.Turbine; import com.octo.captcha.component.image.backgroundgenerator.BackgroundGenerator; import com.octo.captcha.component.image.backgroundgenerator.FunkyBackgroundGenerator; import com.octo.captcha.component.image.fontgenerator.FontGenerator; import com.octo.captcha.component.image.fontgenerator.TwistedAndShearedRandomFontGenerator; import com.octo.captcha.component.image.textpaster.RandomTextPaster; import com.octo.captcha.component.image.textpaster.TextPaster; import com.octo.captcha.component.image.wordtoimage.ComposedWordToImage; import com.octo.captcha.component.image.wordtoimage.WordToImage; import com.octo.captcha.component.word.wordgenerator.RandomWordGenerator; import com.octo.captcha.component.word.wordgenerator.WordGenerator; import com.octo.captcha.engine.image.ListImageCaptchaEngine; import com.octo.captcha.image.gimpy.GimpyFactory; public class CaptchaEngine extends ListImageCaptchaEngine { private final static String LOGHEADER = "com.zamek.portal_zamek.services.captcha."; private final static Log log = LogFactory.getLog(CaptchaEngine.class); @Override protected void buildInitialFactories() { Configuration conf = Turbine.getConfiguration(); int parserMin = conf.getInt( CaptchaService.PARSER_MIN_KEY, CaptchaService.DEFAULT_PARSER_MIN), parserMax = conf.getInt( CaptchaService.PARSER_MAX_KEY, CaptchaService.DEFAULT_PARSER_MAX), sizeWidth = conf.getInt( CaptchaService.SIZE_WIDTH_KEY, CaptchaService.DEFAULT_SIZE_WIDTH), sizeHeight = conf.getInt( CaptchaService.SIZE_HEIGHT_KEY, CaptchaService.DEFAULT_SIZE_HEIGHT), fontMin = conf.getInt( CaptchaService.MIN_FONT_KEY, CaptchaService.DEFAULT_FONT_MIN), fontMax = conf.getInt( CaptchaService.MAX_FONT_KEY, CaptchaService.DEFAULT_FONT_MAX); String chars = conf.getString( CaptchaService.CHARS_KEY, CaptchaService.DEFAULT_CHARS), colorName = conf.getString( CaptchaService.FONT_COLOR_KEY, CaptchaService.DEFAULT_FONT_COLOR); Color fontColor = Color.getColor(colorName); if (log.isDebugEnabled()) log.debug(LOGHEADER + String.format("init, parserMin:%d, parserMax:%d, sizeWidth:%d, sizeHeight:%d, fontMin:%d, fontMax:%d, chars:%s", parserMin, parserMax, sizeWidth, sizeHeight, fontMin, fontMax, chars)); WordGenerator wordGenerator = new RandomWordGenerator(chars); TextPaster textParser = new RandomTextPaster(parserMin, parserMax, fontColor); BackgroundGenerator backgroundGenerator = new FunkyBackgroundGenerator (sizeWidth, sizeHeight); FontGenerator fontGenerator = new TwistedAndShearedRandomFontGenerator (fontMin, fontMax); WordToImage wordToImage = new ComposedWordToImage(fontGenerator, backgroundGenerator, textParser); this.addFactory(new GimpyFactory(wordGenerator, wordToImage)); } } }}} --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]