From 59e666b16fdf4755fb7f3028a8a6448f26b37759 Mon Sep 17 00:00:00 2001 From: Lakshan Date: Fri, 6 Oct 2023 13:11:56 +1100 Subject: [PATCH] Add warn logs for recaptcha v3 --- .../captcha/internal/CaptchaDataHolder.java | 13 ++++++++ .../captcha/util/CaptchaConstants.java | 5 +++ .../identity/captcha/util/CaptchaUtil.java | 33 +++++++++++++++++++ .../conf/captcha-config.properties.j2 | 3 ++ 4 files changed, 54 insertions(+) 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 f701657965..b5e069a6ad 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 @@ -58,6 +58,9 @@ public class CaptchaDataHolder { // Threshold for score in reCAPTCHA v3. private double reCaptchaScoreThreshold; + // Threshold for score for warn logs in reCAPTCHA v3. + private double reCaptchaWarnScoreThreshold; + private IdentityGovernanceService identityGovernanceService; private RealmService realmService; @@ -168,6 +171,16 @@ public void setReCaptchaScoreThreshold(double reCaptchaScoreThreshold) { this.reCaptchaScoreThreshold = reCaptchaScoreThreshold; } + public double getReCaptchaWarnScoreThreshold() { + + return reCaptchaWarnScoreThreshold; + } + + public void setReCaptchaWarnScoreThreshold(double reCaptchaWarnScoreThreshold) { + + this.reCaptchaWarnScoreThreshold = reCaptchaWarnScoreThreshold; + } + public String getReCaptchaErrorRedirectUrls() { return reCaptchaErrorRedirectUrls; } 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 742865a234..6859e5b460 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 @@ -59,6 +59,8 @@ public class CaptchaConstants { public static final String RE_CAPTCHA_SCORE_THRESHOLD = "recaptcha.threshold"; + public static final String RE_CAPTCHA_WARN_SCORE_THRESHOLD = "recaptcha.threshold.warn"; + public static final String BASIC_AUTHENTICATOR = "BasicAuthenticator"; public static final String BASIC_AUTH_MECHANISM = "basic"; @@ -81,6 +83,9 @@ public class CaptchaConstants { // Default value for threshold for score in reCAPTCHA v3. public static final double CAPTCHA_V3_DEFAULT_THRESHOLD = 0.5; + // Default value for threshold for score to issue warn logs in reCAPTCHA v3. + public static final double CAPTCHA_V3_DEFAULT_WARN_THRESHOLD = 0.7; + public static final String SSO_LOGIN_RECAPTCHA_CONNECTOR_NAME = "sso.login.recaptcha"; /** 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 6496f2333a..13cd18b91b 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 @@ -350,6 +350,7 @@ private static void verifyReCaptchaEnterpriseResponse(HttpEntity entity) throws CaptchaServerException, CaptchaClientException { final double scoreThreshold = CaptchaDataHolder.getInstance().getReCaptchaScoreThreshold(); + final double warnScoreThreshold = CaptchaDataHolder.getInstance().getReCaptchaWarnScoreThreshold(); try { try (InputStream in = entity.getContent()) { @@ -380,6 +381,8 @@ private static void verifyReCaptchaEnterpriseResponse(HttpEntity entity) } if (score < scoreThreshold) { throw new CaptchaClientException("reCaptcha score is less than the threshold."); + } else if (score < warnScoreThreshold) { + log.warn("User access with low reCaptcha score."); } } } @@ -394,6 +397,7 @@ private static void verifyReCaptchaResponse(HttpEntity entity) throws CaptchaServerException, CaptchaClientException { final double scoreThreshold = CaptchaDataHolder.getInstance().getReCaptchaScoreThreshold(); + final double warnScoreThreshold = CaptchaDataHolder.getInstance().getReCaptchaWarnScoreThreshold(); try { try (InputStream in = entity.getContent()) { @@ -418,6 +422,8 @@ private static void verifyReCaptchaResponse(HttpEntity entity) } if (score < scoreThreshold) { throw new CaptchaClientException("reCaptcha score is less than the threshold."); + } else if (score < warnScoreThreshold) { + log.warn("reCaptcha score is below warn threshold."); } } else { if (log.isDebugEnabled()) { @@ -616,6 +622,13 @@ private static void setReCaptchaConfigs(Properties properties) { throw new RuntimeException(getValidationErrorMessage(CaptchaConstants.RE_CAPTCHA_SCORE_THRESHOLD)); } + try { + Double reCaptchaWarnScoreThreshold = getReCaptchaWarnThreshold(properties); + CaptchaDataHolder.getInstance().setReCaptchaWarnScoreThreshold(reCaptchaWarnScoreThreshold); + } catch (NumberFormatException e) { + throw new RuntimeException(getValidationErrorMessage(CaptchaConstants.RE_CAPTCHA_SCORE_THRESHOLD)); + } + String forcefullyEnableRecaptchaForAllTenants = properties.getProperty(CaptchaConstants.FORCEFULLY_ENABLED_RECAPTCHA_FOR_ALL_TENANTS); CaptchaDataHolder.getInstance().setForcefullyEnabledRecaptchaForAllTenants( @@ -642,6 +655,26 @@ private static double getReCaptchaThreshold(Properties properties) throws Number return Double.parseDouble(threshold); } + /** + * Method to get the warn threshold value used by reCAPTCHA v3. + * + * @param properties Properties. + * @return Warn threshold value set by the user or the default warn threshold. + * @throws java.lang.NumberFormatException Error while parsing the threshold value into double. + */ + private static double getReCaptchaWarnThreshold(Properties properties) throws NumberFormatException { + + String warnThreshold = properties.getProperty(CaptchaConstants.RE_CAPTCHA_WARN_SCORE_THRESHOLD); + if (StringUtils.isBlank(warnThreshold)) { + if (log.isDebugEnabled()) { + log.debug("Error parsing recaptcha.threshold.warn from config. Hence using the default value : " + + CaptchaConstants.CAPTCHA_V3_DEFAULT_WARN_THRESHOLD); + } + return CaptchaConstants.CAPTCHA_V3_DEFAULT_WARN_THRESHOLD; + } + return Double.parseDouble(warnThreshold); + } + private static void setSSOLoginConnectorConfigs(Properties properties) { Map connectorPropertyMap = new HashMap<>(); 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 6b8a2a196c..798a2cedfb 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 @@ -57,5 +57,8 @@ recaptcha.request.wrap.urls={{recaptcha.request_wrap_urls}} # recaptcha v3 score threshold recaptcha.threshold={{recaptcha.threshold}} +# recaptcha enterprise score threshold to issue warn logs +recaptcha.threshold.warn={{recaptcha.threshold_warn}} + # reCaptcha API key for enterprise recaptcha recaptcha.api.key={{recaptcha.api_key}}