diff --git a/cas/src/main/java/org/springframework/security/cas/authentication/TriggerCasGatewayException.java b/cas/src/main/java/org/springframework/security/cas/authentication/TriggerCasGatewayException.java
new file mode 100644
index 00000000000..ba22550e9c6
--- /dev/null
+++ b/cas/src/main/java/org/springframework/security/cas/authentication/TriggerCasGatewayException.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2013-2013 the original author or authors.
+ *
+ * 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 org.springframework.security.cas.authentication;
+
+import org.springframework.security.cas.web.CasAuthenticationEntryPoint;
+import org.springframework.security.core.AuthenticationException;
+
+/**
+ * Exception used to indicate the {@link CasAuthenticationEntryPoint} to make a CAS gateway authentication request.
+ *
+ * @author Michael Remond
+ *
+ */
+public class TriggerCasGatewayException extends
+ AuthenticationException {
+
+ //~ Constructors ===================================================================================================
+
+ /**
+ * Constructs an {@code InitiateCasGatewayAuthenticationException} with the specified message and no root cause.
+ *
+ * @param msg the detail message
+ */
+ public TriggerCasGatewayException(String msg) {
+ super(msg);
+ }
+
+ /**
+ * Constructs an {@code InitiateCasGatewayAuthenticationException} with the specified message and root cause.
+ *
+ * @param msg the detail message
+ * @param t the root cause
+ */
+ public TriggerCasGatewayException(String msg, Throwable t) {
+ super(msg, t);
+ }
+
+}
diff --git a/cas/src/main/java/org/springframework/security/cas/web/CasAuthenticationEntryPoint.java b/cas/src/main/java/org/springframework/security/cas/web/CasAuthenticationEntryPoint.java
index a06b73dfade..b29ff81ddf2 100644
--- a/cas/src/main/java/org/springframework/security/cas/web/CasAuthenticationEntryPoint.java
+++ b/cas/src/main/java/org/springframework/security/cas/web/CasAuthenticationEntryPoint.java
@@ -1,4 +1,4 @@
-/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
+/* Copyright 2004, 2005, 2006, 2013 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.
@@ -22,10 +22,11 @@
import javax.servlet.http.HttpServletResponse;
import org.jasig.cas.client.util.CommonUtils;
+import org.springframework.beans.factory.InitializingBean;
import org.springframework.security.cas.ServiceProperties;
+import org.springframework.security.cas.authentication.TriggerCasGatewayException;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
-import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;
@@ -38,6 +39,9 @@
* redirect to the page indicated by the service
property. The service
is a HTTP URL
* belonging to the current application. The service
URL is monitored by the {@link CasAuthenticationFilter},
* which will validate the CAS login was successful.
+ *
+ * If the raised exception is {@link TriggerCasGatewayException}, the parameter gateway
is set
+ * to true on the redirect url.
*
* @author Ben Alex
* @author Scott Battaglia
@@ -72,7 +76,7 @@ public final void commence(final HttpServletRequest servletRequest, final HttpSe
final AuthenticationException authenticationException) throws IOException, ServletException {
final String urlEncodedService = createServiceUrl(servletRequest, response);
- final String redirectUrl = createRedirectUrl(urlEncodedService);
+ final String redirectUrl = createRedirectUrl(servletRequest, response, authenticationException, urlEncodedService);
preCommence(servletRequest, response);
@@ -95,8 +99,24 @@ protected String createServiceUrl(final HttpServletRequest request, final HttpSe
* @param serviceUrl the service url that should be included.
* @return the redirect url. CANNOT be NULL.
*/
+ @Deprecated
protected String createRedirectUrl(final String serviceUrl) {
- return CommonUtils.constructRedirectUrl(this.loginUrl, this.serviceProperties.getServiceParameter(), serviceUrl, this.serviceProperties.isSendRenew(), false);
+ return createRedirectUrl(null, null, null, serviceUrl);
+ }
+
+ /**
+ * Constructs the Url for Redirection to the CAS server. Default implementation relies on the CAS client to do the bulk of the work.
+ * Parameter gateway is infered from authenticationException class.
+ *
+ * @param request the HttpServletRequest
+ * @param response the HttpServletResponse
+ * @param authenticationException the authentication Exception that triggers CasAuthenticationEntryPoint
+ * @param serviceUrl the service url that should be included.
+ * @return the redirect url. CANNOT be NULL.
+ */
+ protected String createRedirectUrl(HttpServletRequest request, HttpServletResponse response, final AuthenticationException authenticationException, final String serviceUrl) {
+ boolean gateway = authenticationException instanceof TriggerCasGatewayException;
+ return CommonUtils.constructRedirectUrl(this.loginUrl, this.serviceProperties.getServiceParameter(), serviceUrl, this.serviceProperties.isSendRenew(), gateway);
}
/**
diff --git a/cas/src/main/java/org/springframework/security/cas/web/CasAuthenticationFilter.java b/cas/src/main/java/org/springframework/security/cas/web/CasAuthenticationFilter.java
index ed2e53126de..8c0fee6e6e8 100644
--- a/cas/src/main/java/org/springframework/security/cas/web/CasAuthenticationFilter.java
+++ b/cas/src/main/java/org/springframework/security/cas/web/CasAuthenticationFilter.java
@@ -1,4 +1,4 @@
-/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited
+/* Copyright 2004, 2005, 2006, 2013 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.
@@ -35,10 +35,16 @@
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.web.DefaultRedirectStrategy;
+import org.springframework.security.web.RedirectStrategy;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
+import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
+import org.springframework.security.web.savedrequest.RequestCache;
+import org.springframework.security.web.savedrequest.SavedRequest;
import org.springframework.util.Assert;
+import org.springframework.util.StringUtils;
/**
* Processes a CAS service ticket, obtains proxy granting tickets, and processes proxy tickets.
@@ -183,6 +189,10 @@ public class CasAuthenticationFilter extends AbstractAuthenticationProcessingFil
private AuthenticationFailureHandler proxyFailureHandler = new SimpleUrlAuthenticationFailureHandler();
+ private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
+
+ private RequestCache requestCache = new HttpSessionRequestCache();
+
//~ Constructors ===================================================================================================
public CasAuthenticationFilter() {
@@ -216,6 +226,25 @@ protected final void successfulAuthentication(HttpServletRequest request,
chain.doFilter(request, response);
}
+ /**
+ * We override this method because we don't want to clear the rememberMe in case of an unsuccessfull CAS gateway request.
+ */
+ @Override
+ protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response,
+ AuthenticationException failed) throws IOException, ServletException {
+
+ // if the request had a non empty artifact, we really encounter an unsuccessful authentication
+ // else it is probably an CAS gateway request with no SSO session, we redirect to the saved url
+ if (StringUtils.hasText(obtainArtifact(request))) {
+ super.unsuccessfulAuthentication(request, response, failed);
+ } else {
+ SavedRequest savedRequest = requestCache.getRequest(request, response);
+ if (savedRequest != null) {
+ redirectStrategy.sendRedirect(request, response, savedRequest.getRedirectUrl());
+ }
+ }
+ }
+
@Override
public Authentication attemptAuthentication(final HttpServletRequest request, final HttpServletResponse response)
throws AuthenticationException, IOException {
@@ -299,6 +328,16 @@ public final void setServiceProperties(final ServiceProperties serviceProperties
this.authenticateAllArtifacts = serviceProperties.isAuthenticateAllArtifacts();
}
+ public final void setRedirectStrategy(RedirectStrategy redirectStrategy) {
+ Assert.notNull(redirectStrategy,"redirectStrategy cannot be null");
+ this.redirectStrategy = redirectStrategy;
+ }
+
+ public final void setRequestCache(RequestCache requestCache) {
+ Assert.notNull(requestCache,"requestCache cannot be null");
+ this.requestCache = requestCache;
+ }
+
/**
* Indicates if the request is elgible to process a service ticket. This method exists for readability.
* @param request
diff --git a/cas/src/main/java/org/springframework/security/cas/web/DefaultCasGatewayRequestMatcher.java b/cas/src/main/java/org/springframework/security/cas/web/DefaultCasGatewayRequestMatcher.java
new file mode 100644
index 00000000000..ebc07f3337a
--- /dev/null
+++ b/cas/src/main/java/org/springframework/security/cas/web/DefaultCasGatewayRequestMatcher.java
@@ -0,0 +1,103 @@
+package org.springframework.security.cas.web;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.jasig.cas.client.authentication.DefaultGatewayResolverImpl;
+import org.jasig.cas.client.authentication.GatewayResolver;
+import org.springframework.security.cas.ServiceProperties;
+import org.springframework.security.cas.authentication.CasAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.web.util.RequestMatcher;
+import org.springframework.util.Assert;
+
+/**
+ * Default RequestMatcher implementation for the {@link TriggerCasGatewayFilter}.
+ *
+ * This RequestMatcher returns true
iff :
+ *
+ * The request is marked as "gatewayed" using the configured {@link GatewayResolver} to avoid infinite loop.
+ *
+ * @author Michael Remond
+ *
+ */
+public class DefaultCasGatewayRequestMatcher implements RequestMatcher {
+
+ // ~ Instance fields
+ // ================================================================================================
+
+ private ServiceProperties serviceProperties;
+
+ private GatewayResolver gatewayStorage = new DefaultGatewayResolverImpl();
+
+ // ~ Constructors
+ // ===================================================================================================
+
+ public DefaultCasGatewayRequestMatcher(ServiceProperties serviceProperties) {
+ Assert.notNull(serviceProperties, "serviceProperties cannot be null");
+ this.serviceProperties = serviceProperties;
+ }
+
+ public final boolean matches(HttpServletRequest request) {
+
+ // Test if we are already authenticated
+ if (isAuthenticated(request)) {
+ return false;
+ }
+
+ // Test if the request was already gatewayed to avoid infinite loop
+ final boolean wasGatewayed = this.gatewayStorage.hasGatewayedAlready(request, serviceProperties.getService());
+
+ if (wasGatewayed) {
+ return false;
+ }
+
+ // If request matches gateway criteria, we mark the request as gatewayed and return true to trigger a CAS
+ // gateway authentication
+ if (performGatewayAuthentication(request)) {
+ gatewayStorage.storeGatewayInformation(request, serviceProperties.getService());
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Test if the user is authenticated in Spring Security. Default implementation test if the user is CAS
+ * authenticated.
+ *
+ * @param request
+ * @return true if the user is authenticated
+ */
+ protected boolean isAuthenticated(HttpServletRequest request) {
+ Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
+ return authentication instanceof CasAuthenticationToken;
+ }
+
+ /**
+ * Method that determines if the current request triggers a CAS gateway authentication. Default implementation
+ * always returns true
.
+ *
+ * @param request
+ * @return true if the request must trigger a CAS gateway authentication
+ */
+ protected boolean performGatewayAuthentication(HttpServletRequest request) {
+ return true;
+ }
+
+ public void setGatewayStorage(GatewayResolver gatewayStorage) {
+ Assert.notNull(gatewayStorage, "gatewayStorage cannot be null");
+ this.gatewayStorage = gatewayStorage;
+ }
+
+}
diff --git a/cas/src/main/java/org/springframework/security/cas/web/TriggerCasGatewayFilter.java b/cas/src/main/java/org/springframework/security/cas/web/TriggerCasGatewayFilter.java
new file mode 100644
index 00000000000..b060a3d08c9
--- /dev/null
+++ b/cas/src/main/java/org/springframework/security/cas/web/TriggerCasGatewayFilter.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2013-2013 the original author or authors.
+ *
+ * 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 org.springframework.security.cas.web;
+
+import java.io.IOException;
+
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.springframework.security.cas.authentication.TriggerCasGatewayException;
+import org.springframework.security.web.util.RequestMatcher;
+import org.springframework.util.Assert;
+import org.springframework.web.filter.GenericFilterBean;
+
+/**
+ * Triggers a CAS gateway authentication attempt.
+ *
+ * This filter must be placed after the ExceptionTranslationFilter
in the filter chain in order to start
+ * the authentication process. Throws a {@link TriggerCasGatewayException} when the current request matches against the
+ * configured {@link RequestMatcher}.
+ *
+ * The default implementation you can use is {@link DefaultCasGatewayRequestMatcher}. + * + * @author Michael Remond + */ +public class TriggerCasGatewayFilter extends GenericFilterBean { + + // ~ Instance fields + // ================================================================================================ + + private RequestMatcher requestMatcher; + + // ~ Constructors + // =================================================================================================== + + public TriggerCasGatewayFilter(RequestMatcher requestMatcher) { + Assert.notNull(requestMatcher, "requestMatcher cannot be null"); + this.requestMatcher = requestMatcher; + } + + public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, + ServletException { + + HttpServletRequest request = (HttpServletRequest) req; + HttpServletResponse response = (HttpServletResponse) res; + + if (requestMatcher.matches(request)) { + throw new TriggerCasGatewayException("Try a CAS gateway authentication"); + } else { + // Continue in the chain + chain.doFilter(request, response); + } + + } + + public void setRequestMatcher(RequestMatcher requestMatcher) { + this.requestMatcher = requestMatcher; + } + +} diff --git a/cas/src/test/java/org/springframework/security/cas/web/CasAuthenticationEntryPointTests.java b/cas/src/test/java/org/springframework/security/cas/web/CasAuthenticationEntryPointTests.java index 5349fc4e944..153efcf6208 100644 --- a/cas/src/test/java/org/springframework/security/cas/web/CasAuthenticationEntryPointTests.java +++ b/cas/src/test/java/org/springframework/security/cas/web/CasAuthenticationEntryPointTests.java @@ -20,6 +20,7 @@ import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.security.cas.ServiceProperties; +import org.springframework.security.cas.authentication.TriggerCasGatewayException; import org.springframework.security.cas.web.CasAuthenticationEntryPoint; import java.net.URLEncoder; @@ -108,4 +109,46 @@ public void testNormalOperationWithRenewTrue() throws Exception { + URLEncoder.encode("https://mycompany.com/bigWebApp/j_spring_cas_security_check", "UTF-8") + "&renew=true", response.getRedirectedUrl()); } + + public void testNormalOperationWithRenewFalseAndGateway() throws Exception { + ServiceProperties sp = new ServiceProperties(); + sp.setSendRenew(false); + sp.setService("https://mycompany.com/bigWebApp/j_spring_cas_security_check"); + + CasAuthenticationEntryPoint ep = new CasAuthenticationEntryPoint(); + ep.setLoginUrl("https://cas/login"); + ep.setServiceProperties(sp); + + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setRequestURI("/some_path"); + + MockHttpServletResponse response = new MockHttpServletResponse(); + + ep.afterPropertiesSet(); + ep.commence(request, response, new TriggerCasGatewayException("")); + assertEquals("https://cas/login?service=" + + URLEncoder.encode("https://mycompany.com/bigWebApp/j_spring_cas_security_check", "UTF-8") + "&gateway=true", + response.getRedirectedUrl()); + } + + public void testNormalOperationWithRenewTrueAndGateway() throws Exception { + ServiceProperties sp = new ServiceProperties(); + sp.setSendRenew(true); + sp.setService("https://mycompany.com/bigWebApp/j_spring_cas_security_check"); + + CasAuthenticationEntryPoint ep = new CasAuthenticationEntryPoint(); + ep.setLoginUrl("https://cas/login"); + ep.setServiceProperties(sp); + + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setRequestURI("/some_path"); + + MockHttpServletResponse response = new MockHttpServletResponse(); + + ep.afterPropertiesSet(); + ep.commence(request, response, new TriggerCasGatewayException("")); + assertEquals("https://cas/login?service=" + + URLEncoder.encode("https://mycompany.com/bigWebApp/j_spring_cas_security_check", "UTF-8") + "&renew=true&gateway=true", + response.getRedirectedUrl()); + } } diff --git a/cas/src/test/java/org/springframework/security/cas/web/CasAuthenticationFilterTests.java b/cas/src/test/java/org/springframework/security/cas/web/CasAuthenticationFilterTests.java index f5967b33c9e..6fee2f43bba 100644 --- a/cas/src/test/java/org/springframework/security/cas/web/CasAuthenticationFilterTests.java +++ b/cas/src/test/java/org/springframework/security/cas/web/CasAuthenticationFilterTests.java @@ -19,9 +19,11 @@ import static org.mockito.Matchers.any; import static org.mockito.Mockito.*; +import java.io.IOException; import java.lang.reflect.Method; import javax.servlet.FilterChain; +import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -43,6 +45,7 @@ import org.springframework.security.web.authentication.AuthenticationFailureHandler; import org.springframework.security.web.authentication.AuthenticationSuccessHandler; import org.springframework.security.web.authentication.NullRememberMeServices; +import org.springframework.security.web.savedrequest.HttpSessionRequestCache; import org.springframework.util.ReflectionUtils; @@ -211,4 +214,30 @@ public void testChainNotInvokedForProxyReceptor() throws Exception { filter.doFilter(request,response,chain); verifyZeroInteractions(chain); } + + // SEC-977 + @Test + public void testCasGatewayWithNoSSOSession() throws IOException, ServletException { + HttpSessionRequestCache requestCache = new HttpSessionRequestCache(); + MockHttpServletRequest initialRequest = new MockHttpServletRequest("GET", "/some_path"); + requestCache.saveRequest(initialRequest, null); + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/j_spring_cas_security_check"); + request.setSession(initialRequest.getSession()); + MockHttpServletResponse response = new MockHttpServletResponse(); + FilterChain chain = mock(FilterChain.class); + + CasAuthenticationFilter filter = new CasAuthenticationFilter(); + filter.setProxyGrantingTicketStorage(mock(ProxyGrantingTicketStorage.class)); + filter.setAuthenticationManager(new AuthenticationManager() { + public Authentication authenticate(Authentication a) { + throw new BadCredentialsException("No ticket found"); + } + }); + + filter.doFilter(request,response,chain); + verify(chain, never()).doFilter(request, response); + assertEquals("Should redirect to saved url", "http://localhost/some_path", response.getRedirectedUrl()); + + } } \ No newline at end of file diff --git a/cas/src/test/java/org/springframework/security/cas/web/DefaultCasGatewayRequestMatcherTests.java b/cas/src/test/java/org/springframework/security/cas/web/DefaultCasGatewayRequestMatcherTests.java new file mode 100644 index 00000000000..5422f15dba2 --- /dev/null +++ b/cas/src/test/java/org/springframework/security/cas/web/DefaultCasGatewayRequestMatcherTests.java @@ -0,0 +1,74 @@ +package org.springframework.security.cas.web; + +import static org.junit.Assert.fail; +import static org.mockito.Mockito.mock; + +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; + +import junit.framework.Assert; + +import org.jasig.cas.client.authentication.DefaultGatewayResolverImpl; +import org.junit.Test; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.security.cas.ServiceProperties; +import org.springframework.security.cas.authentication.CasAuthenticationToken; +import org.springframework.security.core.context.SecurityContextHolder; + +public class DefaultCasGatewayRequestMatcherTests { + + @Test + public void testNullServiceProperties() throws Exception { + try { + new DefaultCasGatewayRequestMatcher(null); + fail("Should have thrown IllegalArgumentException"); + } catch (IllegalArgumentException expected) { + Assert.assertEquals("serviceProperties cannot be null", expected.getMessage()); + } + } + + @Test + public void testNormalOperationWithNoSSOSession() throws IOException, ServletException { + ServiceProperties serviceProperties = new ServiceProperties(); + serviceProperties.setService("http://localhost/j_spring_cas_security_check"); + DefaultCasGatewayRequestMatcher rm = new DefaultCasGatewayRequestMatcher(serviceProperties); + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/some_path"); + + // First request + Assert.assertTrue(rm.matches(request)); + Assert.assertNotNull(request.getSession(false).getAttribute(DefaultGatewayResolverImpl.CONST_CAS_GATEWAY)); + // Second request + Assert.assertFalse(rm.matches(request)); + Assert.assertNull(request.getSession(false).getAttribute(DefaultGatewayResolverImpl.CONST_CAS_GATEWAY)); + } + + @Test + public void testGatewayWhenAlreadyCasAuthenticated() throws IOException, ServletException { + SecurityContextHolder.getContext().setAuthentication(mock(CasAuthenticationToken.class)); + + ServiceProperties serviceProperties = new ServiceProperties(); + serviceProperties.setService("http://localhost/j_spring_cas_security_check"); + DefaultCasGatewayRequestMatcher rm = new DefaultCasGatewayRequestMatcher(serviceProperties); + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/some_path"); + + Assert.assertFalse(rm.matches(request)); + } + + @Test + public void testGatewayWithNoMatchingRequest() throws IOException, ServletException { + ServiceProperties serviceProperties = new ServiceProperties(); + serviceProperties.setService("http://localhost/j_spring_cas_security_check"); + DefaultCasGatewayRequestMatcher rm = new DefaultCasGatewayRequestMatcher(serviceProperties) { + @Override + protected boolean performGatewayAuthentication(HttpServletRequest request) { + return false; + } + }; + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/some_path"); + + Assert.assertFalse(rm.matches(request)); + } + +} diff --git a/cas/src/test/java/org/springframework/security/cas/web/TriggerCasGatewayFilterTests.java b/cas/src/test/java/org/springframework/security/cas/web/TriggerCasGatewayFilterTests.java new file mode 100644 index 00000000000..2720ae5e1f2 --- /dev/null +++ b/cas/src/test/java/org/springframework/security/cas/web/TriggerCasGatewayFilterTests.java @@ -0,0 +1,90 @@ +/* + * Copyright 2013-2013 the original author or authors. + * + * 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 org.springframework.security.cas.web; + +import static org.junit.Assert.fail; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyZeroInteractions; + +import java.io.IOException; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; + +import junit.framework.Assert; + +import org.junit.Test; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.security.cas.authentication.TriggerCasGatewayException; +import org.springframework.security.web.util.AnyRequestMatcher; +import org.springframework.security.web.util.RequestMatcher; + +/** + * Tests {@link TriggerCasGatewayFilter} + * + * @author Michael Remond + * + */ +public class TriggerCasGatewayFilterTests { + + @Test + public void testNullRequestMatcher() throws Exception { + try { + new TriggerCasGatewayFilter(null); + fail("Should have thrown IllegalArgumentException"); + } catch (IllegalArgumentException expected) { + Assert.assertEquals("requestMatcher cannot be null", expected.getMessage()); + } + } + + @Test + public void testGatewayWithMatchingRequest() throws IOException, ServletException { + TriggerCasGatewayFilter filter = new TriggerCasGatewayFilter(new AnyRequestMatcher()); + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/some_path"); + MockHttpServletResponse response = new MockHttpServletResponse(); + FilterChain chain = mock(FilterChain.class); + + try { + filter.doFilter(request, response, chain); + fail("should have throw an AuthenticationException"); + } catch (TriggerCasGatewayException expected) { + Assert.assertEquals("Try a CAS gateway authentication", expected.getMessage()); + } + verifyZeroInteractions(chain); + } + + @Test + public void testGatewayWithNoMatchingRequest() throws IOException, ServletException { + TriggerCasGatewayFilter filter = new TriggerCasGatewayFilter(new RequestMatcher() { + public boolean matches(HttpServletRequest request) { + return false; + } + }); + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/some_path"); + MockHttpServletResponse response = new MockHttpServletResponse(); + FilterChain chain = mock(FilterChain.class); + + filter.doFilter(request, response, chain); + verify(chain).doFilter(request, response); + } + +} diff --git a/cas/template.mf b/cas/template.mf index 0b20a5b55c3..80f2444238c 100644 --- a/cas/template.mf +++ b/cas/template.mf @@ -14,6 +14,7 @@ Import-Template: org.springframework.security.core.*;version="${secRange}", org.springframework.security.authentication.*;version="${secRange}", org.springframework.security.web.*;version="${secRange}", + org.springframework.web.filter.*;version="${springRange}", org.springframework.beans.factory;version="${springRange}", org.springframework.cache.*;version="${springRange}";resolution:=optional, org.springframework.context.*;version="${springRange}",