diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/authentication/ExactUrlPatternMatcherStrategy.java b/cas-client-core/src/main/java/org/jasig/cas/client/authentication/ExactUrlPatternMatcherStrategy.java index 64f20eb..9fd0ddf 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/authentication/ExactUrlPatternMatcherStrategy.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/authentication/ExactUrlPatternMatcherStrategy.java @@ -28,7 +28,13 @@ package org.jasig.cas.client.authentication; public final class ExactUrlPatternMatcherStrategy implements UrlPatternMatcherStrategy { private String pattern; - + + public ExactUrlPatternMatcherStrategy() {} + + public ExactUrlPatternMatcherStrategy(final String pattern) { + this.setPattern(pattern); + } + public boolean matches(final String url) { return url.equals(this.pattern); } diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/authentication/RegexUrlPatternMatcherStrategy.java b/cas-client-core/src/main/java/org/jasig/cas/client/authentication/RegexUrlPatternMatcherStrategy.java index a941459..e5665cd 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/authentication/RegexUrlPatternMatcherStrategy.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/authentication/RegexUrlPatternMatcherStrategy.java @@ -30,6 +30,12 @@ import java.util.regex.Pattern; public final class RegexUrlPatternMatcherStrategy implements UrlPatternMatcherStrategy { private Pattern pattern; + + public RegexUrlPatternMatcherStrategy() {} + + public RegexUrlPatternMatcherStrategy(final String pattern) { + this.setPattern(pattern); + } public boolean matches(final String url) { return this.pattern.matcher(url).find(); diff --git a/cas-client-core/src/main/java/org/jasig/cas/client/validation/ProxyList.java b/cas-client-core/src/main/java/org/jasig/cas/client/validation/ProxyList.java index 35642d3..f208779 100644 --- a/cas-client-core/src/main/java/org/jasig/cas/client/validation/ProxyList.java +++ b/cas-client-core/src/main/java/org/jasig/cas/client/validation/ProxyList.java @@ -19,9 +19,13 @@ package org.jasig.cas.client.validation; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; +import org.jasig.cas.client.authentication.ExactUrlPatternMatcherStrategy; +import org.jasig.cas.client.authentication.RegexUrlPatternMatcherStrategy; +import org.jasig.cas.client.authentication.UrlPatternMatcherStrategy; import org.jasig.cas.client.util.CommonUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Holding class for the proxy list to make Spring configuration easier. @@ -32,11 +36,28 @@ import org.jasig.cas.client.util.CommonUtils; */ public final class ProxyList { - private final List proxyChains; + private final Logger logger = LoggerFactory.getLogger(getClass()); + + private final List> proxyChains; public ProxyList(final List proxyChains) { CommonUtils.assertNotNull(proxyChains, "List of proxy chains cannot be null."); - this.proxyChains = proxyChains; + + this.proxyChains = new ArrayList>(); + + for (final String[] list : proxyChains) { + final List chain = new ArrayList(); + + for (final String item : list) { + if (item.startsWith("^")) { + chain.add(new RegexUrlPatternMatcherStrategy(item)); + } else { + chain.add(new ExactUrlPatternMatcherStrategy(item)); + } + } + + this.proxyChains.add(chain); + } } public ProxyList() { @@ -44,12 +65,33 @@ public final class ProxyList { } public boolean contains(final String[] proxiedList) { - for (final String[] list : this.proxyChains) { - if (Arrays.equals(proxiedList, list)) { - return true; + StringBuilder loggingOutput; + + for (final List proxyChain : this.proxyChains) { + loggingOutput = new StringBuilder(); + + if (proxyChain.size() == proxiedList.length) { + for (int linkIndex = 0; linkIndex < proxyChain.size(); linkIndex++) { + final String linkToTest = proxiedList[linkIndex]; + loggingOutput.append(linkToTest); + + if (proxyChain.get(linkIndex).matches(linkToTest)) { + //If we are at the last link, we found a good proxyChain. + if (linkIndex == proxyChain.size() - 1) { + logger.info("Proxy chain matched: {}", loggingOutput.toString()); + return true; + } + + } else { + logger.warn("Proxy chain did not match at {}. Skipping to next allowedProxyChain", loggingOutput.toString()); + break; + } + loggingOutput.append("->"); + } } } + logger.warn("No proxy chain matched the allowedProxyChains list."); return false; } diff --git a/cas-client-core/src/test/java/org/jasig/cas/client/validation/Cas20ProxyTicketValidatorTests.java b/cas-client-core/src/test/java/org/jasig/cas/client/validation/Cas20ProxyTicketValidatorTests.java index 4701107..b0db574 100644 --- a/cas-client-core/src/test/java/org/jasig/cas/client/validation/Cas20ProxyTicketValidatorTests.java +++ b/cas-client-core/src/test/java/org/jasig/cas/client/validation/Cas20ProxyTicketValidatorTests.java @@ -105,6 +105,37 @@ public final class Cas20ProxyTicketValidatorTests extends AbstractTicketValidato } } + @Test + public void testRegexProxyChainWithValidProxy() throws TicketValidationException, UnsupportedEncodingException { + final List list = new ArrayList(); + list.add(new String[] { "proxy1", "proxy2", "^proxy3/[a-z]*/" }); + this.ticketValidator.setAllowedProxyChains(new ProxyList(list)); + + final String USERNAME = "username"; + final String RESPONSE = "usernamePGTIOU-84678-8a9d...proxy1proxy2proxy3/abc/"; + server.content = RESPONSE.getBytes(server.encoding); + + final Assertion assertion = this.ticketValidator.validate("test", "test"); + assertEquals(USERNAME, assertion.getPrincipal().getName()); + } + + @Test + public void testRegexProxyChainWithInvalidProxy() throws TicketValidationException, UnsupportedEncodingException { + final List list = new ArrayList(); + list.add(new String[] { "proxy1", "proxy2", "^proxy3/[a-z]*/" }); + this.ticketValidator.setAllowedProxyChains(new ProxyList(list)); + + final String RESPONSE = "usernamePGTIOU-84678-8a9d...proxy1proxy2proxy3/ABC/"; + server.content = RESPONSE.getBytes(server.encoding); + + try { + this.ticketValidator.validate("test", "test"); + fail("Invalid proxy chain"); + } catch (InvalidProxyChainTicketValidationException e) { + // expected + } + } + @Test public void testConstructionFromSpringBean() throws TicketValidationException, UnsupportedEncodingException { final ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(