org.sakaiproject.nakamura.captcha.ReCaptchaService.java Source code

Java tutorial

Introduction

Here is the source code for org.sakaiproject.nakamura.captcha.ReCaptchaService.java

Source

/**
 * Licensed to the Sakai Foundation (SF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The SF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations under the License.
 */
package org.sakaiproject.nakamura.captcha;

import org.apache.commons.httpclient.Credentials;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.UsernamePasswordCredentials;
import org.apache.commons.httpclient.auth.AuthScope;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.io.IOUtils;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Properties;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Service;
import org.apache.sling.commons.osgi.PropertiesUtil;
import org.sakaiproject.nakamura.api.captcha.CaptchaService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

@Service
@Component(immediate = true, metatype = true)
@Properties(value = { @Property(name = "service.vendor", value = "The Sakai Foundation"),
        @Property(name = "service.description", value = "An implementation for the CaptchaService that uses the Google reCAPTCHA webservice.") })
public class ReCaptchaService implements CaptchaService {

    @Property(value = "6Lef4bsSAAAAAJOwQE-qwkAOzGG3DizFP7GYYng-", description = "Your public key for the reCAPTCHA service")
    static final String KEY_PUBLIC = "org.sakaiproject.nakamura.captcha.key_public";

    @Property(value = "6Lef4bsSAAAAAId09ufqqs89SwdWpa9t7htW1aRc", description = "Your private key for the reCAPTCHA service.")
    static final String KEY_PRIVATE = "org.sakaiproject.nakamura.captcha.key_private";

    @Property(value = "http://www.google.com/recaptcha/api/verify", description = "The REST endpoint for the reCAPTCHA service.")
    static final String RECAPTCHA_ENDPOINT = "org.sakaiproject.nakamura.captcha.endpoint";

    static final Logger LOGGER = LoggerFactory.getLogger(ReCaptchaService.class);

    /**
     * The HTTP client that we will use to connect to the reCAPTCHA REST service.
     */
    private HttpClient client;
    private String keyPrivate;
    private String keyPublic;
    private String endpoint;

    @Activate
    protected void activate(Map<?, ?> properties) {
        // Get the properties.
        keyPrivate = PropertiesUtil.toString(properties.get(KEY_PRIVATE), "");
        keyPublic = PropertiesUtil.toString(properties.get(KEY_PUBLIC), "");
        endpoint = PropertiesUtil.toString(properties.get(RECAPTCHA_ENDPOINT), "");

        // Initialize the client on start up.
        client = new HttpClient();

        // allow communications via a proxy server if command line
        // java parameters http.proxyHost,http.proxyPort,http.proxyUser,
        // http.proxyPassword have been provided.
        String proxyHost = System.getProperty("http.proxyHost", "");
        int proxyPort = Integer.parseInt(System.getProperty("http.proxyPort", "80"));
        if (!proxyHost.equals("")) {
            // allow communications via a non-authenticating proxy
            client.getHostConfiguration().setProxy(proxyHost, proxyPort);

            String proxyUser = System.getProperty("http.proxyUser", "");
            String proxyPassword = System.getProperty("http.proxyPassword", "");
            if (!proxyUser.equals("")) {
                // allow communications via an authenticating proxy
                Credentials credentials = new UsernamePasswordCredentials(proxyUser, proxyPassword);
                AuthScope authScope = new AuthScope(proxyHost, proxyPort);
                client.getState().setProxyCredentials(authScope, credentials);
            }
        }
    }

    /**
     * 
     * {@inheritDoc}
     * 
     * @see org.sakaiproject.nakamura.api.captcha.CaptchaService#checkRequest(javax.servlet.http.HttpServletRequest)
     */
    public boolean checkRequest(HttpServletRequest request) {
        // We need the following things to verify a request with reCAPTCHA
        // - Our private key (privatekey)
        // - The user his IP address (remoteip)
        // - The challenge (challenge)
        // - The response (response)

        String challenge = request.getParameter(":recaptcha-challenge");
        String response = request.getParameter(":recaptcha-response");

        // No point in doing a request when this one is false.
        if (challenge == null || response == null) {
            return false;
        }

        PostMethod method = new PostMethod(endpoint);
        method.addParameter("privatekey", keyPrivate);
        method.addParameter("remoteip", request.getRemoteAddr());
        method.addParameter("challenge", challenge);
        method.addParameter("response", response);

        try {
            int code = client.executeMethod(method);
            if (code != 200) {
                LOGGER.warn(
                        "ReCaptcha request responded with {} {} if this persists enable debug logging on this class for more info ",
                        code, method.getStatusText());
                if (LOGGER.isDebugEnabled()) {
                    LOGGER.debug("Response was {} ", method.getResponseBodyAsString());
                }
                return false;
            }

            InputStream bodyStream = method.getResponseBodyAsStream();
            StringWriter writer = new StringWriter();
            IOUtils.copy(bodyStream, writer);
            String body = writer.toString();

            LOGGER.debug("=== start of reCAPTCHA output ===\n" + body + "\n=== end of reCAPTCHA output ==="); // allow logging statement to show more clearly that the reCAPTCHA output contains a crlf character.
            if (!body.startsWith("true")) {
                LOGGER.warn("ReCaptcha challenge [{}] responde [{}] denied, debug level has more info ", challenge,
                        response);
                return false;
            }

            return true;
        } catch (HttpException e) {
            LOGGER.error("Caught an HTTPException when trying to check a request with the reCAPTCHA service.", e);
        } catch (IOException e) {
            LOGGER.error("Caught an IOException when trying to check a request with the reCAPTCHA service.", e);
        }

        return false;
    }

    /**
     * @return The properties that are defined in the OSGi admin console.
     */
    public Map<String, Object> getProperties() {
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("public-key", keyPublic);
        return map;
    }

}