package org.apereo.cas.web.flow;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectReader;
import org.apache.commons.lang3.StringUtils;
import org.apereo.cas.configuration.model.support.captcha.GoogleRecaptchaProperties;
import org.apereo.cas.web.support.WebUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.binding.message.MessageBuilder;
import org.springframework.binding.message.MessageContext;
import org.springframework.http.HttpStatus;
import org.springframework.webflow.action.AbstractAction;
import org.springframework.webflow.execution.Event;
import org.springframework.webflow.execution.RequestContext;
import javax.net.ssl.HttpsURLConnection;
import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.stream.Collectors;
/**
* This is {@link ValidateCaptchaAction}.
*
* @author Misagh Moayyed
* @since 5.0.0
*/
public class ValidateCaptchaAction extends AbstractAction {
private static final Logger LOGGER = LoggerFactory.getLogger(ValidateCaptchaAction.class);
private static final ObjectReader READER = new ObjectMapper().findAndRegisterModules().reader();
private static final String CODE = "captchaError";
private final GoogleRecaptchaProperties recaptchaProperties;
public ValidateCaptchaAction(final GoogleRecaptchaProperties recaptchaProperties) {
this.recaptchaProperties = recaptchaProperties;
}
@Override
protected Event doExecute(final RequestContext requestContext) throws Exception {
final HttpServletRequest request = WebUtils.getHttpServletRequest(requestContext);
final String gRecaptchaResponse = request.getParameter("g-recaptcha-response");
if (StringUtils.isBlank(gRecaptchaResponse)) {
LOGGER.warn("Recaptcha response is missing from the request");
return getError(requestContext);
}
try {
final URL obj = new URL(recaptchaProperties.getVerifyUrl());
final HttpsURLConnection con = (HttpsURLConnection) obj.openConnection();
con.setRequestMethod("POST");
con.setRequestProperty("User-Agent", WebUtils.getHttpServletRequestUserAgent());
con.setRequestProperty("Accept-Language", "en-US,en;q=0.5");
final String postParams = "secret=" + recaptchaProperties.getSecret() + "&response=" + gRecaptchaResponse;
LOGGER.debug("Sending 'POST' request to URL: [{}]", obj);
con.setDoOutput(true);
try (DataOutputStream wr = new DataOutputStream(con.getOutputStream())) {
wr.writeBytes(postParams);
wr.flush();
}
final int responseCode = con.getResponseCode();
LOGGER.debug("Response Code: [{}]", responseCode);
if (responseCode == HttpStatus.OK.value()) {
try (BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream(), StandardCharsets.UTF_8))) {
final String response = in.lines().collect(Collectors.joining());
LOGGER.debug("Google captcha response received: [{}]", response);
final JsonNode node = READER.readTree(response);
if (node.has("success") && node.get("success").booleanValue()) {
return null;
}
}
}
} catch (final Exception e) {
LOGGER.error(e.getMessage(), e);
}
return getError(requestContext);
}
private Event getError(final RequestContext requestContext) {
final MessageContext messageContext = requestContext.getMessageContext();
messageContext.addMessage(new MessageBuilder().error().code(CODE).build());
return getEventFactorySupport().event(this, CODE);
}
}