tag for 3.1.7
This commit is contained in:
Scott Battaglia 2009-08-12 13:47:49 +00:00
parent e78706747a
commit 3f72803d57
15 changed files with 275 additions and 206 deletions

View File

@ -2,7 +2,7 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<groupId>org.jasig.cas</groupId>
<version>3.1.5</version>
<version>3.1.7</version>
<artifactId>cas-client</artifactId>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -87,38 +87,43 @@ public class AuthenticationFilter extends AbstractCasFilter {
final HttpServletRequest request = (HttpServletRequest) servletRequest;
final HttpServletResponse response = (HttpServletResponse) servletResponse;
final HttpSession session = request.getSession(false);
final String ticket = request.getParameter(getArtifactParameterName());
final String serviceUrl = constructServiceUrl(request, response);
final Assertion assertion = session != null ? (Assertion) session
.getAttribute(CONST_CAS_ASSERTION) : null;
final boolean wasGatewayed = this.gatewayStorage.hasGatewayedAlready(request, serviceUrl);
final Assertion assertion = session != null ? (Assertion) session.getAttribute(CONST_CAS_ASSERTION) : null;
if (CommonUtils.isBlank(ticket) && assertion == null && !wasGatewayed) {
final String modifiedServiceUrl;
log.debug("no ticket and no assertion found");
if (this.gateway) {
log.debug("setting gateway attribute in session");
modifiedServiceUrl = this.gatewayStorage.storeGatewayInformation(request, serviceUrl);
} else {
modifiedServiceUrl = serviceUrl;
}
if (log.isDebugEnabled()) {
log.debug("Constructed service url: " + modifiedServiceUrl);
}
final String urlToRedirectTo = CommonUtils.constructRedirectUrl(this.casServerLoginUrl, getServiceParameterName(), modifiedServiceUrl, this.renew, this.gateway);
if (log.isDebugEnabled()) {
log.debug("redirecting to \"" + urlToRedirectTo + "\"");
}
response.sendRedirect(urlToRedirectTo);
if (assertion != null) {
filterChain.doFilter(request, response);
return;
}
filterChain.doFilter(request, response);
final String ticket = CommonUtils.safeGetParameter(request,getArtifactParameterName());
final boolean wasGatewayed = this.gatewayStorage.hasGatewayedAlready(request, serviceUrl);
if (CommonUtils.isNotBlank(ticket) || wasGatewayed) {
filterChain.doFilter(request, response);
return;
}
final String modifiedServiceUrl;
log.debug("no ticket and no assertion found");
if (this.gateway) {
log.debug("setting gateway attribute in session");
modifiedServiceUrl = this.gatewayStorage.storeGatewayInformation(request, serviceUrl);
} else {
modifiedServiceUrl = serviceUrl;
}
if (log.isDebugEnabled()) {
log.debug("Constructed service url: " + modifiedServiceUrl);
}
final String urlToRedirectTo = CommonUtils.constructRedirectUrl(this.casServerLoginUrl, getServiceParameterName(), modifiedServiceUrl, this.renew, this.gateway);
if (log.isDebugEnabled()) {
log.debug("redirecting to \"" + urlToRedirectTo + "\"");
}
response.sendRedirect(urlToRedirectTo);
}
public final void setRenew(final boolean renew) {

View File

@ -57,7 +57,7 @@ public final class SingleSignOutFilter extends AbstractConfigurationFilter {
final HttpServletRequest request = (HttpServletRequest) servletRequest;
if ("POST".equals(request.getMethod())) {
final String logoutRequest = request.getParameter("logoutRequest");
final String logoutRequest = CommonUtils.safeGetParameter(request, "logoutRequest");
if (CommonUtils.isNotBlank(logoutRequest)) {
@ -87,7 +87,7 @@ public final class SingleSignOutFilter extends AbstractConfigurationFilter {
}
}
} else {
final String artifact = request.getParameter(this.artifactParameterName);
final String artifact = CommonUtils.safeGetParameter(request, this.artifactParameterName);
final HttpSession session = request.getSession();
if (log.isDebugEnabled() && session != null) {

View File

@ -11,6 +11,7 @@ import org.jasig.cas.client.proxy.ProxyGrantingTicketStorage;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.ServletRequest;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
@ -138,7 +139,7 @@ public final class CommonUtils {
*/
public static final String constructRedirectUrl(final String casServerLoginUrl, final String serviceParameterName, final String serviceUrl, final boolean renew, final boolean gateway) {
try {
return casServerLoginUrl + "?" + serviceParameterName + "="
return casServerLoginUrl + (casServerLoginUrl.indexOf("?") != -1 ? "&" : "?") + serviceParameterName + "="
+ URLEncoder.encode(serviceUrl, "UTF-8")
+ (renew ? "&renew=true" : "")
+ (gateway ? "&gateway=true" : "");
@ -236,4 +237,15 @@ public final class CommonUtils {
return returnValue;
}
/**
* Safe method for retrieving a parameter from the request without disrupting the reader UNLESS the parameter
* actually exists in the query string.
*
* @param request the request to check.
* @param parameter the parameter to look for.
* @return the value of the parameter.
*/
public static String safeGetParameter(final HttpServletRequest request, final String parameter) {
return request.getQueryString() == null || request.getQueryString().indexOf(parameter) == -1 ? null : request.getParameter(parameter);
}
}

View File

@ -14,6 +14,7 @@ import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.Iterator;
import java.util.Map;
@ -89,8 +90,7 @@ public final class DelegatingFilter implements Filter {
final ServletResponse response, final FilterChain filterChain)
throws IOException, ServletException {
final String parameter = request
.getParameter(this.requestParameterName);
final String parameter = CommonUtils.safeGetParameter((HttpServletRequest) request, this.requestParameterName);
if (CommonUtils.isNotEmpty(parameter)) {
for (final Iterator iter = this.delegators.keySet().iterator(); iter

View File

@ -121,7 +121,7 @@ public abstract class AbstractTicketValidationFilter extends AbstractCasFilter {
final HttpServletRequest request = (HttpServletRequest) servletRequest;
final HttpServletResponse response = (HttpServletResponse) servletResponse;
final String ticket = request.getParameter(getArtifactParameterName());
final String ticket = CommonUtils.safeGetParameter(request, getArtifactParameterName());
if (CommonUtils.isNotBlank(ticket)) {
if (log.isDebugEnabled()) {

View File

@ -91,7 +91,7 @@ public class Cas20ProxyReceivingTicketValidationFilter extends AbstractTicketVal
if (CommonUtils.isNotBlank(allowAnyProxy) || CommonUtils.isNotBlank(allowedProxyChains)) {
final Cas20ProxyTicketValidator v = new Cas20ProxyTicketValidator(casServerUrlPrefix);
v.setAcceptAnyProxy(parseBoolean(allowAnyProxy));
v.setAllowedProxyChains(new ProxyList(constructListOfProxies(allowedProxyChains)));
v.setAllowedProxyChains(createProxyList(allowedProxyChains));
validator = v;
} else {
validator = new Cas20ServiceTicketValidator(casServerUrlPrefix);
@ -117,17 +117,15 @@ public class Cas20ProxyReceivingTicketValidationFilter extends AbstractTicketVal
return validator;
}
protected final List constructListOfProxies(final String proxies) {
protected final ProxyList createProxyList(final String proxies) {
if (CommonUtils.isBlank(proxies)) {
return new ArrayList();
return new ProxyList();
}
final String[] splitProxies = proxies.split("\n");
final List items = Arrays.asList(splitProxies);
final ProxyListEditor editor = new ProxyListEditor();
editor.setValue(items);
return (List) editor.getValue();
}
editor.setAsText(proxies);
return (ProxyList) editor.getValue();
}
public void destroy() {
super.destroy();
@ -166,4 +164,8 @@ public class Cas20ProxyReceivingTicketValidationFilter extends AbstractTicketVal
public void setTimerTask(final TimerTask timerTask) {
this.timerTask = timerTask;
}
public void setMillisBetweenCleanUps(final int millisBetweenCleanUps) {
this.millisBetweenCleanUps = millisBetweenCleanUps;
}
}

View File

@ -5,6 +5,8 @@
*/
package org.jasig.cas.client.validation;
import org.jasig.cas.client.util.CommonUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.Iterator;
@ -22,6 +24,13 @@ public final class ProxyList {
private final List proxyChains;
public ProxyList(final List proxyChains) {
CommonUtils.assertNotNull(proxyChains, "List of proxy chains cannot be null.");
// Assert that all entries in the list are String[]
for (final Iterator iter = proxyChains.iterator(); iter.hasNext();) {
CommonUtils.assertTrue(iter.next() instanceof String[], "Proxy chains must contain String[] items exclusively.");
}
this.proxyChains = proxyChains;
}

View File

@ -13,6 +13,8 @@ import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.*;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
/**
* TicketValidator that can understand validating a SAML artifact. This includes the SOAP request/response.
@ -158,8 +160,14 @@ public final class Saml11TicketValidator extends AbstractUrlBasedTicketValidator
return list;
}
private static String getFormattedDateAndTime(final Date date) {
final DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
return dateFormat.format(date);
}
protected String retrieveResponseFromServer(final URL validationUrl, final String ticket) {
final String MESSAGE_TO_SEND = "<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\"><SOAP-ENV:Header/><SOAP-ENV:Body><samlp:Request xmlns:samlp=\"urn:oasis:names:tc:SAML:1.0:protocol\" MajorVersion=\"1\" MinorVersion=\"1\" RequestID=\"_192.168.16.51.1024506224022\" IssueInstant=\"2002-06-19T17:03:44.022Z\">"
final String MESSAGE_TO_SEND = "<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\"><SOAP-ENV:Header/><SOAP-ENV:Body><samlp:Request xmlns:samlp=\"urn:oasis:names:tc:SAML:1.0:protocol\" MajorVersion=\"1\" MinorVersion=\"1\" RequestID=\"" + UUID.randomUUID().toString() + "\" IssueInstant=\"" + getFormattedDateAndTime(new Date()) + "\">"
+ "<samlp:AssertionArtifact>" + ticket
+ "</samlp:AssertionArtifact></samlp:Request></SOAP-ENV:Body></SOAP-ENV:Envelope>";

View File

@ -1,125 +0,0 @@
package org.jasig.cas.client.proxy;
import java.util.Timer;
import java.util.TimerTask;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import junit.framework.TestCase;
import org.jasig.cas.client.util.MethodFlag;
import org.springframework.mock.web.MockServletContext;
/**
* Unit test for {@link CleanUpListener}
*
* @author Brad Cupit (brad [at] lsu {dot} edu)
*/
public class CleanUpListenerTest extends TestCase {
private final Timer defaultTimer = new Timer(true);
/*
private final CleanUpTimerTask defaultTimerTask = new CleanUpTimerTask();
public void testStartsThreadAtStartup() throws Exception {
final MethodFlag scheduleMethodFlag = new MethodFlag();
final Timer timer = new Timer(true) {
public void schedule(TimerTask task, long delay, long period) {
scheduleMethodFlag.setCalled();
}
};
final CleanUpListener cleanUpListener = new CleanUpListener(timer, defaultTimerTask);
cleanUpListener.contextInitialized(new TestServletContextEvent(1));
assertTrue(scheduleMethodFlag.wasCalled());
}
public void testShutsDownTimerThread() throws Exception {
final MethodFlag cancelMethodFlag = new MethodFlag();
final Timer timer = new Timer(true) {
public void cancel() {
cancelMethodFlag.setCalled();
super.cancel();
}
};
final CleanUpListener cleanUpListener = new CleanUpListener(timer, defaultTimerTask);
cleanUpListener.contextInitialized(new TestServletContextEvent(1));
cleanUpListener.contextDestroyed(null);
assertTrue(cancelMethodFlag.wasCalled());
}
public void testCallsCleanAllOnSchedule() throws Exception {
final MethodFlag timerTaskFlag = new MethodFlag();
final TimerTask timerTask = new TimerTask() {
public void run() {
timerTaskFlag.setCalled();
}
};
long millisBetweenCleanUps = 250;
final CleanUpListener cleanUpListener = new CleanUpListener(defaultTimer, timerTask);
cleanUpListener.contextInitialized(new TestServletContextEvent(millisBetweenCleanUps));
// wait long enough for the clean up to occur
Thread.sleep(millisBetweenCleanUps * 2);
assertTrue(timerTaskFlag.wasCalled());
}
public void testDelaysFirstCleanAll() throws Exception {
final MethodFlag timerTaskFlag = new MethodFlag();
final TimerTask timerTask = new TimerTask() {
public void run() {
timerTaskFlag.setCalled();
}
};
long millisBetweenCleanUps = 250;
final CleanUpListener cleanUpListener = new CleanUpListener(defaultTimer, timerTask);
cleanUpListener.contextInitialized(new TestServletContextEvent(millisBetweenCleanUps));
assertFalse(timerTaskFlag.wasCalled());
// wait long enough for the clean up to occur
Thread.sleep(millisBetweenCleanUps * 2);
assertTrue(timerTaskFlag.wasCalled());
}
public void testReturnsDefaultWhenNoContextParamConfigured() throws Exception {
final ServletContext servletContext = new MockServletContext();
long millisBetweenCleanups = new CleanUpListener().getMillisBetweenCleanups(servletContext);
assertEquals(CleanUpListener.DEFAULT_MILLIS_BETWEEN_CLEANUPS, millisBetweenCleanups);
}
public void testFailsWithInvalidNumber() throws Exception {
final ServletContext servletContext = new MockServletContext() {
public String getInitParameter(String name) {
if (name.equals(CleanUpListener.MILLIS_BETWEEN_CLEANUPS_INIT_PARAM)) {
return "not a number";
} else {
return null;
}
}
};
try {
new CleanUpListener().getMillisBetweenCleanups(servletContext);
fail("expected an exception");
} catch (RuntimeException e) {
// expected, test passes
}
}
*/
}

View File

@ -19,6 +19,22 @@ import java.util.Collection;
*/
public final class CommonUtilsTests extends TestCase {
public void testRedirectUrlWithParam() {
final String loginUrl = "http://localhost:8080/login?myName=foo";
final String fullyConstructedUrl = CommonUtils.constructRedirectUrl(loginUrl, "foo", "foo", false, false);
int count = 0;
final char[] chars = fullyConstructedUrl.toCharArray();
for (int i = 0; i < chars.length; i++) {
if (chars[i] == '?') {
count ++;
}
}
assertEquals(1, count);
}
public void testAssertNotNull() {
final String CONST_MESSAGE = "test";
CommonUtils.assertNotNull(new Object(), CONST_MESSAGE);

View File

@ -1,34 +0,0 @@
package org.jasig.cas.client.validation;
import junit.framework.TestCase;
/**
* Unit test for {@link Cas20ProxyReceivingTicketValidationFilter}
*
* @author Brad Cupit (brad [at] lsu {dot} edu)
*/
public class Cas20ProxyReceivingTicketValidationFilterTest extends TestCase {
public void testThrowsForNullStorage() throws Exception {
Cas20ProxyReceivingTicketValidationFilter filter = newCas20ProxyReceivingTicketValidationFilter();
filter.setProxyGrantingTicketStorage(null);
try {
filter.init();
fail("expected an exception due to null ProxyGrantingTicketStorage");
} catch (IllegalArgumentException exception) {
// test passes
}
}
/**
* construct a working {@link Cas20ProxyReceivingTicketValidationFilter}
*/
private Cas20ProxyReceivingTicketValidationFilter newCas20ProxyReceivingTicketValidationFilter() {
final Cas20ProxyReceivingTicketValidationFilter filter = new Cas20ProxyReceivingTicketValidationFilter();
filter.setServerName("localhost");
filter.setTicketValidator(new Cas20ProxyTicketValidator(""));
return filter;
}
}

View File

@ -0,0 +1,176 @@
package org.jasig.cas.client.validation;
import junit.framework.TestCase;
import org.jasig.cas.client.proxy.CleanUpTimerTask;
import org.jasig.cas.client.proxy.ProxyGrantingTicketStorage;
import org.jasig.cas.client.proxy.ProxyGrantingTicketStorageImpl;
import org.jasig.cas.client.util.MethodFlag;
import org.springframework.mock.web.MockFilterConfig;
import java.util.Timer;
import java.util.TimerTask;
/**
* Unit test for {@link org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter}
*
* @author Brad Cupit (brad [at] lsu {dot} edu)
*/
public class Cas20ProxyReceivingTicketValidationFilterTests extends TestCase {
private final Timer defaultTimer = new Timer(true);
private final ProxyGrantingTicketStorage storage = new ProxyGrantingTicketStorageImpl();
private final CleanUpTimerTask defaultTimerTask = new CleanUpTimerTask(storage);
public void testStartsThreadAtStartup() throws Exception {
final MethodFlag scheduleMethodFlag = new MethodFlag();
final Cas20ProxyReceivingTicketValidationFilter filter = newCas20ProxyReceivingTicketValidationFilter();
final Timer timer = new Timer(true) {
public void schedule(TimerTask task, long delay, long period) {
scheduleMethodFlag.setCalled();
}
};
filter.setMillisBetweenCleanUps(1);
filter.setProxyGrantingTicketStorage(storage);
filter.setTimer(timer);
filter.setTimerTask(defaultTimerTask);
filter.init();
assertTrue(scheduleMethodFlag.wasCalled());
}
public void testShutsDownTimerThread() throws Exception {
final MethodFlag cancelMethodFlag = new MethodFlag();
final Cas20ProxyReceivingTicketValidationFilter filter = newCas20ProxyReceivingTicketValidationFilter();
final Timer timer = new Timer(true) {
public void cancel() {
cancelMethodFlag.setCalled();
super.cancel();
}
};
filter.setProxyGrantingTicketStorage(storage);
filter.setMillisBetweenCleanUps(1);
filter.setTimer(timer);
filter.setTimerTask(defaultTimerTask);
filter.init();
filter.destroy();
assertTrue(cancelMethodFlag.wasCalled());
}
public void testCallsCleanAllOnSchedule() throws Exception {
final MethodFlag timerTaskFlag = new MethodFlag();
final Cas20ProxyReceivingTicketValidationFilter filter = newCas20ProxyReceivingTicketValidationFilter();
final TimerTask timerTask = new TimerTask() {
public void run() {
timerTaskFlag.setCalled();
}
};
final int millisBetweenCleanUps = 250;
filter.setProxyGrantingTicketStorage(storage);
filter.setTimerTask(timerTask);
filter.setTimer(defaultTimer);
filter.setMillisBetweenCleanUps(millisBetweenCleanUps);
filter.init();
// wait long enough for the clean up to occur
Thread.sleep(millisBetweenCleanUps * 2);
assertTrue(timerTaskFlag.wasCalled());
filter.destroy();
}
public void testDelaysFirstCleanAll() throws Exception {
final MethodFlag timerTaskFlag = new MethodFlag();
final Cas20ProxyReceivingTicketValidationFilter filter = newCas20ProxyReceivingTicketValidationFilter();
final TimerTask timerTask = new TimerTask() {
public void run() {
timerTaskFlag.setCalled();
}
};
final int millisBetweenCleanUps = 250;
filter.setProxyGrantingTicketStorage(storage);
filter.setMillisBetweenCleanUps(millisBetweenCleanUps);
filter.setTimer(defaultTimer);
filter.setTimerTask(timerTask);
filter.init();
assertFalse(timerTaskFlag.wasCalled());
// wait long enough for the clean up to occur
Thread.sleep(millisBetweenCleanUps * 2);
assertTrue(timerTaskFlag.wasCalled());
filter.destroy();
}
public void testThrowsForNullStorage() throws Exception {
Cas20ProxyReceivingTicketValidationFilter filter = newCas20ProxyReceivingTicketValidationFilter();
filter.setProxyGrantingTicketStorage(null);
try {
filter.init();
fail("expected an exception due to null ProxyGrantingTicketStorage");
} catch (IllegalArgumentException exception) {
// test passes
}
}
public void testGetTicketValidator() throws Exception {
Cas20ProxyReceivingTicketValidationFilter filter = newCas20ProxyReceivingTicketValidationFilter();
filter.setProxyGrantingTicketStorage(storage);
filter.setMillisBetweenCleanUps(250);
filter.setTimer(defaultTimer);
filter.setTimerTask(new TimerTask() {
public void run() {}
});
filter.init();
// Test case #1
final MockFilterConfig config1 = new MockFilterConfig();
config1.addInitParameter("allowedProxyChains", "https://a.example.com");
config1.addInitParameter("casServerUrlPrefix", "https://cas.jasig.org/");
assertNotNull(filter.getTicketValidator(config1));
// Test case #2
final MockFilterConfig config2 = new MockFilterConfig();
config2.addInitParameter(
"allowedProxyChains",
"https://a.example.com https://b.example.com");
config2.addInitParameter("casServerUrlPrefix", "https://cas.jasig.org/");
assertNotNull(filter.getTicketValidator(config2));
// Test case #3
final MockFilterConfig config3 = new MockFilterConfig();
config3.addInitParameter(
"allowedProxyChains",
"https://a.example.com https://b.example.com\nhttps://c.example.com");
config3.addInitParameter("casServerUrlPrefix", "https://cas.jasig.org/");
assertNotNull(filter.getTicketValidator(config3));
}
/**
* construct a working {@link org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter}
*/
private Cas20ProxyReceivingTicketValidationFilter newCas20ProxyReceivingTicketValidationFilter() {
final Cas20ProxyReceivingTicketValidationFilter filter = new Cas20ProxyReceivingTicketValidationFilter();
filter.setServerName("localhost");
filter.setTicketValidator(new Cas20ProxyTicketValidator(""));
return filter;
}
}

View File

@ -2,7 +2,7 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<groupId>org.jasig.cas</groupId>
<version>3.1.5</version>
<version>3.1.7</version>
<artifactId>cas-client</artifactId>
</parent>
<modelVersion>4.0.0</modelVersion>
@ -65,13 +65,13 @@
<groupId>opensymphony</groupId>
<artifactId>propertyset</artifactId>
</exclusion>
</exclusions>
</exclusions>
</dependency>
<dependency>
<groupId>com.atlassian.confluence</groupId>
<artifactId>confluence</artifactId>
<version>2.7.3</version>
<version>2.7.3</version>
<scope>provided</scope>
<exclusions>
<exclusion>

View File

@ -1,7 +1,7 @@
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>org.jasig.cas</groupId>
<version>3.1.5</version>
<version>3.1.7</version>
<artifactId>cas-client</artifactId>
<packaging>pom</packaging>
<name>JA-SIG CAS Client for Java</name>