AnonymousAuthenticationFilter should cache its Supplier<SecurityContext>
Closes gh-11900
This commit is contained in:
parent
5a55987d6e
commit
56b9badcfe
|
@ -37,6 +37,7 @@ 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.SecurityContextHolderStrategy;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
import org.springframework.util.function.SingletonSupplier;
|
||||||
import org.springframework.web.filter.GenericFilterBean;
|
import org.springframework.web.filter.GenericFilterBean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -45,6 +46,7 @@ import org.springframework.web.filter.GenericFilterBean;
|
||||||
*
|
*
|
||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
* @author Luke Taylor
|
* @author Luke Taylor
|
||||||
|
* @author Evgeniy Cheban
|
||||||
*/
|
*/
|
||||||
public class AnonymousAuthenticationFilter extends GenericFilterBean implements InitializingBean {
|
public class AnonymousAuthenticationFilter extends GenericFilterBean implements InitializingBean {
|
||||||
|
|
||||||
|
@ -100,10 +102,10 @@ public class AnonymousAuthenticationFilter extends GenericFilterBean implements
|
||||||
|
|
||||||
private Supplier<SecurityContext> defaultWithAnonymous(HttpServletRequest request,
|
private Supplier<SecurityContext> defaultWithAnonymous(HttpServletRequest request,
|
||||||
Supplier<SecurityContext> currentDeferredContext) {
|
Supplier<SecurityContext> currentDeferredContext) {
|
||||||
return () -> {
|
return SingletonSupplier.of(() -> {
|
||||||
SecurityContext currentContext = currentDeferredContext.get();
|
SecurityContext currentContext = currentDeferredContext.get();
|
||||||
return defaultWithAnonymous(request, currentContext);
|
return defaultWithAnonymous(request, currentContext);
|
||||||
};
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private SecurityContext defaultWithAnonymous(HttpServletRequest request, SecurityContext currentContext) {
|
private SecurityContext defaultWithAnonymous(HttpServletRequest request, SecurityContext currentContext) {
|
||||||
|
|
|
@ -16,6 +16,8 @@
|
||||||
|
|
||||||
package org.springframework.security;
|
package org.springframework.security;
|
||||||
|
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.core.context.SecurityContext;
|
import org.springframework.security.core.context.SecurityContext;
|
||||||
import org.springframework.security.core.context.SecurityContextHolderStrategy;
|
import org.springframework.security.core.context.SecurityContextHolderStrategy;
|
||||||
|
@ -23,29 +25,33 @@ import org.springframework.security.core.context.SecurityContextImpl;
|
||||||
|
|
||||||
public class MockSecurityContextHolderStrategy implements SecurityContextHolderStrategy {
|
public class MockSecurityContextHolderStrategy implements SecurityContextHolderStrategy {
|
||||||
|
|
||||||
private SecurityContext mock;
|
private Supplier<SecurityContext> mock;
|
||||||
|
|
||||||
public MockSecurityContextHolderStrategy() {
|
public MockSecurityContextHolderStrategy() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public MockSecurityContextHolderStrategy(Authentication authentication) {
|
public MockSecurityContextHolderStrategy(Authentication authentication) {
|
||||||
this.mock = new SecurityContextImpl(authentication);
|
this(() -> new SecurityContextImpl(authentication));
|
||||||
|
}
|
||||||
|
|
||||||
|
public MockSecurityContextHolderStrategy(Supplier<SecurityContext> mock) {
|
||||||
|
this.mock = mock;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void clearContext() {
|
public void clearContext() {
|
||||||
this.mock = null;
|
this.mock = () -> null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SecurityContext getContext() {
|
public SecurityContext getContext() {
|
||||||
return this.mock;
|
return this.mock.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setContext(SecurityContext context) {
|
public void setContext(SecurityContext context) {
|
||||||
this.mock = context;
|
this.mock = () -> context;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -53,4 +59,14 @@ public class MockSecurityContextHolderStrategy implements SecurityContextHolderS
|
||||||
return new SecurityContextImpl();
|
return new SecurityContextImpl();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Supplier<SecurityContext> getDeferredContext() {
|
||||||
|
return this.mock;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setDeferredContext(Supplier<SecurityContext> deferredContext) {
|
||||||
|
this.mock = deferredContext;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,7 @@ import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import org.springframework.mock.web.MockHttpServletRequest;
|
import org.springframework.mock.web.MockHttpServletRequest;
|
||||||
import org.springframework.mock.web.MockHttpServletResponse;
|
import org.springframework.mock.web.MockHttpServletResponse;
|
||||||
|
import org.springframework.security.MockSecurityContextHolderStrategy;
|
||||||
import org.springframework.security.authentication.TestingAuthenticationToken;
|
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.core.authority.AuthorityUtils;
|
import org.springframework.security.core.authority.AuthorityUtils;
|
||||||
|
@ -46,6 +47,7 @@ import static org.assertj.core.api.Assertions.fail;
|
||||||
import static org.mockito.BDDMockito.given;
|
import static org.mockito.BDDMockito.given;
|
||||||
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.times;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -53,6 +55,7 @@ import static org.mockito.Mockito.verify;
|
||||||
*
|
*
|
||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
* @author Eddú Meléndez
|
* @author Eddú Meléndez
|
||||||
|
* @author Evgeniy Cheban
|
||||||
*/
|
*/
|
||||||
public class AnonymousAuthenticationFilterTests {
|
public class AnonymousAuthenticationFilterTests {
|
||||||
|
|
||||||
|
@ -128,6 +131,25 @@ public class AnonymousAuthenticationFilterTests {
|
||||||
verify(originalSupplier, never()).get();
|
verify(originalSupplier, never()).get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void doFilterSetsSingletonSupplier() throws Exception {
|
||||||
|
Supplier<SecurityContext> originalSupplier = mock(Supplier.class);
|
||||||
|
Authentication originalAuth = new TestingAuthenticationToken("user", "password", "ROLE_A");
|
||||||
|
SecurityContext originalContext = new SecurityContextImpl(originalAuth);
|
||||||
|
SecurityContextHolderStrategy strategy = new MockSecurityContextHolderStrategy(originalSupplier);
|
||||||
|
given(originalSupplier.get()).willReturn(originalContext);
|
||||||
|
AnonymousAuthenticationFilter filter = new AnonymousAuthenticationFilter("qwerty", "anonymousUsername",
|
||||||
|
AuthorityUtils.createAuthorityList("ROLE_ANONYMOUS"));
|
||||||
|
filter.setSecurityContextHolderStrategy(strategy);
|
||||||
|
filter.afterPropertiesSet();
|
||||||
|
executeFilterInContainerSimulator(mock(FilterConfig.class), filter, new MockHttpServletRequest(),
|
||||||
|
new MockHttpServletResponse(), new MockFilterChain(true));
|
||||||
|
Supplier<SecurityContext> deferredContext = strategy.getDeferredContext();
|
||||||
|
deferredContext.get();
|
||||||
|
deferredContext.get();
|
||||||
|
verify(originalSupplier, times(1)).get();
|
||||||
|
}
|
||||||
|
|
||||||
private class MockFilterChain implements FilterChain {
|
private class MockFilterChain implements FilterChain {
|
||||||
|
|
||||||
private boolean expectToProceed;
|
private boolean expectToProceed;
|
||||||
|
|
Loading…
Reference in New Issue