Merge pull request #49 from battags/CASC-206
CASC-206 Added Authentication Redirect Strategy to support original use case and new Faces support
This commit is contained in:
commit
180f1f803b
|
|
@ -20,6 +20,7 @@ package org.jasig.cas.client.authentication;
|
|||
|
||||
import org.jasig.cas.client.util.AbstractCasFilter;
|
||||
import org.jasig.cas.client.util.CommonUtils;
|
||||
import org.jasig.cas.client.util.ReflectUtils;
|
||||
import org.jasig.cas.client.validation.Assertion;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
|
|
@ -68,6 +69,8 @@ public class AuthenticationFilter extends AbstractCasFilter {
|
|||
|
||||
private GatewayResolver gatewayStorage = new DefaultGatewayResolverImpl();
|
||||
|
||||
private AuthenticationRedirectStrategy authenticationRedirectStrategy = new DefaultAuthenticationRedirectStrategy();
|
||||
|
||||
protected void initInternal(final FilterConfig filterConfig) throws ServletException {
|
||||
if (!isIgnoreInitConfiguration()) {
|
||||
super.initInternal(filterConfig);
|
||||
|
|
@ -81,12 +84,13 @@ public class AuthenticationFilter extends AbstractCasFilter {
|
|||
final String gatewayStorageClass = getPropertyFromInitParams(filterConfig, "gatewayStorageClass", null);
|
||||
|
||||
if (gatewayStorageClass != null) {
|
||||
try {
|
||||
this.gatewayStorage = (GatewayResolver) Class.forName(gatewayStorageClass).newInstance();
|
||||
} catch (final Exception e) {
|
||||
logger.error(e.getMessage(),e);
|
||||
throw new ServletException(e);
|
||||
}
|
||||
this.gatewayStorage = ReflectUtils.newInstance(gatewayStorageClass);
|
||||
}
|
||||
|
||||
final String authenticationRedirectStrategyClass = getPropertyFromInitParams(filterConfig, "authenticationRedirectStrategyClass", null);
|
||||
|
||||
if (authenticationRedirectStrategyClass != null) {
|
||||
this.authenticationRedirectStrategy = ReflectUtils.newInstance(authenticationRedirectStrategyClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -131,8 +135,7 @@ public class AuthenticationFilter extends AbstractCasFilter {
|
|||
final String urlToRedirectTo = CommonUtils.constructRedirectUrl(this.casServerLoginUrl, getServiceParameterName(), modifiedServiceUrl, this.renew, this.gateway);
|
||||
|
||||
logger.debug("redirecting to \"{}\"", urlToRedirectTo);
|
||||
|
||||
response.sendRedirect(urlToRedirectTo);
|
||||
this.authenticationRedirectStrategy.redirect(request, response, urlToRedirectTo);
|
||||
}
|
||||
|
||||
public final void setRenew(final boolean renew) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,27 @@
|
|||
package org.jasig.cas.client.authentication;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Interface to abstract the authentication strategy for redirecting. The traditional method was to always just redirect,
|
||||
* but due to AJAX, etc. we may need to support other strategies. This interface is designed to hold that logic such that
|
||||
* authentication filter class does not get crazily complex.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @since 3.3.0
|
||||
*/
|
||||
public interface AuthenticationRedirectStrategy {
|
||||
|
||||
/**
|
||||
* Method name is a bit of a misnomer. This method handles "redirection" for a localized version of redirection (i.e. AJAX might mean an XML fragment that contains the url to go to).
|
||||
*
|
||||
* @param request the original HttpServletRequest. MAY NOT BE NULL.
|
||||
* @param response the original HttpServletResponse. MAY NOT BE NULL.
|
||||
* @param potentialRedirectUrl the url that might be used (there are no guarantees of course!)
|
||||
* @throws IOException the exception to throw if there is some type of error. This will bubble up through the filter.
|
||||
*/
|
||||
void redirect(HttpServletRequest request, HttpServletResponse response, String potentialRedirectUrl) throws IOException;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
package org.jasig.cas.client.authentication;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Implementation of the {@link AuthenticationRedirectStrategy} class that preserves the original behavior that existed prior to 3.3.0.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @since 3.3.0
|
||||
*/
|
||||
public final class DefaultAuthenticationRedirectStrategy implements AuthenticationRedirectStrategy {
|
||||
|
||||
public void redirect(final HttpServletRequest request, final HttpServletResponse response, final String potentialRedirectUrl) throws IOException {
|
||||
response.sendRedirect(potentialRedirectUrl);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
package org.jasig.cas.client.authentication;
|
||||
|
||||
import org.jasig.cas.client.util.CommonUtils;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
/**
|
||||
* Implementation of the redirect strategy that can handle a Faces Ajax request in addition to the standard redirect style.
|
||||
*
|
||||
* @author Scott Battaglia
|
||||
* @since 3.3.0
|
||||
*/
|
||||
public final class FacesCompatibleAuthenticationRedirectStrategy implements AuthenticationRedirectStrategy {
|
||||
|
||||
private static final String FACES_PARTIAL_AJAX_PARAMETER = "javax.faces.partial.ajax";
|
||||
|
||||
public void redirect(final HttpServletRequest request, final HttpServletResponse response, final String potentialRedirectUrl) throws IOException {
|
||||
|
||||
if (CommonUtils.isNotBlank(request.getParameter(FACES_PARTIAL_AJAX_PARAMETER))) {
|
||||
// this is an ajax request - redirect ajaxly
|
||||
response.setContentType("text/xml");
|
||||
response.setStatus(200);
|
||||
|
||||
final PrintWriter writer = response.getWriter();
|
||||
writer.write("<?xml version='1.0' encoding='UTF-8'?>");
|
||||
writer.write(String.format("<partial-response><redirect url=\"%s\"></redirect></partial-response>", potentialRedirectUrl));
|
||||
} else {
|
||||
response.sendRedirect(potentialRedirectUrl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -27,15 +27,19 @@ import javax.servlet.ServletException;
|
|||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
import org.jasig.cas.client.util.AbstractCasFilter;
|
||||
import org.jasig.cas.client.validation.AssertionImpl;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
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;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Tests for the AuthenticationFilter.
|
||||
*
|
||||
|
|
@ -43,7 +47,7 @@ import org.springframework.mock.web.MockServletContext;
|
|||
* @version $Revision: 11753 $ $Date: 2007-01-03 13:37:26 -0500 (Wed, 03 Jan 2007) $
|
||||
* @since 3.0
|
||||
*/
|
||||
public final class AuthenticationFilterTests extends TestCase {
|
||||
public final class AuthenticationFilterTests {
|
||||
|
||||
private static final String CAS_SERVICE_URL = "https://localhost:8443/service";
|
||||
|
||||
|
|
@ -51,7 +55,8 @@ public final class AuthenticationFilterTests extends TestCase {
|
|||
|
||||
private AuthenticationFilter filter;
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
// TODO CAS_SERVICE_URL, false, CAS_LOGIN_URL
|
||||
this.filter = new AuthenticationFilter();
|
||||
final MockFilterConfig config = new MockFilterConfig();
|
||||
|
|
@ -60,10 +65,12 @@ public final class AuthenticationFilterTests extends TestCase {
|
|||
this.filter.init(config);
|
||||
}
|
||||
|
||||
protected void tearDown() throws Exception {
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
this.filter.destroy();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRedirect() throws Exception {
|
||||
final MockHttpSession session = new MockHttpSession();
|
||||
final MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
|
|
@ -84,6 +91,7 @@ public final class AuthenticationFilterTests extends TestCase {
|
|||
.getRedirectedUrl());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRedirectWithQueryString() throws Exception {
|
||||
final MockHttpSession session = new MockHttpSession();
|
||||
final MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
|
|
@ -116,6 +124,7 @@ public final class AuthenticationFilterTests extends TestCase {
|
|||
"UTF-8"), response.getRedirectedUrl());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAssertion() throws Exception {
|
||||
final MockHttpSession session = new MockHttpSession();
|
||||
final MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
|
|
@ -136,6 +145,7 @@ public final class AuthenticationFilterTests extends TestCase {
|
|||
assertNull(response.getRedirectedUrl());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRenew() throws Exception {
|
||||
final MockHttpSession session = new MockHttpSession();
|
||||
final MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
|
|
@ -156,6 +166,7 @@ public final class AuthenticationFilterTests extends TestCase {
|
|||
assertTrue(response.getRedirectedUrl().indexOf("renew=true") != -1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGateway() throws Exception {
|
||||
final MockHttpSession session = new MockHttpSession();
|
||||
final MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
|
|
@ -181,6 +192,7 @@ public final class AuthenticationFilterTests extends TestCase {
|
|||
assertNull(response2.getRedirectedUrl());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRenewInitParamThrows() throws Exception {
|
||||
final AuthenticationFilter f = new AuthenticationFilter();
|
||||
final MockFilterConfig config = new MockFilterConfig();
|
||||
|
|
@ -195,6 +207,7 @@ public final class AuthenticationFilterTests extends TestCase {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAllowsRenewContextParam() throws Exception {
|
||||
final AuthenticationFilter f = new AuthenticationFilter();
|
||||
final MockServletContext context = new MockServletContext();
|
||||
|
|
@ -206,4 +219,14 @@ public final class AuthenticationFilterTests extends TestCase {
|
|||
renewField.setAccessible(true);
|
||||
assertTrue((Boolean) renewField.get(f));
|
||||
}
|
||||
|
||||
@Test
|
||||
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("authenticationRedirectStrategyClass", "org.jasig.cas.client.authentication.FacesCompatibleAuthenticationRedirectStrategy");
|
||||
f.init(new MockFilterConfig(context));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
package org.jasig.cas.client.authentication;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
|
||||
public class DefaultAuthenticationRedirectStrategyTests {
|
||||
|
||||
private DefaultAuthenticationRedirectStrategy strategy;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
this.strategy = new DefaultAuthenticationRedirectStrategy();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void didWeRedirect() throws Exception {
|
||||
final String redirectUrl = "http://www.jasig.org";
|
||||
final MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
final MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
|
||||
this.strategy.redirect(request, response, redirectUrl);
|
||||
assertEquals(redirectUrl, response.getRedirectedUrl());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
package org.jasig.cas.client.authentication;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class FacesCompatibleAuthenticationRedirectStrategyTests {
|
||||
|
||||
private FacesCompatibleAuthenticationRedirectStrategy strategy;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
this.strategy = new FacesCompatibleAuthenticationRedirectStrategy();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void didWeRedirect() throws Exception {
|
||||
final String redirectUrl = "http://www.jasig.org";
|
||||
final MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
final MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
|
||||
this.strategy.redirect(request, response, redirectUrl);
|
||||
assertEquals(redirectUrl, response.getRedirectedUrl());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void facesPartialResponse() throws Exception {
|
||||
final String redirectUrl = "http://www.jasig.org";
|
||||
final MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
final MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
request.setParameter("javax.faces.partial.ajax", "true");
|
||||
this.strategy.redirect(request, response, redirectUrl);
|
||||
assertNull(response.getRedirectedUrl());
|
||||
assertTrue(response.getContentAsString().contains(redirectUrl));
|
||||
}
|
||||
}
|
||||
|
|
@ -28,6 +28,7 @@ import org.junit.Test;
|
|||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Test cases for the {@link Cas20ServiceTicketValidator}.
|
||||
|
|
|
|||
Loading…
Reference in New Issue