diff --git a/web/src/main/java/org/springframework/security/web/authentication/AbstractAuthenticationProcessingFilter.java b/web/src/main/java/org/springframework/security/web/authentication/AbstractAuthenticationProcessingFilter.java index a2db4907817..b1cda2e04de 100644 --- a/web/src/main/java/org/springframework/security/web/authentication/AbstractAuthenticationProcessingFilter.java +++ b/web/src/main/java/org/springframework/security/web/authentication/AbstractAuthenticationProcessingFilter.java @@ -198,6 +198,9 @@ public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) return; } sessionStrategy.onAuthentication(authResult, request, response); + } catch (AuthenticationRedirectException e) { + response.sendRedirect(e.getRedirectUrl()); + return; } catch(InternalAuthenticationServiceException failed) { logger.error("An internal error occurred while trying to authenticate the user.", failed); unsuccessfulAuthentication(request, response, failed); diff --git a/web/src/main/java/org/springframework/security/web/authentication/AuthenticationRedirectException.java b/web/src/main/java/org/springframework/security/web/authentication/AuthenticationRedirectException.java new file mode 100644 index 00000000000..f1ba3a61586 --- /dev/null +++ b/web/src/main/java/org/springframework/security/web/authentication/AuthenticationRedirectException.java @@ -0,0 +1,47 @@ +/* Copyright 2004, 2005, 2006 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. + * 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.web.authentication; + +import java.net.URL; + +import org.springframework.security.core.AuthenticationException; + +/** + * Indicates the need to perform a redirect in the course of authentication, for example with a social OAuth + * service provider. + * + * @author Stefan Fussenegger + * @author Yuan Ji + * + */ +@SuppressWarnings("serial") +public class AuthenticationRedirectException extends AuthenticationException{ + private final String redirectUrl; + + public AuthenticationRedirectException(URL redirectUrl) { + this(redirectUrl.toString()); + } + + public AuthenticationRedirectException(String redirectUrl) { + super(""); + this.redirectUrl = redirectUrl; + } + + public String getRedirectUrl() { + return redirectUrl; + } + +} diff --git a/web/src/test/java/org/springframework/security/web/authentication/AbstractAuthenticationProcessingFilterTests.java b/web/src/test/java/org/springframework/security/web/authentication/AbstractAuthenticationProcessingFilterTests.java index 21be453b4e5..128e97db9d4 100644 --- a/web/src/test/java/org/springframework/security/web/authentication/AbstractAuthenticationProcessingFilterTests.java +++ b/web/src/test/java/org/springframework/security/web/authentication/AbstractAuthenticationProcessingFilterTests.java @@ -379,6 +379,23 @@ public void loginErrorWithInternAuthenticationServiceExceptionLogsError() throws assertEquals(HttpServletResponse.SC_UNAUTHORIZED, response.getStatus()); } + @Test + public void handleRedirect() throws Exception { + String redirectUrl = "www.example.com/redirect"; + + MockHttpServletRequest request = createMockAuthenticationRequest(); + + MockFilterChain chain = new MockFilterChain(true); + MockHttpServletResponse response = new MockHttpServletResponse(); + + MockAuthenticationFilter filter = new MockAuthenticationFilter(false); + filter.exceptionToThrow = new AuthenticationRedirectException(redirectUrl); + + filter.doFilter(request, response, chain); + + assertEquals(redirectUrl, response.getRedirectedUrl()); + + } //~ Inner Classes ================================================================================================== private class MockAuthenticationFilter extends AbstractAuthenticationProcessingFilter {