diff --git a/core/src/main/java/org/acegisecurity/captcha/AlwaysTestAfterMaxRequestsCaptchaChannelProcessor.java b/core/src/main/java/org/acegisecurity/captcha/AlwaysTestAfterMaxRequestsCaptchaChannelProcessor.java new file mode 100644 index 0000000000..63f9b3ed13 --- /dev/null +++ b/core/src/main/java/org/acegisecurity/captcha/AlwaysTestAfterMaxRequestsCaptchaChannelProcessor.java @@ -0,0 +1,68 @@ +/* Copyright 2004, 2005 Acegi Technology Pty Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Copyright (c) 2005 Your Corporation. All Rights Reserved. + */ +package net.sf.acegisecurity.captcha; + +/** + *

+ * return false if ny CaptchaChannelProcessorTemplate of mapped urls has been + * requested more than thresold;
+ * Default keyword : REQUIRES_CAPTCHA_ABOVE_THRESOLD_REQUESTS + *

+ * + * @author Marc-Antoine Garrigue + * @version $Id$ + */ +public class AlwaysTestAfterMaxRequestsCaptchaChannelProcessor + extends CaptchaChannelProcessorTemplate { + //~ Static fields/initializers ============================================= + + /** Keyword for this channelProcessor */ + public static final String DEFAULT_KEYWORD = "REQUIRES_CAPTCHA_ABOVE_THRESOLD_REQUESTS"; + + //~ Constructors =========================================================== + + /** + * Constructor + */ + public AlwaysTestAfterMaxRequestsCaptchaChannelProcessor() { + super(); + this.setKeyword(DEFAULT_KEYWORD); + } + + //~ Methods ================================================================ + + /** + * Verify wheter the context is valid concerning humanity + * + * @param context + * + * @return true if valid, false otherwise + */ + boolean isContextValidConcerningHumanity(CaptchaSecurityContext context) { + if (context.getHumanRestrictedResourcesRequestsCount() < getThresold()) { + logger.debug("context is valid : request count < thresold"); + + return true; + } else { + logger.debug("context is not valid : request count > thresold"); + + return false; + } + } +} diff --git a/core/src/main/java/org/acegisecurity/captcha/AlwaysTestAfterTimeInMillisCaptchaChannelProcessor.java b/core/src/main/java/org/acegisecurity/captcha/AlwaysTestAfterTimeInMillisCaptchaChannelProcessor.java new file mode 100644 index 0000000000..208fe0ae83 --- /dev/null +++ b/core/src/main/java/org/acegisecurity/captcha/AlwaysTestAfterTimeInMillisCaptchaChannelProcessor.java @@ -0,0 +1,66 @@ +/* Copyright 2004, 2005 Acegi Technology Pty Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package net.sf.acegisecurity.captcha; + +/** + *

+ * return false if thresold is greater than millis since last captcha test has occured;
+ * Default keyword : REQUIRES_CAPTCHA_AFTER_THRESOLD_IN_MILLIS + *

+ * + * @author Marc-Antoine Garrigue + * @version $Id$ + */ +public class AlwaysTestAfterTimeInMillisCaptchaChannelProcessor + extends CaptchaChannelProcessorTemplate { + //~ Static fields/initializers ============================================= + + /** Keyword for this channelProcessor */ + public static final String DEFAULT_KEYWORD = "REQUIRES_CAPTCHA_AFTER_THRESOLD_IN_MILLIS"; + + //~ Constructors =========================================================== + + /** + * Constructor + */ + public AlwaysTestAfterTimeInMillisCaptchaChannelProcessor() { + super(); + this.setKeyword(DEFAULT_KEYWORD); + } + + //~ Methods ================================================================ + + /** + * Verify wheter the context is valid concerning humanity + * + * @param context the CaptchaSecurityContext + * + * @return true if valid, false otherwise + */ + boolean isContextValidConcerningHumanity(CaptchaSecurityContext context) { + if ((System.currentTimeMillis() + - context.getLastPassedCaptchaDateInMillis()) < getThresold()) { + logger.debug( + "context is valid : last passed captcha date - current time < thresold"); + + return true; + } else { + logger.debug( + "context is not valid : last passed captcha date - current time > thresold"); + + return false; + } + } +} diff --git a/core/src/main/java/org/acegisecurity/captcha/AlwaysTestBelowAverageTimeInMillisBetweenRequestsChannelProcessor.java b/core/src/main/java/org/acegisecurity/captcha/AlwaysTestBelowAverageTimeInMillisBetweenRequestsChannelProcessor.java new file mode 100644 index 0000000000..6ef02114ac --- /dev/null +++ b/core/src/main/java/org/acegisecurity/captcha/AlwaysTestBelowAverageTimeInMillisBetweenRequestsChannelProcessor.java @@ -0,0 +1,93 @@ +/* Copyright 2004, 2005 Acegi Technology Pty Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.sf.acegisecurity.captcha; + +import org.springframework.util.Assert; + + +/** + *

+ * return false if thresold is lower than average time millis between any + * CaptchaChannelProcessorTemplate mapped urls requests and is human;
+ * Default keyword : REQUIRES_CAPTCHA_AFTER_THRESOLD_IN_MILLIS
+ * Note : before first humanity check + *

+ * + * @author Marc-Antoine Garrigue + * @version $Id$ + */ +public class AlwaysTestBelowAverageTimeInMillisBetweenRequestsChannelProcessor + extends CaptchaChannelProcessorTemplate { + //~ Static fields/initializers ============================================= + + /** Keyword for this channelProcessor */ + public static final String DEFAULT_KEYWORD = "REQUIRES_CAPTCHA_BELOW_AVERAGE_TIME_IN_MILLIS_REQUESTS"; + + //~ Constructors =========================================================== + + /** + * Constructor + */ + public AlwaysTestBelowAverageTimeInMillisBetweenRequestsChannelProcessor() { + super(); + this.setKeyword(DEFAULT_KEYWORD); + } + + //~ Methods ================================================================ + + /** + * Verify if thresold is > 0 + * + * @throws Exception if false + */ + public void afterPropertiesSet() throws Exception { + super.afterPropertiesSet(); + Assert.isTrue(getThresold() > 0, "thresold must be > 0"); + } + + /** + * Verify wheter the context is valid concerning humanity + * + * @param context + * + * @return true if valid, false otherwise + */ + boolean isContextValidConcerningHumanity(CaptchaSecurityContext context) { + int req = context.getHumanRestrictedResourcesRequestsCount(); + float thresold = getThresold(); + float duration = System.currentTimeMillis() + - context.getLastPassedCaptchaDateInMillis(); + float average; + + if (req == 0) { + average = thresold + 1; + } else { + average = duration / req; + } + + if (context.isHuman() && (average > thresold)) { + logger.debug( + "context is valid : average time between requests < thresold && is human"); + + return true; + } else { + logger.debug( + "context is not valid : request count > thresold or is not human"); + + return false; + } + } +} diff --git a/core/src/main/java/org/acegisecurity/captcha/CaptchaChannelProcessor.java b/core/src/main/java/org/acegisecurity/captcha/CaptchaChannelProcessor.java deleted file mode 100644 index 87cebfce13..0000000000 --- a/core/src/main/java/org/acegisecurity/captcha/CaptchaChannelProcessor.java +++ /dev/null @@ -1,371 +0,0 @@ -/* Copyright 2004 Acegi Technology Pty Limited - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package net.sf.acegisecurity.captcha; - -import java.io.IOException; -import java.util.Iterator; - -import javax.servlet.ServletException; - -import net.sf.acegisecurity.ConfigAttribute; -import net.sf.acegisecurity.ConfigAttributeDefinition; -import net.sf.acegisecurity.context.SecurityContextHolder; -import net.sf.acegisecurity.intercept.web.FilterInvocation; -import net.sf.acegisecurity.securechannel.ChannelEntryPoint; -import net.sf.acegisecurity.securechannel.ChannelProcessor; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.util.Assert; - -/** - *

- * Ensures the user has enougth human privileges by review of the - * {@link net.sf.acegisecurity.captcha.CaptchaSecurityContext}. - *

- * - *

- * The class takes 3 required attributes : - *

- * The class responds to two case-sensitive keywords : - * - *

- * - *

- * Examples : to ensure an url is accessed only by human that pass a captcha - * (assuming you are using the - * {@link net.sf.acegisecurity.context.HttpSessionContextIntegrationFilter}) - *
- *

- * - * - * @author marc antoine Garrigue - * @version $Id$ - */ -public class CaptchaChannelProcessor implements ChannelProcessor, - InitializingBean { - // ~ Static fields/initializers - // ============================================= - - private static final Log logger = LogFactory - .getLog(CaptchaChannelProcessor.class); - - private String requiresHumanAfterMaxRequestsKeyword = "REQUIRES_HUMAN_AFTER_MAX_REQUESTS"; - - private String requiresHumanAfterMaxMillisKeyword = "REQUIRES_HUMAN_AFTER_MAX_MILLIS"; - - private String keywordPrefix = ""; - - - private ChannelEntryPoint entryPoint; - - private int maxRequestsBeforeReTest = -1; - - private int maxRequestsBeforeFirstTest = 0; - - private long maxMillisBeforeReTest = -1; - - public String getKeywordPrefix() { - return keywordPrefix; - } - - public void setKeywordPrefix(String keywordPrefix) { - this.keywordPrefix = keywordPrefix; - } - - public String getRequiresHumanAfterMaxMillisKeyword() { - return requiresHumanAfterMaxMillisKeyword; - } - - public void setRequiresHumanAfterMaxMillisKeyword( - String requiresHumanAfterMaxMillis) { - this.requiresHumanAfterMaxMillisKeyword = requiresHumanAfterMaxMillis; - - } - - public void setRequiresHumanAfterMaxRequestsKeyword( - String requiresHumanAfterMaxRequestsKeyword) { - this.requiresHumanAfterMaxRequestsKeyword = requiresHumanAfterMaxRequestsKeyword; - } - - public ChannelEntryPoint getEntryPoint() { - return entryPoint; - } - - public void setEntryPoint(ChannelEntryPoint entryPoint) { - this.entryPoint = entryPoint; - } - - public int getMaxRequestsBeforeReTest() { - return maxRequestsBeforeReTest; - } - - public void setMaxRequestsBeforeReTest(int maxRequestsBeforeReTest) { - this.maxRequestsBeforeReTest = maxRequestsBeforeReTest; - } - - public String getRequiresHumanAfterMaxRequestsKeyword() { - return requiresHumanAfterMaxRequestsKeyword; - } - - public int getMaxRequestsBeforeFirstTest() { - return maxRequestsBeforeFirstTest; - } - - public void setMaxRequestsBeforeFirstTest(int maxRequestsBeforeFirstTest) { - this.maxRequestsBeforeFirstTest = maxRequestsBeforeFirstTest; - } - - public void afterPropertiesSet() throws Exception { - Assert.notNull(entryPoint, "entryPoint required"); - } - - public long getMaxMillisBeforeReTest() { - return maxMillisBeforeReTest; - } - - public void setMaxMillisBeforeReTest(long maxMillisBeforeReTest) { - this.maxMillisBeforeReTest = maxMillisBeforeReTest; - } - - public void decide(FilterInvocation invocation, - ConfigAttributeDefinition config) throws IOException, - ServletException { - if ((invocation == null) || (config == null)) { - throw new IllegalArgumentException("Nulls cannot be provided"); - } - CaptchaSecurityContext context = null; - context = (CaptchaSecurityContext) SecurityContextHolder - .getContext(); - - Iterator iter = config.getConfigAttributes(); - boolean shouldRedirect = false; - - while (iter.hasNext()) { - ConfigAttribute attribute = (ConfigAttribute) iter.next(); - if (supports(attribute)) { - logger.debug("supports this attribute : " + attribute); - if (!isContextValidForAttribute(context, attribute)) { - shouldRedirect = true; - } - } - } - if (shouldRedirect) { - logger - .debug("context is not allowed to access ressource, redirect to captcha entry point"); - redirectToEntryPoint(invocation); - } else { - // if we reach this point, we forward the request so - // increment it - logger - .debug("context is allowed to access ressource, increment rectricted ressource requests count "); - context.incrementHumanRestrictedRessoucesRequestsCount(); - - } - } - - private boolean isContextValidForAttribute(CaptchaSecurityContext context, - ConfigAttribute attribute) { - boolean valid = false; - if ((attribute != null) || (attribute.getAttribute() != null)) { - - // test the REQUIRES_HUMAN_AFTER_MAX_REQUESTS keyword - if (isKeywordMaxRequest(attribute)) { - if (isContextValidConcerningHumanOrFirstTest(context) - && isContextValidConcerningReTest(context)) { - valid = true; - } - } - - // test the REQUIRES_HUMAN_AFTER_MAX_MILLIS keyword - if (isKeywordMillis(attribute)) { - if (isContextValidConcerningHumanOrFirstTest(context) - && isContextValidConcerningMaxMillis(context)) { - valid = true; - } - } - - } - return valid; - } - - private boolean isContextValidConcerningHumanOrFirstTest( - CaptchaSecurityContext context) { - if (context.isHuman() - || context.getHumanRestrictedResourcesRequestsCount() < maxRequestsBeforeFirstTest) { - logger - .debug("context is valid concerning humanity or request count < maxRequestsBeforeFirstTest"); - - return true; - } else { - logger - .debug("context is not valid concerning humanity and request count > maxRequestsBeforeFirstTest"); - return false; - } - } - - private boolean isContextValidConcerningReTest( - CaptchaSecurityContext context) { - if (context.getHumanRestrictedResourcesRequestsCount() < maxRequestsBeforeReTest - || maxRequestsBeforeReTest < 0) { - logger.debug("context is valid concerning reTest"); - - return true; - } else { - logger.debug("context is not valid concerning reTest"); - - return false; - } - } - - private boolean isContextValidConcerningMaxMillis( - CaptchaSecurityContext context) { - if (System.currentTimeMillis() - - context.getLastPassedCaptchaDateInMillis() < maxMillisBeforeReTest - || maxMillisBeforeReTest < 0) { - logger.debug("context is valid concerning maxMillis"); - - return true; - } else { - logger.debug("context is not valid concerning maxMillis"); - - return false; - } - } - - private void redirectToEntryPoint(FilterInvocation invocation) - throws IOException, ServletException { - logger - .debug("security constraints not repected : redirecting to entry point"); - entryPoint.commence(invocation.getRequest(), invocation.getResponse()); - return; - } - - public boolean supports(ConfigAttribute attribute) { - if ((attribute != null) - && (attribute.getAttribute() != null) - && (isKeywordMaxRequest(attribute) || isKeywordMillis(attribute) - - )) { - return true; - } else { - return false; - } - } - - private boolean isKeywordMillis(ConfigAttribute attribute) { - return attribute - .getAttribute().equals( - getKeywordPrefix()+getRequiresHumanAfterMaxMillisKeyword()); - } - - private boolean isKeywordMaxRequest(ConfigAttribute attribute) { - return attribute.getAttribute().equals( - getKeywordPrefix()+getRequiresHumanAfterMaxRequestsKeyword()); - } - -} diff --git a/core/src/main/java/org/acegisecurity/captcha/CaptchaChannelProcessorTemplate.java b/core/src/main/java/org/acegisecurity/captcha/CaptchaChannelProcessorTemplate.java new file mode 100644 index 0000000000..1e7f5e9f82 --- /dev/null +++ b/core/src/main/java/org/acegisecurity/captcha/CaptchaChannelProcessorTemplate.java @@ -0,0 +1,163 @@ +/* Copyright 2004, 2005 Acegi Technology Pty Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.sf.acegisecurity.captcha; + +import net.sf.acegisecurity.ConfigAttribute; +import net.sf.acegisecurity.ConfigAttributeDefinition; +import net.sf.acegisecurity.context.SecurityContextHolder; +import net.sf.acegisecurity.intercept.web.FilterInvocation; +import net.sf.acegisecurity.securechannel.ChannelEntryPoint; +import net.sf.acegisecurity.securechannel.ChannelProcessor; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.springframework.beans.factory.InitializingBean; + +import org.springframework.util.Assert; + +import java.io.IOException; + +import java.util.Iterator; + +import javax.servlet.ServletException; + + +/** + *

+ * CaptchaChannel template : Ensures the user has enough human privileges by + * review of the {@link CaptchaSecurityContext} and using an abstract routine + * {@link #isContextValidConcerningHumanity(CaptchaSecurityContext)} + * (implemented by sub classes) + *

+ * + *

+ * The component uses 2 main parameters for its configuration : + * + *

+ *

+ * + * @author marc antoine Garrigue + * @version $Id$ + */ +public abstract class CaptchaChannelProcessorTemplate + implements ChannelProcessor, InitializingBean { + //~ Instance fields ======================================================== + + protected Log logger = LogFactory.getLog(this.getClass()); + private ChannelEntryPoint entryPoint; + private String keyword = null; + private int thresold = 0; + + //~ Methods ================================================================ + + public void setEntryPoint(ChannelEntryPoint entryPoint) { + this.entryPoint = entryPoint; + } + + public ChannelEntryPoint getEntryPoint() { + return entryPoint; + } + + public void setKeyword(String keyword) { + this.keyword = keyword; + } + + public String getKeyword() { + return keyword; + } + + public void setThresold(int thresold) { + this.thresold = thresold; + } + + public int getThresold() { + return thresold; + } + + /** + * Verify if entryPoint and keyword are ok + * + * @throws Exception if not + */ + public void afterPropertiesSet() throws Exception { + Assert.notNull(entryPoint, "entryPoint required"); + Assert.hasLength(keyword, "keyword required"); + } + + public void decide(FilterInvocation invocation, + ConfigAttributeDefinition config) throws IOException, ServletException { + if ((invocation == null) || (config == null)) { + throw new IllegalArgumentException("Nulls cannot be provided"); + } + + CaptchaSecurityContext context = null; + context = (CaptchaSecurityContext) SecurityContextHolder.getContext(); + + Iterator iter = config.getConfigAttributes(); + + while (iter.hasNext()) { + ConfigAttribute attribute = (ConfigAttribute) iter.next(); + + if (supports(attribute)) { + logger.debug("supports this attribute : " + attribute); + + if (!isContextValidConcerningHumanity(context)) { + logger.debug( + "context is not allowed to access ressource, redirect to captcha entry point"); + redirectToEntryPoint(invocation); + } else { + logger.debug( + "has been successfully checked this keyword, increment request count"); + context.incrementHumanRestrictedRessoucesRequestsCount(); + } + } else { + logger.debug("do not support this attribute"); + } + } + } + + public boolean supports(ConfigAttribute attribute) { + if ((attribute != null) && (keyword.equals(attribute.getAttribute()))) { + return true; + } else { + return false; + } + } + + abstract boolean isContextValidConcerningHumanity( + CaptchaSecurityContext context); + + private void redirectToEntryPoint(FilterInvocation invocation) + throws IOException, ServletException { + if (logger.isDebugEnabled()) { + logger.debug("context is not valid : redirecting to entry point"); + } + + entryPoint.commence(invocation.getRequest(), invocation.getResponse()); + } +} diff --git a/core/src/main/java/org/acegisecurity/captcha/CaptchaEntryPoint.java b/core/src/main/java/org/acegisecurity/captcha/CaptchaEntryPoint.java index 4f58d40f59..9e30b80a24 100644 --- a/core/src/main/java/org/acegisecurity/captcha/CaptchaEntryPoint.java +++ b/core/src/main/java/org/acegisecurity/captcha/CaptchaEntryPoint.java @@ -1,4 +1,4 @@ -/* Copyright 2004 Acegi Technology Pty Limited +/* Copyright 2004, 2005 Acegi Technology Pty Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,6 +12,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package net.sf.acegisecurity.captcha; import net.sf.acegisecurity.securechannel.ChannelEntryPoint; @@ -19,96 +20,142 @@ import net.sf.acegisecurity.util.PortMapper; import net.sf.acegisecurity.util.PortMapperImpl; import net.sf.acegisecurity.util.PortResolver; import net.sf.acegisecurity.util.PortResolverImpl; + import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; + import org.springframework.beans.factory.InitializingBean; + import org.springframework.util.Assert; +import java.io.IOException; +import java.io.UnsupportedEncodingException; + +import java.net.URLEncoder; + +import java.util.Enumeration; + import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; -import java.util.Enumeration; + /** - * The captcha entry point : redirect to the captcha test page.
- *

- * This entry point can force the use of SSL : see {@link #getForceHttps()}
- *

- * This entry point allows internal OR external redirect : see {@link #setOutsideWebApp(boolean)}
/ Original request - * can be added to the redirect path using a custom translation : see {@link #setIncludeOriginalRequest(boolean)}
- * Original request is translated using URLEncoding and the following translation mapping in the redirect url :

- *

- *

- *

- *
Default values :
forceHttps = false
includesOriginalRequest = true
includesOriginalParameters = - * false
isOutsideWebApp=false
originalRequestUrlParameterName ="original_requestUrl"
- * originalRequestParametersParameterName = "original_request_parameters";
- *

- * originalRequestParametersNameValueSeparator = "@@";
- *

- * originalRequestParametersSeparator = ";;";
- *

- * originalRequestMethodParameterName = "original_request_method";
- *

- * urlEncodingCharset = "UTF-8";
+ * The captcha entry point : redirect to the captcha test page.
+ * + *

+ * This entry point can force the use of SSL : see {@link #getForceHttps()}
+ *

+ * This entry point allows internal OR external redirect : see {@link #setOutsideWebApp(boolean)}
+ * / Original request can be added to the redirect path using a custom + * translation : see {@link #setIncludeOriginalRequest(boolean)}
+ * Original request is translated using URLEncoding and the following + * translation mapping in the redirect url : + * + * + * + *

+ * Default values :
+ * forceHttps = false
+ * includesOriginalRequest = true
+ * includesOriginalParameters = false
+ * isOutsideWebApp=false
+ * originalRequestUrlParameterName =original_requestUrl
+ * originalRequestParametersParameterName = original_request_parameters
+ * originalRequestParametersNameValueSeparator = __
+ * originalRequestParametersSeparator = ;;
+ * originalRequestMethodParameterName = original_request_method
+ * urlEncodingCharset = UTF-8
* * @author marc antoine Garrigue * @version $Id$ */ public class CaptchaEntryPoint implements ChannelEntryPoint, InitializingBean { + //~ Static fields/initializers ============================================= + // ~ Static fields/initializers // ============================================= + private static final Log logger = LogFactory.getLog(CaptchaEntryPoint.class); - private static final Log logger = LogFactory - .getLog(CaptchaEntryPoint.class); + //~ Instance fields ======================================================== // ~ Instance fields // ======================================================== - private PortMapper portMapper = new PortMapperImpl(); - private PortResolver portResolver = new PortResolverImpl(); - private String captchaFormUrl; - - private boolean forceHttps = false; - - private String originalRequestUrlParameterName = "original_requestUrl"; - - private String originalRequestParametersParameterName = "original_request_parameters"; - - private String originalRequestParametersNameValueSeparator = "@@"; - - private String originalRequestParametersSeparator = ";;"; - private String originalRequestMethodParameterName = "original_request_method"; - + private String originalRequestParametersNameValueSeparator = "__"; + private String originalRequestParametersParameterName = "original_request_parameters"; + private String originalRequestParametersSeparator = ";;"; + private String originalRequestUrlParameterName = "original_requestUrl"; private String urlEncodingCharset = "UTF-8"; - + private boolean forceHttps = false; + private boolean includeOriginalParameters = false; + private boolean includeOriginalRequest = true; private boolean isOutsideWebApp = false; - private boolean includeOriginalRequest = true; + //~ Methods ================================================================ - private boolean includeOriginalParameters = false; + /** + * The URL where the CaptchaProcessingFilter login page can be + * found. Should be relative to the web-app context path, and include a + * leading / + * + * @param captchaFormUrl + */ + public void setCaptchaFormUrl(String captchaFormUrl) { + this.captchaFormUrl = captchaFormUrl; + } + + /** + * DOCUMENT ME! + * + * @return the captcha test page to redirect to. + */ + public String getCaptchaFormUrl() { + return captchaFormUrl; + } // ~ Methods // ================================================================ /** - * Set to true to force captcha form access to be via https. If this value is ture (the default is false), and the - * incoming request for the protected resource which triggered the interceptor was not already https, - * then + * Set to true to force captcha form access to be via https. If this value + * is ture (the default is false), and the incoming request for the + * protected resource which triggered the interceptor was not already + * https, then + * + * @param forceHttps */ public void setForceHttps(boolean forceHttps) { this.forceHttps = forceHttps; @@ -118,19 +165,86 @@ public class CaptchaEntryPoint implements ChannelEntryPoint, InitializingBean { return forceHttps; } - /** - * The URL where the CaptchaProcessingFilter login page can be found. Should be relative to the web-app - * context path, and include a leading / - */ - public void setCaptchaFormUrl(String captchaFormUrl) { - this.captchaFormUrl = captchaFormUrl; + public void setIncludeOriginalParameters(boolean includeOriginalParameters) { + this.includeOriginalParameters = includeOriginalParameters; + } + + public boolean isIncludeOriginalParameters() { + return includeOriginalParameters; } /** - * @return the captcha test page to redirect to. + * If set to true, the original request url will be appended to the + * redirect url using the {@link #getOriginalRequestUrlParameterName()}. + * + * @param includeOriginalRequest */ - public String getCaptchaFormUrl() { - return captchaFormUrl; + public void setIncludeOriginalRequest(boolean includeOriginalRequest) { + this.includeOriginalRequest = includeOriginalRequest; + } + + public boolean isIncludeOriginalRequest() { + return includeOriginalRequest; + } + + public void setOriginalRequestMethodParameterName( + String originalRequestMethodParameterName) { + this.originalRequestMethodParameterName = originalRequestMethodParameterName; + } + + public String getOriginalRequestMethodParameterName() { + return originalRequestMethodParameterName; + } + + public void setOriginalRequestParametersNameValueSeparator( + String originalRequestParametersNameValueSeparator) { + this.originalRequestParametersNameValueSeparator = originalRequestParametersNameValueSeparator; + } + + public String getOriginalRequestParametersNameValueSeparator() { + return originalRequestParametersNameValueSeparator; + } + + public void setOriginalRequestParametersParameterName( + String originalRequestParametersParameterName) { + this.originalRequestParametersParameterName = originalRequestParametersParameterName; + } + + public String getOriginalRequestParametersParameterName() { + return originalRequestParametersParameterName; + } + + public void setOriginalRequestParametersSeparator( + String originalRequestParametersSeparator) { + this.originalRequestParametersSeparator = originalRequestParametersSeparator; + } + + public String getOriginalRequestParametersSeparator() { + return originalRequestParametersSeparator; + } + + public void setOriginalRequestUrlParameterName( + String originalRequestUrlParameterName) { + this.originalRequestUrlParameterName = originalRequestUrlParameterName; + } + + public String getOriginalRequestUrlParameterName() { + return originalRequestUrlParameterName; + } + + /** + * if set to true, the {@link #commence(ServletRequest, ServletResponse)} + * method uses the {@link #getCaptchaFormUrl()} as a complete URL, else it + * as a 'inside WebApp' path. + * + * @param isOutsideWebApp + */ + public void setOutsideWebApp(boolean isOutsideWebApp) { + this.isOutsideWebApp = isOutsideWebApp; + } + + public boolean isOutsideWebApp() { + return isOutsideWebApp; } public void setPortMapper(PortMapper portMapper) { @@ -149,104 +263,35 @@ public class CaptchaEntryPoint implements ChannelEntryPoint, InitializingBean { return portResolver; } - - public boolean isOutsideWebApp() { - return isOutsideWebApp; - } - - - public String getOriginalRequestUrlParameterName() { - return originalRequestUrlParameterName; - } - - public void setOriginalRequestUrlParameterName(String originalRequestUrlParameterName) { - this.originalRequestUrlParameterName = originalRequestUrlParameterName; - } - - public String getOriginalRequestParametersParameterName() { - return originalRequestParametersParameterName; - } - - public void setOriginalRequestParametersParameterName(String originalRequestParametersParameterName) { - this.originalRequestParametersParameterName = originalRequestParametersParameterName; - } - - public String getOriginalRequestParametersNameValueSeparator() { - return originalRequestParametersNameValueSeparator; - } - - public void setOriginalRequestParametersNameValueSeparator(String originalRequestParametersNameValueSeparator) { - this.originalRequestParametersNameValueSeparator = originalRequestParametersNameValueSeparator; - } - - public String getOriginalRequestParametersSeparator() { - return originalRequestParametersSeparator; - } - - public void setOriginalRequestParametersSeparator(String originalRequestParametersSeparator) { - this.originalRequestParametersSeparator = originalRequestParametersSeparator; - } - - public String getOriginalRequestMethodParameterName() { - return originalRequestMethodParameterName; - } - - public void setOriginalRequestMethodParameterName(String originalRequestMethodParameterName) { - this.originalRequestMethodParameterName = originalRequestMethodParameterName; + public void setUrlEncodingCharset(String urlEncodingCharset) { + this.urlEncodingCharset = urlEncodingCharset; } public String getUrlEncodingCharset() { return urlEncodingCharset; } - public void setUrlEncodingCharset(String urlEncodingCharset) { - this.urlEncodingCharset = urlEncodingCharset; - } - - /** - * if set to true, the {@link #commence(ServletRequest, ServletResponse)} method uses the {@link - * #getCaptchaFormUrl()} as a complete URL, else it as a 'inside WebApp' path. - */ - public void setOutsideWebApp(boolean isOutsideWebApp) { - this.isOutsideWebApp = isOutsideWebApp; - } - - - public boolean isIncludeOriginalRequest() { - return includeOriginalRequest; - } - - /** - * If set to true, the original request url will be appended to the redirect url using the {@link - * #getOriginalRequestParameterName()}. - */ - public void setIncludeOriginalRequest(boolean includeOriginalRequest) { - this.includeOriginalRequest = includeOriginalRequest; - } - - public boolean isIncludeOriginalParameters() { - return includeOriginalParameters; - } - - public void setIncludeOriginalParameters(boolean includeOriginalParameters) { - this.includeOriginalParameters = includeOriginalParameters; - } - public void afterPropertiesSet() throws Exception { Assert.hasLength(captchaFormUrl, "captchaFormUrl must be specified"); - Assert.hasLength(originalRequestMethodParameterName, "originalRequestMethodParameterName must be specified"); - Assert.hasLength(originalRequestParametersNameValueSeparator, "originalRequestParametersNameValueSeparator must be specified"); - Assert.hasLength(originalRequestParametersParameterName, "originalRequestParametersParameterName must be specified"); - Assert.hasLength(originalRequestParametersSeparator, "originalRequestParametersSeparator must be specified"); - Assert.hasLength(originalRequestUrlParameterName, "originalRequestUrlParameterName must be specified"); - Assert.hasLength(urlEncodingCharset, "urlEncodingCharset must be specified"); + Assert.hasLength(originalRequestMethodParameterName, + "originalRequestMethodParameterName must be specified"); + Assert.hasLength(originalRequestParametersNameValueSeparator, + "originalRequestParametersNameValueSeparator must be specified"); + Assert.hasLength(originalRequestParametersParameterName, + "originalRequestParametersParameterName must be specified"); + Assert.hasLength(originalRequestParametersSeparator, + "originalRequestParametersSeparator must be specified"); + Assert.hasLength(originalRequestUrlParameterName, + "originalRequestUrlParameterName must be specified"); + Assert.hasLength(urlEncodingCharset, + "urlEncodingCharset must be specified"); Assert.notNull(portMapper, "portMapper must be specified"); Assert.notNull(portResolver, "portResolver must be specified"); URLEncoder.encode(" fzaef é& à ", urlEncodingCharset); } public void commence(ServletRequest request, ServletResponse response) - throws IOException, ServletException { + throws IOException, ServletException { StringBuffer redirectUrl = new StringBuffer(); HttpServletRequest req = (HttpServletRequest) request; @@ -259,70 +304,17 @@ public class CaptchaEntryPoint implements ChannelEntryPoint, InitializingBean { if (includeOriginalRequest) { includeOriginalRequest(redirectUrl, req); } + // add post parameter? DONE! if (logger.isDebugEnabled()) { logger.debug("Redirecting to: " + redirectUrl); } - ((HttpServletResponse) response) - .sendRedirect(redirectUrl.toString()); - } - - private void includeOriginalRequest(StringBuffer redirectUrl, - HttpServletRequest req) { - // add original request to the url - if (redirectUrl.indexOf("?") >= 0) { - redirectUrl.append("&"); - } else { - redirectUrl.append("?"); - } - - redirectUrl.append(originalRequestUrlParameterName); - redirectUrl.append("="); - try { - redirectUrl.append(URLEncoder.encode(req.getRequestURL().toString(), urlEncodingCharset)); - } catch (UnsupportedEncodingException e) { - logger.warn(e); - } - - //append method - redirectUrl.append("&"); - redirectUrl.append(originalRequestMethodParameterName); - redirectUrl.append("="); - redirectUrl.append(req.getMethod()); - if (includeOriginalParameters) { - - // append query params - - redirectUrl.append("&"); - redirectUrl.append(originalRequestParametersParameterName); - redirectUrl.append("="); - StringBuffer qp = new StringBuffer(); - Enumeration parameters = req.getParameterNames(); - if (parameters != null && parameters.hasMoreElements()) { - //qp.append("?"); - while (parameters.hasMoreElements()) { - String name = parameters.nextElement().toString(); - String value = req.getParameter(name); - qp.append(name); - qp.append(originalRequestParametersNameValueSeparator); - qp.append(value); - if (parameters.hasMoreElements()) { - qp.append(originalRequestParametersSeparator); - } - } - } - try { - redirectUrl.append(URLEncoder.encode(qp.toString(), urlEncodingCharset)); - } catch (Exception e) { - logger.warn(e); - } - } - + ((HttpServletResponse) response).sendRedirect(redirectUrl.toString()); } private void buildInternalRedirect(StringBuffer redirectUrl, - HttpServletRequest req) { + HttpServletRequest req) { // construct it StringBuffer simpleRedirect = new StringBuffer(); @@ -331,9 +323,11 @@ public class CaptchaEntryPoint implements ChannelEntryPoint, InitializingBean { int serverPort = portResolver.getServerPort(req); String contextPath = req.getContextPath(); boolean includePort = true; + if ("http".equals(scheme.toLowerCase()) && (serverPort == 80)) { includePort = false; } + if ("https".equals(scheme.toLowerCase()) && (serverPort == 443)) { includePort = false; } @@ -341,10 +335,12 @@ public class CaptchaEntryPoint implements ChannelEntryPoint, InitializingBean { simpleRedirect.append(scheme); simpleRedirect.append("://"); simpleRedirect.append(serverName); + if (includePort) { simpleRedirect.append(":"); simpleRedirect.append(serverPort); } + simpleRedirect.append(contextPath); simpleRedirect.append(captchaFormUrl); @@ -361,10 +357,12 @@ public class CaptchaEntryPoint implements ChannelEntryPoint, InitializingBean { redirectUrl.append("https://"); redirectUrl.append(serverName); + if (includePort) { redirectUrl.append(":"); redirectUrl.append(httpsPort); } + redirectUrl.append(contextPath); redirectUrl.append(captchaFormUrl); } else { @@ -375,4 +373,61 @@ public class CaptchaEntryPoint implements ChannelEntryPoint, InitializingBean { } } + private void includeOriginalRequest(StringBuffer redirectUrl, + HttpServletRequest req) { + // add original request to the url + if (redirectUrl.indexOf("?") >= 0) { + redirectUrl.append("&"); + } else { + redirectUrl.append("?"); + } + + redirectUrl.append(originalRequestUrlParameterName); + redirectUrl.append("="); + + try { + redirectUrl.append(URLEncoder.encode(req.getRequestURL().toString(), + urlEncodingCharset)); + } catch (UnsupportedEncodingException e) { + logger.warn(e); + } + + //append method + redirectUrl.append("&"); + redirectUrl.append(originalRequestMethodParameterName); + redirectUrl.append("="); + redirectUrl.append(req.getMethod()); + + if (includeOriginalParameters) { + // append query params + redirectUrl.append("&"); + redirectUrl.append(originalRequestParametersParameterName); + redirectUrl.append("="); + + StringBuffer qp = new StringBuffer(); + Enumeration parameters = req.getParameterNames(); + + if ((parameters != null) && parameters.hasMoreElements()) { + //qp.append("?"); + while (parameters.hasMoreElements()) { + String name = parameters.nextElement().toString(); + String value = req.getParameter(name); + qp.append(name); + qp.append(originalRequestParametersNameValueSeparator); + qp.append(value); + + if (parameters.hasMoreElements()) { + qp.append(originalRequestParametersSeparator); + } + } + } + + try { + redirectUrl.append(URLEncoder.encode(qp.toString(), + urlEncodingCharset)); + } catch (Exception e) { + logger.warn(e); + } + } + } } diff --git a/core/src/main/java/org/acegisecurity/captcha/CaptchaSecurityContext.java b/core/src/main/java/org/acegisecurity/captcha/CaptchaSecurityContext.java index 03d3bb423a..769f1ee7d6 100644 --- a/core/src/main/java/org/acegisecurity/captcha/CaptchaSecurityContext.java +++ b/core/src/main/java/org/acegisecurity/captcha/CaptchaSecurityContext.java @@ -12,42 +12,50 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package net.sf.acegisecurity.captcha; import net.sf.acegisecurity.context.SecurityContext; + /** * Interface that add humanity concerns to the SecurityContext - * + * * @author marc antoine garrigue */ public interface CaptchaSecurityContext extends SecurityContext { + //~ Methods ================================================================ - /** - * @return true if the current user has already passed a captcha. - */ - boolean isHuman(); + /** + * set human attribute, should called after captcha validation. + */ + void setHuman(); - /** - * set human attribute, should called after captcha validation. - */ - void setHuman(); + /** + * DOCUMENT ME! + * + * @return true if the current user has already passed a captcha. + */ + boolean isHuman(); - /** - * - * @return number of human restricted resources requests since the last - * passed captcha. - */ - int getHumanRestrictedResourcesRequestsCount(); + /** + * DOCUMENT ME! + * + * @return number of human restricted resources requests since the last + * passed captcha. + */ + int getHumanRestrictedResourcesRequestsCount(); - /** - * @return the date of the last passed Captcha in millis, 0 if the user - * never passed captcha. - */ - long getLastPassedCaptchaDateInMillis(); + /** + * DOCUMENT ME! + * + * @return the date of the last passed Captcha in millis, 0 if the user + * never passed captcha. + */ + long getLastPassedCaptchaDateInMillis(); - /** - * Method to increment the human Restricted Resrouces Requests Count; - */ - void incrementHumanRestrictedRessoucesRequestsCount(); + /** + * Method to increment the human Restricted Resrouces Requests Count; + */ + void incrementHumanRestrictedRessoucesRequestsCount(); } diff --git a/core/src/main/java/org/acegisecurity/captcha/CaptchaSecurityContextImpl.java b/core/src/main/java/org/acegisecurity/captcha/CaptchaSecurityContextImpl.java index 112fbbd965..68dbbc0aac 100644 --- a/core/src/main/java/org/acegisecurity/captcha/CaptchaSecurityContextImpl.java +++ b/core/src/main/java/org/acegisecurity/captcha/CaptchaSecurityContextImpl.java @@ -1,4 +1,4 @@ -/* Copyright 2004 Acegi Technology Pty Limited +/* Copyright 2004, 2005 Acegi Technology Pty Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -12,74 +12,79 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package net.sf.acegisecurity.captcha; import net.sf.acegisecurity.context.SecurityContextImpl; + /** + * Default CaptchaSecurityContext implementation + * * @author mag - * */ -public class CaptchaSecurityContextImpl extends SecurityContextImpl implements - CaptchaSecurityContext { +public class CaptchaSecurityContextImpl extends SecurityContextImpl + implements CaptchaSecurityContext { + //~ Instance fields ======================================================== - private boolean human; + private boolean human; + private int humanRestrictedResourcesRequestsCount; + private long lastPassedCaptchaDate; - private long lastPassedCaptchaDate; + //~ Constructors =========================================================== - private int humanRestrictedResourcesRequestsCount; + /** + * + */ + public CaptchaSecurityContextImpl() { + super(); + human = false; + lastPassedCaptchaDate = 0; + humanRestrictedResourcesRequestsCount = 0; + } - /** - * - */ - public CaptchaSecurityContextImpl() { - super(); - human = false; - lastPassedCaptchaDate = 0; - humanRestrictedResourcesRequestsCount = 0; - } + //~ Methods ================================================================ - /* - * (non-Javadoc) - * - * @see net.sf.acegisecurity.context.CaptchaSecurityContext#isHuman() - */ - public boolean isHuman() { - return human; - } + /** + * reset the lastPassedCaptchaDate and count. + */ + public void setHuman() { + this.human = true; + this.lastPassedCaptchaDate = System.currentTimeMillis(); + this.humanRestrictedResourcesRequestsCount = 0; + } - /** - * reset the lastPassedCaptchaDate and count. - */ - public void setHuman() { - this.human = true; - this.lastPassedCaptchaDate = System.currentTimeMillis(); - this.humanRestrictedResourcesRequestsCount = 0; - } + /* + * (non-Javadoc) + * + * @see net.sf.acegisecurity.context.CaptchaSecurityContext#isHuman() + */ + public boolean isHuman() { + return human; + } - /* - * (non-Javadoc) - * - * @see net.sf.acegisecurity.context.CaptchaSecurityContext#getHumanRestrictedResourcesRequestsCount() - */ - public int getHumanRestrictedResourcesRequestsCount() { - return humanRestrictedResourcesRequestsCount; - } + /* + * (non-Javadoc) + * + * @see net.sf.acegisecurity.context.CaptchaSecurityContext#getHumanRestrictedResourcesRequestsCount() + */ + public int getHumanRestrictedResourcesRequestsCount() { + return humanRestrictedResourcesRequestsCount; + } - /* - * (non-Javadoc) - * - * @see net.sf.acegisecurity.context.CaptchaSecurityContext#getLastPassedCaptchaDateInMillis() - */ - public long getLastPassedCaptchaDateInMillis() { + /* + * (non-Javadoc) + * + * @see net.sf.acegisecurity.context.CaptchaSecurityContext#getLastPassedCaptchaDateInMillis() + */ + public long getLastPassedCaptchaDateInMillis() { + return lastPassedCaptchaDate; + } - return lastPassedCaptchaDate; - } - - /** - * Method to increment the human Restricted Resrouces Requests Count; - */ - public void incrementHumanRestrictedRessoucesRequestsCount() { - humanRestrictedResourcesRequestsCount++; - }; + /** + * Method to increment the human Restricted Resrouces Requests Count; + */ + public void incrementHumanRestrictedRessoucesRequestsCount() { + humanRestrictedResourcesRequestsCount++; + } } diff --git a/core/src/main/java/org/acegisecurity/captcha/CaptchaServiceProxy.java b/core/src/main/java/org/acegisecurity/captcha/CaptchaServiceProxy.java index 2c1057e3c2..3cbdc9a833 100644 --- a/core/src/main/java/org/acegisecurity/captcha/CaptchaServiceProxy.java +++ b/core/src/main/java/org/acegisecurity/captcha/CaptchaServiceProxy.java @@ -1,4 +1,4 @@ -/* Copyright 2004 Acegi Technology Pty Limited +/* Copyright 2004, 2005 Acegi Technology Pty Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,18 +17,24 @@ package net.sf.acegisecurity.captcha; import javax.servlet.ServletRequest; + /** * Provide a common interface for captcha validation. - * + * * @author marc antoine Garrigue * @version $Id$ */ public interface CaptchaServiceProxy { + //~ Methods ================================================================ - /** + /** + * DOCUMENT ME! + * * @param id the id token * @param captchaResponse the user response - * @return true if the response is validated by the back end captcha service. - */ - boolean validateReponseForId(String id , Object captchaResponse); + * + * @return true if the response is validated by the back end captcha + * service. + */ + boolean validateReponseForId(String id, Object captchaResponse); } diff --git a/core/src/main/java/org/acegisecurity/captcha/CaptchaValidationProcessingFilter.java b/core/src/main/java/org/acegisecurity/captcha/CaptchaValidationProcessingFilter.java index a72fd46969..167eb39ab4 100644 --- a/core/src/main/java/org/acegisecurity/captcha/CaptchaValidationProcessingFilter.java +++ b/core/src/main/java/org/acegisecurity/captcha/CaptchaValidationProcessingFilter.java @@ -1,4 +1,4 @@ -/* Copyright 2004 Acegi Technology Pty Limited +/* Copyright 2004, 2005 Acegi Technology Pty Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,87 +15,96 @@ package net.sf.acegisecurity.captcha; -import net.sf.acegisecurity.context.HttpSessionContextIntegrationFilter; import net.sf.acegisecurity.context.SecurityContextHolder; + import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; + import org.springframework.beans.factory.InitializingBean; +import java.io.IOException; + import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; -import java.io.IOException; + /** - * Filter for web integration of the {@link CaptchaServiceProxy}.
It basically intercept calls containing the - * specific validation parameter, use the {@link CaptchaServiceProxy} to validate the request, and update the {@link - * CaptchaSecurityContext} if the request passed the validation.

This Filter should be placed after the - * ContextIntegration filter and before the {@link CaptchaChannelProcessor} filter in the filter stack in order to - * update the {@link CaptchaSecurityContext} before the humanity verification routine occurs.

This filter - * should only be used in conjunction with the {@link CaptchaSecurityContext}

+ * Filter for web integration of the {@link CaptchaServiceProxy}.
+ * It basically intercept calls containing the specific validation parameter, + * use the {@link CaptchaServiceProxy} to validate the request, and update the + * {@link CaptchaSecurityContext} if the request passed the validation.
+ * This Filter should be placed after the ContextIntegration filter and before + * the {@link CaptchaChannelProcessorTemplate} filter in the filter stack in + * order to update the {@link CaptchaSecurityContext} before the humanity + * verification routine occurs.
+ * This filter should only be used in conjunction with the {@link + * CaptchaSecurityContext}
* * @author marc antoine Garrigue * @version $Id$ */ public class CaptchaValidationProcessingFilter implements InitializingBean, - Filter { + Filter { + //~ Static fields/initializers ============================================= + // ~ Static fields/initializers // ============================================= - protected static final Log logger = LogFactory - .getLog(CaptchaValidationProcessingFilter.class); + protected static final Log logger = LogFactory.getLog(CaptchaValidationProcessingFilter.class); + + //~ Instance fields ======================================================== // ~ Instance fields // ======================================================== - private CaptchaServiceProxy captchaService; private String captchaValidationParameter = "_captcha_parameter"; - - // ~ Methods - // ================================================================ - - public CaptchaServiceProxy getCaptchaService() { - return captchaService; - } + //~ Methods ================================================================ public void setCaptchaService(CaptchaServiceProxy captchaService) { this.captchaService = captchaService; } - - public String getCaptchaValidationParameter() { - return captchaValidationParameter; + // ~ Methods + // ================================================================ + public CaptchaServiceProxy getCaptchaService() { + return captchaService; } public void setCaptchaValidationParameter(String captchaValidationParameter) { this.captchaValidationParameter = captchaValidationParameter; } + public String getCaptchaValidationParameter() { + return captchaValidationParameter; + } + public void afterPropertiesSet() throws Exception { if (this.captchaService == null) { throw new IllegalArgumentException( - "CaptchaServiceProxy must be defined "); + "CaptchaServiceProxy must be defined "); } - if (this.captchaValidationParameter == null||"".equals(captchaValidationParameter)) { + + if ((this.captchaValidationParameter == null) + || "".equals(captchaValidationParameter)) { throw new IllegalArgumentException( - "captchaValidationParameter must not be empty or null"); + "captchaValidationParameter must not be empty or null"); } } /** * Does nothing. We use IoC container lifecycle services instead. */ - public void destroy() { - } + public void destroy() {} public void doFilter(ServletRequest request, ServletResponse response, - FilterChain chain) throws IOException, ServletException { - String captcha_reponse = request - .getParameter(captchaValidationParameter); - if ((request != null) && request instanceof HttpServletRequest - && ( captcha_reponse!= null)) { + FilterChain chain) throws IOException, ServletException { + String captcha_reponse = request.getParameter(captchaValidationParameter); + if ((request != null) && request instanceof HttpServletRequest + && (captcha_reponse != null)) { logger.debug("captcha validation parameter found"); + // validate the request against CaptchaServiceProxy boolean valid = false; @@ -103,30 +112,35 @@ public class CaptchaValidationProcessingFilter implements InitializingBean, //get session HttpSession session = ((HttpServletRequest) request).getSession(); - if (session != null) { + if (session != null) { String id = session.getId(); valid = this.captchaService.validateReponseForId(id, captcha_reponse); logger.debug("captchaServiceProxy says : request is valid = " - + valid); + + valid); + if (valid) { logger.debug("update the context"); ((CaptchaSecurityContext) SecurityContextHolder.getContext()) - .setHuman(); + .setHuman(); + //logger.debug("retrieve original request from ") - - }else{ - logger.debug("captcha test failed"); + } else { + logger.debug("captcha test failed"); } - - }else{ - logger.debug("no session found, user don't even ask a captcha challenge"); + } else { + logger.debug( + "no session found, user don't even ask a captcha challenge"); } } else { - logger.debug("captcha validation parameter not found, do nothing"); + logger.debug("captcha validation parameter not found, do nothing"); } - logger.debug("chain ..."); + + if (logger.isDebugEnabled()) { + logger.debug("chain ..."); + } + chain.doFilter(request, response); } @@ -137,6 +151,5 @@ public class CaptchaValidationProcessingFilter implements InitializingBean, * * @throws ServletException ignored */ - public void init(FilterConfig filterConfig) throws ServletException { - } + public void init(FilterConfig filterConfig) throws ServletException {} } diff --git a/core/src/main/java/org/acegisecurity/captcha/TestOnceAfterMaxRequestsCaptchaChannelProcessor.java b/core/src/main/java/org/acegisecurity/captcha/TestOnceAfterMaxRequestsCaptchaChannelProcessor.java new file mode 100644 index 0000000000..c9ff09624e --- /dev/null +++ b/core/src/main/java/org/acegisecurity/captcha/TestOnceAfterMaxRequestsCaptchaChannelProcessor.java @@ -0,0 +1,56 @@ +/* Copyright 2004, 2005 Acegi Technology Pty Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package net.sf.acegisecurity.captcha; + +/** + *

+ * return false if ny CaptchaChannelProcessorTemplate mapped urls has been + * requested more than thresold and humanity is false;
+ * Default keyword : REQUIRES_CAPTCHA_ONCE_ABOVE_THRESOLD_REQUESTS + *

+ * + * @author Marc-Antoine Garrigue + * @version $Id$ + */ +public class TestOnceAfterMaxRequestsCaptchaChannelProcessor + extends CaptchaChannelProcessorTemplate { + //~ Static fields/initializers ============================================= + + public static final String DEFAULT_KEYWORD = "REQUIRES_CAPTCHA_ONCE_ABOVE_THRESOLD_REQUESTS"; + + //~ Constructors =========================================================== + + public TestOnceAfterMaxRequestsCaptchaChannelProcessor() { + super(); + this.setKeyword(DEFAULT_KEYWORD); + } + + //~ Methods ================================================================ + + boolean isContextValidConcerningHumanity(CaptchaSecurityContext context) { + if (context.isHuman() + || (context.getHumanRestrictedResourcesRequestsCount() < getThresold())) { + logger.debug( + "context is valid concerning humanity or request count < thresold"); + + return true; + } else { + logger.debug( + "context is not valid concerning humanity and request count > thresold"); + + return false; + } + } +} diff --git a/core/src/main/java/org/acegisecurity/captcha/package.html b/core/src/main/java/org/acegisecurity/captcha/package.html index 2786b1d912..8ae2702220 100644 --- a/core/src/main/java/org/acegisecurity/captcha/package.html +++ b/core/src/main/java/org/acegisecurity/captcha/package.html @@ -1,6 +1,12 @@ -Captcha classes. +Captcha classes. Contains :
+ diff --git a/core/src/test/java/org/acegisecurity/captcha/AlwaysTestAfterMaxRequestsCaptchaChannelProcessorTests.java b/core/src/test/java/org/acegisecurity/captcha/AlwaysTestAfterMaxRequestsCaptchaChannelProcessorTests.java new file mode 100644 index 0000000000..c48b667691 --- /dev/null +++ b/core/src/test/java/org/acegisecurity/captcha/AlwaysTestAfterMaxRequestsCaptchaChannelProcessorTests.java @@ -0,0 +1,76 @@ +/* Copyright 2004, 2005 Acegi Technology Pty Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.sf.acegisecurity.captcha; + +import junit.framework.*; + +import net.sf.acegisecurity.captcha.AlwaysTestAfterMaxRequestsCaptchaChannelProcessor; + + +/** + * DOCUMENT ME! + * + * @author $author$ + * @version $Revision$ + */ +public class AlwaysTestAfterMaxRequestsCaptchaChannelProcessorTests + extends TestCase { + //~ Instance fields ======================================================== + + AlwaysTestAfterMaxRequestsCaptchaChannelProcessor alwaysTestAfterMaxRequestsCaptchaChannelProcessor; + + //~ Methods ================================================================ + + public void testIsContextValidConcerningHumanity() + throws Exception { + alwaysTestAfterMaxRequestsCaptchaChannelProcessor.setThresold(1); + + CaptchaSecurityContextImpl context = new CaptchaSecurityContextImpl(); + assertTrue(alwaysTestAfterMaxRequestsCaptchaChannelProcessor + .isContextValidConcerningHumanity(context)); + + context.incrementHumanRestrictedRessoucesRequestsCount(); + + alwaysTestAfterMaxRequestsCaptchaChannelProcessor.setThresold(-1); + assertFalse(alwaysTestAfterMaxRequestsCaptchaChannelProcessor + .isContextValidConcerningHumanity(context)); + + alwaysTestAfterMaxRequestsCaptchaChannelProcessor.setThresold(3); + assertTrue(alwaysTestAfterMaxRequestsCaptchaChannelProcessor + .isContextValidConcerningHumanity(context)); + context.incrementHumanRestrictedRessoucesRequestsCount(); + assertTrue(alwaysTestAfterMaxRequestsCaptchaChannelProcessor + .isContextValidConcerningHumanity(context)); + context.incrementHumanRestrictedRessoucesRequestsCount(); + assertFalse(alwaysTestAfterMaxRequestsCaptchaChannelProcessor + .isContextValidConcerningHumanity(context)); + } + + public void testNewContext() { + CaptchaSecurityContextImpl context = new CaptchaSecurityContextImpl(); + + assertFalse(alwaysTestAfterMaxRequestsCaptchaChannelProcessor + .isContextValidConcerningHumanity(context)); + alwaysTestAfterMaxRequestsCaptchaChannelProcessor.setThresold(1); + assertTrue(alwaysTestAfterMaxRequestsCaptchaChannelProcessor + .isContextValidConcerningHumanity(context)); + } + + protected void setUp() throws Exception { + super.setUp(); + alwaysTestAfterMaxRequestsCaptchaChannelProcessor = new AlwaysTestAfterMaxRequestsCaptchaChannelProcessor(); + } +} diff --git a/core/src/test/java/org/acegisecurity/captcha/AlwaysTestAfterTimeInMillisCaptchaChannelProcessorTests.java b/core/src/test/java/org/acegisecurity/captcha/AlwaysTestAfterTimeInMillisCaptchaChannelProcessorTests.java new file mode 100644 index 0000000000..7e6ef6c781 --- /dev/null +++ b/core/src/test/java/org/acegisecurity/captcha/AlwaysTestAfterTimeInMillisCaptchaChannelProcessorTests.java @@ -0,0 +1,98 @@ +/* Copyright 2004, 2005 Acegi Technology Pty Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.sf.acegisecurity.captcha; + +import junit.framework.*; + +import net.sf.acegisecurity.captcha.AlwaysTestAfterTimeInMillisCaptchaChannelProcessor; + + +/** + * WARNING! This test class make some assumptions concerning the compute speed! + * For example the two following instructions should be computed in the same + * millis or the test is not valid. + *

+ * context.setHuman();
+ * assertFalse(alwaysTestAfterTimeInMillisCaptchaChannelProcessor.isContextValidConcerningHumanity(context));
+ * 
+ * This should be the case for most environements unless + * + * + */ +public class AlwaysTestAfterTimeInMillisCaptchaChannelProcessorTests + extends TestCase { + //~ Instance fields ======================================================== + + AlwaysTestAfterTimeInMillisCaptchaChannelProcessor alwaysTestAfterTimeInMillisCaptchaChannelProcessor; + + //~ Methods ================================================================ + + public void testEqualsThresold() { + CaptchaSecurityContext context = new CaptchaSecurityContextImpl(); + assertFalse(alwaysTestAfterTimeInMillisCaptchaChannelProcessor + .isContextValidConcerningHumanity(context)); + + //the two following instructions should be computed or the test is not valid (never fails). This should be the case + // for most environements unless if you run it on a good old TRS-80 (thanks mom). + context.setHuman(); + assertFalse(alwaysTestAfterTimeInMillisCaptchaChannelProcessor + .isContextValidConcerningHumanity(context)); + } + + public void testIsContextValidConcerningHumanity() + throws Exception { + CaptchaSecurityContext context = new CaptchaSecurityContextImpl(); + alwaysTestAfterTimeInMillisCaptchaChannelProcessor.setThresold(100); + context.setHuman(); + + while ((System.currentTimeMillis() + - context.getLastPassedCaptchaDateInMillis()) < alwaysTestAfterTimeInMillisCaptchaChannelProcessor + .getThresold()) { + assertTrue(alwaysTestAfterTimeInMillisCaptchaChannelProcessor + .isContextValidConcerningHumanity(context)); + context.incrementHumanRestrictedRessoucesRequestsCount(); + + long now = System.currentTimeMillis(); + + while ((System.currentTimeMillis() - now) < 1) {} + + ; + } + + assertFalse(alwaysTestAfterTimeInMillisCaptchaChannelProcessor + .isContextValidConcerningHumanity(context)); + } + + public void testNewContext() { + CaptchaSecurityContext context = new CaptchaSecurityContextImpl(); + + //alwaysTestAfterTimeInMillisCaptchaChannelProcessor.setThresold(10); + assertFalse(alwaysTestAfterTimeInMillisCaptchaChannelProcessor + .isContextValidConcerningHumanity(context)); + } + + protected void setUp() throws Exception { + super.setUp(); + alwaysTestAfterTimeInMillisCaptchaChannelProcessor = new AlwaysTestAfterTimeInMillisCaptchaChannelProcessor(); + } +} diff --git a/core/src/test/java/org/acegisecurity/captcha/AlwaysTestBelowAverageTimeInMillisBetweenRequestsChannelProcessorTests.java b/core/src/test/java/org/acegisecurity/captcha/AlwaysTestBelowAverageTimeInMillisBetweenRequestsChannelProcessorTests.java new file mode 100644 index 0000000000..06cc40e61f --- /dev/null +++ b/core/src/test/java/org/acegisecurity/captcha/AlwaysTestBelowAverageTimeInMillisBetweenRequestsChannelProcessorTests.java @@ -0,0 +1,125 @@ +/* Copyright 2004, 2005 Acegi Technology Pty Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.sf.acegisecurity.captcha; + +import junit.framework.TestCase; + + +/** + * DOCUMENT ME! + * + * @author $author$ + * @version $Revision$ + */ +public class AlwaysTestBelowAverageTimeInMillisBetweenRequestsChannelProcessorTests + extends TestCase { + //~ Instance fields ======================================================== + + AlwaysTestBelowAverageTimeInMillisBetweenRequestsChannelProcessor alwaysTestBelowAverageTimeInMillisBetweenRequestsChannelProcessor; + + //~ Methods ================================================================ + + public void testEqualsThresold() { + CaptchaSecurityContext context = new CaptchaSecurityContextImpl(); + alwaysTestBelowAverageTimeInMillisBetweenRequestsChannelProcessor + .setThresold(100); + + context.setHuman(); + + long now = System.currentTimeMillis(); + + while ((System.currentTimeMillis() - now) <= 100) { + assertTrue(alwaysTestBelowAverageTimeInMillisBetweenRequestsChannelProcessor + .isContextValidConcerningHumanity(context)); + } + + context.incrementHumanRestrictedRessoucesRequestsCount(); + assertTrue(alwaysTestBelowAverageTimeInMillisBetweenRequestsChannelProcessor + .isContextValidConcerningHumanity(context)); + + context.setHuman(); + context.incrementHumanRestrictedRessoucesRequestsCount(); + assertFalse(alwaysTestBelowAverageTimeInMillisBetweenRequestsChannelProcessor + .isContextValidConcerningHumanity(context)); + + alwaysTestBelowAverageTimeInMillisBetweenRequestsChannelProcessor + .setThresold(0); + context.setHuman(); + context.incrementHumanRestrictedRessoucesRequestsCount(); + assertFalse(alwaysTestBelowAverageTimeInMillisBetweenRequestsChannelProcessor + .isContextValidConcerningHumanity(context)); + alwaysTestBelowAverageTimeInMillisBetweenRequestsChannelProcessor + .setThresold(0); + } + + public void testIsContextValidConcerningHumanity() + throws Exception { + CaptchaSecurityContext context = new CaptchaSecurityContextImpl(); + alwaysTestBelowAverageTimeInMillisBetweenRequestsChannelProcessor + .setThresold(10); + context.setHuman(); + + while ((System.currentTimeMillis() + - context.getLastPassedCaptchaDateInMillis()) < (10 * alwaysTestBelowAverageTimeInMillisBetweenRequestsChannelProcessor + .getThresold())) { + assertTrue(alwaysTestBelowAverageTimeInMillisBetweenRequestsChannelProcessor + .isContextValidConcerningHumanity(context)); + } + } + + public void testNewContext() { + CaptchaSecurityContext context = new CaptchaSecurityContextImpl(); + assertFalse(alwaysTestBelowAverageTimeInMillisBetweenRequestsChannelProcessor + .isContextValidConcerningHumanity(context)); + + context.setHuman(); + assertTrue(alwaysTestBelowAverageTimeInMillisBetweenRequestsChannelProcessor + .isContextValidConcerningHumanity(context)); + } + + public void testShouldPassAbove() { + CaptchaSecurityContext context = new CaptchaSecurityContextImpl(); + + context.setHuman(); + + int i = 0; + + while ((System.currentTimeMillis() + - context.getLastPassedCaptchaDateInMillis()) < (100 * alwaysTestBelowAverageTimeInMillisBetweenRequestsChannelProcessor + .getThresold())) { + System.out.println((System.currentTimeMillis() + - context.getLastPassedCaptchaDateInMillis())); + + context.incrementHumanRestrictedRessoucesRequestsCount(); + i++; + + while ((System.currentTimeMillis() + - context.getLastPassedCaptchaDateInMillis()) < (alwaysTestBelowAverageTimeInMillisBetweenRequestsChannelProcessor + .getThresold() * i)) {} + + System.out.println((System.currentTimeMillis() + - context.getLastPassedCaptchaDateInMillis())); + + assertTrue(alwaysTestBelowAverageTimeInMillisBetweenRequestsChannelProcessor + .isContextValidConcerningHumanity(context)); + } + } + + protected void setUp() throws Exception { + super.setUp(); + alwaysTestBelowAverageTimeInMillisBetweenRequestsChannelProcessor = new AlwaysTestBelowAverageTimeInMillisBetweenRequestsChannelProcessor(); + } +} diff --git a/core/src/test/java/org/acegisecurity/captcha/CaptchaChannelProcessorTemplateTests.java b/core/src/test/java/org/acegisecurity/captcha/CaptchaChannelProcessorTemplateTests.java new file mode 100644 index 0000000000..5b570accbe --- /dev/null +++ b/core/src/test/java/org/acegisecurity/captcha/CaptchaChannelProcessorTemplateTests.java @@ -0,0 +1,216 @@ +/* Copyright 2004, 2005 Acegi Technology Pty Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package net.sf.acegisecurity.captcha; + +import junit.framework.TestCase; + +import net.sf.acegisecurity.ConfigAttributeDefinition; +import net.sf.acegisecurity.MockFilterChain; +import net.sf.acegisecurity.SecurityConfig; +import net.sf.acegisecurity.context.SecurityContextHolder; +import net.sf.acegisecurity.intercept.web.FilterInvocation; + +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; + +import java.io.IOException; + +import javax.servlet.ServletException; + + +/** + * Tests {@link net.sf.acegisecurity.captcha.CaptchaChannelProcessorTemplate} + * + * @author marc antoine Garrigue + * @version $Id$ + */ +public class CaptchaChannelProcessorTemplateTests extends TestCase { + //~ Methods ================================================================ + + public void testContextRedirect() throws Exception { + CaptchaChannelProcessorTemplate processor = new TestHumanityCaptchaChannelProcessor(); + processor.setKeyword("X"); + + ConfigAttributeDefinition cad = new ConfigAttributeDefinition(); + cad.addConfigAttribute(new SecurityConfig("Y")); + + CaptchaSecurityContext context = new CaptchaSecurityContextImpl(); + SecurityContextHolder.setContext(context); + + CaptchaEntryPoint epoint = new CaptchaEntryPoint(); + epoint.setCaptchaFormUrl("/jcaptcha.do"); + epoint.setIncludeOriginalRequest(false); + + processor.setEntryPoint(epoint); + + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setQueryString("info=true"); + request.setServerName("localhost"); + request.setContextPath("/demo"); + request.setServletPath("/restricted"); + request.setScheme("http"); + request.setServerPort(8000); + + MockHttpServletResponse response = new MockHttpServletResponse(); + MockFilterChain chain = new MockFilterChain(); + FilterInvocation fi = new FilterInvocation(request, response, chain); + + processor.decide(fi, cad); + assertEquals(null, response.getRedirectedUrl()); + processor.setKeyword("Y"); + response = decideWithNewResponse(cad, processor, request); + assertEquals("http://localhost:8000/demo/jcaptcha.do", + response.getRedirectedUrl()); + context.setHuman(); + response = decideWithNewResponse(cad, processor, request); + assertEquals(null, response.getRedirectedUrl()); + } + + public void testDecideRejectsNulls() throws Exception { + CaptchaChannelProcessorTemplate processor = new TestHumanityCaptchaChannelProcessor(); + processor.setEntryPoint(new CaptchaEntryPoint()); + processor.setKeyword("X"); + processor.afterPropertiesSet(); + + try { + processor.decide(null, null); + fail("Should have thrown IllegalArgumentException"); + } catch (IllegalArgumentException expected) { + assertTrue(true); + } + } + + public void testGettersSetters() { + CaptchaChannelProcessorTemplate processor = new TestHumanityCaptchaChannelProcessor(); + assertEquals(null, processor.getKeyword()); + processor.setKeyword("X"); + assertEquals("X", processor.getKeyword()); + + assertEquals(0, processor.getThresold()); + processor.setThresold(1); + assertEquals(1, processor.getThresold()); + + assertTrue(processor.getEntryPoint() == null); + processor.setEntryPoint(new CaptchaEntryPoint()); + assertTrue(processor.getEntryPoint() != null); + } + + public void testIncrementRequestCount() throws Exception { + CaptchaChannelProcessorTemplate processor = new TestHumanityCaptchaChannelProcessor(); + processor.setKeyword("X"); + + ConfigAttributeDefinition cad = new ConfigAttributeDefinition(); + cad.addConfigAttribute(new SecurityConfig("X")); + + CaptchaSecurityContext context = new CaptchaSecurityContextImpl(); + SecurityContextHolder.setContext(context); + + CaptchaEntryPoint epoint = new CaptchaEntryPoint(); + epoint.setCaptchaFormUrl("/jcaptcha.do"); + processor.setEntryPoint(epoint); + + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setQueryString("info=true"); + request.setServerName("localhost"); + request.setContextPath("/demo"); + request.setServletPath("/restricted"); + request.setScheme("http"); + request.setServerPort(8000); + + MockHttpServletResponse response = new MockHttpServletResponse(); + MockFilterChain chain = new MockFilterChain(); + FilterInvocation fi = new FilterInvocation(request, response, chain); + + processor.decide(fi, cad); + assertEquals(0, context.getHumanRestrictedResourcesRequestsCount()); + context.setHuman(); + decideWithNewResponse(cad, processor, request); + assertEquals(1, context.getHumanRestrictedResourcesRequestsCount()); + decideWithNewResponse(cad, processor, request); + assertEquals(2, context.getHumanRestrictedResourcesRequestsCount()); + processor.setKeyword("Y"); + decideWithNewResponse(cad, processor, request); + assertEquals(2, context.getHumanRestrictedResourcesRequestsCount()); + context = new CaptchaSecurityContextImpl(); + decideWithNewResponse(cad, processor, request); + assertEquals(0, context.getHumanRestrictedResourcesRequestsCount()); + } + + public void testMissingEntryPoint() throws Exception { + CaptchaChannelProcessorTemplate processor = new TestHumanityCaptchaChannelProcessor(); + processor.setEntryPoint(null); + + try { + processor.afterPropertiesSet(); + fail("Should have thrown IllegalArgumentException"); + } catch (IllegalArgumentException expected) { + assertEquals("entryPoint required", expected.getMessage()); + } + } + + public void testMissingKeyword() throws Exception { + CaptchaChannelProcessorTemplate processor = new TestHumanityCaptchaChannelProcessor(); + processor.setKeyword(null); + + try { + processor.afterPropertiesSet(); + fail("Should have thrown IllegalArgumentException"); + } catch (IllegalArgumentException expected) {} + + processor.setKeyword(""); + + try { + processor.afterPropertiesSet(); + fail("Should have thrown IllegalArgumentException"); + } catch (IllegalArgumentException expected) {} + } + + public void testSupports() { + CaptchaChannelProcessorTemplate processor = new TestHumanityCaptchaChannelProcessor(); + processor.setKeyword("X"); + assertTrue(processor.supports( + new SecurityConfig(processor.getKeyword()))); + + assertTrue(processor.supports(new SecurityConfig("X"))); + + assertFalse(processor.supports(null)); + + assertFalse(processor.supports(new SecurityConfig("NOT_SUPPORTED"))); + } + + private MockHttpServletResponse decideWithNewResponse( + ConfigAttributeDefinition cad, + CaptchaChannelProcessorTemplate processor, + MockHttpServletRequest request) throws IOException, ServletException { + MockHttpServletResponse response; + MockFilterChain chain; + FilterInvocation fi; + response = new MockHttpServletResponse(); + chain = new MockFilterChain(); + fi = new FilterInvocation(request, response, chain); + processor.decide(fi, cad); + + return response; + } + + //~ Inner Classes ========================================================== + + private class TestHumanityCaptchaChannelProcessor + extends CaptchaChannelProcessorTemplate { + boolean isContextValidConcerningHumanity(CaptchaSecurityContext context) { + return context.isHuman(); + } + } +} diff --git a/core/src/test/java/org/acegisecurity/captcha/CaptchaChannelProcessorTests.java b/core/src/test/java/org/acegisecurity/captcha/CaptchaChannelProcessorTests.java deleted file mode 100644 index 65f3aa3b01..0000000000 --- a/core/src/test/java/org/acegisecurity/captcha/CaptchaChannelProcessorTests.java +++ /dev/null @@ -1,552 +0,0 @@ -/* Copyright 2004 Acegi Technology Pty Limited - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.sf.acegisecurity.captcha; - -import junit.framework.TestCase; -import net.sf.acegisecurity.ConfigAttributeDefinition; -import net.sf.acegisecurity.MockFilterChain; -import net.sf.acegisecurity.SecurityConfig; -import net.sf.acegisecurity.context.SecurityContextHolder; -import net.sf.acegisecurity.intercept.web.FilterInvocation; -import org.springframework.mock.web.MockHttpServletRequest; -import org.springframework.mock.web.MockHttpServletResponse; - -import javax.servlet.ServletException; -import java.io.IOException; - -/** - * Tests {@link CaptchaChannelProcessor} - * - * @author marc antoine Garrigue - * @version $Id$ - */ -public class CaptchaChannelProcessorTests extends TestCase { - - public void testDecideRequestsFirstTestRequests() throws Exception { - ConfigAttributeDefinition cad = new ConfigAttributeDefinition(); - cad.addConfigAttribute(new SecurityConfig("SOME_IGNORED_ATTRIBUTE")); - cad.addConfigAttribute(new SecurityConfig( - "REQUIRES_HUMAN_AFTER_MAX_REQUESTS")); - - CaptchaSecurityContext context = new CaptchaSecurityContextImpl(); - SecurityContextHolder.setContext(context); - - CaptchaChannelProcessor processor = new CaptchaChannelProcessor(); - CaptchaEntryPoint epoint = new CaptchaEntryPoint(); - epoint.setCaptchaFormUrl("/jcaptcha.do"); - epoint.setIncludeOriginalRequest(false); - - processor.setEntryPoint(epoint); - - MockHttpServletRequest request = new MockHttpServletRequest(); - request.setQueryString("info=true"); - request.setServerName("localhost"); - request.setContextPath("/demo"); - request.setServletPath("/restricted"); - request.setScheme("http"); - request.setServerPort(8000); - - MockHttpServletResponse response = new MockHttpServletResponse(); - MockFilterChain chain = new MockFilterChain(); - FilterInvocation fi = new FilterInvocation(request, response, chain); - - processor.decide(fi, cad); - assertEquals(response.getRedirectedUrl(), - "http://localhost:8000/demo/jcaptcha.do"); - - processor.setMaxRequestsBeforeFirstTest(1); - - response = decideWithNewResponse(cad, processor, request); - assertEquals(response.getRedirectedUrl(), null); - - response = decideWithNewResponse(cad, processor, request); - assertEquals(response.getRedirectedUrl(), - "http://localhost:8000/demo/jcaptcha.do"); - - processor.setMaxRequestsBeforeFirstTest(2); - processor.setMaxMillisBeforeReTest(0); - - response = decideWithNewResponse(cad, processor, request); - assertEquals(null, response.getRedirectedUrl()); - - response = decideWithNewResponse(cad, processor, request); - assertEquals("http://localhost:8000/demo/jcaptcha.do", response - .getRedirectedUrl()); - } - - public void testDecideRequestsFirstTestMillis() throws Exception { - ConfigAttributeDefinition cad = new ConfigAttributeDefinition(); - cad.addConfigAttribute(new SecurityConfig("SOME_IGNORED_ATTRIBUTE")); - cad.addConfigAttribute(new SecurityConfig( - "REQUIRES_HUMAN_AFTER_MAX_MILLIS")); - - CaptchaSecurityContext context = new CaptchaSecurityContextImpl(); - SecurityContextHolder.setContext(context); - - CaptchaChannelProcessor processor = new CaptchaChannelProcessor(); - CaptchaEntryPoint epoint = new CaptchaEntryPoint(); - epoint.setCaptchaFormUrl("/jcaptcha.do"); - epoint.setIncludeOriginalRequest(false); - - processor.setEntryPoint(epoint); - - MockHttpServletRequest request = new MockHttpServletRequest(); - request.setQueryString("info=true"); - request.setServerName("localhost"); - request.setContextPath("/demo"); - request.setServletPath("/restricted"); - request.setScheme("http"); - request.setServerPort(8000); - - MockHttpServletResponse response = new MockHttpServletResponse(); - MockFilterChain chain = new MockFilterChain(); - FilterInvocation fi = new FilterInvocation(request, response, chain); - - processor.decide(fi, cad); - assertEquals("http://localhost:8000/demo/jcaptcha.do", response - .getRedirectedUrl()); - - processor.setMaxRequestsBeforeFirstTest(1); - - response = decideWithNewResponse(cad, processor, request); - assertEquals(null, response.getRedirectedUrl()); - - response = decideWithNewResponse(cad, processor, request); - assertEquals("http://localhost:8000/demo/jcaptcha.do", response - .getRedirectedUrl()); - - processor.setMaxRequestsBeforeFirstTest(2); - processor.setMaxRequestsBeforeReTest(0); - - response = decideWithNewResponse(cad, processor, request); - assertEquals(null, response.getRedirectedUrl()); - - response = decideWithNewResponse(cad, processor, request); - assertEquals("http://localhost:8000/demo/jcaptcha.do", response - .getRedirectedUrl()); - - } - - public void testDecideRequestsReTest() throws Exception { - ConfigAttributeDefinition cad = new ConfigAttributeDefinition(); - cad.addConfigAttribute(new SecurityConfig("SOME_IGNORED_ATTRIBUTE")); - cad.addConfigAttribute(new SecurityConfig( - "REQUIRES_HUMAN_AFTER_MAX_REQUESTS")); - - CaptchaSecurityContext context = new CaptchaSecurityContextImpl(); - SecurityContextHolder.setContext(context); - - CaptchaChannelProcessor processor = new CaptchaChannelProcessor(); - CaptchaEntryPoint epoint = new CaptchaEntryPoint(); - epoint.setCaptchaFormUrl("/jcaptcha.do"); - epoint.setIncludeOriginalRequest(false); - - processor.setEntryPoint(epoint); - - MockHttpServletRequest request = new MockHttpServletRequest(); - request.setQueryString("info=true"); - request.setServerName("localhost"); - request.setContextPath("/demo"); - request.setServletPath("/restricted"); - request.setScheme("http"); - request.setServerPort(8000); - - MockHttpServletResponse response = new MockHttpServletResponse(); - MockFilterChain chain = new MockFilterChain(); - FilterInvocation fi = new FilterInvocation(request, response, chain); - - processor.decide(fi, cad); - assertEquals("http://localhost:8000/demo/jcaptcha.do", response - .getRedirectedUrl()); - - processor.setMaxRequestsBeforeFirstTest(1); - - response = decideWithNewResponse(cad, processor, request); - assertEquals(response.getRedirectedUrl(), null); - - response = decideWithNewResponse(cad, processor, request); - assertEquals("http://localhost:8000/demo/jcaptcha.do", response - .getRedirectedUrl()); - - processor.setMaxRequestsBeforeReTest(2); - - response = decideWithNewResponse(cad, processor, request); - assertEquals("http://localhost:8000/demo/jcaptcha.do", response - .getRedirectedUrl()); - - context.setHuman(); - SecurityContextHolder.setContext(context); - - response = decideWithNewResponse(cad, processor, request); - assertEquals(null, response.getRedirectedUrl()); - - response = decideWithNewResponse(cad, processor, request); - assertEquals(null, response.getRedirectedUrl()); - - response = decideWithNewResponse(cad, processor, request); - assertEquals("http://localhost:8000/demo/jcaptcha.do", response - .getRedirectedUrl()); - - processor.setMaxMillisBeforeReTest(0); - context.setHuman(); - SecurityContextHolder.setContext(context); - - response = decideWithNewResponse(cad, processor, request); - assertEquals(null, response.getRedirectedUrl()); - - response = decideWithNewResponse(cad, processor, request); - assertEquals(null, response.getRedirectedUrl()); - - response = decideWithNewResponse(cad, processor, request); - assertEquals("http://localhost:8000/demo/jcaptcha.do", response - .getRedirectedUrl()); - - context.setHuman(); - SecurityContextHolder.setContext(context); - - response = decideWithNewResponse(cad, processor, request); - assertEquals(null, response.getRedirectedUrl()); - - response = decideWithNewResponse(cad, processor, request); - assertEquals(null, response.getRedirectedUrl()); - - response = decideWithNewResponse(cad, processor, request); - assertEquals("http://localhost:8000/demo/jcaptcha.do", response - .getRedirectedUrl()); - } - - private MockHttpServletResponse decideWithNewResponse( - ConfigAttributeDefinition cad, CaptchaChannelProcessor processor, - MockHttpServletRequest request) throws IOException, - ServletException { - MockHttpServletResponse response; - MockFilterChain chain; - FilterInvocation fi; - response = new MockHttpServletResponse(); - chain = new MockFilterChain(); - fi = new FilterInvocation(request, response, chain); - processor.decide(fi, cad); - return response; - } - - public void testDecideRejectsNulls() throws Exception { - CaptchaChannelProcessor processor = new CaptchaChannelProcessor(); - processor.setEntryPoint(new CaptchaEntryPoint()); - processor.afterPropertiesSet(); - - try { - processor.decide(null, null); - fail("Should have thrown IllegalArgumentException"); - } catch (IllegalArgumentException expected) { - assertTrue(true); - } - } - - public void testDecideMillis() throws Exception { - ConfigAttributeDefinition cad = new ConfigAttributeDefinition(); - cad.addConfigAttribute(new SecurityConfig("SOME_IGNORED_ATTRIBUTE")); - cad.addConfigAttribute(new SecurityConfig( - "REQUIRES_HUMAN_AFTER_MAX_MILLIS")); - - CaptchaSecurityContext context = new CaptchaSecurityContextImpl(); - SecurityContextHolder.setContext(context); - - CaptchaChannelProcessor processor = new CaptchaChannelProcessor(); - CaptchaEntryPoint epoint = new CaptchaEntryPoint(); - epoint.setCaptchaFormUrl("/jcaptcha.do"); - epoint.setIncludeOriginalRequest(false); - - processor.setEntryPoint(epoint); - - MockHttpServletRequest request = new MockHttpServletRequest(); - request.setQueryString("info=true"); - request.setServerName("localhost"); - request.setContextPath("/demo"); - request.setServletPath("/restricted"); - request.setScheme("http"); - request.setServerPort(8000); - - MockHttpServletResponse response = new MockHttpServletResponse(); - MockFilterChain chain = new MockFilterChain(); - FilterInvocation fi = new FilterInvocation(request, response, chain); - - processor.decide(fi, cad); - assertEquals("http://localhost:8000/demo/jcaptcha.do", response - .getRedirectedUrl()); - - processor.setMaxRequestsBeforeFirstTest(1); - - response = decideWithNewResponse(cad, processor, request); - assertEquals(response.getRedirectedUrl(), null); - - response = decideWithNewResponse(cad, processor, request); - assertEquals("http://localhost:8000/demo/jcaptcha.do", response - .getRedirectedUrl()); - - processor.setMaxMillisBeforeReTest(100); - - response = decideWithNewResponse(cad, processor, request); - assertEquals("http://localhost:8000/demo/jcaptcha.do", response - .getRedirectedUrl()); - - context.setHuman(); - SecurityContextHolder.setContext(context); - - response = decideWithNewResponse(cad, processor, request); - assertEquals(null, response.getRedirectedUrl()); - - waitFor(100); - - response = decideWithNewResponse(cad, processor, request); - assertEquals("http://localhost:8000/demo/jcaptcha.do", response - .getRedirectedUrl()); - - processor.setMaxRequestsBeforeReTest(0); - context.setHuman(); - SecurityContextHolder.setContext(context); - - response = decideWithNewResponse(cad, processor, request); - assertEquals(null, response.getRedirectedUrl()); - - response = decideWithNewResponse(cad, processor, request); - assertEquals(null, response.getRedirectedUrl()); - - waitFor(100); - - response = decideWithNewResponse(cad, processor, request); - assertEquals("http://localhost:8000/demo/jcaptcha.do", response - .getRedirectedUrl()); - - context.setHuman(); - SecurityContextHolder.setContext(context); - - response = decideWithNewResponse(cad, processor, request); - assertEquals(null, response.getRedirectedUrl()); - - response = decideWithNewResponse(cad, processor, request); - assertEquals(null, response.getRedirectedUrl()); - - waitFor(100); - - response = decideWithNewResponse(cad, processor, request); - assertEquals("http://localhost:8000/demo/jcaptcha.do", response - .getRedirectedUrl()); - } - - public void testDecideBoth() throws Exception { - ConfigAttributeDefinition cad = new ConfigAttributeDefinition(); - cad.addConfigAttribute(new SecurityConfig("SOME_IGNORED_ATTRIBUTE")); - cad.addConfigAttribute(new SecurityConfig( - "REQUIRES_HUMAN_AFTER_MAX_MILLIS")); - cad.addConfigAttribute(new SecurityConfig( - "REQUIRES_HUMAN_AFTER_MAX_REQUESTS")); - - CaptchaSecurityContext context = new CaptchaSecurityContextImpl(); - SecurityContextHolder.setContext(context); - - CaptchaChannelProcessor processor = new CaptchaChannelProcessor(); - CaptchaEntryPoint epoint = new CaptchaEntryPoint(); - epoint.setCaptchaFormUrl("/jcaptcha.do"); - epoint.setIncludeOriginalRequest(false); - - processor.setEntryPoint(epoint); - - MockHttpServletRequest request = new MockHttpServletRequest(); - request.setQueryString("info=true"); - request.setServerName("localhost"); - request.setContextPath("/demo"); - request.setServletPath("/restricted"); - request.setScheme("http"); - request.setServerPort(8000); - - MockHttpServletResponse response = new MockHttpServletResponse(); - MockFilterChain chain = new MockFilterChain(); - FilterInvocation fi = new FilterInvocation(request, response, chain); - - processor.decide(fi, cad); - assertEquals("http://localhost:8000/demo/jcaptcha.do", response - .getRedirectedUrl()); - - processor.setMaxRequestsBeforeFirstTest(1); - - response = decideWithNewResponse(cad, processor, request); - assertEquals(response.getRedirectedUrl(), null); - - response = decideWithNewResponse(cad, processor, request); - assertEquals("http://localhost:8000/demo/jcaptcha.do", response - .getRedirectedUrl()); - - processor.setMaxMillisBeforeReTest(100); - processor.setMaxRequestsBeforeReTest(2); - - response = decideWithNewResponse(cad, processor, request); - assertEquals("http://localhost:8000/demo/jcaptcha.do", response - .getRedirectedUrl()); - - context.setHuman(); - SecurityContextHolder.setContext(context); - - response = decideWithNewResponse(cad, processor, request); - assertEquals(null, response.getRedirectedUrl()); - - waitFor(100); - - response = decideWithNewResponse(cad, processor, request); - assertEquals("http://localhost:8000/demo/jcaptcha.do", response - .getRedirectedUrl()); - - response = decideWithNewResponse(cad, processor, request); - assertEquals("http://localhost:8000/demo/jcaptcha.do", response - .getRedirectedUrl()); - - context.setHuman(); - SecurityContextHolder.setContext(context); - - response = decideWithNewResponse(cad, processor, request); - assertEquals(null, response.getRedirectedUrl()); - - response = decideWithNewResponse(cad, processor, request); - assertEquals(null, response.getRedirectedUrl()); - - response = decideWithNewResponse(cad, processor, request); - assertEquals("http://localhost:8000/demo/jcaptcha.do", response - .getRedirectedUrl()); - - response = decideWithNewResponse(cad, processor, request); - assertEquals("http://localhost:8000/demo/jcaptcha.do", response - .getRedirectedUrl()); - - context.setHuman(); - SecurityContextHolder.setContext(context); - - response = decideWithNewResponse(cad, processor, request); - assertEquals(null, response.getRedirectedUrl()); - - waitFor(100); - - response = decideWithNewResponse(cad, processor, request); - assertEquals("http://localhost:8000/demo/jcaptcha.do", response - .getRedirectedUrl()); - - response = decideWithNewResponse(cad, processor, request); - assertEquals("http://localhost:8000/demo/jcaptcha.do", response - .getRedirectedUrl()); - } - - public void testGettersSetters() { - CaptchaChannelProcessor processor = new CaptchaChannelProcessor(); - assertEquals("REQUIRES_HUMAN_AFTER_MAX_MILLIS", processor - .getRequiresHumanAfterMaxMillisKeyword()); - processor.setRequiresHumanAfterMaxMillisKeyword("X"); - assertEquals("X", processor.getRequiresHumanAfterMaxMillisKeyword()); - - assertEquals("REQUIRES_HUMAN_AFTER_MAX_REQUESTS", processor - .getRequiresHumanAfterMaxRequestsKeyword()); - processor.setRequiresHumanAfterMaxRequestsKeyword("Y"); - assertEquals("Y", processor.getRequiresHumanAfterMaxRequestsKeyword()); - - assertEquals(0, processor.getMaxRequestsBeforeFirstTest()); - processor.setMaxRequestsBeforeFirstTest(1); - assertEquals(1, processor.getMaxRequestsBeforeFirstTest()); - - assertEquals(-1, processor.getMaxRequestsBeforeReTest()); - processor.setMaxRequestsBeforeReTest(11); - assertEquals(11, processor.getMaxRequestsBeforeReTest()); - - assertEquals(-1, processor.getMaxMillisBeforeReTest()); - processor.setMaxMillisBeforeReTest(111); - assertEquals(111, processor.getMaxMillisBeforeReTest()); - - assertTrue(processor.getEntryPoint() == null); - processor.setEntryPoint(new CaptchaEntryPoint()); - assertTrue(processor.getEntryPoint() != null); - } - - public void testMissingEntryPoint() throws Exception { - CaptchaChannelProcessor processor = new CaptchaChannelProcessor(); - processor.setEntryPoint(null); - - try { - processor.afterPropertiesSet(); - fail("Should have thrown IllegalArgumentException"); - } catch (IllegalArgumentException expected) { - assertEquals("entryPoint required", expected.getMessage()); - } - } - - public void testMissingKeyword() throws Exception { - CaptchaChannelProcessor processor = new CaptchaChannelProcessor(); - processor.setRequiresHumanAfterMaxMillisKeyword(null); - - try { - processor.afterPropertiesSet(); - fail("Should have thrown IllegalArgumentException"); - } catch (IllegalArgumentException expected) { - - } - processor.setRequiresHumanAfterMaxMillisKeyword(""); - - try { - processor.afterPropertiesSet(); - fail("Should have thrown IllegalArgumentException"); - } catch (IllegalArgumentException expected) { - - } - processor.setRequiresHumanAfterMaxRequestsKeyword(""); - - try { - processor.afterPropertiesSet(); - fail("Should have thrown IllegalArgumentException"); - } catch (IllegalArgumentException expected) { - - } - - processor.setRequiresHumanAfterMaxRequestsKeyword(null); - - try { - processor.afterPropertiesSet(); - fail("Should have thrown IllegalArgumentException"); - } catch (IllegalArgumentException expected) { - - } - - } - - public void testSupports() { - CaptchaChannelProcessor processor = new CaptchaChannelProcessor(); - assertTrue(processor.supports(new SecurityConfig(processor - .getRequiresHumanAfterMaxMillisKeyword()))); - assertTrue(processor.supports(new SecurityConfig(processor - .getRequiresHumanAfterMaxRequestsKeyword()))); - - assertTrue(processor.supports(new SecurityConfig( - "REQUIRES_HUMAN_AFTER_MAX_REQUESTS"))); - assertTrue(processor.supports(new SecurityConfig( - "REQUIRES_HUMAN_AFTER_MAX_MILLIS"))); - - assertFalse(processor.supports(null)); - - assertFalse(processor.supports(new SecurityConfig("NOT_SUPPORTED"))); - } - - private void waitFor(int time){ - long start=System.currentTimeMillis(); - while(System.currentTimeMillis()= 0); + assertTrue("should be less than 0,1 seconde", + (context.getLastPassedCaptchaDateInMillis() - now) < 100); } public void testSetHuman() { @@ -39,47 +72,11 @@ public class CaptchaSecurityContextImplTests extends SecurityContextImplTests { long now = System.currentTimeMillis(); context.setHuman(); assertEquals("should be human", true, context.isHuman()); - assertTrue("should be more than 0", context - .getLastPassedCaptchaDateInMillis() - - now >= 0); - assertTrue("should be less than 0,1 seconde", context - .getLastPassedCaptchaDateInMillis() - - now < 100); - assertEquals("should be 0", 0, context - .getHumanRestrictedResourcesRequestsCount()); + assertTrue("should be more than 0", + (context.getLastPassedCaptchaDateInMillis() - now) >= 0); + assertTrue("should be less than 0,1 seconde", + (context.getLastPassedCaptchaDateInMillis() - now) < 100); + assertEquals("should be 0", 0, + context.getHumanRestrictedResourcesRequestsCount()); } - - public void testIncrementRequests() { - CaptchaSecurityContext context = new CaptchaSecurityContextImpl(); - context.setHuman(); - assertEquals("should be human", true, context.isHuman()); - assertEquals("should be 0", 0, context - .getHumanRestrictedResourcesRequestsCount()); - context.incrementHumanRestrictedRessoucesRequestsCount(); - assertEquals("should be 1", 1, context - .getHumanRestrictedResourcesRequestsCount()); - } - - public void testResetHuman() { - CaptchaSecurityContext context = new CaptchaSecurityContextImpl(); - context.setHuman(); - assertEquals("should be human", true, context.isHuman()); - assertEquals("should be 0", 0, context - .getHumanRestrictedResourcesRequestsCount()); - context.incrementHumanRestrictedRessoucesRequestsCount(); - assertEquals("should be 1", 1, context - .getHumanRestrictedResourcesRequestsCount()); - long now = System.currentTimeMillis(); - context.setHuman(); - assertEquals("should be 0", 0, context - .getHumanRestrictedResourcesRequestsCount()); - assertTrue("should be more than 0", context - .getLastPassedCaptchaDateInMillis() - - now >= 0); - assertTrue("should be less than 0,1 seconde", context - .getLastPassedCaptchaDateInMillis() - - now < 100); - - } - } diff --git a/core/src/test/java/org/acegisecurity/captcha/CaptchaValidationProcessingFilterTests.java b/core/src/test/java/org/acegisecurity/captcha/CaptchaValidationProcessingFilterTests.java index 688ab47926..e965890c59 100644 --- a/core/src/test/java/org/acegisecurity/captcha/CaptchaValidationProcessingFilterTests.java +++ b/core/src/test/java/org/acegisecurity/captcha/CaptchaValidationProcessingFilterTests.java @@ -1,4 +1,4 @@ -/* Copyright 2004 Acegi Technology Pty Limited +/* Copyright 2004, 2005 Acegi Technology Pty Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,10 +16,13 @@ package net.sf.acegisecurity.captcha; import junit.framework.TestCase; + import net.sf.acegisecurity.context.SecurityContextHolder; import net.sf.acegisecurity.util.MockFilterChain; + import org.springframework.mock.web.MockHttpServletRequest; + /** * Tests {@link CaptchaValidationProcessingFilter}. * @@ -27,9 +30,10 @@ import org.springframework.mock.web.MockHttpServletRequest; * @version $Id$ */ public class CaptchaValidationProcessingFilterTests extends TestCase { + //~ Methods ================================================================ /* - */ + */ public void testAfterPropertiesSet() throws Exception { CaptchaValidationProcessingFilter filter = new CaptchaValidationProcessingFilter(); @@ -38,54 +42,27 @@ public class CaptchaValidationProcessingFilterTests extends TestCase { fail("should have thrown an invalid argument exception"); } catch (Exception e) { assertTrue("should be an InvalidArgumentException", - IllegalArgumentException.class.isAssignableFrom(e - .getClass())); + IllegalArgumentException.class.isAssignableFrom(e.getClass())); } filter.setCaptchaService(new MockCaptchaServiceProxy()); filter.afterPropertiesSet(); filter.setCaptchaValidationParameter(null); + try { filter.afterPropertiesSet(); fail("should have thrown an invalid argument exception"); } catch (Exception e) { assertTrue("should be an InvalidArgumentException", - IllegalArgumentException.class.isAssignableFrom(e - .getClass())); + IllegalArgumentException.class.isAssignableFrom(e.getClass())); } - - } /* - * Test method for - * 'net.sf.acegisecurity.captcha.CaptchaValidationProcessingFilter.doFilter(ServletRequest, - * ServletResponse, FilterChain)' - */ - public void testDoFilterWithoutRequestParameter() throws Exception { - CaptchaSecurityContext context = new CaptchaSecurityContextImpl(); - SecurityContextHolder.setContext(context); - MockHttpServletRequest request = new MockHttpServletRequest(); - CaptchaValidationProcessingFilter filter = new CaptchaValidationProcessingFilter(); - MockCaptchaServiceProxy service = new MockCaptchaServiceProxy(); - MockFilterChain chain = new MockFilterChain(true); - filter.setCaptchaService(service); - filter.doFilter(request, null, chain); - assertFalse("proxy should not have been called", service.hasBeenCalled); - assertFalse("context should not have been updated", context.isHuman()); - // test with valid - service.valid = true; - filter.doFilter(request, null, chain); - assertFalse("proxy should not have been called", service.hasBeenCalled); - assertFalse("context should not have been updated", context.isHuman()); - - } - - /* - * Test method for - * 'net.sf.acegisecurity.captcha.CaptchaValidationProcessingFilter.doFilter(ServletRequest, - * ServletResponse, FilterChain)' - */ + * Test method for + * 'net.sf.acegisecurity.captcha.CaptchaValidationProcessingFilter.doFilter(ServletRequest, + * ServletResponse, FilterChain)' + */ public void testDoFilterWithRequestParameter() throws Exception { CaptchaSecurityContext context = new CaptchaSecurityContextImpl(); SecurityContextHolder.setContext(context); @@ -93,10 +70,7 @@ public class CaptchaValidationProcessingFilterTests extends TestCase { MockHttpServletRequest request = new MockHttpServletRequest(); CaptchaValidationProcessingFilter filter = new CaptchaValidationProcessingFilter(); - request - .addParameter( - filter.getCaptchaValidationParameter(), - ""); + request.addParameter(filter.getCaptchaValidationParameter(), ""); MockCaptchaServiceProxy service = new MockCaptchaServiceProxy(); MockFilterChain chain = new MockFilterChain(true); @@ -104,12 +78,36 @@ public class CaptchaValidationProcessingFilterTests extends TestCase { filter.doFilter(request, null, chain); assertTrue("should have been called", service.hasBeenCalled); assertFalse("context should not have been updated", context.isHuman()); + // test with valid service.valid = true; filter.doFilter(request, null, chain); assertTrue("should have been called", service.hasBeenCalled); assertTrue("context should have been updated", context.isHuman()); - } + /* + * Test method for + * 'net.sf.acegisecurity.captcha.CaptchaValidationProcessingFilter.doFilter(ServletRequest, + * ServletResponse, FilterChain)' + */ + public void testDoFilterWithoutRequestParameter() throws Exception { + CaptchaSecurityContext context = new CaptchaSecurityContextImpl(); + SecurityContextHolder.setContext(context); + + MockHttpServletRequest request = new MockHttpServletRequest(); + CaptchaValidationProcessingFilter filter = new CaptchaValidationProcessingFilter(); + MockCaptchaServiceProxy service = new MockCaptchaServiceProxy(); + MockFilterChain chain = new MockFilterChain(true); + filter.setCaptchaService(service); + filter.doFilter(request, null, chain); + assertFalse("proxy should not have been called", service.hasBeenCalled); + assertFalse("context should not have been updated", context.isHuman()); + + // test with valid + service.valid = true; + filter.doFilter(request, null, chain); + assertFalse("proxy should not have been called", service.hasBeenCalled); + assertFalse("context should not have been updated", context.isHuman()); + } } diff --git a/core/src/test/java/org/acegisecurity/captcha/MockCaptchaServiceProxy.java b/core/src/test/java/org/acegisecurity/captcha/MockCaptchaServiceProxy.java index 6b3197e9ee..d1cf9c2a05 100644 --- a/core/src/test/java/org/acegisecurity/captcha/MockCaptchaServiceProxy.java +++ b/core/src/test/java/org/acegisecurity/captcha/MockCaptchaServiceProxy.java @@ -1,4 +1,4 @@ -/* Copyright 2004 Acegi Technology Pty Limited +/* Copyright 2004, 2005 Acegi Technology Pty Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,19 +16,22 @@ package net.sf.acegisecurity.captcha; /** + * DOCUMENT ME! + * * @author marc antoine Garrigue * @version $Id$ */ public class MockCaptchaServiceProxy implements CaptchaServiceProxy { - - public boolean valid = false; + //~ Instance fields ======================================================== public boolean hasBeenCalled = false; + public boolean valid = false; + + //~ Methods ================================================================ public boolean validateReponseForId(String id, Object response) { hasBeenCalled = true; + return valid; - } - } diff --git a/core/src/test/java/org/acegisecurity/captcha/TestOnceAfterMaxRequestsCaptchaChannelProcessorTests.java b/core/src/test/java/org/acegisecurity/captcha/TestOnceAfterMaxRequestsCaptchaChannelProcessorTests.java new file mode 100644 index 0000000000..7ac277750c --- /dev/null +++ b/core/src/test/java/org/acegisecurity/captcha/TestOnceAfterMaxRequestsCaptchaChannelProcessorTests.java @@ -0,0 +1,84 @@ +/* Copyright 2004, 2005 Acegi Technology Pty Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.sf.acegisecurity.captcha; + +import junit.framework.*; + +import net.sf.acegisecurity.captcha.TestOnceAfterMaxRequestsCaptchaChannelProcessor; + + +/** + * DOCUMENT ME! + * + * @author $author$ + * @version $Revision$ + */ +public class TestOnceAfterMaxRequestsCaptchaChannelProcessorTests + extends TestCase { + //~ Instance fields ======================================================== + + TestOnceAfterMaxRequestsCaptchaChannelProcessor testOnceAfterMaxRequestsCaptchaChannelProcessor; + + //~ Methods ================================================================ + + public void testIsContextValidConcerningHumanity() + throws Exception { + testOnceAfterMaxRequestsCaptchaChannelProcessor.setThresold(1); + + CaptchaSecurityContextImpl context = new CaptchaSecurityContextImpl(); + assertTrue(testOnceAfterMaxRequestsCaptchaChannelProcessor + .isContextValidConcerningHumanity(context)); + + context.incrementHumanRestrictedRessoucesRequestsCount(); + + testOnceAfterMaxRequestsCaptchaChannelProcessor.setThresold(-1); + assertFalse(testOnceAfterMaxRequestsCaptchaChannelProcessor + .isContextValidConcerningHumanity(context)); + + testOnceAfterMaxRequestsCaptchaChannelProcessor.setThresold(3); + assertTrue(testOnceAfterMaxRequestsCaptchaChannelProcessor + .isContextValidConcerningHumanity(context)); + context.incrementHumanRestrictedRessoucesRequestsCount(); + assertTrue(testOnceAfterMaxRequestsCaptchaChannelProcessor + .isContextValidConcerningHumanity(context)); + context.incrementHumanRestrictedRessoucesRequestsCount(); + assertFalse(testOnceAfterMaxRequestsCaptchaChannelProcessor + .isContextValidConcerningHumanity(context)); + context.setHuman(); + + for (int i = 0; + i < (2 * testOnceAfterMaxRequestsCaptchaChannelProcessor + .getThresold()); i++) { + assertTrue(testOnceAfterMaxRequestsCaptchaChannelProcessor + .isContextValidConcerningHumanity(context)); + } + } + + public void testNewContext() { + CaptchaSecurityContextImpl context = new CaptchaSecurityContextImpl(); + + assertFalse(testOnceAfterMaxRequestsCaptchaChannelProcessor + .isContextValidConcerningHumanity(context)); + testOnceAfterMaxRequestsCaptchaChannelProcessor.setThresold(1); + assertTrue(testOnceAfterMaxRequestsCaptchaChannelProcessor + .isContextValidConcerningHumanity(context)); + } + + protected void setUp() throws Exception { + super.setUp(); + testOnceAfterMaxRequestsCaptchaChannelProcessor = new TestOnceAfterMaxRequestsCaptchaChannelProcessor(); + } +}