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