diff --git a/core/src/main/java/org/acegisecurity/providers/dao/event/AuthenticationSwitchUserEvent.java b/core/src/main/java/org/acegisecurity/providers/dao/event/AuthenticationSwitchUserEvent.java new file mode 100644 index 0000000000..f1b998883e --- /dev/null +++ b/core/src/main/java/org/acegisecurity/providers/dao/event/AuthenticationSwitchUserEvent.java @@ -0,0 +1,43 @@ +/* Copyright 2004, 2005 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 net.sf.acegisecurity.providers.dao.event; + +import net.sf.acegisecurity.Authentication; +import net.sf.acegisecurity.UserDetails; + + +/** + * Application event which indicates that a user context switch. + * + * @author Mark St.Godard + * @version $Id$ + */ +public class AuthenticationSwitchUserEvent extends AuthenticationEvent { + //~ Constructors =========================================================== + + /** + * Switch user context event constructor + * + * @param authentication The current Authentication object + * @param sourceUser The original user + * @param targetUser The target user + */ + public AuthenticationSwitchUserEvent(Authentication authentication, + UserDetails targetUser) { + super(authentication, targetUser); + } + +} diff --git a/core/src/main/java/org/acegisecurity/ui/switchuser/SwitchUserProcessingFilter.java b/core/src/main/java/org/acegisecurity/ui/switchuser/SwitchUserProcessingFilter.java index 8c1dfb452e..1f3ae8cd12 100644 --- a/core/src/main/java/org/acegisecurity/ui/switchuser/SwitchUserProcessingFilter.java +++ b/core/src/main/java/org/acegisecurity/ui/switchuser/SwitchUserProcessingFilter.java @@ -15,6 +15,20 @@ package net.sf.acegisecurity.ui.switchuser; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + import net.sf.acegisecurity.AccountExpiredException; import net.sf.acegisecurity.Authentication; import net.sf.acegisecurity.AuthenticationCredentialsNotFoundException; @@ -27,30 +41,17 @@ import net.sf.acegisecurity.context.SecurityContextHolder; import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken; import net.sf.acegisecurity.providers.dao.AuthenticationDao; import net.sf.acegisecurity.providers.dao.UsernameNotFoundException; +import net.sf.acegisecurity.providers.dao.event.AuthenticationSwitchUserEvent; import net.sf.acegisecurity.ui.WebAuthenticationDetails; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; - +import org.springframework.beans.BeansException; import org.springframework.beans.factory.InitializingBean; - +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; import org.springframework.util.Assert; -import java.io.IOException; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import javax.servlet.Filter; -import javax.servlet.FilterChain; -import javax.servlet.FilterConfig; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - /** * Switch User processing filter responsible for user context switching. @@ -104,7 +105,8 @@ import javax.servlet.http.HttpServletResponse; * * @see net.sf.acegisecurity.ui.switchuser.SwitchUserGrantedAuthority */ -public class SwitchUserProcessingFilter implements InitializingBean, Filter { +public class SwitchUserProcessingFilter implements Filter, InitializingBean, + ApplicationContextAware { //~ Static fields/initializers ============================================= private static final Log logger = LogFactory.getLog(SwitchUserProcessingFilter.class); @@ -112,19 +114,26 @@ public class SwitchUserProcessingFilter implements InitializingBean, Filter { // ~ Static fields/initializers // ============================================= public static final String ACEGI_SECURITY_SWITCH_USERNAME_KEY = "j_username"; - public static final String SWITCH_USER_GRANTED_AUTHORITY = "PREVIOUS_ADMINISTRATOR"; + public static final String ROLE_PREVIOUS_ADMINISTRATOR = "ROLE_PREVIOUS_ADMINISTRATOR"; //~ Instance fields ======================================================== + private ApplicationContext context; + // ~ Instance fields // ======================================================== private AuthenticationDao authenticationDao; - private String exitUserUrl; - private String switchUserUrl; + private String exitUserUrl = "/j_acegi_exit_user"; + private String switchUserUrl = "/j_acegi_switch_user"; private String targetUrl; //~ Methods ================================================================ + public void setApplicationContext(ApplicationContext context) + throws BeansException { + this.context = context; + } + /** * Sets the authentication data access object. * @@ -134,27 +143,6 @@ public class SwitchUserProcessingFilter implements InitializingBean, Filter { this.authenticationDao = authenticationDao; } - /** - * This filter by default responds to /j_acegi_exit_user. - * - * @return the default exit user url - */ - public String getDefaultExitUserUrl() { - return "/j_acegi_exit_user"; - } - - // ~ Methods - // ================================================================ - - /** - * This filter by default responds to /j_acegi_switch_user. - * - * @return the default switch user url - */ - public String getDefaultSwitchUserUrl() { - return "/j_acegi_switch_user"; - } - /** * Set the URL to respond to exit user processing. * @@ -196,13 +184,9 @@ public class SwitchUserProcessingFilter implements InitializingBean, Filter { */ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { - if (!(request instanceof HttpServletRequest)) { - throw new ServletException("Can only process HttpServletRequest"); - } - - if (!(response instanceof HttpServletResponse)) { - throw new ServletException("Can only process HttpServletResponse"); - } + + Assert.isInstanceOf(HttpServletRequest.class,request); + Assert.isInstanceOf(HttpServletResponse.class,response); HttpServletRequest httpRequest = (HttpServletRequest) request; HttpServletResponse httpResponse = (HttpServletResponse) response; @@ -214,7 +198,7 @@ public class SwitchUserProcessingFilter implements InitializingBean, Filter { // update the current context to the new target user SecurityContextHolder.getContext().setAuthentication(targetUser); - + // redirect to target url httpResponse.sendRedirect(httpResponse.encodeRedirectURL(targetUrl)); @@ -268,6 +252,12 @@ public class SwitchUserProcessingFilter implements InitializingBean, Filter { throw new AuthenticationCredentialsNotFoundException( "Could not find original Authentication object!"); } + + // TODO: fix target user on exit + if (this.context != null) { + context.publishEvent(new AuthenticationSwitchUserEvent( + current, null) ); + } return original; } @@ -333,6 +323,13 @@ public class SwitchUserProcessingFilter implements InitializingBean, Filter { logger.debug("Switch User Token [" + targetUserRequest + "]"); } + // publish event + if (this.context != null) { + context.publishEvent(new AuthenticationSwitchUserEvent( + SecurityContextHolder.getContext().getAuthentication(), + targetUser) ); + } + return targetUserRequest; } @@ -437,7 +434,7 @@ public class SwitchUserProcessingFilter implements InitializingBean, Filter { // which will be used to 'exit' from the current switched user. Authentication currentAuth = SecurityContextHolder.getContext() .getAuthentication(); - GrantedAuthority switchAuthority = new SwitchUserGrantedAuthority(SWITCH_USER_GRANTED_AUTHORITY, + GrantedAuthority switchAuthority = new SwitchUserGrantedAuthority(ROLE_PREVIOUS_ADMINISTRATOR, currentAuth); // get the original authorities diff --git a/core/src/test/java/org/acegisecurity/providers/dao/event/AuthenticationEventTests.java b/core/src/test/java/org/acegisecurity/providers/dao/event/AuthenticationEventTests.java index be4e52e8ff..0c1653ca2d 100644 --- a/core/src/test/java/org/acegisecurity/providers/dao/event/AuthenticationEventTests.java +++ b/core/src/test/java/org/acegisecurity/providers/dao/event/AuthenticationEventTests.java @@ -22,6 +22,7 @@ import net.sf.acegisecurity.GrantedAuthority; import net.sf.acegisecurity.GrantedAuthorityImpl; import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken; import net.sf.acegisecurity.providers.dao.User; +import net.sf.acegisecurity.ui.switchuser.SwitchUserGrantedAuthority; /** @@ -88,6 +89,16 @@ public class AuthenticationEventTests extends TestCase { assertEquals(user, event.getUser()); } + public void testSwitchUserContextEvent() { + Authentication auth = getAuthentication(); + User targetUser = getUser(); + + AuthenticationSwitchUserEvent event = new AuthenticationSwitchUserEvent(auth, + targetUser); + assertEquals(auth, event.getAuthentication()); + assertEquals(targetUser, event.getUser()); + } + private Authentication getAuthentication() { UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken("Principal", "Credentials"); diff --git a/core/src/test/java/org/acegisecurity/ui/switchuser/SwitchUserProcessingFilterTests.java b/core/src/test/java/org/acegisecurity/ui/switchuser/SwitchUserProcessingFilterTests.java index 11bc2b14e6..febdea1bfa 100644 --- a/core/src/test/java/org/acegisecurity/ui/switchuser/SwitchUserProcessingFilterTests.java +++ b/core/src/test/java/org/acegisecurity/ui/switchuser/SwitchUserProcessingFilterTests.java @@ -16,7 +16,6 @@ package net.sf.acegisecurity.ui.switchuser; import junit.framework.TestCase; - import net.sf.acegisecurity.AccountExpiredException; import net.sf.acegisecurity.Authentication; import net.sf.acegisecurity.AuthenticationException; @@ -33,7 +32,6 @@ import net.sf.acegisecurity.providers.dao.UsernameNotFoundException; import net.sf.acegisecurity.util.MockFilterChain; import org.springframework.dao.DataAccessException; - import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; @@ -191,34 +189,6 @@ public class SwitchUserProcessingFilterTests extends TestCase { } } - public void testBadConfigMissingExitUserUrl() { - SwitchUserProcessingFilter filter = new SwitchUserProcessingFilter(); - filter.setAuthenticationDao(new MockAuthenticationDaoUserJackLord()); - filter.setSwitchUserUrl("/j_acegi_switch_user"); - filter.setTargetUrl("/main.jsp"); - - try { - filter.afterPropertiesSet(); - fail("Expect to fail due to missing 'exitUserUrl'"); - } catch (Exception expected) { - // expected exception - } - } - - public void testBadConfigMissingSwitchUserUrl() { - SwitchUserProcessingFilter filter = new SwitchUserProcessingFilter(); - filter.setAuthenticationDao(new MockAuthenticationDaoUserJackLord()); - filter.setExitUserUrl("/j_acegi_exit_user"); - filter.setTargetUrl("/main.jsp"); - - try { - filter.afterPropertiesSet(); - fail("Expect to fail due to missing 'switchUserUrl'"); - } catch (Exception expected) { - // expected exception - } - } - public void testBadConfigMissingTargetUrl() { SwitchUserProcessingFilter filter = new SwitchUserProcessingFilter(); filter.setAuthenticationDao(new MockAuthenticationDaoUserJackLord()); @@ -233,11 +203,6 @@ public class SwitchUserProcessingFilterTests extends TestCase { } } - public void testDefaultExitProcessUrl() { - SwitchUserProcessingFilter filter = new SwitchUserProcessingFilter(); - assertEquals("/j_acegi_exit_user", filter.getDefaultExitUserUrl()); - } - public void testDefaultProcessesFilterUrlWithPathParameter() { MockHttpServletRequest request = createMockSwitchRequest(); SwitchUserProcessingFilter filter = new SwitchUserProcessingFilter(); @@ -248,11 +213,6 @@ public class SwitchUserProcessingFilterTests extends TestCase { assertTrue(filter.requiresSwitchUser(request)); } - public void testDefaultSwitchProcessUrl() { - SwitchUserProcessingFilter filter = new SwitchUserProcessingFilter(); - assertEquals("/j_acegi_switch_user", filter.getDefaultSwitchUserUrl()); - } - public void testExitRequestUserJackLordToDano() throws Exception { // original user GrantedAuthority[] auths = {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl(