diff --git a/components/org.wso2.carbon.identity.account.suspension.notification.task/pom.xml b/components/org.wso2.carbon.identity.account.suspension.notification.task/pom.xml
index bdcfa91d2a..c13dd2146f 100644
--- a/components/org.wso2.carbon.identity.account.suspension.notification.task/pom.xml
+++ b/components/org.wso2.carbon.identity.account.suspension.notification.task/pom.xml
@@ -20,7 +20,7 @@
identity-governance
org.wso2.carbon.identity.governance
- 1.8.67-SNAPSHOT
+ 1.8.68-SNAPSHOT
../../pom.xml
diff --git a/components/org.wso2.carbon.identity.api.user.governance/pom.xml b/components/org.wso2.carbon.identity.api.user.governance/pom.xml
index 019118e436..19a75be55f 100644
--- a/components/org.wso2.carbon.identity.api.user.governance/pom.xml
+++ b/components/org.wso2.carbon.identity.api.user.governance/pom.xml
@@ -23,12 +23,12 @@
org.wso2.carbon.identity.governance
identity-governance
- 1.8.67-SNAPSHOT
+ 1.8.68-SNAPSHOT
../..
org.wso2.carbon.identity.api.user.governance
- 1.8.67-SNAPSHOT
+ 1.8.68-SNAPSHOT
jar
WSO2 Carbon - User Rest Governance API
WSO2 Carbon - User Rest Governance API
diff --git a/components/org.wso2.carbon.identity.api.user.recovery/pom.xml b/components/org.wso2.carbon.identity.api.user.recovery/pom.xml
index 181f52210e..98ac3ad3db 100644
--- a/components/org.wso2.carbon.identity.api.user.recovery/pom.xml
+++ b/components/org.wso2.carbon.identity.api.user.recovery/pom.xml
@@ -23,12 +23,12 @@
org.wso2.carbon.identity.governance
identity-governance
- 1.8.67-SNAPSHOT
+ 1.8.68-SNAPSHOT
../..
org.wso2.carbon.identity.api.user.recovery
- 1.8.67-SNAPSHOT
+ 1.8.68-SNAPSHOT
jar
WSO2 Carbon - Identity Management Recovery Rest API
WSO2 Carbon - Identity Management Recovery Rest API
diff --git a/components/org.wso2.carbon.identity.api.user.recovery/src/gen/java/org/wso2/carbon/identity/recovery/endpoint/dto/ReCaptchaPropertiesDTO.java b/components/org.wso2.carbon.identity.api.user.recovery/src/gen/java/org/wso2/carbon/identity/recovery/endpoint/dto/ReCaptchaPropertiesDTO.java
index 1e3ca858cd..7172a0ab70 100644
--- a/components/org.wso2.carbon.identity.api.user.recovery/src/gen/java/org/wso2/carbon/identity/recovery/endpoint/dto/ReCaptchaPropertiesDTO.java
+++ b/components/org.wso2.carbon.identity.api.user.recovery/src/gen/java/org/wso2/carbon/identity/recovery/endpoint/dto/ReCaptchaPropertiesDTO.java
@@ -10,18 +10,21 @@
@ApiModel(description = "")
public class ReCaptchaPropertiesDTO {
-
-
-
+
+
+
private Boolean reCaptchaEnabled = null;
-
-
+
+
+ private String reCaptchaType = null;
+
+
private String reCaptchaKey = null;
-
-
+
+
private String reCaptchaAPI = null;
-
+
/**
**/
@ApiModelProperty(value = "")
@@ -33,7 +36,19 @@ public void setReCaptchaEnabled(Boolean reCaptchaEnabled) {
this.reCaptchaEnabled = reCaptchaEnabled;
}
-
+
+ /**
+ **/
+ @ApiModelProperty(value = "")
+ @JsonProperty("reCaptchaType")
+ public String getReCaptchaType() {
+ return reCaptchaType;
+ }
+ public void setReCaptchaType(String reCaptchaType) {
+ this.reCaptchaType = reCaptchaType;
+ }
+
+
/**
**/
@ApiModelProperty(value = "")
@@ -45,7 +60,7 @@ public void setReCaptchaKey(String reCaptchaKey) {
this.reCaptchaKey = reCaptchaKey;
}
-
+
/**
**/
@ApiModelProperty(value = "")
@@ -57,14 +72,15 @@ public void setReCaptchaAPI(String reCaptchaAPI) {
this.reCaptchaAPI = reCaptchaAPI;
}
-
+
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("class ReCaptchaPropertiesDTO {\n");
-
+
sb.append(" reCaptchaEnabled: ").append(reCaptchaEnabled).append("\n");
+ sb.append(" reCaptchaType: ").append(reCaptchaType).append("\n");
sb.append(" reCaptchaKey: ").append(reCaptchaKey).append("\n");
sb.append(" reCaptchaAPI: ").append(reCaptchaAPI).append("\n");
sb.append("}\n");
diff --git a/components/org.wso2.carbon.identity.api.user.recovery/src/main/java/org/wso2/carbon/identity/recovery/endpoint/Utils/RecoveryUtil.java b/components/org.wso2.carbon.identity.api.user.recovery/src/main/java/org/wso2/carbon/identity/recovery/endpoint/Utils/RecoveryUtil.java
index fd90f2821d..9d090d0801 100644
--- a/components/org.wso2.carbon.identity.api.user.recovery/src/main/java/org/wso2/carbon/identity/recovery/endpoint/Utils/RecoveryUtil.java
+++ b/components/org.wso2.carbon.identity.api.user.recovery/src/main/java/org/wso2/carbon/identity/recovery/endpoint/Utils/RecoveryUtil.java
@@ -452,6 +452,7 @@ public static Properties getValidatedCaptchaConfigs() {
private static Properties validateCaptchaConfigs(Properties properties) {
boolean reCaptchaEnabled = Boolean.valueOf(properties.getProperty(CaptchaConstants.RE_CAPTCHA_ENABLED));
+ String reCaptchaType = properties.getProperty(CaptchaConstants.RE_CAPTCHA_TYPE);
if (reCaptchaEnabled && StringUtils.isBlank(properties.getProperty(CaptchaConstants.RE_CAPTCHA_SITE_KEY))) {
RecoveryUtil.handleBadRequest(String.format("%s is not found ", CaptchaConstants.RE_CAPTCHA_SITE_KEY),
@@ -469,6 +470,12 @@ 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.
+ 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
+ .RE_CAPTCHA_PROJECT_ID), Constants.STATUS_INTERNAL_SERVER_ERROR_MESSAGE_DEFAULT);
+ }
return properties;
}
diff --git a/components/org.wso2.carbon.identity.api.user.recovery/src/main/java/org/wso2/carbon/identity/recovery/endpoint/impl/CaptchaApiServiceImpl.java b/components/org.wso2.carbon.identity.api.user.recovery/src/main/java/org/wso2/carbon/identity/recovery/endpoint/impl/CaptchaApiServiceImpl.java
index 3171ccb798..fd96ce7afa 100644
--- a/components/org.wso2.carbon.identity.api.user.recovery/src/main/java/org/wso2/carbon/identity/recovery/endpoint/impl/CaptchaApiServiceImpl.java
+++ b/components/org.wso2.carbon.identity.api.user.recovery/src/main/java/org/wso2/carbon/identity/recovery/endpoint/impl/CaptchaApiServiceImpl.java
@@ -42,7 +42,6 @@
*/
public class CaptchaApiServiceImpl extends CaptchaApiService {
- private static final String SUCCESS = "success";
private static final Log log = LogFactory.getLog(CaptchaApiServiceImpl.class);
private final String RECAPTCHA = "ReCaptcha";
@@ -64,11 +63,11 @@ public Response getCaptcha(String captchaType, String recoveryType, String tenan
reCaptchaPropertiesDTO.setReCaptchaEnabled(true);
reCaptchaPropertiesDTO.setReCaptchaKey(properties.getProperty(CaptchaConstants.RE_CAPTCHA_SITE_KEY));
reCaptchaPropertiesDTO.setReCaptchaAPI(properties.getProperty(CaptchaConstants.RE_CAPTCHA_API_URL));
- return Response.ok(reCaptchaPropertiesDTO).build();
+ reCaptchaPropertiesDTO.setReCaptchaType(properties.getProperty(CaptchaConstants.RE_CAPTCHA_TYPE));
} else {
reCaptchaPropertiesDTO.setReCaptchaEnabled(false);
- return Response.ok(reCaptchaPropertiesDTO).build();
}
+ return Response.ok(reCaptchaPropertiesDTO).build();
}
@Override
@@ -80,6 +79,7 @@ public Response verifyCaptcha(ReCaptchaResponseTokenDTO reCaptchaResponse, Strin
Properties properties = RecoveryUtil.getValidatedCaptchaConfigs();
boolean reCaptchaEnabled = Boolean.valueOf(properties.getProperty(CaptchaConstants.RE_CAPTCHA_ENABLED));
+ String reCaptchaType = properties.getProperty(CaptchaConstants.RE_CAPTCHA_TYPE);
if (!reCaptchaEnabled) {
RecoveryUtil.handleBadRequest("ReCaptcha is disabled", Constants.INVALID);
@@ -89,21 +89,30 @@ public Response verifyCaptcha(ReCaptchaResponseTokenDTO reCaptchaResponse, Strin
HttpEntity entity = response.getEntity();
ReCaptchaVerificationResponseDTO reCaptchaVerificationResponseDTO = new ReCaptchaVerificationResponseDTO();
- try {
- if (entity == null) {
- RecoveryUtil.handleBadRequest("ReCaptcha verification response is not received.",
- 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 {
- try (InputStream in = entity.getContent()) {
- JsonObject verificationResponse = new JsonParser().parse(IOUtils.toString(in)).getAsJsonObject();
- reCaptchaVerificationResponseDTO.setSuccess(verificationResponse.get(SUCCESS).getAsBoolean());
- }
+ // 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();
}
}
diff --git a/components/org.wso2.carbon.identity.api.user.recovery/src/main/resources/api.identity.recovery.yaml b/components/org.wso2.carbon.identity.api.user.recovery/src/main/resources/api.identity.recovery.yaml
index f32bf762e4..770c4c24d8 100644
--- a/components/org.wso2.carbon.identity.api.user.recovery/src/main/resources/api.identity.recovery.yaml
+++ b/components/org.wso2.carbon.identity.api.user.recovery/src/main/resources/api.identity.recovery.yaml
@@ -790,6 +790,8 @@ definitions:
properties:
reCaptchaEnabled:
type: boolean
+ reCaptchaType:
+ type: string
reCaptchaKey:
type: string
reCaptchaAPI:
diff --git a/components/org.wso2.carbon.identity.api.user.recovery/src/test/java/org/wso2/carbon/identity/recovery/endpoint/impl/CaptchaApiServiceImplTest.java b/components/org.wso2.carbon.identity.api.user.recovery/src/test/java/org/wso2/carbon/identity/recovery/endpoint/impl/CaptchaApiServiceImplTest.java
index 70088128a9..c78f19b42e 100644
--- a/components/org.wso2.carbon.identity.api.user.recovery/src/test/java/org/wso2/carbon/identity/recovery/endpoint/impl/CaptchaApiServiceImplTest.java
+++ b/components/org.wso2.carbon.identity.api.user.recovery/src/test/java/org/wso2/carbon/identity/recovery/endpoint/impl/CaptchaApiServiceImplTest.java
@@ -17,16 +17,18 @@
package org.wso2.carbon.identity.recovery.endpoint.impl;
+import org.apache.commons.lang.StringUtils;
import org.mockito.InjectMocks;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import org.wso2.carbon.identity.captcha.util.CaptchaConstants;
import org.wso2.carbon.identity.recovery.endpoint.Utils.RecoveryUtil;
-
+import org.wso2.carbon.identity.recovery.endpoint.dto.ReCaptchaPropertiesDTO;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
@@ -35,8 +37,9 @@
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Properties;
-
+import javax.ws.rs.core.Response;
import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNull;
/**
* Unit tests for CaptchaApiServiceImpl.java
@@ -61,8 +64,51 @@ public void tearDown() {
mockedRecoveryUtil.close();
}
- @Test(description = "This method test, getReCaptcha method for username recovery")
- public void testGetCaptcha() throws IOException {
+ @DataProvider(name = "captchaTestDataProvider")
+ public static Object[][] getCaptchaTestDataProvider() {
+
+ String reCaptchaEnterprise = CaptchaConstants.RE_CAPTCHA_TYPE_ENTERPRISE;
+
+ return new Object[][]{
+ {false, "", ""},
+ {true, "", "https://www.google.com/recaptcha/api.js"},
+ {true, reCaptchaEnterprise, "https://www.google.com/recaptcha/enterprise.js"}
+ };
+ }
+
+ @Test(description = "This method test, getReCaptcha method for username recovery",
+ dataProvider = "captchaTestDataProvider")
+ public void testGetCaptcha(boolean reCaptchaEnabled, String reCaptchaType,
+ String reCaptchaAPI) throws IOException {
+
+ Properties sampleProperties = getSampleConfigFile();
+
+ sampleProperties.setProperty(CaptchaConstants.RE_CAPTCHA_ENABLED, String.valueOf(reCaptchaEnabled));
+ sampleProperties.setProperty(CaptchaConstants.RE_CAPTCHA_TYPE, reCaptchaType);
+ sampleProperties.setProperty(CaptchaConstants.RE_CAPTCHA_API_URL, reCaptchaAPI);
+
+ mockedRecoveryUtil.when(RecoveryUtil::getValidatedCaptchaConfigs).thenReturn(sampleProperties);
+ mockedRecoveryUtil.when(() -> RecoveryUtil.checkCaptchaEnabledResidentIdpConfiguration(Mockito.anyString(),
+ Mockito.anyString())).thenReturn(true);
+ Response response = captchaApiService.getCaptcha("ReCaptcha", "username-recovery",
+ "test.org");
+
+ ReCaptchaPropertiesDTO reCaptchaPropertiesDTO = response.readEntity(ReCaptchaPropertiesDTO.class);
+
+ assertEquals(reCaptchaPropertiesDTO.getReCaptchaEnabled().booleanValue(), reCaptchaEnabled);
+ if (reCaptchaPropertiesDTO.getReCaptchaType() == null) {
+ assertNull(reCaptchaPropertiesDTO.getReCaptchaType());
+ } else {
+ assertEquals(reCaptchaPropertiesDTO.getReCaptchaType(), reCaptchaType);
+ }
+ if (StringUtils.isBlank(reCaptchaAPI)) {
+ assertNull(reCaptchaPropertiesDTO.getReCaptchaAPI());
+ } else {
+ assertEquals(reCaptchaPropertiesDTO.getReCaptchaAPI(), reCaptchaAPI);
+ }
+ }
+
+ public Properties getSampleConfigFile() throws IOException {
Path path = Paths.get("src/test/resources", "repository", "conf", "identity",
CaptchaConstants.CAPTCHA_CONFIG_FILE_NAME);
@@ -74,11 +120,6 @@ public void testGetCaptcha() throws IOException {
throw new IOException("Unable to read the captcha configuration file.", e);
}
}
-
- mockedRecoveryUtil.when(RecoveryUtil::getValidatedCaptchaConfigs).thenReturn(sampleProperties);
- mockedRecoveryUtil.when(() -> RecoveryUtil.checkCaptchaEnabledResidentIdpConfiguration(Mockito.anyString(),
- Mockito.anyString())).thenReturn(true);
- assertEquals(captchaApiService.getCaptcha("ReCaptcha", "username-recovery",
- null).getStatus(), 200);
+ return sampleProperties;
}
}
diff --git a/components/org.wso2.carbon.identity.auth.attribute.handler/pom.xml b/components/org.wso2.carbon.identity.auth.attribute.handler/pom.xml
index d0632232e5..a2f234dc75 100644
--- a/components/org.wso2.carbon.identity.auth.attribute.handler/pom.xml
+++ b/components/org.wso2.carbon.identity.auth.attribute.handler/pom.xml
@@ -22,7 +22,7 @@
org.wso2.carbon.identity.governance
identity-governance
- 1.8.67-SNAPSHOT
+ 1.8.68-SNAPSHOT
../../pom.xml
diff --git a/components/org.wso2.carbon.identity.captcha/pom.xml b/components/org.wso2.carbon.identity.captcha/pom.xml
index b6e342bd0b..d3e5b314c0 100644
--- a/components/org.wso2.carbon.identity.captcha/pom.xml
+++ b/components/org.wso2.carbon.identity.captcha/pom.xml
@@ -21,7 +21,7 @@
org.wso2.carbon.identity.governance
identity-governance
- 1.8.67-SNAPSHOT
+ 1.8.68-SNAPSHOT
../../pom.xml
@@ -114,6 +114,22 @@
org.wso2.securevault
org.wso2.securevault
+
+ org.testng
+ testng
+ test
+
+
+ org.jacoco
+ org.jacoco.agent
+ runtime
+ test
+
+
+ org.mockito
+ mockito-inline
+ test
+
@@ -185,6 +201,16 @@
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ ${maven.surefire.plugin.version}
+
+
+ src/test/resources/testng.xml
+
+
+
com.github.spotbugs
spotbugs-maven-plugin
diff --git a/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/internal/CaptchaDataHolder.java b/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/internal/CaptchaDataHolder.java
index 0ddf99ea64..f701657965 100644
--- a/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/internal/CaptchaDataHolder.java
+++ b/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/internal/CaptchaDataHolder.java
@@ -37,6 +37,8 @@ public class CaptchaDataHolder {
private boolean reCaptchaEnabled;
+ private String reCaptchaType;
+
private String reCaptchaAPIUrl;
private String reCaptchaVerifyUrl;
@@ -45,6 +47,10 @@ public class CaptchaDataHolder {
private String reCaptchaSecretKey;
+ private String reCaptchaAPIKey;
+
+ private String reCaptchaProjectID;
+
private String reCaptchaErrorRedirectUrls;
private String reCaptchaRequestWrapUrls;
@@ -84,6 +90,26 @@ public void setReCaptchaEnabled(boolean reCaptchaEnabled) {
this.reCaptchaEnabled = reCaptchaEnabled;
}
+ public String getReCaptchaType() {
+
+ return reCaptchaType;
+ }
+
+ public void setReCaptchaType(String reCaptchaType) {
+
+ this.reCaptchaType = reCaptchaType;
+ }
+
+ public String getReCaptchaProjectID() {
+
+ return reCaptchaProjectID;
+ }
+
+ public void setReCaptchaProjectID(String reCaptchaProjectID) {
+
+ this.reCaptchaProjectID = reCaptchaProjectID;
+ }
+
public String getReCaptchaAPIUrl() {
return reCaptchaAPIUrl;
}
@@ -116,6 +142,14 @@ public void setReCaptchaSecretKey(String reCaptchaSecretKey) {
this.reCaptchaSecretKey = reCaptchaSecretKey;
}
+ public String getReCaptchaAPIKey() {
+ return reCaptchaAPIKey;
+ }
+
+ public void setReCaptchaAPIKey(String reCaptchaAPIKey) {
+ this.reCaptchaAPIKey = reCaptchaAPIKey;
+ }
+
public String getReCaptchaRequestWrapUrls() {
return reCaptchaRequestWrapUrls;
}
diff --git a/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/util/CaptchaConstants.java b/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/util/CaptchaConstants.java
index 985ef64f7e..742865a234 100644
--- a/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/util/CaptchaConstants.java
+++ b/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/util/CaptchaConstants.java
@@ -34,6 +34,8 @@ public class CaptchaConstants {
public static final String RE_CAPTCHA_ENABLED = "recaptcha.enabled";
+ public static final String RE_CAPTCHA_TYPE = "recaptcha.type";
+
public static final String FORCEFULLY_ENABLED_RECAPTCHA_FOR_ALL_TENANTS = "recaptcha" +
".forcefullyEnabledForAllTenants";
@@ -43,8 +45,12 @@ public class CaptchaConstants {
public static final String RE_CAPTCHA_SITE_KEY = "recaptcha.site.key";
+ public static final String RE_CAPTCHA_PROJECT_ID = "recaptcha.project.id";
+
public static final String RE_CAPTCHA_SECRET_KEY = "recaptcha.secret.key";
+ public static final String RE_CAPTCHA_API_KEY = "recaptcha.api.key";
+
public static final String RE_CAPTCHA_REQUEST_WRAP_URLS = "recaptcha.request.wrap.urls";
public static final String FAIL_LOGIN_ATTEMPT_VALIDATOR_ENABLED = "failLoginAttemptValidator.enable";
@@ -66,6 +72,11 @@ public class CaptchaConstants {
public static final String AUTH_FAILURE_MSG = "authFailureMsg";
public static final String RECAPTCHA_FAIL_MSG_KEY = "recaptcha.fail.message";
public static final String TRUE = "true";
+ public static final String CAPTCHA_VALID = "valid";
+ 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 = "recaptcha-enterprise";
// Default value for threshold for score in reCAPTCHA v3.
public static final double CAPTCHA_V3_DEFAULT_THRESHOLD = 0.5;
diff --git a/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/util/CaptchaUtil.java b/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/util/CaptchaUtil.java
index 85e30c76e7..8162079049 100644
--- a/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/util/CaptchaUtil.java
+++ b/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/util/CaptchaUtil.java
@@ -18,17 +18,19 @@
package org.wso2.carbon.identity.captcha.util;
+import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import org.apache.commons.collections.MapUtils;
-import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.math.NumberUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.HttpEntity;
+import org.apache.http.HttpHeaders;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
+import org.apache.http.entity.StringEntity;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
@@ -272,16 +274,23 @@ public static Map getClaimValues(User user, int tenantId,
public static boolean isValidCaptcha(String reCaptchaResponse) throws CaptchaException {
CloseableHttpClient httpclient = HttpClientBuilder.create().useSystemProperties().build();
- HttpPost httppost = new HttpPost(CaptchaDataHolder.getInstance().getReCaptchaVerifyUrl());
- final double scoreThreshold = CaptchaDataHolder.getInstance().getReCaptchaScoreThreshold();
+ String reCaptchaType = CaptchaDataHolder.getInstance().getReCaptchaType();
- List params = Arrays.asList(new BasicNameValuePair("secret", CaptchaDataHolder
- .getInstance().getReCaptchaSecretKey()), new BasicNameValuePair("response", reCaptchaResponse));
- httppost.setEntity(new UrlEncodedFormEntity(params, StandardCharsets.UTF_8));
+ 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);
+ response = httpclient.execute(httpPost);
} catch (IOException e) {
throw new CaptchaServerException("Unable to get the verification response.", e);
}
@@ -291,14 +300,109 @@ public static boolean isValidCaptcha(String reCaptchaResponse) throws CaptchaExc
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;
+ String recaptchaUrl = CaptchaDataHolder.getInstance().getReCaptchaVerifyUrl();
+ String projectID = CaptchaDataHolder.getInstance().getReCaptchaProjectID();
+ String siteKey = CaptchaDataHolder.getInstance().getReCaptchaSiteKey();
+ String apiKey = CaptchaDataHolder.getInstance().getReCaptchaAPIKey();
+
+ String verifyUrl = recaptchaUrl + "/v1/projects/" + projectID + "/assessments?key=" + apiKey;
+ httpPost = new HttpPost(verifyUrl);
+
+ httpPost.setHeader(HttpHeaders.CONTENT_TYPE, "application/json");
+
+ String json = String.format("{ \"event\": { \"token\": \"%s\", \"siteKey\": \"%s\" } }", reCaptchaResponse,
+ siteKey);
+
+ StringEntity entity = new StringEntity(json, StandardCharsets.UTF_8);
+
+ httpPost.setEntity(entity);
+
+ return httpPost;
+ }
+
+ private static HttpPost createReCaptchaVerificationHttpPost(String reCaptchaResponse) {
+
+ HttpPost httpPost;
+ httpPost = new HttpPost(CaptchaDataHolder.getInstance().getReCaptchaVerifyUrl());
+ List params = Arrays.asList(new BasicNameValuePair("secret", CaptchaDataHolder
+ .getInstance().getReCaptchaSecretKey()),
+ new BasicNameValuePair("response", reCaptchaResponse));
+ httpPost.setEntity(new UrlEncodedFormEntity(params, StandardCharsets.UTF_8));
+
+ return httpPost;
+ }
+
+ private static void verifyReCaptchaEnterpriseResponse(HttpEntity entity)
+ throws CaptchaServerException, CaptchaClientException {
+
+ final double scoreThreshold = CaptchaDataHolder.getInstance().getReCaptchaScoreThreshold();
+
try {
try (InputStream in = entity.getContent()) {
- JsonObject verificationResponse = new JsonParser().parse(IOUtils.toString(in)).getAsJsonObject();
+ JsonElement jsonElement = JsonParser.parseReader(new InputStreamReader(in, StandardCharsets.UTF_8));
+ JsonObject verificationResponse = jsonElement.getAsJsonObject();
if (verificationResponse == null) {
throw new CaptchaClientException("Error receiving reCaptcha response from the server");
}
- boolean success = verificationResponse.get(CaptchaConstants.CAPTCHA_SUCCESS) != null
- && verificationResponse.get(CaptchaConstants.CAPTCHA_SUCCESS).getAsBoolean();
+ JsonObject tokenProperties = verificationResponse.get(CaptchaConstants.CAPTCHA_TOKEN_PROPERTIES).
+ getAsJsonObject();
+ boolean success = tokenProperties.get(CaptchaConstants.CAPTCHA_VALID).getAsBoolean();
+
+ JsonObject riskAnalysis = verificationResponse.get(CaptchaConstants.CAPTCHA_RISK_ANALYSIS).
+ getAsJsonObject();
+
+ // Whether this request was a valid reCAPTCHA token.
+ if (!success) {
+ throw new CaptchaClientException("reCaptcha token is invalid. Error:" +
+ verificationResponse.get("error-codes"));
+ }
+ if (riskAnalysis.get(CaptchaConstants.CAPTCHA_SCORE) != null) {
+ double score = riskAnalysis.get(CaptchaConstants.CAPTCHA_SCORE).getAsDouble();
+ // reCAPTCHA enterprise response contains score.
+ if (log.isDebugEnabled()) {
+ log.debug("reCAPTCHA Enterprise response { timestamp:" +
+ tokenProperties.get("createTime") + ", action: " +
+ tokenProperties.get("action") + ", score: " + score + " }");
+ }
+ if (score < scoreThreshold) {
+ throw new CaptchaClientException("reCaptcha score is less than the threshold.");
+ }
+ }
+ }
+ } catch (IOException e) {
+ throw new CaptchaServerException("Unable to read the verification response.", e);
+ } catch (ClassCastException e) {
+ throw new CaptchaServerException("Unable to cast the response value.", e);
+ }
+ }
+
+ private static void verifyReCaptchaResponse(HttpEntity entity)
+ throws CaptchaServerException, CaptchaClientException {
+
+ final double scoreThreshold = CaptchaDataHolder.getInstance().getReCaptchaScoreThreshold();
+
+ try {
+ try (InputStream in = entity.getContent()) {
+ JsonElement jsonElement = JsonParser.parseReader(new InputStreamReader(in, StandardCharsets.UTF_8));
+ JsonObject verificationResponse = jsonElement.getAsJsonObject();
+ if (verificationResponse == null) {
+ throw new CaptchaClientException("Error receiving reCaptcha response from the server");
+ }
+ boolean success = verificationResponse.get(CaptchaConstants.CAPTCHA_SUCCESS).getAsBoolean();
// Whether this request was a valid reCAPTCHA token.
if (!success) {
throw new CaptchaClientException("reCaptcha token is invalid. Error:" +
@@ -306,7 +410,7 @@ public static boolean isValidCaptcha(String reCaptchaResponse) throws CaptchaExc
}
if (verificationResponse.get(CaptchaConstants.CAPTCHA_SCORE) != null) {
double score = verificationResponse.get(CaptchaConstants.CAPTCHA_SCORE).getAsDouble();
- // reCAPTCHA v3 response contains score
+ // reCAPTCHA v3 response contains score.
if (log.isDebugEnabled()) {
log.debug("reCAPTCHA v3 response { timestamp:" +
verificationResponse.get("challenge_ts") + ", action: " +
@@ -327,8 +431,6 @@ public static boolean isValidCaptcha(String reCaptchaResponse) throws CaptchaExc
} catch (ClassCastException e) {
throw new CaptchaServerException("Unable to cast the response value.", e);
}
-
- return true;
}
public static boolean isMaximumFailedLoginAttemptsReached(String usernameWithDomain, String tenantDomain) throws
@@ -456,6 +558,33 @@ private static UserStoreManager getUserStoreManagerForUser(String userName,
private static void setReCaptchaConfigs(Properties properties) {
+ String reCaptchaType = properties.getProperty(CaptchaConstants.RE_CAPTCHA_TYPE);
+ if (!StringUtils.isBlank(reCaptchaType)) {
+ CaptchaDataHolder.getInstance().setReCaptchaType(reCaptchaType);
+ }
+
+ if (CaptchaConstants.RE_CAPTCHA_TYPE_ENTERPRISE.equals(reCaptchaType)) {
+ // ReCaptcha Enterprise require Project ID.
+ String reCaptchaProjectID = properties.getProperty(CaptchaConstants.RE_CAPTCHA_PROJECT_ID);
+ if (StringUtils.isBlank(reCaptchaProjectID)) {
+ throw new RuntimeException(getValidationErrorMessage(CaptchaConstants.RE_CAPTCHA_PROJECT_ID));
+ }
+ CaptchaDataHolder.getInstance().setReCaptchaProjectID(reCaptchaProjectID);
+
+ String reCaptchaAPIKey = properties.getProperty(CaptchaConstants.RE_CAPTCHA_API_KEY);
+ if (StringUtils.isBlank(reCaptchaAPIKey)) {
+ throw new RuntimeException(getValidationErrorMessage(CaptchaConstants.RE_CAPTCHA_API_KEY));
+ }
+ CaptchaDataHolder.getInstance().setReCaptchaAPIKey(reCaptchaAPIKey);
+ } else {
+ // 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));
+ }
+ CaptchaDataHolder.getInstance().setReCaptchaSecretKey(reCaptchaSecretKey);
+ }
+
String reCaptchaAPIUrl = properties.getProperty(CaptchaConstants.RE_CAPTCHA_API_URL);
if (StringUtils.isBlank(reCaptchaAPIUrl)) {
throw new RuntimeException(getValidationErrorMessage(CaptchaConstants.RE_CAPTCHA_API_URL));
@@ -474,12 +603,6 @@ private static void setReCaptchaConfigs(Properties properties) {
}
CaptchaDataHolder.getInstance().setReCaptchaSiteKey(reCaptchaSiteKey);
- String reCaptchaSecretKey = properties.getProperty(CaptchaConstants.RE_CAPTCHA_SECRET_KEY);
- if (StringUtils.isBlank(reCaptchaSecretKey)) {
- throw new RuntimeException(getValidationErrorMessage(CaptchaConstants.RE_CAPTCHA_SECRET_KEY));
- }
- CaptchaDataHolder.getInstance().setReCaptchaSecretKey(reCaptchaSecretKey);
-
String reCaptchaRequestWrapUrls = properties.getProperty(CaptchaConstants.RE_CAPTCHA_REQUEST_WRAP_URLS);
if (reCaptchaRequestWrapUrls == null) {
throw new RuntimeException(getValidationErrorMessage(CaptchaConstants.RE_CAPTCHA_REQUEST_WRAP_URLS));
@@ -692,6 +815,15 @@ public static Boolean isReCaptchaEnabled() {
return CaptchaDataHolder.getInstance().isReCaptchaEnabled();
}
+ /**
+ * Get the ReCaptcha Type.
+ * @return ReCaptcha Type as a String.
+ */
+ public static String getReCaptchaType() {
+
+ return CaptchaDataHolder.getInstance().getReCaptchaType();
+ }
+
/**
* Check whether ReCaptcha is forcefully enabled for all tenants.
*
diff --git a/components/org.wso2.carbon.identity.captcha/src/test/java/org/wso2/carbon/identity/captcha/util/CaptchaUtilTest.java b/components/org.wso2.carbon.identity.captcha/src/test/java/org/wso2/carbon/identity/captcha/util/CaptchaUtilTest.java
new file mode 100644
index 0000000000..0a8083d3c4
--- /dev/null
+++ b/components/org.wso2.carbon.identity.captcha/src/test/java/org/wso2/carbon/identity/captcha/util/CaptchaUtilTest.java
@@ -0,0 +1,225 @@
+/*
+ * Copyright (c) 2023, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * Licensed 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.wso2.carbon.identity.captcha.util;
+
+import com.google.gson.JsonObject;
+import org.apache.http.HttpEntity;
+import org.apache.http.client.methods.HttpPost;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.testng.Assert;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+import org.wso2.carbon.identity.captcha.internal.CaptchaDataHolder;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import static org.testng.Assert.assertThrows;
+
+/**
+ * Unit tests for CaptchaUtil.java
+ */
+public class CaptchaUtilTest {
+
+ private final String RECAPTCHA_API_URL = "https://www.google.com/recaptcha/api/siteverify";
+ private final String RECAPTCHA_ENTERPRISE_API_URL = "https://recaptchaenterprise.googleapis.com";
+
+ @BeforeMethod
+ public void setUp() {
+
+ MockitoAnnotations.openMocks(this);
+ }
+
+ private Method getCreateReCaptchaEnterpriseVerificationHttpPostMethod() throws NoSuchMethodException {
+
+ Method method = CaptchaUtil.class.getDeclaredMethod("createReCaptchaEnterpriseVerificationHttpPost",
+ String.class);
+ method.setAccessible(true);
+ return method;
+ }
+
+ private Method getCreateReCaptchaVerificationHttpPostMethod() throws NoSuchMethodException {
+
+ Method method = CaptchaUtil.class.getDeclaredMethod("createReCaptchaVerificationHttpPost",
+ String.class);
+ method.setAccessible(true);
+ return method;
+ }
+
+ private Method getVerifyReCaptchaEnterpriseResponseMethod() throws NoSuchMethodException {
+
+ Method method = CaptchaUtil.class.getDeclaredMethod("verifyReCaptchaEnterpriseResponse",
+ HttpEntity.class);
+ method.setAccessible(true);
+ return method;
+ }
+
+ private Method getVerifyReCaptchaResponseMethod() throws NoSuchMethodException {
+
+ Method method = CaptchaUtil.class.getDeclaredMethod("verifyReCaptchaResponse",
+ HttpEntity.class);
+ method.setAccessible(true);
+ return method;
+ }
+
+ private JsonObject getReCaptchaEnterpriseJsonObject(boolean valid, double score) {
+
+ JsonObject verificationResponse = new JsonObject();
+ JsonObject tokenProperties = new JsonObject();
+ tokenProperties.addProperty(CaptchaConstants.CAPTCHA_VALID, valid);
+ verificationResponse.add(CaptchaConstants.CAPTCHA_TOKEN_PROPERTIES, tokenProperties);
+ JsonObject riskAnalysis = new JsonObject();
+ riskAnalysis.addProperty(CaptchaConstants.CAPTCHA_SCORE, score);
+ verificationResponse.add(CaptchaConstants.CAPTCHA_RISK_ANALYSIS, riskAnalysis);
+ return verificationResponse;
+ }
+
+ private JsonObject getReCaptchaJsonObject(boolean valid, double score) {
+
+ JsonObject verificationResponse = new JsonObject();
+ verificationResponse.addProperty(CaptchaConstants.CAPTCHA_SUCCESS, valid);
+ verificationResponse.addProperty(CaptchaConstants.CAPTCHA_SCORE, score);
+ return verificationResponse;
+ }
+
+ @Test (description = "This method is used to test the createReCaptchaEnterpriseVerificationHttpPost method")
+ public void testCreateReCaptchaEnterpriseVerificationHttpPost() throws NoSuchMethodException,
+ InvocationTargetException, IllegalAccessException {
+
+ CaptchaDataHolder.getInstance().setReCaptchaVerifyUrl(RECAPTCHA_ENTERPRISE_API_URL);
+ CaptchaDataHolder.getInstance().setReCaptchaAPIKey("dummyKey");
+ 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";
+ Assert.assertEquals(httpPost.getURI().toString(), expectedURI);
+
+ }
+
+ @Test (description = "This method is used to test the createReCaptchaEnterpriseVerificationHttpPost method")
+ public void testCreateReCaptchaVerificationHttpPost() throws NoSuchMethodException,
+ InvocationTargetException, IllegalAccessException {
+
+ CaptchaDataHolder.getInstance().setReCaptchaVerifyUrl(RECAPTCHA_API_URL);
+ CaptchaDataHolder.getInstance().setReCaptchaSecretKey("dummyKey");
+ CaptchaDataHolder.getInstance().setReCaptchaSiteKey("dummySiteKey");
+ CaptchaDataHolder.getInstance().setReCaptchaProjectID("dummyProjectId");
+
+ Method method = getCreateReCaptchaVerificationHttpPostMethod();
+ HttpPost httpPost = (HttpPost) method.invoke(null, "reCaptchaEnterpriseResponse");
+ Assert.assertEquals(httpPost.getURI().toString(), RECAPTCHA_API_URL);
+ }
+
+
+ @Test (description = "This method is used to test the verifyReCaptchaEnterpriseResponse method, " +
+ "with high captcha score")
+ public void testVerifyReCaptchaEnterpriseResponseWithHighScore() throws IOException, NoSuchMethodException,
+ InvocationTargetException, IllegalAccessException {
+
+ CaptchaDataHolder.getInstance().setReCaptchaScoreThreshold(CaptchaConstants.CAPTCHA_V3_DEFAULT_THRESHOLD);
+
+ JsonObject verificationResponse = getReCaptchaEnterpriseJsonObject(true, 0.7);
+ Method method = getVerifyReCaptchaEnterpriseResponseMethod();
+ HttpEntity httpEntity = Mockito.mock(HttpEntity.class);
+ Mockito.when(httpEntity.getContent()).thenReturn(new ByteArrayInputStream(
+ verificationResponse.toString().getBytes()));
+ // Verify no exception is thrown for high score.
+ method.invoke(null, httpEntity);
+ }
+
+ @Test (description = "This method is used to test the verifyReCaptchaEnterpriseResponse method, " +
+ "with low captcha score")
+ public void testVerifyReCaptchaEnterpriseResponseWithLowScore() throws IOException, NoSuchMethodException {
+
+ CaptchaDataHolder.getInstance().setReCaptchaScoreThreshold(CaptchaConstants.CAPTCHA_V3_DEFAULT_THRESHOLD);
+
+ JsonObject verificationResponse = getReCaptchaEnterpriseJsonObject(true, 0.4);
+ Method method = getVerifyReCaptchaEnterpriseResponseMethod();
+ HttpEntity httpEntity = Mockito.mock(HttpEntity.class);
+ Mockito.when(httpEntity.getContent()).thenReturn(new ByteArrayInputStream(verificationResponse.toString().
+ getBytes()));
+ // Verify an exception is thrown for low score.
+ assertThrows(InvocationTargetException.class, () -> method.invoke(null, httpEntity));
+ }
+
+ @Test (description = "This method is used to test the verifyReCaptchaEnterpriseResponse method, " +
+ "with invalid response")
+ public void testVerifyReCaptchaEnterpriseResponseWithInvalidResponse() throws IOException, NoSuchMethodException {
+
+ CaptchaDataHolder.getInstance().setReCaptchaScoreThreshold(CaptchaConstants.CAPTCHA_V3_DEFAULT_THRESHOLD);
+
+ JsonObject verificationResponse = getReCaptchaEnterpriseJsonObject(false, 0.7);
+ Method method = getVerifyReCaptchaEnterpriseResponseMethod();
+ HttpEntity httpEntity = Mockito.mock(HttpEntity.class);
+ Mockito.when(httpEntity.getContent()).thenReturn(new ByteArrayInputStream(verificationResponse.
+ toString().getBytes()));
+ // Verify an exception is thrown for invalid response.
+ assertThrows(InvocationTargetException.class, () -> method.invoke(null, httpEntity));
+ }
+
+ @Test (description = "This method is used to test the verifyReCaptchaResponse method, " +
+ "with high captcha score")
+ public void testVerifyReCaptchaResponseWithHighScore() throws IOException, NoSuchMethodException,
+ InvocationTargetException, IllegalAccessException {
+
+ CaptchaDataHolder.getInstance().setReCaptchaScoreThreshold(CaptchaConstants.CAPTCHA_V3_DEFAULT_THRESHOLD);
+
+ JsonObject verificationResponse = getReCaptchaJsonObject(true, 0.7);
+ Method method = getVerifyReCaptchaResponseMethod();
+ HttpEntity httpEntity = Mockito.mock(HttpEntity.class);
+ Mockito.when(httpEntity.getContent()).thenReturn(new ByteArrayInputStream(verificationResponse.toString().
+ getBytes()));
+ // Verify no exception is thrown for high score.
+ method.invoke(null, httpEntity);
+ }
+
+ @Test (description = "This method is used to test the verifyReCaptchaResponse method, " +
+ "with low captcha score")
+ public void testVerifyReCaptchaResponseWithLowScore() throws IOException, NoSuchMethodException {
+
+ CaptchaDataHolder.getInstance().setReCaptchaScoreThreshold(CaptchaConstants.CAPTCHA_V3_DEFAULT_THRESHOLD);
+
+ JsonObject verificationResponse = getReCaptchaJsonObject(true, 0.4);
+ Method method = getVerifyReCaptchaResponseMethod();
+ HttpEntity httpEntity = Mockito.mock(HttpEntity.class);
+ Mockito.when(httpEntity.getContent()).thenReturn(new ByteArrayInputStream(verificationResponse.toString().
+ getBytes()));
+ // Verify no exception is thrown for low score.
+ assertThrows(InvocationTargetException.class, () -> method.invoke(null, httpEntity));
+ }
+
+ @Test (description = "This method is used to test the verifyReCaptchaResponse method, " +
+ "with invalid response")
+ public void testVerifyReCaptchaResponseWithInvalidResponse() throws IOException, NoSuchMethodException {
+
+ CaptchaDataHolder.getInstance().setReCaptchaScoreThreshold(CaptchaConstants.CAPTCHA_V3_DEFAULT_THRESHOLD);
+
+ JsonObject verificationResponse = getReCaptchaJsonObject(false, 0.7);
+ Method method = getVerifyReCaptchaResponseMethod();
+ HttpEntity httpEntity = Mockito.mock(HttpEntity.class);
+ Mockito.when(httpEntity.getContent()).thenReturn(new ByteArrayInputStream(verificationResponse.toString().
+ getBytes()));
+ // Verify no exception is thrown for invalid response.
+ assertThrows(InvocationTargetException.class, () -> method.invoke(null, httpEntity));
+ }
+}
diff --git a/components/org.wso2.carbon.identity.captcha/src/test/resources/testng.xml b/components/org.wso2.carbon.identity.captcha/src/test/resources/testng.xml
new file mode 100644
index 0000000000..dc33af0505
--- /dev/null
+++ b/components/org.wso2.carbon.identity.captcha/src/test/resources/testng.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/components/org.wso2.carbon.identity.governance/pom.xml b/components/org.wso2.carbon.identity.governance/pom.xml
index 3bfdb2b6d4..b618d5c55d 100644
--- a/components/org.wso2.carbon.identity.governance/pom.xml
+++ b/components/org.wso2.carbon.identity.governance/pom.xml
@@ -18,7 +18,7 @@
org.wso2.carbon.identity.governance
identity-governance
- 1.8.67-SNAPSHOT
+ 1.8.68-SNAPSHOT
../../pom.xml
diff --git a/components/org.wso2.carbon.identity.idle.account.identification/pom.xml b/components/org.wso2.carbon.identity.idle.account.identification/pom.xml
index b29c53a5c7..f34b93c6f3 100644
--- a/components/org.wso2.carbon.identity.idle.account.identification/pom.xml
+++ b/components/org.wso2.carbon.identity.idle.account.identification/pom.xml
@@ -18,7 +18,7 @@
identity-governance
org.wso2.carbon.identity.governance
- 1.8.67-SNAPSHOT
+ 1.8.68-SNAPSHOT
../../pom.xml
4.0.0
diff --git a/components/org.wso2.carbon.identity.multi.attribute.login/org.wso2.carbon.identity.multi.attribute.login.resolver.regex/pom.xml b/components/org.wso2.carbon.identity.multi.attribute.login/org.wso2.carbon.identity.multi.attribute.login.resolver.regex/pom.xml
index e3059753a1..5477c4af57 100644
--- a/components/org.wso2.carbon.identity.multi.attribute.login/org.wso2.carbon.identity.multi.attribute.login.resolver.regex/pom.xml
+++ b/components/org.wso2.carbon.identity.multi.attribute.login/org.wso2.carbon.identity.multi.attribute.login.resolver.regex/pom.xml
@@ -21,7 +21,7 @@
identity-governance
org.wso2.carbon.identity.governance
- 1.8.67-SNAPSHOT
+ 1.8.68-SNAPSHOT
../../../pom.xml
4.0.0
diff --git a/components/org.wso2.carbon.identity.multi.attribute.login/org.wso2.carbon.identity.multi.attribute.login.service/pom.xml b/components/org.wso2.carbon.identity.multi.attribute.login/org.wso2.carbon.identity.multi.attribute.login.service/pom.xml
index 040adddfa7..0f3f9b1e9f 100644
--- a/components/org.wso2.carbon.identity.multi.attribute.login/org.wso2.carbon.identity.multi.attribute.login.service/pom.xml
+++ b/components/org.wso2.carbon.identity.multi.attribute.login/org.wso2.carbon.identity.multi.attribute.login.service/pom.xml
@@ -21,7 +21,7 @@
identity-governance
org.wso2.carbon.identity.governance
- 1.8.67-SNAPSHOT
+ 1.8.68-SNAPSHOT
../../../pom.xml
4.0.0
diff --git a/components/org.wso2.carbon.identity.multi.attribute.login/pom.xml b/components/org.wso2.carbon.identity.multi.attribute.login/pom.xml
index cf4de86c55..dd1fcffa28 100644
--- a/components/org.wso2.carbon.identity.multi.attribute.login/pom.xml
+++ b/components/org.wso2.carbon.identity.multi.attribute.login/pom.xml
@@ -21,7 +21,7 @@
identity-governance
org.wso2.carbon.identity.governance
- 1.8.67-SNAPSHOT
+ 1.8.68-SNAPSHOT
../../pom.xml
4.0.0
diff --git a/components/org.wso2.carbon.identity.password.expiry/pom.xml b/components/org.wso2.carbon.identity.password.expiry/pom.xml
index 665cf57f83..1d8470daae 100644
--- a/components/org.wso2.carbon.identity.password.expiry/pom.xml
+++ b/components/org.wso2.carbon.identity.password.expiry/pom.xml
@@ -20,7 +20,7 @@
org.wso2.carbon.identity.governance
identity-governance
- 1.8.67-SNAPSHOT
+ 1.8.68-SNAPSHOT
../../pom.xml
diff --git a/components/org.wso2.carbon.identity.password.history/pom.xml b/components/org.wso2.carbon.identity.password.history/pom.xml
index 67d072ba13..d7a93d2aef 100644
--- a/components/org.wso2.carbon.identity.password.history/pom.xml
+++ b/components/org.wso2.carbon.identity.password.history/pom.xml
@@ -18,7 +18,7 @@
org.wso2.carbon.identity.governance
identity-governance
- 1.8.67-SNAPSHOT
+ 1.8.68-SNAPSHOT
../../pom.xml
diff --git a/components/org.wso2.carbon.identity.password.policy/pom.xml b/components/org.wso2.carbon.identity.password.policy/pom.xml
index f144af7828..3a7d07427e 100644
--- a/components/org.wso2.carbon.identity.password.policy/pom.xml
+++ b/components/org.wso2.carbon.identity.password.policy/pom.xml
@@ -18,7 +18,7 @@
org.wso2.carbon.identity.governance
identity-governance
- 1.8.67-SNAPSHOT
+ 1.8.68-SNAPSHOT
../../pom.xml
diff --git a/components/org.wso2.carbon.identity.password.policy/src/main/java/org/wso2/carbon/identity/password/policy/constants/PasswordPolicyConstants.java b/components/org.wso2.carbon.identity.password.policy/src/main/java/org/wso2/carbon/identity/password/policy/constants/PasswordPolicyConstants.java
index 7bfbe740fc..25ce59e216 100644
--- a/components/org.wso2.carbon.identity.password.policy/src/main/java/org/wso2/carbon/identity/password/policy/constants/PasswordPolicyConstants.java
+++ b/components/org.wso2.carbon.identity.password.policy/src/main/java/org/wso2/carbon/identity/password/policy/constants/PasswordPolicyConstants.java
@@ -26,6 +26,7 @@ public class PasswordPolicyConstants {
public static final String PW_POLICY_LENGTH_CLASS = "passwordPolicy.class.PasswordLengthPolicy";
public static final String PW_POLICY_NAME_CLASS = "passwordPolicy.class.PasswordNamePolicy";
public static final String PW_POLICY_PATTERN_CLASS = "passwordPolicy.class.PasswordPatternPolicy";
+ public static final String PW_POLICY_HANDLER_ENABLED = "PasswordPolicy.PasswordPolicyValidationHandler.Enable";
public enum ErrorMessages {
diff --git a/components/org.wso2.carbon.identity.password.policy/src/main/java/org/wso2/carbon/identity/password/policy/handler/PasswordPolicyValidationHandler.java b/components/org.wso2.carbon.identity.password.policy/src/main/java/org/wso2/carbon/identity/password/policy/handler/PasswordPolicyValidationHandler.java
index 7a34f02f00..f31fefdd28 100644
--- a/components/org.wso2.carbon.identity.password.policy/src/main/java/org/wso2/carbon/identity/password/policy/handler/PasswordPolicyValidationHandler.java
+++ b/components/org.wso2.carbon.identity.password.policy/src/main/java/org/wso2/carbon/identity/password/policy/handler/PasswordPolicyValidationHandler.java
@@ -232,8 +232,6 @@ public Map getPropertyDescriptionMapping() {
public void init(InitConfig configuration) throws IdentityRuntimeException {
super.init(configuration);
- IdentityPasswordPolicyServiceDataHolder.getInstance().getBundleContext().registerService
- (IdentityConnectorConfig.class.getName(), this, null);
}
public String[] getPropertyNames() {
diff --git a/components/org.wso2.carbon.identity.password.policy/src/main/java/org/wso2/carbon/identity/password/policy/internal/IdentityPasswordPolicyServiceComponent.java b/components/org.wso2.carbon.identity.password.policy/src/main/java/org/wso2/carbon/identity/password/policy/internal/IdentityPasswordPolicyServiceComponent.java
index abacfe7821..63fc3e21a8 100644
--- a/components/org.wso2.carbon.identity.password.policy/src/main/java/org/wso2/carbon/identity/password/policy/internal/IdentityPasswordPolicyServiceComponent.java
+++ b/components/org.wso2.carbon.identity.password.policy/src/main/java/org/wso2/carbon/identity/password/policy/internal/IdentityPasswordPolicyServiceComponent.java
@@ -21,6 +21,7 @@
import org.osgi.service.component.ComponentContext;
import org.wso2.carbon.identity.event.handler.AbstractEventHandler;
import org.wso2.carbon.identity.governance.IdentityGovernanceService;
+import org.wso2.carbon.identity.governance.common.IdentityConnectorConfig;
import org.wso2.carbon.identity.password.policy.handler.PasswordPolicyValidationHandler;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
@@ -45,8 +46,16 @@ protected void activate(ComponentContext context) {
}
BundleContext bundleContext = context.getBundleContext();
IdentityPasswordPolicyServiceDataHolder.getInstance().setBundleContext(bundleContext);
- PasswordPolicyValidationHandler handler = new PasswordPolicyValidationHandler();
- context.getBundleContext().registerService(AbstractEventHandler.class.getName(), handler, null);
+ if (IdentityPasswordPolicyServiceDataHolder.getInstance().isPasswordPolicyHandlerEnabled()) {
+
+ PasswordPolicyValidationHandler handler = new PasswordPolicyValidationHandler();
+ context.getBundleContext().registerService(AbstractEventHandler.class.getName(), handler, null);
+ context.getBundleContext().registerService(IdentityConnectorConfig.class.getName(), handler, null);
+ } else {
+ if (log.isDebugEnabled()) {
+ log.debug("Password Policy Validation Handler is disabled.");
+ }
+ }
} catch (Exception e) {
log.error("Error while activating password policy component.", e);
}
diff --git a/components/org.wso2.carbon.identity.password.policy/src/main/java/org/wso2/carbon/identity/password/policy/internal/IdentityPasswordPolicyServiceDataHolder.java b/components/org.wso2.carbon.identity.password.policy/src/main/java/org/wso2/carbon/identity/password/policy/internal/IdentityPasswordPolicyServiceDataHolder.java
index db9b22894a..79780c7cc0 100644
--- a/components/org.wso2.carbon.identity.password.policy/src/main/java/org/wso2/carbon/identity/password/policy/internal/IdentityPasswordPolicyServiceDataHolder.java
+++ b/components/org.wso2.carbon.identity.password.policy/src/main/java/org/wso2/carbon/identity/password/policy/internal/IdentityPasswordPolicyServiceDataHolder.java
@@ -16,8 +16,11 @@
package org.wso2.carbon.identity.password.policy.internal;
+import org.apache.commons.lang.StringUtils;
import org.osgi.framework.BundleContext;
+import org.wso2.carbon.identity.core.util.IdentityUtil;
import org.wso2.carbon.identity.governance.IdentityGovernanceService;
+import org.wso2.carbon.identity.password.policy.constants.PasswordPolicyConstants;
public class IdentityPasswordPolicyServiceDataHolder {
@@ -33,6 +36,19 @@ public static IdentityPasswordPolicyServiceDataHolder getInstance() {
return instance;
}
+ public boolean isPasswordPolicyHandlerEnabled() {
+
+ String passwordPolicyHandlerEnabled =
+ IdentityUtil.getProperty(PasswordPolicyConstants.PW_POLICY_HANDLER_ENABLED);
+ if (StringUtils.isBlank(passwordPolicyHandlerEnabled)) {
+ /*
+ This indicates config not in the identity.xml. In that case, we need to maintain default behaviour.
+ */
+ return false;
+ }
+ return Boolean.parseBoolean(passwordPolicyHandlerEnabled);
+ }
+
public IdentityGovernanceService getIdentityGovernanceService() {
return identityGovernanceService;
}
diff --git a/components/org.wso2.carbon.identity.piicontroller/pom.xml b/components/org.wso2.carbon.identity.piicontroller/pom.xml
index b41f4b10ec..d96401efd6 100644
--- a/components/org.wso2.carbon.identity.piicontroller/pom.xml
+++ b/components/org.wso2.carbon.identity.piicontroller/pom.xml
@@ -19,7 +19,7 @@
org.wso2.carbon.identity.governance
identity-governance
- 1.8.67-SNAPSHOT
+ 1.8.68-SNAPSHOT
../../pom.xml
diff --git a/components/org.wso2.carbon.identity.recovery.endpoint/pom.xml b/components/org.wso2.carbon.identity.recovery.endpoint/pom.xml
index 803fc34fe6..8e6b043d57 100644
--- a/components/org.wso2.carbon.identity.recovery.endpoint/pom.xml
+++ b/components/org.wso2.carbon.identity.recovery.endpoint/pom.xml
@@ -5,7 +5,7 @@
org.wso2.carbon.identity.governance
identity-governance
- 1.8.67-SNAPSHOT
+ 1.8.68-SNAPSHOT
../../pom.xml
diff --git a/components/org.wso2.carbon.identity.recovery.ui/pom.xml b/components/org.wso2.carbon.identity.recovery.ui/pom.xml
index 2aa2e4d61c..ffc7f16216 100644
--- a/components/org.wso2.carbon.identity.recovery.ui/pom.xml
+++ b/components/org.wso2.carbon.identity.recovery.ui/pom.xml
@@ -18,7 +18,7 @@
identity-governance
org.wso2.carbon.identity.governance
- 1.8.67-SNAPSHOT
+ 1.8.68-SNAPSHOT
../../pom.xml
diff --git a/components/org.wso2.carbon.identity.recovery/pom.xml b/components/org.wso2.carbon.identity.recovery/pom.xml
index 3d39409ece..1a8553497d 100644
--- a/components/org.wso2.carbon.identity.recovery/pom.xml
+++ b/components/org.wso2.carbon.identity.recovery/pom.xml
@@ -18,7 +18,7 @@
org.wso2.carbon.identity.governance
identity-governance
- 1.8.67-SNAPSHOT
+ 1.8.68-SNAPSHOT
../../pom.xml
diff --git a/components/org.wso2.carbon.identity.tenant.resource.manager/pom.xml b/components/org.wso2.carbon.identity.tenant.resource.manager/pom.xml
index fce1911a1b..7a8b918d47 100644
--- a/components/org.wso2.carbon.identity.tenant.resource.manager/pom.xml
+++ b/components/org.wso2.carbon.identity.tenant.resource.manager/pom.xml
@@ -22,7 +22,7 @@
identity-governance
org.wso2.carbon.identity.governance
- 1.8.67-SNAPSHOT
+ 1.8.68-SNAPSHOT
../../pom.xml
diff --git a/components/org.wso2.carbon.identity.user.endpoint/pom.xml b/components/org.wso2.carbon.identity.user.endpoint/pom.xml
index c45312d439..7136f94e21 100644
--- a/components/org.wso2.carbon.identity.user.endpoint/pom.xml
+++ b/components/org.wso2.carbon.identity.user.endpoint/pom.xml
@@ -5,7 +5,7 @@
org.wso2.carbon.identity.governance
identity-governance
- 1.8.67-SNAPSHOT
+ 1.8.68-SNAPSHOT
../../pom.xml
diff --git a/components/org.wso2.carbon.identity.user.export.core/pom.xml b/components/org.wso2.carbon.identity.user.export.core/pom.xml
index 434d769e25..f0e7ec1ff2 100644
--- a/components/org.wso2.carbon.identity.user.export.core/pom.xml
+++ b/components/org.wso2.carbon.identity.user.export.core/pom.xml
@@ -21,7 +21,7 @@
org.wso2.carbon.identity.governance
identity-governance
- 1.8.67-SNAPSHOT
+ 1.8.68-SNAPSHOT
../../pom.xml
diff --git a/components/org.wso2.carbon.identity.user.rename.core/pom.xml b/components/org.wso2.carbon.identity.user.rename.core/pom.xml
index 7682b065cb..6b56878bb5 100644
--- a/components/org.wso2.carbon.identity.user.rename.core/pom.xml
+++ b/components/org.wso2.carbon.identity.user.rename.core/pom.xml
@@ -20,7 +20,7 @@
identity-governance
org.wso2.carbon.identity.governance
- 1.8.67-SNAPSHOT
+ 1.8.68-SNAPSHOT
../../pom.xml
4.0.0
diff --git a/features/org.wso2.carbon.identity.account.suspension.notification.task.server.feature/pom.xml b/features/org.wso2.carbon.identity.account.suspension.notification.task.server.feature/pom.xml
index 7b6d207c51..147061264f 100644
--- a/features/org.wso2.carbon.identity.account.suspension.notification.task.server.feature/pom.xml
+++ b/features/org.wso2.carbon.identity.account.suspension.notification.task.server.feature/pom.xml
@@ -21,7 +21,7 @@
org.wso2.carbon.identity.governance
identity-governance
../../pom.xml
- 1.8.67-SNAPSHOT
+ 1.8.68-SNAPSHOT
4.0.0
diff --git a/features/org.wso2.carbon.identity.auth.attribute.handler.server.feature/pom.xml b/features/org.wso2.carbon.identity.auth.attribute.handler.server.feature/pom.xml
index b4f6654767..dc8d85c35a 100644
--- a/features/org.wso2.carbon.identity.auth.attribute.handler.server.feature/pom.xml
+++ b/features/org.wso2.carbon.identity.auth.attribute.handler.server.feature/pom.xml
@@ -22,7 +22,7 @@
org.wso2.carbon.identity.governance
identity-governance
../../pom.xml
- 1.8.67-SNAPSHOT
+ 1.8.68-SNAPSHOT
4.0.0
diff --git a/features/org.wso2.carbon.identity.captcha.server.feature/pom.xml b/features/org.wso2.carbon.identity.captcha.server.feature/pom.xml
index 0d79c4ff45..de562382f9 100644
--- a/features/org.wso2.carbon.identity.captcha.server.feature/pom.xml
+++ b/features/org.wso2.carbon.identity.captcha.server.feature/pom.xml
@@ -21,7 +21,7 @@
org.wso2.carbon.identity.governance
identity-governance
../../pom.xml
- 1.8.67-SNAPSHOT
+ 1.8.68-SNAPSHOT
4.0.0
diff --git a/features/org.wso2.carbon.identity.captcha.server.feature/resources/conf/captcha-config.properties.j2 b/features/org.wso2.carbon.identity.captcha.server.feature/resources/conf/captcha-config.properties.j2
index 45078ab9ef..6b8a2a196c 100644
--- a/features/org.wso2.carbon.identity.captcha.server.feature/resources/conf/captcha-config.properties.j2
+++ b/features/org.wso2.carbon.identity.captcha.server.feature/resources/conf/captcha-config.properties.j2
@@ -21,6 +21,9 @@
# Enable Google reCAPTCHA
recaptcha.enabled={{recaptcha.enabled}}
+# captcha type
+recaptcha.type={{recaptcha.type}}
+
# Forcefully enable Google reCAPTCHA for all tenants
recaptcha.forcefullyEnabledForAllTenants={{recaptcha.forcefully_enabled_for_all_tenants}}
@@ -36,6 +39,9 @@ recaptcha.site.key={{recaptcha.site_key}}
# reCaptcha secret key
recaptcha.secret.key={{recaptcha.secret_key}}
+# reCaptcha Enterprise project id
+recaptcha.project.id={{recaptcha.project_id}}
+
# login.do URL paths
{% if recaptcha.redirect_urls is defined %}
recaptcha.failed.redirect.urls={{recaptcha.redirect_urls}}
@@ -50,3 +56,6 @@ recaptcha.request.wrap.urls={{recaptcha.request_wrap_urls}}
# recaptcha v3 score threshold
recaptcha.threshold={{recaptcha.threshold}}
+
+# reCaptcha API key for enterprise recaptcha
+recaptcha.api.key={{recaptcha.api_key}}
diff --git a/features/org.wso2.carbon.identity.governance.feature/pom.xml b/features/org.wso2.carbon.identity.governance.feature/pom.xml
index 8ce4b95c45..57292a9f67 100644
--- a/features/org.wso2.carbon.identity.governance.feature/pom.xml
+++ b/features/org.wso2.carbon.identity.governance.feature/pom.xml
@@ -21,7 +21,7 @@
org.wso2.carbon.identity.governance
identity-governance
- 1.8.67-SNAPSHOT
+ 1.8.68-SNAPSHOT
../../pom.xml
diff --git a/features/org.wso2.carbon.identity.governance.server.feature/pom.xml b/features/org.wso2.carbon.identity.governance.server.feature/pom.xml
index 22162090b6..3a1e559fd5 100644
--- a/features/org.wso2.carbon.identity.governance.server.feature/pom.xml
+++ b/features/org.wso2.carbon.identity.governance.server.feature/pom.xml
@@ -21,7 +21,7 @@
org.wso2.carbon.identity.governance
identity-governance
../../pom.xml
- 1.8.67-SNAPSHOT
+ 1.8.68-SNAPSHOT
4.0.0
diff --git a/features/org.wso2.carbon.identity.idle.account.identification.server.feature/pom.xml b/features/org.wso2.carbon.identity.idle.account.identification.server.feature/pom.xml
index fe967ce49b..73e1a6703b 100644
--- a/features/org.wso2.carbon.identity.idle.account.identification.server.feature/pom.xml
+++ b/features/org.wso2.carbon.identity.idle.account.identification.server.feature/pom.xml
@@ -21,7 +21,7 @@
org.wso2.carbon.identity.governance
identity-governance
../../pom.xml
- 1.8.67-SNAPSHOT
+ 1.8.68-SNAPSHOT
4.0.0
diff --git a/features/org.wso2.carbon.identity.multi.attribute.login.service.server.feature/pom.xml b/features/org.wso2.carbon.identity.multi.attribute.login.service.server.feature/pom.xml
index ad0b43460f..84fdc4e725 100644
--- a/features/org.wso2.carbon.identity.multi.attribute.login.service.server.feature/pom.xml
+++ b/features/org.wso2.carbon.identity.multi.attribute.login.service.server.feature/pom.xml
@@ -3,7 +3,7 @@
identity-governance
org.wso2.carbon.identity.governance
- 1.8.67-SNAPSHOT
+ 1.8.68-SNAPSHOT
../../pom.xml
4.0.0
diff --git a/features/org.wso2.carbon.identity.password.expiry.server.feature/pom.xml b/features/org.wso2.carbon.identity.password.expiry.server.feature/pom.xml
index cccbb199c2..287b2db3b5 100644
--- a/features/org.wso2.carbon.identity.password.expiry.server.feature/pom.xml
+++ b/features/org.wso2.carbon.identity.password.expiry.server.feature/pom.xml
@@ -22,7 +22,7 @@
org.wso2.carbon.identity.governance
identity-governance
../../pom.xml
- 1.8.67-SNAPSHOT
+ 1.8.68-SNAPSHOT
4.0.0
diff --git a/features/org.wso2.carbon.identity.password.history.server.feature/pom.xml b/features/org.wso2.carbon.identity.password.history.server.feature/pom.xml
index bf9668063d..1055cbaa4e 100644
--- a/features/org.wso2.carbon.identity.password.history.server.feature/pom.xml
+++ b/features/org.wso2.carbon.identity.password.history.server.feature/pom.xml
@@ -21,7 +21,7 @@
org.wso2.carbon.identity.governance
identity-governance
../../pom.xml
- 1.8.67-SNAPSHOT
+ 1.8.68-SNAPSHOT
4.0.0
diff --git a/features/org.wso2.carbon.identity.password.policy.server.feature/pom.xml b/features/org.wso2.carbon.identity.password.policy.server.feature/pom.xml
index 12111994ce..59068f5580 100644
--- a/features/org.wso2.carbon.identity.password.policy.server.feature/pom.xml
+++ b/features/org.wso2.carbon.identity.password.policy.server.feature/pom.xml
@@ -21,7 +21,7 @@
org.wso2.carbon.identity.governance
identity-governance
../../pom.xml
- 1.8.67-SNAPSHOT
+ 1.8.68-SNAPSHOT
4.0.0
diff --git a/features/org.wso2.carbon.identity.piicontroller.server.feature/pom.xml b/features/org.wso2.carbon.identity.piicontroller.server.feature/pom.xml
index ac1c7e66ce..b626640455 100644
--- a/features/org.wso2.carbon.identity.piicontroller.server.feature/pom.xml
+++ b/features/org.wso2.carbon.identity.piicontroller.server.feature/pom.xml
@@ -21,7 +21,7 @@
org.wso2.carbon.identity.governance
identity-governance
../../pom.xml
- 1.8.67-SNAPSHOT
+ 1.8.68-SNAPSHOT
4.0.0
diff --git a/features/org.wso2.carbon.identity.recovery.server.feature/pom.xml b/features/org.wso2.carbon.identity.recovery.server.feature/pom.xml
index e23f6a549c..cb5814a524 100644
--- a/features/org.wso2.carbon.identity.recovery.server.feature/pom.xml
+++ b/features/org.wso2.carbon.identity.recovery.server.feature/pom.xml
@@ -21,7 +21,7 @@
org.wso2.carbon.identity.governance
identity-governance
../../pom.xml
- 1.8.67-SNAPSHOT
+ 1.8.68-SNAPSHOT
4.0.0
diff --git a/features/org.wso2.carbon.identity.recovery.ui.feature/pom.xml b/features/org.wso2.carbon.identity.recovery.ui.feature/pom.xml
index 00ab362af8..df819e25aa 100644
--- a/features/org.wso2.carbon.identity.recovery.ui.feature/pom.xml
+++ b/features/org.wso2.carbon.identity.recovery.ui.feature/pom.xml
@@ -20,7 +20,7 @@
org.wso2.carbon.identity.governance
identity-governance
- 1.8.67-SNAPSHOT
+ 1.8.68-SNAPSHOT
../../pom.xml
diff --git a/features/org.wso2.carbon.identity.tenant.resource.manager.feature/pom.xml b/features/org.wso2.carbon.identity.tenant.resource.manager.feature/pom.xml
index 341275cc16..111b47796c 100644
--- a/features/org.wso2.carbon.identity.tenant.resource.manager.feature/pom.xml
+++ b/features/org.wso2.carbon.identity.tenant.resource.manager.feature/pom.xml
@@ -20,7 +20,7 @@
org.wso2.carbon.identity.governance
identity-governance
- 1.8.67-SNAPSHOT
+ 1.8.68-SNAPSHOT
../../pom.xml
diff --git a/features/org.wso2.carbon.identity.user.server.feature/pom.xml b/features/org.wso2.carbon.identity.user.server.feature/pom.xml
index 0d97546cac..9b57b3d839 100644
--- a/features/org.wso2.carbon.identity.user.server.feature/pom.xml
+++ b/features/org.wso2.carbon.identity.user.server.feature/pom.xml
@@ -21,7 +21,7 @@
org.wso2.carbon.identity.governance
identity-governance
../../pom.xml
- 1.8.67-SNAPSHOT
+ 1.8.68-SNAPSHOT
4.0.0
diff --git a/pom.xml b/pom.xml
index 8202c8d0a9..c05c6e5778 100644
--- a/pom.xml
+++ b/pom.xml
@@ -18,7 +18,7 @@
org.wso2.carbon.identity.governance
identity-governance
- 1.8.67-SNAPSHOT
+ 1.8.68-SNAPSHOT
4.0.0
pom
WSO2 Carbon - Governance Module
diff --git a/service-stubs/identity/org.wso2.carbon.identity.recovery.stub/pom.xml b/service-stubs/identity/org.wso2.carbon.identity.recovery.stub/pom.xml
index 69901e4f05..1618479b5b 100644
--- a/service-stubs/identity/org.wso2.carbon.identity.recovery.stub/pom.xml
+++ b/service-stubs/identity/org.wso2.carbon.identity.recovery.stub/pom.xml
@@ -19,7 +19,7 @@
org.wso2.carbon.identity.governance
carbon-service-stubs
- 1.8.67-SNAPSHOT
+ 1.8.68-SNAPSHOT
../pom.xml
diff --git a/service-stubs/identity/pom.xml b/service-stubs/identity/pom.xml
index 3fa6493f98..ce98332ee9 100644
--- a/service-stubs/identity/pom.xml
+++ b/service-stubs/identity/pom.xml
@@ -19,7 +19,7 @@
org.wso2.carbon.identity.governance
identity-governance
- 1.8.67-SNAPSHOT
+ 1.8.68-SNAPSHOT
../../pom.xml