mirror of
https://github.com/spring-projects/spring-security.git
synced 2025-06-28 14:52:24 +00:00
Use SecurityContextHolderStrategy for Switch User
Issue gh-11060
This commit is contained in:
parent
98995f2225
commit
e1c211c11f
@ -49,6 +49,7 @@ import org.springframework.security.core.GrantedAuthority;
|
|||||||
import org.springframework.security.core.SpringSecurityMessageSource;
|
import org.springframework.security.core.SpringSecurityMessageSource;
|
||||||
import org.springframework.security.core.context.SecurityContext;
|
import org.springframework.security.core.context.SecurityContext;
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolderStrategy;
|
||||||
import org.springframework.security.core.userdetails.UserDetails;
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
import org.springframework.security.core.userdetails.UserDetailsChecker;
|
import org.springframework.security.core.userdetails.UserDetailsChecker;
|
||||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||||
@ -114,6 +115,9 @@ public class SwitchUserFilter extends GenericFilterBean implements ApplicationEv
|
|||||||
|
|
||||||
public static final String ROLE_PREVIOUS_ADMINISTRATOR = "ROLE_PREVIOUS_ADMINISTRATOR";
|
public static final String ROLE_PREVIOUS_ADMINISTRATOR = "ROLE_PREVIOUS_ADMINISTRATOR";
|
||||||
|
|
||||||
|
private SecurityContextHolderStrategy securityContextHolderStrategy = SecurityContextHolder
|
||||||
|
.getContextHolderStrategy();
|
||||||
|
|
||||||
private ApplicationEventPublisher eventPublisher;
|
private ApplicationEventPublisher eventPublisher;
|
||||||
|
|
||||||
private AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource = new WebAuthenticationDetailsSource();
|
private AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource = new WebAuthenticationDetailsSource();
|
||||||
@ -175,9 +179,9 @@ public class SwitchUserFilter extends GenericFilterBean implements ApplicationEv
|
|||||||
try {
|
try {
|
||||||
Authentication targetUser = attemptSwitchUser(request);
|
Authentication targetUser = attemptSwitchUser(request);
|
||||||
// update the current context to the new target user
|
// update the current context to the new target user
|
||||||
SecurityContext context = SecurityContextHolder.createEmptyContext();
|
SecurityContext context = this.securityContextHolderStrategy.createEmptyContext();
|
||||||
context.setAuthentication(targetUser);
|
context.setAuthentication(targetUser);
|
||||||
SecurityContextHolder.setContext(context);
|
this.securityContextHolderStrategy.setContext(context);
|
||||||
this.logger.debug(LogMessage.format("Set SecurityContextHolder to %s", targetUser));
|
this.logger.debug(LogMessage.format("Set SecurityContextHolder to %s", targetUser));
|
||||||
// redirect to target url
|
// redirect to target url
|
||||||
this.successHandler.onAuthenticationSuccess(request, response, targetUser);
|
this.successHandler.onAuthenticationSuccess(request, response, targetUser);
|
||||||
@ -192,9 +196,9 @@ public class SwitchUserFilter extends GenericFilterBean implements ApplicationEv
|
|||||||
// get the original authentication object (if exists)
|
// get the original authentication object (if exists)
|
||||||
Authentication originalUser = attemptExitUser(request);
|
Authentication originalUser = attemptExitUser(request);
|
||||||
// update the current context back to the original user
|
// update the current context back to the original user
|
||||||
SecurityContext context = SecurityContextHolder.createEmptyContext();
|
SecurityContext context = this.securityContextHolderStrategy.createEmptyContext();
|
||||||
context.setAuthentication(originalUser);
|
context.setAuthentication(originalUser);
|
||||||
SecurityContextHolder.setContext(context);
|
this.securityContextHolderStrategy.setContext(context);
|
||||||
this.logger.debug(LogMessage.format("Set SecurityContextHolder to %s", originalUser));
|
this.logger.debug(LogMessage.format("Set SecurityContextHolder to %s", originalUser));
|
||||||
// redirect to target url
|
// redirect to target url
|
||||||
this.successHandler.onAuthenticationSuccess(request, response, originalUser);
|
this.successHandler.onAuthenticationSuccess(request, response, originalUser);
|
||||||
@ -228,7 +232,7 @@ public class SwitchUserFilter extends GenericFilterBean implements ApplicationEv
|
|||||||
// publish event
|
// publish event
|
||||||
if (this.eventPublisher != null) {
|
if (this.eventPublisher != null) {
|
||||||
this.eventPublisher.publishEvent(new AuthenticationSwitchUserEvent(
|
this.eventPublisher.publishEvent(new AuthenticationSwitchUserEvent(
|
||||||
SecurityContextHolder.getContext().getAuthentication(), targetUser));
|
this.securityContextHolderStrategy.getContext().getAuthentication(), targetUser));
|
||||||
}
|
}
|
||||||
return targetUserRequest;
|
return targetUserRequest;
|
||||||
}
|
}
|
||||||
@ -244,7 +248,7 @@ public class SwitchUserFilter extends GenericFilterBean implements ApplicationEv
|
|||||||
protected Authentication attemptExitUser(HttpServletRequest request)
|
protected Authentication attemptExitUser(HttpServletRequest request)
|
||||||
throws AuthenticationCredentialsNotFoundException {
|
throws AuthenticationCredentialsNotFoundException {
|
||||||
// need to check to see if the current user has a SwitchUserGrantedAuthority
|
// need to check to see if the current user has a SwitchUserGrantedAuthority
|
||||||
Authentication current = SecurityContextHolder.getContext().getAuthentication();
|
Authentication current = this.securityContextHolderStrategy.getContext().getAuthentication();
|
||||||
if (current == null) {
|
if (current == null) {
|
||||||
throw new AuthenticationCredentialsNotFoundException(this.messages
|
throw new AuthenticationCredentialsNotFoundException(this.messages
|
||||||
.getMessage("SwitchUserFilter.noCurrentUser", "No current user associated with this request"));
|
.getMessage("SwitchUserFilter.noCurrentUser", "No current user associated with this request"));
|
||||||
@ -310,7 +314,7 @@ public class SwitchUserFilter extends GenericFilterBean implements ApplicationEv
|
|||||||
return attemptExitUser(request);
|
return attemptExitUser(request);
|
||||||
}
|
}
|
||||||
catch (AuthenticationCredentialsNotFoundException ex) {
|
catch (AuthenticationCredentialsNotFoundException ex) {
|
||||||
return SecurityContextHolder.getContext().getAuthentication();
|
return this.securityContextHolderStrategy.getContext().getAuthentication();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -510,6 +514,17 @@ public class SwitchUserFilter extends GenericFilterBean implements ApplicationEv
|
|||||||
this.switchAuthorityRole = switchAuthorityRole;
|
this.switchAuthorityRole = switchAuthorityRole;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the {@link SecurityContextHolderStrategy} to use. The default action is to use
|
||||||
|
* the {@link SecurityContextHolderStrategy} stored in {@link SecurityContextHolder}.
|
||||||
|
*
|
||||||
|
* @since 5.8
|
||||||
|
*/
|
||||||
|
public void setSecurityContextHolderStrategy(SecurityContextHolderStrategy securityContextHolderStrategy) {
|
||||||
|
Assert.notNull(securityContextHolderStrategy, "securityContextHolderStrategy cannot be null");
|
||||||
|
this.securityContextHolderStrategy = securityContextHolderStrategy;
|
||||||
|
}
|
||||||
|
|
||||||
private static RequestMatcher createMatcher(String pattern) {
|
private static RequestMatcher createMatcher(String pattern) {
|
||||||
return new AntPathRequestMatcher(pattern, "POST", true, new UrlPathHelper());
|
return new AntPathRequestMatcher(pattern, "POST", true, new UrlPathHelper());
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,10 @@ import org.springframework.security.core.AuthenticationException;
|
|||||||
import org.springframework.security.core.GrantedAuthority;
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
import org.springframework.security.core.authority.AuthorityUtils;
|
import org.springframework.security.core.authority.AuthorityUtils;
|
||||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||||
|
import org.springframework.security.core.context.SecurityContext;
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolderStrategy;
|
||||||
|
import org.springframework.security.core.context.SecurityContextImpl;
|
||||||
import org.springframework.security.core.userdetails.User;
|
import org.springframework.security.core.userdetails.User;
|
||||||
import org.springframework.security.core.userdetails.UserDetails;
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||||
@ -49,8 +52,10 @@ import org.springframework.security.web.util.matcher.AnyRequestMatcher;
|
|||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||||
|
import static org.mockito.Mockito.atLeastOnce;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.never;
|
import static org.mockito.Mockito.never;
|
||||||
|
import static org.mockito.Mockito.spy;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -416,6 +421,21 @@ public class SwitchUserFilterTests {
|
|||||||
assertThat(AuthorityUtils.authorityListToSet(result.getAuthorities())).contains("ROLE_NEW");
|
assertThat(AuthorityUtils.authorityListToSet(result.getAuthorities())).contains("ROLE_NEW");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void doFilterWhenCustomSecurityContextRepositoryThenUses() {
|
||||||
|
SecurityContextHolderStrategy securityContextHolderStrategy = spy(new MockSecurityContextHolderStrategy(
|
||||||
|
UsernamePasswordAuthenticationToken.unauthenticated("dano", "hawaii50")));
|
||||||
|
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||||
|
request.addParameter(SwitchUserFilter.SPRING_SECURITY_SWITCH_USERNAME_KEY, "jacklord");
|
||||||
|
SwitchUserFilter filter = new SwitchUserFilter();
|
||||||
|
filter.setSecurityContextHolderStrategy(securityContextHolderStrategy);
|
||||||
|
filter.setUserDetailsService(new MockUserDetailsService());
|
||||||
|
Authentication result = filter.attemptSwitchUser(request);
|
||||||
|
assertThat(result).isNotNull();
|
||||||
|
assertThat(result.getName()).isEqualTo("jacklord");
|
||||||
|
verify(securityContextHolderStrategy, atLeastOnce()).getContext();
|
||||||
|
}
|
||||||
|
|
||||||
// SEC-1763
|
// SEC-1763
|
||||||
@Test
|
@Test
|
||||||
public void nestedSwitchesAreNotAllowed() {
|
public void nestedSwitchesAreNotAllowed() {
|
||||||
@ -512,4 +532,34 @@ public class SwitchUserFilterTests {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static final class MockSecurityContextHolderStrategy implements SecurityContextHolderStrategy {
|
||||||
|
|
||||||
|
private SecurityContext mock;
|
||||||
|
|
||||||
|
private MockSecurityContextHolderStrategy(Authentication authentication) {
|
||||||
|
this.mock = new SecurityContextImpl(authentication);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clearContext() {
|
||||||
|
this.mock = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SecurityContext getContext() {
|
||||||
|
return this.mock;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setContext(SecurityContext context) {
|
||||||
|
this.mock = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SecurityContext createEmptyContext() {
|
||||||
|
return new SecurityContextImpl();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user