From c857e4610b613fcb1154681456a22bbee6abdd02 Mon Sep 17 00:00:00 2001 From: Misagh Moayyed Date: Thu, 27 Feb 2014 22:02:19 -0700 Subject: [PATCH] CAS-219: Provide support for certain urls to be excluded from CAS filters. --- .../authentication/AuthenticationFilter.java | 8 ++++ .../cas/client/util/AbstractCasFilter.java | 33 +++++++++++++ .../AbstractTicketValidationFilter.java | 14 ++++-- .../AuthenticationFilterTests.java | 42 +++++++++++++---- .../Cas10TicketValidationFilterTests.java | 46 +++++++++++++++++++ .../Saml11TicketValidationFilterTests.java | 46 +++++++++++++++++++ .../Saml11TicketValidatorTests.java | 15 +++++- 7 files changed, 191 insertions(+), 13 deletions(-) diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/authentication/AuthenticationFilter.java b/cas-client-core/src/main/java/org/jasig/cas/client/authentication/AuthenticationFilter.java index 2e73556..c00be68 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/authentication/AuthenticationFilter.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/authentication/AuthenticationFilter.java @@ -98,8 +98,16 @@ public class AuthenticationFilter extends AbstractCasFilter { public final void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse, final FilterChain filterChain) throws IOException, ServletException { + final HttpServletRequest request = (HttpServletRequest) servletRequest; final HttpServletResponse response = (HttpServletResponse) servletResponse; + + if (isRequestUrlExcluded(request)) { + logger.debug("Request is ignored."); + filterChain.doFilter(request, response); + return; + } + final HttpSession session = request.getSession(false); final Assertion assertion = session != null ? (Assertion) session.getAttribute(CONST_CAS_ASSERTION) : null; diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/util/AbstractCasFilter.java b/cas-client-core/src/main/java/org/jasig/cas/client/util/AbstractCasFilter.java index 78f5f7b..7b4d5cf 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/util/AbstractCasFilter.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/util/AbstractCasFilter.java @@ -18,6 +18,10 @@ */ package org.jasig.cas.client.util; +import java.util.Collections; +import java.util.List; +import java.util.regex.Pattern; + import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; @@ -48,6 +52,9 @@ public abstract class AbstractCasFilter extends AbstractConfigurationFilter { /** Defines the parameter to look for for the service. */ private String serviceParameterName = "service"; + /** Url pattern for this filter to exclude and ignore. **/ + private Pattern ignorePattern = null; + /** Sets where response.encodeUrl should be called on service urls when constructed. */ private boolean encodeServiceUrl = true; @@ -72,6 +79,12 @@ public abstract class AbstractCasFilter extends AbstractConfigurationFilter { setEncodeServiceUrl(parseBoolean(getPropertyFromInitParams(filterConfig, "encodeServiceUrl", "true"))); logger.trace("Loading encodeServiceUrl property: {}", this.encodeServiceUrl); + final String ignorePattern = getPropertyFromInitParams(filterConfig, "ignorePattern", null); + if (ignorePattern != null) { + setIgnorePattern(Pattern.compile(ignorePattern)); + logger.trace("Loading ignorePattern property: {}", this.ignorePattern.pattern()); + } + initInternal(filterConfig); } init(); @@ -148,6 +161,10 @@ public abstract class AbstractCasFilter extends AbstractConfigurationFilter { return this.serviceParameterName; } + public final void setIgnorePattern(final Pattern patternToIgnore) { + this.ignorePattern = patternToIgnore; + } + /** * Template method to allow you to change how you retrieve the ticket. * @@ -157,4 +174,20 @@ public abstract class AbstractCasFilter extends AbstractConfigurationFilter { protected String retrieveTicketFromRequest(final HttpServletRequest request) { return CommonUtils.safeGetParameter(request, getArtifactParameterName()); } + + protected boolean isRequestUrlExcluded(final HttpServletRequest request) { + boolean result = false; + if (this.ignorePattern != null) { + final StringBuffer urlBuffer = request.getRequestURL(); + if (request.getQueryString() != null) { + urlBuffer.append("?").append(request.getQueryString()); + } + final String requestUri = urlBuffer.toString(); + logger.debug("Checking [{}] against pattern [{}]", requestUri, this.ignorePattern.pattern()); + result = this.ignorePattern.matcher(requestUri).find(); + } else { + logger.debug("Ignore pattern is not defined"); + } + return result; + } } diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/validation/AbstractTicketValidationFilter.java b/cas-client-core/src/main/java/org/jasig/cas/client/validation/AbstractTicketValidationFilter.java index 58f57c4..836b63a 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/validation/AbstractTicketValidationFilter.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/validation/AbstractTicketValidationFilter.java @@ -190,13 +190,19 @@ public abstract class AbstractTicketValidationFilter extends AbstractCasFilter { public final void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse, final FilterChain filterChain) throws IOException, ServletException { - + final HttpServletRequest request = (HttpServletRequest) servletRequest; + final HttpServletResponse response = (HttpServletResponse) servletResponse; + + if (isRequestUrlExcluded(request)) { + logger.debug("Request is ignored."); + filterChain.doFilter(request, response); + return; + } + if (!preFilter(servletRequest, servletResponse, filterChain)) { return; } - - final HttpServletRequest request = (HttpServletRequest) servletRequest; - final HttpServletResponse response = (HttpServletResponse) servletResponse; + final String ticket = retrieveTicketFromRequest(request); if (CommonUtils.isNotBlank(ticket)) { diff --git a/cas-client-core/src/test/java/org/jasig/cas/client/authentication/AuthenticationFilterTests.java b/cas-client-core/src/test/java/org/jasig/cas/client/authentication/AuthenticationFilterTests.java index 396c536..34d6686 100644 --- a/cas-client-core/src/test/java/org/jasig/cas/client/authentication/AuthenticationFilterTests.java +++ b/cas-client-core/src/test/java/org/jasig/cas/client/authentication/AuthenticationFilterTests.java @@ -37,7 +37,6 @@ import org.springframework.mock.web.*; * Tests for the AuthenticationFilter. * * @author Scott Battaglia - * @version $Revision: 11753 $ $Date: 2007-01-03 13:37:26 -0500 (Wed, 03 Jan 2007) $ * @since 3.0 */ public final class AuthenticationFilterTests { @@ -50,11 +49,10 @@ public final class AuthenticationFilterTests { @Before public void setUp() throws Exception { - // TODO CAS_SERVICE_URL, false, CAS_LOGIN_URL this.filter = new AuthenticationFilter(); final MockFilterConfig config = new MockFilterConfig(); config.addInitParameter("casServerLoginUrl", CAS_LOGIN_URL); - config.addInitParameter("service", "https://localhost:8443/service"); + config.addInitParameter("service", CAS_SERVICE_URL); this.filter.init(config); } @@ -184,7 +182,7 @@ public final class AuthenticationFilterTests { final AuthenticationFilter f = new AuthenticationFilter(); final MockFilterConfig config = new MockFilterConfig(); config.addInitParameter("casServerLoginUrl", CAS_LOGIN_URL); - config.addInitParameter("service", "https://localhost:8443/service"); + config.addInitParameter("service", CAS_SERVICE_URL); config.addInitParameter("renew", "true"); try { f.init(config); @@ -198,8 +196,8 @@ public final class AuthenticationFilterTests { public void testAllowsRenewContextParam() throws Exception { final AuthenticationFilter f = new AuthenticationFilter(); final MockServletContext context = new MockServletContext(); - context.addInitParameter("casServerLoginUrl", "https://cas.example.com/login"); - context.addInitParameter("service", "https://localhost:8443/service"); + context.addInitParameter("casServerLoginUrl", CAS_LOGIN_URL); + context.addInitParameter("service", CAS_SERVICE_URL); context.addInitParameter("renew", "true"); f.init(new MockFilterConfig(context)); final Field renewField = AuthenticationFilter.class.getDeclaredField("renew"); @@ -211,10 +209,38 @@ public final class AuthenticationFilterTests { public void customRedirectStrategy() throws Exception { final AuthenticationFilter f = new AuthenticationFilter(); final MockServletContext context = new MockServletContext(); - context.addInitParameter("casServerLoginUrl", "https://cas.example.com/login"); - context.addInitParameter("service", "https://localhost:8443/service"); + context.addInitParameter("casServerLoginUrl", CAS_LOGIN_URL); + context.addInitParameter("service", CAS_SERVICE_URL); context.addInitParameter("authenticationRedirectStrategyClass", "org.jasig.cas.client.authentication.FacesCompatibleAuthenticationRedirectStrategy"); f.init(new MockFilterConfig(context)); } + + @Test + public void testIgnorePatterns() throws Exception { + final AuthenticationFilter f = new AuthenticationFilter(); + final MockServletContext context = new MockServletContext(); + context.addInitParameter("casServerLoginUrl", CAS_LOGIN_URL); + + context.addInitParameter("ignorePattern", "=valueTo(\\w+)"); + context.addInitParameter("service", CAS_SERVICE_URL); + f.init(new MockFilterConfig(context)); + + final MockHttpServletRequest request = new MockHttpServletRequest(); + final String URL = CAS_SERVICE_URL + "?param=valueToIgnore"; + request.setRequestURI(URL); + + final MockHttpSession session = new MockHttpSession(); + request.setSession(session); + + final MockHttpServletResponse response = new MockHttpServletResponse(); + + final FilterChain filterChain = new FilterChain() { + public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException { + } + }; + + f.doFilter(request, response, filterChain); + assertNull(response.getRedirectedUrl()); + } } diff --git a/cas-client-core/src/test/java/org/jasig/cas/client/validation/Cas10TicketValidationFilterTests.java b/cas-client-core/src/test/java/org/jasig/cas/client/validation/Cas10TicketValidationFilterTests.java index e8daab4..174b9f7 100644 --- a/cas-client-core/src/test/java/org/jasig/cas/client/validation/Cas10TicketValidationFilterTests.java +++ b/cas-client-core/src/test/java/org/jasig/cas/client/validation/Cas10TicketValidationFilterTests.java @@ -20,8 +20,19 @@ package org.jasig.cas.client.validation; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; + +import java.io.IOException; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; + import org.junit.Test; import org.springframework.mock.web.MockFilterConfig; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.mock.web.MockHttpSession; import org.springframework.mock.web.MockServletContext; /** @@ -54,4 +65,39 @@ public class Cas10TicketValidationFilterTests { assertTrue(validator instanceof Cas10TicketValidator); assertTrue(((Cas10TicketValidator) validator).isRenew()); } + + @Test + public void testIgnorePatterns() throws Exception { + final Cas10TicketValidationFilter f = new Cas10TicketValidationFilter(); + + final MockServletContext context = new MockServletContext(); + context.addInitParameter("casServerUrlPrefix", "https://cas.example.com"); + context.addInitParameter("serverName", "https://localhost:8443"); + + context.addInitParameter("ignorePattern", "=valueTo(\\w+)"); + f.init(new MockFilterConfig(context)); + + final MockHttpServletRequest request = new MockHttpServletRequest(); + final String URL = "https://localhost:8443/?param=valueToIgnore"; + request.setRequestURI(URL); + request.setQueryString("ticket=ST-1234"); + request.setParameter("ticket", "ST-1234"); + + final MockHttpSession session = new MockHttpSession(); + request.setSession(session); + + final MockHttpServletResponse response = new MockHttpServletResponse(); + + final FilterChain filterChain = new FilterChain() { + public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException { + } + }; + + try { + f.doFilter(request, response, filterChain); + } catch (final Exception e) { + fail("The validation request should have been ignored"); + } + + } } diff --git a/cas-client-core/src/test/java/org/jasig/cas/client/validation/Saml11TicketValidationFilterTests.java b/cas-client-core/src/test/java/org/jasig/cas/client/validation/Saml11TicketValidationFilterTests.java index 804b46f..c0e267e 100644 --- a/cas-client-core/src/test/java/org/jasig/cas/client/validation/Saml11TicketValidationFilterTests.java +++ b/cas-client-core/src/test/java/org/jasig/cas/client/validation/Saml11TicketValidationFilterTests.java @@ -20,8 +20,19 @@ package org.jasig.cas.client.validation; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; + +import java.io.IOException; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; + import org.junit.Test; import org.springframework.mock.web.MockFilterConfig; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.mock.web.MockHttpSession; import org.springframework.mock.web.MockServletContext; /** @@ -54,4 +65,39 @@ public class Saml11TicketValidationFilterTests { assertTrue(validator instanceof Saml11TicketValidator); assertTrue(((Saml11TicketValidator) validator).isRenew()); } + + @Test + public void testIgnorePatterns() throws Exception { + final Saml11TicketValidationFilter f = new Saml11TicketValidationFilter(); + + final MockServletContext context = new MockServletContext(); + context.addInitParameter("casServerUrlPrefix", "https://cas.example.com"); + context.addInitParameter("serverName", "https://localhost:8443"); + + context.addInitParameter("ignorePattern", "=valueTo(\\w+)"); + f.init(new MockFilterConfig(context)); + + final MockHttpServletRequest request = new MockHttpServletRequest(); + final String URL = "https://localhost:8443/?param=valueToIgnore"; + request.setRequestURI(URL); + request.setQueryString("SAMLart=ST-1234"); + request.setParameter("SAMLart", "ST-1234"); + + final MockHttpSession session = new MockHttpSession(); + request.setSession(session); + + final MockHttpServletResponse response = new MockHttpServletResponse(); + + final FilterChain filterChain = new FilterChain() { + public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException { + } + }; + + try { + f.doFilter(request, response, filterChain); + } catch (final Exception e) { + fail("The validation request should have been ignored"); + } + + } } diff --git a/cas-client-core/src/test/java/org/jasig/cas/client/validation/Saml11TicketValidatorTests.java b/cas-client-core/src/test/java/org/jasig/cas/client/validation/Saml11TicketValidatorTests.java index 951e610..9e90749 100644 --- a/cas-client-core/src/test/java/org/jasig/cas/client/validation/Saml11TicketValidatorTests.java +++ b/cas-client-core/src/test/java/org/jasig/cas/client/validation/Saml11TicketValidatorTests.java @@ -20,8 +20,16 @@ package org.jasig.cas.client.validation; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; + +import java.io.IOException; import java.io.UnsupportedEncodingException; import java.util.Date; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; + import org.jasig.cas.client.PublicTestHttpServer; import org.jasig.cas.client.util.CommonUtils; import org.joda.time.DateTime; @@ -30,6 +38,11 @@ import org.joda.time.Interval; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; +import org.springframework.mock.web.MockFilterConfig; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.mock.web.MockHttpSession; +import org.springframework.mock.web.MockServletContext; /** * @author Scott Battaglia @@ -137,7 +150,7 @@ public final class Saml11TicketValidatorTests extends AbstractTicketValidatorTes fail(e.toString()); } } - + private Interval currentTimeRangeInterval() { return new Interval(new DateTime(DateTimeZone.UTC).minus(5000), new DateTime(DateTimeZone.UTC).plus(200000000)); }