mirror of
https://github.com/spring-projects/spring-security.git
synced 2025-07-12 13:23:29 +00:00
Initial commit for captcha adapter
This commit is contained in:
parent
a67b529734
commit
3287439421
@ -0,0 +1,361 @@
|
|||||||
|
/* 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* Ensures the user has enougth human privileges by review of the
|
||||||
|
* {@link net.sf.acegisecurity.captcha.CaptchaSecurityContext}.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <P>
|
||||||
|
* The class takes 3 required attributes :
|
||||||
|
* <ul>
|
||||||
|
* <li>maxRequestsBeforeFirstTest : used by
|
||||||
|
* {@link #getRequiresHumanAfterMaxRequestsKeyword()} and
|
||||||
|
* {@link #getRequiresHumanAfterMaxMillisKeyword()}<br>
|
||||||
|
* default value = 0 (ie first request).</li>
|
||||||
|
* <li>maxRequestsBeforeReTest : used by
|
||||||
|
* {@link #getRequiresHumanAfterMaxMillisKeyword()}<br>
|
||||||
|
* default value = -1 (ie disabled, once in a {@link CaptchaSecurityContext}'s
|
||||||
|
* life).</li>
|
||||||
|
* <li>maxMillisBeforeReTest: used by
|
||||||
|
* {@link #getRequiresHumanAfterMaxMillisKeyword()} <br>
|
||||||
|
* default value = -1 (ie disabled, once in a {@link CaptchaSecurityContext}'s
|
||||||
|
* life).</li>
|
||||||
|
* </ul>
|
||||||
|
* The class responds to two case-sensitive keywords :
|
||||||
|
* <ul>
|
||||||
|
* <li>{@link #getRequiresHumanAfterMaxRequestsKeyword()} <br>
|
||||||
|
* default value = <code>REQUIRES_HUMAN_AFTER_MAX_REQUESTS</code> <br>
|
||||||
|
* if detected, checks if :
|
||||||
|
* <ul>
|
||||||
|
* <ul>
|
||||||
|
* <li><code>{@link CaptchaSecurityContext#isHuman()} == true</code> </li>
|
||||||
|
* <li><b>or</b></li>
|
||||||
|
* <li><code>{@link CaptchaSecurityContext#getHumanRestrictedResourcesRequestsCount()} < maxRequestsBeforeFirstTest</code></b></li>
|
||||||
|
* </ul>
|
||||||
|
* <li><b>and</b></li>
|
||||||
|
* <ul>
|
||||||
|
* <li><code>{@link CaptchaSecurityContext#getHumanRestrictedResourcesRequestsCount()} < maxRequestsBeforeReTest </code></li>
|
||||||
|
* <li><b>or</b></li>
|
||||||
|
* <li><code>maxRequestsBeforeReTest < 0 </code></b></li>
|
||||||
|
* </ul>
|
||||||
|
* </ul>
|
||||||
|
* </li>
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* <li>{@link #getRequiresHumanUntilMaxRequestsKeyword()} <br>
|
||||||
|
* default value = <code>REQUIRES_HUMAN_AFTER_MAX_MILLIS</code> <br>
|
||||||
|
* if detected, checks if :
|
||||||
|
*
|
||||||
|
* <ul>
|
||||||
|
* <ul>
|
||||||
|
* <li><code>{@link CaptchaSecurityContext#isHuman()} == true</code> </li>
|
||||||
|
* <li><b>or</b></li>
|
||||||
|
* <li><code>{@link CaptchaSecurityContext#getHumanRestrictedResourcesRequestsCount()} < =maxRequestsBeforeFirstTest</code></b></li>
|
||||||
|
* </ul>
|
||||||
|
* <li><b>and</b></li>
|
||||||
|
* <ul>
|
||||||
|
* <li><code>System.currentTimeMillis()-{@link CaptchaSecurityContext#getLastPassedCaptchaDateInMillis()} <= maxMillisBeforeReTest </code></li>
|
||||||
|
* <li><b>or</b></li>
|
||||||
|
* <li><code>maxMillisBeforeReTest < 0 </code></b></li>
|
||||||
|
* </ul>
|
||||||
|
* </ul>
|
||||||
|
* </li>
|
||||||
|
* </ul>
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* <u>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})
|
||||||
|
* </u><br>
|
||||||
|
* <ul>
|
||||||
|
* <li>Once in a session and at first request : use the <br>
|
||||||
|
* REQUIRES_HUMAN_AFTER_MAX_REQUESTS keyword <br>
|
||||||
|
* with a maxRequestsBeforeFirstTest=0<br>
|
||||||
|
* and a maxRequestsBeforeReTest=-1<br>
|
||||||
|
* </li>
|
||||||
|
* <br>
|
||||||
|
*
|
||||||
|
* <li>Once in a session and only after 3 requests : use the <br>
|
||||||
|
* REQUIRES_HUMAN_AFTER_MAX_REQUESTS keyword <br>
|
||||||
|
* with a maxRequestsBeforeFirstTest=3</li>
|
||||||
|
* and a maxRequestsBeforeReTest=-1<br>
|
||||||
|
* <br>
|
||||||
|
*
|
||||||
|
* <li>Every request and only after 5 requests : use the <br>
|
||||||
|
* REQUIRES_HUMAN_AFTER_MAX_REQUESTS <br>
|
||||||
|
* with a maxRequestsBeforeReTest=0<br>
|
||||||
|
* and a maxRequestsBeforeFirstTest=5</li>
|
||||||
|
* <br>
|
||||||
|
*
|
||||||
|
* <li>Every 3 requests and every minute : use the <br>
|
||||||
|
* REQUIRES_HUMAN_AFTER_MAX_MILLIS keywords <br>
|
||||||
|
* with a maxMillisBeforeReTest=6000 <br>
|
||||||
|
* and a maxRequestsBeforeFirstTest=3</li>
|
||||||
|
* <br>
|
||||||
|
*
|
||||||
|
* <li>Every 20 requests and every hour and only after 100 requests : use the
|
||||||
|
* <br>
|
||||||
|
* REQUIRES_HUMAN_AFTER_MAX_REQUESTS <br>
|
||||||
|
* and the REQUIRES_HUMAN_AFTER_MAX_MILLIS <br>
|
||||||
|
* and the REQUIRES_HUMAN_AFTER_MAX_REQUESTS keywords <br>
|
||||||
|
* with a maxRequestsBeforeReTest=20 <br>
|
||||||
|
* and a maxMillisBeforeReTest=3600000 <br>
|
||||||
|
* and amaxRequestsBeforeFirstTest=1000</li>
|
||||||
|
*
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @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 ChannelEntryPoint entryPoint;
|
||||||
|
|
||||||
|
private int maxRequestsBeforeReTest = -1;
|
||||||
|
|
||||||
|
private int maxRequestsBeforeFirstTest = 0;
|
||||||
|
|
||||||
|
private long maxMillisBeforeReTest = -1;
|
||||||
|
|
||||||
|
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 = (CaptchaSecurityContext) SecurityContextHolder
|
||||||
|
.getContext();
|
||||||
|
|
||||||
|
Iterator iter = config.getConfigAttributes();
|
||||||
|
boolean shouldRedirect = true;
|
||||||
|
|
||||||
|
while (iter.hasNext()) {
|
||||||
|
ConfigAttribute attribute = (ConfigAttribute) iter.next();
|
||||||
|
|
||||||
|
if (supports(attribute)) {
|
||||||
|
logger.debug("supports this attribute : " + attribute);
|
||||||
|
if (isContextValidForAttribute(context, attribute)) {
|
||||||
|
shouldRedirect = false;
|
||||||
|
} else {
|
||||||
|
// reset if already passed a constraint
|
||||||
|
|
||||||
|
shouldRedirect = true;
|
||||||
|
// break at first unsatisfy contraint
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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 (attribute.getAttribute().equals(
|
||||||
|
getRequiresHumanAfterMaxRequestsKeyword())) {
|
||||||
|
if (isContextValidConcerningHumanOrFirstTest(context)
|
||||||
|
&& isContextValidConcerningReTest(context)) {
|
||||||
|
valid = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// test the REQUIRES_HUMAN_AFTER_MAX_MILLIS keyword
|
||||||
|
if (attribute.getAttribute().equals(
|
||||||
|
getRequiresHumanAfterMaxMillisKeyword())) {
|
||||||
|
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)
|
||||||
|
&& (attribute.getAttribute().equals(
|
||||||
|
getRequiresHumanAfterMaxRequestsKeyword()) || attribute
|
||||||
|
.getAttribute().equals(
|
||||||
|
getRequiresHumanAfterMaxMillisKeyword())
|
||||||
|
|
||||||
|
)) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,287 @@
|
|||||||
|
/* 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.Enumeration;
|
||||||
|
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.ServletRequest;
|
||||||
|
import javax.servlet.ServletResponse;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import net.sf.acegisecurity.securechannel.ChannelEntryPoint;
|
||||||
|
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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The captcha entry point : redirect to the captcha test page. <br/>
|
||||||
|
*
|
||||||
|
* This entry point can force the use of SSL : see {@link #getForceHttps()}<br/>
|
||||||
|
*
|
||||||
|
* This entry point allows internal OR external redirect : see
|
||||||
|
* {@link #setOutsideWebApp(boolean)}<br/>/ Original request can be added to
|
||||||
|
* the redirect path using a special parameter : see
|
||||||
|
* {@link #getOriginalRequestParameterName()} and
|
||||||
|
* {@link #setIncludeOriginalRequest()} <br/> <br/> Default values :<br/>
|
||||||
|
* forceHttps = false<br/> includesOriginalRequest = false<br/>
|
||||||
|
* originalRequestParameterName= "originalRequest"<br/> isOutsideWebApp=false<br/>
|
||||||
|
*
|
||||||
|
* @author marc antoine Garrigue
|
||||||
|
* @version $Id$
|
||||||
|
*/
|
||||||
|
public class CaptchaEntryPoint implements ChannelEntryPoint, InitializingBean {
|
||||||
|
// ~ Static fields/initializers
|
||||||
|
// =============================================
|
||||||
|
|
||||||
|
private static final Log logger = LogFactory
|
||||||
|
.getLog(CaptchaEntryPoint.class);
|
||||||
|
|
||||||
|
// ~ Instance fields
|
||||||
|
// ========================================================
|
||||||
|
|
||||||
|
private PortMapper portMapper = new PortMapperImpl();
|
||||||
|
|
||||||
|
private PortResolver portResolver = new PortResolverImpl();
|
||||||
|
|
||||||
|
private String captchaFormUrl;
|
||||||
|
|
||||||
|
private boolean forceHttps = false;
|
||||||
|
|
||||||
|
private String originalRequestParameterName = "originalRequest";
|
||||||
|
|
||||||
|
private boolean isOutsideWebApp = false;
|
||||||
|
|
||||||
|
private boolean includeOriginalRequest = false;
|
||||||
|
|
||||||
|
// ~ 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
|
||||||
|
* <code>https</code>, then
|
||||||
|
*
|
||||||
|
* @param forceHttps
|
||||||
|
*/
|
||||||
|
public void setForceHttps(boolean forceHttps) {
|
||||||
|
this.forceHttps = forceHttps;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getForceHttps() {
|
||||||
|
return forceHttps;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The URL where the <code>CaptchaProcessingFilter</code> login page can
|
||||||
|
* be found. Should be relative to the web-app context path, and include a
|
||||||
|
* leading <code>/</code>
|
||||||
|
*
|
||||||
|
* @param captchaFormUrl
|
||||||
|
*/
|
||||||
|
public void setCaptchaFormUrl(String loginFormUrl) {
|
||||||
|
this.captchaFormUrl = loginFormUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the captcha test page to redirect to.
|
||||||
|
*/
|
||||||
|
public String getCaptchaFormUrl() {
|
||||||
|
return captchaFormUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPortMapper(PortMapper portMapper) {
|
||||||
|
this.portMapper = portMapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PortMapper getPortMapper() {
|
||||||
|
return portMapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPortResolver(PortResolver portResolver) {
|
||||||
|
this.portResolver = portResolver;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PortResolver getPortResolver() {
|
||||||
|
return portResolver;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isOutsideWebApp() {
|
||||||
|
return isOutsideWebApp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 String getOriginalRequestParameterName() {
|
||||||
|
return originalRequestParameterName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sets the parameter under which the original request url will be appended
|
||||||
|
* to the redirect url (only if {@link #isIncludeOriginalRequest()}==true).
|
||||||
|
*
|
||||||
|
* @param originalRequestParameterName
|
||||||
|
*/
|
||||||
|
public void setOriginalRequestParameterName(
|
||||||
|
String originalRequestParameterName) {
|
||||||
|
this.originalRequestParameterName = originalRequestParameterName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isIncludeOriginalRequest() {
|
||||||
|
return includeOriginalRequest;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If set to true, the original request url will be appended to the redirect
|
||||||
|
* url using the {@link #getOriginalRequestParameterName()}.
|
||||||
|
*
|
||||||
|
* @param includeOriginalRequest
|
||||||
|
*/
|
||||||
|
public void setIncludeOriginalRequest(boolean includeOriginalRequest) {
|
||||||
|
this.includeOriginalRequest = includeOriginalRequest;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void afterPropertiesSet() throws Exception {
|
||||||
|
Assert.hasLength(captchaFormUrl, "captchaFormUrl must be specified");
|
||||||
|
Assert.notNull(portMapper, "portMapper must be specified");
|
||||||
|
Assert.notNull(portResolver, "portResolver must be specified");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void commence(ServletRequest request, ServletResponse response)
|
||||||
|
throws IOException, ServletException {
|
||||||
|
StringBuffer redirectUrl = new StringBuffer();
|
||||||
|
HttpServletRequest req = (HttpServletRequest) request;
|
||||||
|
|
||||||
|
if (isOutsideWebApp) {
|
||||||
|
redirectUrl = redirectUrl.append(captchaFormUrl);
|
||||||
|
} else {
|
||||||
|
buildInternalRedirect(redirectUrl, req);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (includeOriginalRequest) {
|
||||||
|
includeOriginalRequest(redirectUrl, req);
|
||||||
|
}
|
||||||
|
// add post parameter? TODO?
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("Redirecting to: " + redirectUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
((HttpServletResponse) response)
|
||||||
|
.sendRedirect(((HttpServletResponse) response)
|
||||||
|
.encodeRedirectURL(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(originalRequestParameterName);
|
||||||
|
redirectUrl.append("=");
|
||||||
|
redirectUrl.append(req.getRequestURL().toString());
|
||||||
|
// append query params
|
||||||
|
Enumeration parameters = req.getParameterNames();
|
||||||
|
if (parameters != null && parameters.hasMoreElements()) {
|
||||||
|
redirectUrl.append("?");
|
||||||
|
while (parameters.hasMoreElements()) {
|
||||||
|
String name = parameters.nextElement().toString();
|
||||||
|
String value = req.getParameter(name);
|
||||||
|
redirectUrl.append(name);
|
||||||
|
redirectUrl.append("=");
|
||||||
|
redirectUrl.append(value);
|
||||||
|
if (parameters.hasMoreElements()) {
|
||||||
|
redirectUrl.append("&");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void buildInternalRedirect(StringBuffer redirectUrl,
|
||||||
|
HttpServletRequest req) {
|
||||||
|
// construct it
|
||||||
|
StringBuffer simpleRedirect = new StringBuffer();
|
||||||
|
|
||||||
|
String scheme = req.getScheme();
|
||||||
|
String serverName = req.getServerName();
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
simpleRedirect.append(scheme);
|
||||||
|
simpleRedirect.append("://");
|
||||||
|
simpleRedirect.append(serverName);
|
||||||
|
if (includePort) {
|
||||||
|
simpleRedirect.append(":");
|
||||||
|
simpleRedirect.append(serverPort);
|
||||||
|
}
|
||||||
|
simpleRedirect.append(contextPath);
|
||||||
|
simpleRedirect.append(captchaFormUrl);
|
||||||
|
|
||||||
|
if (forceHttps && req.getScheme().equals("http")) {
|
||||||
|
Integer httpPort = new Integer(portResolver.getServerPort(req));
|
||||||
|
Integer httpsPort = (Integer) portMapper.lookupHttpsPort(httpPort);
|
||||||
|
|
||||||
|
if (httpsPort != null) {
|
||||||
|
if (httpsPort.intValue() == 443) {
|
||||||
|
includePort = false;
|
||||||
|
} else {
|
||||||
|
includePort = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
redirectUrl.append("https://");
|
||||||
|
redirectUrl.append(serverName);
|
||||||
|
if (includePort) {
|
||||||
|
redirectUrl.append(":");
|
||||||
|
redirectUrl.append(httpsPort);
|
||||||
|
}
|
||||||
|
redirectUrl.append(contextPath);
|
||||||
|
redirectUrl.append(captchaFormUrl);
|
||||||
|
} else {
|
||||||
|
redirectUrl.append(simpleRedirect);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
redirectUrl.append(simpleRedirect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,55 @@
|
|||||||
|
/* 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.context.SecurityContext;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface that add humanity concerns to the SecurityContext
|
||||||
|
*
|
||||||
|
* @author marc antoine garrigue
|
||||||
|
*/
|
||||||
|
public interface CaptchaSecurityContext extends SecurityContext {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if the current user has already passed a captcha.
|
||||||
|
*/
|
||||||
|
boolean isHuman();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set human attribute, should called after captcha validation.
|
||||||
|
*
|
||||||
|
* @param human
|
||||||
|
*/
|
||||||
|
void setHuman();
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @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();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to increment the human Restricted Resrouces Requests Count;
|
||||||
|
*/
|
||||||
|
void incrementHumanRestrictedRessoucesRequestsCount();
|
||||||
|
}
|
@ -0,0 +1,85 @@
|
|||||||
|
/* 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 net.sf.acegisecurity.context.SecurityContextImpl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author mag
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class CaptchaSecurityContextImpl extends SecurityContextImpl implements
|
||||||
|
CaptchaSecurityContext {
|
||||||
|
|
||||||
|
private boolean human;
|
||||||
|
|
||||||
|
private long lastPassedCaptchaDate;
|
||||||
|
|
||||||
|
private int humanRestrictedResourcesRequestsCount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public CaptchaSecurityContextImpl() {
|
||||||
|
super();
|
||||||
|
human = false;
|
||||||
|
lastPassedCaptchaDate = 0;
|
||||||
|
humanRestrictedResourcesRequestsCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (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() {
|
||||||
|
|
||||||
|
return lastPassedCaptchaDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to increment the human Restricted Resrouces Requests Count;
|
||||||
|
*/
|
||||||
|
public void incrementHumanRestrictedRessoucesRequestsCount() {
|
||||||
|
humanRestrictedResourcesRequestsCount++;
|
||||||
|
};
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
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 {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if the request is validated by the back end captcha service.
|
||||||
|
*/
|
||||||
|
boolean validateRequest(ServletRequest request);
|
||||||
|
}
|
@ -0,0 +1,126 @@
|
|||||||
|
/* 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 javax.servlet.Filter;
|
||||||
|
import javax.servlet.FilterChain;
|
||||||
|
import javax.servlet.FilterConfig;
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.ServletRequest;
|
||||||
|
import javax.servlet.ServletResponse;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter for web integration of the {@link CaptchaServiceProxy}. <br/> 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. <br/>
|
||||||
|
* <br/> 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. <br/> <br/> This filter should only be used in
|
||||||
|
* conjunction with the {@link CaptchaSecurityContext} <br/> <br/>
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @author marc antoine Garrigue
|
||||||
|
* @version $Id$
|
||||||
|
*/
|
||||||
|
public class CaptchaValidationProcessingFilter implements InitializingBean,
|
||||||
|
Filter {
|
||||||
|
// ~ Static fields/initializers
|
||||||
|
// =============================================
|
||||||
|
public static String CAPTCHA_VALIDATION_SECURITY_PARAMETER_KEY = "_captcha_parameter";
|
||||||
|
|
||||||
|
protected static final Log logger = LogFactory
|
||||||
|
.getLog(HttpSessionContextIntegrationFilter.class);
|
||||||
|
|
||||||
|
// ~ Instance fields
|
||||||
|
// ========================================================
|
||||||
|
|
||||||
|
private CaptchaServiceProxy captchaService;
|
||||||
|
|
||||||
|
// ~ Methods
|
||||||
|
// ================================================================
|
||||||
|
|
||||||
|
public CaptchaServiceProxy getCaptchaService() {
|
||||||
|
return captchaService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCaptchaService(CaptchaServiceProxy captchaService) {
|
||||||
|
this.captchaService = captchaService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void afterPropertiesSet() throws Exception {
|
||||||
|
if (this.captchaService == null) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"CaptchaServiceProxy must be defined ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does nothing. We use IoC container lifecycle services instead.
|
||||||
|
*/
|
||||||
|
public void destroy() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void doFilter(ServletRequest request, ServletResponse response,
|
||||||
|
FilterChain chain) throws IOException, ServletException {
|
||||||
|
|
||||||
|
if ((request != null)
|
||||||
|
&& (request
|
||||||
|
.getParameter(CAPTCHA_VALIDATION_SECURITY_PARAMETER_KEY) != null)) {
|
||||||
|
logger.debug("captcha validation parameter not found, do nothing");
|
||||||
|
// validate the request against CaptchaServiceProxy
|
||||||
|
boolean valid = false;
|
||||||
|
|
||||||
|
logger.debug("try to validate");
|
||||||
|
valid = this.captchaService.validateRequest(request);
|
||||||
|
logger.debug("captchaServiceProxy says : request is valid ="
|
||||||
|
+ valid);
|
||||||
|
if (valid) {
|
||||||
|
logger.debug("update the context");
|
||||||
|
((CaptchaSecurityContext) SecurityContextHolder.getContext())
|
||||||
|
.setHuman();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
logger.debug("captcha validation parameter not found, do nothing");
|
||||||
|
}
|
||||||
|
logger.debug("chain...");
|
||||||
|
chain.doFilter(request, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does nothing. We use IoC container lifecycle services instead.
|
||||||
|
*
|
||||||
|
* @param filterConfig
|
||||||
|
* ignored
|
||||||
|
*
|
||||||
|
* @throws ServletException
|
||||||
|
* ignored
|
||||||
|
*/
|
||||||
|
public void init(FilterConfig filterConfig) throws ServletException {
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,536 @@
|
|||||||
|
/* 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 javax.servlet.ServletException;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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");
|
||||||
|
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");
|
||||||
|
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");
|
||||||
|
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");
|
||||||
|
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());
|
||||||
|
|
||||||
|
Thread.sleep(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());
|
||||||
|
|
||||||
|
Thread.sleep(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());
|
||||||
|
|
||||||
|
Thread.sleep(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");
|
||||||
|
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());
|
||||||
|
|
||||||
|
Thread.sleep(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());
|
||||||
|
|
||||||
|
Thread.sleep(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")));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,385 @@
|
|||||||
|
/* 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.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
import net.sf.acegisecurity.MockPortResolver;
|
||||||
|
import net.sf.acegisecurity.securechannel.RetryWithHttpEntryPoint;
|
||||||
|
import net.sf.acegisecurity.util.PortMapperImpl;
|
||||||
|
|
||||||
|
import org.springframework.mock.web.MockHttpServletRequest;
|
||||||
|
import org.springframework.mock.web.MockHttpServletResponse;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests {@link RetryWithHttpEntryPoint}.
|
||||||
|
*
|
||||||
|
* @author Ben Alex
|
||||||
|
* @version $Id: RetryWithHttpEntryPointTests.java,v 1.4 2005/04/11 01:07:02
|
||||||
|
* luke_t Exp $
|
||||||
|
*/
|
||||||
|
public class CaptchaEntryPointTests extends TestCase {
|
||||||
|
// ~ Methods
|
||||||
|
// ================================================================
|
||||||
|
|
||||||
|
public final void setUp() throws Exception {
|
||||||
|
super.setUp();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
junit.textui.TestRunner.run(CaptchaEntryPointTests.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testDetectsMissingCaptchaFormUrl() throws Exception {
|
||||||
|
CaptchaEntryPoint ep = new CaptchaEntryPoint();
|
||||||
|
ep.setPortMapper(new PortMapperImpl());
|
||||||
|
ep.setPortResolver(new MockPortResolver(80, 443));
|
||||||
|
|
||||||
|
try {
|
||||||
|
ep.afterPropertiesSet();
|
||||||
|
fail("Should have thrown IllegalArgumentException");
|
||||||
|
} catch (IllegalArgumentException expected) {
|
||||||
|
assertEquals("captchaFormUrl must be specified", expected
|
||||||
|
.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testDetectsMissingPortMapper() throws Exception {
|
||||||
|
CaptchaEntryPoint ep = new CaptchaEntryPoint();
|
||||||
|
ep.setCaptchaFormUrl("xxx");
|
||||||
|
ep.setPortMapper(null);
|
||||||
|
|
||||||
|
try {
|
||||||
|
ep.afterPropertiesSet();
|
||||||
|
fail("Should have thrown IllegalArgumentException");
|
||||||
|
} catch (IllegalArgumentException expected) {
|
||||||
|
assertEquals("portMapper must be specified", expected.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testDetectsMissingPortResolver() throws Exception {
|
||||||
|
CaptchaEntryPoint ep = new CaptchaEntryPoint();
|
||||||
|
ep.setCaptchaFormUrl("xxx");
|
||||||
|
ep.setPortResolver(null);
|
||||||
|
|
||||||
|
try {
|
||||||
|
ep.afterPropertiesSet();
|
||||||
|
fail("Should have thrown IllegalArgumentException");
|
||||||
|
} catch (IllegalArgumentException expected) {
|
||||||
|
assertEquals("portResolver must be specified", expected
|
||||||
|
.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testGettersSetters() {
|
||||||
|
CaptchaEntryPoint ep = new CaptchaEntryPoint();
|
||||||
|
ep.setCaptchaFormUrl("/hello");
|
||||||
|
ep.setPortMapper(new PortMapperImpl());
|
||||||
|
ep.setPortResolver(new MockPortResolver(8080, 8443));
|
||||||
|
assertEquals("/hello", ep.getCaptchaFormUrl());
|
||||||
|
assertTrue(ep.getPortMapper() != null);
|
||||||
|
assertTrue(ep.getPortResolver() != null);
|
||||||
|
|
||||||
|
assertEquals("originalRequest", ep.getOriginalRequestParameterName());
|
||||||
|
ep.setOriginalRequestParameterName("Z");
|
||||||
|
assertEquals("Z", ep.getOriginalRequestParameterName());
|
||||||
|
|
||||||
|
assertEquals(false, ep.isIncludeOriginalRequest());
|
||||||
|
ep.setIncludeOriginalRequest(true);
|
||||||
|
assertEquals(true, ep.isIncludeOriginalRequest());
|
||||||
|
|
||||||
|
assertEquals(false, ep.isOutsideWebApp());
|
||||||
|
ep.setOutsideWebApp(true);
|
||||||
|
assertEquals(true, ep.isOutsideWebApp());
|
||||||
|
|
||||||
|
ep.setForceHttps(false);
|
||||||
|
assertFalse(ep.getForceHttps());
|
||||||
|
ep.setForceHttps(true);
|
||||||
|
assertTrue(ep.getForceHttps());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testHttpsOperationFromOriginalHttpUrl() throws Exception {
|
||||||
|
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||||
|
request.setRequestURI("/some_path");
|
||||||
|
request.setScheme("http");
|
||||||
|
request.setServerName("www.example.com");
|
||||||
|
request.setContextPath("/bigWebApp");
|
||||||
|
request.setServerPort(80);
|
||||||
|
|
||||||
|
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||||
|
|
||||||
|
CaptchaEntryPoint ep = new CaptchaEntryPoint();
|
||||||
|
ep.setCaptchaFormUrl("/hello");
|
||||||
|
ep.setPortMapper(new PortMapperImpl());
|
||||||
|
ep.setForceHttps(true);
|
||||||
|
ep.setPortMapper(new PortMapperImpl());
|
||||||
|
ep.setPortResolver(new MockPortResolver(80, 443));
|
||||||
|
ep.afterPropertiesSet();
|
||||||
|
|
||||||
|
ep.commence(request, response);
|
||||||
|
assertEquals("https://www.example.com/bigWebApp/hello", response
|
||||||
|
.getRedirectedUrl());
|
||||||
|
|
||||||
|
request.setServerPort(8080);
|
||||||
|
response = new MockHttpServletResponse();
|
||||||
|
ep.setPortResolver(new MockPortResolver(8080, 8443));
|
||||||
|
ep.commence(request, response);
|
||||||
|
assertEquals("https://www.example.com:8443/bigWebApp/hello", response
|
||||||
|
.getRedirectedUrl());
|
||||||
|
|
||||||
|
// Now test an unusual custom HTTP:HTTPS is handled properly
|
||||||
|
request.setServerPort(8888);
|
||||||
|
response = new MockHttpServletResponse();
|
||||||
|
ep.commence(request, response);
|
||||||
|
assertEquals("https://www.example.com:8443/bigWebApp/hello", response
|
||||||
|
.getRedirectedUrl());
|
||||||
|
|
||||||
|
PortMapperImpl portMapper = new PortMapperImpl();
|
||||||
|
Map map = new HashMap();
|
||||||
|
map.put("8888", "9999");
|
||||||
|
portMapper.setPortMappings(map);
|
||||||
|
response = new MockHttpServletResponse();
|
||||||
|
|
||||||
|
ep = new CaptchaEntryPoint();
|
||||||
|
ep.setCaptchaFormUrl("/hello");
|
||||||
|
ep.setPortMapper(new PortMapperImpl());
|
||||||
|
ep.setForceHttps(true);
|
||||||
|
ep.setPortMapper(portMapper);
|
||||||
|
ep.setPortResolver(new MockPortResolver(8888, 9999));
|
||||||
|
ep.afterPropertiesSet();
|
||||||
|
|
||||||
|
ep.commence(request, response);
|
||||||
|
assertEquals("https://www.example.com:9999/bigWebApp/hello", response
|
||||||
|
.getRedirectedUrl());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testHttpsOperationFromOriginalHttpsUrl() throws Exception {
|
||||||
|
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||||
|
request.setRequestURI("/some_path");
|
||||||
|
request.setScheme("https");
|
||||||
|
request.setServerName("www.example.com");
|
||||||
|
request.setContextPath("/bigWebApp");
|
||||||
|
request.setServerPort(443);
|
||||||
|
|
||||||
|
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||||
|
|
||||||
|
CaptchaEntryPoint ep = new CaptchaEntryPoint();
|
||||||
|
ep.setCaptchaFormUrl("/hello");
|
||||||
|
ep.setPortMapper(new PortMapperImpl());
|
||||||
|
ep.setForceHttps(true);
|
||||||
|
ep.setPortMapper(new PortMapperImpl());
|
||||||
|
ep.setPortResolver(new MockPortResolver(80, 443));
|
||||||
|
ep.afterPropertiesSet();
|
||||||
|
|
||||||
|
ep.commence(request, response);
|
||||||
|
assertEquals("https://www.example.com/bigWebApp/hello", response
|
||||||
|
.getRedirectedUrl());
|
||||||
|
|
||||||
|
request.setServerPort(8443);
|
||||||
|
response = new MockHttpServletResponse();
|
||||||
|
ep.setPortResolver(new MockPortResolver(8080, 8443));
|
||||||
|
ep.commence(request, response);
|
||||||
|
assertEquals("https://www.example.com:8443/bigWebApp/hello", response
|
||||||
|
.getRedirectedUrl());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testNormalOperation() throws Exception {
|
||||||
|
CaptchaEntryPoint ep = new CaptchaEntryPoint();
|
||||||
|
ep.setCaptchaFormUrl("/hello");
|
||||||
|
ep.setPortMapper(new PortMapperImpl());
|
||||||
|
ep.setPortResolver(new MockPortResolver(80, 443));
|
||||||
|
ep.afterPropertiesSet();
|
||||||
|
|
||||||
|
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||||
|
request.setRequestURI("/some_path");
|
||||||
|
request.setContextPath("/bigWebApp");
|
||||||
|
request.setScheme("http");
|
||||||
|
request.setServerName("www.example.com");
|
||||||
|
request.setContextPath("/bigWebApp");
|
||||||
|
request.setServerPort(80);
|
||||||
|
|
||||||
|
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||||
|
|
||||||
|
ep.afterPropertiesSet();
|
||||||
|
ep.commence(request, response);
|
||||||
|
assertEquals("http://www.example.com/bigWebApp/hello", response
|
||||||
|
.getRedirectedUrl());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testOperationWhenHttpsRequestsButHttpsPortUnknown()
|
||||||
|
throws Exception {
|
||||||
|
CaptchaEntryPoint ep = new CaptchaEntryPoint();
|
||||||
|
ep.setCaptchaFormUrl("/hello");
|
||||||
|
ep.setPortMapper(new PortMapperImpl());
|
||||||
|
ep.setPortResolver(new MockPortResolver(8888, 1234));
|
||||||
|
ep.setForceHttps(true);
|
||||||
|
ep.afterPropertiesSet();
|
||||||
|
|
||||||
|
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||||
|
request.setRequestURI("/some_path");
|
||||||
|
request.setContextPath("/bigWebApp");
|
||||||
|
request.setScheme("http");
|
||||||
|
request.setServerName("www.example.com");
|
||||||
|
request.setContextPath("/bigWebApp");
|
||||||
|
request.setServerPort(8888); // NB: Port we can't resolve
|
||||||
|
|
||||||
|
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||||
|
|
||||||
|
ep.afterPropertiesSet();
|
||||||
|
ep.commence(request, response);
|
||||||
|
|
||||||
|
// Response doesn't switch to HTTPS, as we didn't know HTTP port 8888 to
|
||||||
|
// HTTP port mapping
|
||||||
|
assertEquals("http://www.example.com:8888/bigWebApp/hello", response
|
||||||
|
.getRedirectedUrl());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testOperationWithOriginalRequestIncludes() throws Exception {
|
||||||
|
CaptchaEntryPoint ep = new CaptchaEntryPoint();
|
||||||
|
ep.setCaptchaFormUrl("/hello");
|
||||||
|
PortMapperImpl mapper = new PortMapperImpl();
|
||||||
|
mapper.getTranslatedPortMappings().put(new Integer(8888),
|
||||||
|
new Integer(1234));
|
||||||
|
ep.setPortMapper(mapper);
|
||||||
|
|
||||||
|
ep.setPortResolver(new MockPortResolver(8888, 1234));
|
||||||
|
ep.setIncludeOriginalRequest(true);
|
||||||
|
ep.afterPropertiesSet();
|
||||||
|
|
||||||
|
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||||
|
request.setRequestURI("/some_path");
|
||||||
|
request.setScheme("http");
|
||||||
|
request.setServerName("www.example.com");
|
||||||
|
// request.setContextPath("/bigWebApp");
|
||||||
|
// TODO correct this when the getRequestUrl from mock works...
|
||||||
|
|
||||||
|
request.setServerPort(8888); // NB: Port we can't resolve
|
||||||
|
|
||||||
|
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||||
|
|
||||||
|
ep.afterPropertiesSet();
|
||||||
|
ep.commence(request, response);
|
||||||
|
assertEquals(
|
||||||
|
"http://www.example.com:8888/hello?originalRequest=http://www.example.com:8888/some_path",
|
||||||
|
response.getRedirectedUrl());
|
||||||
|
|
||||||
|
// test the query params
|
||||||
|
request.addParameter("name", "value");
|
||||||
|
response = new MockHttpServletResponse();
|
||||||
|
ep.commence(request, response);
|
||||||
|
assertEquals(
|
||||||
|
"http://www.example.com:8888/hello?originalRequest=http://www.example.com:8888/some_path?name=value",
|
||||||
|
response.getRedirectedUrl());
|
||||||
|
|
||||||
|
// test the multiple query params
|
||||||
|
request.addParameter("name", "value");
|
||||||
|
request.addParameter("name1", "value2");
|
||||||
|
response = new MockHttpServletResponse();
|
||||||
|
ep.commence(request, response);
|
||||||
|
assertEquals(
|
||||||
|
"http://www.example.com:8888/hello?originalRequest=http://www.example.com:8888/some_path?name=value&name1=value2",
|
||||||
|
response.getRedirectedUrl());
|
||||||
|
|
||||||
|
// test add parameter to captcha form url??
|
||||||
|
|
||||||
|
ep.setCaptchaFormUrl("/hello?toto=titi");
|
||||||
|
response = new MockHttpServletResponse();
|
||||||
|
ep.commence(request, response);
|
||||||
|
assertEquals(
|
||||||
|
"http://www.example.com:8888/hello?toto=titi&originalRequest=http://www.example.com:8888/some_path?name=value&name1=value2",
|
||||||
|
response.getRedirectedUrl());
|
||||||
|
|
||||||
|
// with forcing!!!
|
||||||
|
ep.setForceHttps(true);
|
||||||
|
response = new MockHttpServletResponse();
|
||||||
|
ep.commence(request, response);
|
||||||
|
assertEquals(
|
||||||
|
"https://www.example.com:1234/hello?toto=titi&originalRequest=http://www.example.com:8888/some_path?name=value&name1=value2",
|
||||||
|
response.getRedirectedUrl());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testOperationWithOutsideWebApp() throws Exception {
|
||||||
|
CaptchaEntryPoint ep = new CaptchaEntryPoint();
|
||||||
|
ep.setCaptchaFormUrl("https://www.jcaptcha.net/dotest/");
|
||||||
|
PortMapperImpl mapper = new PortMapperImpl();
|
||||||
|
mapper.getTranslatedPortMappings().put(new Integer(8888),
|
||||||
|
new Integer(1234));
|
||||||
|
ep.setPortMapper(mapper);
|
||||||
|
|
||||||
|
ep.setPortResolver(new MockPortResolver(8888, 1234));
|
||||||
|
ep.setIncludeOriginalRequest(true);
|
||||||
|
ep.setOutsideWebApp(true);
|
||||||
|
|
||||||
|
ep.afterPropertiesSet();
|
||||||
|
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||||
|
request.setRequestURI("/some_path");
|
||||||
|
request.setScheme("http");
|
||||||
|
request.setServerName("www.example.com");
|
||||||
|
// request.setContextPath("/bigWebApp");
|
||||||
|
// TODO correct this when the getRequestUrl from mock works...
|
||||||
|
|
||||||
|
request.setServerPort(8888); // NB: Port we can't resolve
|
||||||
|
|
||||||
|
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||||
|
|
||||||
|
ep.afterPropertiesSet();
|
||||||
|
ep.commence(request, response);
|
||||||
|
assertEquals(
|
||||||
|
"https://www.jcaptcha.net/dotest/?originalRequest=http://www.example.com:8888/some_path",
|
||||||
|
response.getRedirectedUrl());
|
||||||
|
|
||||||
|
// test the query params
|
||||||
|
request.addParameter("name", "value");
|
||||||
|
response = new MockHttpServletResponse();
|
||||||
|
ep.commence(request, response);
|
||||||
|
assertEquals(
|
||||||
|
"https://www.jcaptcha.net/dotest/?originalRequest=http://www.example.com:8888/some_path?name=value",
|
||||||
|
response.getRedirectedUrl());
|
||||||
|
|
||||||
|
// test the multiple query params
|
||||||
|
request.addParameter("name", "value");
|
||||||
|
request.addParameter("name1", "value2");
|
||||||
|
response = new MockHttpServletResponse();
|
||||||
|
ep.commence(request, response);
|
||||||
|
assertEquals(
|
||||||
|
"https://www.jcaptcha.net/dotest/?originalRequest=http://www.example.com:8888/some_path?name=value&name1=value2",
|
||||||
|
response.getRedirectedUrl());
|
||||||
|
|
||||||
|
// test add parameter to captcha form url??
|
||||||
|
|
||||||
|
ep.setCaptchaFormUrl("https://www.jcaptcha.net/dotest/?toto=titi");
|
||||||
|
response = new MockHttpServletResponse();
|
||||||
|
ep.commence(request, response);
|
||||||
|
assertEquals(
|
||||||
|
"https://www.jcaptcha.net/dotest/?toto=titi&originalRequest=http://www.example.com:8888/some_path?name=value&name1=value2",
|
||||||
|
response.getRedirectedUrl());
|
||||||
|
|
||||||
|
// with forcing!!!
|
||||||
|
ep.setForceHttps(true);
|
||||||
|
response = new MockHttpServletResponse();
|
||||||
|
ep.commence(request, response);
|
||||||
|
assertEquals(
|
||||||
|
"https://www.jcaptcha.net/dotest/?toto=titi&originalRequest=http://www.example.com:8888/some_path?name=value&name1=value2",
|
||||||
|
response.getRedirectedUrl());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,64 @@
|
|||||||
|
package net.sf.acegisecurity.captcha;
|
||||||
|
|
||||||
|
import net.sf.acegisecurity.context.SecurityContextImplTests;
|
||||||
|
|
||||||
|
public class CaptchaSecurityContextImplTests extends SecurityContextImplTests {
|
||||||
|
|
||||||
|
public void testDefaultValues() {
|
||||||
|
CaptchaSecurityContext context = new CaptchaSecurityContextImpl();
|
||||||
|
assertEquals("should not be human", false, context.isHuman());
|
||||||
|
assertEquals("should be 0", 0, context
|
||||||
|
.getLastPassedCaptchaDateInMillis());
|
||||||
|
assertEquals("should be 0", 0, context
|
||||||
|
.getHumanRestrictedResourcesRequestsCount());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testSetHuman() {
|
||||||
|
CaptchaSecurityContext context = new CaptchaSecurityContextImpl();
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,83 @@
|
|||||||
|
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;
|
||||||
|
|
||||||
|
public class CaptchaValidationProcessingFilterTests extends TestCase {
|
||||||
|
|
||||||
|
/*
|
||||||
|
*/
|
||||||
|
public void testAfterPropertiesSet() throws Exception {
|
||||||
|
CaptchaValidationProcessingFilter filter = new CaptchaValidationProcessingFilter();
|
||||||
|
|
||||||
|
try {
|
||||||
|
filter.afterPropertiesSet();
|
||||||
|
fail("should have thrown an invalid argument exception");
|
||||||
|
} catch (Exception e) {
|
||||||
|
assertTrue("should be an InvalidArgumentException",
|
||||||
|
IllegalArgumentException.class.isAssignableFrom(e
|
||||||
|
.getClass()));
|
||||||
|
}
|
||||||
|
filter.setCaptchaService(new MockCaptchaServiceProxy());
|
||||||
|
filter.afterPropertiesSet();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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)'
|
||||||
|
*/
|
||||||
|
public void testDoFilterWithRequestParameter() throws Exception {
|
||||||
|
CaptchaSecurityContext context = new CaptchaSecurityContextImpl();
|
||||||
|
SecurityContextHolder.setContext(context);
|
||||||
|
|
||||||
|
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||||
|
request
|
||||||
|
.addParameter(
|
||||||
|
CaptchaValidationProcessingFilter.CAPTCHA_VALIDATION_SECURITY_PARAMETER_KEY,
|
||||||
|
"");
|
||||||
|
|
||||||
|
CaptchaValidationProcessingFilter filter = new CaptchaValidationProcessingFilter();
|
||||||
|
MockCaptchaServiceProxy service = new MockCaptchaServiceProxy();
|
||||||
|
MockFilterChain chain = new MockFilterChain(true);
|
||||||
|
filter.setCaptchaService(service);
|
||||||
|
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());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
/* 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 javax.servlet.ServletRequest;
|
||||||
|
|
||||||
|
public class MockCaptchaServiceProxy implements CaptchaServiceProxy {
|
||||||
|
|
||||||
|
public boolean valid = false;
|
||||||
|
|
||||||
|
public boolean hasBeenCalled = false;
|
||||||
|
|
||||||
|
public boolean validateRequest(ServletRequest request) {
|
||||||
|
hasBeenCalled = true;
|
||||||
|
return valid;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user