1   /**
2    * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
3    *
4    * The contents of this file are subject to the terms of the Liferay Enterprise
5    * Subscription License ("License"). You may not use this file except in
6    * compliance with the License. You can obtain a copy of the License by
7    * contacting Liferay, Inc. See the License for the specific language governing
8    * permissions and limitations under the License, including but not limited to
9    * distribution rights of the Software.
10   *
11   *
12   *
13   */
14  
15  package com.liferay.portal.captcha.simplecaptcha;
16  
17  import com.liferay.portal.kernel.captcha.Captcha;
18  import com.liferay.portal.kernel.captcha.CaptchaException;
19  import com.liferay.portal.kernel.captcha.CaptchaMaxChallengesException;
20  import com.liferay.portal.kernel.captcha.CaptchaTextException;
21  import com.liferay.portal.kernel.log.Log;
22  import com.liferay.portal.kernel.log.LogFactoryUtil;
23  import com.liferay.portal.kernel.util.ContentTypes;
24  import com.liferay.portal.kernel.util.InstancePool;
25  import com.liferay.portal.kernel.util.ParamUtil;
26  import com.liferay.portal.kernel.util.Randomizer;
27  import com.liferay.portal.kernel.util.Validator;
28  import com.liferay.portal.util.PortalUtil;
29  import com.liferay.portal.util.PropsValues;
30  import com.liferay.portal.util.WebKeys;
31  
32  import java.io.IOException;
33  
34  import javax.portlet.PortletRequest;
35  import javax.portlet.PortletResponse;
36  import javax.portlet.PortletSession;
37  
38  import javax.servlet.http.HttpServletRequest;
39  import javax.servlet.http.HttpServletResponse;
40  import javax.servlet.http.HttpSession;
41  
42  import nl.captcha.backgrounds.BackgroundProducer;
43  import nl.captcha.gimpy.GimpyRenderer;
44  import nl.captcha.noise.NoiseProducer;
45  import nl.captcha.servlet.CaptchaServletUtil;
46  import nl.captcha.text.producer.TextProducer;
47  import nl.captcha.text.renderer.WordRenderer;
48  
49  /**
50   * <a href="SimpleCaptchaImpl.java.html"><b><i>View Source</i></b></a>
51   *
52   * @author Brian Wing Shun Chan
53   */
54  public class SimpleCaptchaImpl implements Captcha {
55  
56      public SimpleCaptchaImpl() {
57          initBackgroundProducers();
58          initGimpyRenderers();
59          initNoiseProducers();
60          initTextProducers();
61          initWordRenderers();
62      }
63  
64      public void check(HttpServletRequest request) throws CaptchaException {
65          if (!isEnabled(request)) {
66              return;
67          }
68  
69          HttpSession session = request.getSession();
70  
71          String captchaText = (String)session.getAttribute(WebKeys.CAPTCHA_TEXT);
72  
73          if (captchaText == null) {
74              _log.error(
75                  "Captcha text is null. User " + request.getRemoteUser() +
76                      " may be trying to circumvent the captcha.");
77  
78              throw new CaptchaTextException();
79          }
80  
81          if (!captchaText.equals(ParamUtil.getString(request, "captchaText"))) {
82              if ((PropsValues.CAPTCHA_MAX_CHALLENGES > 0) &&
83                  (Validator.isNotNull(request.getRemoteUser()))) {
84  
85                  Integer count = (Integer)session.getAttribute(
86                      WebKeys.CAPTCHA_COUNT);
87  
88                  if (count == null) {
89                      count = new Integer(1);
90                  }
91                  else {
92                      count = new Integer(count.intValue() + 1);
93                  }
94  
95                  session.setAttribute(WebKeys.CAPTCHA_COUNT, count);
96              }
97  
98              throw new CaptchaTextException();
99          }
100 
101         if (_log.isDebugEnabled()) {
102             _log.debug("Captcha text is valid");
103         }
104 
105         session.removeAttribute(WebKeys.CAPTCHA_TEXT);
106     }
107 
108     public void check(PortletRequest portletRequest) throws CaptchaException {
109         if (!isEnabled(portletRequest)) {
110             return;
111         }
112 
113         PortletSession portletSession = portletRequest.getPortletSession();
114 
115         String captchaText = (String)portletSession.getAttribute(
116             WebKeys.CAPTCHA_TEXT);
117 
118         if (captchaText == null) {
119             _log.error(
120                 "Captcha text is null. User " + portletRequest.getRemoteUser() +
121                     " may be trying to circumvent the captcha.");
122 
123             throw new CaptchaTextException();
124         }
125 
126         if (!captchaText.equals(
127                 ParamUtil.getString(portletRequest, "captchaText"))) {
128 
129             if ((PropsValues.CAPTCHA_MAX_CHALLENGES > 0) &&
130                 (Validator.isNotNull(portletRequest.getRemoteUser()))) {
131 
132                 Integer count = (Integer)portletSession.getAttribute(
133                     WebKeys.CAPTCHA_COUNT);
134 
135                 if (count == null) {
136                     count = new Integer(1);
137                 }
138                 else {
139                     count = new Integer(count.intValue() + 1);
140                 }
141 
142                 portletSession.setAttribute(WebKeys.CAPTCHA_COUNT, count);
143             }
144 
145             throw new CaptchaTextException();
146         }
147 
148         if (_log.isDebugEnabled()) {
149             _log.debug("Captcha text is valid");
150         }
151 
152         portletSession.removeAttribute(WebKeys.CAPTCHA_TEXT);
153     }
154 
155     public String getTaglibPath() {
156         return _TAGLIB_PATH;
157     }
158 
159     public boolean isEnabled(HttpServletRequest request)
160         throws CaptchaException {
161 
162         if (PropsValues.CAPTCHA_MAX_CHALLENGES > 0) {
163             HttpSession session = request.getSession();
164 
165             Integer count = (Integer)session.getAttribute(
166                 WebKeys.CAPTCHA_COUNT);
167 
168             if (count != null && count >= PropsValues.CAPTCHA_MAX_CHALLENGES) {
169                 throw new CaptchaMaxChallengesException();
170             }
171 
172             if ((count != null) &&
173                 (PropsValues.CAPTCHA_MAX_CHALLENGES <= count.intValue())) {
174 
175                 return false;
176             }
177             else {
178                 return true;
179             }
180         }
181         else if (PropsValues.CAPTCHA_MAX_CHALLENGES < 0) {
182             return false;
183         }
184         else {
185             return true;
186         }
187     }
188 
189     public boolean isEnabled(PortletRequest portletRequest)
190         throws CaptchaException {
191 
192         if (PropsValues.CAPTCHA_MAX_CHALLENGES > 0) {
193             PortletSession portletSession = portletRequest.getPortletSession();
194 
195             Integer count = (Integer)portletSession.getAttribute(
196                 WebKeys.CAPTCHA_COUNT);
197 
198             if (count != null && count >= PropsValues.CAPTCHA_MAX_CHALLENGES) {
199                 throw new CaptchaMaxChallengesException();
200             }
201 
202             if ((count != null) &&
203                 (PropsValues.CAPTCHA_MAX_CHALLENGES <= count.intValue())) {
204 
205                 return false;
206             }
207             else {
208                 return true;
209             }
210         }
211         else if (PropsValues.CAPTCHA_MAX_CHALLENGES < 0) {
212             return false;
213         }
214         else {
215             return true;
216         }
217     }
218 
219     public void serveImage(
220             HttpServletRequest request, HttpServletResponse response)
221         throws IOException {
222 
223         HttpSession session = request.getSession();
224 
225         nl.captcha.Captcha simpleCaptcha = getSimpleCaptcha();
226 
227         session.setAttribute(WebKeys.CAPTCHA_TEXT, simpleCaptcha.getAnswer());
228 
229         response.setContentType(ContentTypes.IMAGE_JPEG);
230 
231         CaptchaServletUtil.writeImage(
232             response.getOutputStream(), simpleCaptcha.getImage());
233     }
234 
235     public void serveImage(
236             PortletRequest portletRequest, PortletResponse portletResponse)
237         throws IOException {
238 
239         PortletSession portletSession = portletRequest.getPortletSession();
240 
241         nl.captcha.Captcha simpleCaptcha = getSimpleCaptcha();
242 
243         portletSession.setAttribute(
244             WebKeys.CAPTCHA_TEXT, simpleCaptcha.getAnswer());
245 
246         HttpServletResponse response = PortalUtil.getHttpServletResponse(
247             portletResponse);
248 
249         CaptchaServletUtil.writeImage(
250             response.getOutputStream(), simpleCaptcha.getImage());
251     }
252 
253     protected BackgroundProducer getBackgroundProducer() {
254         if (_backgroundProducers.length == 1) {
255             return _backgroundProducers[0];
256         }
257 
258         Randomizer randomizer = Randomizer.getInstance();
259 
260         int pos = randomizer.nextInt(_backgroundProducers.length);
261 
262         return _backgroundProducers[pos];
263     }
264 
265     protected GimpyRenderer getGimpyRenderer() {
266         if (_gimpyRenderers.length == 1) {
267             return _gimpyRenderers[0];
268         }
269 
270         Randomizer randomizer = Randomizer.getInstance();
271 
272         int pos = randomizer.nextInt(_gimpyRenderers.length);
273 
274         return _gimpyRenderers[pos];
275     }
276 
277     protected int getHeight() {
278         return PropsValues.CAPTCHA_ENGINE_SIMPLECAPTCHA_HEIGHT;
279     }
280 
281     protected NoiseProducer getNoiseProducer() {
282         if (_noiseProducers.length == 1) {
283             return _noiseProducers[0];
284         }
285 
286         Randomizer randomizer = Randomizer.getInstance();
287 
288         int pos = randomizer.nextInt(_noiseProducers.length);
289 
290         return _noiseProducers[pos];
291     }
292 
293     protected nl.captcha.Captcha getSimpleCaptcha() {
294         nl.captcha.Captcha.Builder captchaBuilder =
295             new nl.captcha.Captcha.Builder(getWidth(), getHeight());
296 
297         captchaBuilder.addText(getTextProducer(), getWordRenderer());
298         captchaBuilder.addBackground(getBackgroundProducer());
299         captchaBuilder.gimp(getGimpyRenderer());
300         captchaBuilder.addNoise(getNoiseProducer());
301         captchaBuilder.addBorder();
302 
303         return captchaBuilder.build();
304     }
305 
306     protected TextProducer getTextProducer() {
307         if (_textProducers.length == 1) {
308             return _textProducers[0];
309         }
310 
311         Randomizer randomizer = Randomizer.getInstance();
312 
313         int pos = randomizer.nextInt(_textProducers.length);
314 
315         return _textProducers[pos];
316     }
317 
318     protected int getWidth() {
319         return PropsValues.CAPTCHA_ENGINE_SIMPLECAPTCHA_WIDTH;
320     }
321 
322     protected WordRenderer getWordRenderer() {
323         if (_wordRenderers.length == 1) {
324             return _wordRenderers[0];
325         }
326 
327         Randomizer randomizer = Randomizer.getInstance();
328 
329         int pos = randomizer.nextInt(_wordRenderers.length);
330 
331         return _wordRenderers[pos];
332     }
333 
334     protected void initBackgroundProducers() {
335         String[] backgroundProducerClassNames =
336             PropsValues.CAPTCHA_ENGINE_SIMPLECAPTCHA_BACKGROUND_PRODUCERS;
337 
338         _backgroundProducers = new BackgroundProducer[
339             backgroundProducerClassNames.length];
340 
341         for (int i = 0; i < backgroundProducerClassNames.length; i++) {
342             String backgroundProducerClassName =
343                 backgroundProducerClassNames[i];
344 
345             _backgroundProducers[i] = (BackgroundProducer)InstancePool.get(
346                 backgroundProducerClassName);
347         }
348     }
349 
350     protected void initGimpyRenderers() {
351         String[] gimpyRendererClassNames =
352             PropsValues.CAPTCHA_ENGINE_SIMPLECAPTCHA_GIMPY_RENDERERS;
353 
354         _gimpyRenderers = new GimpyRenderer[
355             gimpyRendererClassNames.length];
356 
357         for (int i = 0; i < gimpyRendererClassNames.length; i++) {
358             String gimpyRendererClassName =
359                 gimpyRendererClassNames[i];
360 
361             _gimpyRenderers[i] = (GimpyRenderer)InstancePool.get(
362                 gimpyRendererClassName);
363         }
364     }
365 
366     protected void initNoiseProducers() {
367         String[] noiseProducerClassNames =
368             PropsValues.CAPTCHA_ENGINE_SIMPLECAPTCHA_NOISE_PRODUCERS;
369 
370         _noiseProducers = new NoiseProducer[noiseProducerClassNames.length];
371 
372         for (int i = 0; i < noiseProducerClassNames.length; i++) {
373             String noiseProducerClassName = noiseProducerClassNames[i];
374 
375             _noiseProducers[i] = (NoiseProducer)InstancePool.get(
376                 noiseProducerClassName);
377         }
378     }
379 
380     protected void initTextProducers() {
381         String[] textProducerClassNames =
382             PropsValues.CAPTCHA_ENGINE_SIMPLECAPTCHA_TEXT_PRODUCERS;
383 
384         _textProducers = new TextProducer[textProducerClassNames.length];
385 
386         for (int i = 0; i < textProducerClassNames.length; i++) {
387             String textProducerClassName = textProducerClassNames[i];
388 
389             _textProducers[i] = (TextProducer)InstancePool.get(
390                 textProducerClassName);
391         }
392     }
393 
394     protected void initWordRenderers() {
395         String[] wordRendererClassNames =
396             PropsValues.CAPTCHA_ENGINE_SIMPLECAPTCHA_WORD_RENDERERS;
397 
398         _wordRenderers = new WordRenderer[wordRendererClassNames.length];
399 
400         for (int i = 0; i < wordRendererClassNames.length; i++) {
401             String wordRendererClassName = wordRendererClassNames[i];
402 
403             _wordRenderers[i] = (WordRenderer)InstancePool.get(
404                 wordRendererClassName);
405         }
406     }
407 
408     private static final String _TAGLIB_PATH =
409         "/html/taglib/ui/captcha/simplecaptcha.jsp";
410 
411     private static Log _log = LogFactoryUtil.getLog(SimpleCaptchaImpl.class);
412 
413     private BackgroundProducer[] _backgroundProducers;
414     private GimpyRenderer[] _gimpyRenderers;
415     private NoiseProducer[] _noiseProducers;
416     private TextProducer[] _textProducers;
417     private WordRenderer[] _wordRenderers;
418 
419 }