From 9cc29f94defaece2ae2ab87d471f35d4bd31364c Mon Sep 17 00:00:00 2001 From: kaveesha Date: Sun, 25 Jul 2021 20:28:12 +0530 Subject: [PATCH 1/4] Add strategy and multiple captcha connectors. --- .../captcha/connector/CaptchaConnector.java | 20 ++- .../captcha/connector/CaptchaProvider.java | 28 ++++ .../connector/kaptcha/KaptchaConnector.java | 67 ++++++++ .../kaptcha/KaptchaImageProvider.java | 92 ++++++++++ .../PasswordRecoveryReCaptchaConnector.java | 158 ++++++++++++++++++ .../SelfSignUpReCaptchaConnector.java | 22 +++ .../UsernameRecoveryReCaptchaConnector.java | 20 +++ .../recaptchaRevamp/RecaptchaConnector.java | 80 +++++++++ .../captcha/filter/CaptchaFilter.java | 36 ++-- .../captcha/internal/CaptchaDataHolder.java | 12 ++ .../strategy/AbstractStrategyConnector.java | 4 + .../strategy/DefaultStrategyConnector.java | 24 +++ .../strategy/FlowBasedStrategyConnector.java | 24 +++ .../LocationBasedStrategyConnector.java | 50 ++++++ .../captcha/strategy/StrategyConnector.java | 17 ++ 15 files changed, 643 insertions(+), 11 deletions(-) create mode 100644 components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/CaptchaProvider.java create mode 100644 components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/kaptcha/KaptchaConnector.java create mode 100644 components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/kaptcha/KaptchaImageProvider.java create mode 100644 components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/recaptchaRevamp/RecaptchaConnector.java create mode 100644 components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/strategy/AbstractStrategyConnector.java create mode 100644 components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/strategy/DefaultStrategyConnector.java create mode 100644 components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/strategy/FlowBasedStrategyConnector.java create mode 100644 components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/strategy/LocationBasedStrategyConnector.java create mode 100644 components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/strategy/StrategyConnector.java diff --git a/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/CaptchaConnector.java b/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/CaptchaConnector.java index dbb5c68f23..30de1dd90b 100644 --- a/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/CaptchaConnector.java +++ b/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/CaptchaConnector.java @@ -35,11 +35,29 @@ public interface CaptchaConnector { boolean canHandle(ServletRequest servletRequest, ServletResponse servletResponse) throws CaptchaException; + @Deprecated CaptchaPreValidationResponse preValidate(ServletRequest servletRequest, ServletResponse servletResponse) throws CaptchaException; - boolean verifyCaptcha(ServletRequest servletRequest, ServletResponse servletResponse) throws CaptchaException; + default CaptchaPreValidationResponse preValidate(ServletRequest servletRequest, ServletResponse servletResponse, CaptchaProvider captchaProvider) throws + CaptchaException { + return null; + } + @Deprecated CaptchaPostValidationResponse postValidate(ServletRequest servletRequest, ServletResponse servletResponse) throws CaptchaException; + + default CaptchaPostValidationResponse postValidate(ServletRequest servletRequest, ServletResponse servletResponse, CaptchaProvider captchaProvider) throws + CaptchaException{ + return null; + } + + @Deprecated + boolean verifyCaptcha(ServletRequest servletRequest, ServletResponse servletResponse) throws CaptchaException; + + default boolean verifyCaptcha(ServletRequest servletRequest, ServletResponse servletResponse, CaptchaProvider captchaProvider) throws CaptchaException{ + return false; + } + } diff --git a/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/CaptchaProvider.java b/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/CaptchaProvider.java new file mode 100644 index 0000000000..a6f6084dbf --- /dev/null +++ b/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/CaptchaProvider.java @@ -0,0 +1,28 @@ +package org.wso2.carbon.identity.captcha.connector; + +import org.wso2.carbon.identity.captcha.exception.CaptchaException; + +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; + +public interface CaptchaProvider { + + void preValidateForSelfSignUp(ServletRequest servletRequest, ServletResponse servletResponse) throws + CaptchaException; + + void preValidateForSSOLogin(ServletRequest servletRequest, ServletResponse servletResponse) throws + CaptchaException; + + void preValidateForUsernameRecovery(ServletRequest servletRequest, ServletResponse servletResponse) throws + CaptchaException; + + void preValidateForPasswordRecovery(ServletRequest servletRequest, ServletResponse servletResponse) throws + CaptchaException; + + boolean verifyCaptcha(ServletRequest servletRequest, ServletResponse servletResponse) throws CaptchaException; + + void postValidateForSSOLogin(ServletRequest servletRequest, ServletResponse servletResponse) throws + CaptchaException; + + void addPostValidationData(ServletRequest servletRequest); +} diff --git a/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/kaptcha/KaptchaConnector.java b/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/kaptcha/KaptchaConnector.java new file mode 100644 index 0000000000..da1fec136d --- /dev/null +++ b/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/kaptcha/KaptchaConnector.java @@ -0,0 +1,67 @@ +package org.wso2.carbon.identity.captcha.connector.kaptcha; + +import org.apache.commons.lang.StringUtils; +import org.wso2.carbon.identity.application.authentication.framework.context.AuthenticationContext; +import org.wso2.carbon.identity.application.authentication.framework.util.FrameworkConstants; +import org.wso2.carbon.identity.application.authentication.framework.util.FrameworkUtils; +import org.wso2.carbon.identity.captcha.connector.CaptchaProvider; +import org.wso2.carbon.identity.captcha.exception.CaptchaException; + +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; + +public class KaptchaConnector implements CaptchaProvider { + + + @Override + public void preValidateForSelfSignUp(ServletRequest servletRequest, ServletResponse servletResponse) throws CaptchaException { + + } + + @Override + public void preValidateForSSOLogin(ServletRequest servletRequest, ServletResponse servletResponse) throws CaptchaException { + + } + + @Override + public void preValidateForUsernameRecovery(ServletRequest servletRequest, ServletResponse servletResponse) throws CaptchaException { + + } + + @Override + public void preValidateForPasswordRecovery(ServletRequest servletRequest, ServletResponse servletResponse) throws CaptchaException { + + } + + @Override + public boolean verifyCaptcha(ServletRequest servletRequest, ServletResponse servletResponse) throws CaptchaException { + AuthenticationContext context = getAuthenticationContext(servletRequest); + String generatedCaptchaText = (String) context.getProperty("CAPTCHA_TEXT"); + String userCaptcha = servletRequest.getParameter("CAPTCHA_TEXT"); + return StringUtils.equalsIgnoreCase(generatedCaptchaText, userCaptcha); + } + + protected AuthenticationContext getAuthenticationContext(ServletRequest request) { + + String sessionDataKey = request.getParameter(FrameworkConstants.SESSION_DATA_KEY); + if (StringUtils.isNotEmpty(sessionDataKey)) { + return FrameworkUtils.getAuthenticationContextFromCache(sessionDataKey); + } + return null; + } + + + + @Override + public void postValidateForSSOLogin(ServletRequest servletRequest, ServletResponse servletResponse) throws CaptchaException { + + } + + + @Override + public void addPostValidationData(ServletRequest servletRequest) { + + } + + +} diff --git a/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/kaptcha/KaptchaImageProvider.java b/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/kaptcha/KaptchaImageProvider.java new file mode 100644 index 0000000000..6d8fd3767c --- /dev/null +++ b/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/kaptcha/KaptchaImageProvider.java @@ -0,0 +1,92 @@ +package org.wso2.carbon.identity.captcha.connector.kaptcha; + +import com.google.code.kaptcha.Producer; +import com.google.code.kaptcha.util.Config; +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.identity.application.authentication.framework.context.AuthenticationContext; +import org.wso2.carbon.identity.application.authentication.framework.util.FrameworkUtils; +import org.wso2.carbon.identity.captcha.exception.CaptchaException; + +import java.awt.image.BufferedImage; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.Properties; +import javax.imageio.ImageIO; +import javax.servlet.http.HttpSession; + +public class KaptchaImageProvider { + + private static final Log LOG = LogFactory.getLog(KaptchaImageProvider.class); + + public String generateImageForSSO(String sessionDataKey) { + // String sessionDataKey = "iVBORw0KGgoAAAANSUhEUgAAAMgAAAAyCAYAAAAZUZThAAAGlUlEQVR42u1cC4hUVRg+WWoYPWwzM1PpbbXVUpmZ2QsJEYmwyNJMrVCJit4hW0SWvTMrsXcRJgtWq6mlZg9CIkQrMzU1SirMamlbS1zbZq3/536Dx7Nn7r0zc+fujPt98OHOvedx58z5zv8452oMQRAEQRAEQRAEQRAEQRAEQRAEkTT+K5Icg71vPAgKhAIhKBAKhKBAKBCCAqFAiDKaHBwDCqTDYT/hZOES4V/CFuGOEv7IVcKJwjnCNcLt6FPZJFwmnCasKWOBEB1gFVScLNyU0iqowpgJIcTt7xM8YxaNzv0vi3ieVU5bjRQIBWKzn7AhJTdhiPC3Al2TncKxaKfec69Q7HTaqqdAKBCby1Lyoy8Icdny4RjhdM/1XgU8U09PO9PzGLvZwtX4Xi0QWyPGVNsZymnXMQPNl+GSZSeGxiyfCh8VVueYiA0J9a2T8A7P9eEFjMkITzujEh67HxFrERUuEF0JJwh7W3W6FDgp5kMUWbweUlbFVSvsg7KdYG0+D6mz0nNtQgFjMtnTTk2JFhdNfnTnNKxMgcwsgeXRWGMAJn4mxBoMCMmqLQ9pv9Vj1fKFK9wMBFoq6/uZcH9OxcoSyPISumYqkqkh9x+I6HtwSN2tHqtlY4KnzjinzCKPFS21e/okp2JlCWRkiWOX30PuVUf03Smk7i/O5wan7uwcQbWNpoj77hioKGdhzPpY1kZd0Us92TUfM5Y7SVSAQHrGrLcEq/IJzsTQ4HhOwqtsHDZ7rtnu0VrP/bUR8dXtOcZAExDDcrhfLsbGePZaTsfKEUjUjz4foojCMNN2T6GU9G00DopILmQQ2+Ry34YnNNbPRjz7+5yOlSOQJDGlHSyJL0U73BGFXeYSlBnlqV+V0DhURzxnE6dj5QgkyaxKr5QFsd35/KBHqJo5WmN9vhNlppm26eak0CmG9evo2NeUWdo71491ekr9+NilyL7cLFQdrr9tXZthghRw9vNclJnr1F1EgRT1fdX6nig8FwmL64R3Cx8XviZcgMVqo/AP4S78W/YCGZ1gHz3yFMiIIvub5bS3CtcbnSyd7U5tQZnVTt1ZCY5DTQW7WPtgZT9eeA5+o/GwvHpS4hXEpbo98C2yh60FegCtMRMf7SqQaQn2cYvJf3c5X/SzrMAY03bjsbcnrnCv9fDEJlfn6K/O7Hm6IA5mRnzv+hR/94OFxwoHIja7Ftm6h4Uv4Vk0S7fOBPtWmZTc41ZYkO7lLpB5CbU/GH58vgM1JWb7mkl70cpeGWSt3PZusv7eZNXfYvZM57r1BoaM206snnEORI6L8Z1vLXCMDxQebYLTB5o1vAZtPSR8Aa6lvhrwjQn2bFpSmuzqLv0p/M4ER4QWmuCUwhPCe4Q3CC8TnifsLzysnCxHlEC2CbvmqLMe/ruurhcJuzn3q2CC34hYeRZGDPBHGEB7NemGFa/W+M9lZX1ft1/7vRZ748/eq1lv4h0xMZ5yCyCC/qbtftD8mIkF/Z4HwBqeiczaaFjgqXD35mJcvoa4/0kx+aFz4nvhCuF7+H2fwmI2EW7r+SZ4R+dwszt1vldmsbK++1FFBty5qC5Kkqd53fT0hpAy9tGS60PKrU8o6RCHutI2pzjZ1apvNsEBz8VYNJ7GwqOHNa8QXojU9BHCzkzz5j43NSThybHZ7N5b0LZ3lEAgdSFl+lvlqiNEnEVXxBya3bvYtO++js/66PH5L4RLYRWfEd4nvFF4JZ75NOGRIZ4BkYdAWpy/b05IICs8PvsgJxYohLqnYb+IVBuycnbGM5yKVTKXm/IzxPx3ipN9B/r9ygQvWKlInxPejzjqKnzPGlh3ngJuJ4Hoyv6rJxu00RR+gndKiE9/EALefK3JxwhKT4H/OxL+8Jsm/lGU9uA6jIfGGWcI+3piOaKMBWKwQq0sMmWn5v8H4Qcw/bpBd69wkvByK6jrgaC2L7JJi5FPb7YC7gwCxQYIbhsyJWmd8dqKTJBmhN4SPm+CXXoV9qvCD7EP0AShZ1BvO+K5Ovj3PLW7F6GXSfewYRr8FwJbh1z/O0gV697PbdgT0OzT2cJjYN0IIhRjEKSeZLkyk+Drz4BLsxSB4k8JB95R71E0wNosx/6NpqAfMcE76uORctbd3+OEh5hgV5gg2h3ZnP5ZJtjAGosVOrtbOw+TeoPlKu1CnKPnc96F6/KY8C4TnOPR8zx6rkc3CA/lZCc6Croju8T/wIAgCIIgCIIgCIIgCIIgCIIgCIIgCIIoHP8DrVNh47xiVYYAAAAASUVORK5CYII="; + Config config = new Config(new Properties()); + Producer captchaProducer = config.getProducerImpl(); + String captchaText = captchaProducer.createText(); + try { + byte[] encodedCaptchaImage = generateBase64EncodedCaptchaImage(captchaProducer, captchaText); + setCaptchaTextToAuthenticationContext(sessionDataKey, captchaText); + return new String(encodedCaptchaImage); + } catch (IOException e) { + LOG.error("Error when creating captcha image for session data key: " + sessionDataKey); + return null; + } catch (CaptchaException e) { + LOG.error("Error when setting captcha text to context " + sessionDataKey); + return null; + } + } + + /** + * Generate a captcha image and set the text value in the session as a attribute + * @param session The session object to set the captcha answer as an attribute + * @return + */ + public String generateImageForSession(HttpSession session) { + + Config config = new Config(new Properties()); + Producer captchaProducer = config.getProducerImpl(); + String captchaText = captchaProducer.createText(); + try { + byte[] encodedCaptchaImage = generateBase64EncodedCaptchaImage(captchaProducer, captchaText); + setCaptchaTextToSession(session, captchaText); + return new String(encodedCaptchaImage); + } catch (IOException e) { + LOG.error("Error when creating captcha image for session"); + return null; + } + } + + private byte[] generateBase64EncodedCaptchaImage(Producer captchaProducer, String captchaText) throws IOException { + + BufferedImage image = captchaProducer.createImage(captchaText); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ImageIO.write(image, "jpg", baos); + return Base64.encodeBase64(baos.toByteArray()); + + } + + private void setCaptchaTextToAuthenticationContext(String sessionDataKey, String captchaText) throws + CaptchaException { + + AuthenticationContext context = FrameworkUtils.getAuthenticationContextFromCache(sessionDataKey); + if (context != null) { + context.setProperty("captchaAnswer", captchaText); + if (LOG.isDebugEnabled()) { + LOG.debug(String.format("Captcha text set for session data key : %s, captcha text: %s", + sessionDataKey, captchaText)); + } + return; + } + if (LOG.isDebugEnabled()) { + LOG.debug("Invalid authentication context Id: " + sessionDataKey); + } + throw new CaptchaException("Invalid authentication context id."); + } + + private void setCaptchaTextToSession(HttpSession session, String captchaText) { + + session.setAttribute("captchaAnswer", captchaText); + } +} diff --git a/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/recaptcha/PasswordRecoveryReCaptchaConnector.java b/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/recaptcha/PasswordRecoveryReCaptchaConnector.java index fed7f5e7a5..03ce9d4e95 100644 --- a/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/recaptcha/PasswordRecoveryReCaptchaConnector.java +++ b/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/recaptcha/PasswordRecoveryReCaptchaConnector.java @@ -29,6 +29,7 @@ import org.wso2.carbon.identity.application.common.model.User; import org.wso2.carbon.identity.captcha.connector.CaptchaPostValidationResponse; import org.wso2.carbon.identity.captcha.connector.CaptchaPreValidationResponse; +import org.wso2.carbon.identity.captcha.connector.CaptchaProvider; import org.wso2.carbon.identity.captcha.exception.CaptchaClientException; import org.wso2.carbon.identity.captcha.exception.CaptchaException; import org.wso2.carbon.identity.captcha.exception.CaptchaServerException; @@ -265,6 +266,163 @@ public CaptchaPreValidationResponse preValidate(ServletRequest servletRequest, S return preValidationResponse; } + public CaptchaPreValidationResponse preValidate(ServletRequest servletRequest, ServletResponse servletResponse, CaptchaProvider captchaProvider) throws CaptchaException { + + CaptchaPreValidationResponse preValidationResponse = new CaptchaPreValidationResponse(); + boolean forgotPasswordRecaptchaEnabled = checkReCaptchaEnabledForForgotPassoword(servletRequest, + FORGOT_PASSWORD_RECAPTCHA_ENABLE); + String pathUrl = ((HttpServletRequest) servletRequest).getRequestURI(); + + if (forgotPasswordRecaptchaEnabled && + (CaptchaUtil.isPathAvailable(pathUrl, ACCOUNT_SECURITY_QUESTION_URL) || + CaptchaUtil.isPathAvailable(pathUrl, ACCOUNT_SECURITY_QUESTIONS_URL) || + CaptchaUtil.isPathAvailable(pathUrl, RECOVER_PASSWORD_URL))) { + preValidationResponse.setCaptchaValidationRequired(true); + } + + // Handle recover with Email option. + if (pathUrl.equals(RECOVER_PASSWORD_URL)) { + return preValidationResponse; + } + + // Handle recover with security questions option. + HttpServletRequest httpServletRequestWrapper; + try { + httpServletRequestWrapper = new CaptchaHttpServletRequestWrapper((HttpServletRequest) servletRequest); + preValidationResponse.setWrappedHttpServletRequest(httpServletRequestWrapper); + } catch (IOException e) { + log.error("Error occurred while wrapping ServletRequest.", e); + return preValidationResponse; + } + + String path = httpServletRequestWrapper.getRequestURI(); + + User user = new User(); + boolean initializationFlow = false; + if (CaptchaUtil.isPathAvailable(path, ACCOUNT_SECURITY_QUESTION_URL) + || CaptchaUtil.isPathAvailable(path, ACCOUNT_SECURITY_QUESTIONS_URL)) { + user.setUserName(servletRequest.getParameter("username")); + if (StringUtils.isNotBlank(servletRequest.getParameter("realm"))) { + user.setUserStoreDomain(servletRequest.getParameter("realm")); + } else { + user.setUserStoreDomain(IdentityUtil.getPrimaryDomainName()); + } + user.setTenantDomain(servletRequest.getParameter("tenant-domain")); + initializationFlow = true; + } else { + JsonObject requestObject; + try { + try (InputStream in = httpServletRequestWrapper.getInputStream()) { + requestObject = new JsonParser().parse(IOUtils.toString(in)).getAsJsonObject(); + } + } catch (IOException e) { + return preValidationResponse; + } + UserRecoveryDataStore userRecoveryDataStore = JDBCRecoveryDataStore.getInstance(); + try { + UserRecoveryData userRecoveryData = userRecoveryDataStore.load(requestObject.get("key").getAsString()); + if(userRecoveryData != null) { + user = userRecoveryData.getUser(); + } + } catch (IdentityRecoveryException e) { + return preValidationResponse; + } + } + + if (StringUtils.isBlank(user.getUserName())) { + // Invalid Request + return preValidationResponse; + } + + if (StringUtils.isBlank(user.getTenantDomain())) { + user.setTenantDomain(MultitenantConstants.SUPER_TENANT_DOMAIN_NAME); + } + + Property[] connectorConfigs; + try { + connectorConfigs = identityGovernanceService.getConfiguration(new String[]{ + RECOVERY_QUESTION_PASSWORD_RECAPTCHA_ENABLE, + RECOVERY_QUESTION_PASSWORD_RECAPTCHA_MAX_FAILED_ATTEMPTS}, + user.getTenantDomain()); + } catch (IdentityGovernanceException e) { + throw new CaptchaServerException("Unable to retrieve connector configs.", e); + } + + String connectorEnabled = null; + String maxAttemptsStr = null; + for (Property connectorConfig : connectorConfigs) { + if ((RECOVERY_QUESTION_PASSWORD_RECAPTCHA_ENABLE) + .equals(connectorConfig.getName())) { + connectorEnabled = connectorConfig.getValue(); + } else if ((RECOVERY_QUESTION_PASSWORD_RECAPTCHA_MAX_FAILED_ATTEMPTS) + .equals(connectorConfig.getName())) { + maxAttemptsStr = connectorConfig.getValue(); + } + } + + if (!Boolean.parseBoolean(connectorEnabled)) { + return preValidationResponse; + } + + if (StringUtils.isBlank(maxAttemptsStr) || !NumberUtils.isNumber(maxAttemptsStr)) { + log.warn("Invalid configuration found in the PasswordRecoveryReCaptchaConnector for the tenant - " + + user.getTenantDomain()); + return preValidationResponse; + } + int maxFailedAttempts = Integer.parseInt(maxAttemptsStr); + + int tenantId; + try { + tenantId = IdentityTenantUtil.getTenantId(user.getTenantDomain()); + } catch (Exception e) { + //Invalid tenant + return preValidationResponse; + } + + try { + if (CaptchaDataHolder.getInstance().getAccountLockService().isAccountLocked(user.getUserName(), user + .getTenantDomain(), user.getUserStoreDomain())) { + return preValidationResponse; + } + } catch (AccountLockServiceException e) { + if (log.isDebugEnabled()) { + log.debug("Error while validating if account is locked for user: " + user.getUserName() + " of user " + + "store domain: " + user.getUserStoreDomain() + " and tenant domain: " + + user.getTenantDomain()); + } + return preValidationResponse; + } + + Map claimValues = CaptchaUtil.getClaimValues(user, tenantId, new String[]{FAIL_ATTEMPTS_CLAIM}); + + if (claimValues == null || claimValues.isEmpty()) { + // Invalid user + return preValidationResponse; + } + + int currentFailedAttempts = 0; + if (NumberUtils.isNumber(claimValues.get(FAIL_ATTEMPTS_CLAIM))) { + currentFailedAttempts = Integer.parseInt(claimValues.get(FAIL_ATTEMPTS_CLAIM)); + } + + HttpServletResponse httpServletResponse = ((HttpServletResponse) servletResponse); + if (currentFailedAttempts > maxFailedAttempts) { + if (initializationFlow) { + httpServletResponse.setHeader("reCaptcha", "true"); + captchaProvider.preValidateForPasswordRecovery(servletRequest,servletResponse); + } else { + preValidationResponse.setCaptchaValidationRequired(true); + preValidationResponse.setMaxFailedLimitReached(true); + captchaProvider.addPostValidationData(servletRequest); + } + } else if (currentFailedAttempts == maxFailedAttempts && !initializationFlow) { + captchaProvider.addPostValidationData(servletRequest); + } + + return preValidationResponse; + } + + @Override public boolean verifyCaptcha(ServletRequest servletRequest, ServletResponse servletResponse) throws CaptchaException { diff --git a/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/recaptcha/SelfSignUpReCaptchaConnector.java b/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/recaptcha/SelfSignUpReCaptchaConnector.java index b297b1c8e2..892940b5c0 100644 --- a/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/recaptcha/SelfSignUpReCaptchaConnector.java +++ b/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/recaptcha/SelfSignUpReCaptchaConnector.java @@ -24,6 +24,7 @@ import org.wso2.carbon.identity.application.common.model.Property; import org.wso2.carbon.identity.captcha.connector.CaptchaPostValidationResponse; import org.wso2.carbon.identity.captcha.connector.CaptchaPreValidationResponse; +import org.wso2.carbon.identity.captcha.connector.CaptchaProvider; import org.wso2.carbon.identity.captcha.exception.CaptchaClientException; import org.wso2.carbon.identity.captcha.exception.CaptchaException; import org.wso2.carbon.identity.captcha.internal.CaptchaDataHolder; @@ -123,6 +124,27 @@ public CaptchaPreValidationResponse preValidate(ServletRequest servletRequest, S return preValidationResponse; } + public CaptchaPreValidationResponse preValidate(ServletRequest servletRequest, ServletResponse servletResponse, CaptchaProvider captchaProvider) throws CaptchaException { + // reCaptcha is required for all requests. + CaptchaPreValidationResponse preValidationResponse = new CaptchaPreValidationResponse(); + + String path = ((HttpServletRequest) servletRequest).getRequestURI(); + + HttpServletResponse httpServletResponse = ((HttpServletResponse) servletResponse); + + if (CaptchaUtil.isPathAvailable(path, SELF_REGISTRATION_INITIATE_URL)) { + httpServletResponse.setHeader("reCaptcha", "true"); + } else { + httpServletResponse.setHeader("reCaptcha", "conditional"); + preValidationResponse.setCaptchaValidationRequired(true); + preValidationResponse.setMaxFailedLimitReached(true); + } + + captchaProvider.preValidateForSelfSignUp(servletRequest, servletResponse); + + return preValidationResponse; + } + @Override public boolean verifyCaptcha(ServletRequest servletRequest, ServletResponse servletResponse) throws CaptchaException { diff --git a/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/recaptcha/UsernameRecoveryReCaptchaConnector.java b/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/recaptcha/UsernameRecoveryReCaptchaConnector.java index 2e1925203b..af7154a2b7 100644 --- a/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/recaptcha/UsernameRecoveryReCaptchaConnector.java +++ b/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/recaptcha/UsernameRecoveryReCaptchaConnector.java @@ -24,6 +24,7 @@ import org.wso2.carbon.identity.application.common.model.Property; import org.wso2.carbon.identity.captcha.connector.CaptchaPostValidationResponse; import org.wso2.carbon.identity.captcha.connector.CaptchaPreValidationResponse; +import org.wso2.carbon.identity.captcha.connector.CaptchaProvider; import org.wso2.carbon.identity.captcha.exception.CaptchaClientException; import org.wso2.carbon.identity.captcha.exception.CaptchaException; import org.wso2.carbon.identity.captcha.util.CaptchaUtil; @@ -101,6 +102,19 @@ public CaptchaPreValidationResponse preValidate(ServletRequest servletRequest, S return preValidationResponse; } + public CaptchaPreValidationResponse preValidate(ServletRequest servletRequest, ServletResponse servletResponse, CaptchaProvider captchaProvider) + throws CaptchaException { + + CaptchaPreValidationResponse preValidationResponse = new CaptchaPreValidationResponse(); + String path = ((HttpServletRequest) servletRequest).getRequestURI(); + + if (CaptchaUtil.isPathAvailable(path, RECOVER_USERNAME_URL)) { + captchaProvider.preValidateForUsernameRecovery(servletRequest,servletResponse); + preValidationResponse.setCaptchaValidationRequired(true); + } + return preValidationResponse; + } + @Override public boolean verifyCaptcha(ServletRequest servletRequest, ServletResponse servletResponse) throws CaptchaException { @@ -112,6 +126,12 @@ public boolean verifyCaptcha(ServletRequest servletRequest, ServletResponse serv return CaptchaUtil.isValidCaptcha(reCaptchaResponse); } + public boolean verifyCaptcha(ServletRequest servletRequest, ServletResponse servletResponse, CaptchaProvider captchaProvider) + throws CaptchaException { + + return captchaProvider.verifyCaptcha(servletRequest,servletResponse); + } + @Override public CaptchaPostValidationResponse postValidate(ServletRequest servletRequest, ServletResponse servletResponse) throws CaptchaException { diff --git a/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/recaptchaRevamp/RecaptchaConnector.java b/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/recaptchaRevamp/RecaptchaConnector.java new file mode 100644 index 0000000000..7781bd8903 --- /dev/null +++ b/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/recaptchaRevamp/RecaptchaConnector.java @@ -0,0 +1,80 @@ +package org.wso2.carbon.identity.captcha.connector.recaptchaRevamp; + +import org.apache.commons.lang.StringUtils; +import org.wso2.carbon.identity.captcha.connector.CaptchaProvider; +import org.wso2.carbon.identity.captcha.exception.CaptchaClientException; +import org.wso2.carbon.identity.captcha.exception.CaptchaException; +import org.wso2.carbon.identity.captcha.internal.CaptchaDataHolder; +import org.wso2.carbon.identity.captcha.util.CaptchaUtil; +import org.wso2.carbon.identity.captcha.util.EnabledSecurityMechanism; + +import java.util.HashMap; +import java.util.Map; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +public class RecaptchaConnector implements CaptchaProvider { + + private static final String SELF_REGISTRATION_INITIATE_URL = "/api/identity/recovery/v0.9/claims"; + + + @Override + public void preValidateForSelfSignUp(ServletRequest servletRequest, ServletResponse servletResponse) throws CaptchaException { + + HttpServletResponse httpServletResponse = ((HttpServletResponse) servletResponse); + httpServletResponse.setHeader("reCaptchaKey", CaptchaDataHolder.getInstance().getReCaptchaSiteKey()); + httpServletResponse.setHeader("reCaptchaAPI", CaptchaDataHolder.getInstance().getReCaptchaAPIUrl()); + + } + + @Override + public void preValidateForSSOLogin(ServletRequest servletRequest, ServletResponse servletResponse) throws CaptchaException { + + } + + @Override + public void preValidateForUsernameRecovery(ServletRequest servletRequest, ServletResponse servletResponse) throws CaptchaException { + HttpServletResponse httpServletResponse = ((HttpServletResponse) servletResponse); + httpServletResponse.setHeader("reCaptcha", "conditional"); + } + + @Override + public void preValidateForPasswordRecovery(ServletRequest servletRequest, ServletResponse servletResponse) throws CaptchaException { + HttpServletResponse httpServletResponse = ((HttpServletResponse) servletResponse); + httpServletResponse.setHeader("reCaptchaKey", CaptchaDataHolder.getInstance().getReCaptchaSiteKey()); + httpServletResponse.setHeader("reCaptchaAPI", CaptchaDataHolder.getInstance().getReCaptchaAPIUrl()); + } + + public void addPostValidationData(ServletRequest servletRequest){ + EnabledSecurityMechanism enabledSecurityMechanism = new EnabledSecurityMechanism(); + enabledSecurityMechanism.setMechanism("reCaptcha"); + Map properties = new HashMap<>(); + properties.put("reCaptchaKey", CaptchaDataHolder.getInstance().getReCaptchaSiteKey()); + properties.put("reCaptchaAPI", CaptchaDataHolder.getInstance().getReCaptchaAPIUrl()); + enabledSecurityMechanism.setProperties(properties); + ((HttpServletRequest) servletRequest).getSession().setAttribute("enabled-security-mechanism", + enabledSecurityMechanism); + } + + @Override + public boolean verifyCaptcha(ServletRequest servletRequest, ServletResponse servletResponse) throws CaptchaException { + + String reCaptchaResponse = ((HttpServletRequest) servletRequest).getHeader("g-recaptcha-response"); + if (StringUtils.isBlank(reCaptchaResponse)) { + throw new CaptchaClientException("reCaptcha response is not available in the request."); + } + + return CaptchaUtil.isValidCaptcha(reCaptchaResponse); + } + + + @Override + public void postValidateForSSOLogin(ServletRequest servletRequest, ServletResponse servletResponse) throws CaptchaException { + + } + + + +} diff --git a/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/filter/CaptchaFilter.java b/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/filter/CaptchaFilter.java index 4e93d458fd..4765c2bf24 100644 --- a/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/filter/CaptchaFilter.java +++ b/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/filter/CaptchaFilter.java @@ -24,9 +24,11 @@ import org.wso2.carbon.identity.captcha.connector.CaptchaConnector; import org.wso2.carbon.identity.captcha.connector.CaptchaPostValidationResponse; import org.wso2.carbon.identity.captcha.connector.CaptchaPreValidationResponse; +import org.wso2.carbon.identity.captcha.connector.CaptchaProvider; import org.wso2.carbon.identity.captcha.exception.CaptchaClientException; import org.wso2.carbon.identity.captcha.exception.CaptchaException; import org.wso2.carbon.identity.captcha.internal.CaptchaDataHolder; +import org.wso2.carbon.identity.captcha.strategy.StrategyConnector; import org.wso2.carbon.identity.captcha.util.CaptchaHttpServletRequestWrapper; import org.wso2.carbon.identity.captcha.util.CaptchaHttpServletResponseWrapper; import org.wso2.carbon.identity.captcha.util.CaptchaUtil; @@ -82,22 +84,36 @@ public void doFilter(ServletRequest servletRequest, ServletResponse servletRespo } List captchaConnectors = CaptchaDataHolder.getInstance().getCaptchaConnectors(); - - CaptchaConnector selectedCaptchaConnector = null; - for (CaptchaConnector captchaConnector : captchaConnectors) { - if (captchaConnector.canHandle(servletRequest, servletResponse) && (selectedCaptchaConnector == null || - captchaConnector.getPriority() > selectedCaptchaConnector.getPriority())) { - selectedCaptchaConnector = captchaConnector; + List strategyConnectors = CaptchaDataHolder.getInstance().getStrategyConnectors(); + List captchaFlowConnectors = CaptchaDataHolder.getInstance().getCaptchaFlowConnectors(); + + //select the relevant flow connector + CaptchaConnector selectedCaptchaFlowConnector = null; + for (CaptchaConnector captchaFlowConnector : captchaFlowConnectors) { + if (captchaFlowConnector.canHandle(servletRequest, servletResponse) && (selectedCaptchaFlowConnector == null || + captchaFlowConnector.getPriority() > selectedCaptchaFlowConnector.getPriority())) { + selectedCaptchaFlowConnector = captchaFlowConnector; } } - if (selectedCaptchaConnector == null) { + if (selectedCaptchaFlowConnector == null) { filterChain.doFilter(servletRequest, servletResponse); return; } + //select the strategy + StrategyConnector selectedStrategyConnector = null; + for (StrategyConnector strategyConnector : strategyConnectors) { + if (selectedCaptchaFlowConnector != null && (selectedStrategyConnector == null || + strategyConnector.getPriority() > selectedStrategyConnector.getPriority())) { + selectedStrategyConnector = strategyConnector; + } + } + + CaptchaProvider selectedCaptchaProvider = selectedStrategyConnector.getCaptchaProvider(servletRequest, servletResponse); + // Check whether captcha is required or will reach to the max failed attempts with the current attempt. - CaptchaPreValidationResponse captchaPreValidationResponse = selectedCaptchaConnector + CaptchaPreValidationResponse captchaPreValidationResponse = selectedCaptchaFlowConnector .preValidate(servletRequest, servletResponse); if (captchaPreValidationResponse == null) { @@ -111,7 +127,7 @@ public void doFilter(ServletRequest servletRequest, ServletResponse servletRespo if (captchaPreValidationResponse.isCaptchaValidationRequired()) { try { - boolean validCaptcha = selectedCaptchaConnector.verifyCaptcha(servletRequest, servletResponse); + boolean validCaptcha = selectedCaptchaFlowConnector.verifyCaptcha(servletRequest, servletResponse); if (!validCaptcha) { log.warn("Captcha validation failed for the user."); httpResponse.sendRedirect(CaptchaUtil.getOnFailRedirectUrl(httpRequest.getHeader("referer"), @@ -150,7 +166,7 @@ public void doFilter(ServletRequest servletRequest, ServletResponse servletRespo CaptchaHttpServletResponseWrapper responseWrapper = new CaptchaHttpServletResponseWrapper(httpResponse); doFilter(captchaPreValidationResponse, servletRequest, responseWrapper, filterChain); - CaptchaPostValidationResponse postValidationResponse = selectedCaptchaConnector + CaptchaPostValidationResponse postValidationResponse = selectedCaptchaFlowConnector .postValidate(servletRequest, responseWrapper); // Check whether this attempt is failed 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 3d5f532579..16e786d19b 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 @@ -19,6 +19,7 @@ package org.wso2.carbon.identity.captcha.internal; import org.wso2.carbon.identity.captcha.connector.CaptchaConnector; +import org.wso2.carbon.identity.captcha.strategy.StrategyConnector; import org.wso2.carbon.identity.governance.IdentityGovernanceService; import org.wso2.carbon.identity.handler.event.account.lock.service.AccountLockService; import org.wso2.carbon.user.core.service.RealmService; @@ -57,6 +58,10 @@ public class CaptchaDataHolder { private List captchaConnectors = new ArrayList<>(); + private List strategyConnectors = new ArrayList<>(); + + private List captchaFlowConnectors = new ArrayList<>(); + private Map ssoLoginReCaptchaConnectorPropertyMap = new HashMap<>(); private Map pathBasedReCaptchaConnectorPropertyMap = new HashMap<>(); @@ -168,6 +173,13 @@ public void addCaptchaConnector(CaptchaConnector captchaConnector) { this.captchaConnectors.add(captchaConnector); } + public List getStrategyConnectors() { return strategyConnectors; } + + public void addStrategyConnectors(StrategyConnector strategyConnectors) { this.strategyConnectors.add(strategyConnectors); } + + public List getCaptchaFlowConnectors() { return captchaFlowConnectors ; } + + public void addCaptchaFlowConnector(CaptchaConnector captchaFlowConnector) { this.captchaFlowConnectors.add(captchaFlowConnector); } public void setRealmService(RealmService realmService) { this.realmService = realmService; } diff --git a/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/strategy/AbstractStrategyConnector.java b/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/strategy/AbstractStrategyConnector.java new file mode 100644 index 0000000000..19c7649c0b --- /dev/null +++ b/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/strategy/AbstractStrategyConnector.java @@ -0,0 +1,4 @@ +package org.wso2.carbon.identity.captcha.strategy; + +public abstract class AbstractStrategyConnector implements StrategyConnector { +} diff --git a/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/strategy/DefaultStrategyConnector.java b/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/strategy/DefaultStrategyConnector.java new file mode 100644 index 0000000000..a2a003c56e --- /dev/null +++ b/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/strategy/DefaultStrategyConnector.java @@ -0,0 +1,24 @@ +package org.wso2.carbon.identity.captcha.strategy; + +import org.wso2.carbon.identity.captcha.connector.CaptchaProvider; +import org.wso2.carbon.identity.governance.IdentityGovernanceService; + +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; + +public class DefaultStrategyConnector extends AbstractStrategyConnector{ + @Override + public void init(IdentityGovernanceService identityGovernanceService) { + + } + + @Override + public int getPriority() { + return 0; + } + + @Override + public CaptchaProvider getCaptchaProvider(ServletRequest servletRequest, ServletResponse servletResponse) { + return null; + } +} diff --git a/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/strategy/FlowBasedStrategyConnector.java b/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/strategy/FlowBasedStrategyConnector.java new file mode 100644 index 0000000000..f53cbb2f17 --- /dev/null +++ b/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/strategy/FlowBasedStrategyConnector.java @@ -0,0 +1,24 @@ +package org.wso2.carbon.identity.captcha.strategy; + +import org.wso2.carbon.identity.captcha.connector.CaptchaProvider; +import org.wso2.carbon.identity.governance.IdentityGovernanceService; + +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; + +public class FlowBasedStrategyConnector extends AbstractStrategyConnector{ + @Override + public void init(IdentityGovernanceService identityGovernanceService) { + + } + + @Override + public int getPriority() { + return 0; + } + + @Override + public CaptchaProvider getCaptchaProvider(ServletRequest servletRequest, ServletResponse servletResponse) { + return null; + } +} diff --git a/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/strategy/LocationBasedStrategyConnector.java b/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/strategy/LocationBasedStrategyConnector.java new file mode 100644 index 0000000000..d655180770 --- /dev/null +++ b/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/strategy/LocationBasedStrategyConnector.java @@ -0,0 +1,50 @@ +package org.wso2.carbon.identity.captcha.strategy; + +import org.wso2.carbon.identity.captcha.connector.CaptchaProvider; +import org.wso2.carbon.identity.governance.IdentityGovernanceService; + +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; + +public class LocationBasedStrategyConnector extends AbstractStrategyConnector { + + @Override + public void init(IdentityGovernanceService identityGovernanceService) { + + } + + @Override + public int getPriority() { + + return 10; + } + + @Override + public CaptchaProvider getCaptchaProvider(ServletRequest servletRequest, ServletResponse servletResponse) { + //if client + return null; + } + + public static String getClientIpAddress(HttpServletRequest request) { + + String ip = request.getHeader("X-Forwarded-For"); + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + ip = request.getHeader("Proxy-Client-IP"); + } + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + ip = request.getHeader("WL-Proxy-Client-IP"); + } + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + ip = request.getHeader("HTTP_CLIENT_IP"); + } + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + ip = request.getHeader("HTTP_X_FORWARDED_FOR"); + } + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + ip = request.getRemoteAddr(); + } + return ip; + } + +} diff --git a/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/strategy/StrategyConnector.java b/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/strategy/StrategyConnector.java new file mode 100644 index 0000000000..4cc15e24e4 --- /dev/null +++ b/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/strategy/StrategyConnector.java @@ -0,0 +1,17 @@ +package org.wso2.carbon.identity.captcha.strategy; + +import org.wso2.carbon.identity.captcha.connector.CaptchaProvider; +import org.wso2.carbon.identity.governance.IdentityGovernanceService; + +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; + +public interface StrategyConnector { + + void init(IdentityGovernanceService identityGovernanceService); + + int getPriority(); + + CaptchaProvider getCaptchaProvider(ServletRequest servletRequest, ServletResponse servletResponse); + +} From 9da2120f251436eb838fd9569531c3443cf76946 Mon Sep 17 00:00:00 2001 From: kaveesha Date: Thu, 5 Aug 2021 14:09:47 +0530 Subject: [PATCH 2/4] Add selected captcha providers in preValidate and postValidate methods --- .../wso2/carbon/identity/captcha/filter/CaptchaFilter.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/filter/CaptchaFilter.java b/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/filter/CaptchaFilter.java index 4765c2bf24..cf6058301f 100644 --- a/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/filter/CaptchaFilter.java +++ b/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/filter/CaptchaFilter.java @@ -114,7 +114,7 @@ public void doFilter(ServletRequest servletRequest, ServletResponse servletRespo // Check whether captcha is required or will reach to the max failed attempts with the current attempt. CaptchaPreValidationResponse captchaPreValidationResponse = selectedCaptchaFlowConnector - .preValidate(servletRequest, servletResponse); + .preValidate(servletRequest, servletResponse, selectedCaptchaProvider); if (captchaPreValidationResponse == null) { // Captcha connector failed to response. Default is success. @@ -127,7 +127,7 @@ public void doFilter(ServletRequest servletRequest, ServletResponse servletRespo if (captchaPreValidationResponse.isCaptchaValidationRequired()) { try { - boolean validCaptcha = selectedCaptchaFlowConnector.verifyCaptcha(servletRequest, servletResponse); + boolean validCaptcha = selectedCaptchaFlowConnector.verifyCaptcha(servletRequest, servletResponse, selectedCaptchaProvider); if (!validCaptcha) { log.warn("Captcha validation failed for the user."); httpResponse.sendRedirect(CaptchaUtil.getOnFailRedirectUrl(httpRequest.getHeader("referer"), @@ -167,7 +167,7 @@ public void doFilter(ServletRequest servletRequest, ServletResponse servletRespo doFilter(captchaPreValidationResponse, servletRequest, responseWrapper, filterChain); CaptchaPostValidationResponse postValidationResponse = selectedCaptchaFlowConnector - .postValidate(servletRequest, responseWrapper); + .postValidate(servletRequest, responseWrapper, selectedCaptchaProvider); // Check whether this attempt is failed if (postValidationResponse == null || postValidationResponse.isSuccessfulAttempt()) { From aa04350d0e154d0ed52e38ae8d323015a053b5d5 Mon Sep 17 00:00:00 2001 From: kaveesha Date: Thu, 23 Sep 2021 23:04:31 +0530 Subject: [PATCH 3/4] Add captcha configs --- .../connector/provider/CaptchaProvider.java | 29 ++++++++++ .../connector/provider/HCaptchaProvider.java | 56 ++++++++++++++++++ .../strategy/DefaultStrategyConnector.java | 40 +++++++++++++ .../connector/strategy/StrategyConnector.java | 19 +++++++ .../captcha/internal/CaptchaComponent.java | 7 +++ .../captcha/internal/CaptchaDataHolder.java | 24 ++++++++ .../identity/captcha/util/CaptchaConfigs.java | 57 +++++++++++++++++++ .../captcha/util/CaptchaConstants.java | 11 ++++ .../identity/captcha/util/CaptchaUtil.java | 18 ++++++ 9 files changed, 261 insertions(+) create mode 100644 components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/provider/CaptchaProvider.java create mode 100644 components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/provider/HCaptchaProvider.java create mode 100644 components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/strategy/DefaultStrategyConnector.java create mode 100644 components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/strategy/StrategyConnector.java create mode 100644 components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/util/CaptchaConfigs.java diff --git a/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/provider/CaptchaProvider.java b/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/provider/CaptchaProvider.java new file mode 100644 index 0000000000..b9e0d0e024 --- /dev/null +++ b/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/provider/CaptchaProvider.java @@ -0,0 +1,29 @@ +package org.wso2.carbon.identity.captcha.connector.provider; + +import org.wso2.carbon.identity.captcha.exception.CaptchaException; +import org.wso2.carbon.identity.captcha.util.CaptchaConfigs; +import org.wso2.carbon.identity.captcha.util.CaptchaConstants; + +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; + +/** + * Captcha Provider interface. + */ +public interface CaptchaProvider { + + String getName(); + + int getPriority(); + + void handleCaptchaProperties(CaptchaConfigs captchaConfigs); + + void init(); + + void setCaptchaParamsForPreValidation(ServletRequest servletRequest, ServletResponse servletResponse, + CaptchaConstants.Flow flow) throws CaptchaException; + + boolean verifyCaptcha(ServletRequest servletRequest, ServletResponse servletResponse) throws CaptchaException; + + void addPostValidationData(ServletRequest servletRequest); +} diff --git a/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/provider/HCaptchaProvider.java b/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/provider/HCaptchaProvider.java new file mode 100644 index 0000000000..06b5b20bbb --- /dev/null +++ b/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/provider/HCaptchaProvider.java @@ -0,0 +1,56 @@ +package org.wso2.carbon.identity.captcha.connector.provider; + +import org.wso2.carbon.identity.captcha.exception.CaptchaException; +import org.wso2.carbon.identity.captcha.internal.CaptchaDataHolder; +import org.wso2.carbon.identity.captcha.util.CaptchaConfigs; +import org.wso2.carbon.identity.captcha.util.CaptchaConstants; + +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; + +public class HCaptchaProvider implements CaptchaProvider{ + + @Override + public String getName() { + + return "HCaptcha"; + } + + @Override + public int getPriority() { + + return 0; + } + + @Override + public void handleCaptchaProperties(CaptchaConfigs captchaConfigs) { + + for (CaptchaConfigs captchaConfigs1: CaptchaDataHolder.getInstance().getCaptchaConfigs()){ + if (this.getName().equals(captchaConfigs.getCaptchaProviderName())){ + return captchaConfigs; + } + } + return null; + } + + @Override + public void init() { + + } + + @Override + public void setCaptchaParamsForPreValidation(ServletRequest servletRequest, ServletResponse servletResponse, CaptchaConstants.Flow flow) throws CaptchaException { + + } + + @Override + public boolean verifyCaptcha(ServletRequest servletRequest, ServletResponse servletResponse) throws CaptchaException { + + return false; + } + + @Override + public void addPostValidationData(ServletRequest servletRequest) { + + } +} diff --git a/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/strategy/DefaultStrategyConnector.java b/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/strategy/DefaultStrategyConnector.java new file mode 100644 index 0000000000..c8e36bcca7 --- /dev/null +++ b/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/strategy/DefaultStrategyConnector.java @@ -0,0 +1,40 @@ +package org.wso2.carbon.identity.captcha.connector.strategy; + +import org.wso2.carbon.identity.captcha.connector.provider.CaptchaProvider; +import org.wso2.carbon.identity.captcha.internal.CaptchaDataHolder; + +import java.util.List; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; + +public class DefaultStrategyConnector implements StrategyConnector{ + + @Override + public boolean canHandle(ServletRequest servletRequest, ServletResponse servletResponse) { + + return true; + } + + @Override + public int getPriority() { + + return 0; + } + + @Override + public CaptchaProvider getCaptchaProvider(ServletRequest servletRequest, ServletResponse servletResponse) { + + //loop all the registered providers and return the highest priority + + List captchaProviders = CaptchaDataHolder.getInstance().getCaptchaProviders(); + CaptchaProvider selectedCaptchaProvider = null; + + for(CaptchaProvider captchaProvider: captchaProviders){ + if (selectedCaptchaProvider == null || + captchaProvider.getPriority() > selectedCaptchaProvider.getPriority()) { + selectedCaptchaProvider = captchaProvider; + } + } + return selectedCaptchaProvider; + } +} diff --git a/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/strategy/StrategyConnector.java b/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/strategy/StrategyConnector.java new file mode 100644 index 0000000000..d7cda3d215 --- /dev/null +++ b/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/strategy/StrategyConnector.java @@ -0,0 +1,19 @@ +package org.wso2.carbon.identity.captcha.connector.strategy; + +import org.wso2.carbon.identity.captcha.connector.provider.CaptchaProvider; + +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; + +/** + * Strategy connector interface. + */ +public interface StrategyConnector { + + boolean canHandle(ServletRequest servletRequest, ServletResponse servletResponse); + + int getPriority(); + + CaptchaProvider getCaptchaProvider(ServletRequest servletRequest, ServletResponse servletResponse); + +} diff --git a/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/internal/CaptchaComponent.java b/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/internal/CaptchaComponent.java index eb084964b2..a9c44b9acd 100644 --- a/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/internal/CaptchaComponent.java +++ b/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/internal/CaptchaComponent.java @@ -22,6 +22,8 @@ import org.osgi.service.component.ComponentContext; import org.wso2.carbon.identity.application.authentication.framework.AuthenticationDataPublisher; import org.wso2.carbon.identity.captcha.connector.CaptchaConnector; +import org.wso2.carbon.identity.captcha.connector.provider.CaptchaProvider; +import org.wso2.carbon.identity.captcha.connector.provider.HCaptchaProvider; import org.wso2.carbon.identity.captcha.connector.recaptcha.PasswordRecoveryReCaptchaConnector; import org.wso2.carbon.identity.captcha.connector.recaptcha.ResendConfirmationReCaptchaConnector; import org.wso2.carbon.identity.captcha.connector.recaptcha.SSOLoginReCaptchaConfig; @@ -76,6 +78,11 @@ protected void activate(ComponentContext context) { captchaConnector = new ResendConfirmationReCaptchaConnector(); captchaConnector.init(CaptchaDataHolder.getInstance().getIdentityGovernanceService()); CaptchaDataHolder.getInstance().addCaptchaConnector(captchaConnector); + + //Register Captcha Providers + CaptchaProvider captchaProvider = new HCaptchaProvider(); + CaptchaDataHolder.getInstance().addCaptchaProvider(captchaProvider); + AuthenticationDataPublisher failedLoginAttemptValidator = new FailLoginAttemptValidator(); context.getBundleContext().registerService(AuthenticationDataPublisher.class, failedLoginAttemptValidator, null); 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 3d5f532579..14d1705f90 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 @@ -19,6 +19,8 @@ package org.wso2.carbon.identity.captcha.internal; import org.wso2.carbon.identity.captcha.connector.CaptchaConnector; +import org.wso2.carbon.identity.captcha.connector.provider.CaptchaProvider; +import org.wso2.carbon.identity.captcha.util.CaptchaConfigs; import org.wso2.carbon.identity.governance.IdentityGovernanceService; import org.wso2.carbon.identity.handler.event.account.lock.service.AccountLockService; import org.wso2.carbon.user.core.service.RealmService; @@ -57,6 +59,10 @@ public class CaptchaDataHolder { private List captchaConnectors = new ArrayList<>(); + private List captchaProviders = new ArrayList<>(); + + private List captchaConfigs = new ArrayList<>(); + private Map ssoLoginReCaptchaConnectorPropertyMap = new HashMap<>(); private Map pathBasedReCaptchaConnectorPropertyMap = new HashMap<>(); @@ -168,6 +174,24 @@ public void addCaptchaConnector(CaptchaConnector captchaConnector) { this.captchaConnectors.add(captchaConnector); } + public List getCaptchaProviders() { + + return captchaProviders; + } + + public void addCaptchaProvider(CaptchaProvider captchaProvider) { + + this.captchaProviders.add(captchaProvider); + } + + public List getCaptchaConfigs() { + return captchaConfigs; + } + + public void addCaptchaConfigs(CaptchaConfigs captchaConfigs) { + this.captchaConfigs.add(captchaConfigs); + } + public void setRealmService(RealmService realmService) { this.realmService = realmService; } diff --git a/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/util/CaptchaConfigs.java b/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/util/CaptchaConfigs.java new file mode 100644 index 0000000000..3ea97be00a --- /dev/null +++ b/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/util/CaptchaConfigs.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you 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 java.util.Map; + +/** + * Captcha Configs class. + */ +public class CaptchaConfigs { + + private String captchaProviderName; + + private Map captchaProperties; + + public CaptchaConfigs(String captchaProviderName, Map captchaProperties) { + + this.captchaProviderName = captchaProviderName; + this.captchaProperties = captchaProperties; + } + + public String getCaptchaProviderName() { + + return captchaProviderName; + } + + public void setCaptchaProviderName(String captchaProviderName) { + + this.captchaProviderName = captchaProviderName; + } + + public Map getCaptchaProperties() { + + return captchaProperties; + } + + public void setCaptchaProperties(Map captchaProperties) { + + this.captchaProperties = captchaProperties; + } +} 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 8d4f53198b..8c6fe95448 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 @@ -51,6 +51,17 @@ public class CaptchaConstants { public static final String BASIC_AUTH_MECHANISM = "basic"; + public static final String MULTIPLE_CAPTCHA_ENABLED = "captcha."; + + public enum Flow{ + + PASSWORD_RECOVERY_FLOW, + SSO_LOGIN_FLOW, + USERNAME_RECOVERY_FLOW, + SELF_SIGNUP_FLOW, + RESEND_CONFIRMATION_FLOW + } + /** * Captcha Connector configuration constants from the identity.xml. */ 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 4c5dc7e74c..4918810728 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 @@ -43,6 +43,7 @@ import org.wso2.carbon.identity.application.authentication.framework.context.AuthenticationContext; import org.wso2.carbon.identity.application.common.model.Property; import org.wso2.carbon.identity.application.common.model.User; +import org.wso2.carbon.identity.captcha.connector.provider.CaptchaProvider; import org.wso2.carbon.identity.captcha.exception.CaptchaClientException; import org.wso2.carbon.identity.captcha.exception.CaptchaException; import org.wso2.carbon.identity.captcha.exception.CaptchaServerException; @@ -108,6 +109,23 @@ public static void buildReCaptchaFilterProperties() { if (StringUtils.isNotBlank(reCaptchaFailedRedirectUrls)) { CaptchaDataHolder.getInstance().setReCaptchaErrorRedirectUrls(reCaptchaFailedRedirectUrls); } + for(int i = 1; properties.getProperty(CaptchaConstants.MULTIPLE_CAPTCHA_ENABLED + i +".enabled") != null; i++) { + //do something + boolean multipleCaptchaEnabled = Boolean + .valueOf(properties.getProperty(CaptchaConstants.MULTIPLE_CAPTCHA_ENABLED + i +".enabled")); + String name = String. + valueOf(properties.getProperty(CaptchaConstants.MULTIPLE_CAPTCHA_ENABLED + i +".name")); + Map captchaProperties = new HashMap<>(); + captchaProperties.put("api",String. + valueOf(properties.getProperty(CaptchaConstants.MULTIPLE_CAPTCHA_ENABLED + i +".api"))); + CaptchaConfigs captchaConfigs = new CaptchaConfigs(name, captchaProperties); + CaptchaDataHolder.getInstance().addCaptchaConfigs(captchaConfigs); + } + + List captchaProviders = CaptchaDataHolder.getInstance().getCaptchaProviders(); + for(CaptchaProvider captchaProvider: captchaProviders){ + captchaProvider.init(); + } if (reCaptchaEnabled) { CaptchaDataHolder.getInstance().setReCaptchaEnabled(true); From 8c51c5f9318ea19c4cbceb7b795b12ae246e05d4 Mon Sep 17 00:00:00 2001 From: kaveesha Date: Tue, 28 Sep 2021 08:20:58 +0530 Subject: [PATCH 4/4] Add captcha configs --- .../captcha/connector/CaptchaConnector.java | 1 + .../captcha/connector/CaptchaProvider.java | 28 ------ .../connector/kaptcha/KaptchaConnector.java | 67 ------------- .../kaptcha/KaptchaImageProvider.java | 92 ------------------ .../connector/provider/CaptchaProvider.java | 25 ++++- .../connector/provider/HCaptchaProvider.java | 88 ++++++++++++++++- .../connector/provider/ReCaptchaProvider.java | 95 +++++++++++++++++++ .../PasswordRecoveryReCaptchaConnector.java | 11 ++- .../ResendConfirmationReCaptchaConnector.java | 24 +++++ .../SelfSignUpReCaptchaConnector.java | 12 ++- .../UsernameRecoveryReCaptchaConnector.java | 5 +- .../recaptchaRevamp/RecaptchaConnector.java | 80 ---------------- .../strategy/DefaultStrategyConnector.java | 21 ++++ .../connector/strategy/StrategyConnector.java | 18 ++++ .../captcha/filter/CaptchaFilter.java | 9 +- .../captcha/internal/CaptchaDataHolder.java | 2 +- .../strategy/AbstractStrategyConnector.java | 4 - .../strategy/DefaultStrategyConnector.java | 24 ----- .../strategy/FlowBasedStrategyConnector.java | 24 ----- .../LocationBasedStrategyConnector.java | 50 ---------- .../captcha/strategy/StrategyConnector.java | 17 ---- .../captcha/util/CaptchaConstants.java | 13 +++ .../identity/captcha/util/CaptchaUtil.java | 59 ++++++++---- 23 files changed, 346 insertions(+), 423 deletions(-) delete mode 100644 components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/CaptchaProvider.java delete mode 100644 components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/kaptcha/KaptchaConnector.java delete mode 100644 components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/kaptcha/KaptchaImageProvider.java create mode 100644 components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/provider/ReCaptchaProvider.java delete mode 100644 components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/recaptchaRevamp/RecaptchaConnector.java delete mode 100644 components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/strategy/AbstractStrategyConnector.java delete mode 100644 components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/strategy/DefaultStrategyConnector.java delete mode 100644 components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/strategy/FlowBasedStrategyConnector.java delete mode 100644 components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/strategy/LocationBasedStrategyConnector.java delete mode 100644 components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/strategy/StrategyConnector.java diff --git a/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/CaptchaConnector.java b/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/CaptchaConnector.java index 30de1dd90b..1ad3108f9c 100644 --- a/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/CaptchaConnector.java +++ b/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/CaptchaConnector.java @@ -18,6 +18,7 @@ package org.wso2.carbon.identity.captcha.connector; +import org.wso2.carbon.identity.captcha.connector.provider.CaptchaProvider; import org.wso2.carbon.identity.captcha.exception.CaptchaException; import org.wso2.carbon.identity.governance.IdentityGovernanceService; diff --git a/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/CaptchaProvider.java b/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/CaptchaProvider.java deleted file mode 100644 index a6f6084dbf..0000000000 --- a/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/CaptchaProvider.java +++ /dev/null @@ -1,28 +0,0 @@ -package org.wso2.carbon.identity.captcha.connector; - -import org.wso2.carbon.identity.captcha.exception.CaptchaException; - -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; - -public interface CaptchaProvider { - - void preValidateForSelfSignUp(ServletRequest servletRequest, ServletResponse servletResponse) throws - CaptchaException; - - void preValidateForSSOLogin(ServletRequest servletRequest, ServletResponse servletResponse) throws - CaptchaException; - - void preValidateForUsernameRecovery(ServletRequest servletRequest, ServletResponse servletResponse) throws - CaptchaException; - - void preValidateForPasswordRecovery(ServletRequest servletRequest, ServletResponse servletResponse) throws - CaptchaException; - - boolean verifyCaptcha(ServletRequest servletRequest, ServletResponse servletResponse) throws CaptchaException; - - void postValidateForSSOLogin(ServletRequest servletRequest, ServletResponse servletResponse) throws - CaptchaException; - - void addPostValidationData(ServletRequest servletRequest); -} diff --git a/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/kaptcha/KaptchaConnector.java b/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/kaptcha/KaptchaConnector.java deleted file mode 100644 index da1fec136d..0000000000 --- a/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/kaptcha/KaptchaConnector.java +++ /dev/null @@ -1,67 +0,0 @@ -package org.wso2.carbon.identity.captcha.connector.kaptcha; - -import org.apache.commons.lang.StringUtils; -import org.wso2.carbon.identity.application.authentication.framework.context.AuthenticationContext; -import org.wso2.carbon.identity.application.authentication.framework.util.FrameworkConstants; -import org.wso2.carbon.identity.application.authentication.framework.util.FrameworkUtils; -import org.wso2.carbon.identity.captcha.connector.CaptchaProvider; -import org.wso2.carbon.identity.captcha.exception.CaptchaException; - -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; - -public class KaptchaConnector implements CaptchaProvider { - - - @Override - public void preValidateForSelfSignUp(ServletRequest servletRequest, ServletResponse servletResponse) throws CaptchaException { - - } - - @Override - public void preValidateForSSOLogin(ServletRequest servletRequest, ServletResponse servletResponse) throws CaptchaException { - - } - - @Override - public void preValidateForUsernameRecovery(ServletRequest servletRequest, ServletResponse servletResponse) throws CaptchaException { - - } - - @Override - public void preValidateForPasswordRecovery(ServletRequest servletRequest, ServletResponse servletResponse) throws CaptchaException { - - } - - @Override - public boolean verifyCaptcha(ServletRequest servletRequest, ServletResponse servletResponse) throws CaptchaException { - AuthenticationContext context = getAuthenticationContext(servletRequest); - String generatedCaptchaText = (String) context.getProperty("CAPTCHA_TEXT"); - String userCaptcha = servletRequest.getParameter("CAPTCHA_TEXT"); - return StringUtils.equalsIgnoreCase(generatedCaptchaText, userCaptcha); - } - - protected AuthenticationContext getAuthenticationContext(ServletRequest request) { - - String sessionDataKey = request.getParameter(FrameworkConstants.SESSION_DATA_KEY); - if (StringUtils.isNotEmpty(sessionDataKey)) { - return FrameworkUtils.getAuthenticationContextFromCache(sessionDataKey); - } - return null; - } - - - - @Override - public void postValidateForSSOLogin(ServletRequest servletRequest, ServletResponse servletResponse) throws CaptchaException { - - } - - - @Override - public void addPostValidationData(ServletRequest servletRequest) { - - } - - -} diff --git a/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/kaptcha/KaptchaImageProvider.java b/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/kaptcha/KaptchaImageProvider.java deleted file mode 100644 index 6d8fd3767c..0000000000 --- a/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/kaptcha/KaptchaImageProvider.java +++ /dev/null @@ -1,92 +0,0 @@ -package org.wso2.carbon.identity.captcha.connector.kaptcha; - -import com.google.code.kaptcha.Producer; -import com.google.code.kaptcha.util.Config; -import org.apache.commons.codec.binary.Base64; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.wso2.carbon.identity.application.authentication.framework.context.AuthenticationContext; -import org.wso2.carbon.identity.application.authentication.framework.util.FrameworkUtils; -import org.wso2.carbon.identity.captcha.exception.CaptchaException; - -import java.awt.image.BufferedImage; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.util.Properties; -import javax.imageio.ImageIO; -import javax.servlet.http.HttpSession; - -public class KaptchaImageProvider { - - private static final Log LOG = LogFactory.getLog(KaptchaImageProvider.class); - - public String generateImageForSSO(String sessionDataKey) { - // String sessionDataKey = "iVBORw0KGgoAAAANSUhEUgAAAMgAAAAyCAYAAAAZUZThAAAGlUlEQVR42u1cC4hUVRg+WWoYPWwzM1PpbbXVUpmZ2QsJEYmwyNJMrVCJit4hW0SWvTMrsXcRJgtWq6mlZg9CIkQrMzU1SirMamlbS1zbZq3/536Dx7Nn7r0zc+fujPt98OHOvedx58z5zv8452oMQRAEQRAEQRAEQRAEQRAEQRAEkTT+K5Icg71vPAgKhAIhKBAKhKBAKBCCAqFAiDKaHBwDCqTDYT/hZOES4V/CFuGOEv7IVcKJwjnCNcLt6FPZJFwmnCasKWOBEB1gFVScLNyU0iqowpgJIcTt7xM8YxaNzv0vi3ieVU5bjRQIBWKzn7AhJTdhiPC3Al2TncKxaKfec69Q7HTaqqdAKBCby1Lyoy8Icdny4RjhdM/1XgU8U09PO9PzGLvZwtX4Xi0QWyPGVNsZymnXMQPNl+GSZSeGxiyfCh8VVueYiA0J9a2T8A7P9eEFjMkITzujEh67HxFrERUuEF0JJwh7W3W6FDgp5kMUWbweUlbFVSvsg7KdYG0+D6mz0nNtQgFjMtnTTk2JFhdNfnTnNKxMgcwsgeXRWGMAJn4mxBoMCMmqLQ9pv9Vj1fKFK9wMBFoq6/uZcH9OxcoSyPISumYqkqkh9x+I6HtwSN2tHqtlY4KnzjinzCKPFS21e/okp2JlCWRkiWOX30PuVUf03Smk7i/O5wan7uwcQbWNpoj77hioKGdhzPpY1kZd0Us92TUfM5Y7SVSAQHrGrLcEq/IJzsTQ4HhOwqtsHDZ7rtnu0VrP/bUR8dXtOcZAExDDcrhfLsbGePZaTsfKEUjUjz4foojCMNN2T6GU9G00DopILmQQ2+Ry34YnNNbPRjz7+5yOlSOQJDGlHSyJL0U73BGFXeYSlBnlqV+V0DhURzxnE6dj5QgkyaxKr5QFsd35/KBHqJo5WmN9vhNlppm26eak0CmG9evo2NeUWdo71491ekr9+NilyL7cLFQdrr9tXZthghRw9vNclJnr1F1EgRT1fdX6nig8FwmL64R3Cx8XviZcgMVqo/AP4S78W/YCGZ1gHz3yFMiIIvub5bS3CtcbnSyd7U5tQZnVTt1ZCY5DTQW7WPtgZT9eeA5+o/GwvHpS4hXEpbo98C2yh60FegCtMRMf7SqQaQn2cYvJf3c5X/SzrMAY03bjsbcnrnCv9fDEJlfn6K/O7Hm6IA5mRnzv+hR/94OFxwoHIja7Ftm6h4Uv4Vk0S7fOBPtWmZTc41ZYkO7lLpB5CbU/GH58vgM1JWb7mkl70cpeGWSt3PZusv7eZNXfYvZM57r1BoaM206snnEORI6L8Z1vLXCMDxQebYLTB5o1vAZtPSR8Aa6lvhrwjQn2bFpSmuzqLv0p/M4ER4QWmuCUwhPCe4Q3CC8TnifsLzysnCxHlEC2CbvmqLMe/ruurhcJuzn3q2CC34hYeRZGDPBHGEB7NemGFa/W+M9lZX1ft1/7vRZ748/eq1lv4h0xMZ5yCyCC/qbtftD8mIkF/Z4HwBqeiczaaFjgqXD35mJcvoa4/0kx+aFz4nvhCuF7+H2fwmI2EW7r+SZ4R+dwszt1vldmsbK++1FFBty5qC5Kkqd53fT0hpAy9tGS60PKrU8o6RCHutI2pzjZ1apvNsEBz8VYNJ7GwqOHNa8QXojU9BHCzkzz5j43NSThybHZ7N5b0LZ3lEAgdSFl+lvlqiNEnEVXxBya3bvYtO++js/66PH5L4RLYRWfEd4nvFF4JZ75NOGRIZ4BkYdAWpy/b05IICs8PvsgJxYohLqnYb+IVBuycnbGM5yKVTKXm/IzxPx3ipN9B/r9ygQvWKlInxPejzjqKnzPGlh3ngJuJ4Hoyv6rJxu00RR+gndKiE9/EALefK3JxwhKT4H/OxL+8Jsm/lGU9uA6jIfGGWcI+3piOaKMBWKwQq0sMmWn5v8H4Qcw/bpBd69wkvByK6jrgaC2L7JJi5FPb7YC7gwCxQYIbhsyJWmd8dqKTJBmhN4SPm+CXXoV9qvCD7EP0AShZ1BvO+K5Ovj3PLW7F6GXSfewYRr8FwJbh1z/O0gV697PbdgT0OzT2cJjYN0IIhRjEKSeZLkyk+Drz4BLsxSB4k8JB95R71E0wNosx/6NpqAfMcE76uORctbd3+OEh5hgV5gg2h3ZnP5ZJtjAGosVOrtbOw+TeoPlKu1CnKPnc96F6/KY8C4TnOPR8zx6rkc3CA/lZCc6Croju8T/wIAgCIIgCIIgCIIgCIIgCIIgCIIgCIIoHP8DrVNh47xiVYYAAAAASUVORK5CYII="; - Config config = new Config(new Properties()); - Producer captchaProducer = config.getProducerImpl(); - String captchaText = captchaProducer.createText(); - try { - byte[] encodedCaptchaImage = generateBase64EncodedCaptchaImage(captchaProducer, captchaText); - setCaptchaTextToAuthenticationContext(sessionDataKey, captchaText); - return new String(encodedCaptchaImage); - } catch (IOException e) { - LOG.error("Error when creating captcha image for session data key: " + sessionDataKey); - return null; - } catch (CaptchaException e) { - LOG.error("Error when setting captcha text to context " + sessionDataKey); - return null; - } - } - - /** - * Generate a captcha image and set the text value in the session as a attribute - * @param session The session object to set the captcha answer as an attribute - * @return - */ - public String generateImageForSession(HttpSession session) { - - Config config = new Config(new Properties()); - Producer captchaProducer = config.getProducerImpl(); - String captchaText = captchaProducer.createText(); - try { - byte[] encodedCaptchaImage = generateBase64EncodedCaptchaImage(captchaProducer, captchaText); - setCaptchaTextToSession(session, captchaText); - return new String(encodedCaptchaImage); - } catch (IOException e) { - LOG.error("Error when creating captcha image for session"); - return null; - } - } - - private byte[] generateBase64EncodedCaptchaImage(Producer captchaProducer, String captchaText) throws IOException { - - BufferedImage image = captchaProducer.createImage(captchaText); - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - ImageIO.write(image, "jpg", baos); - return Base64.encodeBase64(baos.toByteArray()); - - } - - private void setCaptchaTextToAuthenticationContext(String sessionDataKey, String captchaText) throws - CaptchaException { - - AuthenticationContext context = FrameworkUtils.getAuthenticationContextFromCache(sessionDataKey); - if (context != null) { - context.setProperty("captchaAnswer", captchaText); - if (LOG.isDebugEnabled()) { - LOG.debug(String.format("Captcha text set for session data key : %s, captcha text: %s", - sessionDataKey, captchaText)); - } - return; - } - if (LOG.isDebugEnabled()) { - LOG.debug("Invalid authentication context Id: " + sessionDataKey); - } - throw new CaptchaException("Invalid authentication context id."); - } - - private void setCaptchaTextToSession(HttpSession session, String captchaText) { - - session.setAttribute("captchaAnswer", captchaText); - } -} diff --git a/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/provider/CaptchaProvider.java b/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/provider/CaptchaProvider.java index b9e0d0e024..1375526a6c 100644 --- a/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/provider/CaptchaProvider.java +++ b/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/provider/CaptchaProvider.java @@ -1,3 +1,21 @@ +/* + * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you 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.connector.provider; import org.wso2.carbon.identity.captcha.exception.CaptchaException; @@ -16,13 +34,14 @@ public interface CaptchaProvider { int getPriority(); - void handleCaptchaProperties(CaptchaConfigs captchaConfigs); - - void init(); + CaptchaConfigs getCaptchaProperties(); void setCaptchaParamsForPreValidation(ServletRequest servletRequest, ServletResponse servletResponse, CaptchaConstants.Flow flow) throws CaptchaException; + void setCaptchaParamsForPostValidation(ServletRequest servletRequest, ServletResponse servletResponse, + CaptchaConstants.Flow flow) throws CaptchaException; + boolean verifyCaptcha(ServletRequest servletRequest, ServletResponse servletResponse) throws CaptchaException; void addPostValidationData(ServletRequest servletRequest); diff --git a/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/provider/HCaptchaProvider.java b/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/provider/HCaptchaProvider.java index 06b5b20bbb..c849836543 100644 --- a/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/provider/HCaptchaProvider.java +++ b/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/provider/HCaptchaProvider.java @@ -1,13 +1,54 @@ +/* + * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you 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.connector.provider; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang.StringUtils; +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.client.entity.UrlEncodedFormEntity; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.message.BasicNameValuePair; +import org.wso2.carbon.identity.captcha.exception.CaptchaClientException; import org.wso2.carbon.identity.captcha.exception.CaptchaException; +import org.wso2.carbon.identity.captcha.exception.CaptchaServerException; import org.wso2.carbon.identity.captcha.internal.CaptchaDataHolder; import org.wso2.carbon.identity.captcha.util.CaptchaConfigs; import org.wso2.carbon.identity.captcha.util.CaptchaConstants; +import org.wso2.carbon.identity.captcha.util.CaptchaUtil; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.List; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +/** + * HCaptchaProvider + */ public class HCaptchaProvider implements CaptchaProvider{ @Override @@ -23,9 +64,9 @@ public int getPriority() { } @Override - public void handleCaptchaProperties(CaptchaConfigs captchaConfigs) { + public CaptchaConfigs getCaptchaProperties() { - for (CaptchaConfigs captchaConfigs1: CaptchaDataHolder.getInstance().getCaptchaConfigs()){ + for (CaptchaConfigs captchaConfigs: CaptchaDataHolder.getInstance().getCaptchaConfigs()){ if (this.getName().equals(captchaConfigs.getCaptchaProviderName())){ return captchaConfigs; } @@ -34,19 +75,56 @@ public void handleCaptchaProperties(CaptchaConfigs captchaConfigs) { } @Override - public void init() { + public void setCaptchaParamsForPreValidation(ServletRequest servletRequest, ServletResponse servletResponse, CaptchaConstants.Flow flow) throws CaptchaException { } @Override - public void setCaptchaParamsForPreValidation(ServletRequest servletRequest, ServletResponse servletResponse, CaptchaConstants.Flow flow) throws CaptchaException { + public void setCaptchaParamsForPostValidation(ServletRequest servletRequest, ServletResponse servletResponse, CaptchaConstants.Flow flow) throws CaptchaException { } @Override public boolean verifyCaptcha(ServletRequest servletRequest, ServletResponse servletResponse) throws CaptchaException { - return false; + String HCaptchaResponse = ((HttpServletRequest) servletRequest).getHeader("h-captcha-response"); + if (StringUtils.isBlank(HCaptchaResponse)) { + throw new CaptchaClientException("reCaptcha response is not available in the request."); + } + + CloseableHttpClient httpclient = HttpClientBuilder.create().useSystemProperties().build(); + HttpPost httppost = new HttpPost(getCaptchaProperties().getCaptchaProperties().get("VerifyUrl").toString()); + + + List params = Arrays.asList(new BasicNameValuePair("secret", getCaptchaProperties() + .getCaptchaProperties().get("SecretKey").toString()), new BasicNameValuePair("response", HCaptchaResponse)); + httppost.setEntity(new UrlEncodedFormEntity(params, StandardCharsets.UTF_8)); + + HttpResponse response; + try { + response = httpclient.execute(httppost); + } catch (IOException e) { + throw new CaptchaServerException("Unable to get the verification response.", e); + } + + HttpEntity entity = response.getEntity(); + if (entity == null) { + throw new CaptchaServerException("reCaptcha verification response is not received."); + } + + try { + try (InputStream in = entity.getContent()) { + JsonObject verificationResponse = new JsonParser().parse(IOUtils.toString(in)).getAsJsonObject(); + if (verificationResponse == null || verificationResponse.get("success") == null || + !verificationResponse.get("success").getAsBoolean()) { + throw new CaptchaClientException("Captcha verification failed. Please try again."); + } + } + } catch (IOException e) { + throw new CaptchaServerException("Unable to read the verification response.", e); + } + + return true; } @Override diff --git a/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/provider/ReCaptchaProvider.java b/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/provider/ReCaptchaProvider.java new file mode 100644 index 0000000000..b0784e3007 --- /dev/null +++ b/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/provider/ReCaptchaProvider.java @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you 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.connector.provider; + +import org.apache.commons.lang.StringUtils; +import org.wso2.carbon.identity.captcha.exception.CaptchaClientException; +import org.wso2.carbon.identity.captcha.exception.CaptchaException; +import org.wso2.carbon.identity.captcha.internal.CaptchaDataHolder; +import org.wso2.carbon.identity.captcha.util.CaptchaConfigs; +import org.wso2.carbon.identity.captcha.util.CaptchaConstants; +import org.wso2.carbon.identity.captcha.util.CaptchaUtil; + +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * RecaptchaProvider + */ +public class ReCaptchaProvider implements CaptchaProvider{ + + @Override + public String getName() { + + return "Recaptcha"; + } + + @Override + public int getPriority() { + + return 0; + } + + @Override + public CaptchaConfigs getCaptchaProperties() { + + for (CaptchaConfigs captchaConfigs: CaptchaDataHolder.getInstance().getCaptchaConfigs()){ + if (this.getName().equals(captchaConfigs.getCaptchaProviderName())){ + return captchaConfigs; + } + } + return null; + } + + @Override + public void setCaptchaParamsForPreValidation(ServletRequest servletRequest, ServletResponse servletResponse, CaptchaConstants.Flow flow) throws CaptchaException { + HttpServletResponse httpServletResponse = ((HttpServletResponse) servletResponse); + switch (flow){ + case SELF_SIGNUP_FLOW: + case PASSWORD_RECOVERY_FLOW: + httpServletResponse.setHeader("reCaptchaKey", (String) getCaptchaProperties().getCaptchaProperties().get("SiteKey")); + httpServletResponse.setHeader("reCaptchaAPI", (String) getCaptchaProperties().getCaptchaProperties().get("API")); + break; + } + + } + + @Override + public void setCaptchaParamsForPostValidation(ServletRequest servletRequest, ServletResponse servletResponse, CaptchaConstants.Flow flow) throws CaptchaException { + + } + + @Override + public boolean verifyCaptcha(ServletRequest servletRequest, ServletResponse servletResponse) throws CaptchaException { + + String reCaptchaResponse = ((HttpServletRequest) servletRequest).getHeader("g-recaptcha-response"); + if (StringUtils.isBlank(reCaptchaResponse)) { + throw new CaptchaClientException("reCaptcha response is not available in the request."); + } + + return CaptchaUtil.isValidCaptcha(reCaptchaResponse); + } + + @Override + public void addPostValidationData(ServletRequest servletRequest) { + + } +} diff --git a/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/recaptcha/PasswordRecoveryReCaptchaConnector.java b/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/recaptcha/PasswordRecoveryReCaptchaConnector.java index 03ce9d4e95..0cca6fb145 100644 --- a/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/recaptcha/PasswordRecoveryReCaptchaConnector.java +++ b/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/recaptcha/PasswordRecoveryReCaptchaConnector.java @@ -29,11 +29,12 @@ import org.wso2.carbon.identity.application.common.model.User; import org.wso2.carbon.identity.captcha.connector.CaptchaPostValidationResponse; import org.wso2.carbon.identity.captcha.connector.CaptchaPreValidationResponse; -import org.wso2.carbon.identity.captcha.connector.CaptchaProvider; +import org.wso2.carbon.identity.captcha.connector.provider.CaptchaProvider; import org.wso2.carbon.identity.captcha.exception.CaptchaClientException; import org.wso2.carbon.identity.captcha.exception.CaptchaException; import org.wso2.carbon.identity.captcha.exception.CaptchaServerException; import org.wso2.carbon.identity.captcha.internal.CaptchaDataHolder; +import org.wso2.carbon.identity.captcha.util.CaptchaConstants; import org.wso2.carbon.identity.captcha.util.CaptchaHttpServletRequestWrapper; import org.wso2.carbon.identity.captcha.util.CaptchaUtil; import org.wso2.carbon.identity.captcha.util.EnabledSecurityMechanism; @@ -409,7 +410,7 @@ public CaptchaPreValidationResponse preValidate(ServletRequest servletRequest, S if (currentFailedAttempts > maxFailedAttempts) { if (initializationFlow) { httpServletResponse.setHeader("reCaptcha", "true"); - captchaProvider.preValidateForPasswordRecovery(servletRequest,servletResponse); + captchaProvider.setCaptchaParamsForPreValidation(servletRequest,servletResponse, CaptchaConstants.Flow.PASSWORD_RECOVERY_FLOW); } else { preValidationResponse.setCaptchaValidationRequired(true); preValidationResponse.setMaxFailedLimitReached(true); @@ -435,6 +436,12 @@ public boolean verifyCaptcha(ServletRequest servletRequest, ServletResponse serv return CaptchaUtil.isValidCaptcha(reCaptchaResponse); } + public boolean verifyCaptcha(ServletRequest servletRequest, ServletResponse servletResponse, CaptchaProvider captchaProvider) + throws CaptchaException { + + return captchaProvider.verifyCaptcha(servletRequest, servletResponse); + } + @Override public CaptchaPostValidationResponse postValidate(ServletRequest servletRequest, ServletResponse servletResponse) throws CaptchaException { diff --git a/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/recaptcha/ResendConfirmationReCaptchaConnector.java b/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/recaptcha/ResendConfirmationReCaptchaConnector.java index ccd2c0177b..efde77ce0a 100644 --- a/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/recaptcha/ResendConfirmationReCaptchaConnector.java +++ b/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/recaptcha/ResendConfirmationReCaptchaConnector.java @@ -24,6 +24,7 @@ import org.wso2.carbon.identity.application.common.model.Property; import org.wso2.carbon.identity.captcha.connector.CaptchaPostValidationResponse; import org.wso2.carbon.identity.captcha.connector.CaptchaPreValidationResponse; +import org.wso2.carbon.identity.captcha.connector.provider.CaptchaProvider; import org.wso2.carbon.identity.captcha.exception.CaptchaClientException; import org.wso2.carbon.identity.captcha.exception.CaptchaException; import org.wso2.carbon.identity.captcha.util.CaptchaUtil; @@ -107,6 +108,24 @@ public CaptchaPreValidationResponse preValidate(ServletRequest servletRequest, S return preValidationResponse; } + public CaptchaPreValidationResponse preValidate(ServletRequest servletRequest, ServletResponse servletResponse, CaptchaProvider captchaProvider) + throws CaptchaException { + + CaptchaPreValidationResponse preValidationResponse = new CaptchaPreValidationResponse(); + String path = ((HttpServletRequest) servletRequest).getRequestURI(); + HttpServletResponse httpServletResponse = ((HttpServletResponse) servletResponse); + + if (CaptchaUtil.isPathAvailable(path, RESEND_CONFIRMATION_URL)) { + httpServletResponse.setHeader("reCaptchaResend", "true"); + preValidationResponse.setCaptchaValidationRequired(true); + Map params = new HashMap<>(); + params.put("errorMessage", "recaptcha.fail.message"); + preValidationResponse.setCaptchaAttributes(params); + preValidationResponse.setCaptchaValidationRequired(true); + } + return preValidationResponse; + } + @Override public boolean verifyCaptcha(ServletRequest servletRequest, ServletResponse servletResponse) throws CaptchaException { @@ -118,6 +137,11 @@ public boolean verifyCaptcha(ServletRequest servletRequest, ServletResponse serv return CaptchaUtil.isValidCaptcha(reCaptchaResponse); } + public boolean verifyCaptcha(ServletRequest servletRequest, ServletResponse servletResponse, CaptchaProvider captchaProvider) + throws CaptchaException { + + return captchaProvider.verifyCaptcha(servletRequest, servletResponse); + } @Override public CaptchaPostValidationResponse postValidate(ServletRequest servletRequest, ServletResponse servletResponse) throws CaptchaException { diff --git a/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/recaptcha/SelfSignUpReCaptchaConnector.java b/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/recaptcha/SelfSignUpReCaptchaConnector.java index 892940b5c0..9b5cfa1df0 100644 --- a/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/recaptcha/SelfSignUpReCaptchaConnector.java +++ b/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/recaptcha/SelfSignUpReCaptchaConnector.java @@ -24,10 +24,11 @@ import org.wso2.carbon.identity.application.common.model.Property; import org.wso2.carbon.identity.captcha.connector.CaptchaPostValidationResponse; import org.wso2.carbon.identity.captcha.connector.CaptchaPreValidationResponse; -import org.wso2.carbon.identity.captcha.connector.CaptchaProvider; +import org.wso2.carbon.identity.captcha.connector.provider.CaptchaProvider; import org.wso2.carbon.identity.captcha.exception.CaptchaClientException; import org.wso2.carbon.identity.captcha.exception.CaptchaException; import org.wso2.carbon.identity.captcha.internal.CaptchaDataHolder; +import org.wso2.carbon.identity.captcha.util.CaptchaConstants; import org.wso2.carbon.identity.captcha.util.CaptchaUtil; import org.wso2.carbon.identity.governance.IdentityGovernanceService; @@ -140,7 +141,7 @@ public CaptchaPreValidationResponse preValidate(ServletRequest servletRequest, S preValidationResponse.setMaxFailedLimitReached(true); } - captchaProvider.preValidateForSelfSignUp(servletRequest, servletResponse); + captchaProvider.setCaptchaParamsForPreValidation(servletRequest,servletResponse, CaptchaConstants.Flow.SELF_SIGNUP_FLOW); return preValidationResponse; } @@ -157,6 +158,13 @@ public boolean verifyCaptcha(ServletRequest servletRequest, ServletResponse serv return CaptchaUtil.isValidCaptcha(reCaptchaResponse); } + public boolean verifyCaptcha(ServletRequest servletRequest, ServletResponse servletResponse, CaptchaProvider captchaProvider) + throws CaptchaException { + + return captchaProvider.verifyCaptcha(servletRequest, servletResponse); + + } + @Override public CaptchaPostValidationResponse postValidate(ServletRequest servletRequest, ServletResponse servletResponse) throws CaptchaException { diff --git a/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/recaptcha/UsernameRecoveryReCaptchaConnector.java b/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/recaptcha/UsernameRecoveryReCaptchaConnector.java index af7154a2b7..556692ca9a 100644 --- a/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/recaptcha/UsernameRecoveryReCaptchaConnector.java +++ b/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/recaptcha/UsernameRecoveryReCaptchaConnector.java @@ -24,7 +24,7 @@ import org.wso2.carbon.identity.application.common.model.Property; import org.wso2.carbon.identity.captcha.connector.CaptchaPostValidationResponse; import org.wso2.carbon.identity.captcha.connector.CaptchaPreValidationResponse; -import org.wso2.carbon.identity.captcha.connector.CaptchaProvider; +import org.wso2.carbon.identity.captcha.connector.provider.CaptchaProvider; import org.wso2.carbon.identity.captcha.exception.CaptchaClientException; import org.wso2.carbon.identity.captcha.exception.CaptchaException; import org.wso2.carbon.identity.captcha.util.CaptchaUtil; @@ -107,9 +107,10 @@ public CaptchaPreValidationResponse preValidate(ServletRequest servletRequest, S CaptchaPreValidationResponse preValidationResponse = new CaptchaPreValidationResponse(); String path = ((HttpServletRequest) servletRequest).getRequestURI(); + HttpServletResponse httpServletResponse = ((HttpServletResponse) servletResponse); if (CaptchaUtil.isPathAvailable(path, RECOVER_USERNAME_URL)) { - captchaProvider.preValidateForUsernameRecovery(servletRequest,servletResponse); + httpServletResponse.setHeader("reCaptcha", "conditional"); preValidationResponse.setCaptchaValidationRequired(true); } return preValidationResponse; diff --git a/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/recaptchaRevamp/RecaptchaConnector.java b/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/recaptchaRevamp/RecaptchaConnector.java deleted file mode 100644 index 7781bd8903..0000000000 --- a/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/recaptchaRevamp/RecaptchaConnector.java +++ /dev/null @@ -1,80 +0,0 @@ -package org.wso2.carbon.identity.captcha.connector.recaptchaRevamp; - -import org.apache.commons.lang.StringUtils; -import org.wso2.carbon.identity.captcha.connector.CaptchaProvider; -import org.wso2.carbon.identity.captcha.exception.CaptchaClientException; -import org.wso2.carbon.identity.captcha.exception.CaptchaException; -import org.wso2.carbon.identity.captcha.internal.CaptchaDataHolder; -import org.wso2.carbon.identity.captcha.util.CaptchaUtil; -import org.wso2.carbon.identity.captcha.util.EnabledSecurityMechanism; - -import java.util.HashMap; -import java.util.Map; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -public class RecaptchaConnector implements CaptchaProvider { - - private static final String SELF_REGISTRATION_INITIATE_URL = "/api/identity/recovery/v0.9/claims"; - - - @Override - public void preValidateForSelfSignUp(ServletRequest servletRequest, ServletResponse servletResponse) throws CaptchaException { - - HttpServletResponse httpServletResponse = ((HttpServletResponse) servletResponse); - httpServletResponse.setHeader("reCaptchaKey", CaptchaDataHolder.getInstance().getReCaptchaSiteKey()); - httpServletResponse.setHeader("reCaptchaAPI", CaptchaDataHolder.getInstance().getReCaptchaAPIUrl()); - - } - - @Override - public void preValidateForSSOLogin(ServletRequest servletRequest, ServletResponse servletResponse) throws CaptchaException { - - } - - @Override - public void preValidateForUsernameRecovery(ServletRequest servletRequest, ServletResponse servletResponse) throws CaptchaException { - HttpServletResponse httpServletResponse = ((HttpServletResponse) servletResponse); - httpServletResponse.setHeader("reCaptcha", "conditional"); - } - - @Override - public void preValidateForPasswordRecovery(ServletRequest servletRequest, ServletResponse servletResponse) throws CaptchaException { - HttpServletResponse httpServletResponse = ((HttpServletResponse) servletResponse); - httpServletResponse.setHeader("reCaptchaKey", CaptchaDataHolder.getInstance().getReCaptchaSiteKey()); - httpServletResponse.setHeader("reCaptchaAPI", CaptchaDataHolder.getInstance().getReCaptchaAPIUrl()); - } - - public void addPostValidationData(ServletRequest servletRequest){ - EnabledSecurityMechanism enabledSecurityMechanism = new EnabledSecurityMechanism(); - enabledSecurityMechanism.setMechanism("reCaptcha"); - Map properties = new HashMap<>(); - properties.put("reCaptchaKey", CaptchaDataHolder.getInstance().getReCaptchaSiteKey()); - properties.put("reCaptchaAPI", CaptchaDataHolder.getInstance().getReCaptchaAPIUrl()); - enabledSecurityMechanism.setProperties(properties); - ((HttpServletRequest) servletRequest).getSession().setAttribute("enabled-security-mechanism", - enabledSecurityMechanism); - } - - @Override - public boolean verifyCaptcha(ServletRequest servletRequest, ServletResponse servletResponse) throws CaptchaException { - - String reCaptchaResponse = ((HttpServletRequest) servletRequest).getHeader("g-recaptcha-response"); - if (StringUtils.isBlank(reCaptchaResponse)) { - throw new CaptchaClientException("reCaptcha response is not available in the request."); - } - - return CaptchaUtil.isValidCaptcha(reCaptchaResponse); - } - - - @Override - public void postValidateForSSOLogin(ServletRequest servletRequest, ServletResponse servletResponse) throws CaptchaException { - - } - - - -} diff --git a/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/strategy/DefaultStrategyConnector.java b/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/strategy/DefaultStrategyConnector.java index c8e36bcca7..b7b36e0dcc 100644 --- a/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/strategy/DefaultStrategyConnector.java +++ b/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/strategy/DefaultStrategyConnector.java @@ -1,3 +1,21 @@ +/* + * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you 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.connector.strategy; import org.wso2.carbon.identity.captcha.connector.provider.CaptchaProvider; @@ -7,6 +25,9 @@ import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; +/** + * Default Strategy when there's no specific strategy implemented. + */ public class DefaultStrategyConnector implements StrategyConnector{ @Override diff --git a/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/strategy/StrategyConnector.java b/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/strategy/StrategyConnector.java index d7cda3d215..7c426f6c02 100644 --- a/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/strategy/StrategyConnector.java +++ b/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/connector/strategy/StrategyConnector.java @@ -1,3 +1,21 @@ +/* + * Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you 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.connector.strategy; import org.wso2.carbon.identity.captcha.connector.provider.CaptchaProvider; diff --git a/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/filter/CaptchaFilter.java b/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/filter/CaptchaFilter.java index cf6058301f..15f66defcb 100644 --- a/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/filter/CaptchaFilter.java +++ b/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/filter/CaptchaFilter.java @@ -24,11 +24,11 @@ import org.wso2.carbon.identity.captcha.connector.CaptchaConnector; import org.wso2.carbon.identity.captcha.connector.CaptchaPostValidationResponse; import org.wso2.carbon.identity.captcha.connector.CaptchaPreValidationResponse; -import org.wso2.carbon.identity.captcha.connector.CaptchaProvider; +import org.wso2.carbon.identity.captcha.connector.provider.CaptchaProvider; +import org.wso2.carbon.identity.captcha.connector.strategy.StrategyConnector; import org.wso2.carbon.identity.captcha.exception.CaptchaClientException; import org.wso2.carbon.identity.captcha.exception.CaptchaException; import org.wso2.carbon.identity.captcha.internal.CaptchaDataHolder; -import org.wso2.carbon.identity.captcha.strategy.StrategyConnector; import org.wso2.carbon.identity.captcha.util.CaptchaHttpServletRequestWrapper; import org.wso2.carbon.identity.captcha.util.CaptchaHttpServletResponseWrapper; import org.wso2.carbon.identity.captcha.util.CaptchaUtil; @@ -83,7 +83,6 @@ public void doFilter(ServletRequest servletRequest, ServletResponse servletRespo } } - List captchaConnectors = CaptchaDataHolder.getInstance().getCaptchaConnectors(); List strategyConnectors = CaptchaDataHolder.getInstance().getStrategyConnectors(); List captchaFlowConnectors = CaptchaDataHolder.getInstance().getCaptchaFlowConnectors(); @@ -104,8 +103,8 @@ public void doFilter(ServletRequest servletRequest, ServletResponse servletRespo //select the strategy StrategyConnector selectedStrategyConnector = null; for (StrategyConnector strategyConnector : strategyConnectors) { - if (selectedCaptchaFlowConnector != null && (selectedStrategyConnector == null || - strategyConnector.getPriority() > selectedStrategyConnector.getPriority())) { + if (selectedStrategyConnector == null || + strategyConnector.getPriority() > selectedStrategyConnector.getPriority()) { selectedStrategyConnector = strategyConnector; } } 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 8f9228b5ee..c262d7433d 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 @@ -20,8 +20,8 @@ import org.wso2.carbon.identity.captcha.connector.CaptchaConnector; import org.wso2.carbon.identity.captcha.connector.provider.CaptchaProvider; +import org.wso2.carbon.identity.captcha.connector.strategy.StrategyConnector; import org.wso2.carbon.identity.captcha.util.CaptchaConfigs; -import org.wso2.carbon.identity.captcha.strategy.StrategyConnector; import org.wso2.carbon.identity.governance.IdentityGovernanceService; import org.wso2.carbon.identity.handler.event.account.lock.service.AccountLockService; import org.wso2.carbon.user.core.service.RealmService; diff --git a/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/strategy/AbstractStrategyConnector.java b/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/strategy/AbstractStrategyConnector.java deleted file mode 100644 index 19c7649c0b..0000000000 --- a/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/strategy/AbstractStrategyConnector.java +++ /dev/null @@ -1,4 +0,0 @@ -package org.wso2.carbon.identity.captcha.strategy; - -public abstract class AbstractStrategyConnector implements StrategyConnector { -} diff --git a/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/strategy/DefaultStrategyConnector.java b/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/strategy/DefaultStrategyConnector.java deleted file mode 100644 index a2a003c56e..0000000000 --- a/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/strategy/DefaultStrategyConnector.java +++ /dev/null @@ -1,24 +0,0 @@ -package org.wso2.carbon.identity.captcha.strategy; - -import org.wso2.carbon.identity.captcha.connector.CaptchaProvider; -import org.wso2.carbon.identity.governance.IdentityGovernanceService; - -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; - -public class DefaultStrategyConnector extends AbstractStrategyConnector{ - @Override - public void init(IdentityGovernanceService identityGovernanceService) { - - } - - @Override - public int getPriority() { - return 0; - } - - @Override - public CaptchaProvider getCaptchaProvider(ServletRequest servletRequest, ServletResponse servletResponse) { - return null; - } -} diff --git a/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/strategy/FlowBasedStrategyConnector.java b/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/strategy/FlowBasedStrategyConnector.java deleted file mode 100644 index f53cbb2f17..0000000000 --- a/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/strategy/FlowBasedStrategyConnector.java +++ /dev/null @@ -1,24 +0,0 @@ -package org.wso2.carbon.identity.captcha.strategy; - -import org.wso2.carbon.identity.captcha.connector.CaptchaProvider; -import org.wso2.carbon.identity.governance.IdentityGovernanceService; - -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; - -public class FlowBasedStrategyConnector extends AbstractStrategyConnector{ - @Override - public void init(IdentityGovernanceService identityGovernanceService) { - - } - - @Override - public int getPriority() { - return 0; - } - - @Override - public CaptchaProvider getCaptchaProvider(ServletRequest servletRequest, ServletResponse servletResponse) { - return null; - } -} diff --git a/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/strategy/LocationBasedStrategyConnector.java b/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/strategy/LocationBasedStrategyConnector.java deleted file mode 100644 index d655180770..0000000000 --- a/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/strategy/LocationBasedStrategyConnector.java +++ /dev/null @@ -1,50 +0,0 @@ -package org.wso2.carbon.identity.captcha.strategy; - -import org.wso2.carbon.identity.captcha.connector.CaptchaProvider; -import org.wso2.carbon.identity.governance.IdentityGovernanceService; - -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletRequest; - -public class LocationBasedStrategyConnector extends AbstractStrategyConnector { - - @Override - public void init(IdentityGovernanceService identityGovernanceService) { - - } - - @Override - public int getPriority() { - - return 10; - } - - @Override - public CaptchaProvider getCaptchaProvider(ServletRequest servletRequest, ServletResponse servletResponse) { - //if client - return null; - } - - public static String getClientIpAddress(HttpServletRequest request) { - - String ip = request.getHeader("X-Forwarded-For"); - if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { - ip = request.getHeader("Proxy-Client-IP"); - } - if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { - ip = request.getHeader("WL-Proxy-Client-IP"); - } - if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { - ip = request.getHeader("HTTP_CLIENT_IP"); - } - if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { - ip = request.getHeader("HTTP_X_FORWARDED_FOR"); - } - if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { - ip = request.getRemoteAddr(); - } - return ip; - } - -} diff --git a/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/strategy/StrategyConnector.java b/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/strategy/StrategyConnector.java deleted file mode 100644 index 4cc15e24e4..0000000000 --- a/components/org.wso2.carbon.identity.captcha/src/main/java/org/wso2/carbon/identity/captcha/strategy/StrategyConnector.java +++ /dev/null @@ -1,17 +0,0 @@ -package org.wso2.carbon.identity.captcha.strategy; - -import org.wso2.carbon.identity.captcha.connector.CaptchaProvider; -import org.wso2.carbon.identity.governance.IdentityGovernanceService; - -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; - -public interface StrategyConnector { - - void init(IdentityGovernanceService identityGovernanceService); - - int getPriority(); - - CaptchaProvider getCaptchaProvider(ServletRequest servletRequest, ServletResponse servletResponse); - -} 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 8c6fe95448..50eca816bf 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 @@ -53,6 +53,19 @@ public class CaptchaConstants { public static final String MULTIPLE_CAPTCHA_ENABLED = "captcha."; + public static final class MultipleCaptchaConfig { + + public static final String ENABLED = ".enable"; + public static final String NAME = ".name"; + public static final String API_URL = "api.url"; + public static final String SITE_KEY = ".site.key"; + public static final String VERIFY_URL = ".verify.url"; + public static final String SECRET_KEY = ".secret.key"; + public static final String OPTIONAL_PROPERTIES = ".properties."; + + + } + public enum Flow{ PASSWORD_RECOVERY_FLOW, 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 4918810728..3e875e53a8 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 @@ -101,7 +101,7 @@ public static void buildReCaptchaFilterProperties() { .CAPTCHA_CONFIG_FILE_NAME + "' configuration file", e); } - boolean reCaptchaEnabled = Boolean.valueOf(properties.getProperty(CaptchaConstants + boolean captchaEnabled = Boolean.valueOf(properties.getProperty(CaptchaConstants .RE_CAPTCHA_ENABLED)); String reCaptchaFailedRedirectUrls = properties.getProperty(CaptchaConstants. @@ -109,25 +109,21 @@ public static void buildReCaptchaFilterProperties() { if (StringUtils.isNotBlank(reCaptchaFailedRedirectUrls)) { CaptchaDataHolder.getInstance().setReCaptchaErrorRedirectUrls(reCaptchaFailedRedirectUrls); } - for(int i = 1; properties.getProperty(CaptchaConstants.MULTIPLE_CAPTCHA_ENABLED + i +".enabled") != null; i++) { - //do something - boolean multipleCaptchaEnabled = Boolean - .valueOf(properties.getProperty(CaptchaConstants.MULTIPLE_CAPTCHA_ENABLED + i +".enabled")); - String name = String. - valueOf(properties.getProperty(CaptchaConstants.MULTIPLE_CAPTCHA_ENABLED + i +".name")); - Map captchaProperties = new HashMap<>(); - captchaProperties.put("api",String. - valueOf(properties.getProperty(CaptchaConstants.MULTIPLE_CAPTCHA_ENABLED + i +".api"))); - CaptchaConfigs captchaConfigs = new CaptchaConfigs(name, captchaProperties); - CaptchaDataHolder.getInstance().addCaptchaConfigs(captchaConfigs); - } + Boolean multipleCaptchaEnabled = false; + + for(int i = 1; properties.getProperty(String.format("%s%d%s", CaptchaConstants.MULTIPLE_CAPTCHA_ENABLED,i, + CaptchaConstants.MultipleCaptchaConfig.ENABLED)) != null; i++) { - List captchaProviders = CaptchaDataHolder.getInstance().getCaptchaProviders(); - for(CaptchaProvider captchaProvider: captchaProviders){ - captchaProvider.init(); + multipleCaptchaEnabled = Boolean + .valueOf(properties.getProperty(String.format("%s%d%s", + CaptchaConstants.MULTIPLE_CAPTCHA_ENABLED,i, + CaptchaConstants.MultipleCaptchaConfig.ENABLED))); + if(multipleCaptchaEnabled){ + setMultipleCaptchaConfigs(properties, i); + } } - if (reCaptchaEnabled) { + if (captchaEnabled || multipleCaptchaEnabled) { CaptchaDataHolder.getInstance().setReCaptchaEnabled(true); resolveSecrets(properties); setReCaptchaConfigs(properties); @@ -428,6 +424,35 @@ private static void setSSOLoginConnectorConfigs(Properties properties) { CaptchaDataHolder.getInstance().setSSOLoginReCaptchaConnectorPropertyMap(connectorPropertyMap); } + private static void setMultipleCaptchaConfigs(Properties properties, int i) { + String name = String. + valueOf(properties.getProperty(String.format("%s%d%s", + CaptchaConstants.MULTIPLE_CAPTCHA_ENABLED,i, + CaptchaConstants.MultipleCaptchaConfig.NAME))); + Map captchaProperties = new HashMap<>(); + captchaProperties.put("API",String. + valueOf(properties.getProperty(String.format("%s%d%s", CaptchaConstants.MULTIPLE_CAPTCHA_ENABLED,i, + CaptchaConstants.MultipleCaptchaConfig.API_URL)))); + captchaProperties.put("SiteKey",String. + valueOf(properties.getProperty(String.format("%s%d%s", CaptchaConstants.MULTIPLE_CAPTCHA_ENABLED,i, + CaptchaConstants.MultipleCaptchaConfig.SITE_KEY)))); + captchaProperties.put("SecretKey",String. + valueOf(properties.getProperty(String.format("%s%d%s", CaptchaConstants.MULTIPLE_CAPTCHA_ENABLED,i, + CaptchaConstants.MultipleCaptchaConfig.SECRET_KEY)))); + captchaProperties.put("VerifyUrl",String. + valueOf(properties.getProperty(String.format("%s%d%s", CaptchaConstants.MULTIPLE_CAPTCHA_ENABLED,i, + CaptchaConstants.MultipleCaptchaConfig.VERIFY_URL)))); + + for(int j = 1; properties.getProperty(String.format("%s%s%d",name, + CaptchaConstants.MultipleCaptchaConfig.OPTIONAL_PROPERTIES,j))!= null; i++) { + String[] optionalProperties = properties.getProperty(StringUtils.trim(String.format("%s%s%d",name, + CaptchaConstants.MultipleCaptchaConfig.OPTIONAL_PROPERTIES,j))).split(","); + captchaProperties.put(optionalProperties[0],optionalProperties[1]); + } + + CaptchaConfigs captchaConfigs = new CaptchaConfigs(name, captchaProperties); + CaptchaDataHolder.getInstance().addCaptchaConfigs(captchaConfigs); + } private static void setPathBasedConnectorConfigs(Properties properties) { Map connectorPropertyMap = new HashMap<>();