001
014
015 package com.liferay.portal.captcha.simplecaptcha;
016
017 import com.liferay.portal.kernel.captcha.Captcha;
018 import com.liferay.portal.kernel.captcha.CaptchaException;
019 import com.liferay.portal.kernel.captcha.CaptchaMaxChallengesException;
020 import com.liferay.portal.kernel.captcha.CaptchaTextException;
021 import com.liferay.portal.kernel.log.Log;
022 import com.liferay.portal.kernel.log.LogFactoryUtil;
023 import com.liferay.portal.kernel.util.ContentTypes;
024 import com.liferay.portal.kernel.util.InstancePool;
025 import com.liferay.portal.kernel.util.ParamUtil;
026 import com.liferay.portal.kernel.util.Randomizer;
027 import com.liferay.portal.kernel.util.Validator;
028 import com.liferay.portal.util.PortalUtil;
029 import com.liferay.portal.util.PropsValues;
030 import com.liferay.portal.util.WebKeys;
031
032 import java.io.IOException;
033
034 import javax.portlet.PortletRequest;
035 import javax.portlet.PortletResponse;
036 import javax.portlet.PortletSession;
037
038 import javax.servlet.http.HttpServletRequest;
039 import javax.servlet.http.HttpServletResponse;
040 import javax.servlet.http.HttpSession;
041
042 import nl.captcha.backgrounds.BackgroundProducer;
043 import nl.captcha.gimpy.GimpyRenderer;
044 import nl.captcha.noise.NoiseProducer;
045 import nl.captcha.servlet.CaptchaServletUtil;
046 import nl.captcha.text.producer.TextProducer;
047 import nl.captcha.text.renderer.WordRenderer;
048
049
053 public class SimpleCaptchaImpl implements Captcha {
054
055 public SimpleCaptchaImpl() {
056 initBackgroundProducers();
057 initGimpyRenderers();
058 initNoiseProducers();
059 initTextProducers();
060 initWordRenderers();
061 }
062
063 public void check(HttpServletRequest request) throws CaptchaException {
064 if (!isEnabled(request)) {
065 return;
066 }
067
068 if (!validateChallenge(request)) {
069 incrementCounter(request);
070
071 checkMaxChallenges(request);
072
073 throw new CaptchaTextException();
074 }
075
076 if (_log.isDebugEnabled()) {
077 _log.debug("Captcha text is valid");
078 }
079 }
080
081 public void check(PortletRequest portletRequest) throws CaptchaException {
082 if (!isEnabled(portletRequest)) {
083 return;
084 }
085
086 if (!validateChallenge(portletRequest)) {
087 incrementCounter(portletRequest);
088
089 checkMaxChallenges(portletRequest);
090
091 throw new CaptchaTextException();
092 }
093
094 if (_log.isDebugEnabled()) {
095 _log.debug("Captcha text is valid");
096 }
097 }
098
099 public String getTaglibPath() {
100 return _TAGLIB_PATH;
101 }
102
103 public boolean isEnabled(HttpServletRequest request)
104 throws CaptchaException {
105
106 checkMaxChallenges(request);
107
108 if (PropsValues.CAPTCHA_MAX_CHALLENGES >= 0) {
109 return true;
110 }
111 else {
112 return false;
113 }
114 }
115
116 public boolean isEnabled(PortletRequest portletRequest)
117 throws CaptchaException {
118
119 checkMaxChallenges(portletRequest);
120
121 if (PropsValues.CAPTCHA_MAX_CHALLENGES >= 0) {
122 return true;
123 }
124 else {
125 return false;
126 }
127 }
128
129 public void serveImage(
130 HttpServletRequest request, HttpServletResponse response)
131 throws IOException {
132
133 HttpSession session = request.getSession();
134
135 nl.captcha.Captcha simpleCaptcha = getSimpleCaptcha();
136
137 session.setAttribute(WebKeys.CAPTCHA_TEXT, simpleCaptcha.getAnswer());
138
139 response.setContentType(ContentTypes.IMAGE_JPEG);
140
141 CaptchaServletUtil.writeImage(
142 response.getOutputStream(), simpleCaptcha.getImage());
143 }
144
145 public void serveImage(
146 PortletRequest portletRequest, PortletResponse portletResponse)
147 throws IOException {
148
149 PortletSession portletSession = portletRequest.getPortletSession();
150
151 nl.captcha.Captcha simpleCaptcha = getSimpleCaptcha();
152
153 portletSession.setAttribute(
154 WebKeys.CAPTCHA_TEXT, simpleCaptcha.getAnswer());
155
156 HttpServletResponse response = PortalUtil.getHttpServletResponse(
157 portletResponse);
158
159 CaptchaServletUtil.writeImage(
160 response.getOutputStream(), simpleCaptcha.getImage());
161 }
162
163 protected void checkMaxChallenges(HttpServletRequest request)
164 throws CaptchaMaxChallengesException {
165
166 if (PropsValues.CAPTCHA_MAX_CHALLENGES > 0) {
167 HttpSession session = request.getSession();
168
169 Integer count = (Integer)session.getAttribute(
170 WebKeys.CAPTCHA_COUNT);
171
172 checkMaxChallenges(count);
173 }
174 }
175
176 protected void checkMaxChallenges(Integer count)
177 throws CaptchaMaxChallengesException {
178
179 if ((count != null) && (count > PropsValues.CAPTCHA_MAX_CHALLENGES)) {
180 throw new CaptchaMaxChallengesException();
181 }
182 }
183
184 protected void checkMaxChallenges(PortletRequest portletRequest)
185 throws CaptchaMaxChallengesException {
186
187 if (PropsValues.CAPTCHA_MAX_CHALLENGES > 0) {
188 PortletSession portletSession = portletRequest.getPortletSession();
189
190 Integer count = (Integer)portletSession.getAttribute(
191 WebKeys.CAPTCHA_COUNT);
192
193 checkMaxChallenges(count);
194 }
195 }
196
197 protected BackgroundProducer getBackgroundProducer() {
198 if (_backgroundProducers.length == 1) {
199 return _backgroundProducers[0];
200 }
201
202 Randomizer randomizer = Randomizer.getInstance();
203
204 int pos = randomizer.nextInt(_backgroundProducers.length);
205
206 return _backgroundProducers[pos];
207 }
208
209 protected GimpyRenderer getGimpyRenderer() {
210 if (_gimpyRenderers.length == 1) {
211 return _gimpyRenderers[0];
212 }
213
214 Randomizer randomizer = Randomizer.getInstance();
215
216 int pos = randomizer.nextInt(_gimpyRenderers.length);
217
218 return _gimpyRenderers[pos];
219 }
220
221 protected int getHeight() {
222 return PropsValues.CAPTCHA_ENGINE_SIMPLECAPTCHA_HEIGHT;
223 }
224
225 protected NoiseProducer getNoiseProducer() {
226 if (_noiseProducers.length == 1) {
227 return _noiseProducers[0];
228 }
229
230 Randomizer randomizer = Randomizer.getInstance();
231
232 int pos = randomizer.nextInt(_noiseProducers.length);
233
234 return _noiseProducers[pos];
235 }
236
237 protected nl.captcha.Captcha getSimpleCaptcha() {
238 nl.captcha.Captcha.Builder captchaBuilder =
239 new nl.captcha.Captcha.Builder(getWidth(), getHeight());
240
241 captchaBuilder.addText(getTextProducer(), getWordRenderer());
242 captchaBuilder.addBackground(getBackgroundProducer());
243 captchaBuilder.gimp(getGimpyRenderer());
244 captchaBuilder.addNoise(getNoiseProducer());
245 captchaBuilder.addBorder();
246
247 return captchaBuilder.build();
248 }
249
250 protected TextProducer getTextProducer() {
251 if (_textProducers.length == 1) {
252 return _textProducers[0];
253 }
254
255 Randomizer randomizer = Randomizer.getInstance();
256
257 int pos = randomizer.nextInt(_textProducers.length);
258
259 return _textProducers[pos];
260 }
261
262 protected int getWidth() {
263 return PropsValues.CAPTCHA_ENGINE_SIMPLECAPTCHA_WIDTH;
264 }
265
266 protected WordRenderer getWordRenderer() {
267 if (_wordRenderers.length == 1) {
268 return _wordRenderers[0];
269 }
270
271 Randomizer randomizer = Randomizer.getInstance();
272
273 int pos = randomizer.nextInt(_wordRenderers.length);
274
275 return _wordRenderers[pos];
276 }
277
278 protected void incrementCounter(HttpServletRequest request) {
279 if ((PropsValues.CAPTCHA_MAX_CHALLENGES > 0) &&
280 (Validator.isNotNull(request.getRemoteUser()))) {
281
282 HttpSession session = request.getSession();
283
284 Integer count = (Integer)session.getAttribute(
285 WebKeys.CAPTCHA_COUNT);
286
287 session.setAttribute(WebKeys.CAPTCHA_COUNT,
288 incrementCounter(count));
289 }
290 }
291
292 protected Integer incrementCounter(Integer count) {
293 if (count == null) {
294 count = new Integer(1);
295 }
296 else {
297 count = new Integer(count.intValue() + 1);
298 }
299
300 return count;
301 }
302
303 protected void incrementCounter(PortletRequest portletRequest) {
304 if ((PropsValues.CAPTCHA_MAX_CHALLENGES > 0) &&
305 (Validator.isNotNull(portletRequest.getRemoteUser()))) {
306
307 PortletSession portletSession = portletRequest.getPortletSession();
308
309 Integer count = (Integer)portletSession.getAttribute(
310 WebKeys.CAPTCHA_COUNT);
311
312 portletSession.setAttribute(WebKeys.CAPTCHA_COUNT,
313 incrementCounter(count));
314 }
315 }
316
317 protected void initBackgroundProducers() {
318 String[] backgroundProducerClassNames =
319 PropsValues.CAPTCHA_ENGINE_SIMPLECAPTCHA_BACKGROUND_PRODUCERS;
320
321 _backgroundProducers = new BackgroundProducer[
322 backgroundProducerClassNames.length];
323
324 for (int i = 0; i < backgroundProducerClassNames.length; i++) {
325 String backgroundProducerClassName =
326 backgroundProducerClassNames[i];
327
328 _backgroundProducers[i] = (BackgroundProducer)InstancePool.get(
329 backgroundProducerClassName);
330 }
331 }
332
333 protected void initGimpyRenderers() {
334 String[] gimpyRendererClassNames =
335 PropsValues.CAPTCHA_ENGINE_SIMPLECAPTCHA_GIMPY_RENDERERS;
336
337 _gimpyRenderers = new GimpyRenderer[
338 gimpyRendererClassNames.length];
339
340 for (int i = 0; i < gimpyRendererClassNames.length; i++) {
341 String gimpyRendererClassName = gimpyRendererClassNames[i];
342
343 _gimpyRenderers[i] = (GimpyRenderer)InstancePool.get(
344 gimpyRendererClassName);
345 }
346 }
347
348 protected void initNoiseProducers() {
349 String[] noiseProducerClassNames =
350 PropsValues.CAPTCHA_ENGINE_SIMPLECAPTCHA_NOISE_PRODUCERS;
351
352 _noiseProducers = new NoiseProducer[noiseProducerClassNames.length];
353
354 for (int i = 0; i < noiseProducerClassNames.length; i++) {
355 String noiseProducerClassName = noiseProducerClassNames[i];
356
357 _noiseProducers[i] = (NoiseProducer)InstancePool.get(
358 noiseProducerClassName);
359 }
360 }
361
362 protected void initTextProducers() {
363 String[] textProducerClassNames =
364 PropsValues.CAPTCHA_ENGINE_SIMPLECAPTCHA_TEXT_PRODUCERS;
365
366 _textProducers = new TextProducer[textProducerClassNames.length];
367
368 for (int i = 0; i < textProducerClassNames.length; i++) {
369 String textProducerClassName = textProducerClassNames[i];
370
371 _textProducers[i] = (TextProducer)InstancePool.get(
372 textProducerClassName);
373 }
374 }
375
376 protected void initWordRenderers() {
377 String[] wordRendererClassNames =
378 PropsValues.CAPTCHA_ENGINE_SIMPLECAPTCHA_WORD_RENDERERS;
379
380 _wordRenderers = new WordRenderer[wordRendererClassNames.length];
381
382 for (int i = 0; i < wordRendererClassNames.length; i++) {
383 String wordRendererClassName = wordRendererClassNames[i];
384
385 _wordRenderers[i] = (WordRenderer)InstancePool.get(
386 wordRendererClassName);
387 }
388 }
389
390 protected boolean validateChallenge(HttpServletRequest request)
391 throws CaptchaException {
392
393 HttpSession session = request.getSession();
394
395 String captchaText = (String)session.getAttribute(WebKeys.CAPTCHA_TEXT);
396
397 if (captchaText == null) {
398 _log.error(
399 "Captcha text is null. User " + request.getRemoteUser() +
400 " may be trying to circumvent the captcha.");
401
402 throw new CaptchaTextException();
403 }
404
405 boolean valid = captchaText.equals(
406 ParamUtil.getString(request, "captchaText"));
407
408 if (valid) {
409 session.removeAttribute(WebKeys.CAPTCHA_TEXT);
410 }
411
412 return valid;
413 }
414
415 protected boolean validateChallenge(PortletRequest portletRequest)
416 throws CaptchaException {
417
418 PortletSession portletSession = portletRequest.getPortletSession();
419
420 String captchaText = (String)portletSession.getAttribute(
421 WebKeys.CAPTCHA_TEXT);
422
423 if (captchaText == null) {
424 _log.error(
425 "Captcha text is null. User " + portletRequest.getRemoteUser() +
426 " may be trying to circumvent the captcha.");
427
428 throw new CaptchaTextException();
429 }
430
431 boolean valid = captchaText.equals(
432 ParamUtil.getString(portletRequest, "captchaText"));
433
434 if (valid) {
435 portletSession.removeAttribute(WebKeys.CAPTCHA_TEXT);
436 }
437
438 return valid;
439 }
440
441 private static final String _TAGLIB_PATH =
442 "/html/taglib/ui/captcha/simplecaptcha.jsp";
443
444 private static Log _log = LogFactoryUtil.getLog(SimpleCaptchaImpl.class);
445
446 private BackgroundProducer[] _backgroundProducers;
447 private GimpyRenderer[] _gimpyRenderers;
448 private NoiseProducer[] _noiseProducers;
449 private TextProducer[] _textProducers;
450 private WordRenderer[] _wordRenderers;
451
452 }