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