Skip to content

Commit

Permalink
Changes based on comments in recaptcha enterprise
Browse files Browse the repository at this point in the history
  • Loading branch information
Lakshan-Banneheke committed Sep 11, 2023
1 parent bdadd5c commit 645e44c
Show file tree
Hide file tree
Showing 7 changed files with 73 additions and 92 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -470,7 +470,7 @@ private static Properties validateCaptchaConfigs(Properties properties) {
RecoveryUtil.handleBadRequest(String.format("%s is not found ", CaptchaConstants.RE_CAPTCHA_VERIFY_URL),
Constants.STATUS_INTERNAL_SERVER_ERROR_MESSAGE_DEFAULT);
}
// Check if project id is available for reCaptcha Enterprise
// Check if project id is available for reCaptcha Enterprise.
if (CaptchaConstants.RE_CAPTCHA_TYPE_ENTERPRISE.equals(reCaptchaType) &&
StringUtils.isBlank(properties.getProperty(CaptchaConstants.RE_CAPTCHA_PROJECT_ID))) {
RecoveryUtil.handleBadRequest(String.format("%s is not found ", CaptchaConstants
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.HttpEntity;
Expand Down Expand Up @@ -90,42 +89,28 @@ public Response verifyCaptcha(ReCaptchaResponseTokenDTO reCaptchaResponse, Strin
HttpEntity entity = response.getEntity();
ReCaptchaVerificationResponseDTO reCaptchaVerificationResponseDTO = new ReCaptchaVerificationResponseDTO();

if (CaptchaConstants.RE_CAPTCHA_TYPE_ENTERPRISE.equals(reCaptchaType)) {
// For ReCaptcha Enterprise.
if (entity == null) {
RecoveryUtil.handleBadRequest("ReCaptcha Enterprise verification response is not received.",
Constants.STATUS_INTERNAL_SERVER_ERROR_MESSAGE_DEFAULT);
}
try {
try (InputStream in = entity.getContent()) {
JsonObject verificationResponse = new JsonParser().parse(IOUtils.toString(in)).getAsJsonObject();
JsonObject tokenProperties = verificationResponse.get(CaptchaConstants.CAPTCHA_TOKEN_PROPERTIES)
.getAsJsonObject();
boolean success = tokenProperties.get(CaptchaConstants.CAPTCHA_VALID).getAsBoolean();
reCaptchaVerificationResponseDTO.setSuccess(success);
}
} catch (IOException e) {
log.error("Unable to read the verification response.", e);
RecoveryUtil.handleBadRequest("Unable to read the verification response.",
Constants.STATUS_INTERNAL_SERVER_ERROR_MESSAGE_DEFAULT);
}
} else {
// For ReCaptcha v2 and v3.
try {
if (entity == null) {
RecoveryUtil.handleBadRequest("ReCaptcha verification response is not received.",
Constants.STATUS_INTERNAL_SERVER_ERROR_MESSAGE_DEFAULT);
}
try (InputStream in = entity.getContent()) {
JsonObject verificationResponse = new JsonParser().parse(IOUtils.toString(in)).getAsJsonObject();
reCaptchaVerificationResponseDTO.setSuccess(verificationResponse.get(
CaptchaConstants.CAPTCHA_SUCCESS).getAsBoolean());
}
} catch (IOException e) {
log.error("Unable to read the verification response.", e);
RecoveryUtil.handleBadRequest("Unable to read the verification response.",
Constants.STATUS_INTERNAL_SERVER_ERROR_MESSAGE_DEFAULT);
if (entity == null) {
RecoveryUtil.handleBadRequest("ReCaptcha verification response is not received.",
Constants.STATUS_INTERNAL_SERVER_ERROR_MESSAGE_DEFAULT);
}
try (InputStream in = entity.getContent()) {
JsonObject verificationResponse = new JsonParser().parse(IOUtils.toString(in)).getAsJsonObject();

if (CaptchaConstants.RE_CAPTCHA_TYPE_ENTERPRISE.equals(reCaptchaType)) {
// For Recaptcha Enterprise.
JsonObject tokenProperties = verificationResponse.get(CaptchaConstants.CAPTCHA_TOKEN_PROPERTIES)
.getAsJsonObject();
boolean success = tokenProperties.get(CaptchaConstants.CAPTCHA_VALID).getAsBoolean();
reCaptchaVerificationResponseDTO.setSuccess(success);
} else {
// For ReCaptcha v2 and v3.
reCaptchaVerificationResponseDTO.setSuccess(verificationResponse.get(
CaptchaConstants.CAPTCHA_SUCCESS).getAsBoolean());
}
} catch (IOException e) {
log.error("Unable to read the verification response.", e);
RecoveryUtil.handleBadRequest("Unable to read the verification response.",
Constants.STATUS_INTERNAL_SERVER_ERROR_MESSAGE_DEFAULT);
}

return Response.ok(reCaptchaVerificationResponseDTO).build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ public void testGetCaptcha(boolean reCaptchaEnabled, String reCaptchaType,
}

public Properties getSampleConfigFile() throws IOException {

Path path = Paths.get("src/test/resources", "repository", "conf", "identity",
CaptchaConstants.CAPTCHA_CONFIG_FILE_NAME);
Properties sampleProperties = new Properties();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,6 @@
# Enable Google reCAPTCHA
recaptcha.enabled=true

# Google reCAPTCHA type
recaptcha.type=default

# reCaptcha API URL
recaptcha.api.url=https://www.google.com/recaptcha/api.js

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ public class CaptchaConstants {
public static final String CAPTCHA_TOKEN_PROPERTIES = "tokenProperties";
public static final String CAPTCHA_RISK_ANALYSIS = "riskAnalysis";
// Captcha Types.
public static final String RE_CAPTCHA_TYPE_ENTERPRISE = "enterprise";
public static final String RE_CAPTCHA_TYPE_ENTERPRISE = "recaptcha-enterprise";

// Default value for threshold for score in reCAPTCHA v3.
public static final double CAPTCHA_V3_DEFAULT_THRESHOLD = 0.5;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,46 @@ public static Map<String, String> getClaimValues(User user, int tenantId,
return claimValues;
}

public static boolean isValidCaptcha(String reCaptchaResponse) throws CaptchaException {

CloseableHttpClient httpclient = HttpClientBuilder.create().useSystemProperties().build();
String reCaptchaType = CaptchaDataHolder.getInstance().getReCaptchaType();

HttpPost httpPost;

// If the reCaptcha type is defined and, it is enterprise, the enterprise process will be done. Otherwise,
// the reCaptcha v2/v3 process will be done.
if (CaptchaConstants.RE_CAPTCHA_TYPE_ENTERPRISE.equals(reCaptchaType)) {
// For ReCaptcha Enterprise.
httpPost = createReCaptchaEnterpriseVerificationHttpPost(reCaptchaResponse);
} else {
// For ReCaptcha v2 and v3.
httpPost = createReCaptchaVerificationHttpPost(reCaptchaResponse);
}

HttpResponse response;
try {
response = httpclient.execute(httpPost);
} catch (IOException e) {
throw new CaptchaServerException("Unable to get the verification response.", e);
}

HttpEntity entity = response.getEntity();
if (entity == null) {
throw new CaptchaServerException("reCaptcha verification response is not received.");
}

if (CaptchaConstants.RE_CAPTCHA_TYPE_ENTERPRISE.equals(reCaptchaType)) {
// For ReCaptcha Enterprise.
verifyReCaptchaEnterpriseResponse(entity);
} else {
// For Recaptcha v2 and v3.
verifyReCaptchaResponse(entity);
}

return true;
}

private static HttpPost createReCaptchaEnterpriseVerificationHttpPost(String reCaptchaResponse) {

HttpPost httpPost;
Expand Down Expand Up @@ -394,46 +434,6 @@ private static void verifyReCaptchaResponse(HttpEntity entity)
}
}

public static boolean isValidCaptcha(String reCaptchaResponse) throws CaptchaException {

CloseableHttpClient httpclient = HttpClientBuilder.create().useSystemProperties().build();
String reCaptchaType = CaptchaDataHolder.getInstance().getReCaptchaType();

HttpPost httpPost;

// If the reCaptcha type is defined and, it is enterprise, the enterprise process will be done. Otherwise,
// the reCaptcha v2/v3 process will be done.
if (CaptchaConstants.RE_CAPTCHA_TYPE_ENTERPRISE.equals(reCaptchaType)) {
// For ReCaptcha Enterprise.
httpPost = createReCaptchaEnterpriseVerificationHttpPost(reCaptchaResponse);
} else {
// For ReCaptcha v2 and v3.
httpPost = createReCaptchaVerificationHttpPost(reCaptchaResponse);
}

HttpResponse response;
try {
response = httpclient.execute(httpPost);
} catch (IOException e) {
throw new CaptchaServerException("Unable to get the verification response.", e);
}

HttpEntity entity = response.getEntity();
if (entity == null) {
throw new CaptchaServerException("reCaptcha verification response is not received.");
}

if (CaptchaConstants.RE_CAPTCHA_TYPE_ENTERPRISE.equals(reCaptchaType)) {
// For ReCaptcha Enterprise.
verifyReCaptchaEnterpriseResponse(entity);
} else {
// For Recaptcha v2 and v3.
verifyReCaptchaResponse(entity);
}

return true;
}

public static boolean isMaximumFailedLoginAttemptsReached(String usernameWithDomain, String tenantDomain) throws
CaptchaException {

Expand Down Expand Up @@ -578,7 +578,7 @@ private static void setReCaptchaConfigs(Properties properties) {
}
CaptchaDataHolder.getInstance().setReCaptchaAPIKey(reCaptchaAPIKey);
} else {
// Secret Key is only required if recaptcha enterprise is not enabled
// Secret Key is only required if recaptcha enterprise is not enabled.
String reCaptchaSecretKey = properties.getProperty(CaptchaConstants.RE_CAPTCHA_SECRET_KEY);
if (StringUtils.isBlank(reCaptchaSecretKey)) {
throw new RuntimeException(getValidationErrorMessage(CaptchaConstants.RE_CAPTCHA_SECRET_KEY));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.testng.Assert;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import org.wso2.carbon.identity.captcha.internal.CaptchaDataHolder;
Expand All @@ -32,7 +31,8 @@

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import static org.testng.Assert.*;

import static org.testng.Assert.assertThrows;

/**
* Unit tests for CaptchaUtil.java
Expand Down Expand Up @@ -109,8 +109,6 @@ public void testCreateReCaptchaEnterpriseVerificationHttpPost() throws NoSuchMet
CaptchaDataHolder.getInstance().setReCaptchaSiteKey("dummySiteKey");
CaptchaDataHolder.getInstance().setReCaptchaProjectID("dummyProjectId");



Method method = getCreateReCaptchaEnterpriseVerificationHttpPostMethod();
HttpPost httpPost = (HttpPost) method.invoke(null, "reCaptchaEnterpriseResponse");
String expectedURI = RECAPTCHA_ENTERPRISE_API_URL+ "/v1/projects/dummyProjectId/assessments?key=dummyKey";
Expand Down Expand Up @@ -145,7 +143,7 @@ public void testVerifyReCaptchaEnterpriseResponseWithHighScore() throws IOExcept
HttpEntity httpEntity = Mockito.mock(HttpEntity.class);
Mockito.when(httpEntity.getContent()).thenReturn(new ByteArrayInputStream(
verificationResponse.toString().getBytes()));
// verify no exception is thrown for high score
// Verify no exception is thrown for high score.
method.invoke(null, httpEntity);
}

Expand All @@ -160,7 +158,7 @@ public void testVerifyReCaptchaEnterpriseResponseWithLowScore() throws IOExcepti
HttpEntity httpEntity = Mockito.mock(HttpEntity.class);
Mockito.when(httpEntity.getContent()).thenReturn(new ByteArrayInputStream(verificationResponse.toString().
getBytes()));
// verify an exception is thrown for low score
// Verify an exception is thrown for low score.
assertThrows(InvocationTargetException.class, () -> method.invoke(null, httpEntity));
}

Expand All @@ -175,7 +173,7 @@ public void testVerifyReCaptchaEnterpriseResponseWithInvalidResponse() throws IO
HttpEntity httpEntity = Mockito.mock(HttpEntity.class);
Mockito.when(httpEntity.getContent()).thenReturn(new ByteArrayInputStream(verificationResponse.
toString().getBytes()));
// verify an exception is thrown for invalid response
// Verify an exception is thrown for invalid response.
assertThrows(InvocationTargetException.class, () -> method.invoke(null, httpEntity));
}

Expand All @@ -191,7 +189,7 @@ public void testVerifyReCaptchaResponseWithHighScore() throws IOException, NoSuc
HttpEntity httpEntity = Mockito.mock(HttpEntity.class);
Mockito.when(httpEntity.getContent()).thenReturn(new ByteArrayInputStream(verificationResponse.toString().
getBytes()));
// verify no exception is thrown for high score
// Verify no exception is thrown for high score.
method.invoke(null, httpEntity);
}

Expand All @@ -206,7 +204,7 @@ public void testVerifyReCaptchaResponseWithLowScore() throws IOException, NoSuch
HttpEntity httpEntity = Mockito.mock(HttpEntity.class);
Mockito.when(httpEntity.getContent()).thenReturn(new ByteArrayInputStream(verificationResponse.toString().
getBytes()));
// verify no exception is thrown for low score
// Verify no exception is thrown for low score.
assertThrows(InvocationTargetException.class, () -> method.invoke(null, httpEntity));
}

Expand All @@ -221,7 +219,7 @@ public void testVerifyReCaptchaResponseWithInvalidResponse() throws IOException,
HttpEntity httpEntity = Mockito.mock(HttpEntity.class);
Mockito.when(httpEntity.getContent()).thenReturn(new ByteArrayInputStream(verificationResponse.toString().
getBytes()));
// verify no exception is thrown for invalid response
// Verify no exception is thrown for invalid response.
assertThrows(InvocationTargetException.class, () -> method.invoke(null, httpEntity));
}
}

0 comments on commit 645e44c

Please sign in to comment.