001    /**
002     * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.captcha.recaptcha;
016    
017    import com.liferay.portal.captcha.simplecaptcha.SimpleCaptchaImpl;
018    import com.liferay.portal.kernel.captcha.CaptchaConfigurationException;
019    import com.liferay.portal.kernel.captcha.CaptchaException;
020    import com.liferay.portal.kernel.exception.SystemException;
021    import com.liferay.portal.kernel.json.JSONArray;
022    import com.liferay.portal.kernel.json.JSONException;
023    import com.liferay.portal.kernel.json.JSONFactoryUtil;
024    import com.liferay.portal.kernel.json.JSONObject;
025    import com.liferay.portal.kernel.log.Log;
026    import com.liferay.portal.kernel.log.LogFactoryUtil;
027    import com.liferay.portal.kernel.util.Http;
028    import com.liferay.portal.kernel.util.HttpUtil;
029    import com.liferay.portal.kernel.util.ParamUtil;
030    import com.liferay.portal.kernel.util.PropsKeys;
031    import com.liferay.portal.kernel.util.StringBundler;
032    import com.liferay.portal.kernel.util.StringPool;
033    import com.liferay.portal.kernel.util.StringUtil;
034    import com.liferay.portal.util.PortalUtil;
035    import com.liferay.portal.util.PrefsPropsUtil;
036    import com.liferay.portal.util.PropsValues;
037    
038    import java.io.IOException;
039    
040    import javax.portlet.PortletRequest;
041    import javax.portlet.ResourceRequest;
042    import javax.portlet.ResourceResponse;
043    
044    import javax.servlet.http.HttpServletRequest;
045    import javax.servlet.http.HttpServletResponse;
046    
047    /**
048     * @author Tagnaouti Boubker
049     * @author Jorge Ferrer
050     * @author Brian Wing Shun Chan
051     * @author Daniel Sanz
052     */
053    public class ReCaptchaImpl extends SimpleCaptchaImpl {
054    
055            @Override
056            public String getTaglibPath() {
057                    return _TAGLIB_PATH;
058            }
059    
060            @Override
061            public void serveImage(
062                    HttpServletRequest request, HttpServletResponse response) {
063    
064                    throw new UnsupportedOperationException();
065            }
066    
067            @Override
068            public void serveImage(
069                    ResourceRequest resourceRequest, ResourceResponse resourceResponse) {
070    
071                    throw new UnsupportedOperationException();
072            }
073    
074            @Override
075            protected boolean validateChallenge(HttpServletRequest request)
076                    throws CaptchaException {
077    
078                    String reCaptchaResponse = ParamUtil.getString(
079                            request, "g-recaptcha-response");
080    
081                    Http.Options options = new Http.Options();
082    
083                    try {
084                            options.addPart(
085                                    "secret",
086                                    PrefsPropsUtil.getString(
087                                            PropsKeys.CAPTCHA_ENGINE_RECAPTCHA_KEY_PRIVATE,
088                                            PropsValues.CAPTCHA_ENGINE_RECAPTCHA_KEY_PRIVATE));
089                    }
090                    catch (SystemException se) {
091                            _log.error(se, se);
092                    }
093    
094                    options.addPart("remoteip", request.getRemoteAddr());
095                    options.addPart("response", reCaptchaResponse);
096                    options.setLocation(PropsValues.CAPTCHA_ENGINE_RECAPTCHA_URL_VERIFY);
097                    options.setPost(true);
098    
099                    String content = null;
100    
101                    try {
102                            content = HttpUtil.URLtoString(options);
103                    }
104                    catch (IOException ioe) {
105                            _log.error(ioe, ioe);
106    
107                            throw new CaptchaConfigurationException();
108                    }
109    
110                    if (content == null) {
111                            _log.error("reCAPTCHA did not return a result");
112    
113                            throw new CaptchaConfigurationException();
114                    }
115    
116                    try {
117                            JSONObject jsonObject = JSONFactoryUtil.createJSONObject(content);
118    
119                            String success = jsonObject.getString("success");
120    
121                            if (StringUtil.equalsIgnoreCase(success, "true")) {
122                                    return true;
123                            }
124    
125                            JSONArray jsonArray = jsonObject.getJSONArray("error-codes");
126    
127                            if ((jsonArray == null) || (jsonArray.length() == 0)) {
128                                    _log.error("reCAPTCHA encountered an error");
129    
130                                    throw new CaptchaConfigurationException();
131                            }
132    
133                            StringBundler sb = new StringBundler(jsonArray.length() * 2 - 1);
134    
135                            for (int i = 0; i < jsonArray.length(); i++) {
136                                    sb.append(jsonArray.getString(i));
137    
138                                    if (i < (jsonArray.length() - 1)) {
139                                            sb.append(StringPool.COMMA_AND_SPACE);
140                                    }
141                            }
142    
143                            _log.error("reCAPTCHA encountered an error: " + sb.toString());
144    
145                            throw new CaptchaConfigurationException();
146                    }
147                    catch (JSONException jsone) {
148                            _log.error("reCAPTCHA did not return a valid result: " + content);
149    
150                            throw new CaptchaConfigurationException();
151                    }
152            }
153    
154            @Override
155            protected boolean validateChallenge(PortletRequest portletRequest)
156                    throws CaptchaException {
157    
158                    HttpServletRequest request = PortalUtil.getHttpServletRequest(
159                            portletRequest);
160    
161                    request = PortalUtil.getOriginalServletRequest(request);
162    
163                    return validateChallenge(request);
164            }
165    
166            private static final String _TAGLIB_PATH =
167                    "/html/taglib/ui/captcha/recaptcha.jsp";
168    
169            private static final Log _log = LogFactoryUtil.getLog(ReCaptchaImpl.class);
170    
171    }