4 changed files with 969 additions and 0 deletions
@ -0,0 +1,59 @@
@@ -0,0 +1,59 @@
|
||||
/* 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.ui.switchuser; |
||||
|
||||
import net.sf.acegisecurity.Authentication; |
||||
import net.sf.acegisecurity.GrantedAuthorityImpl; |
||||
|
||||
|
||||
/** |
||||
* Custom <code>GrantedAuthority</code> used by {@link |
||||
* net.sf.acegisecurity.ui.switchuser.SwitchUserProcessingFilter} |
||||
* |
||||
* <p> |
||||
* Stores the <code>Authentication</code> object of the original user to be |
||||
* used later when 'exiting' from a user switch. |
||||
* </p> |
||||
* |
||||
* @author Mark St.Godard |
||||
* @version $Id$ |
||||
* |
||||
* @see net.sf.acegisecurity.ui.switchuser.SwitchUserProcessingFilter |
||||
*/ |
||||
public class SwitchUserGrantedAuthority extends GrantedAuthorityImpl { |
||||
//~ Instance fields ========================================================
|
||||
|
||||
private Authentication source; |
||||
|
||||
//~ Constructors ===========================================================
|
||||
|
||||
public SwitchUserGrantedAuthority(String role, Authentication source) { |
||||
super(role); |
||||
this.source = source; |
||||
} |
||||
|
||||
//~ Methods ================================================================
|
||||
|
||||
/** |
||||
* Returns the original user associated with a successful user switch. |
||||
* |
||||
* @return The original <code>Authentication</code> object of the switched |
||||
* user. |
||||
*/ |
||||
public Authentication getSource() { |
||||
return source; |
||||
} |
||||
} |
||||
@ -0,0 +1,462 @@
@@ -0,0 +1,462 @@
|
||||
/* 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.ui.switchuser; |
||||
|
||||
import net.sf.acegisecurity.AccountExpiredException; |
||||
import net.sf.acegisecurity.Authentication; |
||||
import net.sf.acegisecurity.AuthenticationCredentialsNotFoundException; |
||||
import net.sf.acegisecurity.AuthenticationException; |
||||
import net.sf.acegisecurity.CredentialsExpiredException; |
||||
import net.sf.acegisecurity.DisabledException; |
||||
import net.sf.acegisecurity.GrantedAuthority; |
||||
import net.sf.acegisecurity.UserDetails; |
||||
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.ui.WebAuthenticationDetails; |
||||
|
||||
import org.apache.commons.logging.Log; |
||||
import org.apache.commons.logging.LogFactory; |
||||
|
||||
import org.springframework.beans.factory.InitializingBean; |
||||
|
||||
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. |
||||
* |
||||
* <p> |
||||
* This filter is similar to Unix 'su' however for Acegi-managed web |
||||
* applications. A common use-case for this feature is the ability to allow |
||||
* higher-authority users (i.e. ROLE_ADMIN) to switch to a regular user (i.e. |
||||
* ROLE_USER). |
||||
* </p> |
||||
* |
||||
* <p> |
||||
* This filter assumes that the user performing the switch will be required to |
||||
* be logged in as normal (i.e. ROLE_ADMIN user). The user will then access a |
||||
* page/controller that enables the administrator to specify who they wish to |
||||
* become (see <code>switchUserUrl</code>). <br> |
||||
* <b>Note: This URL will be required to have to appropriate security |
||||
* contraints configured so that only users of that role can access (i.e. |
||||
* ROLE_ADMIN).</b> |
||||
* </p> |
||||
* |
||||
* <p> |
||||
* On successful switch, the user's <code>SecureContextHolder</code> will be |
||||
* updated to reflect the specified user and will also contain an additinal |
||||
* {@link net.sf.acegisecurity.ui.switchuser.SwitchUserGrantedAuthority } |
||||
* which contains the original user. |
||||
* </p> |
||||
* |
||||
* <p> |
||||
* To 'exit' from a user context, the user will then need to access a URL (see |
||||
* <code>exitUserUrl</code>) that will switch back to the original user as |
||||
* identified by the <code>SWITCH_USER_GRANTED_AUTHORITY</code>. |
||||
* </p> |
||||
* |
||||
* <p> |
||||
* To configure the Switch User Processing Filter, create a bean definition for |
||||
* the Switch User processing filter and add to the filterChainProxy. <br> |
||||
* Example: |
||||
* <pre> |
||||
* <bean id="switchUserProcessingFilter" class="net.sf.acegisecurity.ui.switchuser.SwitchUserProcessingFilter"> |
||||
* <property name="authenticationDao" ref="jdbcDaoImpl" /> |
||||
* <property name="switchUserUrl"><value>/j_acegi_switch_user</value></property> |
||||
* <property name="exitUserUrl"><value>/j_acegi_exit_user</value></property> |
||||
* <property name="targetUrl"><value>/index.jsp</value></property> |
||||
* </bean> |
||||
* </pre> |
||||
* </p> |
||||
* |
||||
* @author Mark St.Godard |
||||
* @version $Id$ |
||||
* |
||||
* @see net.sf.acegisecurity.ui.switchuser.SwitchUserGrantedAuthority |
||||
*/ |
||||
public class SwitchUserProcessingFilter implements InitializingBean, Filter { |
||||
//~ Static fields/initializers =============================================
|
||||
|
||||
private static final Log logger = LogFactory.getLog(SwitchUserProcessingFilter.class); |
||||
|
||||
// ~ Static fields/initializers
|
||||
// =============================================
|
||||
public static final String ACEGI_SECURITY_SWITCH_USERNAME_KEY = "j_username"; |
||||
public static final String SWITCH_USER_GRANTED_AUTHORITY = "PREVIOUS_ADMINISTRATOR"; |
||||
|
||||
//~ Instance fields ========================================================
|
||||
|
||||
// ~ Instance fields
|
||||
// ========================================================
|
||||
private AuthenticationDao authenticationDao; |
||||
private String exitUserUrl; |
||||
private String switchUserUrl; |
||||
private String targetUrl; |
||||
|
||||
//~ Methods ================================================================
|
||||
|
||||
/** |
||||
* Sets the authentication data access object. |
||||
* |
||||
* @param authenticationDao The authentication dao |
||||
*/ |
||||
public void setAuthenticationDao(AuthenticationDao authenticationDao) { |
||||
this.authenticationDao = authenticationDao; |
||||
} |
||||
|
||||
/** |
||||
* This filter by default responds to <code>/j_acegi_exit_user</code>. |
||||
* |
||||
* @return the default exit user url |
||||
*/ |
||||
public String getDefaultExitUserUrl() { |
||||
return "/j_acegi_exit_user"; |
||||
} |
||||
|
||||
// ~ Methods
|
||||
// ================================================================
|
||||
|
||||
/** |
||||
* This filter by default responds to <code>/j_acegi_switch_user</code>. |
||||
* |
||||
* @return the default switch user url |
||||
*/ |
||||
public String getDefaultSwitchUserUrl() { |
||||
return "/j_acegi_switch_user"; |
||||
} |
||||
|
||||
/** |
||||
* Set the URL to respond to exit user processing. |
||||
* |
||||
* @param exitUserUrl The exit user URL. |
||||
*/ |
||||
public void setExitUserUrl(String exitUserUrl) { |
||||
this.exitUserUrl = exitUserUrl; |
||||
} |
||||
|
||||
/** |
||||
* Set the URL to respond to switch user processing. |
||||
* |
||||
* @param switchUserUrl The switch user URL. |
||||
*/ |
||||
public void setSwitchUserUrl(String switchUserUrl) { |
||||
this.switchUserUrl = switchUserUrl; |
||||
} |
||||
|
||||
/** |
||||
* Sets the URL to go to after a successful switch / exit user request. |
||||
* |
||||
* @param targetUrl The target url. |
||||
*/ |
||||
public void setTargetUrl(String targetUrl) { |
||||
this.targetUrl = targetUrl; |
||||
} |
||||
|
||||
public void afterPropertiesSet() throws Exception { |
||||
Assert.hasLength(switchUserUrl, "switchUserUrl must be specified"); |
||||
Assert.hasLength(exitUserUrl, "exitUserUrl must be specified"); |
||||
Assert.hasLength(targetUrl, "targetUrl must be specified"); |
||||
Assert.notNull(authenticationDao, "authenticationDao must be specified"); |
||||
} |
||||
|
||||
public void destroy() {} |
||||
|
||||
/** |
||||
* @see javax.servlet.Filter#doFilter |
||||
*/ |
||||
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"); |
||||
} |
||||
|
||||
HttpServletRequest httpRequest = (HttpServletRequest) request; |
||||
HttpServletResponse httpResponse = (HttpServletResponse) response; |
||||
|
||||
// check for switch or exit request
|
||||
if (requiresSwitchUser(httpRequest)) { |
||||
// if set, attempt switch and store original
|
||||
Authentication targetUser = attemptSwitchUser(httpRequest); |
||||
|
||||
// update the current context to the new target user
|
||||
SecurityContextHolder.getContext().setAuthentication(targetUser); |
||||
|
||||
// redirect to target url
|
||||
httpResponse.sendRedirect(httpResponse.encodeRedirectURL(targetUrl)); |
||||
|
||||
return; |
||||
} else if (requiresExitUser(httpRequest)) { |
||||
// get the original authentication object (if exists)
|
||||
Authentication originalUser = attemptExitUser(httpRequest); |
||||
|
||||
// update the current context back to the original user
|
||||
SecurityContextHolder.getContext().setAuthentication(originalUser); |
||||
|
||||
// redirect to target url
|
||||
httpResponse.sendRedirect(httpResponse.encodeRedirectURL(targetUrl)); |
||||
|
||||
return; |
||||
} |
||||
|
||||
chain.doFilter(request, response); |
||||
} |
||||
|
||||
public void init(FilterConfig filterConfig) throws ServletException {} |
||||
|
||||
/** |
||||
* Attempt to exit from an already switched user. |
||||
* |
||||
* @param request The http servlet request |
||||
* |
||||
* @return The original <code>Authentication</code> object or |
||||
* <code>null</code> otherwise. |
||||
* |
||||
* @throws AuthenticationCredentialsNotFoundException If no |
||||
* <code>Authentication</code> associated with this request. |
||||
*/ |
||||
protected Authentication attemptExitUser(HttpServletRequest request) |
||||
throws AuthenticationCredentialsNotFoundException { |
||||
// need to check to see if the current user has a SwitchUserGrantedAuthority
|
||||
Authentication current = SecurityContextHolder.getContext() |
||||
.getAuthentication(); |
||||
|
||||
if (null == current) { |
||||
throw new AuthenticationCredentialsNotFoundException( |
||||
"No current user associated with this request!"); |
||||
} |
||||
|
||||
// check to see if the current user did actual switch to another user
|
||||
// if so, get the original source user so we can switch back
|
||||
Authentication original = getSourceAuthentication(current); |
||||
|
||||
if (original == null) { |
||||
logger.error("Could not find original user Authentication object!"); |
||||
throw new AuthenticationCredentialsNotFoundException( |
||||
"Could not find original Authentication object!"); |
||||
} |
||||
|
||||
return original; |
||||
} |
||||
|
||||
/** |
||||
* Attempt to switch to another user. If the user does not exist or is not |
||||
* active, return null. |
||||
* |
||||
* @param request The http request |
||||
* |
||||
* @return The new <code>Authentication</code> request if successfully |
||||
* switched to another user, <code>null</code> otherwise. |
||||
* |
||||
* @throws AuthenticationException |
||||
* @throws UsernameNotFoundException If the target user is not found. |
||||
* @throws DisabledException If the target user is disabled. |
||||
* @throws AccountExpiredException If the target user account is expired. |
||||
* @throws CredentialsExpiredException If the target user credentials are |
||||
* expired. |
||||
*/ |
||||
protected Authentication attemptSwitchUser(HttpServletRequest request) |
||||
throws AuthenticationException { |
||||
UsernamePasswordAuthenticationToken targetUserRequest = null; |
||||
|
||||
String username = request.getParameter(ACEGI_SECURITY_SWITCH_USERNAME_KEY); |
||||
|
||||
if (username == null) { |
||||
username = ""; |
||||
} |
||||
|
||||
if (logger.isDebugEnabled()) { |
||||
logger.debug("Attempt to switch to user [" + username + "]"); |
||||
} |
||||
|
||||
// load the user by name
|
||||
UserDetails targetUser = this.authenticationDao.loadUserByUsername(username); |
||||
|
||||
// user not found
|
||||
if (targetUser == null) { |
||||
throw new UsernameNotFoundException("User [" + username |
||||
+ "] cannot be found!"); |
||||
} |
||||
|
||||
// user is disabled
|
||||
if (!targetUser.isEnabled()) { |
||||
throw new DisabledException("User is disabled"); |
||||
} |
||||
|
||||
// account is expired
|
||||
if (!targetUser.isAccountNonExpired()) { |
||||
throw new AccountExpiredException("User account has expired"); |
||||
} |
||||
|
||||
// credentials expired
|
||||
if (!targetUser.isCredentialsNonExpired()) { |
||||
throw new CredentialsExpiredException("User credentials expired"); |
||||
} |
||||
|
||||
// ok, create the switch user token
|
||||
targetUserRequest = createSwitchUserToken(request, username, targetUser); |
||||
|
||||
if (logger.isDebugEnabled()) { |
||||
logger.debug("Switch User Token [" + targetUserRequest + "]"); |
||||
} |
||||
|
||||
return targetUserRequest; |
||||
} |
||||
|
||||
/** |
||||
* Checks the request URI for the presence of <tt>exitUserUrl</tt>. |
||||
* |
||||
* @param request The http servlet request |
||||
* |
||||
* @return <code>true</code> if the request requires a exit user, |
||||
* <code>false</code> otherwise. |
||||
* |
||||
* @see SwitchUserProcessingFilter#exitUserUrl |
||||
*/ |
||||
protected boolean requiresExitUser(HttpServletRequest request) { |
||||
String uri = stripUri(request); |
||||
|
||||
return uri.endsWith(request.getContextPath() + exitUserUrl); |
||||
} |
||||
|
||||
/** |
||||
* Checks the request URI for the presence of <tt>switchUserUrl</tt>. |
||||
* |
||||
* @param request The http servlet request |
||||
* |
||||
* @return <code>true</code> if the request requires a switch, |
||||
* <code>false</code> otherwise. |
||||
* |
||||
* @see SwitchUserProcessingFilter#switchUserUrl |
||||
*/ |
||||
protected boolean requiresSwitchUser(HttpServletRequest request) { |
||||
String uri = stripUri(request); |
||||
|
||||
return uri.endsWith(request.getContextPath() + switchUserUrl); |
||||
} |
||||
|
||||
/** |
||||
* Strips any content after the ';' in the request URI |
||||
* |
||||
* @param request The http request |
||||
* |
||||
* @return The stripped uri |
||||
*/ |
||||
private static String stripUri(HttpServletRequest request) { |
||||
String uri = request.getRequestURI(); |
||||
int idx = uri.indexOf(';'); |
||||
|
||||
if (idx > 0) { |
||||
uri = uri.substring(0, idx); |
||||
} |
||||
|
||||
return uri; |
||||
} |
||||
|
||||
/** |
||||
* Find the original <code>Authentication</code> object from the current |
||||
* user's granted authorities. A successfully switched user should have a |
||||
* <code>SwitchUserGrantedAuthority</code> that contains the original |
||||
* source user <code>Authentication</code> object. |
||||
* |
||||
* @param current The current <code>Authentication</code> object |
||||
* |
||||
* @return The source user <code>Authentication</code> object or |
||||
* <code>null</code> otherwise. |
||||
*/ |
||||
private Authentication getSourceAuthentication(Authentication current) { |
||||
Authentication original = null; |
||||
|
||||
// iterate over granted authorities and find the 'switch user' authority
|
||||
GrantedAuthority[] authorities = current.getAuthorities(); |
||||
|
||||
for (int i = 0; i < authorities.length; i++) { |
||||
// check for switch user type of authority
|
||||
if (authorities[i] instanceof SwitchUserGrantedAuthority) { |
||||
original = ((SwitchUserGrantedAuthority) authorities[i]) |
||||
.getSource(); |
||||
logger.debug("Found original switch user granted authority [" |
||||
+ original + "]"); |
||||
} |
||||
} |
||||
|
||||
return original; |
||||
} |
||||
|
||||
/** |
||||
* Create a switch user token that contains an additional |
||||
* <tt>GrantedAuthority</tt> that contains the original |
||||
* <code>Authentication</code> object. |
||||
* |
||||
* @param request The http servlet request. |
||||
* @param username The username of target user |
||||
* @param targetUser The target user |
||||
* |
||||
* @return The authentication token |
||||
* |
||||
* @see SwitchUserGrantedAuthority |
||||
*/ |
||||
private UsernamePasswordAuthenticationToken createSwitchUserToken( |
||||
HttpServletRequest request, String username, UserDetails targetUser) { |
||||
UsernamePasswordAuthenticationToken targetUserRequest; |
||||
|
||||
// grant an additional authority that contains the original Authentication object
|
||||
// which will be used to 'exit' from the current switched user.
|
||||
Authentication currentAuth = SecurityContextHolder.getContext() |
||||
.getAuthentication(); |
||||
GrantedAuthority switchAuthority = new SwitchUserGrantedAuthority(SWITCH_USER_GRANTED_AUTHORITY, |
||||
currentAuth); |
||||
|
||||
// get the original authorities
|
||||
List orig = Arrays.asList(targetUser.getAuthorities()); |
||||
|
||||
// add the new switch user authority
|
||||
List newAuths = new ArrayList(orig); |
||||
newAuths.add(switchAuthority); |
||||
|
||||
GrantedAuthority[] authorities = {}; |
||||
authorities = (GrantedAuthority[]) newAuths.toArray(authorities); |
||||
|
||||
// create the new authentication token
|
||||
targetUserRequest = new UsernamePasswordAuthenticationToken(username, |
||||
targetUser.getPassword(), authorities); |
||||
|
||||
// set details
|
||||
targetUserRequest.setDetails(new WebAuthenticationDetails(request)); |
||||
|
||||
return targetUserRequest; |
||||
} |
||||
} |
||||
@ -0,0 +1,447 @@
@@ -0,0 +1,447 @@
|
||||
/* 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.ui.switchuser; |
||||
|
||||
import junit.framework.TestCase; |
||||
|
||||
import net.sf.acegisecurity.AccountExpiredException; |
||||
import net.sf.acegisecurity.Authentication; |
||||
import net.sf.acegisecurity.AuthenticationException; |
||||
import net.sf.acegisecurity.CredentialsExpiredException; |
||||
import net.sf.acegisecurity.DisabledException; |
||||
import net.sf.acegisecurity.GrantedAuthority; |
||||
import net.sf.acegisecurity.GrantedAuthorityImpl; |
||||
import net.sf.acegisecurity.UserDetails; |
||||
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.User; |
||||
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; |
||||
|
||||
|
||||
/** |
||||
* Tests {@link net.sf.acegisecurity.ui.switchuser.SwitchUserProcessingFilter}. |
||||
* |
||||
* @author Mark St.Godard |
||||
* @version $Id$ |
||||
*/ |
||||
public class SwitchUserProcessingFilterTests extends TestCase { |
||||
//~ Constructors ===========================================================
|
||||
|
||||
public SwitchUserProcessingFilterTests() { |
||||
super(); |
||||
} |
||||
|
||||
public SwitchUserProcessingFilterTests(String arg0) { |
||||
super(arg0); |
||||
} |
||||
|
||||
//~ Methods ================================================================
|
||||
|
||||
public final void setUp() throws Exception { |
||||
super.setUp(); |
||||
} |
||||
|
||||
public static void main(String[] args) { |
||||
junit.textui.TestRunner.run(SwitchUserProcessingFilterTests.class); |
||||
} |
||||
|
||||
public void testAttemptSwitchToUnknownUser() throws Exception { |
||||
// set current user
|
||||
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken("dano", |
||||
"hawaii50"); |
||||
SecurityContextHolder.getContext().setAuthentication(auth); |
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest(); |
||||
request.addParameter(SwitchUserProcessingFilter.ACEGI_SECURITY_SWITCH_USERNAME_KEY, |
||||
"user-that-doesnt-exist"); |
||||
|
||||
SwitchUserProcessingFilter filter = new SwitchUserProcessingFilter(); |
||||
filter.setAuthenticationDao(new MockAuthenticationDaoUserJackLord()); |
||||
|
||||
try { |
||||
Authentication result = filter.attemptSwitchUser(request); |
||||
|
||||
fail("Should not be able to switch to unknown user"); |
||||
} catch (UsernameNotFoundException expected) {} |
||||
} |
||||
|
||||
public void testAttemptSwitchToUserThatIsDisabled() |
||||
throws Exception { |
||||
// set current user
|
||||
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken("dano", |
||||
"hawaii50"); |
||||
SecurityContextHolder.getContext().setAuthentication(auth); |
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest(); |
||||
|
||||
// this user is disabled
|
||||
request.addParameter(SwitchUserProcessingFilter.ACEGI_SECURITY_SWITCH_USERNAME_KEY, |
||||
"mcgarrett"); |
||||
|
||||
SwitchUserProcessingFilter filter = new SwitchUserProcessingFilter(); |
||||
filter.setAuthenticationDao(new MockAuthenticationDaoUserJackLord()); |
||||
|
||||
try { |
||||
Authentication result = filter.attemptSwitchUser(request); |
||||
|
||||
fail("Should not be able to switch to disabled user"); |
||||
} catch (DisabledException expected) { |
||||
// user should be disabled
|
||||
} |
||||
} |
||||
|
||||
public void testAttemptSwitchToUserWithAccountExpired() |
||||
throws Exception { |
||||
// set current user
|
||||
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken("dano", |
||||
"hawaii50"); |
||||
SecurityContextHolder.getContext().setAuthentication(auth); |
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest(); |
||||
|
||||
// this user is disabled
|
||||
request.addParameter(SwitchUserProcessingFilter.ACEGI_SECURITY_SWITCH_USERNAME_KEY, |
||||
"wofat"); |
||||
|
||||
SwitchUserProcessingFilter filter = new SwitchUserProcessingFilter(); |
||||
filter.setAuthenticationDao(new MockAuthenticationDaoUserJackLord()); |
||||
|
||||
try { |
||||
Authentication result = filter.attemptSwitchUser(request); |
||||
|
||||
fail("Should not be able to switch to user with expired account"); |
||||
} catch (AccountExpiredException expected) { |
||||
// expected user account expired
|
||||
} |
||||
} |
||||
|
||||
public void testAttemptSwitchToUserWithExpiredCredentials() |
||||
throws Exception { |
||||
// set current user
|
||||
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken("dano", |
||||
"hawaii50"); |
||||
SecurityContextHolder.getContext().setAuthentication(auth); |
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest(); |
||||
|
||||
// this user is disabled
|
||||
request.addParameter(SwitchUserProcessingFilter.ACEGI_SECURITY_SWITCH_USERNAME_KEY, |
||||
"steve"); |
||||
|
||||
SwitchUserProcessingFilter filter = new SwitchUserProcessingFilter(); |
||||
filter.setAuthenticationDao(new MockAuthenticationDaoUserJackLord()); |
||||
|
||||
try { |
||||
Authentication result = filter.attemptSwitchUser(request); |
||||
|
||||
fail("Should not be able to switch to user with expired account"); |
||||
} catch (CredentialsExpiredException expected) { |
||||
// user credentials expired
|
||||
} |
||||
} |
||||
|
||||
public void testAttemptSwitchUser() throws Exception { |
||||
// set current user
|
||||
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken("dano", |
||||
"hawaii50"); |
||||
SecurityContextHolder.getContext().setAuthentication(auth); |
||||
|
||||
MockHttpServletRequest request = new MockHttpServletRequest(); |
||||
request.addParameter(SwitchUserProcessingFilter.ACEGI_SECURITY_SWITCH_USERNAME_KEY, |
||||
"jacklord"); |
||||
|
||||
SwitchUserProcessingFilter filter = new SwitchUserProcessingFilter(); |
||||
filter.setAuthenticationDao(new MockAuthenticationDaoUserJackLord()); |
||||
|
||||
Authentication result = filter.attemptSwitchUser(request); |
||||
assertTrue(result != null); |
||||
} |
||||
|
||||
public void testBadConfigMissingAuthenticationDao() { |
||||
SwitchUserProcessingFilter filter = new SwitchUserProcessingFilter(); |
||||
filter.setSwitchUserUrl("/j_acegi_switch_user"); |
||||
filter.setExitUserUrl("/j_acegi_exit_user"); |
||||
filter.setTargetUrl("/main.jsp"); |
||||
|
||||
try { |
||||
filter.afterPropertiesSet(); |
||||
fail("Expect to fail due to missing 'authenticationDao'"); |
||||
} catch (Exception expected) { |
||||
// expected exception
|
||||
} |
||||
} |
||||
|
||||
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()); |
||||
filter.setSwitchUserUrl("/j_acegi_switch_user"); |
||||
filter.setExitUserUrl("/j_acegi_exit_user"); |
||||
|
||||
try { |
||||
filter.afterPropertiesSet(); |
||||
fail("Expect to fail due to missing 'targetUrl'"); |
||||
} catch (Exception expected) { |
||||
// expected exception
|
||||
} |
||||
} |
||||
|
||||
public void testDefaultExitProcessUrl() { |
||||
SwitchUserProcessingFilter filter = new SwitchUserProcessingFilter(); |
||||
assertEquals("/j_acegi_exit_user", filter.getDefaultExitUserUrl()); |
||||
} |
||||
|
||||
public void testDefaultProcessesFilterUrlWithPathParameter() { |
||||
MockHttpServletRequest request = createMockSwitchRequest(); |
||||
SwitchUserProcessingFilter filter = new SwitchUserProcessingFilter(); |
||||
filter.setSwitchUserUrl("/j_acegi_switch_user"); |
||||
|
||||
request.setRequestURI( |
||||
"/webapp/j_acegi_switch_user;jsessionid=8JHDUD723J8"); |
||||
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( |
||||
"ROLE_TWO")}; |
||||
UsernamePasswordAuthenticationToken source = new UsernamePasswordAuthenticationToken("dano", |
||||
"hawaii50", auths); |
||||
|
||||
// set current user (Admin)
|
||||
GrantedAuthority[] adminAuths = {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl( |
||||
"ROLE_TWO"), new SwitchUserGrantedAuthority("PREVIOUS_ADMINISTRATOR", |
||||
source)}; |
||||
UsernamePasswordAuthenticationToken admin = new UsernamePasswordAuthenticationToken("jacklord", |
||||
"hawaii50", adminAuths); |
||||
|
||||
SecurityContextHolder.getContext().setAuthentication(admin); |
||||
|
||||
// http request
|
||||
MockHttpServletRequest request = createMockSwitchRequest(); |
||||
request.setRequestURI("/j_acegi_exit_user"); |
||||
|
||||
// http response
|
||||
MockHttpServletResponse response = new MockHttpServletResponse(); |
||||
|
||||
// setup filter
|
||||
SwitchUserProcessingFilter filter = new SwitchUserProcessingFilter(); |
||||
filter.setAuthenticationDao(new MockAuthenticationDaoUserJackLord()); |
||||
filter.setExitUserUrl("/j_acegi_exit_user"); |
||||
|
||||
MockFilterChain chain = new MockFilterChain(true); |
||||
|
||||
// run 'exit'
|
||||
filter.doFilter(request, response, chain); |
||||
|
||||
// check current user, should be back to original user (dano)
|
||||
Authentication targetAuth = SecurityContextHolder.getContext() |
||||
.getAuthentication(); |
||||
assertNotNull(targetAuth); |
||||
assertEquals("dano", targetAuth.getPrincipal()); |
||||
} |
||||
|
||||
public void testExitUserWithNoCurrentUser() throws Exception { |
||||
// no current user in secure context
|
||||
SecurityContextHolder.getContext().setAuthentication(null); |
||||
|
||||
// http request
|
||||
MockHttpServletRequest request = createMockSwitchRequest(); |
||||
request.setRequestURI("/j_acegi_exit_user"); |
||||
|
||||
// http response
|
||||
MockHttpServletResponse response = new MockHttpServletResponse(); |
||||
|
||||
// setup filter
|
||||
SwitchUserProcessingFilter filter = new SwitchUserProcessingFilter(); |
||||
filter.setAuthenticationDao(new MockAuthenticationDaoUserJackLord()); |
||||
filter.setExitUserUrl("/j_acegi_exit_user"); |
||||
|
||||
MockFilterChain chain = new MockFilterChain(true); |
||||
|
||||
// run 'exit', expect fail due to no current user
|
||||
try { |
||||
filter.doFilter(request, response, chain); |
||||
|
||||
fail("Cannot exit from a user with no current user set!"); |
||||
} catch (AuthenticationException expected) {} |
||||
} |
||||
|
||||
public void testRedirectToTargetUrl() throws Exception { |
||||
// set current user
|
||||
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken("dano", |
||||
"hawaii50"); |
||||
SecurityContextHolder.getContext().setAuthentication(auth); |
||||
|
||||
MockHttpServletRequest request = createMockSwitchRequest(); |
||||
request.addParameter(SwitchUserProcessingFilter.ACEGI_SECURITY_SWITCH_USERNAME_KEY, |
||||
"jacklord"); |
||||
request.setRequestURI("/webapp/j_acegi_switch_user"); |
||||
|
||||
MockHttpServletResponse response = new MockHttpServletResponse(); |
||||
MockFilterChain chain = new MockFilterChain(true); |
||||
|
||||
SwitchUserProcessingFilter filter = new SwitchUserProcessingFilter(); |
||||
filter.setSwitchUserUrl("/j_acegi_switch_user"); |
||||
filter.setTargetUrl("/webapp/someOtherUrl"); |
||||
filter.setAuthenticationDao(new MockAuthenticationDaoUserJackLord()); |
||||
|
||||
filter.doFilter(request, response, chain); |
||||
|
||||
assertEquals("/webapp/someOtherUrl", response.getRedirectedUrl()); |
||||
} |
||||
|
||||
public void testRequiresExitUser() { |
||||
// filter
|
||||
SwitchUserProcessingFilter filter = new SwitchUserProcessingFilter(); |
||||
filter.setExitUserUrl("/j_acegi_exit_user"); |
||||
|
||||
// request
|
||||
MockHttpServletRequest request = new MockHttpServletRequest(); |
||||
request.setRequestURI("/j_acegi_exit_user"); |
||||
|
||||
assertTrue(filter.requiresExitUser(request)); |
||||
} |
||||
|
||||
public void testRequiresSwitch() { |
||||
// filter
|
||||
SwitchUserProcessingFilter filter = new SwitchUserProcessingFilter(); |
||||
filter.setSwitchUserUrl("/j_acegi_switch_user"); |
||||
|
||||
// request
|
||||
MockHttpServletRequest request = createMockSwitchRequest(); |
||||
|
||||
assertTrue(filter.requiresSwitchUser(request)); |
||||
} |
||||
|
||||
public void testSwitchRequestFromDanoToJackLord() throws Exception { |
||||
// set current user
|
||||
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken("dano", |
||||
"hawaii50"); |
||||
SecurityContextHolder.getContext().setAuthentication(auth); |
||||
|
||||
// http request
|
||||
MockHttpServletRequest request = new MockHttpServletRequest(); |
||||
request.setRequestURI("/webapp/j_acegi_switch_user"); |
||||
request.addParameter(SwitchUserProcessingFilter.ACEGI_SECURITY_SWITCH_USERNAME_KEY, |
||||
"jacklord"); |
||||
|
||||
// http response
|
||||
MockHttpServletResponse response = new MockHttpServletResponse(); |
||||
|
||||
// setup filter
|
||||
SwitchUserProcessingFilter filter = new SwitchUserProcessingFilter(); |
||||
filter.setAuthenticationDao(new MockAuthenticationDaoUserJackLord()); |
||||
filter.setSwitchUserUrl("/j_acegi_switch_user"); |
||||
|
||||
MockFilterChain chain = new MockFilterChain(true); |
||||
|
||||
// test updates user token and context
|
||||
filter.doFilter(request, response, chain); |
||||
|
||||
// check current user
|
||||
Authentication targetAuth = SecurityContextHolder.getContext() |
||||
.getAuthentication(); |
||||
assertNotNull(targetAuth); |
||||
assertEquals("jacklord", targetAuth.getPrincipal()); |
||||
} |
||||
|
||||
private MockHttpServletRequest createMockSwitchRequest() { |
||||
MockHttpServletRequest request = new MockHttpServletRequest(); |
||||
request.setScheme("http"); |
||||
request.setServerName("localhost"); |
||||
request.setRequestURI("/j_acegi_switch_user"); |
||||
|
||||
return request; |
||||
} |
||||
|
||||
//~ Inner Classes ==========================================================
|
||||
|
||||
private class MockAuthenticationDaoUserJackLord implements AuthenticationDao { |
||||
private String password = "hawaii50"; |
||||
|
||||
public void setPassword(String password) { |
||||
this.password = password; |
||||
} |
||||
|
||||
public UserDetails loadUserByUsername(String username) |
||||
throws UsernameNotFoundException, DataAccessException { |
||||
// jacklord, dano (active)
|
||||
// mcgarrett (disabled)
|
||||
// wofat (account expired)
|
||||
// steve (credentials expired)
|
||||
if ("jacklord".equals(username) || "dano".equals(username)) { |
||||
return new User(username, password, true, true, true, true, |
||||
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl( |
||||
"ROLE_TWO")}); |
||||
} else if ("mcgarrett".equals(username)) { |
||||
return new User(username, password, false, true, true, true, |
||||
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl( |
||||
"ROLE_TWO")}); |
||||
} else if ("wofat".equals(username)) { |
||||
return new User(username, password, true, false, true, true, |
||||
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl( |
||||
"ROLE_TWO")}); |
||||
} else if ("steve".equals(username)) { |
||||
return new User(username, password, true, true, false, true, |
||||
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl( |
||||
"ROLE_TWO")}); |
||||
} else { |
||||
throw new UsernameNotFoundException("Could not find: " |
||||
+ username); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
Loading…
Reference in new issue