Merge Formatting Changes

Issue gh-8945
This commit is contained in:
Rob Winch
2020-08-24 16:38:12 -05:00
2779 changed files with 82438 additions and 91751 deletions

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security;
import java.util.HashSet;
@@ -25,30 +26,33 @@ import org.springframework.beans.factory.config.BeanPostProcessor;
* @author Luke Taylor
*/
public class BeanNameCollectingPostProcessor implements BeanPostProcessor {
Set<String> beforeInitPostProcessedBeans = new HashSet<>();
Set<String> afterInitPostProcessedBeans = new HashSet<>();
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (beanName != null) {
beforeInitPostProcessedBeans.add(beanName);
this.beforeInitPostProcessedBeans.add(beanName);
}
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (beanName != null) {
afterInitPostProcessedBeans.add(beanName);
this.afterInitPostProcessedBeans.add(beanName);
}
return bean;
}
public Set<String> getBeforeInitPostProcessedBeans() {
return beforeInitPostProcessedBeans;
return this.beforeInitPostProcessedBeans;
}
public Set<String> getAfterInitPostProcessedBeans() {
return afterInitPostProcessedBeans;
return this.afterInitPostProcessedBeans;
}
}

View File

@@ -13,9 +13,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security;
import java.util.*;
import java.util.HashSet;
import java.util.Set;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
@@ -30,39 +32,45 @@ import org.springframework.security.authentication.event.AbstractAuthenticationF
* @since 3.1
*/
public class CollectingAppListener implements ApplicationListener {
Set<ApplicationEvent> events = new HashSet<>();
Set<AbstractAuthenticationEvent> authenticationEvents = new HashSet<>();
Set<AbstractAuthenticationFailureEvent> authenticationFailureEvents = new HashSet<>();
Set<AbstractAuthorizationEvent> authorizationEvents = new HashSet<>();
@Override
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof AbstractAuthenticationEvent) {
events.add(event);
authenticationEvents.add((AbstractAuthenticationEvent) event);
this.events.add(event);
this.authenticationEvents.add((AbstractAuthenticationEvent) event);
}
if (event instanceof AbstractAuthenticationFailureEvent) {
events.add(event);
authenticationFailureEvents.add((AbstractAuthenticationFailureEvent) event);
this.events.add(event);
this.authenticationFailureEvents.add((AbstractAuthenticationFailureEvent) event);
}
if (event instanceof AbstractAuthorizationEvent) {
events.add(event);
authorizationEvents.add((AbstractAuthorizationEvent) event);
this.events.add(event);
this.authorizationEvents.add((AbstractAuthorizationEvent) event);
}
}
public Set<ApplicationEvent> getEvents() {
return events;
return this.events;
}
public Set<AbstractAuthenticationEvent> getAuthenticationEvents() {
return authenticationEvents;
return this.authenticationEvents;
}
public Set<AbstractAuthenticationFailureEvent> getAuthenticationFailureEvents() {
return authenticationFailureEvents;
return this.authenticationFailureEvents;
}
public Set<AbstractAuthorizationEvent> getAuthorizationEvents() {
return authorizationEvents;
return this.authorizationEvents;
}
}

View File

@@ -13,9 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config;
public abstract class ConfigTestUtils {
// @formatter:off
public static final String AUTH_PROVIDER_XML = "<authentication-manager alias='authManager'>"
+ " <authentication-provider>"
+ " <user-service id='us'>"
@@ -26,4 +29,6 @@ public abstract class ConfigTestUtils {
+ " </user-service>"
+ " </authentication-provider>"
+ "</authentication-manager>";
// @formatter:on
}

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config;
import javax.sql.DataSource;
@@ -27,18 +28,17 @@ import org.springframework.util.Assert;
* @author Ben Alex
*/
public class DataSourcePopulator implements InitializingBean {
// ~ Instance fields
// ================================================================================================
JdbcTemplate template;
@Override
public void afterPropertiesSet() {
Assert.notNull(template, "dataSource required");
template.execute("CREATE TABLE USERS(USERNAME VARCHAR_IGNORECASE(50) NOT NULL PRIMARY KEY,PASSWORD VARCHAR_IGNORECASE(500) NOT NULL,ENABLED BOOLEAN NOT NULL);");
template.execute("CREATE TABLE AUTHORITIES(USERNAME VARCHAR_IGNORECASE(50) NOT NULL,AUTHORITY VARCHAR_IGNORECASE(50) NOT NULL,CONSTRAINT FK_AUTHORITIES_USERS FOREIGN KEY(USERNAME) REFERENCES USERS(USERNAME));");
template.execute("CREATE UNIQUE INDEX IX_AUTH_USERNAME ON AUTHORITIES(USERNAME,AUTHORITY);");
Assert.notNull(this.template, "dataSource required");
this.template.execute(
"CREATE TABLE USERS(USERNAME VARCHAR_IGNORECASE(50) NOT NULL PRIMARY KEY,PASSWORD VARCHAR_IGNORECASE(500) NOT NULL,ENABLED BOOLEAN NOT NULL);");
this.template.execute(
"CREATE TABLE AUTHORITIES(USERNAME VARCHAR_IGNORECASE(50) NOT NULL,AUTHORITY VARCHAR_IGNORECASE(50) NOT NULL,CONSTRAINT FK_AUTHORITIES_USERS FOREIGN KEY(USERNAME) REFERENCES USERS(USERNAME));");
this.template.execute("CREATE UNIQUE INDEX IX_AUTH_USERNAME ON AUTHORITIES(USERNAME,AUTHORITY);");
/*
* Passwords encoded using MD5, NOT in Base64 format, with null as salt Encoded
* password for rod is "koala" Encoded password for dianne is "emu" Encoded
@@ -46,24 +46,25 @@ public class DataSourcePopulator implements InitializingBean {
* is disabled) Encoded password for bill is "wombat" Encoded password for bob is
* "wombat" Encoded password for jane is "wombat"
*/
template.execute("INSERT INTO USERS VALUES('rod','{noop}koala',TRUE);");
template.execute("INSERT INTO USERS VALUES('dianne','{MD5}65d15fe9156f9c4bbffd98085992a44e',TRUE);");
template.execute("INSERT INTO USERS VALUES('scott','{MD5}2b58af6dddbd072ed27ffc86725d7d3a',TRUE);");
template.execute("INSERT INTO USERS VALUES('peter','{MD5}22b5c9accc6e1ba628cedc63a72d57f8',FALSE);");
template.execute("INSERT INTO USERS VALUES('bill','{MD5}2b58af6dddbd072ed27ffc86725d7d3a',TRUE);");
template.execute("INSERT INTO USERS VALUES('bob','{MD5}2b58af6dddbd072ed27ffc86725d7d3a',TRUE);");
template.execute("INSERT INTO USERS VALUES('jane','{MD5}2b58af6dddbd072ed27ffc86725d7d3a',TRUE);");
template.execute("INSERT INTO AUTHORITIES VALUES('rod','ROLE_USER');");
template.execute("INSERT INTO AUTHORITIES VALUES('rod','ROLE_SUPERVISOR');");
template.execute("INSERT INTO AUTHORITIES VALUES('dianne','ROLE_USER');");
template.execute("INSERT INTO AUTHORITIES VALUES('scott','ROLE_USER');");
template.execute("INSERT INTO AUTHORITIES VALUES('peter','ROLE_USER');");
template.execute("INSERT INTO AUTHORITIES VALUES('bill','ROLE_USER');");
template.execute("INSERT INTO AUTHORITIES VALUES('bob','ROLE_USER');");
template.execute("INSERT INTO AUTHORITIES VALUES('jane','ROLE_USER');");
this.template.execute("INSERT INTO USERS VALUES('rod','{noop}koala',TRUE);");
this.template.execute("INSERT INTO USERS VALUES('dianne','{MD5}65d15fe9156f9c4bbffd98085992a44e',TRUE);");
this.template.execute("INSERT INTO USERS VALUES('scott','{MD5}2b58af6dddbd072ed27ffc86725d7d3a',TRUE);");
this.template.execute("INSERT INTO USERS VALUES('peter','{MD5}22b5c9accc6e1ba628cedc63a72d57f8',FALSE);");
this.template.execute("INSERT INTO USERS VALUES('bill','{MD5}2b58af6dddbd072ed27ffc86725d7d3a',TRUE);");
this.template.execute("INSERT INTO USERS VALUES('bob','{MD5}2b58af6dddbd072ed27ffc86725d7d3a',TRUE);");
this.template.execute("INSERT INTO USERS VALUES('jane','{MD5}2b58af6dddbd072ed27ffc86725d7d3a',TRUE);");
this.template.execute("INSERT INTO AUTHORITIES VALUES('rod','ROLE_USER');");
this.template.execute("INSERT INTO AUTHORITIES VALUES('rod','ROLE_SUPERVISOR');");
this.template.execute("INSERT INTO AUTHORITIES VALUES('dianne','ROLE_USER');");
this.template.execute("INSERT INTO AUTHORITIES VALUES('scott','ROLE_USER');");
this.template.execute("INSERT INTO AUTHORITIES VALUES('peter','ROLE_USER');");
this.template.execute("INSERT INTO AUTHORITIES VALUES('bill','ROLE_USER');");
this.template.execute("INSERT INTO AUTHORITIES VALUES('bob','ROLE_USER');");
this.template.execute("INSERT INTO AUTHORITIES VALUES('jane','ROLE_USER');");
}
public void setDataSource(DataSource dataSource) {
this.template = new JdbcTemplate(dataSource);
}
}

View File

@@ -16,9 +16,6 @@
package org.springframework.security.config;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.*;
import java.util.List;
import javax.servlet.Filter;
@@ -43,6 +40,11 @@ import org.springframework.security.web.servletapi.SecurityContextHolderAwareReq
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.AnyRequestMatcher;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
/**
* Tests {@link FilterChainProxy}.
*
@@ -50,37 +52,32 @@ import org.springframework.security.web.util.matcher.AnyRequestMatcher;
* @author Ben Alex
*/
public class FilterChainProxyConfigTests {
private ClassPathXmlApplicationContext appCtx;
// ~ Methods
// ========================================================================================================
private ClassPathXmlApplicationContext appCtx;
@Before
public void loadContext() {
System.setProperty("sec1235.pattern1", "/login");
System.setProperty("sec1235.pattern2", "/logout");
appCtx = new ClassPathXmlApplicationContext(
"org/springframework/security/util/filtertest-valid.xml");
this.appCtx = new ClassPathXmlApplicationContext("org/springframework/security/util/filtertest-valid.xml");
}
@After
public void closeContext() {
if (appCtx != null) {
appCtx.close();
if (this.appCtx != null) {
this.appCtx.close();
}
}
@Test
public void normalOperation() throws Exception {
FilterChainProxy filterChainProxy = appCtx.getBean("filterChain",
FilterChainProxy.class);
FilterChainProxy filterChainProxy = this.appCtx.getBean("filterChain", FilterChainProxy.class);
doNormalOperation(filterChainProxy);
}
@Test
public void normalOperationWithNewConfig() throws Exception {
FilterChainProxy filterChainProxy = appCtx.getBean("newFilterChainProxy",
FilterChainProxy.class);
FilterChainProxy filterChainProxy = this.appCtx.getBean("newFilterChainProxy", FilterChainProxy.class);
filterChainProxy.setFirewall(new DefaultHttpFirewall());
checkPathAndFilterOrder(filterChainProxy);
doNormalOperation(filterChainProxy);
@@ -88,8 +85,7 @@ public class FilterChainProxyConfigTests {
@Test
public void normalOperationWithNewConfigRegex() throws Exception {
FilterChainProxy filterChainProxy = appCtx.getBean("newFilterChainProxyRegex",
FilterChainProxy.class);
FilterChainProxy filterChainProxy = this.appCtx.getBean("newFilterChainProxyRegex", FilterChainProxy.class);
filterChainProxy.setFirewall(new DefaultHttpFirewall());
checkPathAndFilterOrder(filterChainProxy);
doNormalOperation(filterChainProxy);
@@ -97,8 +93,8 @@ public class FilterChainProxyConfigTests {
@Test
public void normalOperationWithNewConfigNonNamespace() throws Exception {
FilterChainProxy filterChainProxy = appCtx.getBean(
"newFilterChainProxyNonNamespace", FilterChainProxy.class);
FilterChainProxy filterChainProxy = this.appCtx.getBean("newFilterChainProxyNonNamespace",
FilterChainProxy.class);
filterChainProxy.setFirewall(new DefaultHttpFirewall());
checkPathAndFilterOrder(filterChainProxy);
doNormalOperation(filterChainProxy);
@@ -106,43 +102,38 @@ public class FilterChainProxyConfigTests {
@Test
public void pathWithNoMatchHasNoFilters() {
FilterChainProxy filterChainProxy = appCtx.getBean(
"newFilterChainProxyNoDefaultPath", FilterChainProxy.class);
FilterChainProxy filterChainProxy = this.appCtx.getBean("newFilterChainProxyNoDefaultPath",
FilterChainProxy.class);
assertThat(filterChainProxy.getFilters("/nomatch")).isNull();
}
// SEC-1235
@Test
public void mixingPatternsAndPlaceholdersDoesntCauseOrderingIssues() {
FilterChainProxy fcp = appCtx.getBean("sec1235FilterChainProxy",
FilterChainProxy.class);
FilterChainProxy fcp = this.appCtx.getBean("sec1235FilterChainProxy", FilterChainProxy.class);
List<SecurityFilterChain> chains = fcp.getFilterChains();
assertThat(getPattern(chains.get(0))).isEqualTo("/login*");
assertThat(getPattern(chains.get(1))).isEqualTo("/logout");
assertThat(((DefaultSecurityFilterChain) chains.get(2)).getRequestMatcher() instanceof AnyRequestMatcher).isTrue();
assertThat(((DefaultSecurityFilterChain) chains.get(2)).getRequestMatcher() instanceof AnyRequestMatcher)
.isTrue();
}
private String getPattern(SecurityFilterChain chain) {
return ((AntPathRequestMatcher) ((DefaultSecurityFilterChain) chain)
.getRequestMatcher()).getPattern();
return ((AntPathRequestMatcher) ((DefaultSecurityFilterChain) chain).getRequestMatcher()).getPattern();
}
private void checkPathAndFilterOrder(FilterChainProxy filterChainProxy) {
List<Filter> filters = filterChainProxy.getFilters("/foo/blah;x=1");
assertThat(filters).hasSize(1);
assertThat(filters.get(0) instanceof SecurityContextHolderAwareRequestFilter).isTrue();
filters = filterChainProxy.getFilters("/some;x=2,y=3/other/path;z=4/blah");
assertThat(filters).isNotNull();
assertThat(filters).hasSize(3);
assertThat(filters.get(0) instanceof SecurityContextPersistenceFilter).isTrue();
assertThat(filters.get(1) instanceof SecurityContextHolderAwareRequestFilter).isTrue();
assertThat(filters.get(2) instanceof SecurityContextHolderAwareRequestFilter).isTrue();
filters = filterChainProxy.getFilters("/do/not/filter;x=7");
assertThat(filters).isEmpty();
filters = filterChainProxy.getFilters("/another/nonspecificmatch");
assertThat(filters).hasSize(3);
assertThat(filters.get(0) instanceof SecurityContextPersistenceFilter).isTrue();
@@ -153,18 +144,14 @@ public class FilterChainProxyConfigTests {
private void doNormalOperation(FilterChainProxy filterChainProxy) throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest("GET", "");
request.setServletPath("/foo/secure/super/somefile.html");
MockHttpServletResponse response = new MockHttpServletResponse();
FilterChain chain = mock(FilterChain.class);
filterChainProxy.doFilter(request, response, chain);
verify(chain).doFilter(any(HttpServletRequest.class),
any(HttpServletResponse.class));
verify(chain).doFilter(any(HttpServletRequest.class), any(HttpServletResponse.class));
request.setServletPath("/a/path/which/doesnt/match/any/filter.html");
chain = mock(FilterChain.class);
filterChainProxy.doFilter(request, response, chain);
verify(chain).doFilter(any(HttpServletRequest.class),
any(HttpServletResponse.class));
verify(chain).doFilter(any(HttpServletRequest.class), any(HttpServletResponse.class));
}
}

View File

@@ -13,19 +13,21 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config;
import static org.assertj.core.api.Assertions.*;
import static org.junit.Assert.fail;
package org.springframework.security.config;
import org.junit.After;
import org.junit.Test;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.xml.XmlBeanDefinitionStoreException;
import org.springframework.security.config.authentication.AuthenticationManagerFactoryBean;
import org.springframework.security.config.util.InMemoryXmlApplicationContext;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.fail;
/**
* Tests which make sure invalid configurations are rejected by the namespace. In
* particular invalid top-level elements. These are likely to fail after the namespace has
@@ -34,12 +36,13 @@ import org.springframework.security.config.util.InMemoryXmlApplicationContext;
* @author Luke Taylor
*/
public class InvalidConfigurationTests {
private InMemoryXmlApplicationContext appContext;
@After
public void closeAppContext() {
if (appContext != null) {
appContext.close();
if (this.appContext != null) {
this.appContext.close();
}
}
@@ -60,24 +63,24 @@ public class InvalidConfigurationTests {
setContext("<http auto-config='true' />");
fail();
}
catch (BeanCreationException e) {
Throwable cause = ultimateCause(e);
catch (BeanCreationException ex) {
Throwable cause = ultimateCause(ex);
assertThat(cause instanceof NoSuchBeanDefinitionException).isTrue();
NoSuchBeanDefinitionException nsbe = (NoSuchBeanDefinitionException) cause;
assertThat(nsbe.getBeanName()).isEqualTo(BeanIds.AUTHENTICATION_MANAGER);
assertThat(nsbe.getMessage()).endsWith(
AuthenticationManagerFactoryBean.MISSING_BEAN_ERROR_MESSAGE);
assertThat(nsbe.getMessage()).endsWith(AuthenticationManagerFactoryBean.MISSING_BEAN_ERROR_MESSAGE);
}
}
private Throwable ultimateCause(Throwable e) {
if (e.getCause() == null) {
return e;
private Throwable ultimateCause(Throwable ex) {
if (ex.getCause() == null) {
return ex;
}
return ultimateCause(e.getCause());
return ultimateCause(ex.getCause());
}
private void setContext(String context) {
appContext = new InMemoryXmlApplicationContext(context);
this.appContext = new InMemoryXmlApplicationContext(context);
}
}

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config;
import java.util.Collection;
@@ -24,16 +25,18 @@ import org.springframework.security.core.Authentication;
public class MockAfterInvocationProvider implements AfterInvocationProvider {
public Object decide(Authentication authentication, Object object,
Collection<ConfigAttribute> config, Object returnedObject)
throws AccessDeniedException {
@Override
public Object decide(Authentication authentication, Object object, Collection<ConfigAttribute> config,
Object returnedObject) throws AccessDeniedException {
return returnedObject;
}
@Override
public boolean supports(ConfigAttribute attribute) {
return true;
}
@Override
public boolean supports(Class<?> clazz) {
return true;
}

View File

@@ -16,20 +16,21 @@
package org.springframework.security.config;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import java.util.ArrayList;
import java.util.List;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
/**
* @author Rob Winch
* @since 5.0.2
*/
public class MockEventListener<T extends ApplicationEvent>
implements ApplicationListener<T> {
public class MockEventListener<T extends ApplicationEvent> implements ApplicationListener<T> {
private List<T> events = new ArrayList<>();
@Override
public void onApplicationEvent(T event) {
this.events.add(event);
}
@@ -37,4 +38,5 @@ public class MockEventListener<T extends ApplicationEvent>
public List<T> getEvents() {
return this.events;
}
}

View File

@@ -13,27 +13,32 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config;
import static org.mockito.Mockito.mock;
package org.springframework.security.config;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionException;
import org.springframework.transaction.TransactionStatus;
import static org.mockito.Mockito.mock;
/**
* @author Luke Taylor
*/
public class MockTransactionManager implements PlatformTransactionManager {
public TransactionStatus getTransaction(TransactionDefinition definition)
throws TransactionException {
@Override
public TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {
return mock(TransactionStatus.class);
}
@Override
public void commit(TransactionStatus status) throws TransactionException {
}
@Override
public void rollback(TransactionStatus status) throws TransactionException {
}
}

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config;
import org.springframework.beans.BeansException;
@@ -26,18 +27,17 @@ import org.springframework.beans.factory.config.BeanPostProcessor;
*/
public class MockUserServiceBeanPostProcessor implements BeanPostProcessor {
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof PostProcessedMockUserDetailsService) {
((PostProcessedMockUserDetailsService) bean)
.setPostProcessorWasHere("Hello from the post processor!");
((PostProcessedMockUserDetailsService) bean).setPostProcessorWasHere("Hello from the post processor!");
}
return bean;
}
}

View File

@@ -13,12 +13,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
public class PostProcessedMockUserDetailsService implements UserDetailsService {
private String postProcessorWasHere;
public PostProcessedMockUserDetailsService() {
@@ -26,14 +28,16 @@ public class PostProcessedMockUserDetailsService implements UserDetailsService {
}
public String getPostProcessorWasHere() {
return postProcessorWasHere;
return this.postProcessorWasHere;
}
public void setPostProcessorWasHere(String postProcessorWasHere) {
this.postProcessorWasHere = postProcessorWasHere;
}
@Override
public UserDetails loadUserByUsername(String username) {
throw new UnsupportedOperationException("Not for actual use");
}
}

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config;
import org.apache.commons.logging.Log;
@@ -20,6 +21,7 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
@@ -34,14 +36,10 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.powermock.api.mockito.PowerMockito.doThrow;
import static org.powermock.api.mockito.PowerMockito.mock;
import static org.powermock.api.mockito.PowerMockito.spy;
import static org.powermock.api.mockito.PowerMockito.verifyStatic;
import static org.powermock.api.mockito.PowerMockito.verifyZeroInteractions;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verifyZeroInteractions;
/**
*
* @author Luke Taylor
* @author Rob Winch
* @since 3.0
@@ -50,15 +48,22 @@ import static org.powermock.api.mockito.PowerMockito.verifyZeroInteractions;
@PrepareForTest({ ClassUtils.class })
@PowerMockIgnore({ "org.w3c.dom.*", "org.xml.sax.*", "org.apache.xerces.*", "javax.xml.parsers.*" })
public class SecurityNamespaceHandlerTests {
@Rule
public ExpectedException thrown = ExpectedException.none();
// @formatter:off
private static final String XML_AUTHENTICATION_MANAGER = "<authentication-manager>"
+ " <authentication-provider>" + " <user-service id='us'>"
+ " <authentication-provider>"
+ " <user-service id='us'>"
+ " <user name='bob' password='bobspassword' authorities='ROLE_A' />"
+ " </user-service>" + " </authentication-provider>"
+ " </user-service>"
+ " </authentication-provider>"
+ "</authentication-manager>";
// @formatter:on
private static final String XML_HTTP_BLOCK = "<http auto-config='true'/>";
private static final String FILTER_CHAIN_PROXY_CLASSNAME = "org.springframework.security.web.FilterChainProxy";
@Test
@@ -74,15 +79,13 @@ public class SecurityNamespaceHandlerTests {
@Test
public void pre32SchemaAreNotSupported() {
try {
new InMemoryXmlApplicationContext(
"<user-service id='us'>"
+ " <user name='bob' password='bobspassword' authorities='ROLE_A' />"
+ "</user-service>", "3.0.3", null);
new InMemoryXmlApplicationContext("<user-service id='us'>"
+ " <user name='bob' password='bobspassword' authorities='ROLE_A' />" + "</user-service>", "3.0.3",
null);
fail("Expected BeanDefinitionParsingException");
}
catch (BeanDefinitionParsingException expected) {
assertThat(expected.getMessage().contains(
"You cannot use a spring-security-2.0.xsd"));
assertThat(expected.getMessage().contains("You cannot use a spring-security-2.0.xsd"));
}
}
@@ -90,17 +93,14 @@ public class SecurityNamespaceHandlerTests {
@Test
public void initDoesNotLogErrorWhenFilterChainProxyFailsToLoad() throws Exception {
String className = "javax.servlet.Filter";
spy(ClassUtils.class);
doThrow(new NoClassDefFoundError(className)).when(ClassUtils.class, "forName",
PowerMockito.spy(ClassUtils.class);
PowerMockito.doThrow(new NoClassDefFoundError(className)).when(ClassUtils.class, "forName",
eq(FILTER_CHAIN_PROXY_CLASSNAME), any(ClassLoader.class));
Log logger = mock(Log.class);
SecurityNamespaceHandler handler = new SecurityNamespaceHandler();
ReflectionTestUtils.setField(handler, "logger", logger);
handler.init();
verifyStatic(ClassUtils.class);
PowerMockito.verifyStatic(ClassUtils.class);
ClassUtils.forName(eq(FILTER_CHAIN_PROXY_CLASSNAME), any(ClassLoader.class));
verifyZeroInteractions(logger);
}
@@ -108,10 +108,10 @@ public class SecurityNamespaceHandlerTests {
@Test
public void filterNoClassDefFoundError() throws Exception {
String className = "javax.servlet.Filter";
thrown.expect(BeanDefinitionParsingException.class);
thrown.expectMessage("NoClassDefFoundError: " + className);
spy(ClassUtils.class);
doThrow(new NoClassDefFoundError(className)).when(ClassUtils.class, "forName",
this.thrown.expect(BeanDefinitionParsingException.class);
this.thrown.expectMessage("NoClassDefFoundError: " + className);
PowerMockito.spy(ClassUtils.class);
PowerMockito.doThrow(new NoClassDefFoundError(className)).when(ClassUtils.class, "forName",
eq(FILTER_CHAIN_PROXY_CLASSNAME), any(ClassLoader.class));
new InMemoryXmlApplicationContext(XML_AUTHENTICATION_MANAGER + XML_HTTP_BLOCK);
}
@@ -119,8 +119,8 @@ public class SecurityNamespaceHandlerTests {
@Test
public void filterNoClassDefFoundErrorNoHttpBlock() throws Exception {
String className = "javax.servlet.Filter";
spy(ClassUtils.class);
doThrow(new NoClassDefFoundError(className)).when(ClassUtils.class, "forName",
PowerMockito.spy(ClassUtils.class);
PowerMockito.doThrow(new NoClassDefFoundError(className)).when(ClassUtils.class, "forName",
eq(FILTER_CHAIN_PROXY_CLASSNAME), any(ClassLoader.class));
new InMemoryXmlApplicationContext(XML_AUTHENTICATION_MANAGER);
// should load just fine since no http block
@@ -129,10 +129,10 @@ public class SecurityNamespaceHandlerTests {
@Test
public void filterChainProxyClassNotFoundException() throws Exception {
String className = FILTER_CHAIN_PROXY_CLASSNAME;
thrown.expect(BeanDefinitionParsingException.class);
thrown.expectMessage("ClassNotFoundException: " + className);
spy(ClassUtils.class);
doThrow(new ClassNotFoundException(className)).when(ClassUtils.class, "forName",
this.thrown.expect(BeanDefinitionParsingException.class);
this.thrown.expectMessage("ClassNotFoundException: " + className);
PowerMockito.spy(ClassUtils.class);
PowerMockito.doThrow(new ClassNotFoundException(className)).when(ClassUtils.class, "forName",
eq(FILTER_CHAIN_PROXY_CLASSNAME), any(ClassLoader.class));
new InMemoryXmlApplicationContext(XML_AUTHENTICATION_MANAGER + XML_HTTP_BLOCK);
}
@@ -140,8 +140,8 @@ public class SecurityNamespaceHandlerTests {
@Test
public void filterChainProxyClassNotFoundExceptionNoHttpBlock() throws Exception {
String className = FILTER_CHAIN_PROXY_CLASSNAME;
spy(ClassUtils.class);
doThrow(new ClassNotFoundException(className)).when(ClassUtils.class, "forName",
PowerMockito.spy(ClassUtils.class);
PowerMockito.doThrow(new ClassNotFoundException(className)).when(ClassUtils.class, "forName",
eq(FILTER_CHAIN_PROXY_CLASSNAME), any(ClassLoader.class));
new InMemoryXmlApplicationContext(XML_AUTHENTICATION_MANAGER);
// should load just fine since no http block
@@ -150,10 +150,11 @@ public class SecurityNamespaceHandlerTests {
@Test
public void websocketNotFoundExceptionNoMessageBlock() throws Exception {
String className = FILTER_CHAIN_PROXY_CLASSNAME;
spy(ClassUtils.class);
doThrow(new ClassNotFoundException(className)).when(ClassUtils.class, "forName",
PowerMockito.spy(ClassUtils.class);
PowerMockito.doThrow(new ClassNotFoundException(className)).when(ClassUtils.class, "forName",
eq(Message.class.getName()), any(ClassLoader.class));
new InMemoryXmlApplicationContext(XML_AUTHENTICATION_MANAGER);
// should load just fine since no websocket block
}
}

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config;
/**
@@ -29,4 +30,5 @@ public interface TestBusinessBean {
void doSomething();
void unprotected();
}

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config;
import org.springframework.context.ApplicationListener;
@@ -21,15 +22,18 @@ import org.springframework.security.core.session.SessionCreationEvent;
/**
* @author Luke Taylor
*/
public class TestBusinessBeanImpl implements TestBusinessBean,
ApplicationListener<SessionCreationEvent> {
public class TestBusinessBeanImpl implements TestBusinessBean, ApplicationListener<SessionCreationEvent> {
@Override
public void setInteger(int i) {
}
@Override
public int getInteger() {
return 1314;
}
@Override
public void setString(String s) {
}
@@ -37,13 +41,17 @@ public class TestBusinessBeanImpl implements TestBusinessBean,
return "A string.";
}
@Override
public void doSomething() {
}
@Override
public void unprotected() {
}
@Override
public void onApplicationEvent(SessionCreationEvent event) {
System.out.println(event);
}
}

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config;
import org.springframework.transaction.annotation.Transactional;
@@ -21,20 +22,27 @@ import org.springframework.transaction.annotation.Transactional;
* @author Luke Taylor
*/
public class TransactionalTestBusinessBean implements TestBusinessBean {
@Override
public void setInteger(int i) {
}
@Override
public int getInteger() {
return 0;
}
@Override
public void setString(String s) {
}
@Override
@Transactional
public void doSomething() {
}
@Override
public void unprotected() {
}
}

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation;
import java.util.ArrayList;
@@ -22,17 +23,18 @@ import java.util.List;
* @author Rob Winch
*
*/
class ConcereteSecurityConfigurerAdapter extends
SecurityConfigurerAdapter<Object, SecurityBuilder<Object>> {
class ConcereteSecurityConfigurerAdapter extends SecurityConfigurerAdapter<Object, SecurityBuilder<Object>> {
private List<Object> list = new ArrayList<>();
@Override
public void configure(SecurityBuilder<Object> builder) {
list = postProcess(list);
this.list = postProcess(this.list);
}
public ConcereteSecurityConfigurerAdapter list(List<Object> l) {
ConcereteSecurityConfigurerAdapter list(List<Object> l) {
this.list = l;
return this;
}
}

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation;
import java.util.ArrayList;
@@ -21,7 +22,7 @@ import java.util.List;
import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatObject;
/**
* @author Rob Winch
@@ -32,22 +33,24 @@ public class ObjectPostProcessorTests {
@Test
public void convertTypes() {
assertThat((Object) PerformConversion.perform(new ArrayList<>()))
.isInstanceOf(LinkedList.class);
assertThatObject(PerformConversion.perform(new ArrayList<>())).isInstanceOf(LinkedList.class);
}
static class ListToLinkedListObjectPostProcessor implements ObjectPostProcessor<List<?>> {
@Override
public <O extends List<?>> O postProcess(O l) {
return (O) new LinkedList(l);
}
}
static class PerformConversion {
public static List<?> perform(ArrayList<?> l) {
static List<?> perform(ArrayList<?> l) {
return new ListToLinkedListObjectPostProcessor().postProcess(l);
}
}
}

View File

@@ -13,8 +13,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation;
package org.springframework.security.config.annotation;
import java.util.ArrayList;
import java.util.List;
@@ -30,6 +30,7 @@ import static org.mockito.Mockito.mock;
*
*/
public class SecurityConfigurerAdapterClosureTests {
ConcereteSecurityConfigurerAdapter conf = new ConcereteSecurityConfigurerAdapter();
@Test
@@ -42,25 +43,25 @@ public class SecurityConfigurerAdapterClosureTests {
return l;
}
});
this.conf.init(builder);
this.conf.configure(builder);
assertThat(this.conf.list).contains("a");
}
static class ConcereteSecurityConfigurerAdapter extends
SecurityConfigurerAdapter<Object, SecurityBuilder<Object>> {
private List<Object> list = new ArrayList<Object>();
static class ConcereteSecurityConfigurerAdapter extends SecurityConfigurerAdapter<Object, SecurityBuilder<Object>> {
private List<Object> list = new ArrayList<>();
@Override
public void configure(SecurityBuilder<Object> builder) throws Exception {
this.list = postProcess(this.list);
}
public ConcereteSecurityConfigurerAdapter list(List<Object> l) {
ConcereteSecurityConfigurerAdapter list(List<Object> l) {
this.list = l;
return this;
}
}
}

View File

@@ -13,45 +13,52 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation;
import static org.assertj.core.api.Assertions.*;
package org.springframework.security.config.annotation;
import org.junit.Before;
import org.junit.Test;
import org.springframework.core.Ordered;
import static org.assertj.core.api.Assertions.assertThat;
public class SecurityConfigurerAdapterTests {
ConcereteSecurityConfigurerAdapter adapter;
@Before
public void setup() {
adapter = new ConcereteSecurityConfigurerAdapter();
this.adapter = new ConcereteSecurityConfigurerAdapter();
}
@Test
public void postProcessObjectPostProcessorsAreSorted() {
adapter.addObjectPostProcessor(new OrderedObjectPostProcessor(Ordered.LOWEST_PRECEDENCE));
adapter.addObjectPostProcessor(new OrderedObjectPostProcessor(Ordered.HIGHEST_PRECEDENCE));
assertThat(adapter.postProcess("hi"))
this.adapter.addObjectPostProcessor(new OrderedObjectPostProcessor(Ordered.LOWEST_PRECEDENCE));
this.adapter.addObjectPostProcessor(new OrderedObjectPostProcessor(Ordered.HIGHEST_PRECEDENCE));
assertThat(this.adapter.postProcess("hi"))
.isEqualTo("hi " + Ordered.HIGHEST_PRECEDENCE + " " + Ordered.LOWEST_PRECEDENCE);
}
static class OrderedObjectPostProcessor implements ObjectPostProcessor<String>, Ordered {
private final int order;
OrderedObjectPostProcessor(int order) {
this.order = order;
}
@Override
public int getOrder() {
return order;
return this.order;
}
@Override
@SuppressWarnings("unchecked")
public String postProcess(String object) {
return object + " " + order;
return object + " " + this.order;
}
}
}

View File

@@ -13,10 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.authentication;
import java.util.Arrays;
import java.util.Properties;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
@@ -45,17 +50,15 @@ import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers;
import org.springframework.test.web.servlet.MockMvc;
import java.util.Arrays;
import java.util.Properties;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.formLogin;
import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.authenticated;
@@ -63,18 +66,20 @@ import static org.springframework.security.test.web.servlet.response.SecurityMoc
* @author Rob Winch
*/
public class AuthenticationManagerBuilderTests {
@Rule
public final SpringTestRule spring = new SpringTestRule();
@Autowired(required = false)
MockMvc mockMvc;
@Test
public void buildWhenAddAuthenticationProviderThenDoesNotPerformRegistration() throws Exception {
ObjectPostProcessor<Object> opp = mock(ObjectPostProcessor.class);
AuthenticationProvider provider = mock(AuthenticationProvider.class);
AuthenticationManagerBuilder builder = new AuthenticationManagerBuilder(opp);
builder.authenticationProvider(provider);
builder.build();
verify(opp, never()).postProcess(provider);
}
@@ -83,109 +88,55 @@ public class AuthenticationManagerBuilderTests {
public void customAuthenticationEventPublisherWithWeb() throws Exception {
ObjectPostProcessor<Object> opp = mock(ObjectPostProcessor.class);
AuthenticationEventPublisher aep = mock(AuthenticationEventPublisher.class);
when(opp.postProcess(any())).thenAnswer(a -> a.getArgument(0));
AuthenticationManager am = new AuthenticationManagerBuilder(opp)
.authenticationEventPublisher(aep)
.inMemoryAuthentication()
.and()
.build();
given(opp.postProcess(any())).willAnswer((a) -> a.getArgument(0));
AuthenticationManager am = new AuthenticationManagerBuilder(opp).authenticationEventPublisher(aep)
.inMemoryAuthentication().and().build();
try {
am.authenticate(new UsernamePasswordAuthenticationToken("user", "password"));
} catch (AuthenticationException success) {}
}
catch (AuthenticationException success) {
}
verify(aep).publishAuthenticationFailure(any(), any());
}
@Test
public void getAuthenticationManagerWhenGlobalPasswordEncoderBeanThenUsed() throws Exception {
this.spring.register(PasswordEncoderGlobalConfig.class).autowire();
AuthenticationManager manager = this.spring.getContext()
.getBean(AuthenticationConfiguration.class).getAuthenticationManager();
AuthenticationManager manager = this.spring.getContext().getBean(AuthenticationConfiguration.class)
.getAuthenticationManager();
Authentication auth = manager.authenticate(new UsernamePasswordAuthenticationToken("user", "password"));
assertThat(auth.getName()).isEqualTo("user");
assertThat(auth.getAuthorities()).extracting(GrantedAuthority::getAuthority).containsOnly("ROLE_USER");
}
@EnableWebSecurity
static class PasswordEncoderGlobalConfig extends WebSecurityConfigurerAdapter {
@Autowired
void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER");
}
@Bean
PasswordEncoder passwordEncoder() {
return NoOpPasswordEncoder.getInstance();
}
}
@Test
public void getAuthenticationManagerWhenProtectedPasswordEncoderBeanThenUsed() throws Exception {
this.spring.register(PasswordEncoderGlobalConfig.class).autowire();
AuthenticationManager manager = this.spring.getContext()
.getBean(AuthenticationConfiguration.class).getAuthenticationManager();
AuthenticationManager manager = this.spring.getContext().getBean(AuthenticationConfiguration.class)
.getAuthenticationManager();
Authentication auth = manager.authenticate(new UsernamePasswordAuthenticationToken("user", "password"));
assertThat(auth.getName()).isEqualTo("user");
assertThat(auth.getAuthorities()).extracting(GrantedAuthority::getAuthority).containsOnly("ROLE_USER");
}
@EnableWebSecurity
static class PasswordEncoderConfig extends WebSecurityConfigurerAdapter {
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER");
}
@Bean
PasswordEncoder passwordEncoder() {
return NoOpPasswordEncoder.getInstance();
}
}
@Autowired(required = false)
MockMvc mockMvc;
@Test
public void authenticationManagerWhenMultipleProvidersThenWorks() throws Exception {
this.spring.register(MultiAuthenticationProvidersConfig.class).autowire();
this.mockMvc.perform(formLogin())
.andExpect(authenticated().withUsername("user").withRoles("USER"));
this.mockMvc.perform(formLogin().user("admin"))
.andExpect(authenticated().withUsername("admin").withRoles("USER", "ADMIN"));
}
@EnableWebSecurity
static class MultiAuthenticationProvidersConfig
extends WebSecurityConfigurerAdapter {
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser(PasswordEncodedUser.user())
.and()
.inMemoryAuthentication()
.withUser(PasswordEncodedUser.admin());
}
SecurityMockMvcResultMatchers.AuthenticatedMatcher user = authenticated().withUsername("user")
.withRoles("USER");
this.mockMvc.perform(formLogin()).andExpect(user);
SecurityMockMvcResultMatchers.AuthenticatedMatcher admin = authenticated().withUsername("admin")
.withRoles("USER", "ADMIN");
this.mockMvc.perform(formLogin().user("admin")).andExpect(admin);
}
@Test
public void buildWhenAuthenticationProviderThenIsConfigured() throws Exception {
ObjectPostProcessor<Object> opp = mock(ObjectPostProcessor.class);
AuthenticationProvider provider = mock(AuthenticationProvider.class);
AuthenticationManagerBuilder builder = new AuthenticationManagerBuilder(opp);
builder.authenticationProvider(provider);
builder.build();
assertThat(builder.isConfigured()).isTrue();
}
@@ -193,29 +144,79 @@ public class AuthenticationManagerBuilderTests {
public void buildWhenParentThenIsConfigured() throws Exception {
ObjectPostProcessor<Object> opp = mock(ObjectPostProcessor.class);
AuthenticationManager parent = mock(AuthenticationManager.class);
AuthenticationManagerBuilder builder = new AuthenticationManagerBuilder(opp);
builder.parentAuthenticationManager(parent);
builder.build();
assertThat(builder.isConfigured()).isTrue();
}
@Test
public void buildWhenNotConfiguredThenIsConfiguredFalse() throws Exception {
ObjectPostProcessor<Object> opp = mock(ObjectPostProcessor.class);
AuthenticationManagerBuilder builder = new AuthenticationManagerBuilder(opp);
builder.build();
assertThat(builder.isConfigured()).isFalse();
}
public void buildWhenUserFromProperties() throws Exception {
this.spring.register(UserFromPropertiesConfig.class).autowire();
this.mockMvc.perform(formLogin().user("joe", "joespassword"))
.andExpect(authenticated().withUsername("joe").withRoles("USER"));
.andExpect(authenticated().withUsername("joe").withRoles("USER"));
}
@EnableWebSecurity
static class MultiAuthenticationProvidersConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// @formatter:off
auth
.inMemoryAuthentication()
.withUser(PasswordEncodedUser.user())
.and()
.inMemoryAuthentication()
.withUser(PasswordEncodedUser.admin());
// @formatter:on
}
}
@EnableWebSecurity
static class PasswordEncoderGlobalConfig extends WebSecurityConfigurerAdapter {
@Autowired
void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
// @formatter:off
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER");
// @formatter:on
}
@Bean
PasswordEncoder passwordEncoder() {
return NoOpPasswordEncoder.getInstance();
}
}
@EnableWebSecurity
static class PasswordEncoderConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// @formatter:off
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER");
// @formatter:on
}
@Bean
PasswordEncoder passwordEncoder() {
return NoOpPasswordEncoder.getInstance();
}
}
@Configuration
@@ -227,23 +228,24 @@ public class AuthenticationManagerBuilderTests {
Resource users;
@Bean
public AuthenticationManager authenticationManager() throws Exception {
AuthenticationManager authenticationManager() throws Exception {
return new ProviderManager(Arrays.asList(authenticationProvider()));
}
@Bean
public AuthenticationProvider authenticationProvider() throws Exception {
AuthenticationProvider authenticationProvider() throws Exception {
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setUserDetailsService(userDetailsService());
return provider;
}
@Bean
public UserDetailsService userDetailsService() throws Exception {
UserDetailsService userDetailsService() throws Exception {
Properties properties = new Properties();
properties.load(this.users.getInputStream());
return new InMemoryUserDetailsManager(properties);
}
}
}

View File

@@ -13,24 +13,27 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.authentication;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
/**
*
* @author Rob Winch
*/
@Configuration
public class BaseAuthenticationConfig {
@Autowired
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// @formatter:off
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER").and()
.withUser("admin").password("password").roles("USER", "ADMIN");
// @formatter:on
}
}

View File

@@ -13,16 +13,19 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.authentication;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.test.SpringTestRule;
import org.springframework.security.core.userdetails.PasswordEncodedUser;
import org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers;
import org.springframework.test.web.servlet.MockMvc;
import static org.assertj.core.api.Assertions.assertThat;
@@ -33,6 +36,7 @@ import static org.springframework.security.test.web.servlet.response.SecurityMoc
* @author Rob Winch
*/
public class NamespaceAuthenticationManagerTests {
@Rule
public final SpringTestRule spring = new SpringTestRule();
@@ -42,65 +46,74 @@ public class NamespaceAuthenticationManagerTests {
@Test
public void authenticationMangerWhenDefaultThenEraseCredentialsIsTrue() throws Exception {
this.spring.register(EraseCredentialsTrueDefaultConfig.class).autowire();
this.mockMvc.perform(formLogin())
.andExpect(authenticated().withAuthentication(a-> assertThat(a.getCredentials()).isNull()));
this.mockMvc.perform(formLogin())
.andExpect(authenticated().withAuthentication(a-> assertThat(a.getCredentials()).isNull()));
SecurityMockMvcResultMatchers.AuthenticatedMatcher nullCredentials = authenticated()
.withAuthentication((a) -> assertThat(a.getCredentials()).isNull());
this.mockMvc.perform(formLogin()).andExpect(nullCredentials);
this.mockMvc.perform(formLogin()).andExpect(nullCredentials);
// no exception due to username being cleared out
}
@EnableWebSecurity
static class EraseCredentialsTrueDefaultConfig extends WebSecurityConfigurerAdapter {
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser(PasswordEncodedUser.user());
}
}
@Test
public void authenticationMangerWhenEraseCredentialsIsFalseThenCredentialsNotNull() throws Exception {
this.spring.register(EraseCredentialsFalseConfig.class).autowire();
this.mockMvc.perform(formLogin())
.andExpect(authenticated().withAuthentication(a-> assertThat(a.getCredentials()).isNotNull()));
this.mockMvc.perform(formLogin())
.andExpect(authenticated().withAuthentication(a-> assertThat(a.getCredentials()).isNotNull()));
SecurityMockMvcResultMatchers.AuthenticatedMatcher notNullCredentials = authenticated()
.withAuthentication((a) -> assertThat(a.getCredentials()).isNotNull());
this.mockMvc.perform(formLogin()).andExpect(notNullCredentials);
this.mockMvc.perform(formLogin()).andExpect(notNullCredentials);
// no exception due to username being cleared out
}
@EnableWebSecurity
static class EraseCredentialsFalseConfig extends WebSecurityConfigurerAdapter {
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.eraseCredentials(false)
.inMemoryAuthentication()
.withUser(PasswordEncodedUser.user());
}
}
@Test
// SEC-2533
public void authenticationManagerWhenGlobalAndEraseCredentialsIsFalseThenCredentialsNotNull() throws Exception {
this.spring.register(GlobalEraseCredentialsFalseConfig.class).autowire();
this.mockMvc.perform(formLogin())
.andExpect(authenticated().withAuthentication(a-> assertThat(a.getCredentials()).isNotNull()));
SecurityMockMvcResultMatchers.AuthenticatedMatcher notNullCredentials = authenticated()
.withAuthentication((a) -> assertThat(a.getCredentials()).isNotNull());
this.mockMvc.perform(formLogin()).andExpect(notNullCredentials);
}
@EnableWebSecurity
static class GlobalEraseCredentialsFalseConfig extends WebSecurityConfigurerAdapter {
static class EraseCredentialsTrueDefaultConfig extends WebSecurityConfigurerAdapter {
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
// @formatter:off
auth
.inMemoryAuthentication()
.withUser(PasswordEncodedUser.user());
// @formatter:on
}
}
@EnableWebSecurity
static class EraseCredentialsFalseConfig extends WebSecurityConfigurerAdapter {
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
// @formatter:off
auth
.eraseCredentials(false)
.inMemoryAuthentication()
.withUser(PasswordEncodedUser.user());
// @formatter:on
}
}
@EnableWebSecurity
static class GlobalEraseCredentialsFalseConfig extends WebSecurityConfigurerAdapter {
@Autowired
void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
// @formatter:off
auth
.eraseCredentials(false)
.inMemoryAuthentication()
.withUser(PasswordEncodedUser.user());
// @formatter:on
}
}
}

View File

@@ -18,6 +18,7 @@ package org.springframework.security.config.annotation.authentication;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
@@ -48,45 +49,53 @@ public class NamespaceAuthenticationProviderTests {
// authentication-provider@ref
public void authenticationProviderRef() throws Exception {
this.spring.register(AuthenticationProviderRefConfig.class).autowire();
this.mockMvc.perform(formLogin())
.andExpect(authenticated().withUsername("user"));
}
@EnableWebSecurity
static class AuthenticationProviderRefConfig extends WebSecurityConfigurerAdapter {
protected void configure(AuthenticationManagerBuilder auth) {
auth
.authenticationProvider(authenticationProvider());
}
@Bean
public DaoAuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider result = new DaoAuthenticationProvider();
result.setUserDetailsService(new InMemoryUserDetailsManager(PasswordEncodedUser.user()));
return result;
}
this.mockMvc.perform(formLogin()).andExpect(authenticated().withUsername("user"));
}
@Test
// authentication-provider@user-service-ref
public void authenticationProviderUserServiceRef() throws Exception {
this.spring.register(AuthenticationProviderRefConfig.class).autowire();
this.mockMvc.perform(formLogin()).andExpect(authenticated().withUsername("user"));
}
@EnableWebSecurity
static class AuthenticationProviderRefConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) {
// @formatter:off
auth
.authenticationProvider(authenticationProvider());
// @formatter:on
}
@Bean
DaoAuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider result = new DaoAuthenticationProvider();
result.setUserDetailsService(new InMemoryUserDetailsManager(PasswordEncodedUser.user()));
return result;
}
this.mockMvc.perform(formLogin())
.andExpect(authenticated().withUsername("user"));
}
@EnableWebSecurity
static class UserServiceRefConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// @formatter:off
auth
.userDetailsService(userDetailsService());
// @formatter:on
}
@Override
@Bean
public UserDetailsService userDetailsService() {
return new InMemoryUserDetailsManager(PasswordEncodedUser.user());
}
}
}

View File

@@ -16,8 +16,11 @@
package org.springframework.security.config.annotation.authentication;
import javax.sql.DataSource;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -30,11 +33,10 @@ import org.springframework.security.config.test.SpringTestRule;
import org.springframework.security.core.userdetails.PasswordEncodedUser;
import org.springframework.security.core.userdetails.UserCache;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.provisioning.JdbcUserDetailsManager;
import org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl;
import org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers;
import org.springframework.test.web.servlet.MockMvc;
import javax.sql.DataSource;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.formLogin;
import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.authenticated;
@@ -52,48 +54,60 @@ public class NamespaceJdbcUserServiceTests {
@Test
public void jdbcUserService() throws Exception {
this.spring.register(DataSourceConfig.class, JdbcUserServiceConfig.class).autowire();
this.mockMvc.perform(formLogin())
.andExpect(authenticated().withUsername("user"));
}
@EnableWebSecurity
static class JdbcUserServiceConfig extends WebSecurityConfigurerAdapter {
@Autowired
private DataSource dataSource;
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.jdbcAuthentication()
.withDefaultSchema()
.withUser(PasswordEncodedUser.user())
.dataSource(this.dataSource); // jdbc-user-service@data-source-ref
}
}
@Configuration
static class DataSourceConfig {
@Bean
public DataSource dataSource() {
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
return builder.setType(EmbeddedDatabaseType.HSQL).build();
}
SecurityMockMvcResultMatchers.AuthenticatedMatcher user = authenticated().withUsername("user");
this.mockMvc.perform(formLogin()).andExpect(user);
}
@Test
public void jdbcUserServiceCustom() throws Exception {
this.spring.register(CustomDataSourceConfig.class, CustomJdbcUserServiceSampleConfig.class).autowire();
// @formatter:off
SecurityMockMvcResultMatchers.AuthenticatedMatcher dba = authenticated()
.withUsername("user")
.withRoles("DBA", "USER");
// @formatter:on
this.mockMvc.perform(formLogin()).andExpect(dba);
}
@EnableWebSecurity
static class JdbcUserServiceConfig extends WebSecurityConfigurerAdapter {
@Autowired
private DataSource dataSource;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// @formatter:off
auth
.jdbcAuthentication()
.withDefaultSchema()
.withUser(PasswordEncodedUser.user())
.dataSource(this.dataSource); // jdbc-user-service@data-source-ref
// @formatter:on
}
}
@Configuration
static class DataSourceConfig {
@Bean
DataSource dataSource() {
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
return builder.setType(EmbeddedDatabaseType.HSQL).build();
}
this.mockMvc.perform(formLogin())
.andExpect(authenticated().withUsername("user").withRoles("DBA", "USER"));
}
@EnableWebSecurity
static class CustomJdbcUserServiceSampleConfig extends WebSecurityConfigurerAdapter {
@Autowired
private DataSource dataSource;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// @formatter:off
auth
.jdbcAuthentication()
// jdbc-user-service@dataSource
@@ -105,10 +119,10 @@ public class NamespaceJdbcUserServiceTests {
// jdbc-user-service@authorities-by-username-query
.authoritiesByUsernameQuery("select principal,role from roles where principal = ?")
// jdbc-user-service@group-authorities-by-username-query
.groupAuthoritiesByUsername(JdbcUserDetailsManager.DEF_GROUP_AUTHORITIES_BY_USERNAME_QUERY)
.groupAuthoritiesByUsername(JdbcDaoImpl.DEF_GROUP_AUTHORITIES_BY_USERNAME_QUERY)
// jdbc-user-service@role-prefix
.rolePrefix("ROLE_");
// @formatter:on
}
static class CustomUserCache implements UserCache {
@@ -125,16 +139,22 @@ public class NamespaceJdbcUserServiceTests {
@Override
public void removeUserFromCache(String username) {
}
}
}
@Configuration
static class CustomDataSourceConfig {
@Bean
public DataSource dataSource() {
DataSource dataSource() {
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder()
// simulate that the DB already has the schema loaded and users in it
.addScript("CustomJdbcUserServiceSampleConfig.sql");
// simulate that the DB already has the schema loaded and users in it
.addScript("CustomJdbcUserServiceSampleConfig.sql");
return builder.setType(EmbeddedDatabaseType.HSQL).build();
}
}
}

View File

@@ -16,8 +16,11 @@
package org.springframework.security.config.annotation.authentication;
import javax.sql.DataSource;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
@@ -32,8 +35,6 @@ import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.test.web.servlet.MockMvc;
import javax.sql.DataSource;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.formLogin;
import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.authenticated;
@@ -51,80 +52,88 @@ public class NamespacePasswordEncoderTests {
@Test
public void passwordEncoderRefWithInMemory() throws Exception {
this.spring.register(PasswordEncoderWithInMemoryConfig.class).autowire();
this.mockMvc.perform(formLogin())
.andExpect(authenticated());
}
@EnableWebSecurity
static class PasswordEncoderWithInMemoryConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
auth
.inMemoryAuthentication()
.withUser("user").password(encoder.encode("password")).roles("USER").and()
.passwordEncoder(encoder);
}
this.mockMvc.perform(formLogin()).andExpect(authenticated());
}
@Test
public void passwordEncoderRefWithJdbc() throws Exception {
this.spring.register(PasswordEncoderWithJdbcConfig.class).autowire();
this.mockMvc.perform(formLogin()).andExpect(authenticated());
}
@Test
public void passwordEncoderRefWithUserDetailsService() throws Exception {
this.spring.register(PasswordEncoderWithUserDetailsServiceConfig.class).autowire();
this.mockMvc.perform(formLogin()).andExpect(authenticated());
}
@EnableWebSecurity
static class PasswordEncoderWithInMemoryConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
// @formatter:off
auth
.inMemoryAuthentication()
.withUser("user").password(encoder.encode("password")).roles("USER").and()
.passwordEncoder(encoder);
// @formatter:on
}
this.mockMvc.perform(formLogin())
.andExpect(authenticated());
}
@EnableWebSecurity
static class PasswordEncoderWithJdbcConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
// @formatter:off
auth
.jdbcAuthentication()
.withDefaultSchema()
.dataSource(dataSource())
.withUser("user").password(encoder.encode("password")).roles("USER").and()
.passwordEncoder(encoder);
// @formatter:on
}
@Bean
public DataSource dataSource() {
DataSource dataSource() {
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
return builder.setType(EmbeddedDatabaseType.HSQL).build();
}
}
@Test
public void passwordEncoderRefWithUserDetailsService() throws Exception {
this.spring.register(PasswordEncoderWithUserDetailsServiceConfig.class).autowire();
this.mockMvc.perform(formLogin())
.andExpect(authenticated());
}
@EnableWebSecurity
static class PasswordEncoderWithUserDetailsServiceConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
// @formatter:off
UserDetails user = User.withUsername("user")
.passwordEncoder(encoder::encode)
.password("password")
.roles("USER")
.build();
// @formatter:on
InMemoryUserDetailsManager uds = new InMemoryUserDetailsManager(user);
// @formatter:off
auth
.userDetailsService(uds)
.passwordEncoder(encoder);
// @formatter:on
}
@Bean
public DataSource dataSource() {
DataSource dataSource() {
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
return builder.setType(EmbeddedDatabaseType.HSQL).build();
}
}
}

View File

@@ -18,6 +18,7 @@ package org.springframework.security.config.annotation.authentication;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
@@ -47,52 +48,56 @@ public class PasswordEncoderConfigurerTests {
this.spring.register(PasswordEncoderConfig.class).autowire();
}
@Test
public void passwordEncoderRefWhenAuthenticationManagerBuilderThenAuthenticationSuccess() throws Exception {
this.spring.register(PasswordEncoderNoAuthManagerLoadsConfig.class).autowire();
this.mockMvc.perform(formLogin()).andExpect(authenticated());
}
@EnableWebSecurity
static class PasswordEncoderConfig extends WebSecurityConfigurerAdapter {
// @formatter:off
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
BCryptPasswordEncoder encoder = passwordEncoder();
// @formatter:off
auth
.inMemoryAuthentication()
.withUser("user").password(encoder.encode("password")).roles("USER").and()
.passwordEncoder(encoder);
// @formatter:on
}
// @formatter:on
@Override
protected void configure(HttpSecurity http) {
}
@Bean
public BCryptPasswordEncoder passwordEncoder() {
BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
@Test
public void passwordEncoderRefWhenAuthenticationManagerBuilderThenAuthenticationSuccess() throws Exception {
this.spring.register(PasswordEncoderNoAuthManagerLoadsConfig.class).autowire();
this.mockMvc.perform(formLogin())
.andExpect(authenticated());
}
@EnableWebSecurity
static class PasswordEncoderNoAuthManagerLoadsConfig extends
WebSecurityConfigurerAdapter {
// @formatter:off
static class PasswordEncoderNoAuthManagerLoadsConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
BCryptPasswordEncoder encoder = passwordEncoder();
// @formatter:off
auth
.inMemoryAuthentication()
.withUser("user").password(encoder.encode("password")).roles("USER").and()
.passwordEncoder(encoder);
// @formatter:on
}
// @formatter:on
@Bean
public BCryptPasswordEncoder passwordEncoder() {
BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
}

View File

@@ -18,6 +18,7 @@ package org.springframework.security.config.annotation.authentication.configurat
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
@@ -30,13 +31,14 @@ import org.springframework.security.config.MockEventListener;
import org.springframework.security.config.users.AuthenticationTestConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import static org.assertj.core.api.Assertions.*;
import static org.assertj.core.api.Assertions.assertThat;
/**
* @author Rob Winch
*/
@RunWith(SpringJUnit4ClassRunner.class)
public class AuthenticationConfigurationPublishTests {
@Autowired
MockEventListener<AuthenticationSuccessEvent> listener;
@@ -46,7 +48,6 @@ public class AuthenticationConfigurationPublishTests {
@Test
public void authenticationEventPublisherBeanUsedByDefault() {
this.authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("user", "password"));
assertThat(this.listener.getEvents()).hasSize(1);
}
@@ -58,6 +59,7 @@ public class AuthenticationConfigurationPublishTests {
@EnableGlobalAuthentication
@Import(AuthenticationTestConfiguration.class)
static class Config {
@Bean
AuthenticationEventPublisher publisher() {
return new DefaultAuthenticationEventPublisher();
@@ -65,8 +67,10 @@ public class AuthenticationConfigurationPublishTests {
@Bean
MockEventListener<AuthenticationSuccessEvent> eventListener() {
return new MockEventListener<AuthenticationSuccessEvent>(){};
return new MockEventListener<AuthenticationSuccessEvent>() {
};
}
}
}

View File

@@ -13,11 +13,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.authentication.configuration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.junit.After;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.aop.framework.ProxyFactoryBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
@@ -50,19 +56,20 @@ import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.PasswordEncodedUser;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsPasswordService;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.core.userdetails.UserDetailsPasswordService;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.Mockito.*;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.startsWith;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
public class AuthenticationConfigurationTests {
@@ -79,153 +86,87 @@ public class AuthenticationConfigurationTests {
@Test
public void orderingAutowiredOnEnableGlobalMethodSecurity() {
this.spring.register(AuthenticationTestConfiguration.class, GlobalMethodSecurityAutowiredConfig.class, ServicesConfig.class).autowire();
SecurityContextHolder.getContext().setAuthentication(new TestingAuthenticationToken("user", "password", "ROLE_USER"));
this.spring.register(AuthenticationTestConfiguration.class, GlobalMethodSecurityAutowiredConfig.class,
ServicesConfig.class).autowire();
SecurityContextHolder.getContext()
.setAuthentication(new TestingAuthenticationToken("user", "password", "ROLE_USER"));
this.service.run();
}
@EnableGlobalMethodSecurity(securedEnabled = true)
static class GlobalMethodSecurityAutowiredConfig {
}
@Test
public void orderingAutowiredOnEnableWebSecurity() {
this.spring.register(AuthenticationTestConfiguration.class, WebSecurityConfig.class, GlobalMethodSecurityAutowiredConfig.class, ServicesConfig.class).autowire();
SecurityContextHolder.getContext().setAuthentication(new TestingAuthenticationToken("user", "password", "ROLE_USER"));
this.spring.register(AuthenticationTestConfiguration.class, WebSecurityConfig.class,
GlobalMethodSecurityAutowiredConfig.class, ServicesConfig.class).autowire();
SecurityContextHolder.getContext()
.setAuthentication(new TestingAuthenticationToken("user", "password", "ROLE_USER"));
this.service.run();
}
@EnableWebSecurity
static class WebSecurityConfig {}
@Test
public void orderingAutowiredOnEnableWebMvcSecurity() {
this.spring.register(AuthenticationTestConfiguration.class, WebMvcSecurityConfig.class, GlobalMethodSecurityAutowiredConfig.class, ServicesConfig.class).autowire();
SecurityContextHolder.getContext().setAuthentication(new TestingAuthenticationToken("user", "password", "ROLE_USER"));
this.spring.register(AuthenticationTestConfiguration.class, WebMvcSecurityConfig.class,
GlobalMethodSecurityAutowiredConfig.class, ServicesConfig.class).autowire();
SecurityContextHolder.getContext()
.setAuthentication(new TestingAuthenticationToken("user", "password", "ROLE_USER"));
this.service.run();
}
@EnableWebMvcSecurity
static class WebMvcSecurityConfig {}
@Test
public void getAuthenticationManagerWhenNoAuthenticationThenNull() throws Exception {
this.spring.register(AuthenticationConfiguration.class, ObjectPostProcessorConfiguration.class).autowire();
assertThat(this.spring.getContext().getBean(AuthenticationConfiguration.class).getAuthenticationManager()).isNull();
assertThat(this.spring.getContext().getBean(AuthenticationConfiguration.class).getAuthenticationManager())
.isNull();
}
@Test
public void getAuthenticationManagerWhenNoOpGlobalAuthenticationConfigurerAdapterThenNull() throws Exception {
this.spring.register(AuthenticationConfiguration.class, ObjectPostProcessorConfiguration.class, NoOpGlobalAuthenticationConfigurerAdapter.class).autowire();
assertThat(this.spring.getContext().getBean(AuthenticationConfiguration.class).getAuthenticationManager()).isNull();
this.spring.register(AuthenticationConfiguration.class, ObjectPostProcessorConfiguration.class,
NoOpGlobalAuthenticationConfigurerAdapter.class).autowire();
assertThat(this.spring.getContext().getBean(AuthenticationConfiguration.class).getAuthenticationManager())
.isNull();
}
@Configuration
static class NoOpGlobalAuthenticationConfigurerAdapter extends GlobalAuthenticationConfigurerAdapter {}
@Test
public void getAuthenticationWhenGlobalAuthenticationConfigurerAdapterThenAuthenticates() throws Exception {
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("user", "password");
this.spring.register(AuthenticationConfiguration.class, ObjectPostProcessorConfiguration.class, UserGlobalAuthenticationConfigurerAdapter.class).autowire();
AuthenticationManager authentication = this.spring.getContext().getBean(AuthenticationConfiguration.class).getAuthenticationManager();
this.spring.register(AuthenticationConfiguration.class, ObjectPostProcessorConfiguration.class,
UserGlobalAuthenticationConfigurerAdapter.class).autowire();
AuthenticationManager authentication = this.spring.getContext().getBean(AuthenticationConfiguration.class)
.getAuthenticationManager();
assertThat(authentication.authenticate(token).getName()).isEqualTo(token.getName());
}
@Configuration
static class UserGlobalAuthenticationConfigurerAdapter extends GlobalAuthenticationConfigurerAdapter {
public void init(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser(PasswordEncodedUser.user());
}
}
@Test
public void getAuthenticationWhenAuthenticationManagerBeanThenAuthenticates() throws Exception {
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("user", "password");
this.spring.register(AuthenticationConfiguration.class, ObjectPostProcessorConfiguration.class, AuthenticationManagerBeanConfig.class).autowire();
AuthenticationManager authentication = this.spring.getContext().getBean(AuthenticationConfiguration.class).getAuthenticationManager();
when(authentication.authenticate(token)).thenReturn(TestAuthentication.authenticatedUser());
this.spring.register(AuthenticationConfiguration.class, ObjectPostProcessorConfiguration.class,
AuthenticationManagerBeanConfig.class).autowire();
AuthenticationManager authentication = this.spring.getContext().getBean(AuthenticationConfiguration.class)
.getAuthenticationManager();
given(authentication.authenticate(token)).willReturn(TestAuthentication.authenticatedUser());
assertThat(authentication.authenticate(token).getName()).isEqualTo(token.getName());
}
@Configuration
static class AuthenticationManagerBeanConfig {
AuthenticationManager authenticationManager = mock(AuthenticationManager.class);
@Bean
public AuthenticationManager authenticationManager() {
return this.authenticationManager;
}
@Test
public void getAuthenticationWhenMultipleThenOrdered() throws Exception {
this.spring.register(AuthenticationConfiguration.class, ObjectPostProcessorConfiguration.class,
AuthenticationManagerBeanConfig.class).autowire();
AuthenticationConfiguration config = this.spring.getContext().getBean(AuthenticationConfiguration.class);
config.setGlobalAuthenticationConfigurers(Arrays.asList(new LowestOrderGlobalAuthenticationConfigurerAdapter(),
new HighestOrderGlobalAuthenticationConfigurerAdapter(),
new DefaultOrderGlobalAuthenticationConfigurerAdapter()));
}
//
// //
//
@Configuration
static class ServicesConfig {
@Bean
public Service service() {
return new ServiceImpl();
}
}
interface Service {
void run();
}
static class ServiceImpl implements Service {
@Secured("ROLE_USER")
public void run() {}
}
@Test
public void getAuthenticationWhenMultipleThenOrdered() throws Exception {
this.spring.register(AuthenticationConfiguration.class, ObjectPostProcessorConfiguration.class, AuthenticationManagerBeanConfig.class).autowire();
AuthenticationConfiguration config = this.spring.getContext().getBean(AuthenticationConfiguration.class);
config.setGlobalAuthenticationConfigurers(Arrays.asList(new LowestOrderGlobalAuthenticationConfigurerAdapter(), new HighestOrderGlobalAuthenticationConfigurerAdapter(), new DefaultOrderGlobalAuthenticationConfigurerAdapter()));
}
static class DefaultOrderGlobalAuthenticationConfigurerAdapter extends GlobalAuthenticationConfigurerAdapter {
static List<Class<?>> inits = new ArrayList<>();
static List<Class<?>> configs = new ArrayList<>();
public void init(AuthenticationManagerBuilder auth) throws Exception {
inits.add(getClass());
}
public void configure(AuthenticationManagerBuilder auth) {
configs.add(getClass());
}
}
@Order(Ordered.LOWEST_PRECEDENCE)
static class LowestOrderGlobalAuthenticationConfigurerAdapter extends DefaultOrderGlobalAuthenticationConfigurerAdapter {}
@Order(Ordered.HIGHEST_PRECEDENCE)
static class HighestOrderGlobalAuthenticationConfigurerAdapter extends DefaultOrderGlobalAuthenticationConfigurerAdapter {}
@Test
public void getAuthenticationWhenConfiguredThenBootNotTrigger() throws Exception {
this.spring.register(AuthenticationConfiguration.class, ObjectPostProcessorConfiguration.class).autowire();
AuthenticationConfiguration config = this.spring.getContext().getBean(AuthenticationConfiguration.class);
config.setGlobalAuthenticationConfigurers(Arrays.asList(new ConfiguresInMemoryConfigurerAdapter(), new BootGlobalAuthenticationConfigurerAdapter()));
config.setGlobalAuthenticationConfigurers(Arrays.asList(new ConfiguresInMemoryConfigurerAdapter(),
new BootGlobalAuthenticationConfigurerAdapter()));
AuthenticationManager authenticationManager = config.getAuthenticationManager();
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("user", "password"));
assertThatThrownBy(() -> authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("boot", "password")))
.isInstanceOf(AuthenticationException.class);
assertThatExceptionOfType(AuthenticationException.class).isThrownBy(
() -> authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("boot", "password")));
}
@Test
@@ -234,154 +175,332 @@ public class AuthenticationConfigurationTests {
AuthenticationConfiguration config = this.spring.getContext().getBean(AuthenticationConfiguration.class);
config.setGlobalAuthenticationConfigurers(Arrays.asList(new BootGlobalAuthenticationConfigurerAdapter()));
AuthenticationManager authenticationManager = config.getAuthenticationManager();
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("boot", "password"));
}
static class ConfiguresInMemoryConfigurerAdapter extends GlobalAuthenticationConfigurerAdapter {
public void init(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser(PasswordEncodedUser.user());
}
}
@Order(Ordered.LOWEST_PRECEDENCE)
static class BootGlobalAuthenticationConfigurerAdapter extends DefaultOrderGlobalAuthenticationConfigurerAdapter {
public void init(AuthenticationManagerBuilder auth) throws Exception {
auth.apply(new DefaultBootGlobalAuthenticationConfigurerAdapter());
}
}
static class DefaultBootGlobalAuthenticationConfigurerAdapter extends DefaultOrderGlobalAuthenticationConfigurerAdapter {
@Override
public void configure(AuthenticationManagerBuilder auth) {
if (auth.isConfigured()) {
return;
}
UserDetails user = User.withUserDetails(PasswordEncodedUser.user()).username("boot").build();
List<UserDetails> users = Arrays.asList(user);
InMemoryUserDetailsManager inMemory = new InMemoryUserDetailsManager(users);
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setUserDetailsService(inMemory);
auth.authenticationProvider(provider);
}
}
// gh-2531
@Test
public void getAuthenticationManagerWhenPostProcessThenUsesBeanClassLoaderOnProxyFactoryBean() throws Exception {
this.spring.register(Sec2531Config.class).autowire();
ObjectPostProcessor<Object> opp = this.spring.getContext().getBean(ObjectPostProcessor.class);
when(opp.postProcess(any())).thenAnswer(a -> a.getArgument(0));
given(opp.postProcess(any())).willAnswer((a) -> a.getArgument(0));
AuthenticationConfiguration config = this.spring.getContext().getBean(AuthenticationConfiguration.class);
config.getAuthenticationManager();
verify(opp).postProcess(any(ProxyFactoryBean.class));
}
@Test
public void getAuthenticationManagerWhenSec2822ThenCannotForceAuthenticationAlreadyBuilt() throws Exception {
this.spring.register(Sec2822WebSecurity.class, Sec2822UseAuth.class, Sec2822Config.class).autowire();
this.spring.getContext().getBean(AuthenticationConfiguration.class).getAuthenticationManager();
// no exception
}
// sec-2868
@Test
public void getAuthenticationWhenUserDetailsServiceBeanThenAuthenticationManagerUsesUserDetailsServiceBean()
throws Exception {
this.spring.register(UserDetailsServiceBeanConfig.class).autowire();
UserDetailsService uds = this.spring.getContext().getBean(UserDetailsService.class);
AuthenticationManager am = this.spring.getContext().getBean(AuthenticationConfiguration.class)
.getAuthenticationManager();
given(uds.loadUserByUsername("user")).willReturn(PasswordEncodedUser.user(), PasswordEncodedUser.user());
am.authenticate(new UsernamePasswordAuthenticationToken("user", "password"));
assertThatExceptionOfType(AuthenticationException.class)
.isThrownBy(() -> am.authenticate(new UsernamePasswordAuthenticationToken("user", "invalid")));
}
@Test
public void getAuthenticationWhenUserDetailsServiceAndPasswordEncoderBeanThenEncoderUsed() throws Exception {
UserDetails user = new User("user", "$2a$10$FBAKClV1zBIOOC9XMXf3AO8RoGXYVYsfvUdoLxGkd/BnXEn4tqT3u",
AuthorityUtils.createAuthorityList("ROLE_USER"));
this.spring.register(UserDetailsServiceBeanWithPasswordEncoderConfig.class).autowire();
UserDetailsService uds = this.spring.getContext().getBean(UserDetailsService.class);
AuthenticationManager am = this.spring.getContext().getBean(AuthenticationConfiguration.class)
.getAuthenticationManager();
given(uds.loadUserByUsername("user")).willReturn(User.withUserDetails(user).build(),
User.withUserDetails(user).build());
am.authenticate(new UsernamePasswordAuthenticationToken("user", "password"));
assertThatExceptionOfType(AuthenticationException.class)
.isThrownBy(() -> am.authenticate(new UsernamePasswordAuthenticationToken("user", "invalid")));
}
@Test
public void getAuthenticationWhenUserDetailsServiceAndPasswordManagerThenManagerUsed() throws Exception {
UserDetails user = new User("user", "{noop}password", AuthorityUtils.createAuthorityList("ROLE_USER"));
this.spring.register(UserDetailsPasswordManagerBeanConfig.class).autowire();
UserDetailsPasswordManagerBeanConfig.Manager manager = this.spring.getContext()
.getBean(UserDetailsPasswordManagerBeanConfig.Manager.class);
AuthenticationManager am = this.spring.getContext().getBean(AuthenticationConfiguration.class)
.getAuthenticationManager();
given(manager.loadUserByUsername("user")).willReturn(User.withUserDetails(user).build(),
User.withUserDetails(user).build());
given(manager.updatePassword(any(), any())).willReturn(user);
am.authenticate(new UsernamePasswordAuthenticationToken("user", "password"));
verify(manager).updatePassword(eq(user), startsWith("{bcrypt}"));
}
@Test
public void getAuthenticationWhenAuthenticationProviderAndUserDetailsBeanThenAuthenticationProviderUsed()
throws Exception {
this.spring.register(AuthenticationProviderBeanAndUserDetailsServiceConfig.class).autowire();
AuthenticationProvider ap = this.spring.getContext().getBean(AuthenticationProvider.class);
AuthenticationManager am = this.spring.getContext().getBean(AuthenticationConfiguration.class)
.getAuthenticationManager();
given(ap.supports(any())).willReturn(true);
given(ap.authenticate(any())).willReturn(TestAuthentication.authenticatedUser());
am.authenticate(new UsernamePasswordAuthenticationToken("user", "password"));
}
// gh-3091
@Test
public void getAuthenticationWhenAuthenticationProviderBeanThenUsed() throws Exception {
this.spring.register(AuthenticationProviderBeanConfig.class).autowire();
AuthenticationProvider ap = this.spring.getContext().getBean(AuthenticationProvider.class);
AuthenticationManager am = this.spring.getContext().getBean(AuthenticationConfiguration.class)
.getAuthenticationManager();
given(ap.supports(any())).willReturn(true);
given(ap.authenticate(any())).willReturn(TestAuthentication.authenticatedUser());
am.authenticate(new UsernamePasswordAuthenticationToken("user", "password"));
}
@Test
public void enableGlobalMethodSecurityWhenPreAuthorizeThenNoException() {
this.spring.register(UsesPreAuthorizeMethodSecurityConfig.class, AuthenticationManagerBeanConfig.class)
.autowire();
// no exception
}
@Test
public void enableGlobalMethodSecurityWhenPreAuthorizeThenUsesMethodSecurityService() {
this.spring.register(ServicesConfig.class, UsesPreAuthorizeMethodSecurityConfig.class,
AuthenticationManagerBeanConfig.class).autowire();
// no exception
}
@Test
public void getAuthenticationManagerBeanWhenMultipleDefinedAndOnePrimaryThenNoException() throws Exception {
this.spring.register(MultipleAuthenticationManagerBeanConfig.class).autowire();
this.spring.getContext().getBeanFactory().getBean(AuthenticationConfiguration.class).getAuthenticationManager();
}
@Test
public void getAuthenticationManagerWhenAuthenticationConfigurationSubclassedThenBuildsUsingBean()
throws Exception {
this.spring.register(AuthenticationConfigurationSubclass.class).autowire();
AuthenticationManagerBuilder ap = this.spring.getContext().getBean(AuthenticationManagerBuilder.class);
this.spring.getContext().getBean(AuthenticationConfiguration.class).getAuthenticationManager();
assertThatExceptionOfType(AlreadyBuiltException.class).isThrownBy(ap::build);
}
@EnableGlobalMethodSecurity(securedEnabled = true)
static class GlobalMethodSecurityAutowiredConfig {
}
@EnableWebSecurity
static class WebSecurityConfig {
}
@EnableWebMvcSecurity
static class WebMvcSecurityConfig {
}
@Configuration
static class NoOpGlobalAuthenticationConfigurerAdapter extends GlobalAuthenticationConfigurerAdapter {
}
@Configuration
static class UserGlobalAuthenticationConfigurerAdapter extends GlobalAuthenticationConfigurerAdapter {
@Override
public void init(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser(PasswordEncodedUser.user());
}
}
@Configuration
static class AuthenticationManagerBeanConfig {
AuthenticationManager authenticationManager = mock(AuthenticationManager.class);
@Bean
AuthenticationManager authenticationManager() {
return this.authenticationManager;
}
}
@Configuration
static class ServicesConfig {
@Bean
Service service() {
return new ServiceImpl();
}
}
interface Service {
void run();
}
static class ServiceImpl implements Service {
@Override
@Secured("ROLE_USER")
public void run() {
}
}
static class DefaultOrderGlobalAuthenticationConfigurerAdapter extends GlobalAuthenticationConfigurerAdapter {
static List<Class<?>> inits = new ArrayList<>();
static List<Class<?>> configs = new ArrayList<>();
@Override
public void init(AuthenticationManagerBuilder auth) throws Exception {
inits.add(getClass());
}
@Override
public void configure(AuthenticationManagerBuilder auth) {
configs.add(getClass());
}
}
@Order(Ordered.LOWEST_PRECEDENCE)
static class LowestOrderGlobalAuthenticationConfigurerAdapter
extends DefaultOrderGlobalAuthenticationConfigurerAdapter {
}
@Order(Ordered.HIGHEST_PRECEDENCE)
static class HighestOrderGlobalAuthenticationConfigurerAdapter
extends DefaultOrderGlobalAuthenticationConfigurerAdapter {
}
static class ConfiguresInMemoryConfigurerAdapter extends GlobalAuthenticationConfigurerAdapter {
@Override
public void init(AuthenticationManagerBuilder auth) throws Exception {
// @formatter:off
auth
.inMemoryAuthentication()
.withUser(PasswordEncodedUser.user());
// @formatter:on
}
}
@Order(Ordered.LOWEST_PRECEDENCE)
static class BootGlobalAuthenticationConfigurerAdapter extends DefaultOrderGlobalAuthenticationConfigurerAdapter {
@Override
public void init(AuthenticationManagerBuilder auth) throws Exception {
auth.apply(new DefaultBootGlobalAuthenticationConfigurerAdapter());
}
}
static class DefaultBootGlobalAuthenticationConfigurerAdapter
extends DefaultOrderGlobalAuthenticationConfigurerAdapter {
@Override
public void configure(AuthenticationManagerBuilder auth) {
if (auth.isConfigured()) {
return;
}
UserDetails user = User.withUserDetails(PasswordEncodedUser.user()).username("boot").build();
List<UserDetails> users = Arrays.asList(user);
InMemoryUserDetailsManager inMemory = new InMemoryUserDetailsManager(users);
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setUserDetailsService(inMemory);
auth.authenticationProvider(provider);
}
}
@Configuration
@Import(AuthenticationConfiguration.class)
static class Sec2531Config {
@Bean
public ObjectPostProcessor objectPostProcessor() {
ObjectPostProcessor objectPostProcessor() {
return mock(ObjectPostProcessor.class);
}
@Bean
public AuthenticationManager manager() {
AuthenticationManager manager() {
return null;
}
}
@Test
public void getAuthenticationManagerWhenSec2822ThenCannotForceAuthenticationAlreadyBuilt() throws Exception {
this.spring.register(Sec2822WebSecurity.class, Sec2822UseAuth.class, Sec2822Config.class).autowire();
this.spring.getContext().getBean(AuthenticationConfiguration.class).getAuthenticationManager();
// no exception
}
@Configuration
@Import(AuthenticationConfiguration.class)
static class Sec2822Config {}
static class Sec2822Config {
}
@Configuration
@EnableWebSecurity
static class Sec2822WebSecurity extends WebSecurityConfigurerAdapter {
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication();
}
}
@Configuration
static class Sec2822UseAuth {
@Autowired
public void useAuthenticationManager(AuthenticationConfiguration auth) throws Exception {
void useAuthenticationManager(AuthenticationConfiguration auth) throws Exception {
auth.getAuthenticationManager();
}
// Ensures that Sec2822UseAuth is initialized before Sec2822WebSecurity
// must have additional GlobalAuthenticationConfigurerAdapter to trigger SEC-2822
@Bean
public static GlobalAuthenticationConfigurerAdapter bootGlobalAuthenticationConfigurerAdapter() {
static GlobalAuthenticationConfigurerAdapter bootGlobalAuthenticationConfigurerAdapter() {
return new BootGlobalAuthenticationConfigurerAdapter();
}
static class BootGlobalAuthenticationConfigurerAdapter extends GlobalAuthenticationConfigurerAdapter { }
}
static class BootGlobalAuthenticationConfigurerAdapter extends GlobalAuthenticationConfigurerAdapter {
// sec-2868
@Test
public void getAuthenticationWhenUserDetailsServiceBeanThenAuthenticationManagerUsesUserDetailsServiceBean() throws Exception {
this.spring.register(UserDetailsServiceBeanConfig.class).autowire();
UserDetailsService uds = this.spring.getContext().getBean(UserDetailsService.class);
AuthenticationManager am = this.spring.getContext().getBean(AuthenticationConfiguration.class).getAuthenticationManager();
when(uds.loadUserByUsername("user")).thenReturn(PasswordEncodedUser.user(), PasswordEncodedUser.user());
}
am.authenticate(new UsernamePasswordAuthenticationToken("user", "password"));
assertThatThrownBy(() -> am.authenticate(new UsernamePasswordAuthenticationToken("user", "invalid")))
.isInstanceOf(AuthenticationException.class);
}
@Configuration
@Import({AuthenticationConfiguration.class, ObjectPostProcessorConfiguration.class})
@Import({ AuthenticationConfiguration.class, ObjectPostProcessorConfiguration.class })
static class UserDetailsServiceBeanConfig {
UserDetailsService uds = mock(UserDetailsService.class);
@Bean
UserDetailsService userDetailsService() {
return this.uds;
}
}
@Test
public void getAuthenticationWhenUserDetailsServiceAndPasswordEncoderBeanThenEncoderUsed() throws Exception {
UserDetails user = new User("user", "$2a$10$FBAKClV1zBIOOC9XMXf3AO8RoGXYVYsfvUdoLxGkd/BnXEn4tqT3u",
AuthorityUtils.createAuthorityList("ROLE_USER"));
this.spring.register(UserDetailsServiceBeanWithPasswordEncoderConfig.class).autowire();
UserDetailsService uds = this.spring.getContext().getBean(UserDetailsService.class);
AuthenticationManager am = this.spring.getContext().getBean(AuthenticationConfiguration.class).getAuthenticationManager();
when(uds.loadUserByUsername("user")).thenReturn(User.withUserDetails(user).build(), User.withUserDetails(user).build());
am.authenticate(new UsernamePasswordAuthenticationToken("user", "password"));
assertThatThrownBy(() -> am.authenticate(new UsernamePasswordAuthenticationToken("user", "invalid")))
.isInstanceOf(AuthenticationException.class);
}
@Configuration
@Import({AuthenticationConfiguration.class, ObjectPostProcessorConfiguration.class})
@Import({ AuthenticationConfiguration.class, ObjectPostProcessorConfiguration.class })
static class UserDetailsServiceBeanWithPasswordEncoderConfig {
UserDetailsService uds = mock(UserDetailsService.class);
@Bean
@@ -393,26 +512,13 @@ public class AuthenticationConfigurationTests {
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
@Test
public void getAuthenticationWhenUserDetailsServiceAndPasswordManagerThenManagerUsed() throws Exception {
UserDetails user = new User("user", "{noop}password",
AuthorityUtils.createAuthorityList("ROLE_USER"));
this.spring.register(UserDetailsPasswordManagerBeanConfig.class).autowire();
UserDetailsPasswordManagerBeanConfig.Manager manager = this.spring.getContext().getBean(UserDetailsPasswordManagerBeanConfig.Manager.class);
AuthenticationManager am = this.spring.getContext().getBean(AuthenticationConfiguration.class).getAuthenticationManager();
when(manager.loadUserByUsername("user")).thenReturn(User.withUserDetails(user).build(), User.withUserDetails(user).build());
when(manager.updatePassword(any(), any())).thenReturn(user);
am.authenticate(new UsernamePasswordAuthenticationToken("user", "password"));
verify(manager).updatePassword(eq(user), startsWith("{bcrypt}"));
}
@Configuration
@Import({AuthenticationConfiguration.class, ObjectPostProcessorConfiguration.class})
@Import({ AuthenticationConfiguration.class, ObjectPostProcessorConfiguration.class })
static class UserDetailsPasswordManagerBeanConfig {
Manager manager = mock(Manager.class);
@Bean
@@ -421,46 +527,28 @@ public class AuthenticationConfigurationTests {
}
interface Manager extends UserDetailsService, UserDetailsPasswordService {
}
}
//gh-3091
@Test
public void getAuthenticationWhenAuthenticationProviderBeanThenUsed() throws Exception {
this.spring.register(AuthenticationProviderBeanConfig.class).autowire();
AuthenticationProvider ap = this.spring.getContext().getBean(AuthenticationProvider.class);
AuthenticationManager am = this.spring.getContext().getBean(AuthenticationConfiguration.class).getAuthenticationManager();
when(ap.supports(any())).thenReturn(true);
when(ap.authenticate(any())).thenReturn(TestAuthentication.authenticatedUser());
am.authenticate(new UsernamePasswordAuthenticationToken("user", "password"));
}
@Configuration
@Import({AuthenticationConfiguration.class, ObjectPostProcessorConfiguration.class})
@Import({ AuthenticationConfiguration.class, ObjectPostProcessorConfiguration.class })
static class AuthenticationProviderBeanConfig {
AuthenticationProvider provider = mock(AuthenticationProvider.class);
@Bean
AuthenticationProvider authenticationProvider() {
return this.provider;
}
}
@Test
public void getAuthenticationWhenAuthenticationProviderAndUserDetailsBeanThenAuthenticationProviderUsed() throws Exception {
this.spring.register(AuthenticationProviderBeanAndUserDetailsServiceConfig.class).autowire();
AuthenticationProvider ap = this.spring.getContext().getBean(AuthenticationProvider.class);
AuthenticationManager am = this.spring.getContext().getBean(AuthenticationConfiguration.class).getAuthenticationManager();
when(ap.supports(any())).thenReturn(true);
when(ap.authenticate(any())).thenReturn(TestAuthentication.authenticatedUser());
am.authenticate(new UsernamePasswordAuthenticationToken("user", "password"));
}
@Configuration
@Import({AuthenticationConfiguration.class, ObjectPostProcessorConfiguration.class})
@Import({ AuthenticationConfiguration.class, ObjectPostProcessorConfiguration.class })
static class AuthenticationProviderBeanAndUserDetailsServiceConfig {
AuthenticationProvider provider = mock(AuthenticationProvider.class);
UserDetailsService uds = mock(UserDetailsService.class);
@@ -474,40 +562,26 @@ public class AuthenticationConfigurationTests {
AuthenticationProvider authenticationProvider() {
return this.provider;
}
}
@Test
public void enableGlobalMethodSecurityWhenPreAuthorizeThenNoException() {
this.spring.register(UsesPreAuthorizeMethodSecurityConfig.class, AuthenticationManagerBeanConfig.class).autowire();
// no exception
}
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
static class UsesPreAuthorizeMethodSecurityConfig {
@PreAuthorize("denyAll")
void run() {}
}
void run() {
}
@Test
public void enableGlobalMethodSecurityWhenPreAuthorizeThenUsesMethodSecurityService() {
this.spring.register(ServicesConfig.class, UsesPreAuthorizeMethodSecurityConfig.class, AuthenticationManagerBeanConfig.class).autowire();
// no exception
}
@Configuration
@EnableGlobalMethodSecurity(securedEnabled = true)
static class UsesServiceMethodSecurityConfig {
@Autowired
Service service;
}
@Test
public void getAuthenticationManagerBeanWhenMultipleDefinedAndOnePrimaryThenNoException() throws Exception {
this.spring.register(MultipleAuthenticationManagerBeanConfig.class).autowire();
this.spring.getContext().getBeanFactory().getBean(AuthenticationConfiguration.class).getAuthenticationManager();
}
@Configuration
@@ -516,30 +590,20 @@ public class AuthenticationConfigurationTests {
@Bean
@Primary
public AuthenticationManager manager1() {
AuthenticationManager manager1() {
return mock(AuthenticationManager.class);
}
@Bean
public AuthenticationManager manager2() {
AuthenticationManager manager2() {
return mock(AuthenticationManager.class);
}
}
@Test
public void getAuthenticationManagerWhenAuthenticationConfigurationSubclassedThenBuildsUsingBean()
throws Exception {
this.spring.register(AuthenticationConfigurationSubclass.class).autowire();
AuthenticationManagerBuilder ap = this.spring.getContext().getBean(AuthenticationManagerBuilder.class);
this.spring.getContext().getBean(AuthenticationConfiguration.class).getAuthenticationManager();
assertThatThrownBy(ap::build)
.isInstanceOf(AlreadyBuiltException.class);
}
@Configuration
static class AuthenticationConfigurationSubclass extends AuthenticationConfiguration {
}
}

View File

@@ -13,24 +13,26 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.authentication.configuration;
import static org.assertj.core.api.Assertions.assertThat;
package org.springframework.security.config.annotation.authentication.configuration;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.test.SpringTestRule;
import static org.assertj.core.api.Assertions.assertThat;
/**
*
* @author Rob Winch
*
*/
public class EnableGlobalAuthenticationTests {
@Rule
public final SpringTestRule spring = new SpringTestRule();
@@ -38,83 +40,87 @@ public class EnableGlobalAuthenticationTests {
@Test
public void authenticationConfigurationWhenGetAuthenticationManagerThenNotNull() throws Exception {
this.spring.register(Config.class).autowire();
AuthenticationConfiguration auth = spring.getContext().getBean(AuthenticationConfiguration.class);
AuthenticationConfiguration auth = this.spring.getContext().getBean(AuthenticationConfiguration.class);
assertThat(auth.getAuthenticationManager()).isNotNull();
}
@Test
public void enableGlobalAuthenticationWhenNoConfigurationAnnotationThenBeanProxyingEnabled() {
this.spring.register(BeanProxyEnabledByDefaultConfig.class).autowire();
Child childBean = this.spring.getContext().getBean(Child.class);
Parent parentBean = this.spring.getContext().getBean(Parent.class);
assertThat(parentBean.getChild()).isSameAs(childBean);
}
@Test
public void enableGlobalAuthenticationWhenProxyBeanMethodsFalseThenBeanProxyingDisabled() {
this.spring.register(BeanProxyDisabledConfig.class).autowire();
Child childBean = this.spring.getContext().getBean(Child.class);
Parent parentBean = this.spring.getContext().getBean(Parent.class);
assertThat(parentBean.getChild()).isNotSameAs(childBean);
}
@Configuration
@EnableGlobalAuthentication
static class Config {
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("user").password("password").roles("USER");
}
}
@Test
public void enableGlobalAuthenticationWhenNoConfigurationAnnotationThenBeanProxyingEnabled() {
this.spring.register(BeanProxyEnabledByDefaultConfig.class).autowire();
Child childBean = this.spring.getContext().getBean(Child.class);
Parent parentBean = this.spring.getContext().getBean(Parent.class);
assertThat(parentBean.getChild()).isSameAs(childBean);
}
@EnableGlobalAuthentication
static class BeanProxyEnabledByDefaultConfig {
@Bean
public Child child() {
Child child() {
return new Child();
}
@Bean
public Parent parent() {
Parent parent() {
return new Parent(child());
}
}
@Test
public void enableGlobalAuthenticationWhenProxyBeanMethodsFalseThenBeanProxyingDisabled() {
this.spring.register(BeanProxyDisabledConfig.class).autowire();
Child childBean = this.spring.getContext().getBean(Child.class);
Parent parentBean = this.spring.getContext().getBean(Parent.class);
assertThat(parentBean.getChild()).isNotSameAs(childBean);
}
@Configuration(proxyBeanMethods = false)
@EnableGlobalAuthentication
static class BeanProxyDisabledConfig {
@Bean
public Child child() {
Child child() {
return new Child();
}
@Bean
public Parent parent() {
Parent parent() {
return new Parent(child());
}
}
static class Parent {
private Child child;
Parent(Child child) {
this.child = child;
}
public Child getChild() {
return child;
Child getChild() {
return this.child;
}
}
static class Child {
Child() {
}
}
}

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.authentication.configurers.ldap;
import org.junit.Before;
@@ -24,21 +25,21 @@ import org.springframework.security.core.authority.mapping.SimpleAuthorityMapper
import static org.assertj.core.api.Assertions.assertThat;
public class LdapAuthenticationProviderConfigurerTest {
public class LdapAuthenticationProviderConfigurerTests {
private LdapAuthenticationProviderConfigurer<AuthenticationManagerBuilder> configurer;
@Before
public void setUp() {
configurer = new LdapAuthenticationProviderConfigurer<>();
this.configurer = new LdapAuthenticationProviderConfigurer<>();
}
// SEC-2557
@Test
public void getAuthoritiesMapper() throws Exception {
assertThat(configurer.getAuthoritiesMapper()).isInstanceOf(SimpleAuthorityMapper.class);
configurer.authoritiesMapper(new NullAuthoritiesMapper());
assertThat(configurer.getAuthoritiesMapper()).isInstanceOf(NullAuthoritiesMapper.class);
assertThat(this.configurer.getAuthoritiesMapper()).isInstanceOf(SimpleAuthorityMapper.class);
this.configurer.authoritiesMapper(new NullAuthoritiesMapper());
assertThat(this.configurer.getAuthoritiesMapper()).isInstanceOf(NullAuthoritiesMapper.class);
}
}

View File

@@ -16,44 +16,44 @@
package org.springframework.security.config.annotation.authentication.configurers.provisioning;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.Arrays;
import org.junit.Before;
import org.junit.Test;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import static org.assertj.core.api.Assertions.assertThat;
/**
*
* @author Rob Winch
* @author Adolfo Eloy
*/
* @author Rob Winch
* @author Adolfo Eloy
*/
public class UserDetailsManagerConfigurerTests {
private InMemoryUserDetailsManager userDetailsManager;
@Before
public void setup() {
userDetailsManager = new InMemoryUserDetailsManager();
this.userDetailsManager = new InMemoryUserDetailsManager();
}
@Test
public void allAttributesSupported() {
UserDetails userDetails = new UserDetailsManagerConfigurer<AuthenticationManagerBuilder,
InMemoryUserDetailsManagerConfigurer<AuthenticationManagerBuilder>>(userDetailsManager)
.withUser("user")
.password("password")
.roles("USER")
.disabled(true)
.accountExpired(true)
.accountLocked(true)
.credentialsExpired(true)
.build();
// @formatter:off
UserDetails userDetails = configurer()
.withUser("user")
.password("password")
.roles("USER")
.disabled(true)
.accountExpired(true)
.accountLocked(true)
.credentialsExpired(true)
.build();
// @formatter:on
assertThat(userDetails.getUsername()).isEqualTo("user");
assertThat(userDetails.getPassword()).isEqualTo("password");
assertThat(userDetails.getAuthorities().stream().findFirst().get().getAuthority()).isEqualTo("ROLE_USER");
@@ -66,42 +66,45 @@ public class UserDetailsManagerConfigurerTests {
@Test
public void authoritiesWithGrantedAuthorityWorks() {
SimpleGrantedAuthority authority = new SimpleGrantedAuthority("ROLE_USER");
UserDetails userDetails = new UserDetailsManagerConfigurer<AuthenticationManagerBuilder,
InMemoryUserDetailsManagerConfigurer<AuthenticationManagerBuilder>>(userDetailsManager)
.withUser("user")
// @formatter:off
UserDetails userDetails = configurer()
.withUser("user")
.password("password")
.authorities(authority)
.build();
// @formatter:on
assertThat(userDetails.getAuthorities().stream().findFirst().get()).isEqualTo(authority);
}
@Test
public void authoritiesWithStringAuthorityWorks() {
String authority = "ROLE_USER";
UserDetails userDetails = new UserDetailsManagerConfigurer<AuthenticationManagerBuilder,
InMemoryUserDetailsManagerConfigurer<AuthenticationManagerBuilder>>(userDetailsManager)
.withUser("user")
// @formatter:off
UserDetails userDetails = configurer()
.withUser("user")
.password("password")
.authorities(authority)
.build();
// @formatter:on
assertThat(userDetails.getAuthorities().stream().findFirst().get().getAuthority()).isEqualTo(authority);
}
@Test
public void authoritiesWithAListOfGrantedAuthorityWorks() {
SimpleGrantedAuthority authority = new SimpleGrantedAuthority("ROLE_USER");
UserDetails userDetails = new UserDetailsManagerConfigurer<AuthenticationManagerBuilder,
InMemoryUserDetailsManagerConfigurer<AuthenticationManagerBuilder>>(userDetailsManager)
.withUser("user")
// @formatter:off
UserDetails userDetails = configurer()
.withUser("user")
.password("password")
.authorities(Arrays.asList(authority))
.build();
// @formatter:on
assertThat(userDetails.getAuthorities().stream().findFirst().get()).isEqualTo(authority);
}
private UserDetailsManagerConfigurer<AuthenticationManagerBuilder, InMemoryUserDetailsManagerConfigurer<AuthenticationManagerBuilder>> configurer() {
return new UserDetailsManagerConfigurer<AuthenticationManagerBuilder, InMemoryUserDetailsManagerConfigurer<AuthenticationManagerBuilder>>(
this.userDetailsManager);
}
}

View File

@@ -13,13 +13,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.configuration;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
public class AroundMethodInterceptor implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
return String.valueOf(methodInvocation.proceed());
}
}

View File

@@ -13,10 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.configuration;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.DisposableBean;
@@ -33,16 +35,16 @@ import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.test.SpringTestRule;
import org.springframework.web.context.ServletContextAware;
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.isNotNull;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
/**
*
* @author Rob Winch
*/
public class AutowireBeanFactoryObjectPostProcessorTests {
@Rule
public final SpringTestRule spring = new SpringTestRule();
@@ -52,7 +54,6 @@ public class AutowireBeanFactoryObjectPostProcessorTests {
@Test
public void postProcessWhenApplicationContextAwareThenAwareInvoked() {
this.spring.register(Config.class).autowire();
ApplicationContextAware toPostProcess = mock(ApplicationContextAware.class);
this.objectObjectPostProcessor.postProcess(toPostProcess);
verify(toPostProcess).setApplicationContext(isNotNull());
@@ -61,17 +62,14 @@ public class AutowireBeanFactoryObjectPostProcessorTests {
@Test
public void postProcessWhenApplicationEventPublisherAwareThenAwareInvoked() {
this.spring.register(Config.class).autowire();
ApplicationEventPublisherAware toPostProcess = mock(ApplicationEventPublisherAware.class);
this.objectObjectPostProcessor.postProcess(toPostProcess);
verify(toPostProcess).setApplicationEventPublisher(isNotNull());
}
@Test
public void postProcessWhenBeanClassLoaderAwareThenAwareInvoked() {
this.spring.register(Config.class).autowire();
BeanClassLoaderAware toPostProcess = mock(BeanClassLoaderAware.class);
this.objectObjectPostProcessor.postProcess(toPostProcess);
verify(toPostProcess).setBeanClassLoader(isNotNull());
@@ -80,7 +78,6 @@ public class AutowireBeanFactoryObjectPostProcessorTests {
@Test
public void postProcessWhenBeanFactoryAwareThenAwareInvoked() {
this.spring.register(Config.class).autowire();
BeanFactoryAware toPostProcess = mock(BeanFactoryAware.class);
this.objectObjectPostProcessor.postProcess(toPostProcess);
verify(toPostProcess).setBeanFactory(isNotNull());
@@ -89,7 +86,6 @@ public class AutowireBeanFactoryObjectPostProcessorTests {
@Test
public void postProcessWhenEnvironmentAwareThenAwareInvoked() {
this.spring.register(Config.class).autowire();
EnvironmentAware toPostProcess = mock(EnvironmentAware.class);
this.objectObjectPostProcessor.postProcess(toPostProcess);
verify(toPostProcess).setEnvironment(isNotNull());
@@ -98,7 +94,6 @@ public class AutowireBeanFactoryObjectPostProcessorTests {
@Test
public void postProcessWhenMessageSourceAwareThenAwareInvoked() {
this.spring.register(Config.class).autowire();
MessageSourceAware toPostProcess = mock(MessageSourceAware.class);
this.objectObjectPostProcessor.postProcess(toPostProcess);
verify(toPostProcess).setMessageSource(isNotNull());
@@ -107,7 +102,6 @@ public class AutowireBeanFactoryObjectPostProcessorTests {
@Test
public void postProcessWhenServletContextAwareThenAwareInvoked() {
this.spring.register(Config.class).autowire();
ServletContextAware toPostProcess = mock(ServletContextAware.class);
this.objectObjectPostProcessor.postProcess(toPostProcess);
verify(toPostProcess).setServletContext(isNotNull());
@@ -116,62 +110,62 @@ public class AutowireBeanFactoryObjectPostProcessorTests {
@Test
public void postProcessWhenDisposableBeanThenAwareInvoked() throws Exception {
this.spring.register(Config.class).autowire();
DisposableBean toPostProcess = mock(DisposableBean.class);
this.objectObjectPostProcessor.postProcess(toPostProcess);
this.spring.getContext().close();
verify(toPostProcess).destroy();
}
@Configuration
static class Config {
@Bean
public ObjectPostProcessor objectPostProcessor(AutowireCapableBeanFactory beanFactory) {
return new AutowireBeanFactoryObjectPostProcessor(beanFactory);
}
}
@Test
public void postProcessWhenSmartInitializingSingletonThenAwareInvoked() {
this.spring.register(Config.class, SmartConfig.class).autowire();
SmartConfig config = this.spring.getContext().getBean(SmartConfig.class);
verify(config.toTest).afterSingletonsInstantiated();
}
@Configuration
static class SmartConfig {
SmartInitializingSingleton toTest = mock(SmartInitializingSingleton.class);
@Autowired
public void configure(ObjectPostProcessor<Object> p) {
p.postProcess(this.toTest);
}
}
@Test
// SEC-2382
public void autowireBeanFactoryWhenBeanNameAutoProxyCreatorThenWorks() {
this.spring.testConfigLocations("AutowireBeanFactoryObjectPostProcessorTests-aopconfig.xml").autowire();
MyAdvisedBean bean = this.spring.getContext().getBean(MyAdvisedBean.class);
assertThat(bean.doStuff()).isEqualTo("null");
}
@Configuration
static class WithBeanNameAutoProxyCreatorConfig {
static class Config {
@Bean
public ObjectPostProcessor objectPostProcessor(AutowireCapableBeanFactory beanFactory) {
ObjectPostProcessor objectPostProcessor(AutowireCapableBeanFactory beanFactory) {
return new AutowireBeanFactoryObjectPostProcessor(beanFactory);
}
}
@Configuration
static class SmartConfig {
SmartInitializingSingleton toTest = mock(SmartInitializingSingleton.class);
@Autowired
void configure(ObjectPostProcessor<Object> p) {
p.postProcess(this.toTest);
}
}
@Configuration
static class WithBeanNameAutoProxyCreatorConfig {
@Bean
ObjectPostProcessor objectPostProcessor(AutowireCapableBeanFactory beanFactory) {
return new AutowireBeanFactoryObjectPostProcessor(beanFactory);
}
@Autowired
public void configure(ObjectPostProcessor<Object> p) {
void configure(ObjectPostProcessor<Object> p) {
p.postProcess(new Object());
}
}
}

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.configuration;
public class MyAdvisedBean {
@@ -20,4 +21,5 @@ public class MyAdvisedBean {
public Object doStuff() {
return null;
}
}

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.issue50;
import javax.sql.DataSource;
@@ -38,6 +39,7 @@ import org.springframework.transaction.annotation.EnableTransactionManagement;
@EnableJpaRepositories("org.springframework.security.config.annotation.issue50.repo")
@EnableTransactionManagement
public class ApplicationConfig {
@Bean
public DataSource dataSource() {
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
@@ -50,12 +52,10 @@ public class ApplicationConfig {
vendorAdapter.setDatabase(Database.HSQL);
vendorAdapter.setGenerateDdl(true);
vendorAdapter.setShowSql(true);
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setJpaVendorAdapter(vendorAdapter);
factory.setPackagesToScan(User.class.getPackage().getName());
factory.setDataSource(dataSource());
return factory;
}
@@ -65,4 +65,5 @@ public class ApplicationConfig {
txManager.setEntityManagerFactory(entityManagerFactory().getObject());
return txManager;
}
}

View File

@@ -13,12 +13,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.issue50;
import javax.transaction.Transactional;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.AuthenticationManager;
@@ -33,8 +37,6 @@ import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;
import javax.transaction.Transactional;
import static org.assertj.core.api.Assertions.assertThat;
/**
@@ -43,8 +45,9 @@ import static org.assertj.core.api.Assertions.assertThat;
*/
@Transactional
@RunWith(SpringRunner.class)
@ContextConfiguration(classes = {ApplicationConfig.class, SecurityConfig.class})
@ContextConfiguration(classes = { ApplicationConfig.class, SecurityConfig.class })
public class Issue50Tests {
@Autowired
private AuthenticationManager authenticationManager;
@@ -53,7 +56,8 @@ public class Issue50Tests {
@Before
public void setup() {
SecurityContextHolder.getContext().setAuthentication(new TestingAuthenticationToken("test", null, "ROLE_ADMIN"));
SecurityContextHolder.getContext()
.setAuthentication(new TestingAuthenticationToken("test", null, "ROLE_ADMIN"));
}
@After
@@ -82,7 +86,7 @@ public class Issue50Tests {
public void authenticateWhenValidUserThenAuthenticates() {
this.userRepo.save(User.withUsernameAndPassword("test", "password"));
Authentication result = this.authenticationManager
.authenticate(new UsernamePasswordAuthenticationToken("test", "password"));
.authenticate(new UsernamePasswordAuthenticationToken("test", "password"));
assertThat(result.getName()).isEqualTo("test");
}
@@ -91,6 +95,7 @@ public class Issue50Tests {
SecurityContextHolder.getContext().setAuthentication(new TestingAuthenticationToken("test", null, "ROLE_USER"));
this.userRepo.save(User.withUsernameAndPassword("denied", "password"));
Authentication result = this.authenticationManager
.authenticate(new UsernamePasswordAuthenticationToken("test", "password"));
.authenticate(new UsernamePasswordAuthenticationToken("test", "password"));
}
}

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.issue50;
import org.springframework.beans.factory.annotation.Autowired;
@@ -42,25 +43,26 @@ import org.springframework.util.Assert;
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserRepository myUserRepository;
// @formatter:off
@Override
protected void configure(AuthenticationManagerBuilder auth) {
// @formatter:off
auth
.authenticationProvider(authenticationProvider());
// @formatter:on
}
// @formatter:on
// @formatter:off
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.authorizeRequests()
.antMatchers("/*").permitAll();
// @formatter:on
}
// @formatter:on
@Bean
@Override
@@ -70,20 +72,20 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
public AuthenticationProvider authenticationProvider() {
Assert.notNull(myUserRepository);
Assert.notNull(this.myUserRepository);
return new AuthenticationProvider() {
@Override
public boolean supports(Class<?> authentication) {
return true;
}
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
Object principal = authentication.getPrincipal();
String username = String.valueOf(principal);
User user = myUserRepository.findByUsername(username);
User user = SecurityConfig.this.myUserRepository.findByUsername(username);
if (user == null) {
throw new UsernameNotFoundException("No user for principal "
+ principal);
throw new UsernameNotFoundException("No user for principal " + principal);
}
if (!authentication.getCredentials().equals(user.getPassword())) {
throw new BadCredentialsException("Invalid password");
@@ -92,4 +94,5 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
}
};
}
}

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.issue50.domain;
import javax.persistence.Entity;
@@ -36,7 +37,7 @@ public class User {
private String password;
public Long getId() {
return id;
return this.id;
}
public void setId(Long id) {
@@ -44,7 +45,7 @@ public class User {
}
public String getUsername() {
return username;
return this.username;
}
public void setUsername(String username) {
@@ -52,7 +53,7 @@ public class User {
}
public String getPassword() {
return password;
return this.password;
}
public void setPassword(String password) {
@@ -63,6 +64,7 @@ public class User {
User user = new User();
user.setUsername(username);
user.setPassword(password);
return user;
return user;
}
}

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.issue50.repo;
import org.springframework.data.repository.CrudRepository;
@@ -27,4 +28,5 @@ public interface UserRepository extends CrudRepository<User, String> {
@PreAuthorize("hasRole('ROLE_ADMIN')")
User findByUsername(String username);
}
}

View File

@@ -35,7 +35,7 @@ public class Authz {
}
public boolean check(Authentication authentication, String message) {
return message != null &&
message.contains(authentication.getName());
return message != null && message.contains(authentication.getName());
}
}

View File

@@ -13,15 +13,18 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.method.configuration;
import org.reactivestreams.Publisher;
import org.springframework.security.access.prepost.PostAuthorize;
import org.springframework.security.access.prepost.PreAuthorize;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import org.springframework.security.access.prepost.PostAuthorize;
import org.springframework.security.access.prepost.PreAuthorize;
public class DelegatingReactiveMessageService implements ReactiveMessageService {
private final ReactiveMessageService delegate;
public DelegatingReactiveMessageService(ReactiveMessageService delegate) {
@@ -36,100 +39,89 @@ public class DelegatingReactiveMessageService implements ReactiveMessageService
@Override
public Mono<String> monoFindById(long id) {
return delegate.monoFindById(id);
return this.delegate.monoFindById(id);
}
@Override
@PreAuthorize("hasRole('ADMIN')")
public Mono<String> monoPreAuthorizeHasRoleFindById(
long id) {
return delegate.monoPreAuthorizeHasRoleFindById(id);
public Mono<String> monoPreAuthorizeHasRoleFindById(long id) {
return this.delegate.monoPreAuthorizeHasRoleFindById(id);
}
@Override
@PostAuthorize("returnObject?.contains(authentication?.name)")
public Mono<String> monoPostAuthorizeFindById(
long id) {
return delegate.monoPostAuthorizeFindById(id);
public Mono<String> monoPostAuthorizeFindById(long id) {
return this.delegate.monoPostAuthorizeFindById(id);
}
@Override
@PreAuthorize("@authz.check(#id)")
public Mono<String> monoPreAuthorizeBeanFindById(
long id) {
return delegate.monoPreAuthorizeBeanFindById(id);
public Mono<String> monoPreAuthorizeBeanFindById(long id) {
return this.delegate.monoPreAuthorizeBeanFindById(id);
}
@Override
@PostAuthorize("@authz.check(authentication, returnObject)")
public Mono<String> monoPostAuthorizeBeanFindById(
long id) {
return delegate.monoPostAuthorizeBeanFindById(id);
public Mono<String> monoPostAuthorizeBeanFindById(long id) {
return this.delegate.monoPostAuthorizeBeanFindById(id);
}
@Override
public Flux<String> fluxFindById(long id) {
return delegate.fluxFindById(id);
return this.delegate.fluxFindById(id);
}
@Override
@PreAuthorize("hasRole('ADMIN')")
public Flux<String> fluxPreAuthorizeHasRoleFindById(
long id) {
return delegate.fluxPreAuthorizeHasRoleFindById(id);
public Flux<String> fluxPreAuthorizeHasRoleFindById(long id) {
return this.delegate.fluxPreAuthorizeHasRoleFindById(id);
}
@Override
@PostAuthorize("returnObject?.contains(authentication?.name)")
public Flux<String> fluxPostAuthorizeFindById(
long id) {
return delegate.fluxPostAuthorizeFindById(id);
public Flux<String> fluxPostAuthorizeFindById(long id) {
return this.delegate.fluxPostAuthorizeFindById(id);
}
@Override
@PreAuthorize("@authz.check(#id)")
public Flux<String> fluxPreAuthorizeBeanFindById(
long id) {
return delegate.fluxPreAuthorizeBeanFindById(id);
public Flux<String> fluxPreAuthorizeBeanFindById(long id) {
return this.delegate.fluxPreAuthorizeBeanFindById(id);
}
@Override
@PostAuthorize("@authz.check(authentication, returnObject)")
public Flux<String> fluxPostAuthorizeBeanFindById(
long id) {
return delegate.fluxPostAuthorizeBeanFindById(id);
public Flux<String> fluxPostAuthorizeBeanFindById(long id) {
return this.delegate.fluxPostAuthorizeBeanFindById(id);
}
@Override
public Publisher<String> publisherFindById(long id) {
return delegate.publisherFindById(id);
return this.delegate.publisherFindById(id);
}
@Override
@PreAuthorize("hasRole('ADMIN')")
public Publisher<String> publisherPreAuthorizeHasRoleFindById(
long id) {
return delegate.publisherPreAuthorizeHasRoleFindById(id);
public Publisher<String> publisherPreAuthorizeHasRoleFindById(long id) {
return this.delegate.publisherPreAuthorizeHasRoleFindById(id);
}
@Override
@PostAuthorize("returnObject?.contains(authentication?.name)")
public Publisher<String> publisherPostAuthorizeFindById(
long id) {
return delegate.publisherPostAuthorizeFindById(id);
public Publisher<String> publisherPostAuthorizeFindById(long id) {
return this.delegate.publisherPostAuthorizeFindById(id);
}
@Override
@PreAuthorize("@authz.check(#id)")
public Publisher<String> publisherPreAuthorizeBeanFindById(
long id) {
return delegate.publisherPreAuthorizeBeanFindById(id);
public Publisher<String> publisherPreAuthorizeBeanFindById(long id) {
return this.delegate.publisherPreAuthorizeBeanFindById(id);
}
@Override
@PostAuthorize("@authz.check(authentication, returnObject)")
public Publisher<String> publisherPostAuthorizeBeanFindById(
long id) {
return delegate.publisherPostAuthorizeBeanFindById(id);
public Publisher<String> publisherPostAuthorizeBeanFindById(long id) {
return this.delegate.publisherPostAuthorizeBeanFindById(id);
}
}

View File

@@ -16,11 +16,16 @@
package org.springframework.security.config.annotation.method.configuration;
import org.assertj.core.api.AssertionsForClassTypes;
import org.junit.After;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.reactivestreams.Publisher;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
import reactor.test.publisher.TestPublisher;
import reactor.util.context.Context;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.access.AccessDeniedException;
@@ -28,14 +33,12 @@ import org.springframework.security.authentication.TestingAuthenticationToken;
import org.springframework.security.core.context.ReactiveSecurityContextHolder;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
import reactor.test.publisher.TestPublisher;
import reactor.util.context.Context;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.Mockito.*;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset;
/**
* @author Rob Winch
@@ -44,16 +47,23 @@ import static org.mockito.Mockito.*;
@RunWith(SpringRunner.class)
@ContextConfiguration
public class EnableReactiveMethodSecurityTests {
@Autowired ReactiveMessageService messageService;
@Autowired
ReactiveMessageService messageService;
ReactiveMessageService delegate;
TestPublisher<String> result = TestPublisher.create();
Context withAdmin = ReactiveSecurityContextHolder.withAuthentication(new TestingAuthenticationToken("admin", "password", "ROLE_USER", "ROLE_ADMIN"));
Context withUser = ReactiveSecurityContextHolder.withAuthentication(new TestingAuthenticationToken("user", "password", "ROLE_USER"));
Context withAdmin = ReactiveSecurityContextHolder
.withAuthentication(new TestingAuthenticationToken("admin", "password", "ROLE_USER", "ROLE_ADMIN"));
Context withUser = ReactiveSecurityContextHolder
.withAuthentication(new TestingAuthenticationToken("user", "password", "ROLE_USER"));
@After
public void cleanup() {
reset(delegate);
reset(this.delegate);
}
@Autowired
@@ -63,516 +73,332 @@ public class EnableReactiveMethodSecurityTests {
@Test
public void notPublisherPreAuthorizeFindByIdThenThrowsIllegalStateException() {
assertThatThrownBy(() -> this.messageService.notPublisherPreAuthorizeFindById(1L))
.isInstanceOf(IllegalStateException.class)
.extracting(Throwable::getMessage)
.isEqualTo("The returnType class java.lang.String on public abstract java.lang.String org.springframework.security.config.annotation.method.configuration.ReactiveMessageService.notPublisherPreAuthorizeFindById(long) must return an instance of org.reactivestreams.Publisher (i.e. Mono / Flux) in order to support Reactor Context");
assertThatIllegalStateException().isThrownBy(() -> this.messageService.notPublisherPreAuthorizeFindById(1L))
.withMessage("The returnType class java.lang.String on public abstract java.lang.String "
+ "org.springframework.security.config.annotation.method.configuration.ReactiveMessageService"
+ ".notPublisherPreAuthorizeFindById(long) must return an instance of org.reactivestreams"
+ ".Publisher (i.e. Mono / Flux) in order to support Reactor Context");
}
@Test
public void monoWhenPermitAllThenAopDoesNotSubscribe() {
when(this.delegate.monoFindById(1L)).thenReturn(Mono.from(result));
given(this.delegate.monoFindById(1L)).willReturn(Mono.from(this.result));
this.delegate.monoFindById(1L);
result.assertNoSubscribers();
this.result.assertNoSubscribers();
}
@Test
public void monoWhenPermitAllThenSuccess() {
when(this.delegate.monoFindById(1L)).thenReturn(Mono.just("success"));
StepVerifier.create(this.delegate.monoFindById(1L))
.expectNext("success")
.verifyComplete();
given(this.delegate.monoFindById(1L)).willReturn(Mono.just("success"));
StepVerifier.create(this.delegate.monoFindById(1L)).expectNext("success").verifyComplete();
}
@Test
public void monoPreAuthorizeHasRoleWhenGrantedThenSuccess() {
when(this.delegate.monoPreAuthorizeHasRoleFindById(1L)).thenReturn(Mono.just("result"));
given(this.delegate.monoPreAuthorizeHasRoleFindById(1L)).willReturn(Mono.just("result"));
Mono<String> findById = this.messageService.monoPreAuthorizeHasRoleFindById(1L)
.subscriberContext(withAdmin);
StepVerifier
.create(findById)
.expectNext("result")
.verifyComplete();
.subscriberContext(this.withAdmin);
StepVerifier.create(findById).expectNext("result").verifyComplete();
}
@Test
public void monoPreAuthorizeHasRoleWhenNoAuthenticationThenDenied() {
when(this.delegate.monoPreAuthorizeHasRoleFindById(1L)).thenReturn(Mono.from(result));
given(this.delegate.monoPreAuthorizeHasRoleFindById(1L)).willReturn(Mono.from(this.result));
Mono<String> findById = this.messageService.monoPreAuthorizeHasRoleFindById(1L);
StepVerifier
.create(findById)
.expectError(AccessDeniedException.class)
.verify();
result.assertNoSubscribers();
StepVerifier.create(findById).expectError(AccessDeniedException.class).verify();
this.result.assertNoSubscribers();
}
@Test
public void monoPreAuthorizeHasRoleWhenNotAuthorizedThenDenied() {
when(this.delegate.monoPreAuthorizeHasRoleFindById(1L)).thenReturn(Mono.from(result));
given(this.delegate.monoPreAuthorizeHasRoleFindById(1L)).willReturn(Mono.from(this.result));
Mono<String> findById = this.messageService.monoPreAuthorizeHasRoleFindById(1L)
.subscriberContext(withUser);
StepVerifier
.create(findById)
.expectError(AccessDeniedException.class)
.verify();
result.assertNoSubscribers();
.subscriberContext(this.withUser);
StepVerifier.create(findById).expectError(AccessDeniedException.class).verify();
this.result.assertNoSubscribers();
}
@Test
public void monoPreAuthorizeBeanWhenGrantedThenSuccess() {
when(this.delegate.monoPreAuthorizeBeanFindById(2L)).thenReturn(Mono.just("result"));
Mono<String> findById = this.messageService.monoPreAuthorizeBeanFindById(2L)
.subscriberContext(withAdmin);
StepVerifier
.create(findById)
.expectNext("result")
.verifyComplete();
given(this.delegate.monoPreAuthorizeBeanFindById(2L)).willReturn(Mono.just("result"));
Mono<String> findById = this.messageService.monoPreAuthorizeBeanFindById(2L).subscriberContext(this.withAdmin);
StepVerifier.create(findById).expectNext("result").verifyComplete();
}
@Test
public void monoPreAuthorizeBeanWhenNotAuthenticatedAndGrantedThenSuccess() {
when(this.delegate.monoPreAuthorizeBeanFindById(2L)).thenReturn(Mono.just("result"));
given(this.delegate.monoPreAuthorizeBeanFindById(2L)).willReturn(Mono.just("result"));
Mono<String> findById = this.messageService.monoPreAuthorizeBeanFindById(2L);
StepVerifier
.create(findById)
.expectNext("result")
.verifyComplete();
StepVerifier.create(findById).expectNext("result").verifyComplete();
}
@Test
public void monoPreAuthorizeBeanWhenNoAuthenticationThenDenied() {
when(this.delegate.monoPreAuthorizeBeanFindById(1L)).thenReturn(Mono.from(result));
given(this.delegate.monoPreAuthorizeBeanFindById(1L)).willReturn(Mono.from(this.result));
Mono<String> findById = this.messageService.monoPreAuthorizeBeanFindById(1L);
StepVerifier
.create(findById)
.expectError(AccessDeniedException.class)
.verify();
result.assertNoSubscribers();
StepVerifier.create(findById).expectError(AccessDeniedException.class).verify();
this.result.assertNoSubscribers();
}
@Test
public void monoPreAuthorizeBeanWhenNotAuthorizedThenDenied() {
when(this.delegate.monoPreAuthorizeBeanFindById(1L)).thenReturn(Mono.from(result));
Mono<String> findById = this.messageService.monoPreAuthorizeBeanFindById(1L)
.subscriberContext(withUser);
StepVerifier
.create(findById)
.expectError(AccessDeniedException.class)
.verify();
result.assertNoSubscribers();
given(this.delegate.monoPreAuthorizeBeanFindById(1L)).willReturn(Mono.from(this.result));
Mono<String> findById = this.messageService.monoPreAuthorizeBeanFindById(1L).subscriberContext(this.withUser);
StepVerifier.create(findById).expectError(AccessDeniedException.class).verify();
this.result.assertNoSubscribers();
}
@Test
public void monoPostAuthorizeWhenAuthorizedThenSuccess() {
when(this.delegate.monoPostAuthorizeFindById(1L)).thenReturn(Mono.just("user"));
Mono<String> findById = this.messageService.monoPostAuthorizeFindById(1L)
.subscriberContext(withUser);
StepVerifier
.create(findById)
.expectNext("user")
.verifyComplete();
given(this.delegate.monoPostAuthorizeFindById(1L)).willReturn(Mono.just("user"));
Mono<String> findById = this.messageService.monoPostAuthorizeFindById(1L).subscriberContext(this.withUser);
StepVerifier.create(findById).expectNext("user").verifyComplete();
}
@Test
public void monoPostAuthorizeWhenNotAuthorizedThenDenied() {
when(this.delegate.monoPostAuthorizeBeanFindById(1L)).thenReturn(Mono.just("not-authorized"));
Mono<String> findById = this.messageService.monoPostAuthorizeBeanFindById(1L)
.subscriberContext(withUser);
StepVerifier
.create(findById)
.expectError(AccessDeniedException.class)
.verify();
given(this.delegate.monoPostAuthorizeBeanFindById(1L)).willReturn(Mono.just("not-authorized"));
Mono<String> findById = this.messageService.monoPostAuthorizeBeanFindById(1L).subscriberContext(this.withUser);
StepVerifier.create(findById).expectError(AccessDeniedException.class).verify();
}
@Test
public void monoPostAuthorizeWhenBeanAndAuthorizedThenSuccess() {
when(this.delegate.monoPostAuthorizeBeanFindById(2L)).thenReturn(Mono.just("user"));
Mono<String> findById = this.messageService.monoPostAuthorizeBeanFindById(2L)
.subscriberContext(withUser);
StepVerifier
.create(findById)
.expectNext("user")
.verifyComplete();
given(this.delegate.monoPostAuthorizeBeanFindById(2L)).willReturn(Mono.just("user"));
Mono<String> findById = this.messageService.monoPostAuthorizeBeanFindById(2L).subscriberContext(this.withUser);
StepVerifier.create(findById).expectNext("user").verifyComplete();
}
@Test
public void monoPostAuthorizeWhenBeanAndNotAuthenticatedAndAuthorizedThenSuccess() {
when(this.delegate.monoPostAuthorizeBeanFindById(2L)).thenReturn(Mono.just("anonymous"));
given(this.delegate.monoPostAuthorizeBeanFindById(2L)).willReturn(Mono.just("anonymous"));
Mono<String> findById = this.messageService.monoPostAuthorizeBeanFindById(2L);
StepVerifier
.create(findById)
.expectNext("anonymous")
.verifyComplete();
StepVerifier.create(findById).expectNext("anonymous").verifyComplete();
}
@Test
public void monoPostAuthorizeWhenBeanAndNotAuthorizedThenDenied() {
when(this.delegate.monoPostAuthorizeBeanFindById(1L)).thenReturn(Mono.just("not-authorized"));
Mono<String> findById = this.messageService.monoPostAuthorizeBeanFindById(1L)
.subscriberContext(withUser);
StepVerifier
.create(findById)
.expectError(AccessDeniedException.class)
.verify();
given(this.delegate.monoPostAuthorizeBeanFindById(1L)).willReturn(Mono.just("not-authorized"));
Mono<String> findById = this.messageService.monoPostAuthorizeBeanFindById(1L).subscriberContext(this.withUser);
StepVerifier.create(findById).expectError(AccessDeniedException.class).verify();
}
// Flux tests
@Test
public void fluxWhenPermitAllThenAopDoesNotSubscribe() {
when(this.delegate.fluxFindById(1L)).thenReturn(Flux.from(result));
given(this.delegate.fluxFindById(1L)).willReturn(Flux.from(this.result));
this.delegate.fluxFindById(1L);
result.assertNoSubscribers();
this.result.assertNoSubscribers();
}
@Test
public void fluxWhenPermitAllThenSuccess() {
when(this.delegate.fluxFindById(1L)).thenReturn(Flux.just("success"));
StepVerifier.create(this.delegate.fluxFindById(1L))
.expectNext("success")
.verifyComplete();
given(this.delegate.fluxFindById(1L)).willReturn(Flux.just("success"));
StepVerifier.create(this.delegate.fluxFindById(1L)).expectNext("success").verifyComplete();
}
@Test
public void fluxPreAuthorizeHasRoleWhenGrantedThenSuccess() {
when(this.delegate.fluxPreAuthorizeHasRoleFindById(1L)).thenReturn(Flux.just("result"));
given(this.delegate.fluxPreAuthorizeHasRoleFindById(1L)).willReturn(Flux.just("result"));
Flux<String> findById = this.messageService.fluxPreAuthorizeHasRoleFindById(1L)
.subscriberContext(withAdmin);
StepVerifier
.create(findById)
.consumeNextWith( s -> AssertionsForClassTypes.assertThat(s).isEqualTo("result"))
.verifyComplete();
.subscriberContext(this.withAdmin);
StepVerifier.create(findById).consumeNextWith((s) -> assertThat(s).isEqualTo("result")).verifyComplete();
}
@Test
public void fluxPreAuthorizeHasRoleWhenNoAuthenticationThenDenied() {
when(this.delegate.fluxPreAuthorizeHasRoleFindById(1L)).thenReturn(Flux.from(result));
given(this.delegate.fluxPreAuthorizeHasRoleFindById(1L)).willReturn(Flux.from(this.result));
Flux<String> findById = this.messageService.fluxPreAuthorizeHasRoleFindById(1L);
StepVerifier
.create(findById)
.expectError(AccessDeniedException.class)
.verify();
result.assertNoSubscribers();
StepVerifier.create(findById).expectError(AccessDeniedException.class).verify();
this.result.assertNoSubscribers();
}
@Test
public void fluxPreAuthorizeHasRoleWhenNotAuthorizedThenDenied() {
when(this.delegate.fluxPreAuthorizeHasRoleFindById(1L)).thenReturn(Flux.from(result));
given(this.delegate.fluxPreAuthorizeHasRoleFindById(1L)).willReturn(Flux.from(this.result));
Flux<String> findById = this.messageService.fluxPreAuthorizeHasRoleFindById(1L)
.subscriberContext(withUser);
StepVerifier
.create(findById)
.expectError(AccessDeniedException.class)
.verify();
result.assertNoSubscribers();
.subscriberContext(this.withUser);
StepVerifier.create(findById).expectError(AccessDeniedException.class).verify();
this.result.assertNoSubscribers();
}
@Test
public void fluxPreAuthorizeBeanWhenGrantedThenSuccess() {
when(this.delegate.fluxPreAuthorizeBeanFindById(2L)).thenReturn(Flux.just("result"));
Flux<String> findById = this.messageService.fluxPreAuthorizeBeanFindById(2L)
.subscriberContext(withAdmin);
StepVerifier
.create(findById)
.expectNext("result")
.verifyComplete();
given(this.delegate.fluxPreAuthorizeBeanFindById(2L)).willReturn(Flux.just("result"));
Flux<String> findById = this.messageService.fluxPreAuthorizeBeanFindById(2L).subscriberContext(this.withAdmin);
StepVerifier.create(findById).expectNext("result").verifyComplete();
}
@Test
public void fluxPreAuthorizeBeanWhenNotAuthenticatedAndGrantedThenSuccess() {
when(this.delegate.fluxPreAuthorizeBeanFindById(2L)).thenReturn(Flux.just("result"));
given(this.delegate.fluxPreAuthorizeBeanFindById(2L)).willReturn(Flux.just("result"));
Flux<String> findById = this.messageService.fluxPreAuthorizeBeanFindById(2L);
StepVerifier
.create(findById)
.expectNext("result")
.verifyComplete();
StepVerifier.create(findById).expectNext("result").verifyComplete();
}
@Test
public void fluxPreAuthorizeBeanWhenNoAuthenticationThenDenied() {
when(this.delegate.fluxPreAuthorizeBeanFindById(1L)).thenReturn(Flux.from(result));
given(this.delegate.fluxPreAuthorizeBeanFindById(1L)).willReturn(Flux.from(this.result));
Flux<String> findById = this.messageService.fluxPreAuthorizeBeanFindById(1L);
StepVerifier
.create(findById)
.expectError(AccessDeniedException.class)
.verify();
result.assertNoSubscribers();
StepVerifier.create(findById).expectError(AccessDeniedException.class).verify();
this.result.assertNoSubscribers();
}
@Test
public void fluxPreAuthorizeBeanWhenNotAuthorizedThenDenied() {
when(this.delegate.fluxPreAuthorizeBeanFindById(1L)).thenReturn(Flux.from(result));
Flux<String> findById = this.messageService.fluxPreAuthorizeBeanFindById(1L)
.subscriberContext(withUser);
StepVerifier
.create(findById)
.expectError(AccessDeniedException.class)
.verify();
result.assertNoSubscribers();
given(this.delegate.fluxPreAuthorizeBeanFindById(1L)).willReturn(Flux.from(this.result));
Flux<String> findById = this.messageService.fluxPreAuthorizeBeanFindById(1L).subscriberContext(this.withUser);
StepVerifier.create(findById).expectError(AccessDeniedException.class).verify();
this.result.assertNoSubscribers();
}
@Test
public void fluxPostAuthorizeWhenAuthorizedThenSuccess() {
when(this.delegate.fluxPostAuthorizeFindById(1L)).thenReturn(Flux.just("user"));
Flux<String> findById = this.messageService.fluxPostAuthorizeFindById(1L)
.subscriberContext(withUser);
StepVerifier
.create(findById)
.expectNext("user")
.verifyComplete();
given(this.delegate.fluxPostAuthorizeFindById(1L)).willReturn(Flux.just("user"));
Flux<String> findById = this.messageService.fluxPostAuthorizeFindById(1L).subscriberContext(this.withUser);
StepVerifier.create(findById).expectNext("user").verifyComplete();
}
@Test
public void fluxPostAuthorizeWhenNotAuthorizedThenDenied() {
when(this.delegate.fluxPostAuthorizeBeanFindById(1L)).thenReturn(Flux.just("not-authorized"));
Flux<String> findById = this.messageService.fluxPostAuthorizeBeanFindById(1L)
.subscriberContext(withUser);
StepVerifier
.create(findById)
.expectError(AccessDeniedException.class)
.verify();
given(this.delegate.fluxPostAuthorizeBeanFindById(1L)).willReturn(Flux.just("not-authorized"));
Flux<String> findById = this.messageService.fluxPostAuthorizeBeanFindById(1L).subscriberContext(this.withUser);
StepVerifier.create(findById).expectError(AccessDeniedException.class).verify();
}
@Test
public void fluxPostAuthorizeWhenBeanAndAuthorizedThenSuccess() {
when(this.delegate.fluxPostAuthorizeBeanFindById(2L)).thenReturn(Flux.just("user"));
Flux<String> findById = this.messageService.fluxPostAuthorizeBeanFindById(2L)
.subscriberContext(withUser);
StepVerifier
.create(findById)
.expectNext("user")
.verifyComplete();
given(this.delegate.fluxPostAuthorizeBeanFindById(2L)).willReturn(Flux.just("user"));
Flux<String> findById = this.messageService.fluxPostAuthorizeBeanFindById(2L).subscriberContext(this.withUser);
StepVerifier.create(findById).expectNext("user").verifyComplete();
}
@Test
public void fluxPostAuthorizeWhenBeanAndNotAuthenticatedAndAuthorizedThenSuccess() {
when(this.delegate.fluxPostAuthorizeBeanFindById(2L)).thenReturn(Flux.just("anonymous"));
given(this.delegate.fluxPostAuthorizeBeanFindById(2L)).willReturn(Flux.just("anonymous"));
Flux<String> findById = this.messageService.fluxPostAuthorizeBeanFindById(2L);
StepVerifier
.create(findById)
.expectNext("anonymous")
.verifyComplete();
StepVerifier.create(findById).expectNext("anonymous").verifyComplete();
}
@Test
public void fluxPostAuthorizeWhenBeanAndNotAuthorizedThenDenied() {
when(this.delegate.fluxPostAuthorizeBeanFindById(1L)).thenReturn(Flux.just("not-authorized"));
Flux<String> findById = this.messageService.fluxPostAuthorizeBeanFindById(1L)
.subscriberContext(withUser);
StepVerifier
.create(findById)
.expectError(AccessDeniedException.class)
.verify();
given(this.delegate.fluxPostAuthorizeBeanFindById(1L)).willReturn(Flux.just("not-authorized"));
Flux<String> findById = this.messageService.fluxPostAuthorizeBeanFindById(1L).subscriberContext(this.withUser);
StepVerifier.create(findById).expectError(AccessDeniedException.class).verify();
}
// Publisher tests
@Test
public void publisherWhenPermitAllThenAopDoesNotSubscribe() {
when(this.delegate.publisherFindById(1L)).thenReturn(result);
given(this.delegate.publisherFindById(1L)).willReturn(this.result);
this.delegate.publisherFindById(1L);
result.assertNoSubscribers();
this.result.assertNoSubscribers();
}
@Test
public void publisherWhenPermitAllThenSuccess() {
when(this.delegate.publisherFindById(1L)).thenReturn(publisherJust("success"));
StepVerifier.create(this.delegate.publisherFindById(1L))
.expectNext("success")
.verifyComplete();
given(this.delegate.publisherFindById(1L)).willReturn(publisherJust("success"));
StepVerifier.create(this.delegate.publisherFindById(1L)).expectNext("success").verifyComplete();
}
@Test
public void publisherPreAuthorizeHasRoleWhenGrantedThenSuccess() {
when(this.delegate.publisherPreAuthorizeHasRoleFindById(1L)).thenReturn(publisherJust("result"));
given(this.delegate.publisherPreAuthorizeHasRoleFindById(1L)).willReturn(publisherJust("result"));
Publisher<String> findById = Flux.from(this.messageService.publisherPreAuthorizeHasRoleFindById(1L))
.subscriberContext(withAdmin);
StepVerifier
.create(findById)
.consumeNextWith( s -> AssertionsForClassTypes.assertThat(s).isEqualTo("result"))
.verifyComplete();
.subscriberContext(this.withAdmin);
StepVerifier.create(findById).consumeNextWith((s) -> assertThat(s).isEqualTo("result")).verifyComplete();
}
@Test
public void publisherPreAuthorizeHasRoleWhenNoAuthenticationThenDenied() {
when(this.delegate.publisherPreAuthorizeHasRoleFindById(1L)).thenReturn(result);
given(this.delegate.publisherPreAuthorizeHasRoleFindById(1L)).willReturn(this.result);
Publisher<String> findById = this.messageService.publisherPreAuthorizeHasRoleFindById(1L);
StepVerifier
.create(findById)
.expectError(AccessDeniedException.class)
.verify();
result.assertNoSubscribers();
StepVerifier.create(findById).expectError(AccessDeniedException.class).verify();
this.result.assertNoSubscribers();
}
@Test
public void publisherPreAuthorizeHasRoleWhenNotAuthorizedThenDenied() {
when(this.delegate.publisherPreAuthorizeHasRoleFindById(1L)).thenReturn(result);
given(this.delegate.publisherPreAuthorizeHasRoleFindById(1L)).willReturn(this.result);
Publisher<String> findById = Flux.from(this.messageService.publisherPreAuthorizeHasRoleFindById(1L))
.subscriberContext(withUser);
StepVerifier
.create(findById)
.expectError(AccessDeniedException.class)
.verify();
result.assertNoSubscribers();
.subscriberContext(this.withUser);
StepVerifier.create(findById).expectError(AccessDeniedException.class).verify();
this.result.assertNoSubscribers();
}
@Test
public void publisherPreAuthorizeBeanWhenGrantedThenSuccess() {
when(this.delegate.publisherPreAuthorizeBeanFindById(2L)).thenReturn(publisherJust("result"));
given(this.delegate.publisherPreAuthorizeBeanFindById(2L)).willReturn(publisherJust("result"));
Publisher<String> findById = Flux.from(this.messageService.publisherPreAuthorizeBeanFindById(2L))
.subscriberContext(withAdmin);
StepVerifier
.create(findById)
.expectNext("result")
.verifyComplete();
.subscriberContext(this.withAdmin);
StepVerifier.create(findById).expectNext("result").verifyComplete();
}
@Test
public void publisherPreAuthorizeBeanWhenNotAuthenticatedAndGrantedThenSuccess() {
when(this.delegate.publisherPreAuthorizeBeanFindById(2L)).thenReturn(publisherJust("result"));
given(this.delegate.publisherPreAuthorizeBeanFindById(2L)).willReturn(publisherJust("result"));
Publisher<String> findById = this.messageService.publisherPreAuthorizeBeanFindById(2L);
StepVerifier
.create(findById)
.expectNext("result")
.verifyComplete();
StepVerifier.create(findById).expectNext("result").verifyComplete();
}
@Test
public void publisherPreAuthorizeBeanWhenNoAuthenticationThenDenied() {
when(this.delegate.publisherPreAuthorizeBeanFindById(1L)).thenReturn(result);
given(this.delegate.publisherPreAuthorizeBeanFindById(1L)).willReturn(this.result);
Publisher<String> findById = this.messageService.publisherPreAuthorizeBeanFindById(1L);
StepVerifier
.create(findById)
.expectError(AccessDeniedException.class)
.verify();
result.assertNoSubscribers();
StepVerifier.create(findById).expectError(AccessDeniedException.class).verify();
this.result.assertNoSubscribers();
}
@Test
public void publisherPreAuthorizeBeanWhenNotAuthorizedThenDenied() {
when(this.delegate.publisherPreAuthorizeBeanFindById(1L)).thenReturn(result);
given(this.delegate.publisherPreAuthorizeBeanFindById(1L)).willReturn(this.result);
Publisher<String> findById = Flux.from(this.messageService.publisherPreAuthorizeBeanFindById(1L))
.subscriberContext(withUser);
StepVerifier
.create(findById)
.expectError(AccessDeniedException.class)
.verify();
result.assertNoSubscribers();
.subscriberContext(this.withUser);
StepVerifier.create(findById).expectError(AccessDeniedException.class).verify();
this.result.assertNoSubscribers();
}
@Test
public void publisherPostAuthorizeWhenAuthorizedThenSuccess() {
when(this.delegate.publisherPostAuthorizeFindById(1L)).thenReturn(publisherJust("user"));
given(this.delegate.publisherPostAuthorizeFindById(1L)).willReturn(publisherJust("user"));
Publisher<String> findById = Flux.from(this.messageService.publisherPostAuthorizeFindById(1L))
.subscriberContext(withUser);
StepVerifier
.create(findById)
.expectNext("user")
.verifyComplete();
.subscriberContext(this.withUser);
StepVerifier.create(findById).expectNext("user").verifyComplete();
}
@Test
public void publisherPostAuthorizeWhenNotAuthorizedThenDenied() {
when(this.delegate.publisherPostAuthorizeBeanFindById(1L)).thenReturn(publisherJust("not-authorized"));
given(this.delegate.publisherPostAuthorizeBeanFindById(1L)).willReturn(publisherJust("not-authorized"));
Publisher<String> findById = Flux.from(this.messageService.publisherPostAuthorizeBeanFindById(1L))
.subscriberContext(withUser);
StepVerifier
.create(findById)
.expectError(AccessDeniedException.class)
.verify();
.subscriberContext(this.withUser);
StepVerifier.create(findById).expectError(AccessDeniedException.class).verify();
}
@Test
public void publisherPostAuthorizeWhenBeanAndAuthorizedThenSuccess() {
when(this.delegate.publisherPostAuthorizeBeanFindById(2L)).thenReturn(publisherJust("user"));
given(this.delegate.publisherPostAuthorizeBeanFindById(2L)).willReturn(publisherJust("user"));
Publisher<String> findById = Flux.from(this.messageService.publisherPostAuthorizeBeanFindById(2L))
.subscriberContext(withUser);
StepVerifier
.create(findById)
.expectNext("user")
.verifyComplete();
.subscriberContext(this.withUser);
StepVerifier.create(findById).expectNext("user").verifyComplete();
}
@Test
public void publisherPostAuthorizeWhenBeanAndNotAuthenticatedAndAuthorizedThenSuccess() {
when(this.delegate.publisherPostAuthorizeBeanFindById(2L)).thenReturn(publisherJust("anonymous"));
given(this.delegate.publisherPostAuthorizeBeanFindById(2L)).willReturn(publisherJust("anonymous"));
Publisher<String> findById = this.messageService.publisherPostAuthorizeBeanFindById(2L);
StepVerifier
.create(findById)
.expectNext("anonymous")
.verifyComplete();
StepVerifier.create(findById).expectNext("anonymous").verifyComplete();
}
@Test
public void publisherPostAuthorizeWhenBeanAndNotAuthorizedThenDenied() {
when(this.delegate.publisherPostAuthorizeBeanFindById(1L)).thenReturn(publisherJust("not-authorized"));
given(this.delegate.publisherPostAuthorizeBeanFindById(1L)).willReturn(publisherJust("not-authorized"));
Publisher<String> findById = Flux.from(this.messageService.publisherPostAuthorizeBeanFindById(1L))
.subscriberContext(withUser);
StepVerifier
.create(findById)
.expectError(AccessDeniedException.class)
.verify();
.subscriberContext(this.withUser);
StepVerifier.create(findById).expectError(AccessDeniedException.class).verify();
}
static <T> Publisher<T> publisher(Flux<T> flux) {
return subscriber -> flux.subscribe(subscriber);
return (subscriber) -> flux.subscribe(subscriber);
}
static <T> Publisher<T> publisherJust(T... data) {
@@ -581,16 +407,19 @@ public class EnableReactiveMethodSecurityTests {
@EnableReactiveMethodSecurity
static class Config {
ReactiveMessageService delegate = mock(ReactiveMessageService.class);
@Bean
public DelegatingReactiveMessageService defaultMessageService() {
return new DelegatingReactiveMessageService(delegate);
DelegatingReactiveMessageService defaultMessageService() {
return new DelegatingReactiveMessageService(this.delegate);
}
@Bean
public Authz authz() {
Authz authz() {
return new Authz();
}
}
}

View File

@@ -13,11 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.method.configuration;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map;
import javax.sql.DataSource;
import org.aopalliance.intercept.MethodInterceptor;
@@ -59,22 +61,22 @@ import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
/**
*
* @author Rob Winch
* @author Artsiom Yudovin
*/
@RunWith(SpringJUnit4ClassRunner.class)
@SecurityTestExecutionListeners
public class GlobalMethodSecurityConfigurationTests {
@Rule
public final SpringTestRule spring = new SpringTestRule();
@@ -100,197 +102,78 @@ public class GlobalMethodSecurityConfigurationTests {
this.spring.register(IllegalStateGlobalMethodSecurityConfig.class).autowire();
}
@EnableGlobalMethodSecurity
public static class IllegalStateGlobalMethodSecurityConfig extends GlobalMethodSecurityConfiguration {
}
@Test
public void configureWhenGlobalMethodSecurityHasCustomMetadataSourceThenNoEnablingAttributeIsNeeded() {
this.spring.register(CustomMetadataSourceConfig.class).autowire();
}
@EnableGlobalMethodSecurity
public static class CustomMetadataSourceConfig extends GlobalMethodSecurityConfiguration {
@Bean
@Override
protected MethodSecurityMetadataSource customMethodSecurityMetadataSource() {
return mock(MethodSecurityMetadataSource.class);
}
}
@Test
public void methodSecurityAuthenticationManagerPublishesEvent() {
this.spring.register(InMemoryAuthWithGlobalMethodSecurityConfig.class).autowire();
try {
this.authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("foo", "bar"));
} catch(AuthenticationException e) {}
assertThat(this.events.getEvents()).extracting(Object::getClass).containsOnly((Class) AuthenticationFailureBadCredentialsEvent.class);
}
@EnableGlobalMethodSecurity(prePostEnabled = true)
public static class InMemoryAuthWithGlobalMethodSecurityConfig extends GlobalMethodSecurityConfiguration {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication();
}
@Bean
public MockEventListener<AbstractAuthenticationEvent> listener() {
return new MockEventListener<AbstractAuthenticationEvent>() {};
catch (AuthenticationException ex) {
}
assertThat(this.events.getEvents()).extracting(Object::getClass)
.containsOnly((Class) AuthenticationFailureBadCredentialsEvent.class);
}
@Test
@WithMockUser
public void methodSecurityWhenAuthenticationTrustResolverIsBeanThenAutowires() {
this.spring.register(CustomTrustResolverConfig.class).autowire();
AuthenticationTrustResolver trustResolver = this.spring.getContext().getBean(AuthenticationTrustResolver.class);
when(trustResolver.isAnonymous(any())).thenReturn(true, false);
assertThatThrownBy(() -> this.service.preAuthorizeNotAnonymous())
.isInstanceOf(AccessDeniedException.class);
given(trustResolver.isAnonymous(any())).willReturn(true, false);
assertThatExceptionOfType(AccessDeniedException.class)
.isThrownBy(() -> this.service.preAuthorizeNotAnonymous());
this.service.preAuthorizeNotAnonymous();
verify(trustResolver, atLeastOnce()).isAnonymous(any());
}
@EnableGlobalMethodSecurity(prePostEnabled = true)
static class CustomTrustResolverConfig {
@Bean
public AuthenticationTrustResolver trustResolver() {
return mock(AuthenticationTrustResolver.class);
}
@Bean
public MethodSecurityServiceImpl service() {
return new MethodSecurityServiceImpl();
}
}
// SEC-2301
@Test
@WithMockUser
public void defaultWebSecurityExpressionHandlerHasBeanResolverSet() {
this.spring.register(ExpressionHandlerHasBeanResolverSetConfig.class).autowire();
Authz authz = this.spring.getContext().getBean(Authz.class);
assertThatThrownBy(() -> this.service.preAuthorizeBean(false))
.isInstanceOf(AccessDeniedException.class);
assertThatExceptionOfType(AccessDeniedException.class).isThrownBy(() -> this.service.preAuthorizeBean(false));
this.service.preAuthorizeBean(true);
}
@EnableGlobalMethodSecurity(prePostEnabled = true, proxyTargetClass = true)
static class ExpressionHandlerHasBeanResolverSetConfig {
@Bean
public MethodSecurityServiceImpl service() {
return new MethodSecurityServiceImpl();
}
@Bean
public Authz authz() {
return new Authz();
}
}
@Test
@WithMockUser
public void methodSecuritySupportsAnnotaitonsOnInterfaceParamerNames() {
this.spring.register(MethodSecurityServiceConfig.class).autowire();
assertThatThrownBy(() -> this.service.postAnnotation("deny"))
.isInstanceOf(AccessDeniedException.class);
assertThatExceptionOfType(AccessDeniedException.class).isThrownBy(() -> this.service.postAnnotation("deny"));
this.service.postAnnotation("grant");
// no exception
}
@EnableGlobalMethodSecurity(prePostEnabled = true)
static class MethodSecurityServiceConfig {
@Bean
public MethodSecurityService service() {
return new MethodSecurityServiceImpl();
}
}
@Test
@WithMockUser
public void globalMethodSecurityConfigurationAutowiresPermissionEvaluator() {
this.spring.register(AutowirePermissionEvaluatorConfig.class).autowire();
PermissionEvaluator permission = this.spring.getContext().getBean(PermissionEvaluator.class);
when(permission.hasPermission(any(), eq("something"), eq("read"))).thenReturn(true, false);
given(permission.hasPermission(any(), eq("something"), eq("read"))).willReturn(true, false);
this.service.hasPermission("something");
// no exception
assertThatThrownBy(() -> this.service.hasPermission("something"))
.isInstanceOf(AccessDeniedException.class);
}
@EnableGlobalMethodSecurity(prePostEnabled = true)
public static class AutowirePermissionEvaluatorConfig {
@Bean
public PermissionEvaluator permissionEvaluator() {
return mock(PermissionEvaluator.class);
}
@Bean
public MethodSecurityService service() {
return new MethodSecurityServiceImpl();
}
assertThatExceptionOfType(AccessDeniedException.class)
.isThrownBy(() -> this.service.hasPermission("something"));
}
@Test
public void multiPermissionEvaluatorConfig() {
this.spring.register(MultiPermissionEvaluatorConfig.class).autowire();
// no exception
}
@EnableGlobalMethodSecurity(prePostEnabled = true)
public static class MultiPermissionEvaluatorConfig {
@Bean
public PermissionEvaluator permissionEvaluator() {
return mock(PermissionEvaluator.class);
}
@Bean
public PermissionEvaluator permissionEvaluator2() {
return mock(PermissionEvaluator.class);
}
}
// SEC-2425
@Test
@WithMockUser
public void enableGlobalMethodSecurityWorksOnSuperclass() {
this.spring.register(ChildConfig.class).autowire();
assertThatThrownBy(() -> this.service.preAuthorize())
.isInstanceOf(AccessDeniedException.class);
}
@Configuration
static class ChildConfig extends ParentConfig {}
@EnableGlobalMethodSecurity(prePostEnabled = true)
static class ParentConfig {
@Bean
public MethodSecurityService service() {
return new MethodSecurityServiceImpl();
}
assertThatExceptionOfType(AccessDeniedException.class).isThrownBy(() -> this.service.preAuthorize());
}
// SEC-2479
@@ -305,58 +188,254 @@ public class GlobalMethodSecurityConfigurationTests {
child.register(Sec2479ChildConfig.class);
child.refresh();
this.spring.context(child).autowire();
assertThatThrownBy(() -> this.service.preAuthorize())
.isInstanceOf(AccessDeniedException.class);
assertThatExceptionOfType(AccessDeniedException.class).isThrownBy(() -> this.service.preAuthorize());
}
}
}
@Configuration
static class Sec2479ParentConfig {
@Bean
public AuthenticationManager am() {
return mock(AuthenticationManager.class);
}
}
@EnableGlobalMethodSecurity(prePostEnabled = true)
static class Sec2479ChildConfig {
@Bean
public MethodSecurityService service() {
return new MethodSecurityServiceImpl();
}
}
@Test
public void enableGlobalMethodSecurityDoesNotTriggerEagerInitializationOfBeansInGlobalAuthenticationConfigurer() {
this.spring.register(Sec2815Config.class).autowire();
MockBeanPostProcessor pp = this.spring.getContext().getBean(MockBeanPostProcessor.class);
assertThat(pp.beforeInit).containsKeys("dataSource");
assertThat(pp.afterInit).containsKeys("dataSource");
}
@EnableGlobalMethodSecurity(prePostEnabled = true)
static class Sec2815Config {
// SEC-3045
@Test
public void globalSecurityProxiesSecurity() {
this.spring.register(Sec3005Config.class).autowire();
assertThat(this.service.getClass()).matches((c) -> !Proxy.isProxyClass(c), "is not proxy class");
}
//
// // gh-3797
// def preAuthorizeBeanSpel() {
// setup:
// SecurityContextHolder.getContext().setAuthentication(
// new TestingAuthenticationToken("user", "password","ROLE_USER"))
// context = new AnnotationConfigApplicationContext(PreAuthorizeBeanSpelConfig)
// BeanSpelService service = context.getBean(BeanSpelService)
// when:
// service.run(true)
// then:
// noExceptionThrown()
// when:
// service.run(false)
// then:
// thrown(AccessDeniedException)
// }
//
@Test
@WithMockUser
public void preAuthorizeBeanSpel() {
this.spring.register(PreAuthorizeBeanSpelConfig.class).autowire();
assertThatExceptionOfType(AccessDeniedException.class).isThrownBy(() -> this.service.preAuthorizeBean(false));
this.service.preAuthorizeBean(true);
}
// gh-3394
@Test
@WithMockUser
public void roleHierarchy() {
this.spring.register(RoleHierarchyConfig.class).autowire();
assertThatExceptionOfType(AccessDeniedException.class).isThrownBy(() -> this.service.preAuthorize());
this.service.preAuthorizeAdmin();
}
@Test
@WithMockUser(authorities = "ROLE:USER")
public void grantedAuthorityDefaultsAutowires() {
this.spring.register(CustomGrantedAuthorityConfig.class).autowire();
CustomGrantedAuthorityConfig.CustomAuthorityService customService = this.spring.getContext()
.getBean(CustomGrantedAuthorityConfig.CustomAuthorityService.class);
assertThatExceptionOfType(AccessDeniedException.class).isThrownBy(() -> this.service.preAuthorize());
customService.customPrefixRoleUser();
// no exception
}
@Test
@WithMockUser(authorities = "USER")
public void grantedAuthorityDefaultsWithEmptyRolePrefix() {
this.spring.register(EmptyRolePrefixGrantedAuthorityConfig.class).autowire();
EmptyRolePrefixGrantedAuthorityConfig.CustomAuthorityService customService = this.spring.getContext()
.getBean(EmptyRolePrefixGrantedAuthorityConfig.CustomAuthorityService.class);
assertThatExceptionOfType(AccessDeniedException.class).isThrownBy(() -> this.service.securedUser());
customService.emptyPrefixRoleUser();
// no exception
}
@Test
public void methodSecurityInterceptorUsesMetadataSourceBeanWhenProxyingDisabled() {
this.spring.register(CustomMetadataSourceBeanProxyEnabledConfig.class).autowire();
MethodSecurityInterceptor methodInterceptor = (MethodSecurityInterceptor) this.spring.getContext()
.getBean(MethodInterceptor.class);
MethodSecurityMetadataSource methodSecurityMetadataSource = this.spring.getContext()
.getBean(MethodSecurityMetadataSource.class);
assertThat(methodInterceptor.getSecurityMetadataSource()).isSameAs(methodSecurityMetadataSource);
}
@EnableGlobalMethodSecurity
public static class IllegalStateGlobalMethodSecurityConfig extends GlobalMethodSecurityConfiguration {
}
@EnableGlobalMethodSecurity
public static class CustomMetadataSourceConfig extends GlobalMethodSecurityConfiguration {
@Bean
public MethodSecurityService service() {
@Override
protected MethodSecurityMetadataSource customMethodSecurityMetadataSource() {
return mock(MethodSecurityMetadataSource.class);
}
}
@EnableGlobalMethodSecurity(prePostEnabled = true)
public static class InMemoryAuthWithGlobalMethodSecurityConfig extends GlobalMethodSecurityConfiguration {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// @formatter:off
auth
.inMemoryAuthentication();
// @formatter:on
}
@Bean
public MockEventListener<AbstractAuthenticationEvent> listener() {
return new MockEventListener<AbstractAuthenticationEvent>() {
};
}
}
@EnableGlobalMethodSecurity(prePostEnabled = true)
static class CustomTrustResolverConfig {
@Bean
AuthenticationTrustResolver trustResolver() {
return mock(AuthenticationTrustResolver.class);
}
@Bean
MethodSecurityServiceImpl service() {
return new MethodSecurityServiceImpl();
}
}
@EnableGlobalMethodSecurity(prePostEnabled = true, proxyTargetClass = true)
static class ExpressionHandlerHasBeanResolverSetConfig {
@Bean
MethodSecurityServiceImpl service() {
return new MethodSecurityServiceImpl();
}
@Bean
public MockBeanPostProcessor mockBeanPostProcessor() {
Authz authz() {
return new Authz();
}
}
@EnableGlobalMethodSecurity(prePostEnabled = true)
static class MethodSecurityServiceConfig {
@Bean
MethodSecurityService service() {
return new MethodSecurityServiceImpl();
}
}
@EnableGlobalMethodSecurity(prePostEnabled = true)
public static class AutowirePermissionEvaluatorConfig {
@Bean
PermissionEvaluator permissionEvaluator() {
return mock(PermissionEvaluator.class);
}
@Bean
MethodSecurityService service() {
return new MethodSecurityServiceImpl();
}
}
@EnableGlobalMethodSecurity(prePostEnabled = true)
public static class MultiPermissionEvaluatorConfig {
@Bean
PermissionEvaluator permissionEvaluator() {
return mock(PermissionEvaluator.class);
}
@Bean
PermissionEvaluator permissionEvaluator2() {
return mock(PermissionEvaluator.class);
}
}
@Configuration
static class ChildConfig extends ParentConfig {
}
@EnableGlobalMethodSecurity(prePostEnabled = true)
static class ParentConfig {
@Bean
MethodSecurityService service() {
return new MethodSecurityServiceImpl();
}
}
@Configuration
static class Sec2479ParentConfig {
@Bean
AuthenticationManager am() {
return mock(AuthenticationManager.class);
}
}
@EnableGlobalMethodSecurity(prePostEnabled = true)
static class Sec2479ChildConfig {
@Bean
MethodSecurityService service() {
return new MethodSecurityServiceImpl();
}
}
@EnableGlobalMethodSecurity(prePostEnabled = true)
static class Sec2815Config {
@Bean
MethodSecurityService service() {
return new MethodSecurityServiceImpl();
}
@Bean
MockBeanPostProcessor mockBeanPostProcessor() {
return new MockBeanPostProcessor();
}
@Bean
public DataSource dataSource() {
DataSource dataSource() {
return mock(DataSource.class);
}
@Configuration
static class AuthConfig extends GlobalAuthenticationConfigurerAdapter {
@Autowired
DataSource dataSource;
@@ -364,16 +443,19 @@ public class GlobalMethodSecurityConfigurationTests {
public void init(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication();
}
}
}
static class MockBeanPostProcessor implements BeanPostProcessor {
Map<String, Object> beforeInit = new HashMap<>();
Map<String, Object> afterInit = new HashMap<>();
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws
BeansException {
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
this.beforeInit.put(beanName, bean);
return bean;
}
@@ -383,63 +465,29 @@ public class GlobalMethodSecurityConfigurationTests {
this.afterInit.put(beanName, bean);
return bean;
}
}
// SEC-3045
@Test
public void globalSecurityProxiesSecurity() {
this.spring.register(Sec3005Config.class).autowire();
assertThat(this.service.getClass()).matches(c-> !Proxy.isProxyClass(c), "is not proxy class");
}
@EnableGlobalMethodSecurity(prePostEnabled = true, mode= AdviceMode.ASPECTJ)
@EnableGlobalMethodSecurity(prePostEnabled = true, mode = AdviceMode.ASPECTJ)
@EnableTransactionManagement
static class Sec3005Config {
@Bean
public MethodSecurityService service() {
MethodSecurityService service() {
return new MethodSecurityServiceImpl();
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication();
}
}
//
// // gh-3797
// def preAuthorizeBeanSpel() {
// setup:
// SecurityContextHolder.getContext().setAuthentication(
// new TestingAuthenticationToken("user", "password","ROLE_USER"))
// context = new AnnotationConfigApplicationContext(PreAuthorizeBeanSpelConfig)
// BeanSpelService service = context.getBean(BeanSpelService)
// when:
// service.run(true)
// then:
// noExceptionThrown()
// when:
// service.run(false)
// then:
// thrown(AccessDeniedException)
// }
//
@Test
@WithMockUser
public void preAuthorizeBeanSpel() {
this.spring.register(PreAuthorizeBeanSpelConfig.class).autowire();
assertThatThrownBy(() -> this.service.preAuthorizeBean(false))
.isInstanceOf(AccessDeniedException.class);
this.service.preAuthorizeBean(true);
}
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public static class PreAuthorizeBeanSpelConfig {
@Bean
MethodSecurityService service() {
return new MethodSecurityServiceImpl();
@@ -449,22 +497,13 @@ public class GlobalMethodSecurityConfigurationTests {
Authz authz() {
return new Authz();
}
}
// gh-3394
@Test
@WithMockUser
public void roleHierarchy() {
this.spring.register(RoleHierarchyConfig.class).autowire();
assertThatThrownBy(() -> this.service.preAuthorize())
.isInstanceOf(AccessDeniedException.class);
this.service.preAuthorizeAdmin();
}
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Configuration
public static class RoleHierarchyConfig {
@Bean
MethodSecurityService service() {
return new MethodSecurityServiceImpl();
@@ -476,98 +515,69 @@ public class GlobalMethodSecurityConfigurationTests {
result.setHierarchy("ROLE_USER > ROLE_ADMIN");
return result;
}
}
@Test
@WithMockUser(authorities = "ROLE:USER")
public void grantedAuthorityDefaultsAutowires() {
this.spring.register(CustomGrantedAuthorityConfig.class).autowire();
CustomGrantedAuthorityConfig.CustomAuthorityService customService = this.spring.getContext().getBean(
CustomGrantedAuthorityConfig.CustomAuthorityService.class);
assertThatThrownBy(() -> this.service.preAuthorize())
.isInstanceOf(AccessDeniedException.class);
customService.customPrefixRoleUser();
// no exception
}
@EnableGlobalMethodSecurity(prePostEnabled = true)
static class CustomGrantedAuthorityConfig {
@Bean
public GrantedAuthorityDefaults ga() {
GrantedAuthorityDefaults ga() {
return new GrantedAuthorityDefaults("ROLE:");
}
@Bean
public CustomAuthorityService service() {
CustomAuthorityService service() {
return new CustomAuthorityService();
}
@Bean
public MethodSecurityServiceImpl methodSecurityService() {
MethodSecurityServiceImpl methodSecurityService() {
return new MethodSecurityServiceImpl();
}
static class CustomAuthorityService {
@PreAuthorize("hasRole('ROLE:USER')")
public void customPrefixRoleUser() {}
void customPrefixRoleUser() {
}
}
}
@Test
@WithMockUser(authorities = "USER")
public void grantedAuthorityDefaultsWithEmptyRolePrefix() {
this.spring.register(EmptyRolePrefixGrantedAuthorityConfig.class).autowire();
EmptyRolePrefixGrantedAuthorityConfig.CustomAuthorityService customService = this.spring.getContext()
.getBean(EmptyRolePrefixGrantedAuthorityConfig.CustomAuthorityService.class);
assertThatThrownBy(() -> this.service.securedUser())
.isInstanceOf(AccessDeniedException.class);
customService.emptyPrefixRoleUser();
// no exception
}
@EnableGlobalMethodSecurity(securedEnabled = true)
static class EmptyRolePrefixGrantedAuthorityConfig {
@Bean
public GrantedAuthorityDefaults ga() {
GrantedAuthorityDefaults ga() {
return new GrantedAuthorityDefaults("");
}
@Bean
public CustomAuthorityService service() {
CustomAuthorityService service() {
return new CustomAuthorityService();
}
@Bean
public MethodSecurityServiceImpl methodSecurityService() {
MethodSecurityServiceImpl methodSecurityService() {
return new MethodSecurityServiceImpl();
}
static class CustomAuthorityService {
@Secured("USER")
public void emptyPrefixRoleUser() {}
void emptyPrefixRoleUser() {
}
}
}
@Test
public void methodSecurityInterceptorUsesMetadataSourceBeanWhenProxyingDisabled() {
this.spring.register(CustomMetadataSourceBeanProxyEnabledConfig.class).autowire();
MethodSecurityInterceptor methodInterceptor =
(MethodSecurityInterceptor) this.spring.getContext().getBean(MethodInterceptor.class);
MethodSecurityMetadataSource methodSecurityMetadataSource =
this.spring.getContext().getBean(MethodSecurityMetadataSource.class);
assertThat(methodInterceptor.getSecurityMetadataSource()).isSameAs(methodSecurityMetadataSource);
}
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Configuration
public static class CustomMetadataSourceBeanProxyEnabledConfig extends GlobalMethodSecurityConfiguration {
}
}

View File

@@ -16,19 +16,20 @@
package org.springframework.security.config.annotation.method.configuration;
import javax.annotation.security.DenyAll;
import javax.annotation.security.PermitAll;
import org.springframework.security.access.annotation.Secured;
import org.springframework.security.access.prepost.PostAuthorize;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.parameters.P;
import javax.annotation.security.DenyAll;
import javax.annotation.security.PermitAll;
/**
* @author Rob Winch
*/
public interface MethodSecurityService {
@PreAuthorize("denyAll")
String preAuthorize();
@@ -67,4 +68,5 @@ public interface MethodSecurityService {
@PostAuthorize("#o?.contains('grant')")
String postAnnotation(@P("o") String object);
}

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.method.configuration;
import org.springframework.context.annotation.Bean;
@@ -21,8 +22,10 @@ import org.springframework.context.annotation.Bean;
* @author Josh Cummings
*/
public class MethodSecurityServiceConfig {
@Bean
MethodSecurityService service() {
return new MethodSecurityServiceImpl();
}
}

View File

@@ -23,6 +23,7 @@ import org.springframework.security.core.context.SecurityContextHolder;
* @author Rob Winch
*/
public class MethodSecurityServiceImpl implements MethodSecurityService {
@Override
public String preAuthorize() {
return null;

View File

@@ -13,11 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.method.configuration;
import java.io.Serializable;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.PermissionEvaluator;
@@ -29,13 +33,10 @@ import org.springframework.security.test.context.annotation.SecurityTestExecutio
import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.io.Serializable;
import static org.assertj.core.api.Assertions.assertThatCode;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
/**
*
* @author Rob Winch
* @author Josh Cummings
*/
@@ -53,43 +54,41 @@ public class NamespaceGlobalMethodSecurityExpressionHandlerTests {
@WithMockUser
public void methodSecurityWhenUsingCustomPermissionEvaluatorThenPreAuthorizesAccordingly() {
this.spring.register(CustomAccessDecisionManagerConfig.class, MethodSecurityServiceConfig.class).autowire();
assertThatCode(() -> this.service.hasPermission("granted"))
.doesNotThrowAnyException();
assertThatThrownBy(() -> this.service.hasPermission("denied"))
.isInstanceOf(AccessDeniedException.class);
assertThat(this.service.hasPermission("granted")).isNull();
assertThatExceptionOfType(AccessDeniedException.class).isThrownBy(() -> this.service.hasPermission("denied"));
}
@Test
@WithMockUser
public void methodSecurityWhenUsingCustomPermissionEvaluatorThenPostAuthorizesAccordingly() {
this.spring.register(CustomAccessDecisionManagerConfig.class, MethodSecurityServiceConfig.class).autowire();
assertThatCode(() -> this.service.postHasPermission("granted"))
.doesNotThrowAnyException();
assertThatThrownBy(() -> this.service.postHasPermission("denied"))
.isInstanceOf(AccessDeniedException.class);
assertThat(this.service.postHasPermission("granted")).isNull();
assertThatExceptionOfType(AccessDeniedException.class)
.isThrownBy(() -> this.service.postHasPermission("denied"));
}
@EnableGlobalMethodSecurity(prePostEnabled = true)
public static class CustomAccessDecisionManagerConfig extends GlobalMethodSecurityConfiguration {
@Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
DefaultMethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
expressionHandler.setPermissionEvaluator(new PermissionEvaluator() {
public boolean hasPermission(Authentication authentication, Object targetDomainObject, Object permission) {
@Override
public boolean hasPermission(Authentication authentication, Object targetDomainObject,
Object permission) {
return "granted".equals(targetDomainObject);
}
public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, Object permission) {
@Override
public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType,
Object permission) {
throw new UnsupportedOperationException();
}
});
return expressionHandler;
}
}
}

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.method.configuration;
import java.lang.reflect.Method;
@@ -56,11 +57,9 @@ import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatCode;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
/**
*
* @author Rob Winch
* @author Josh Cummings
*/
@@ -74,19 +73,166 @@ public class NamespaceGlobalMethodSecurityTests {
@Autowired(required = false)
private MethodSecurityService service;
// --- access-decision-manager-ref ---
@Test
@WithMockUser
public void methodSecurityWhenCustomAccessDecisionManagerThenAuthorizes() {
this.spring.register(CustomAccessDecisionManagerConfig.class, MethodSecurityServiceConfig.class).autowire();
assertThatExceptionOfType(AccessDeniedException.class).isThrownBy(() -> this.service.preAuthorize());
assertThatExceptionOfType(AccessDeniedException.class).isThrownBy(() -> this.service.secured());
}
assertThatThrownBy(() -> this.service.preAuthorize())
.isInstanceOf(AccessDeniedException.class);
@Test
@WithMockUser
public void methodSecurityWhenCustomAfterInvocationManagerThenAuthorizes() {
this.spring.register(CustomAfterInvocationManagerConfig.class, MethodSecurityServiceConfig.class).autowire();
assertThatExceptionOfType(AccessDeniedException.class).isThrownBy(() -> this.service.preAuthorizePermitAll());
}
assertThatThrownBy(() -> this.service.secured())
.isInstanceOf(AccessDeniedException.class);
@Test
@WithMockUser
public void methodSecurityWhenCustomAuthenticationManagerThenAuthorizes() {
this.spring.register(CustomAuthenticationConfig.class, MethodSecurityServiceConfig.class).autowire();
assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(() -> this.service.preAuthorize());
}
@Test
@WithMockUser
public void methodSecurityWhenJsr250EnabledThenAuthorizes() {
this.spring.register(Jsr250Config.class, MethodSecurityServiceConfig.class).autowire();
this.service.preAuthorize();
this.service.secured();
this.service.jsr250PermitAll();
assertThatExceptionOfType(AccessDeniedException.class).isThrownBy(() -> this.service.jsr250());
}
@Test
@WithMockUser
public void methodSecurityWhenCustomMethodSecurityMetadataSourceThenAuthorizes() {
this.spring.register(CustomMethodSecurityMetadataSourceConfig.class, MethodSecurityServiceConfig.class)
.autowire();
assertThatExceptionOfType(AccessDeniedException.class).isThrownBy(() -> this.service.preAuthorize());
assertThatExceptionOfType(AccessDeniedException.class).isThrownBy(() -> this.service.secured());
assertThatExceptionOfType(AccessDeniedException.class).isThrownBy(() -> this.service.jsr250());
}
@Test
@WithMockUser
public void contextRefreshWhenUsingAspectJThenAutowire() throws Exception {
this.spring.register(AspectJModeConfig.class, MethodSecurityServiceConfig.class).autowire();
assertThat(this.spring.getContext().getBean(
Class.forName("org.springframework.security.access.intercept.aspectj.aspect.AnnotationSecurityAspect")))
.isNotNull();
assertThat(this.spring.getContext().getBean(AspectJMethodSecurityInterceptor.class)).isNotNull();
// TODO diagnose why aspectj isn't weaving method security advice around
// MethodSecurityServiceImpl
}
@Test
public void contextRefreshWhenUsingAspectJAndCustomGlobalMethodSecurityConfigurationThenAutowire()
throws Exception {
this.spring.register(AspectJModeExtendsGMSCConfig.class).autowire();
assertThat(this.spring.getContext().getBean(
Class.forName("org.springframework.security.access.intercept.aspectj.aspect.AnnotationSecurityAspect")))
.isNotNull();
assertThat(this.spring.getContext().getBean(AspectJMethodSecurityInterceptor.class)).isNotNull();
}
@Test
@WithMockUser
public void methodSecurityWhenOrderSpecifiedThenConfigured() {
this.spring.register(CustomOrderConfig.class, MethodSecurityServiceConfig.class).autowire();
assertThat(this.spring.getContext().getBean("metaDataSourceAdvisor", MethodSecurityMetadataSourceAdvisor.class)
.getOrder()).isEqualTo(-135);
assertThatExceptionOfType(AccessDeniedException.class).isThrownBy(() -> this.service.jsr250());
}
@Test
@WithMockUser
public void methodSecurityWhenOrderUnspecifiedThenConfiguredToLowestPrecedence() {
this.spring.register(DefaultOrderConfig.class, MethodSecurityServiceConfig.class).autowire();
assertThat(this.spring.getContext().getBean("metaDataSourceAdvisor", MethodSecurityMetadataSourceAdvisor.class)
.getOrder()).isEqualTo(Ordered.LOWEST_PRECEDENCE);
assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(() -> this.service.jsr250());
}
@Test
@WithMockUser
public void methodSecurityWhenOrderUnspecifiedAndCustomGlobalMethodSecurityConfigurationThenConfiguredToLowestPrecedence() {
this.spring.register(DefaultOrderExtendsMethodSecurityConfig.class, MethodSecurityServiceConfig.class)
.autowire();
assertThat(this.spring.getContext().getBean("metaDataSourceAdvisor", MethodSecurityMetadataSourceAdvisor.class)
.getOrder()).isEqualTo(Ordered.LOWEST_PRECEDENCE);
assertThatExceptionOfType(UnsupportedOperationException.class).isThrownBy(() -> this.service.jsr250());
}
@Test
@WithMockUser
public void methodSecurityWhenPrePostEnabledThenPreAuthorizes() {
this.spring.register(PreAuthorizeConfig.class, MethodSecurityServiceConfig.class).autowire();
this.service.secured();
this.service.jsr250();
assertThatExceptionOfType(AccessDeniedException.class).isThrownBy(() -> this.service.preAuthorize());
}
@Test
@WithMockUser
public void methodSecurityWhenPrePostEnabledAndCustomGlobalMethodSecurityConfigurationThenPreAuthorizes() {
this.spring.register(PreAuthorizeExtendsGMSCConfig.class, MethodSecurityServiceConfig.class).autowire();
this.service.secured();
this.service.jsr250();
assertThatExceptionOfType(AccessDeniedException.class).isThrownBy(() -> this.service.preAuthorize());
}
@Test
@WithMockUser
public void methodSecurityWhenProxyTargetClassThenDoesNotWireToInterface() {
this.spring.register(ProxyTargetClassConfig.class, MethodSecurityServiceConfig.class).autowire();
// make sure service was actually proxied
assertThat(this.service.getClass().getInterfaces()).doesNotContain(MethodSecurityService.class);
assertThatExceptionOfType(AccessDeniedException.class).isThrownBy(() -> this.service.preAuthorize());
}
@Test
@WithMockUser
public void methodSecurityWhenDefaultProxyThenWiresToInterface() {
this.spring.register(DefaultProxyConfig.class, MethodSecurityServiceConfig.class).autowire();
assertThat(this.service.getClass().getInterfaces()).contains(MethodSecurityService.class);
assertThatExceptionOfType(AccessDeniedException.class).isThrownBy(() -> this.service.preAuthorize());
}
@Test
@WithMockUser
public void methodSecurityWhenCustomRunAsManagerThenRunAsWrapsAuthentication() {
this.spring.register(CustomRunAsManagerConfig.class, MethodSecurityServiceConfig.class).autowire();
assertThat(this.service.runAs().getAuthorities())
.anyMatch((authority) -> "ROLE_RUN_AS_SUPER".equals(authority.getAuthority()));
}
@Test
@WithMockUser
public void methodSecurityWhenSecuredEnabledThenSecures() {
this.spring.register(SecuredConfig.class, MethodSecurityServiceConfig.class).autowire();
assertThatExceptionOfType(AccessDeniedException.class).isThrownBy(() -> this.service.secured());
this.service.securedUser();
this.service.preAuthorize();
this.service.jsr250();
}
@Test
@WithMockUser
public void methodSecurityWhenMissingEnableAnnotationThenShowsHelpfulError() {
assertThatExceptionOfType(Exception.class)
.isThrownBy(() -> this.spring.register(ExtendsNoEnableAnntotationConfig.class).autowire())
.withStackTraceContaining(EnableGlobalMethodSecurity.class.getName() + " is required");
}
@Test
@WithMockUser
public void methodSecurityWhenImportingGlobalMethodSecurityConfigurationSubclassThenAuthorizes() {
this.spring.register(ImportSubclassGMSCConfig.class, MethodSecurityServiceConfig.class).autowire();
this.service.secured();
this.service.jsr250();
assertThatExceptionOfType(AccessDeniedException.class).isThrownBy(() -> this.service.preAuthorize());
}
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
@@ -98,32 +244,29 @@ public class NamespaceGlobalMethodSecurityTests {
}
public static class DenyAllAccessDecisionManager implements AccessDecisionManager {
public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) {
@Override
public void decide(Authentication authentication, Object object,
Collection<ConfigAttribute> configAttributes) {
throw new AccessDeniedException("Always Denied");
}
@Override
public boolean supports(ConfigAttribute attribute) {
return true;
}
@Override
public boolean supports(Class<?> clazz) {
return true;
}
}
}
// --- after-invocation-provider
@Test
@WithMockUser
public void methodSecurityWhenCustomAfterInvocationManagerThenAuthorizes() {
this.spring.register(CustomAfterInvocationManagerConfig.class, MethodSecurityServiceConfig.class).autowire();
assertThatThrownBy(() -> this.service.preAuthorizePermitAll())
.isInstanceOf(AccessDeniedException.class);
}
@EnableGlobalMethodSecurity(prePostEnabled = true)
public static class CustomAfterInvocationManagerConfig
extends GlobalMethodSecurityConfiguration {
public static class CustomAfterInvocationManagerConfig extends GlobalMethodSecurityConfiguration {
@Override
protected AfterInvocationManager afterInvocationManager() {
@@ -131,32 +274,25 @@ public class NamespaceGlobalMethodSecurityTests {
}
public static class AfterInvocationManagerStub implements AfterInvocationManager {
public Object decide(Authentication authentication,
Object object,
Collection<ConfigAttribute> attributes,
Object returnedObject) throws AccessDeniedException {
@Override
public Object decide(Authentication authentication, Object object, Collection<ConfigAttribute> attributes,
Object returnedObject) throws AccessDeniedException {
throw new AccessDeniedException("custom AfterInvocationManager");
}
@Override
public boolean supports(ConfigAttribute attribute) {
return true;
}
@Override
public boolean supports(Class<?> clazz) {
return true;
}
}
}
// --- authentication-manager-ref ---
@Test
@WithMockUser
public void methodSecurityWhenCustomAuthenticationManagerThenAuthorizes() {
this.spring.register(CustomAuthenticationConfig.class, MethodSecurityServiceConfig.class).autowire();
assertThatThrownBy(() -> this.service.preAuthorize())
.isInstanceOf(UnsupportedOperationException.class);
}
@EnableGlobalMethodSecurity(prePostEnabled = true)
@@ -175,26 +311,6 @@ public class NamespaceGlobalMethodSecurityTests {
throw new UnsupportedOperationException();
};
}
}
// --- jsr250-annotations ---
@Test
@WithMockUser
public void methodSecurityWhenJsr250EnabledThenAuthorizes() {
this.spring.register(Jsr250Config.class, MethodSecurityServiceConfig.class).autowire();
assertThatCode(() -> this.service.preAuthorize())
.doesNotThrowAnyException();
assertThatCode(() -> this.service.secured())
.doesNotThrowAnyException();
assertThatThrownBy(() -> this.service.jsr250())
.isInstanceOf(AccessDeniedException.class);
assertThatCode(() -> this.service.jsr250PermitAll())
.doesNotThrowAnyException();
}
@@ -204,53 +320,27 @@ public class NamespaceGlobalMethodSecurityTests {
}
// --- metadata-source-ref ---
@Test
@WithMockUser
public void methodSecurityWhenCustomMethodSecurityMetadataSourceThenAuthorizes() {
this.spring.register(CustomMethodSecurityMetadataSourceConfig.class, MethodSecurityServiceConfig.class).autowire();
assertThatThrownBy(() -> this.service.preAuthorize())
.isInstanceOf(AccessDeniedException.class);
assertThatThrownBy(() -> this.service.secured())
.isInstanceOf(AccessDeniedException.class);
assertThatThrownBy(() -> this.service.jsr250())
.isInstanceOf(AccessDeniedException.class);
}
@EnableGlobalMethodSecurity
public static class CustomMethodSecurityMetadataSourceConfig extends GlobalMethodSecurityConfiguration {
@Override
protected MethodSecurityMetadataSource customMethodSecurityMetadataSource() {
return new AbstractMethodSecurityMetadataSource() {
@Override
public Collection<ConfigAttribute> getAttributes(Method method, Class<?> targetClass) {
// require ROLE_NOBODY for any method on MethodSecurityService interface
return MethodSecurityService.class.isAssignableFrom(targetClass) ?
Arrays.asList(new SecurityConfig("ROLE_NOBODY")) :
Collections.emptyList();
// require ROLE_NOBODY for any method on MethodSecurityService
// interface
return MethodSecurityService.class.isAssignableFrom(targetClass)
? Arrays.asList(new SecurityConfig("ROLE_NOBODY")) : Collections.emptyList();
}
@Override
public Collection<ConfigAttribute> getAllConfigAttributes() {
return null;
}
};
}
}
// --- mode ---
@Test
@WithMockUser
public void contextRefreshWhenUsingAspectJThenAutowire() throws Exception {
this.spring.register(AspectJModeConfig.class, MethodSecurityServiceConfig.class).autowire();
assertThat(this.spring.getContext().getBean(Class.forName("org.springframework.security.access.intercept.aspectj.aspect.AnnotationSecurityAspect"))).isNotNull();
assertThat(this.spring.getContext().getBean(AspectJMethodSecurityInterceptor.class)).isNotNull();
//TODO diagnose why aspectj isn't weaving method security advice around MethodSecurityServiceImpl
}
@EnableGlobalMethodSecurity(mode = AdviceMode.ASPECTJ, securedEnabled = true)
@@ -258,64 +348,37 @@ public class NamespaceGlobalMethodSecurityTests {
}
@Test
public void contextRefreshWhenUsingAspectJAndCustomGlobalMethodSecurityConfigurationThenAutowire()
throws Exception {
this.spring.register(AspectJModeExtendsGMSCConfig.class).autowire();
assertThat(this.spring.getContext().getBean(Class.forName("org.springframework.security.access.intercept.aspectj.aspect.AnnotationSecurityAspect"))).isNotNull();
assertThat(this.spring.getContext().getBean(AspectJMethodSecurityInterceptor.class)).isNotNull();
}
@EnableGlobalMethodSecurity(mode = AdviceMode.ASPECTJ, securedEnabled = true)
public static class AspectJModeExtendsGMSCConfig extends GlobalMethodSecurityConfiguration {
}
// --- order ---
private static class AdvisorOrderConfig
implements ImportBeanDefinitionRegistrar {
private static class ExceptingInterceptor implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) {
throw new UnsupportedOperationException("Deny All");
}
}
private static class AdvisorOrderConfig implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
BeanDefinitionBuilder advice = BeanDefinitionBuilder
.rootBeanDefinition(ExceptingInterceptor.class);
registry.registerBeanDefinition("exceptingInterceptor",
advice.getBeanDefinition());
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
BeanDefinitionRegistry registry) {
BeanDefinitionBuilder advice = BeanDefinitionBuilder.rootBeanDefinition(ExceptingInterceptor.class);
registry.registerBeanDefinition("exceptingInterceptor", advice.getBeanDefinition());
BeanDefinitionBuilder advisor = BeanDefinitionBuilder
.rootBeanDefinition(MethodSecurityMetadataSourceAdvisor.class);
.rootBeanDefinition(MethodSecurityMetadataSourceAdvisor.class);
advisor.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
advisor.addConstructorArgValue("exceptingInterceptor");
advisor.addConstructorArgReference("methodSecurityMetadataSource");
advisor.addConstructorArgValue("methodSecurityMetadataSource");
advisor.addPropertyValue("order", 0);
registry.registerBeanDefinition("exceptingAdvisor",
advisor.getBeanDefinition());
registry.registerBeanDefinition("exceptingAdvisor", advisor.getBeanDefinition());
}
}
@Test
@WithMockUser
public void methodSecurityWhenOrderSpecifiedThenConfigured() {
this.spring.register(CustomOrderConfig.class, MethodSecurityServiceConfig.class).autowire();
private static class ExceptingInterceptor implements MethodInterceptor {
assertThat(this.spring.getContext()
.getBean("metaDataSourceAdvisor", MethodSecurityMetadataSourceAdvisor.class)
.getOrder())
.isEqualTo(-135);
@Override
public Object invoke(MethodInvocation invocation) {
throw new UnsupportedOperationException("Deny All");
}
}
assertThatThrownBy(() -> this.service.jsr250())
.isInstanceOf(AccessDeniedException.class);
}
@EnableGlobalMethodSecurity(order = -135, jsr250Enabled = true)
@@ -324,128 +387,36 @@ public class NamespaceGlobalMethodSecurityTests {
}
@Test
@WithMockUser
public void methodSecurityWhenOrderUnspecifiedThenConfiguredToLowestPrecedence() {
this.spring.register(DefaultOrderConfig.class, MethodSecurityServiceConfig.class).autowire();
assertThat(this.spring.getContext()
.getBean("metaDataSourceAdvisor", MethodSecurityMetadataSourceAdvisor.class)
.getOrder())
.isEqualTo(Ordered.LOWEST_PRECEDENCE);
assertThatThrownBy(() -> this.service.jsr250())
.isInstanceOf(UnsupportedOperationException.class);
}
@EnableGlobalMethodSecurity(jsr250Enabled = true)
@Import(AdvisorOrderConfig.class)
public static class DefaultOrderConfig {
}
@Test
@WithMockUser
public void methodSecurityWhenOrderUnspecifiedAndCustomGlobalMethodSecurityConfigurationThenConfiguredToLowestPrecedence() {
this.spring.register(DefaultOrderExtendsMethodSecurityConfig.class, MethodSecurityServiceConfig.class).autowire();
assertThat(this.spring.getContext()
.getBean("metaDataSourceAdvisor", MethodSecurityMetadataSourceAdvisor.class)
.getOrder())
.isEqualTo(Ordered.LOWEST_PRECEDENCE);
assertThatThrownBy(() -> this.service.jsr250())
.isInstanceOf(UnsupportedOperationException.class);
}
@EnableGlobalMethodSecurity(jsr250Enabled = true)
@Import(AdvisorOrderConfig.class)
public static class DefaultOrderExtendsMethodSecurityConfig extends GlobalMethodSecurityConfiguration {
}
// --- pre-post-annotations ---
@Test
@WithMockUser
public void methodSecurityWhenPrePostEnabledThenPreAuthorizes() {
this.spring.register(PreAuthorizeConfig.class, MethodSecurityServiceConfig.class).autowire();
assertThatCode(() -> this.service.secured())
.doesNotThrowAnyException();
assertThatCode(() -> this.service.jsr250())
.doesNotThrowAnyException();
assertThatThrownBy(() -> this.service.preAuthorize())
.isInstanceOf(AccessDeniedException.class);
}
@EnableGlobalMethodSecurity(prePostEnabled = true)
public static class PreAuthorizeConfig {
}
@Test
@WithMockUser
public void methodSecurityWhenPrePostEnabledAndCustomGlobalMethodSecurityConfigurationThenPreAuthorizes() {
this.spring.register(PreAuthorizeExtendsGMSCConfig.class, MethodSecurityServiceConfig.class).autowire();
assertThatCode(() -> this.service.secured())
.doesNotThrowAnyException();
assertThatCode(() -> this.service.jsr250())
.doesNotThrowAnyException();
assertThatThrownBy(() -> this.service.preAuthorize())
.isInstanceOf(AccessDeniedException.class);
}
@EnableGlobalMethodSecurity(prePostEnabled = true)
public static class PreAuthorizeExtendsGMSCConfig extends GlobalMethodSecurityConfiguration {
}
// --- proxy-target-class ---
@Test
@WithMockUser
public void methodSecurityWhenProxyTargetClassThenDoesNotWireToInterface() {
this.spring.register(ProxyTargetClassConfig.class, MethodSecurityServiceConfig.class).autowire();
// make sure service was actually proxied
assertThat(this.service.getClass().getInterfaces())
.doesNotContain(MethodSecurityService.class);
assertThatThrownBy(() -> this.service.preAuthorize())
.isInstanceOf(AccessDeniedException.class);
}
@EnableGlobalMethodSecurity(proxyTargetClass = true, prePostEnabled = true)
public static class ProxyTargetClassConfig {
}
@Test
@WithMockUser
public void methodSecurityWhenDefaultProxyThenWiresToInterface() {
this.spring.register(DefaultProxyConfig.class, MethodSecurityServiceConfig.class).autowire();
assertThat(this.service.getClass().getInterfaces())
.contains(MethodSecurityService.class);
assertThatThrownBy(() -> this.service.preAuthorize())
.isInstanceOf(AccessDeniedException.class);
}
@EnableGlobalMethodSecurity(prePostEnabled = true)
public static class DefaultProxyConfig {
}
// --- run-as-manager-ref ---
@Test
@WithMockUser
public void methodSecurityWhenCustomRunAsManagerThenRunAsWrapsAuthentication() {
this.spring.register(CustomRunAsManagerConfig.class, MethodSecurityServiceConfig.class).autowire();
assertThat(service.runAs().getAuthorities())
.anyMatch(authority -> "ROLE_RUN_AS_SUPER".equals(authority.getAuthority()));
}
@EnableGlobalMethodSecurity(securedEnabled = true)
@@ -457,64 +428,23 @@ public class NamespaceGlobalMethodSecurityTests {
runAsManager.setKey("some key");
return runAsManager;
}
}
// --- secured-annotation ---
@Test
@WithMockUser
public void methodSecurityWhenSecuredEnabledThenSecures() {
this.spring.register(SecuredConfig.class, MethodSecurityServiceConfig.class).autowire();
assertThatThrownBy(() -> this.service.secured())
.isInstanceOf(AccessDeniedException.class);
assertThatCode(() -> this.service.securedUser())
.doesNotThrowAnyException();
assertThatCode(() -> this.service.preAuthorize())
.doesNotThrowAnyException();
assertThatCode(() -> this.service.jsr250())
.doesNotThrowAnyException();
}
@EnableGlobalMethodSecurity(securedEnabled = true)
public static class SecuredConfig {
}
// --- unsorted ---
@Test
@WithMockUser
public void methodSecurityWhenMissingEnableAnnotationThenShowsHelpfulError() {
assertThatThrownBy(() ->
this.spring.register(ExtendsNoEnableAnntotationConfig.class).autowire())
.hasStackTraceContaining(EnableGlobalMethodSecurity.class.getName() + " is required");
}
@Configuration
public static class ExtendsNoEnableAnntotationConfig
extends GlobalMethodSecurityConfiguration {
}
public static class ExtendsNoEnableAnntotationConfig extends GlobalMethodSecurityConfiguration {
@Test
@WithMockUser
public void methodSecurityWhenImportingGlobalMethodSecurityConfigurationSubclassThenAuthorizes() {
this.spring.register(ImportSubclassGMSCConfig.class, MethodSecurityServiceConfig.class).autowire();
assertThatCode(() -> this.service.secured())
.doesNotThrowAnyException();
assertThatCode(() -> this.service.jsr250())
.doesNotThrowAnyException();
assertThatThrownBy(() -> this.service.preAuthorize())
.isInstanceOf(AccessDeniedException.class);
}
@Configuration
@Import(PreAuthorizeExtendsGMSCConfig.class)
public static class ImportSubclassGMSCConfig {
}
}

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.method.configuration;
import org.reactivestreams.Publisher;
@@ -20,23 +21,37 @@ import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
public interface ReactiveMessageService {
String notPublisherPreAuthorizeFindById(long id);
Mono<String> monoFindById(long id);
Mono<String> monoPreAuthorizeHasRoleFindById(long id);
Mono<String> monoPostAuthorizeFindById(long id);
Mono<String> monoPreAuthorizeBeanFindById(long id);
Mono<String> monoPostAuthorizeBeanFindById(long id);
Flux<String> fluxFindById(long id);
Flux<String> fluxPreAuthorizeHasRoleFindById(long id);
Flux<String> fluxPostAuthorizeFindById(long id);
Flux<String> fluxPreAuthorizeBeanFindById(long id);
Flux<String> fluxPostAuthorizeBeanFindById(long id);
Publisher<String> publisherFindById(long id);
Publisher<String> publisherPreAuthorizeHasRoleFindById(long id);
Publisher<String> publisherPostAuthorizeFindById(long id);
Publisher<String> publisherPreAuthorizeBeanFindById(long id);
Publisher<String> publisherPostAuthorizeBeanFindById(long id);
}

View File

@@ -16,10 +16,9 @@
package org.springframework.security.config.annotation.method.configuration;
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -31,6 +30,8 @@ import org.springframework.security.authentication.TestingAuthenticationToken;
import org.springframework.security.config.core.GrantedAuthorityDefaults;
import org.springframework.security.config.test.SpringTestRule;
import static org.assertj.core.api.Assertions.assertThat;
/**
* @author Tadaya Tsuyukubo
*/
@@ -45,16 +46,12 @@ public class ReactiveMethodSecurityConfigurationTests {
@Test
public void rolePrefixWithGrantedAuthorityDefaults() throws NoSuchMethodException {
this.spring.register(WithRolePrefixConfiguration.class).autowire();
TestingAuthenticationToken authentication = new TestingAuthenticationToken(
"principal", "credential", "CUSTOM_ABC");
TestingAuthenticationToken authentication = new TestingAuthenticationToken("principal", "credential",
"CUSTOM_ABC");
MockMethodInvocation methodInvocation = new MockMethodInvocation(new Foo(), Foo.class, "bar", String.class);
EvaluationContext context = this.methodSecurityExpressionHandler
.createEvaluationContext(authentication, methodInvocation);
SecurityExpressionRoot root = (SecurityExpressionRoot) context.getRootObject()
.getValue();
EvaluationContext context = this.methodSecurityExpressionHandler.createEvaluationContext(authentication,
methodInvocation);
SecurityExpressionRoot root = (SecurityExpressionRoot) context.getRootObject().getValue();
assertThat(root.hasRole("ROLE_ABC")).isFalse();
assertThat(root.hasRole("ROLE_CUSTOM_ABC")).isFalse();
assertThat(root.hasRole("CUSTOM_ABC")).isTrue();
@@ -64,16 +61,25 @@ public class ReactiveMethodSecurityConfigurationTests {
@Test
public void rolePrefixWithDefaultConfig() throws NoSuchMethodException {
this.spring.register(ReactiveMethodSecurityConfiguration.class).autowire();
TestingAuthenticationToken authentication = new TestingAuthenticationToken(
"principal", "credential", "ROLE_ABC");
TestingAuthenticationToken authentication = new TestingAuthenticationToken("principal", "credential",
"ROLE_ABC");
MockMethodInvocation methodInvocation = new MockMethodInvocation(new Foo(), Foo.class, "bar", String.class);
EvaluationContext context = this.methodSecurityExpressionHandler.createEvaluationContext(authentication,
methodInvocation);
SecurityExpressionRoot root = (SecurityExpressionRoot) context.getRootObject().getValue();
assertThat(root.hasRole("ROLE_ABC")).isTrue();
assertThat(root.hasRole("ABC")).isTrue();
}
EvaluationContext context = this.methodSecurityExpressionHandler
.createEvaluationContext(authentication, methodInvocation);
SecurityExpressionRoot root = (SecurityExpressionRoot) context.getRootObject()
.getValue();
@Test
public void rolePrefixWithGrantedAuthorityDefaultsAndSubclassWithProxyingEnabled() throws NoSuchMethodException {
this.spring.register(SubclassConfig.class).autowire();
TestingAuthenticationToken authentication = new TestingAuthenticationToken("principal", "credential",
"ROLE_ABC");
MockMethodInvocation methodInvocation = new MockMethodInvocation(new Foo(), Foo.class, "bar", String.class);
EvaluationContext context = this.methodSecurityExpressionHandler.createEvaluationContext(authentication,
methodInvocation);
SecurityExpressionRoot root = (SecurityExpressionRoot) context.getRootObject().getValue();
assertThat(root.hasRole("ROLE_ABC")).isTrue();
assertThat(root.hasRole("ABC")).isTrue();
}
@@ -81,35 +87,24 @@ public class ReactiveMethodSecurityConfigurationTests {
@Configuration
@EnableReactiveMethodSecurity // this imports ReactiveMethodSecurityConfiguration
static class WithRolePrefixConfiguration {
@Bean
GrantedAuthorityDefaults grantedAuthorityDefaults() {
return new GrantedAuthorityDefaults("CUSTOM_");
}
}
@Test
public void rolePrefixWithGrantedAuthorityDefaultsAndSubclassWithProxyingEnabled() throws NoSuchMethodException {
this.spring.register(SubclassConfig.class).autowire();
TestingAuthenticationToken authentication = new TestingAuthenticationToken(
"principal", "credential", "ROLE_ABC");
MockMethodInvocation methodInvocation = new MockMethodInvocation(new Foo(), Foo.class, "bar", String.class);
EvaluationContext context = this.methodSecurityExpressionHandler
.createEvaluationContext(authentication, methodInvocation);
SecurityExpressionRoot root = (SecurityExpressionRoot) context.getRootObject()
.getValue();
assertThat(root.hasRole("ROLE_ABC")).isTrue();
assertThat(root.hasRole("ABC")).isTrue();
}
@Configuration
static class SubclassConfig extends ReactiveMethodSecurityConfiguration {
}
private static class Foo {
public void bar(String param){
static class Foo {
public void bar(String param) {
}
}
}

View File

@@ -13,11 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.method.configuration;
import java.io.Serializable;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.access.AccessDeniedException;
@@ -30,10 +34,8 @@ import org.springframework.security.config.test.SpringTestRule;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import java.io.Serializable;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
/**
* Demonstrate the samples
@@ -42,6 +44,7 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy;
*
*/
public class SampleEnableGlobalMethodSecurityTests {
@Rule
public final SpringTestRule spring = new SpringTestRule();
@@ -50,51 +53,50 @@ public class SampleEnableGlobalMethodSecurityTests {
@Before
public void setup() {
SecurityContextHolder.getContext().setAuthentication(
new TestingAuthenticationToken("user", "password", "ROLE_USER"));
SecurityContextHolder.getContext()
.setAuthentication(new TestingAuthenticationToken("user", "password", "ROLE_USER"));
}
@Test
public void preAuthorize() {
this.spring.register(SampleWebSecurityConfig.class).autowire();
assertThat(this.methodSecurityService.secured()).isNull();
assertThat(this.methodSecurityService.jsr250()).isNull();
assertThatThrownBy(() -> this.methodSecurityService.preAuthorize())
.isInstanceOf(AccessDeniedException.class);
assertThatExceptionOfType(AccessDeniedException.class)
.isThrownBy(() -> this.methodSecurityService.preAuthorize());
}
@EnableGlobalMethodSecurity(prePostEnabled=true)
@Test
public void customPermissionHandler() {
this.spring.register(CustomPermissionEvaluatorWebSecurityConfig.class).autowire();
assertThat(this.methodSecurityService.hasPermission("allowed")).isNull();
assertThatExceptionOfType(AccessDeniedException.class)
.isThrownBy(() -> this.methodSecurityService.hasPermission("denied"));
}
@EnableGlobalMethodSecurity(prePostEnabled = true)
static class SampleWebSecurityConfig {
@Bean
public MethodSecurityService methodSecurityService() {
MethodSecurityService methodSecurityService() {
return new MethodSecurityServiceImpl();
}
@Autowired
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// @formatter:off
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER").and()
.withUser("admin").password("password").roles("USER", "ADMIN");
// @formatter:on
}
}
@Test
public void customPermissionHandler() {
this.spring.register(CustomPermissionEvaluatorWebSecurityConfig.class).autowire();
assertThat(this.methodSecurityService.hasPermission("allowed")).isNull();
assertThatThrownBy(() -> this.methodSecurityService.hasPermission("denied"))
.isInstanceOf(AccessDeniedException.class);
}
@EnableGlobalMethodSecurity(prePostEnabled=true)
@EnableGlobalMethodSecurity(prePostEnabled = true)
public static class CustomPermissionEvaluatorWebSecurityConfig extends GlobalMethodSecurityConfiguration {
@Bean
public MethodSecurityService methodSecurityService() {
return new MethodSecurityServiceImpl();
@@ -109,23 +111,29 @@ public class SampleEnableGlobalMethodSecurityTests {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// @formatter:off
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER").and()
.withUser("admin").password("password").roles("USER", "ADMIN");
// @formatter:on
}
}
static class CustomPermissionEvaluator implements PermissionEvaluator {
public boolean hasPermission(Authentication authentication,
Object targetDomainObject, Object permission) {
@Override
public boolean hasPermission(Authentication authentication, Object targetDomainObject, Object permission) {
return !"denied".equals(targetDomainObject);
}
public boolean hasPermission(Authentication authentication,
Serializable targetId, String targetType, Object permission) {
@Override
public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType,
Object permission) {
return !"denied".equals(targetId);
}
}
}

View File

@@ -13,15 +13,20 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.sec2758;
import javax.annotation.security.RolesAllowed;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.annotation.Bean;
import org.springframework.core.Ordered;
import org.springframework.core.PriorityOrdered;
import org.springframework.security.access.annotation.Jsr250MethodSecurityMetadataSource;
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
@@ -39,9 +44,6 @@ import org.springframework.test.web.servlet.MockMvc;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.security.RolesAllowed;
import static org.assertj.core.api.Assertions.assertThatCode;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@@ -65,44 +67,33 @@ public class Sec2758Tests {
@WithMockUser(authorities = "CUSTOM")
@Test
public void requestWhenNullifyingRolePrefixThenPassivityRestored() throws Exception {
this.spring.register(SecurityConfig.class).autowire();
this.mvc.perform(get("/")).andExpect(status().isOk());
}
@WithMockUser(authorities = "CUSTOM")
@Test
public void methodSecurityWhenNullifyingRolePrefixThenPassivityRestored() {
this.spring.register(SecurityConfig.class).autowire();
assertThatCode(() -> service.doJsr250())
.doesNotThrowAnyException();
assertThatCode(() -> service.doPreAuthorize())
.doesNotThrowAnyException();
this.service.doJsr250();
this.service.doPreAuthorize();
}
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled=true, jsr250Enabled = true)
@EnableGlobalMethodSecurity(prePostEnabled = true, jsr250Enabled = true)
static class SecurityConfig extends WebSecurityConfigurerAdapter {
@RestController
static class RootController {
@GetMapping("/")
public String ok() { return "ok"; }
}
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.authorizeRequests()
.anyRequest().access("hasAnyRole('CUSTOM')");
.authorizeRequests()
.anyRequest().access("hasAnyRole('CUSTOM')");
// @formatter:on
}
@Bean
public Service service() {
Service service() {
return new Service();
}
@@ -111,14 +102,28 @@ public class Sec2758Tests {
return new DefaultRolesPrefixPostProcessor();
}
@RestController
static class RootController {
@GetMapping("/")
String ok() {
return "ok";
}
}
}
static class Service {
@PreAuthorize("hasRole('CUSTOM')")
public void doPreAuthorize() {}
void doPreAuthorize() {
}
@RolesAllowed("CUSTOM")
public void doJsr250() {}
void doJsr250() {
}
}
static class DefaultRolesPrefixPostProcessor implements BeanPostProcessor, PriorityOrdered {
@@ -144,7 +149,9 @@ public class Sec2758Tests {
@Override
public int getOrder() {
return PriorityOrdered.HIGHEST_PRECEDENCE;
return Ordered.HIGHEST_PRECEDENCE;
}
}
}

View File

@@ -13,17 +13,19 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.SecurityConfigurer;
import org.springframework.security.config.annotation.SecurityConfigurerAdapter;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
@@ -34,6 +36,7 @@ import static org.mockito.Mockito.verify;
* @author Joe Grandja
*/
public class AbstractConfiguredSecurityBuilderTests {
private TestConfiguredSecurityBuilder builder;
@Before
@@ -80,7 +83,8 @@ public class AbstractConfiguredSecurityBuilderTests {
@Test(expected = IllegalStateException.class)
public void getConfigurerWhenMultipleConfigurersThenThrowIllegalStateException() throws Exception {
TestConfiguredSecurityBuilder builder = new TestConfiguredSecurityBuilder(mock(ObjectPostProcessor.class), true);
TestConfiguredSecurityBuilder builder = new TestConfiguredSecurityBuilder(mock(ObjectPostProcessor.class),
true);
builder.apply(new DelegateSecurityConfigurer());
builder.apply(new DelegateSecurityConfigurer());
builder.getConfigurer(DelegateSecurityConfigurer.class);
@@ -88,7 +92,8 @@ public class AbstractConfiguredSecurityBuilderTests {
@Test(expected = IllegalStateException.class)
public void removeConfigurerWhenMultipleConfigurersThenThrowIllegalStateException() throws Exception {
TestConfiguredSecurityBuilder builder = new TestConfiguredSecurityBuilder(mock(ObjectPostProcessor.class), true);
TestConfiguredSecurityBuilder builder = new TestConfiguredSecurityBuilder(mock(ObjectPostProcessor.class),
true);
builder.apply(new DelegateSecurityConfigurer());
builder.apply(new DelegateSecurityConfigurer());
builder.removeConfigurer(DelegateSecurityConfigurer.class);
@@ -98,10 +103,12 @@ public class AbstractConfiguredSecurityBuilderTests {
public void removeConfigurersWhenMultipleConfigurersThenConfigurersRemoved() throws Exception {
DelegateSecurityConfigurer configurer1 = new DelegateSecurityConfigurer();
DelegateSecurityConfigurer configurer2 = new DelegateSecurityConfigurer();
TestConfiguredSecurityBuilder builder = new TestConfiguredSecurityBuilder(mock(ObjectPostProcessor.class), true);
TestConfiguredSecurityBuilder builder = new TestConfiguredSecurityBuilder(mock(ObjectPostProcessor.class),
true);
builder.apply(configurer1);
builder.apply(configurer2);
List<DelegateSecurityConfigurer> removedConfigurers = builder.removeConfigurers(DelegateSecurityConfigurer.class);
List<DelegateSecurityConfigurer> removedConfigurers = builder
.removeConfigurers(DelegateSecurityConfigurer.class);
assertThat(removedConfigurers).hasSize(2);
assertThat(removedConfigurers).containsExactly(configurer1, configurer2);
assertThat(builder.getConfigurers(DelegateSecurityConfigurer.class)).isEmpty();
@@ -111,7 +118,8 @@ public class AbstractConfiguredSecurityBuilderTests {
public void getConfigurersWhenMultipleConfigurersThenConfigurersReturned() throws Exception {
DelegateSecurityConfigurer configurer1 = new DelegateSecurityConfigurer();
DelegateSecurityConfigurer configurer2 = new DelegateSecurityConfigurer();
TestConfiguredSecurityBuilder builder = new TestConfiguredSecurityBuilder(mock(ObjectPostProcessor.class), true);
TestConfiguredSecurityBuilder builder = new TestConfiguredSecurityBuilder(mock(ObjectPostProcessor.class),
true);
builder.apply(configurer1);
builder.apply(configurer2);
List<DelegateSecurityConfigurer> configurers = builder.getConfigurers(DelegateSecurityConfigurer.class);
@@ -120,29 +128,40 @@ public class AbstractConfiguredSecurityBuilderTests {
assertThat(builder.getConfigurers(DelegateSecurityConfigurer.class)).hasSize(2);
}
private static class DelegateSecurityConfigurer extends SecurityConfigurerAdapter<Object, TestConfiguredSecurityBuilder> {
private static class DelegateSecurityConfigurer
extends SecurityConfigurerAdapter<Object, TestConfiguredSecurityBuilder> {
private static SecurityConfigurer<Object, TestConfiguredSecurityBuilder> CONFIGURER;
@Override
public void init(TestConfiguredSecurityBuilder builder) throws Exception {
builder.apply(CONFIGURER);
}
}
private static class TestSecurityConfigurer extends SecurityConfigurerAdapter<Object, TestConfiguredSecurityBuilder> { }
private static class TestSecurityConfigurer
extends SecurityConfigurerAdapter<Object, TestConfiguredSecurityBuilder> {
private static class TestConfiguredSecurityBuilder extends AbstractConfiguredSecurityBuilder<Object, TestConfiguredSecurityBuilder> {
}
private static final class TestConfiguredSecurityBuilder
extends AbstractConfiguredSecurityBuilder<Object, TestConfiguredSecurityBuilder> {
private TestConfiguredSecurityBuilder(ObjectPostProcessor<Object> objectPostProcessor) {
super(objectPostProcessor);
}
private TestConfiguredSecurityBuilder(ObjectPostProcessor<Object> objectPostProcessor, boolean allowConfigurersOfSameType) {
private TestConfiguredSecurityBuilder(ObjectPostProcessor<Object> objectPostProcessor,
boolean allowConfigurersOfSameType) {
super(objectPostProcessor, allowConfigurersOfSameType);
}
@Override
public Object performBuild() {
return "success";
}
}
}

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web;
import org.junit.Test;
@@ -30,83 +31,28 @@ import org.springframework.web.context.support.AnnotationConfigWebApplicationCon
*
* @author Ankur Pathak
*/
public class AbstractRequestMatcherRegistryAnyMatcherTests{
@EnableWebSecurity
static class AntMatchersAfterAnyRequestConfig extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.antMatchers("/demo/**").permitAll();
}
}
public class AbstractRequestMatcherRegistryAnyMatcherTests {
@Test(expected = BeanCreationException.class)
public void antMatchersCanNotWorkAfterAnyRequest(){
public void antMatchersCanNotWorkAfterAnyRequest() {
loadConfig(AntMatchersAfterAnyRequestConfig.class);
}
@EnableWebSecurity
static class MvcMatchersAfterAnyRequestConfig extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.mvcMatchers("/demo/**").permitAll();
}
}
@Test(expected = BeanCreationException.class)
public void mvcMatchersCanNotWorkAfterAnyRequest() {
loadConfig(MvcMatchersAfterAnyRequestConfig.class);
}
@EnableWebSecurity
static class RegexMatchersAfterAnyRequestConfig extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.regexMatchers(".*").permitAll();
}
}
@Test(expected = BeanCreationException.class)
public void regexMatchersCanNotWorkAfterAnyRequest() {
loadConfig(RegexMatchersAfterAnyRequestConfig.class);
}
@EnableWebSecurity
static class AnyRequestAfterItselfConfig extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.anyRequest().permitAll();
}
}
@Test(expected = BeanCreationException.class)
public void anyRequestCanNotWorkAfterItself() {
loadConfig(AnyRequestAfterItselfConfig.class);
}
@EnableWebSecurity
static class RequestMatchersAfterAnyRequestConfig extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.requestMatchers(new AntPathRequestMatcher("/**")).permitAll();
}
}
@Test(expected = BeanCreationException.class)
public void requestMatchersCanNotWorkAfterAnyRequest() {
loadConfig(RequestMatchersAfterAnyRequestConfig.class);
@@ -119,4 +65,80 @@ public class AbstractRequestMatcherRegistryAnyMatcherTests{
context.setServletContext(new MockServletContext());
context.refresh();
}
@EnableWebSecurity
static class AntMatchersAfterAnyRequestConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.authorizeRequests()
.anyRequest().authenticated()
.antMatchers("/demo/**").permitAll();
// @formatter:on
}
}
@EnableWebSecurity
static class MvcMatchersAfterAnyRequestConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.authorizeRequests()
.anyRequest().authenticated()
.mvcMatchers("/demo/**").permitAll();
// @formatter:on
}
}
@EnableWebSecurity
static class RegexMatchersAfterAnyRequestConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.authorizeRequests()
.anyRequest().authenticated()
.regexMatchers(".*").permitAll();
// @formatter:on
}
}
@EnableWebSecurity
static class AnyRequestAfterItselfConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.authorizeRequests()
.anyRequest().authenticated()
.anyRequest().permitAll();
// @formatter:on
}
}
@EnableWebSecurity
static class RequestMatchersAfterAnyRequestConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.authorizeRequests()
.anyRequest().authenticated()
.requestMatchers(new AntPathRequestMatcher("/**")).permitAll();
// @formatter:on
}
}
}

View File

@@ -13,17 +13,19 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import org.springframework.http.HttpMethod;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RegexRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
/**
@@ -32,6 +34,7 @@ import static org.assertj.core.api.Assertions.assertThat;
* @author Joe Grandja
*/
public class AbstractRequestMatcherRegistryTests {
private TestRequestMatcherRegistry matcherRegistry;
@Before
@@ -87,5 +90,7 @@ public class AbstractRequestMatcherRegistryTests {
protected List<RequestMatcher> chainRequestMatchers(List<RequestMatcher> requestMatchers) {
return requestMatchers;
}
}
}

View File

@@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
package org.springframework.security.config.annotation.web;
import javax.servlet.Filter;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
@@ -40,8 +38,11 @@ import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
/**
*
* @author Rob Winch
*
*/
@@ -49,8 +50,10 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@ContextConfiguration
@WebAppConfiguration
public class HttpSecurityHeadersTests {
@Autowired
WebApplicationContext wac;
@Autowired
Filter springSecurityFilterChain;
@@ -58,44 +61,54 @@ public class HttpSecurityHeadersTests {
@Before
public void setup() {
mockMvc = MockMvcBuilders
.webAppContextSetup(wac)
.addFilters(springSecurityFilterChain)
.build();
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).addFilters(this.springSecurityFilterChain).build();
}
// gh-2953
// gh-3975
@Test
public void headerWhenSpringMvcResourceThenCacheRelatedHeadersReset() throws Exception {
mockMvc.perform(get("/resources/file.js"))
.andExpect(status().isOk())
.andExpect(header().string(HttpHeaders.CACHE_CONTROL, "max-age=12345"))
.andExpect(header().doesNotExist(HttpHeaders.PRAGMA))
.andExpect(header().doesNotExist(HttpHeaders.EXPIRES));
// @formatter:off
this.mockMvc.perform(get("/resources/file.js"))
.andExpect(status().isOk())
.andExpect(header().string(HttpHeaders.CACHE_CONTROL, "max-age=12345"))
.andExpect(header().doesNotExist(HttpHeaders.PRAGMA))
.andExpect(header().doesNotExist(HttpHeaders.EXPIRES));
// @formatter:on
}
@Test
public void headerWhenNotSpringResourceThenCacheRelatedHeadersSet() throws Exception {
mockMvc.perform(get("/notresource"))
.andExpect(header().string(HttpHeaders.CACHE_CONTROL, "no-cache, no-store, max-age=0, must-revalidate"))
.andExpect(header().string(HttpHeaders.PRAGMA, "no-cache"))
.andExpect(header().string(HttpHeaders.EXPIRES, "0"));
// @formatter:off
this.mockMvc.perform(get("/notresource"))
.andExpect(header().string(HttpHeaders.CACHE_CONTROL, "no-cache, no-store, max-age=0, must-revalidate"))
.andExpect(header().string(HttpHeaders.PRAGMA, "no-cache"))
.andExpect(header().string(HttpHeaders.EXPIRES, "0"));
// @formatter:on
}
@EnableWebSecurity
static class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) {
}
}
@EnableWebMvc
@Configuration
static class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("classpath:/resources/").setCachePeriod(12345);
// @formatter:off
registry.addResourceHandler("/resources/**")
.addResourceLocations("classpath:/resources/")
.setCachePeriod(12345);
// @formatter:on
}
}
}

View File

@@ -13,11 +13,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web;
import java.util.Base64;
import javax.servlet.http.HttpServletResponse;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
@@ -36,9 +42,6 @@ import org.springframework.security.web.csrf.CsrfToken;
import org.springframework.security.web.csrf.DefaultCsrfToken;
import org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository;
import javax.servlet.http.HttpServletResponse;
import java.util.Base64;
import static org.assertj.core.api.Assertions.assertThat;
/**
@@ -48,6 +51,7 @@ import static org.assertj.core.api.Assertions.assertThat;
* @author Joe Grandja
*/
public class SampleWebSecurityConfigurerAdapterTests {
@Rule
public final SpringTestRule spring = new SpringTestRule();
@@ -55,7 +59,9 @@ public class SampleWebSecurityConfigurerAdapterTests {
private FilterChainProxy springSecurityFilterChain;
private MockHttpServletRequest request;
private MockHttpServletResponse response;
private MockFilterChain chain;
@Before
@@ -63,7 +69,6 @@ public class SampleWebSecurityConfigurerAdapterTests {
this.request = new MockHttpServletRequest("GET", "");
this.response = new MockHttpServletResponse();
this.chain = new MockFilterChain();
CsrfToken csrfToken = new DefaultCsrfToken("X-CSRF-TOKEN", "_csrf", "CSRF-TOKEN-TEST");
new HttpSessionCsrfTokenRepository().saveToken(csrfToken, this.request, this.response);
this.request.setParameter(csrfToken.getParameterName(), csrfToken.getToken());
@@ -72,138 +77,187 @@ public class SampleWebSecurityConfigurerAdapterTests {
@Test
public void helloWorldSampleWhenRequestSecureResourceThenRedirectToLogin() throws Exception {
this.spring.register(HelloWorldWebSecurityConfigurerAdapter.class).autowire();
this.request.addHeader("Accept", "text/html");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getRedirectedUrl()).isEqualTo("http://localhost/login");
}
@Test
public void helloWorldSampleWhenRequestLoginWithoutCredentialsThenRedirectToLogin() throws Exception {
this.spring.register(HelloWorldWebSecurityConfigurerAdapter.class).autowire();
this.request.setServletPath("/login");
this.request.setMethod("POST");
this.request.addHeader("Accept", "text/html");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getRedirectedUrl()).isEqualTo("/login?error");
}
@Test
public void helloWorldSampleWhenRequestLoginWithValidCredentialsThenRedirectToIndex() throws Exception {
this.spring.register(HelloWorldWebSecurityConfigurerAdapter.class).autowire();
this.request.setServletPath("/login");
this.request.setMethod("POST");
this.request.addHeader("Accept", "text/html");
this.request.addParameter("username", "user");
this.request.addParameter("password", "password");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getRedirectedUrl()).isEqualTo("/");
}
/**
* <code>
* <http>
* <intercept-url pattern="/resources/**" access="permitAll"/>
* <intercept-url pattern="/**" access="authenticated"/>
* <logout
* logout-success-url="/login?logout"
* logout-url="/logout"
* <form-login
* authentication-failure-url="/login?error"
* login-page="/login" <!-- Except Spring Security renders the login page -->
* login-processing-url="/login" <!-- but only POST -->
* password-parameter="password"
* username-parameter="username"
* />
* </http>
* <authentication-manager>
* <authentication-provider>
* <user-service>
* <user username="user" password="password" authorities="ROLE_USER"/>
* </user-service>
* </authentication-provider>
* </authentication-manager>
* </code>
* @author Rob Winch
*/
@EnableWebSecurity
public static class HelloWorldWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser(PasswordEncodedUser.user());
}
}
@Test
public void readmeSampleWhenRequestSecureResourceThenRedirectToLogin() throws Exception {
this.spring.register(SampleWebSecurityConfigurerAdapter.class).autowire();
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getRedirectedUrl()).isEqualTo("http://localhost/login");
}
@Test
public void readmeSampleWhenRequestLoginWithoutCredentialsThenRedirectToLogin() throws Exception {
this.spring.register(SampleWebSecurityConfigurerAdapter.class).autowire();
this.request.setServletPath("/login");
this.request.setMethod("POST");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getRedirectedUrl()).isEqualTo("/login?error");
}
@Test
public void readmeSampleWhenRequestLoginWithValidCredentialsThenRedirectToIndex() throws Exception {
this.spring.register(SampleWebSecurityConfigurerAdapter.class).autowire();
this.request.setServletPath("/login");
this.request.setMethod("POST");
this.request.addParameter("username", "user");
this.request.addParameter("password", "password");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getRedirectedUrl()).isEqualTo("/");
}
@Test
public void multiHttpSampleWhenRequestSecureResourceThenRedirectToLogin() throws Exception {
this.spring.register(SampleMultiHttpSecurityConfig.class).autowire();
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getRedirectedUrl()).isEqualTo("http://localhost/login");
}
@Test
public void multiHttpSampleWhenRequestLoginWithoutCredentialsThenRedirectToLogin() throws Exception {
this.spring.register(SampleMultiHttpSecurityConfig.class).autowire();
this.request.setServletPath("/login");
this.request.setMethod("POST");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getRedirectedUrl()).isEqualTo("/login?error");
}
@Test
public void multiHttpSampleWhenRequestLoginWithValidCredentialsThenRedirectToIndex() throws Exception {
this.spring.register(SampleMultiHttpSecurityConfig.class).autowire();
this.request.setServletPath("/login");
this.request.setMethod("POST");
this.request.addParameter("username", "user");
this.request.addParameter("password", "password");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getRedirectedUrl()).isEqualTo("/");
}
@Test
public void multiHttpSampleWhenRequestProtectedResourceThenStatusUnauthorized() throws Exception {
this.spring.register(SampleMultiHttpSecurityConfig.class).autowire();
this.request.setServletPath("/api/admin/test");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
}
@Test
public void multiHttpSampleWhenRequestAdminResourceWithRegularUserThenStatusForbidden() throws Exception {
this.spring.register(SampleMultiHttpSecurityConfig.class).autowire();
this.request.setServletPath("/api/admin/test");
this.request.addHeader("Authorization",
"Basic " + Base64.getEncoder().encodeToString("user:password".getBytes()));
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_FORBIDDEN);
}
@Test
public void multiHttpSampleWhenRequestAdminResourceWithAdminUserThenStatusOk() throws Exception {
this.spring.register(SampleMultiHttpSecurityConfig.class).autowire();
this.request.setServletPath("/api/admin/test");
this.request.addHeader("Authorization",
"Basic " + Base64.getEncoder().encodeToString("admin:password".getBytes()));
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
}
/**
* <code>
* <http security="none" pattern="/resources/**"/>
* <http>
* <intercept-url pattern="/logout" access="permitAll"/>
* <intercept-url pattern="/login" access="permitAll"/>
* <intercept-url pattern="/signup" access="permitAll"/>
* <intercept-url pattern="/about" access="permitAll"/>
* <intercept-url pattern="/**" access="hasRole('ROLE_USER')"/>
* <logout
* <pre>
* &lt;http&gt;
* &lt;intercept-url pattern="/resources/**" access="permitAll"/&gt;
* &lt;intercept-url pattern="/**" access="authenticated"/&gt;
* &lt;logout
* logout-success-url="/login?logout"
* logout-url="/logout"
* <form-login
* &lt;form-login
* authentication-failure-url="/login?error"
* login-page="/login"
* login-processing-url="/login" <!-- but only POST -->
* login-page="/login" &lt;!-- Except Spring Security renders the login page --&gt;
* login-processing-url="/login" &lt;!-- but only POST --&gt;
* password-parameter="password"
* username-parameter="username"
* />
* </http>
* <authentication-manager>
* <authentication-provider>
* <user-service>
* <user username="user" password="password" authorities="ROLE_USER"/>
* <user username="admin" password="password" authorities="ROLE_USER,ROLE_ADMIN"/>
* </user-service>
* </authentication-provider>
* </authentication-manager>
* </code>
* /&gt;
* &lt;/http&gt;
* &lt;authentication-manager&gt;
* &lt;authentication-provider&gt;
* &lt;user-service&gt;
* &lt;user username="user" password="password" authorities="ROLE_USER"/&gt;
* &lt;/user-service&gt;
* &lt;/authentication-provider&gt;
* &lt;/authentication-manager&gt;
* </pre>
*
* @author Rob Winch
*/
@EnableWebSecurity
public static class HelloWorldWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// @formatter:off
auth
.inMemoryAuthentication()
.withUser(PasswordEncodedUser.user());
// @formatter:on
}
}
/**
* <pre>
* &lt;http security="none" pattern="/resources/**"/&gt;
* &lt;http&gt;
* &lt;intercept-url pattern="/logout" access="permitAll"/&gt;
* &lt;intercept-url pattern="/login" access="permitAll"/&gt;
* &lt;intercept-url pattern="/signup" access="permitAll"/&gt;
* &lt;intercept-url pattern="/about" access="permitAll"/&gt;
* &lt;intercept-url pattern="/**" access="hasRole('ROLE_USER')"/&gt;
* &lt;logout
* logout-success-url="/login?logout"
* logout-url="/logout"
* &lt;form-login
* authentication-failure-url="/login?error"
* login-page="/login"
* login-processing-url="/login" &lt;!-- but only POST --&gt;
* password-parameter="password"
* username-parameter="username"
* /&gt;
* &lt;/http&gt;
* &lt;authentication-manager&gt;
* &lt;authentication-provider&gt;
* &lt;user-service&gt;
* &lt;user username="user" password="password" authorities="ROLE_USER"/&gt;
* &lt;user username="admin" password="password" authorities=
"ROLE_USER,ROLE_ADMIN"/&gt;
* &lt;/user-service&gt;
* &lt;/authentication-provider&gt;
* &lt;/authentication-manager&gt;
* </pre>
*
* @author Rob Winch
*/
@EnableWebSecurity
@@ -211,13 +265,12 @@ public class SampleWebSecurityConfigurerAdapterTests {
@Override
public void configure(WebSecurity web) {
web
.ignoring()
.antMatchers("/resources/**");
web.ignoring().antMatchers("/resources/**");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.authorizeRequests()
.antMatchers("/signup", "/about").permitAll()
@@ -227,133 +280,79 @@ public class SampleWebSecurityConfigurerAdapterTests {
.loginPage("/login")
// set permitAll for all URLs associated with Form Login
.permitAll();
// @formatter:on
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// @formatter:off
auth
.inMemoryAuthentication()
.withUser(PasswordEncodedUser.user())
.withUser(PasswordEncodedUser.admin());
// @formatter:on
}
}
@Test
public void multiHttpSampleWhenRequestSecureResourceThenRedirectToLogin() throws Exception {
this.spring.register(SampleMultiHttpSecurityConfig.class).autowire();
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getRedirectedUrl()).isEqualTo("http://localhost/login");
}
@Test
public void multiHttpSampleWhenRequestLoginWithoutCredentialsThenRedirectToLogin() throws Exception {
this.spring.register(SampleMultiHttpSecurityConfig.class).autowire();
this.request.setServletPath("/login");
this.request.setMethod("POST");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getRedirectedUrl()).isEqualTo("/login?error");
}
@Test
public void multiHttpSampleWhenRequestLoginWithValidCredentialsThenRedirectToIndex() throws Exception {
this.spring.register(SampleMultiHttpSecurityConfig.class).autowire();
this.request.setServletPath("/login");
this.request.setMethod("POST");
this.request.addParameter("username", "user");
this.request.addParameter("password", "password");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getRedirectedUrl()).isEqualTo("/");
}
@Test
public void multiHttpSampleWhenRequestProtectedResourceThenStatusUnauthorized() throws Exception {
this.spring.register(SampleMultiHttpSecurityConfig.class).autowire();
this.request.setServletPath("/api/admin/test");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
}
@Test
public void multiHttpSampleWhenRequestAdminResourceWithRegularUserThenStatusForbidden() throws Exception {
this.spring.register(SampleMultiHttpSecurityConfig.class).autowire();
this.request.setServletPath("/api/admin/test");
this.request.addHeader("Authorization", "Basic " + Base64.getEncoder().encodeToString("user:password".getBytes()));
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_FORBIDDEN);
}
@Test
public void multiHttpSampleWhenRequestAdminResourceWithAdminUserThenStatusOk() throws Exception {
this.spring.register(SampleMultiHttpSecurityConfig.class).autowire();
this.request.setServletPath("/api/admin/test");
this.request.addHeader("Authorization", "Basic " + Base64.getEncoder().encodeToString("admin:password".getBytes()));
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
}
/**
* <code>
* <http security="none" pattern="/resources/**"/>
* <http pattern="/api/**">
* <intercept-url pattern="/api/admin/**" access="hasRole('ROLE_ADMIN')"/>
* <intercept-url pattern="/api/**" access="hasRole('ROLE_USER')"/>
* <http-basic />
* </http>
* <http>
* <intercept-url pattern="/logout" access="permitAll"/>
* <intercept-url pattern="/login" access="permitAll"/>
* <intercept-url pattern="/signup" access="permitAll"/>
* <intercept-url pattern="/about" access="permitAll"/>
* <intercept-url pattern="/**" access="hasRole('ROLE_USER')"/>
* <logout
* &lt;http security="none" pattern="/resources/**"/&gt;
* &lt;http pattern="/api/**"&gt;
* &lt;intercept-url pattern="/api/admin/**" access="hasRole('ROLE_ADMIN')"/&gt;
* &lt;intercept-url pattern="/api/**" access="hasRole('ROLE_USER')"/&gt;
* &lt;http-basic /&gt;
* &lt;/http&gt;
* &lt;http&gt;
* &lt;intercept-url pattern="/logout" access="permitAll"/&gt;
* &lt;intercept-url pattern="/login" access="permitAll"/&gt;
* &lt;intercept-url pattern="/signup" access="permitAll"/&gt;
* &lt;intercept-url pattern="/about" access="permitAll"/&gt;
* &lt;intercept-url pattern="/**" access="hasRole('ROLE_USER')"/&gt;
* &lt;logout
* logout-success-url="/login?logout"
* logout-url="/logout"
* <form-login
* &lt;form-login
* authentication-failure-url="/login?error"
* login-page="/login"
* login-processing-url="/login" <!-- but only POST -->
* login-processing-url="/login" &lt;!-- but only POST --&gt;
* password-parameter="password"
* username-parameter="username"
* />
* </http>
* <authentication-manager>
* <authentication-provider>
* <user-service>
* <user username="user" password="password" authorities="ROLE_USER"/>
* <user username="admin" password="password" authorities="ROLE_USER,ROLE_ADMIN"/>
* </user-service>
* </authentication-provider>
* </authentication-manager>
* /&gt;
* &lt;/http&gt;
* &lt;authentication-manager&gt;
* &lt;authentication-provider&gt;
* &lt;user-service&gt;
* &lt;user username="user" password="password" authorities="ROLE_USER"/&gt;
* &lt;user username="admin" password="password" authorities=
"ROLE_USER,ROLE_ADMIN"/&gt;
* &lt;/user-service&gt;
* &lt;/authentication-provider&gt;
* &lt;/authentication-manager&gt;
* </code>
*
* @author Rob Winch
*/
@EnableWebSecurity
public static class SampleMultiHttpSecurityConfig {
@Autowired
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// @formatter:off
auth
.inMemoryAuthentication()
.withUser(PasswordEncodedUser.user())
.withUser(PasswordEncodedUser.admin());
// @formatter:on
}
@Configuration
@Order(1)
public static class ApiWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.antMatcher("/api/**")
.authorizeRequests()
@@ -361,20 +360,22 @@ public class SampleWebSecurityConfigurerAdapterTests {
.antMatchers("/api/**").hasRole("USER")
.and()
.httpBasic();
// @formatter:on
}
}
@Configuration
public static class FormLoginWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
@Override
public void configure(WebSecurity web) {
web
.ignoring()
.antMatchers("/resources/**");
web.ignoring().antMatchers("/resources/**");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.authorizeRequests()
.antMatchers("/signup", "/about").permitAll()
@@ -383,7 +384,11 @@ public class SampleWebSecurityConfigurerAdapterTests {
.formLogin()
.loginPage("/login")
.permitAll();
// @formatter:on
}
}
}
}

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web;
import java.util.Arrays;
@@ -22,6 +23,7 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
@@ -48,19 +50,18 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.powermock.api.mockito.PowerMockito.spy;
import static org.powermock.api.mockito.PowerMockito.when;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
/**
*
* @author Rob Winch
*
*/
@RunWith(PowerMockRunner.class)
@PrepareForTest({ SpringFactoriesLoader.class, WebAsyncManager.class })
@PowerMockIgnore({ "org.w3c.dom.*", "org.xml.sax.*", "org.apache.xerces.*", "javax.xml.parsers.*", "javax.xml.transform.*" })
@PowerMockIgnore({ "org.w3c.dom.*", "org.xml.sax.*", "org.apache.xerces.*", "javax.xml.parsers.*",
"javax.xml.transform.*" })
public class WebSecurityConfigurerAdapterPowermockTests {
ConfigurableWebApplicationContext context;
@Rule
@@ -71,25 +72,39 @@ public class WebSecurityConfigurerAdapterPowermockTests {
@After
public void close() {
if (context != null) {
context.close();
if (this.context != null) {
this.context.close();
}
}
@Test
public void loadConfigWhenDefaultConfigurerAsSpringFactoryhenDefaultConfigurerApplied() {
spy(SpringFactoriesLoader.class);
PowerMockito.spy(SpringFactoriesLoader.class);
DefaultConfigurer configurer = new DefaultConfigurer();
when(SpringFactoriesLoader
.loadFactories(AbstractHttpConfigurer.class, getClass().getClassLoader()))
.thenReturn(Arrays.<AbstractHttpConfigurer>asList(configurer));
PowerMockito
.when(SpringFactoriesLoader.loadFactories(AbstractHttpConfigurer.class, getClass().getClassLoader()))
.thenReturn(Arrays.<AbstractHttpConfigurer>asList(configurer));
loadConfig(Config.class);
assertThat(configurer.init).isTrue();
assertThat(configurer.configure).isTrue();
}
@Test
public void loadConfigWhenDefaultConfigThenWebAsyncManagerIntegrationFilterAdded() throws Exception {
this.spring.register(WebAsyncPopulatedByDefaultConfig.class).autowire();
WebAsyncManager webAsyncManager = mock(WebAsyncManager.class);
this.mockMvc.perform(get("/").requestAttr(WebAsyncUtils.WEB_ASYNC_MANAGER_ATTRIBUTE, webAsyncManager));
ArgumentCaptor<CallableProcessingInterceptor> callableProcessingInterceptorArgCaptor = ArgumentCaptor
.forClass(CallableProcessingInterceptor.class);
verify(webAsyncManager, atLeastOnce()).registerCallableInterceptor(any(),
callableProcessingInterceptorArgCaptor.capture());
CallableProcessingInterceptor callableProcessingInterceptor = callableProcessingInterceptorArgCaptor
.getAllValues().stream()
.filter((e) -> SecurityContextCallableProcessingInterceptor.class.isAssignableFrom(e.getClass()))
.findFirst().orElse(null);
assertThat(callableProcessingInterceptor).isNotNull();
}
private void loadConfig(Class<?>... classes) {
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.setClassLoader(getClass().getClassLoader());
@@ -100,13 +115,17 @@ public class WebSecurityConfigurerAdapterPowermockTests {
@EnableWebSecurity
static class Config extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) {
}
}
static class DefaultConfigurer extends AbstractHttpConfigurer<DefaultConfigurer, HttpSecurity> {
boolean init;
boolean configure;
@Override
@@ -118,27 +137,7 @@ public class WebSecurityConfigurerAdapterPowermockTests {
public void configure(HttpSecurity builder) {
this.configure = true;
}
}
@Test
public void loadConfigWhenDefaultConfigThenWebAsyncManagerIntegrationFilterAdded() throws Exception {
this.spring.register(WebAsyncPopulatedByDefaultConfig.class).autowire();
WebAsyncManager webAsyncManager = mock(WebAsyncManager.class);
this.mockMvc.perform(get("/").requestAttr(WebAsyncUtils.WEB_ASYNC_MANAGER_ATTRIBUTE, webAsyncManager));
ArgumentCaptor<CallableProcessingInterceptor> callableProcessingInterceptorArgCaptor =
ArgumentCaptor.forClass(CallableProcessingInterceptor.class);
verify(webAsyncManager, atLeastOnce()).registerCallableInterceptor(any(), callableProcessingInterceptorArgCaptor.capture());
CallableProcessingInterceptor callableProcessingInterceptor =
callableProcessingInterceptorArgCaptor.getAllValues().stream()
.filter(e -> SecurityContextCallableProcessingInterceptor.class.isAssignableFrom(e.getClass()))
.findFirst()
.orElse(null);
assertThat(callableProcessingInterceptor).isNotNull();
}
@EnableWebSecurity
@@ -146,13 +145,17 @@ public class WebSecurityConfigurerAdapterPowermockTests {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// @formatter:off
auth
.inMemoryAuthentication()
.withUser(PasswordEncodedUser.user());
// @formatter:on
}
@Override
protected void configure(HttpSecurity http) {
}
}
}

View File

@@ -13,11 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
@@ -49,12 +51,13 @@ import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import org.springframework.web.accept.ContentNegotiationStrategy;
import org.springframework.web.accept.HeaderContentNegotiationStrategy;
import org.springframework.web.filter.OncePerRequestFilter;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.ThrowableAssert.catchThrowable;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
@@ -71,6 +74,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
* @author Joe Grandja
*/
public class WebSecurityConfigurerAdapterTests {
@Rule
public final SpringTestRule spring = new SpringTestRule();
@@ -80,15 +84,119 @@ public class WebSecurityConfigurerAdapterTests {
@Test
public void loadConfigWhenRequestSecureThenDefaultSecurityHeadersReturned() throws Exception {
this.spring.register(HeadersArePopulatedByDefaultConfig.class).autowire();
// @formatter:off
this.mockMvc.perform(get("/").secure(true))
.andExpect(header().string("X-Content-Type-Options", "nosniff"))
.andExpect(header().string("X-Frame-Options", "DENY"))
.andExpect(header().string("Strict-Transport-Security", "max-age=31536000 ; includeSubDomains"))
.andExpect(header().string("Cache-Control", "no-cache, no-store, max-age=0, must-revalidate"))
.andExpect(header().string("Pragma", "no-cache"))
.andExpect(header().string("Expires", "0"))
.andExpect(header().string("X-XSS-Protection", "1; mode=block"));
.andExpect(header().string("X-Content-Type-Options", "nosniff"))
.andExpect(header().string("X-Frame-Options", "DENY"))
.andExpect(header().string("Strict-Transport-Security", "max-age=31536000 ; includeSubDomains"))
.andExpect(header().string("Cache-Control", "no-cache, no-store, max-age=0, must-revalidate"))
.andExpect(header().string("Pragma", "no-cache")).andExpect(header().string("Expires", "0"))
.andExpect(header().string("X-XSS-Protection", "1; mode=block"));
// @formatter:on
}
@Test
public void loadConfigWhenRequestAuthenticateThenAuthenticationEventPublished() throws Exception {
this.spring.register(InMemoryAuthWithWebSecurityConfigurerAdapter.class).autowire();
this.mockMvc.perform(formLogin()).andExpect(status().is3xxRedirection());
assertThat(InMemoryAuthWithWebSecurityConfigurerAdapter.EVENTS).isNotEmpty();
assertThat(InMemoryAuthWithWebSecurityConfigurerAdapter.EVENTS).hasSize(1);
}
@Test
public void loadConfigWhenInMemoryConfigureProtectedThenPasswordUpgraded() throws Exception {
this.spring.register(InMemoryConfigureProtectedConfig.class).autowire();
this.mockMvc.perform(formLogin()).andExpect(status().is3xxRedirection());
UserDetailsService uds = this.spring.getContext().getBean(UserDetailsService.class);
assertThat(uds.loadUserByUsername("user").getPassword()).startsWith("{bcrypt}");
}
@Test
public void loadConfigWhenInMemoryConfigureGlobalThenPasswordUpgraded() throws Exception {
this.spring.register(InMemoryConfigureGlobalConfig.class).autowire();
this.mockMvc.perform(formLogin()).andExpect(status().is3xxRedirection());
UserDetailsService uds = this.spring.getContext().getBean(UserDetailsService.class);
assertThat(uds.loadUserByUsername("user").getPassword()).startsWith("{bcrypt}");
}
@Test
public void loadConfigWhenCustomContentNegotiationStrategyBeanThenOverridesDefault() {
OverrideContentNegotiationStrategySharedObjectConfig.CONTENT_NEGOTIATION_STRATEGY_BEAN = mock(
ContentNegotiationStrategy.class);
this.spring.register(OverrideContentNegotiationStrategySharedObjectConfig.class).autowire();
OverrideContentNegotiationStrategySharedObjectConfig securityConfig = this.spring.getContext()
.getBean(OverrideContentNegotiationStrategySharedObjectConfig.class);
assertThat(securityConfig.contentNegotiationStrategySharedObject).isNotNull();
assertThat(securityConfig.contentNegotiationStrategySharedObject)
.isSameAs(OverrideContentNegotiationStrategySharedObjectConfig.CONTENT_NEGOTIATION_STRATEGY_BEAN);
}
@Test
public void loadConfigWhenDefaultContentNegotiationStrategyThenHeaderContentNegotiationStrategy() {
this.spring.register(ContentNegotiationStrategyDefaultSharedObjectConfig.class).autowire();
ContentNegotiationStrategyDefaultSharedObjectConfig securityConfig = this.spring.getContext()
.getBean(ContentNegotiationStrategyDefaultSharedObjectConfig.class);
assertThat(securityConfig.contentNegotiationStrategySharedObject).isNotNull();
assertThat(securityConfig.contentNegotiationStrategySharedObject)
.isInstanceOf(HeaderContentNegotiationStrategy.class);
}
@Test
public void loadConfigWhenUserDetailsServiceHasCircularReferenceThenStillLoads() {
this.spring.register(RequiresUserDetailsServiceConfig.class, UserDetailsServiceConfig.class).autowire();
MyFilter myFilter = this.spring.getContext().getBean(MyFilter.class);
myFilter.userDetailsService.loadUserByUsername("user");
assertThatExceptionOfType(UsernameNotFoundException.class)
.isThrownBy(() -> myFilter.userDetailsService.loadUserByUsername("admin"));
}
// SEC-2274: WebSecurityConfigurer adds ApplicationContext as a shared object
@Test
public void loadConfigWhenSharedObjectsCreatedThenApplicationContextAdded() {
this.spring.register(ApplicationContextSharedObjectConfig.class).autowire();
ApplicationContextSharedObjectConfig securityConfig = this.spring.getContext()
.getBean(ApplicationContextSharedObjectConfig.class);
assertThat(securityConfig.applicationContextSharedObject).isNotNull();
assertThat(securityConfig.applicationContextSharedObject).isSameAs(this.spring.getContext());
}
@Test
public void loadConfigWhenCustomAuthenticationTrustResolverBeanThenOverridesDefault() {
CustomTrustResolverConfig.AUTHENTICATION_TRUST_RESOLVER_BEAN = mock(AuthenticationTrustResolver.class);
this.spring.register(CustomTrustResolverConfig.class).autowire();
CustomTrustResolverConfig securityConfig = this.spring.getContext().getBean(CustomTrustResolverConfig.class);
assertThat(securityConfig.authenticationTrustResolverSharedObject).isNotNull();
assertThat(securityConfig.authenticationTrustResolverSharedObject)
.isSameAs(CustomTrustResolverConfig.AUTHENTICATION_TRUST_RESOLVER_BEAN);
}
@Test
public void compareOrderWebSecurityConfigurerAdapterWhenLowestOrderToDefaultOrderThenGreaterThanZero() {
AnnotationAwareOrderComparator comparator = new AnnotationAwareOrderComparator();
assertThat(comparator.compare(new LowestPriorityWebSecurityConfig(), new DefaultOrderWebSecurityConfig()))
.isGreaterThan(0);
}
// gh-7515
@Test
public void performWhenUsingAuthenticationEventPublisherBeanThenUses() throws Exception {
this.spring.register(CustomAuthenticationEventPublisherBean.class).autowire();
AuthenticationEventPublisher authenticationEventPublisher = this.spring.getContext()
.getBean(AuthenticationEventPublisher.class);
this.mockMvc.perform(get("/").with(httpBasic("user", "password")));
verify(authenticationEventPublisher).publishAuthenticationSuccess(any(Authentication.class));
}
// gh-4400
@Test
public void performWhenUsingAuthenticationEventPublisherInDslThenUses() throws Exception {
this.spring.register(CustomAuthenticationEventPublisherDsl.class).autowire();
AuthenticationEventPublisher authenticationEventPublisher = CustomAuthenticationEventPublisherDsl.EVENT_PUBLISHER;
MockHttpServletRequestBuilder userRequest = get("/").with(httpBasic("user", "password"));
// fails since no providers configured
this.mockMvc.perform(userRequest);
verify(authenticationEventPublisher).publishAuthenticationFailure(any(AuthenticationException.class),
any(Authentication.class));
}
@EnableWebSecurity
@@ -96,65 +204,51 @@ public class WebSecurityConfigurerAdapterTests {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// @formatter:off
auth
.inMemoryAuthentication()
.withUser(PasswordEncodedUser.user());
// @formatter:on
}
@Override
protected void configure(HttpSecurity http) {
}
}
@Test
public void loadConfigWhenRequestAuthenticateThenAuthenticationEventPublished() throws Exception {
this.spring.register(InMemoryAuthWithWebSecurityConfigurerAdapter.class).autowire();
this.mockMvc.perform(formLogin())
.andExpect(status().is3xxRedirection());
assertThat(InMemoryAuthWithWebSecurityConfigurerAdapter.EVENTS).isNotEmpty();
assertThat(InMemoryAuthWithWebSecurityConfigurerAdapter.EVENTS).hasSize(1);
}
@EnableWebSecurity
static class InMemoryAuthWithWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter
implements ApplicationListener<AuthenticationSuccessEvent> {
implements ApplicationListener<AuthenticationSuccessEvent> {
static List<AuthenticationSuccessEvent> EVENTS = new ArrayList<>();
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// @formatter:off
auth
.inMemoryAuthentication()
.withUser(PasswordEncodedUser.user());
// @formatter:on
}
@Override
public void onApplicationEvent(AuthenticationSuccessEvent event) {
EVENTS.add(event);
}
}
@Test
public void loadConfigWhenInMemoryConfigureProtectedThenPasswordUpgraded() throws Exception {
this.spring.register(InMemoryConfigureProtectedConfig.class).autowire();
this.mockMvc.perform(formLogin())
.andExpect(status().is3xxRedirection());
UserDetailsService uds = this.spring.getContext()
.getBean(UserDetailsService.class);
assertThat(uds.loadUserByUsername("user").getPassword()).startsWith("{bcrypt}");
}
@EnableWebSecurity
static class InMemoryConfigureProtectedConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// @formatter:off
auth
.inMemoryAuthentication()
.withUser(PasswordEncodedUser.user());
// @formatter:on
}
@Override
@@ -162,27 +256,19 @@ public class WebSecurityConfigurerAdapterTests {
public UserDetailsService userDetailsServiceBean() throws Exception {
return super.userDetailsServiceBean();
}
}
@Test
public void loadConfigWhenInMemoryConfigureGlobalThenPasswordUpgraded() throws Exception {
this.spring.register(InMemoryConfigureGlobalConfig.class).autowire();
this.mockMvc.perform(formLogin())
.andExpect(status().is3xxRedirection());
UserDetailsService uds = this.spring.getContext()
.getBean(UserDetailsService.class);
assertThat(uds.loadUserByUsername("user").getPassword()).startsWith("{bcrypt}");
}
@EnableWebSecurity
static class InMemoryConfigureGlobalConfig extends WebSecurityConfigurerAdapter {
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
// @formatter:off
auth
.inMemoryAuthentication()
.withUser(PasswordEncodedUser.user());
// @formatter:on
}
@Override
@@ -190,28 +276,18 @@ public class WebSecurityConfigurerAdapterTests {
public UserDetailsService userDetailsServiceBean() throws Exception {
return super.userDetailsServiceBean();
}
}
@Test
public void loadConfigWhenCustomContentNegotiationStrategyBeanThenOverridesDefault() {
OverrideContentNegotiationStrategySharedObjectConfig.CONTENT_NEGOTIATION_STRATEGY_BEAN = mock(ContentNegotiationStrategy.class);
this.spring.register(OverrideContentNegotiationStrategySharedObjectConfig.class).autowire();
OverrideContentNegotiationStrategySharedObjectConfig securityConfig =
this.spring.getContext().getBean(OverrideContentNegotiationStrategySharedObjectConfig.class);
assertThat(securityConfig.contentNegotiationStrategySharedObject).isNotNull();
assertThat(securityConfig.contentNegotiationStrategySharedObject)
.isSameAs(OverrideContentNegotiationStrategySharedObjectConfig.CONTENT_NEGOTIATION_STRATEGY_BEAN);
}
@EnableWebSecurity
static class OverrideContentNegotiationStrategySharedObjectConfig extends WebSecurityConfigurerAdapter {
static ContentNegotiationStrategy CONTENT_NEGOTIATION_STRATEGY_BEAN;
private ContentNegotiationStrategy contentNegotiationStrategySharedObject;
@Bean
public ContentNegotiationStrategy contentNegotiationStrategy() {
ContentNegotiationStrategy contentNegotiationStrategy() {
return CONTENT_NEGOTIATION_STRATEGY_BEAN;
}
@@ -220,21 +296,12 @@ public class WebSecurityConfigurerAdapterTests {
this.contentNegotiationStrategySharedObject = http.getSharedObject(ContentNegotiationStrategy.class);
super.configure(http);
}
}
@Test
public void loadConfigWhenDefaultContentNegotiationStrategyThenHeaderContentNegotiationStrategy() {
this.spring.register(ContentNegotiationStrategyDefaultSharedObjectConfig.class).autowire();
ContentNegotiationStrategyDefaultSharedObjectConfig securityConfig =
this.spring.getContext().getBean(ContentNegotiationStrategyDefaultSharedObjectConfig.class);
assertThat(securityConfig.contentNegotiationStrategySharedObject).isNotNull();
assertThat(securityConfig.contentNegotiationStrategySharedObject).isInstanceOf(HeaderContentNegotiationStrategy.class);
}
@EnableWebSecurity
static class ContentNegotiationStrategyDefaultSharedObjectConfig extends WebSecurityConfigurerAdapter {
private ContentNegotiationStrategy contentNegotiationStrategySharedObject;
@Override
@@ -242,31 +309,22 @@ public class WebSecurityConfigurerAdapterTests {
this.contentNegotiationStrategySharedObject = http.getSharedObject(ContentNegotiationStrategy.class);
super.configure(http);
}
}
@Test
public void loadConfigWhenUserDetailsServiceHasCircularReferenceThenStillLoads() {
this.spring.register(RequiresUserDetailsServiceConfig.class, UserDetailsServiceConfig.class).autowire();
MyFilter myFilter = this.spring.getContext().getBean(MyFilter.class);
Throwable thrown = catchThrowable(() -> myFilter.userDetailsService.loadUserByUsername("user") );
assertThat(thrown).isNull();
thrown = catchThrowable(() -> myFilter.userDetailsService.loadUserByUsername("admin") );
assertThat(thrown).isInstanceOf(UsernameNotFoundException.class);
}
@Configuration
static class RequiresUserDetailsServiceConfig {
@Bean
public MyFilter myFilter(UserDetailsService userDetailsService) {
MyFilter myFilter(UserDetailsService userDetailsService) {
return new MyFilter(userDetailsService);
}
}
@EnableWebSecurity
static class UserDetailsServiceConfig extends WebSecurityConfigurerAdapter {
@Autowired
private MyFilter myFilter;
@@ -283,13 +341,17 @@ public class WebSecurityConfigurerAdapterTests {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// @formatter:off
auth
.inMemoryAuthentication()
.withUser(PasswordEncodedUser.user());
// @formatter:on
}
}
static class MyFilter extends OncePerRequestFilter {
private UserDetailsService userDetailsService;
MyFilter(UserDetailsService userDetailsService) {
@@ -297,27 +359,16 @@ public class WebSecurityConfigurerAdapterTests {
}
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
filterChain.doFilter(request, response);
}
}
// SEC-2274: WebSecurityConfigurer adds ApplicationContext as a shared object
@Test
public void loadConfigWhenSharedObjectsCreatedThenApplicationContextAdded() {
this.spring.register(ApplicationContextSharedObjectConfig.class).autowire();
ApplicationContextSharedObjectConfig securityConfig =
this.spring.getContext().getBean(ApplicationContextSharedObjectConfig.class);
assertThat(securityConfig.applicationContextSharedObject).isNotNull();
assertThat(securityConfig.applicationContextSharedObject).isSameAs(this.spring.getContext());
}
@EnableWebSecurity
static class ApplicationContextSharedObjectConfig extends WebSecurityConfigurerAdapter {
private ApplicationContext applicationContextSharedObject;
@Override
@@ -325,28 +376,18 @@ public class WebSecurityConfigurerAdapterTests {
this.applicationContextSharedObject = http.getSharedObject(ApplicationContext.class);
super.configure(http);
}
}
@Test
public void loadConfigWhenCustomAuthenticationTrustResolverBeanThenOverridesDefault() {
CustomTrustResolverConfig.AUTHENTICATION_TRUST_RESOLVER_BEAN = mock(AuthenticationTrustResolver.class);
this.spring.register(CustomTrustResolverConfig.class).autowire();
CustomTrustResolverConfig securityConfig =
this.spring.getContext().getBean(CustomTrustResolverConfig.class);
assertThat(securityConfig.authenticationTrustResolverSharedObject).isNotNull();
assertThat(securityConfig.authenticationTrustResolverSharedObject)
.isSameAs(CustomTrustResolverConfig.AUTHENTICATION_TRUST_RESOLVER_BEAN);
}
@EnableWebSecurity
static class CustomTrustResolverConfig extends WebSecurityConfigurerAdapter {
static AuthenticationTrustResolver AUTHENTICATION_TRUST_RESOLVER_BEAN;
private AuthenticationTrustResolver authenticationTrustResolverSharedObject;
@Bean
public AuthenticationTrustResolver authenticationTrustResolver() {
AuthenticationTrustResolver authenticationTrustResolver() {
return AUTHENTICATION_TRUST_RESOLVER_BEAN;
}
@@ -355,39 +396,21 @@ public class WebSecurityConfigurerAdapterTests {
this.authenticationTrustResolverSharedObject = http.getSharedObject(AuthenticationTrustResolver.class);
super.configure(http);
}
}
@Test
public void compareOrderWebSecurityConfigurerAdapterWhenLowestOrderToDefaultOrderThenGreaterThanZero() {
AnnotationAwareOrderComparator comparator = new AnnotationAwareOrderComparator();
assertThat(comparator.compare(
new LowestPriorityWebSecurityConfig(),
new DefaultOrderWebSecurityConfig())).isGreaterThan(0);
}
static class DefaultOrderWebSecurityConfig extends WebSecurityConfigurerAdapter {
}
@Order
static class LowestPriorityWebSecurityConfig extends WebSecurityConfigurerAdapter {
}
// gh-7515
@Test
public void performWhenUsingAuthenticationEventPublisherBeanThenUses() throws Exception {
this.spring.register(CustomAuthenticationEventPublisherBean.class).autowire();
AuthenticationEventPublisher authenticationEventPublisher =
this.spring.getContext().getBean(AuthenticationEventPublisher.class);
this.mockMvc.perform(get("/")
.with(httpBasic("user", "password")));
verify(authenticationEventPublisher).publishAuthenticationSuccess(any(Authentication.class));
}
@EnableWebSecurity
static class CustomAuthenticationEventPublisherBean extends WebSecurityConfigurerAdapter {
@Bean
@Override
public UserDetailsService userDetailsService() {
@@ -395,34 +418,22 @@ public class WebSecurityConfigurerAdapterTests {
}
@Bean
public AuthenticationEventPublisher authenticationEventPublisher() {
AuthenticationEventPublisher authenticationEventPublisher() {
return mock(AuthenticationEventPublisher.class);
}
}
// gh-4400
@Test
public void performWhenUsingAuthenticationEventPublisherInDslThenUses() throws Exception {
this.spring.register(CustomAuthenticationEventPublisherDsl.class).autowire();
AuthenticationEventPublisher authenticationEventPublisher =
CustomAuthenticationEventPublisherDsl.EVENT_PUBLISHER;
this.mockMvc.perform(get("/")
.with(httpBasic("user", "password"))); // fails since no providers configured
verify(authenticationEventPublisher).publishAuthenticationFailure(
any(AuthenticationException.class),
any(Authentication.class));
}
@EnableWebSecurity
static class CustomAuthenticationEventPublisherDsl extends WebSecurityConfigurerAdapter {
static AuthenticationEventPublisher EVENT_PUBLISHER = mock(AuthenticationEventPublisher.class);
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationEventPublisher(EVENT_PUBLISHER);
}
}
}

View File

@@ -13,10 +13,21 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.builders;
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.cas.web.CasAuthenticationFilter;
@@ -28,17 +39,10 @@ import org.springframework.security.core.userdetails.PasswordEncodedUser;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.ThrowableAssert.catchThrowable;
import static org.mockito.Mockito.*;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@@ -49,6 +53,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
* @author Joe Grandja
*/
public class HttpConfigurationTests {
@Rule
public final SpringTestRule spring = new SpringTestRule();
@@ -57,35 +62,11 @@ public class HttpConfigurationTests {
@Test
public void configureWhenAddFilterUnregisteredThenThrowsBeanCreationException() {
Throwable thrown = catchThrowable(() -> this.spring.register(UnregisteredFilterConfig.class).autowire() );
assertThat(thrown).isInstanceOf(BeanCreationException.class);
assertThat(thrown.getMessage()).contains("The Filter class " + UnregisteredFilter.class.getName() +
" does not have a registered order and cannot be added without a specified order." +
" Consider using addFilterBefore or addFilterAfter instead.");
}
@EnableWebSecurity
static class UnregisteredFilterConfig extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) {
http
.addFilter(new UnregisteredFilter());
}
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser(PasswordEncodedUser.user());
}
}
static class UnregisteredFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
filterChain.doFilter(request, response);
}
assertThatExceptionOfType(BeanCreationException.class)
.isThrownBy(() -> this.spring.register(UnregisteredFilterConfig.class).autowire())
.withMessageContaining("The Filter class " + UnregisteredFilter.class.getName()
+ " does not have a registered order and cannot be added without a specified order."
+ " Consider using addFilterBefore or addFilterAfter instead.");
}
// https://github.com/spring-projects/spring-security-javaconfig/issues/104
@@ -93,37 +74,73 @@ public class HttpConfigurationTests {
public void configureWhenAddFilterCasAuthenticationFilterThenFilterAdded() throws Exception {
CasAuthenticationFilterConfig.CAS_AUTHENTICATION_FILTER = spy(new CasAuthenticationFilter());
this.spring.register(CasAuthenticationFilterConfig.class).autowire();
this.mockMvc.perform(get("/"));
verify(CasAuthenticationFilterConfig.CAS_AUTHENTICATION_FILTER).doFilter(
any(ServletRequest.class), any(ServletResponse.class), any(FilterChain.class));
}
@EnableWebSecurity
static class CasAuthenticationFilterConfig extends WebSecurityConfigurerAdapter {
static CasAuthenticationFilter CAS_AUTHENTICATION_FILTER;
protected void configure(HttpSecurity http) {
http
.addFilter(CAS_AUTHENTICATION_FILTER);
}
verify(CasAuthenticationFilterConfig.CAS_AUTHENTICATION_FILTER).doFilter(any(ServletRequest.class),
any(ServletResponse.class), any(FilterChain.class));
}
@Test
public void configureWhenConfigIsRequestMatchersJavadocThenAuthorizationApplied() throws Exception {
this.spring.register(RequestMatcherRegistryConfigs.class).autowire();
this.mockMvc.perform(get("/oauth/a")).andExpect(status().isUnauthorized());
this.mockMvc.perform(get("/oauth/b")).andExpect(status().isUnauthorized());
this.mockMvc.perform(get("/api/a")).andExpect(status().isUnauthorized());
this.mockMvc.perform(get("/api/b")).andExpect(status().isUnauthorized());
}
@EnableWebSecurity
static class UnregisteredFilterConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) {
// @formatter:off
http
.addFilter(new UnregisteredFilter());
// @formatter:on
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// @formatter:off
auth
.inMemoryAuthentication()
.withUser(PasswordEncodedUser.user());
// @formatter:on
}
}
static class UnregisteredFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
filterChain.doFilter(request, response);
}
}
@EnableWebSecurity
static class CasAuthenticationFilterConfig extends WebSecurityConfigurerAdapter {
static CasAuthenticationFilter CAS_AUTHENTICATION_FILTER;
@Override
protected void configure(HttpSecurity http) {
// @formatter:off
http
.addFilter(CAS_AUTHENTICATION_FILTER);
// @formatter:on
}
}
@EnableWebSecurity
static class RequestMatcherRegistryConfigs extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.requestMatchers()
.antMatchers("/api/**")
@@ -133,6 +150,9 @@ public class HttpConfigurationTests {
.antMatchers("/**").hasRole("USER")
.and()
.httpBasic();
// @formatter:on
}
}
}

View File

@@ -13,10 +13,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.builders;
import javax.security.auth.Subject;
import javax.security.auth.login.LoginContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.ConfigAttribute;
@@ -49,71 +56,247 @@ import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.web.bind.annotation.GetMapping;
import javax.security.auth.Subject;
import javax.security.auth.login.LoginContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyCollection;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.formLogin;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.authentication;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.forwardedUrl;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrlPattern;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
/**
* Tests to verify that all the functionality of <http> attributes are present in Java Config.
* Tests to verify that all the functionality of &lt;http&gt; attributes are present in
* Java Config.
*
* @author Rob Winch
* @author Joe Grandja
*/
public class NamespaceHttpTests {
@Rule
public final SpringTestRule spring = new SpringTestRule();
@Autowired
private MockMvc mockMvc;
@Test // http@access-decision-manager-ref
@Test // http@access-decision-manager-ref
public void configureWhenAccessDecisionManagerSetThenVerifyUse() throws Exception {
AccessDecisionManagerRefConfig.ACCESS_DECISION_MANAGER = mock(AccessDecisionManager.class);
when(AccessDecisionManagerRefConfig.ACCESS_DECISION_MANAGER.supports(FilterInvocation.class)).thenReturn(true);
when(AccessDecisionManagerRefConfig.ACCESS_DECISION_MANAGER.supports(any(ConfigAttribute.class))).thenReturn(true);
given(AccessDecisionManagerRefConfig.ACCESS_DECISION_MANAGER.supports(FilterInvocation.class)).willReturn(true);
given(AccessDecisionManagerRefConfig.ACCESS_DECISION_MANAGER.supports(any(ConfigAttribute.class)))
.willReturn(true);
this.spring.register(AccessDecisionManagerRefConfig.class).autowire();
this.mockMvc.perform(get("/"));
verify(AccessDecisionManagerRefConfig.ACCESS_DECISION_MANAGER, times(1)).decide(any(Authentication.class),
any(), anyCollection());
}
verify(AccessDecisionManagerRefConfig.ACCESS_DECISION_MANAGER, times(1)).decide(any(Authentication.class), any(), anyCollection());
@Test // http@access-denied-page
public void configureWhenAccessDeniedPageSetAndRequestForbiddenThenForwardedToAccessDeniedPage() throws Exception {
this.spring.register(AccessDeniedPageConfig.class).autowire();
this.mockMvc.perform(get("/admin").with(user(PasswordEncodedUser.user()))).andExpect(status().isForbidden())
.andExpect(forwardedUrl("/AccessDeniedPage"));
}
@Test // http@authentication-manager-ref
public void configureWhenAuthenticationManagerProvidedThenVerifyUse() throws Exception {
AuthenticationManagerRefConfig.AUTHENTICATION_MANAGER = mock(AuthenticationManager.class);
this.spring.register(AuthenticationManagerRefConfig.class).autowire();
this.mockMvc.perform(formLogin());
verify(AuthenticationManagerRefConfig.AUTHENTICATION_MANAGER, times(1)).authenticate(any(Authentication.class));
}
@Test // http@create-session=always
public void configureWhenSessionCreationPolicyAlwaysThenSessionCreatedOnRequest() throws Exception {
this.spring.register(CreateSessionAlwaysConfig.class).autowire();
MvcResult mvcResult = this.mockMvc.perform(get("/")).andReturn();
HttpSession session = mvcResult.getRequest().getSession(false);
assertThat(session).isNotNull();
assertThat(session.isNew()).isTrue();
}
@Test // http@create-session=stateless
public void configureWhenSessionCreationPolicyStatelessThenSessionNotCreatedOnRequest() throws Exception {
this.spring.register(CreateSessionStatelessConfig.class).autowire();
MvcResult mvcResult = this.mockMvc.perform(get("/")).andReturn();
HttpSession session = mvcResult.getRequest().getSession(false);
assertThat(session).isNull();
}
@Test // http@create-session=ifRequired
public void configureWhenSessionCreationPolicyIfRequiredThenSessionCreatedWhenRequiredOnRequest() throws Exception {
this.spring.register(IfRequiredConfig.class).autowire();
MvcResult mvcResult = this.mockMvc.perform(get("/unsecure")).andReturn();
HttpSession session = mvcResult.getRequest().getSession(false);
assertThat(session).isNull();
mvcResult = this.mockMvc.perform(formLogin()).andReturn();
session = mvcResult.getRequest().getSession(false);
assertThat(session).isNotNull();
assertThat(session.isNew()).isTrue();
}
@Test // http@create-session=never
public void configureWhenSessionCreationPolicyNeverThenSessionNotCreatedOnRequest() throws Exception {
this.spring.register(CreateSessionNeverConfig.class).autowire();
MvcResult mvcResult = this.mockMvc.perform(get("/")).andReturn();
HttpSession session = mvcResult.getRequest().getSession(false);
assertThat(session).isNull();
}
@Test // http@entry-point-ref
public void configureWhenAuthenticationEntryPointSetAndRequestUnauthorizedThenRedirectedToAuthenticationEntryPoint()
throws Exception {
this.spring.register(EntryPointRefConfig.class).autowire();
// @formatter:off
this.mockMvc.perform(get("/"))
.andExpect(status().is3xxRedirection())
.andExpect(redirectedUrlPattern("**/entry-point"));
// @formatter:on
}
@Test // http@jaas-api-provision
public void configureWhenJaasApiIntegrationFilterAddedThenJaasSubjectObtained() throws Exception {
LoginContext loginContext = mock(LoginContext.class);
given(loginContext.getSubject()).willReturn(new Subject());
JaasAuthenticationToken authenticationToken = mock(JaasAuthenticationToken.class);
given(authenticationToken.isAuthenticated()).willReturn(true);
given(authenticationToken.getLoginContext()).willReturn(loginContext);
this.spring.register(JaasApiProvisionConfig.class).autowire();
this.mockMvc.perform(get("/").with(authentication(authenticationToken)));
verify(loginContext, times(1)).getSubject();
}
@Test // http@realm
public void configureWhenHttpBasicAndRequestUnauthorizedThenReturnWWWAuthenticateWithRealm() throws Exception {
this.spring.register(RealmConfig.class).autowire();
// @formatter:off
this.mockMvc.perform(get("/"))
.andExpect(status().isUnauthorized())
.andExpect(header().string("WWW-Authenticate", "Basic realm=\"RealmConfig\""));
// @formatter:on
}
@Test // http@request-matcher-ref ant
public void configureWhenAntPatternMatchingThenAntPathRequestMatcherUsed() {
this.spring.register(RequestMatcherAntConfig.class).autowire();
FilterChainProxy filterChainProxy = this.spring.getContext().getBean(FilterChainProxy.class);
assertThat(filterChainProxy.getFilterChains().get(0)).isInstanceOf(DefaultSecurityFilterChain.class);
DefaultSecurityFilterChain securityFilterChain = (DefaultSecurityFilterChain) filterChainProxy.getFilterChains()
.get(0);
assertThat(securityFilterChain.getRequestMatcher()).isInstanceOf(AntPathRequestMatcher.class);
}
@Test // http@request-matcher-ref regex
public void configureWhenRegexPatternMatchingThenRegexRequestMatcherUsed() {
this.spring.register(RequestMatcherRegexConfig.class).autowire();
FilterChainProxy filterChainProxy = this.spring.getContext().getBean(FilterChainProxy.class);
assertThat(filterChainProxy.getFilterChains().get(0)).isInstanceOf(DefaultSecurityFilterChain.class);
DefaultSecurityFilterChain securityFilterChain = (DefaultSecurityFilterChain) filterChainProxy.getFilterChains()
.get(0);
assertThat(securityFilterChain.getRequestMatcher()).isInstanceOf(RegexRequestMatcher.class);
}
@Test // http@request-matcher-ref
public void configureWhenRequestMatcherProvidedThenRequestMatcherUsed() {
this.spring.register(RequestMatcherRefConfig.class).autowire();
FilterChainProxy filterChainProxy = this.spring.getContext().getBean(FilterChainProxy.class);
assertThat(filterChainProxy.getFilterChains().get(0)).isInstanceOf(DefaultSecurityFilterChain.class);
DefaultSecurityFilterChain securityFilterChain = (DefaultSecurityFilterChain) filterChainProxy.getFilterChains()
.get(0);
assertThat(securityFilterChain.getRequestMatcher())
.isInstanceOf(RequestMatcherRefConfig.MyRequestMatcher.class);
}
@Test // http@security=none
public void configureWhenIgnoredAntPatternsThenAntPathRequestMatcherUsedWithNoFilters() {
this.spring.register(SecurityNoneConfig.class).autowire();
FilterChainProxy filterChainProxy = this.spring.getContext().getBean(FilterChainProxy.class);
assertThat(filterChainProxy.getFilterChains().get(0)).isInstanceOf(DefaultSecurityFilterChain.class);
DefaultSecurityFilterChain securityFilterChain = (DefaultSecurityFilterChain) filterChainProxy.getFilterChains()
.get(0);
assertThat(securityFilterChain.getRequestMatcher()).isInstanceOf(AntPathRequestMatcher.class);
assertThat(((AntPathRequestMatcher) securityFilterChain.getRequestMatcher()).getPattern())
.isEqualTo("/resources/**");
assertThat(securityFilterChain.getFilters()).isEmpty();
assertThat(filterChainProxy.getFilterChains().get(1)).isInstanceOf(DefaultSecurityFilterChain.class);
securityFilterChain = (DefaultSecurityFilterChain) filterChainProxy.getFilterChains().get(1);
assertThat(securityFilterChain.getRequestMatcher()).isInstanceOf(AntPathRequestMatcher.class);
assertThat(((AntPathRequestMatcher) securityFilterChain.getRequestMatcher()).getPattern())
.isEqualTo("/public/**");
assertThat(securityFilterChain.getFilters()).isEmpty();
}
@Test // http@security-context-repository-ref
public void configureWhenNullSecurityContextRepositoryThenSecurityContextNotSavedInSession() throws Exception {
this.spring.register(SecurityContextRepoConfig.class).autowire();
MvcResult mvcResult = this.mockMvc.perform(formLogin()).andReturn();
HttpSession session = mvcResult.getRequest().getSession(false);
assertThat(session).isNull();
}
@Test // http@servlet-api-provision=false
public void configureWhenServletApiDisabledThenRequestNotServletApiWrapper() throws Exception {
this.spring.register(ServletApiProvisionConfig.class, MainController.class).autowire();
this.mockMvc.perform(get("/"));
assertThat(MainController.HTTP_SERVLET_REQUEST_TYPE)
.isNotInstanceOf(SecurityContextHolderAwareRequestWrapper.class);
}
@Test // http@servlet-api-provision defaults to true
public void configureWhenServletApiDefaultThenRequestIsServletApiWrapper() throws Exception {
this.spring.register(ServletApiProvisionDefaultsConfig.class, MainController.class).autowire();
this.mockMvc.perform(get("/"));
assertThat(SecurityContextHolderAwareRequestWrapper.class)
.isAssignableFrom(MainController.HTTP_SERVLET_REQUEST_TYPE);
}
@Test // http@use-expressions=true
public void configureWhenUseExpressionsEnabledThenExpressionBasedSecurityMetadataSource() {
this.spring.register(UseExpressionsConfig.class).autowire();
UseExpressionsConfig config = this.spring.getContext().getBean(UseExpressionsConfig.class);
assertThat(ExpressionBasedFilterInvocationSecurityMetadataSource.class)
.isAssignableFrom(config.filterInvocationSecurityMetadataSourceType);
}
@Test // http@use-expressions=false
public void configureWhenUseExpressionsDisabledThenDefaultSecurityMetadataSource() {
this.spring.register(DisableUseExpressionsConfig.class).autowire();
DisableUseExpressionsConfig config = this.spring.getContext().getBean(DisableUseExpressionsConfig.class);
assertThat(DefaultFilterInvocationSecurityMetadataSource.class)
.isAssignableFrom(config.filterInvocationSecurityMetadataSourceType);
}
@EnableWebSecurity
static class AccessDecisionManagerRefConfig extends WebSecurityConfigurerAdapter {
static AccessDecisionManager ACCESS_DECISION_MANAGER;
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.authorizeRequests()
.anyRequest().permitAll()
.accessDecisionManager(ACCESS_DECISION_MANAGER);
// @formatter:on
}
}
@Test // http@access-denied-page
public void configureWhenAccessDeniedPageSetAndRequestForbiddenThenForwardedToAccessDeniedPage() throws Exception {
this.spring.register(AccessDeniedPageConfig.class).autowire();
this.mockMvc.perform(get("/admin").with(user(PasswordEncodedUser.user())))
.andExpect(status().isForbidden())
.andExpect(forwardedUrl("/AccessDeniedPage"));
}
@EnableWebSecurity
static class AccessDeniedPageConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.authorizeRequests()
.antMatchers("/admin").hasRole("ADMIN")
@@ -121,21 +304,14 @@ public class NamespaceHttpTests {
.and()
.exceptionHandling()
.accessDeniedPage("/AccessDeniedPage");
// @formatter:on
}
}
@Test // http@authentication-manager-ref
public void configureWhenAuthenticationManagerProvidedThenVerifyUse() throws Exception {
AuthenticationManagerRefConfig.AUTHENTICATION_MANAGER = mock(AuthenticationManager.class);
this.spring.register(AuthenticationManagerRefConfig.class).autowire();
this.mockMvc.perform(formLogin());
verify(AuthenticationManagerRefConfig.AUTHENTICATION_MANAGER, times(1)).authenticate(any(Authentication.class));
}
@EnableWebSecurity
static class AuthenticationManagerRefConfig extends WebSecurityConfigurerAdapter {
static AuthenticationManager AUTHENTICATION_MANAGER;
@Override
@@ -145,81 +321,57 @@ public class NamespaceHttpTests {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin();
// @formatter:on
}
}
@Test // http@create-session=always
public void configureWhenSessionCreationPolicyAlwaysThenSessionCreatedOnRequest() throws Exception {
this.spring.register(CreateSessionAlwaysConfig.class).autowire();
MvcResult mvcResult = this.mockMvc.perform(get("/")).andReturn();
HttpSession session = mvcResult.getRequest().getSession(false);
assertThat(session).isNotNull();
assertThat(session.isNew()).isTrue();
}
@EnableWebSecurity
static class CreateSessionAlwaysConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.authorizeRequests()
.anyRequest().permitAll()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.ALWAYS);
// @formatter:on
}
}
@Test // http@create-session=stateless
public void configureWhenSessionCreationPolicyStatelessThenSessionNotCreatedOnRequest() throws Exception {
this.spring.register(CreateSessionStatelessConfig.class).autowire();
MvcResult mvcResult = this.mockMvc.perform(get("/")).andReturn();
HttpSession session = mvcResult.getRequest().getSession(false);
assertThat(session).isNull();
}
@EnableWebSecurity
static class CreateSessionStatelessConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.authorizeRequests()
.anyRequest().permitAll()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
// @formatter:on
}
}
@Test // http@create-session=ifRequired
public void configureWhenSessionCreationPolicyIfRequiredThenSessionCreatedWhenRequiredOnRequest() throws Exception {
this.spring.register(IfRequiredConfig.class).autowire();
MvcResult mvcResult = this.mockMvc.perform(get("/unsecure")).andReturn();
HttpSession session = mvcResult.getRequest().getSession(false);
assertThat(session).isNull();
mvcResult = this.mockMvc.perform(formLogin()).andReturn();
session = mvcResult.getRequest().getSession(false);
assertThat(session).isNotNull();
assertThat(session.isNew()).isTrue();
}
@EnableWebSecurity
static class IfRequiredConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.authorizeRequests()
.antMatchers("/unsecure").permitAll()
@@ -229,45 +381,34 @@ public class NamespaceHttpTests {
.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
.and()
.formLogin();
// @formatter:on
}
}
@Test // http@create-session=never
public void configureWhenSessionCreationPolicyNeverThenSessionNotCreatedOnRequest() throws Exception {
this.spring.register(CreateSessionNeverConfig.class).autowire();
MvcResult mvcResult = this.mockMvc.perform(get("/")).andReturn();
HttpSession session = mvcResult.getRequest().getSession(false);
assertThat(session).isNull();
}
@EnableWebSecurity
static class CreateSessionNeverConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.authorizeRequests()
.anyRequest().anonymous()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.NEVER);
// @formatter:on
}
}
@Test // http@entry-point-ref
public void configureWhenAuthenticationEntryPointSetAndRequestUnauthorizedThenRedirectedToAuthenticationEntryPoint() throws Exception {
this.spring.register(EntryPointRefConfig.class).autowire();
this.mockMvc.perform(get("/"))
.andExpect(status().is3xxRedirection())
.andExpect(redirectedUrlPattern("**/entry-point"));
}
@EnableWebSecurity
static class EntryPointRefConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.authorizeRequests()
.anyRequest().authenticated()
@@ -276,139 +417,87 @@ public class NamespaceHttpTests {
.authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/entry-point"))
.and()
.formLogin();
// @formatter:on
}
}
@Test // http@jaas-api-provision
public void configureWhenJaasApiIntegrationFilterAddedThenJaasSubjectObtained() throws Exception {
LoginContext loginContext = mock(LoginContext.class);
when(loginContext.getSubject()).thenReturn(new Subject());
JaasAuthenticationToken authenticationToken = mock(JaasAuthenticationToken.class);
when(authenticationToken.isAuthenticated()).thenReturn(true);
when(authenticationToken.getLoginContext()).thenReturn(loginContext);
this.spring.register(JaasApiProvisionConfig.class).autowire();
this.mockMvc.perform(get("/").with(authentication(authenticationToken)));
verify(loginContext, times(1)).getSubject();
}
@EnableWebSecurity
static class JaasApiProvisionConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) {
// @formatter:off
http
.addFilter(new JaasApiIntegrationFilter());
// @formatter:on
}
}
@Test // http@realm
public void configureWhenHttpBasicAndRequestUnauthorizedThenReturnWWWAuthenticateWithRealm() throws Exception {
this.spring.register(RealmConfig.class).autowire();
this.mockMvc.perform(get("/"))
.andExpect(status().isUnauthorized())
.andExpect(header().string("WWW-Authenticate", "Basic realm=\"RealmConfig\""));
}
@EnableWebSecurity
static class RealmConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.httpBasic()
.realmName("RealmConfig");
// @formatter:on
}
}
@Test // http@request-matcher-ref ant
public void configureWhenAntPatternMatchingThenAntPathRequestMatcherUsed() {
this.spring.register(RequestMatcherAntConfig.class).autowire();
FilterChainProxy filterChainProxy = this.spring.getContext().getBean(FilterChainProxy.class);
assertThat(filterChainProxy.getFilterChains().get(0)).isInstanceOf(DefaultSecurityFilterChain.class);
DefaultSecurityFilterChain securityFilterChain = (DefaultSecurityFilterChain) filterChainProxy.getFilterChains().get(0);
assertThat(securityFilterChain.getRequestMatcher()).isInstanceOf(AntPathRequestMatcher.class);
}
@EnableWebSecurity
static class RequestMatcherAntConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) {
// @formatter:off
http
.antMatcher("/api/**");
// @formatter:on
}
}
@Test // http@request-matcher-ref regex
public void configureWhenRegexPatternMatchingThenRegexRequestMatcherUsed() {
this.spring.register(RequestMatcherRegexConfig.class).autowire();
FilterChainProxy filterChainProxy = this.spring.getContext().getBean(FilterChainProxy.class);
assertThat(filterChainProxy.getFilterChains().get(0)).isInstanceOf(DefaultSecurityFilterChain.class);
DefaultSecurityFilterChain securityFilterChain = (DefaultSecurityFilterChain) filterChainProxy.getFilterChains().get(0);
assertThat(securityFilterChain.getRequestMatcher()).isInstanceOf(RegexRequestMatcher.class);
}
@EnableWebSecurity
static class RequestMatcherRegexConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) {
// @formatter:off
http
.regexMatcher("/regex/.*");
// @formatter:on
}
}
@Test // http@request-matcher-ref
public void configureWhenRequestMatcherProvidedThenRequestMatcherUsed() {
this.spring.register(RequestMatcherRefConfig.class).autowire();
FilterChainProxy filterChainProxy = this.spring.getContext().getBean(FilterChainProxy.class);
assertThat(filterChainProxy.getFilterChains().get(0)).isInstanceOf(DefaultSecurityFilterChain.class);
DefaultSecurityFilterChain securityFilterChain = (DefaultSecurityFilterChain) filterChainProxy.getFilterChains().get(0);
assertThat(securityFilterChain.getRequestMatcher()).isInstanceOf(RequestMatcherRefConfig.MyRequestMatcher.class);
}
@EnableWebSecurity
static class RequestMatcherRefConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) {
// @formatter:off
http
.requestMatcher(new MyRequestMatcher());
// @formatter:on
}
static class MyRequestMatcher implements RequestMatcher {
@Override
public boolean matches(HttpServletRequest request) {
return true;
}
}
}
@Test // http@security=none
public void configureWhenIgnoredAntPatternsThenAntPathRequestMatcherUsedWithNoFilters() {
this.spring.register(SecurityNoneConfig.class).autowire();
FilterChainProxy filterChainProxy = this.spring.getContext().getBean(FilterChainProxy.class);
assertThat(filterChainProxy.getFilterChains().get(0)).isInstanceOf(DefaultSecurityFilterChain.class);
DefaultSecurityFilterChain securityFilterChain = (DefaultSecurityFilterChain) filterChainProxy.getFilterChains().get(0);
assertThat(securityFilterChain.getRequestMatcher()).isInstanceOf(AntPathRequestMatcher.class);
assertThat(((AntPathRequestMatcher) securityFilterChain.getRequestMatcher()).getPattern()).isEqualTo("/resources/**");
assertThat(securityFilterChain.getFilters()).isEmpty();
assertThat(filterChainProxy.getFilterChains().get(1)).isInstanceOf(DefaultSecurityFilterChain.class);
securityFilterChain = (DefaultSecurityFilterChain) filterChainProxy.getFilterChains().get(1);
assertThat(securityFilterChain.getRequestMatcher()).isInstanceOf(AntPathRequestMatcher.class);
assertThat(((AntPathRequestMatcher) securityFilterChain.getRequestMatcher()).getPattern()).isEqualTo("/public/**");
assertThat(securityFilterChain.getFilters()).isEmpty();
}
@EnableWebSecurity
@@ -416,29 +505,21 @@ public class NamespaceHttpTests {
@Override
public void configure(WebSecurity web) {
web
.ignoring()
.antMatchers("/resources/**", "/public/**");
web.ignoring().antMatchers("/resources/**", "/public/**");
}
@Override
protected void configure(HttpSecurity http) {
}
}
@Test // http@security-context-repository-ref
public void configureWhenNullSecurityContextRepositoryThenSecurityContextNotSavedInSession() throws Exception {
this.spring.register(SecurityContextRepoConfig.class).autowire();
MvcResult mvcResult = this.mockMvc.perform(formLogin()).andReturn();
HttpSession session = mvcResult.getRequest().getSession(false);
assertThat(session).isNull();
}
@EnableWebSecurity
static class SecurityContextRepoConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.authorizeRequests()
.anyRequest().authenticated()
@@ -447,89 +528,78 @@ public class NamespaceHttpTests {
.securityContextRepository(new NullSecurityContextRepository())
.and()
.formLogin();
// @formatter:on
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// @formatter:off
auth
.inMemoryAuthentication()
.withUser(PasswordEncodedUser.user());
// @formatter:on
}
}
@Test // http@servlet-api-provision=false
public void configureWhenServletApiDisabledThenRequestNotServletApiWrapper() throws Exception {
this.spring.register(ServletApiProvisionConfig.class, MainController.class).autowire();
this.mockMvc.perform(get("/"));
assertThat(MainController.HTTP_SERVLET_REQUEST_TYPE).isNotInstanceOf(SecurityContextHolderAwareRequestWrapper.class);
}
@EnableWebSecurity
static class ServletApiProvisionConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.authorizeRequests()
.anyRequest().permitAll()
.and()
.servletApi()
.disable();
// @formatter:on
}
}
@Test // http@servlet-api-provision defaults to true
public void configureWhenServletApiDefaultThenRequestIsServletApiWrapper() throws Exception {
this.spring.register(ServletApiProvisionDefaultsConfig.class, MainController.class).autowire();
this.mockMvc.perform(get("/"));
assertThat(SecurityContextHolderAwareRequestWrapper.class).isAssignableFrom(MainController.HTTP_SERVLET_REQUEST_TYPE);
}
@EnableWebSecurity
static class ServletApiProvisionDefaultsConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.authorizeRequests()
.anyRequest().permitAll();
// @formatter:on
}
}
@Controller
static class MainController {
static Class<? extends HttpServletRequest> HTTP_SERVLET_REQUEST_TYPE;
@GetMapping("/")
public String index(HttpServletRequest request) {
String index(HttpServletRequest request) {
HTTP_SERVLET_REQUEST_TYPE = request.getClass();
return "index";
}
}
@Test // http@use-expressions=true
public void configureWhenUseExpressionsEnabledThenExpressionBasedSecurityMetadataSource() {
this.spring.register(UseExpressionsConfig.class).autowire();
UseExpressionsConfig config = this.spring.getContext().getBean(UseExpressionsConfig.class);
assertThat(ExpressionBasedFilterInvocationSecurityMetadataSource.class)
.isAssignableFrom(config.filterInvocationSecurityMetadataSourceType);
}
@EnableWebSecurity
static class UseExpressionsConfig extends WebSecurityConfigurerAdapter {
private Class<? extends FilterInvocationSecurityMetadataSource> filterInvocationSecurityMetadataSourceType;
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.authorizeRequests()
.antMatchers("/users**", "/sessions/**").hasRole("USER")
.antMatchers("/signup").permitAll()
.anyRequest().hasRole("USER");
// @formatter:on
}
@Override
@@ -538,33 +608,27 @@ public class NamespaceHttpTests {
final HttpSecurity http = this.getHttp();
web.postBuildAction(() -> {
FilterSecurityInterceptor securityInterceptor = http.getSharedObject(FilterSecurityInterceptor.class);
UseExpressionsConfig.this.filterInvocationSecurityMetadataSourceType =
securityInterceptor.getSecurityMetadataSource().getClass();
UseExpressionsConfig.this.filterInvocationSecurityMetadataSourceType = securityInterceptor
.getSecurityMetadataSource().getClass();
});
}
}
@Test // http@use-expressions=false
public void configureWhenUseExpressionsDisabledThenDefaultSecurityMetadataSource() {
this.spring.register(DisableUseExpressionsConfig.class).autowire();
DisableUseExpressionsConfig config = this.spring.getContext().getBean(DisableUseExpressionsConfig.class);
assertThat(DefaultFilterInvocationSecurityMetadataSource.class)
.isAssignableFrom(config.filterInvocationSecurityMetadataSourceType);
}
@EnableWebSecurity
static class DisableUseExpressionsConfig extends WebSecurityConfigurerAdapter {
private Class<? extends FilterInvocationSecurityMetadataSource> filterInvocationSecurityMetadataSourceType;
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.apply(new UrlAuthorizationConfigurer<>(getApplicationContext())).getRegistry()
.antMatchers("/users**", "/sessions/**").hasRole("USER")
.antMatchers("/signup").hasRole("ANONYMOUS")
.anyRequest().hasRole("USER");
// @formatter:on
}
@Override
@@ -573,9 +637,11 @@ public class NamespaceHttpTests {
final HttpSecurity http = this.getHttp();
web.postBuildAction(() -> {
FilterSecurityInterceptor securityInterceptor = http.getSharedObject(FilterSecurityInterceptor.class);
DisableUseExpressionsConfig.this.filterInvocationSecurityMetadataSourceType =
securityInterceptor.getSecurityMetadataSource().getClass();
DisableUseExpressionsConfig.this.filterInvocationSecurityMetadataSourceType = securityInterceptor
.getSecurityMetadataSource().getClass();
});
}
}
}

View File

@@ -45,10 +45,13 @@ import static org.assertj.core.api.Assertions.assertThat;
* @author Rob Winch
*/
public class WebSecurityTests {
AnnotationConfigWebApplicationContext context;
MockHttpServletRequest request;
MockHttpServletResponse response;
MockFilterChain chain;
@Autowired
@@ -72,39 +75,60 @@ public class WebSecurityTests {
@Test
public void ignoringMvcMatcher() throws Exception {
loadConfig(MvcMatcherConfig.class, LegacyMvcMatchingConfig.class);
this.request.setRequestURI("/path");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
setup();
this.request.setRequestURI("/path.html");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
setup();
this.request.setRequestURI("/path/");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
setup();
this.request.setRequestURI("/other");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
}
assertThat(this.response.getStatus())
.isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
@Test
public void ignoringMvcMatcherServletPath() throws Exception {
loadConfig(MvcMatcherServletPathConfig.class, LegacyMvcMatchingConfig.class);
this.request.setServletPath("/spring");
this.request.setRequestURI("/spring/path");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
setup();
this.request.setServletPath("/spring");
this.request.setRequestURI("/spring/path.html");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
setup();
this.request.setServletPath("/spring");
this.request.setRequestURI("/spring/path/");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
setup();
this.request.setServletPath("/other");
this.request.setRequestURI("/other/path");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
}
public void loadConfig(Class<?>... configs) {
this.context = new AnnotationConfigWebApplicationContext();
this.context.register(configs);
this.context.setServletContext(new MockServletContext());
this.context.refresh();
this.context.getAutowireCapableBeanFactory().autowireBean(this);
}
@EnableWebSecurity
@Configuration
@EnableWebMvc
static class MvcMatcherConfig extends WebSecurityConfigurerAdapter {
@Override
public void configure(WebSecurity web) {
// @formatter:off
@@ -134,53 +158,21 @@ public class WebSecurityTests {
@RestController
static class PathController {
@RequestMapping("/path")
public String path() {
String path() {
return "path";
}
}
}
@Test
public void ignoringMvcMatcherServletPath() throws Exception {
loadConfig(MvcMatcherServletPathConfig.class, LegacyMvcMatchingConfig.class);
this.request.setServletPath("/spring");
this.request.setRequestURI("/spring/path");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
setup();
this.request.setServletPath("/spring");
this.request.setRequestURI("/spring/path.html");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
setup();
this.request.setServletPath("/spring");
this.request.setRequestURI("/spring/path/");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
setup();
this.request.setServletPath("/other");
this.request.setRequestURI("/other/path");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus())
.isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
}
@EnableWebSecurity
@Configuration
@EnableWebMvc
static class MvcMatcherServletPathConfig extends WebSecurityConfigurerAdapter {
@Override
public void configure(WebSecurity web) {
// @formatter:off
@@ -211,28 +203,24 @@ public class WebSecurityTests {
@RestController
static class PathController {
@RequestMapping("/path")
public String path() {
String path() {
return "path";
}
}
}
@Configuration
static class LegacyMvcMatchingConfig implements WebMvcConfigurer {
@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
configurer.setUseSuffixPatternMatch(true);
}
}
public void loadConfig(Class<?>... configs) {
this.context = new AnnotationConfigWebApplicationContext();
this.context.register(configs);
this.context.setServletContext(new MockServletContext());
this.context.refresh();
this.context.getAutowireCapableBeanFactory().autowireBean(this);
}
}

View File

@@ -13,15 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.configuration;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
package org.springframework.security.config.annotation.web.configuration;
import org.junit.After;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
@@ -41,8 +39,11 @@ import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
/**
*
* @author Rob Winch
*
*/
@@ -50,6 +51,7 @@ import org.springframework.web.servlet.config.annotation.EnableWebMvc;
@ContextConfiguration
@WebAppConfiguration
public class AuthenticationPrincipalArgumentResolverTests {
@Autowired
WebApplicationContext wac;
@@ -62,32 +64,32 @@ public class AuthenticationPrincipalArgumentResolverTests {
public void authenticationPrincipalExpressionWhenBeanExpressionSuppliedThenBeanUsed() throws Exception {
User user = new User("user", "password", AuthorityUtils.createAuthorityList("ROLE_USER"));
SecurityContext context = SecurityContextHolder.createEmptyContext();
context.setAuthentication(new UsernamePasswordAuthenticationToken(user, user.getPassword(), user.getAuthorities()));
context.setAuthentication(
new UsernamePasswordAuthenticationToken(user, user.getPassword(), user.getAuthorities()));
SecurityContextHolder.setContext(context);
MockMvc mockMvc = MockMvcBuilders
.webAppContextSetup(wac)
.build();
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
// @formatter:off
mockMvc.perform(get("/users/self"))
.andExpect(status().isOk())
.andExpect(content().string("extracted-user"));
.andExpect(status().isOk())
.andExpect(content().string("extracted-user"));
// @formatter:on
}
@EnableWebSecurity
@EnableWebMvc
static class Config {
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
// @formatter:off
auth
.inMemoryAuthentication();
// @formatter:off
}
@Bean
public UsernameExtractor usernameExtractor() {
return new UsernameExtractor();
}
@RestController
static class UserController {
@GetMapping("/users/self")
@@ -96,7 +98,6 @@ public class AuthenticationPrincipalArgumentResolverTests {
}
}
}
static class UsernameExtractor {
public String extract(User u) {
return "extracted-" + u.getUsername();

View File

@@ -13,10 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.configuration;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -45,6 +47,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
* @author Joe Grandja
*/
public class EnableWebSecurityTests {
@Rule
public final SpringTestRule spring = new SpringTestRule();
@@ -54,19 +57,58 @@ public class EnableWebSecurityTests {
@Test
public void configureWhenOverrideAuthenticationManagerBeanThenAuthenticationManagerBeanRegistered() {
this.spring.register(SecurityConfig.class).autowire();
AuthenticationManager authenticationManager = this.spring.getContext().getBean(AuthenticationManager.class);
Authentication authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("user", "password"));
Authentication authentication = authenticationManager
.authenticate(new UsernamePasswordAuthenticationToken("user", "password"));
assertThat(authentication.isAuthenticated()).isTrue();
}
@Test
public void loadConfigWhenChildConfigExtendsSecurityConfigThenSecurityConfigInherited() {
this.spring.register(ChildSecurityConfig.class).autowire();
this.spring.getContext().getBean("springSecurityFilterChain", DebugFilter.class);
}
@Test
public void configureWhenEnableWebMvcThenAuthenticationPrincipalResolvable() throws Exception {
this.spring.register(AuthenticationPrincipalConfig.class).autowire();
this.mockMvc.perform(get("/").with(authentication(new TestingAuthenticationToken("user1", "password"))))
.andExpect(content().string("user1"));
}
@Test
public void securityFilterChainWhenEnableWebMvcThenAuthenticationPrincipalResolvable() throws Exception {
this.spring.register(SecurityFilterChainAuthenticationPrincipalConfig.class).autowire();
this.mockMvc.perform(get("/").with(authentication(new TestingAuthenticationToken("user1", "password"))))
.andExpect(content().string("user1"));
}
@Test
public void enableWebSecurityWhenNoConfigurationAnnotationThenBeanProxyingEnabled() {
this.spring.register(BeanProxyEnabledByDefaultConfig.class).autowire();
Child childBean = this.spring.getContext().getBean(Child.class);
Parent parentBean = this.spring.getContext().getBean(Parent.class);
assertThat(parentBean.getChild()).isSameAs(childBean);
}
@Test
public void enableWebSecurityWhenProxyBeanMethodsFalseThenBeanProxyingDisabled() {
this.spring.register(BeanProxyDisabledConfig.class).autowire();
Child childBean = this.spring.getContext().getBean(Child.class);
Parent parentBean = this.spring.getContext().getBean(Parent.class);
assertThat(parentBean.getChild()).isNotSameAs(childBean);
}
@EnableWebSecurity
static class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// @formatter:off
auth
.inMemoryAuthentication()
.withUser(PasswordEncodedUser.user());
// @formatter:on
}
@Bean
@@ -77,39 +119,31 @@ public class EnableWebSecurityTests {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.authorizeRequests()
.antMatchers("/*").hasRole("USER")
.and()
.formLogin();
// @formatter:on
}
}
@Test
public void loadConfigWhenChildConfigExtendsSecurityConfigThenSecurityConfigInherited() {
this.spring.register(ChildSecurityConfig.class).autowire();
this.spring.getContext().getBean("springSecurityFilterChain", DebugFilter.class);
}
@Configuration
static class ChildSecurityConfig extends DebugSecurityConfig {
}
@EnableWebSecurity(debug=true)
@EnableWebSecurity(debug = true)
static class DebugSecurityConfig extends WebSecurityConfigurerAdapter {
}
@Test
public void configureWhenEnableWebMvcThenAuthenticationPrincipalResolvable() throws Exception {
this.spring.register(AuthenticationPrincipalConfig.class).autowire();
this.mockMvc.perform(get("/").with(authentication(new TestingAuthenticationToken("user1", "password"))))
.andExpect(content().string("user1"));
}
@EnableWebSecurity
@EnableWebMvc
static class AuthenticationPrincipalConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) {
}
@@ -121,20 +155,15 @@ public class EnableWebSecurityTests {
String principal(@AuthenticationPrincipal String principal) {
return principal;
}
}
}
@Test
public void securityFilterChainWhenEnableWebMvcThenAuthenticationPrincipalResolvable() throws Exception {
this.spring.register(SecurityFilterChainAuthenticationPrincipalConfig.class).autowire();
this.mockMvc.perform(get("/").with(authentication(new TestingAuthenticationToken("user1", "password"))))
.andExpect(content().string("user1"));
}
@EnableWebSecurity
@EnableWebMvc
static class SecurityFilterChainAuthenticationPrincipalConfig {
@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return http.build();
@@ -147,70 +176,61 @@ public class EnableWebSecurityTests {
String principal(@AuthenticationPrincipal String principal) {
return principal;
}
}
}
@Test
public void enableWebSecurityWhenNoConfigurationAnnotationThenBeanProxyingEnabled() {
this.spring.register(BeanProxyEnabledByDefaultConfig.class).autowire();
Child childBean = this.spring.getContext().getBean(Child.class);
Parent parentBean = this.spring.getContext().getBean(Parent.class);
assertThat(parentBean.getChild()).isSameAs(childBean);
}
@EnableWebSecurity
static class BeanProxyEnabledByDefaultConfig extends WebSecurityConfigurerAdapter {
@Bean
public Child child() {
Child child() {
return new Child();
}
@Bean
public Parent parent() {
Parent parent() {
return new Parent(child());
}
}
@Test
public void enableWebSecurityWhenProxyBeanMethodsFalseThenBeanProxyingDisabled() {
this.spring.register(BeanProxyDisabledConfig.class).autowire();
Child childBean = this.spring.getContext().getBean(Child.class);
Parent parentBean = this.spring.getContext().getBean(Parent.class);
assertThat(parentBean.getChild()).isNotSameAs(childBean);
}
@Configuration(proxyBeanMethods = false)
@EnableWebSecurity
static class BeanProxyDisabledConfig extends WebSecurityConfigurerAdapter {
@Bean
public Child child() {
Child child() {
return new Child();
}
@Bean
public Parent parent() {
Parent parent() {
return new Parent(child());
}
}
static class Parent {
private Child child;
Parent(Child child) {
this.child = child;
}
public Child getChild() {
return child;
Child getChild() {
return this.child;
}
}
static class Child {
Child() {
}
}
}

View File

@@ -16,9 +16,14 @@
package org.springframework.security.config.annotation.web.configuration;
import java.util.concurrent.Callable;
import javax.servlet.http.HttpServletRequest;
import com.google.common.net.HttpHeaders;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -36,12 +41,10 @@ import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.header.writers.frameoptions.XFrameOptionsHeaderWriter;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import java.util.concurrent.Callable;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.security.config.Customizer.withDefaults;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.authentication;
@@ -62,6 +65,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
* @author Eleftheria Stein
*/
public class HttpSecurityConfigurationTests {
@Rule
public final SpringTestRule spring = new SpringTestRule();
@@ -70,26 +74,27 @@ public class HttpSecurityConfigurationTests {
@Test
public void postWhenDefaultFilterChainBeanThenRespondsWithForbidden() throws Exception {
this.spring.register(DefaultWithFilterChainConfig.class)
.autowire();
this.spring.register(DefaultWithFilterChainConfig.class).autowire();
this.mockMvc.perform(post("/"))
.andExpect(status().isForbidden());
this.mockMvc.perform(post("/")).andExpect(status().isForbidden());
}
@Test
public void getWhenDefaultFilterChainBeanThenDefaultHeadersInResponse() throws Exception {
this.spring.register(DefaultWithFilterChainConfig.class).autowire();
// @formatter:off
MvcResult mvcResult = this.mockMvc.perform(get("/").secure(true))
.andExpect(header().string(HttpHeaders.X_CONTENT_TYPE_OPTIONS, "nosniff"))
.andExpect(header().string(HttpHeaders.X_FRAME_OPTIONS, XFrameOptionsHeaderWriter.XFrameOptionsMode.DENY.name()))
.andExpect(header().string(HttpHeaders.STRICT_TRANSPORT_SECURITY, "max-age=31536000 ; includeSubDomains"))
.andExpect(header().string(HttpHeaders.X_FRAME_OPTIONS,
XFrameOptionsHeaderWriter.XFrameOptionsMode.DENY.name()))
.andExpect(
header().string(HttpHeaders.STRICT_TRANSPORT_SECURITY, "max-age=31536000 ; includeSubDomains"))
.andExpect(header().string(HttpHeaders.CACHE_CONTROL, "no-cache, no-store, max-age=0, must-revalidate"))
.andExpect(header().string(HttpHeaders.EXPIRES, "0"))
.andExpect(header().string(HttpHeaders.PRAGMA, "no-cache"))
.andExpect(header().string(HttpHeaders.X_XSS_PROTECTION, "1; mode=block"))
.andReturn();
// @formatter:on
assertThat(mvcResult.getResponse().getHeaderNames()).containsExactlyInAnyOrder(
HttpHeaders.X_CONTENT_TYPE_OPTIONS, HttpHeaders.X_FRAME_OPTIONS, HttpHeaders.STRICT_TRANSPORT_SECURITY,
HttpHeaders.CACHE_CONTROL, HttpHeaders.EXPIRES, HttpHeaders.PRAGMA, HttpHeaders.X_XSS_PROTECTION);
@@ -98,151 +103,179 @@ public class HttpSecurityConfigurationTests {
@Test
public void logoutWhenDefaultFilterChainBeanThenCreatesDefaultLogoutEndpoint() throws Exception {
this.spring.register(DefaultWithFilterChainConfig.class).autowire();
// @formatter:off
this.mockMvc.perform(post("/logout").with(csrf()))
.andExpect(redirectedUrl("/login?logout"));
// @formatter:on
}
@Test
public void loadConfigWhenDefaultConfigThenWebAsyncManagerIntegrationFilterAdded() throws Exception {
this.spring.register(DefaultWithFilterChainConfig.class, NameController.class).autowire();
MvcResult mvcResult = this.mockMvc.perform(get("/name").with(user("Bob")))
// @formatter:off
MockHttpServletRequestBuilder requestWithBob = get("/name").with(user("Bob"));
MvcResult mvcResult = this.mockMvc.perform(requestWithBob)
.andExpect(request().asyncStarted())
.andReturn();
this.mockMvc.perform(asyncDispatch(mvcResult))
.andExpect(status().isOk())
.andExpect(content().string("Bob"));
}
@RestController
static class NameController {
@GetMapping("/name")
public Callable<String> name() {
return () -> SecurityContextHolder.getContext().getAuthentication().getName();
}
}
@EnableWebSecurity
static class DefaultWithFilterChainConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return http.build();
}
// @formatter:on
}
@Test
public void getWhenDefaultFilterChainBeanThenAnonymousPermitted() throws Exception {
this.spring.register(AuthorizeRequestsConfig.class, UserDetailsConfig.class, BaseController.class).autowire();
// @formatter:off
this.mockMvc.perform(get("/"))
.andExpect(status().isOk());
}
@EnableWebSecurity
static class AuthorizeRequestsConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return http
.authorizeRequests(authorize -> authorize
.anyRequest().permitAll()
)
.build();
}
// @formatter:on
}
@Test
public void authenticateWhenDefaultFilterChainBeanThenSessionIdChanges() throws Exception {
this.spring.register(SecurityEnabledConfig.class, UserDetailsConfig.class).autowire();
MockHttpSession session = new MockHttpSession();
String sessionId = session.getId();
MvcResult result =
this.mockMvc.perform(post("/login")
.param("username", "user")
.param("password", "password")
.session(session)
.with(csrf()))
.andReturn();
// @formatter:off
MockHttpServletRequestBuilder loginRequest = post("/login")
.param("username", "user")
.param("password", "password")
.session(session)
.with(csrf());
// @formatter:on
MvcResult result = this.mockMvc.perform(loginRequest).andReturn();
assertThat(result.getRequest().getSession(false).getId()).isNotEqualTo(sessionId);
}
@Test
public void authenticateWhenDefaultFilterChainBeanThenRedirectsToSavedRequest() throws Exception {
this.spring.register(SecurityEnabledConfig.class, UserDetailsConfig.class).autowire();
MockHttpSession session = (MockHttpSession)
this.mockMvc.perform(get("/messages"))
.andReturn().getRequest().getSession();
this.mockMvc.perform(post("/login")
// @formatter:off
MockHttpSession session = (MockHttpSession) this.mockMvc.perform(get("/messages"))
.andReturn()
.getRequest()
.getSession();
// @formatter:on
// @formatter:off
MockHttpServletRequestBuilder loginRequest = post("/login")
.param("username", "user")
.param("password", "password")
.session(session)
.with(csrf()))
.with(csrf());
// @formatter:on
// @formatter:off
this.mockMvc.perform(loginRequest)
.andExpect(redirectedUrl("http://localhost/messages"));
// @formatter:on
}
@Test
public void authenticateWhenDefaultFilterChainBeanThenRolePrefixIsSet() throws Exception {
this.spring.register(SecurityEnabledConfig.class, UserDetailsConfig.class, UserController.class).autowire();
this.mockMvc.perform(get("/user")
.with(authentication(new TestingAuthenticationToken("user", "password", "ROLE_USER"))))
TestingAuthenticationToken user = new TestingAuthenticationToken("user", "password", "ROLE_USER");
// @formatter:off
this.mockMvc
.perform(get("/user").with(authentication(user)))
.andExpect(status().isOk());
// @formatter:on
}
@Test
public void loginWhenUsingDefaultsThenDefaultLoginPageGenerated() throws Exception {
this.spring.register(SecurityEnabledConfig.class).autowire();
this.mockMvc.perform(get("/login")).andExpect(status().isOk());
}
@RestController
static class NameController {
@GetMapping("/name")
Callable<String> name() {
return () -> SecurityContextHolder.getContext().getAuthentication().getName();
}
}
@EnableWebSecurity
static class DefaultWithFilterChainConfig {
@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return http.build();
}
}
@EnableWebSecurity
static class AuthorizeRequestsConfig {
@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
// @formatter:off
return http
.authorizeRequests((authorize) -> authorize
.anyRequest().permitAll()
)
.build();
// @formatter:on
}
this.mockMvc.perform(get("/login"))
.andExpect(status().isOk());
}
@EnableWebSecurity
static class SecurityEnabledConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
// @formatter:off
return http
.authorizeRequests(authorize -> authorize
.anyRequest().authenticated()
.authorizeRequests((authorize) -> authorize
.anyRequest().authenticated()
)
.formLogin(withDefaults())
.build();
// @formatter:on
}
}
@Configuration
static class UserDetailsConfig {
@Bean
public UserDetailsService userDetailsService() {
UserDetailsService userDetailsService() {
// @formatter:off
UserDetails user = User.withDefaultPasswordEncoder()
.username("user")
.password("password")
.roles("USER")
.build();
// @formatter:on
return new InMemoryUserDetailsManager(user);
}
}
@RestController
static class BaseController {
@GetMapping("/")
public void index() {
void index() {
}
}
@RestController
static class UserController {
@GetMapping("/user")
public void user(HttpServletRequest request) {
void user(HttpServletRequest request) {
if (!request.isUserInRole("USER")) {
throw new AccessDeniedException("This resource is only available to users");
}
}
}
}

View File

@@ -13,10 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.configuration;
import javax.servlet.http.HttpServletRequest;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
import org.springframework.beans.factory.annotation.Autowired;
@@ -31,28 +36,26 @@ import org.springframework.security.oauth2.client.endpoint.OAuth2AccessTokenResp
import org.springframework.security.oauth2.client.endpoint.OAuth2ClientCredentialsGrantRequest;
import org.springframework.security.oauth2.client.registration.ClientRegistration;
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
import org.springframework.security.oauth2.client.registration.TestClientRegistrations;
import org.springframework.security.oauth2.client.web.OAuth2AuthorizedClientRepository;
import org.springframework.security.oauth2.core.OAuth2AccessToken;
import org.springframework.security.oauth2.core.TestOAuth2AccessTokens;
import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import javax.servlet.http.HttpServletRequest;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.eq;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
import static org.springframework.security.oauth2.client.registration.TestClientRegistrations.clientCredentials;
import static org.springframework.security.oauth2.client.registration.TestClientRegistrations.clientRegistration;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.authentication;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
@@ -64,6 +67,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
* @author Joe Grandja
*/
public class OAuth2ClientConfigurationTests {
@Rule
public final SpringTestRule spring = new SpringTestRule();
@@ -75,68 +79,143 @@ public class OAuth2ClientConfigurationTests {
String clientRegistrationId = "client1";
String principalName = "user1";
TestingAuthenticationToken authentication = new TestingAuthenticationToken(principalName, "password");
ClientRegistrationRepository clientRegistrationRepository = mock(ClientRegistrationRepository.class);
ClientRegistration clientRegistration = clientRegistration().registrationId(clientRegistrationId).build();
when(clientRegistrationRepository.findByRegistrationId(eq(clientRegistrationId))).thenReturn(clientRegistration);
ClientRegistration clientRegistration = TestClientRegistrations.clientRegistration()
.registrationId(clientRegistrationId).build();
given(clientRegistrationRepository.findByRegistrationId(eq(clientRegistrationId)))
.willReturn(clientRegistration);
OAuth2AuthorizedClientRepository authorizedClientRepository = mock(OAuth2AuthorizedClientRepository.class);
OAuth2AuthorizedClient authorizedClient = mock(OAuth2AuthorizedClient.class);
when(authorizedClient.getClientRegistration()).thenReturn(clientRegistration);
when(authorizedClientRepository.loadAuthorizedClient(
eq(clientRegistrationId), eq(authentication), any(HttpServletRequest.class)))
.thenReturn(authorizedClient);
given(authorizedClient.getClientRegistration()).willReturn(clientRegistration);
given(authorizedClientRepository.loadAuthorizedClient(eq(clientRegistrationId), eq(authentication),
any(HttpServletRequest.class))).willReturn(authorizedClient);
OAuth2AccessToken accessToken = mock(OAuth2AccessToken.class);
when(authorizedClient.getAccessToken()).thenReturn(accessToken);
given(authorizedClient.getAccessToken()).willReturn(accessToken);
OAuth2AccessTokenResponseClient accessTokenResponseClient = mock(OAuth2AccessTokenResponseClient.class);
OAuth2AuthorizedClientArgumentResolverConfig.CLIENT_REGISTRATION_REPOSITORY = clientRegistrationRepository;
OAuth2AuthorizedClientArgumentResolverConfig.AUTHORIZED_CLIENT_REPOSITORY = authorizedClientRepository;
OAuth2AuthorizedClientArgumentResolverConfig.ACCESS_TOKEN_RESPONSE_CLIENT = accessTokenResponseClient;
this.spring.register(OAuth2AuthorizedClientArgumentResolverConfig.class).autowire();
// @formatter:off
this.mockMvc.perform(get("/authorized-client").with(authentication(authentication)))
.andExpect(status().isOk())
.andExpect(content().string("resolved"));
// @formatter:on
verifyZeroInteractions(accessTokenResponseClient);
}
@Test
public void requestWhenAuthorizedClientNotFoundAndClientCredentialsThenTokenResponseClientIsUsed() throws Exception {
public void requestWhenAuthorizedClientNotFoundAndClientCredentialsThenTokenResponseClientIsUsed()
throws Exception {
String clientRegistrationId = "client1";
String principalName = "user1";
TestingAuthenticationToken authentication = new TestingAuthenticationToken(principalName, "password");
ClientRegistrationRepository clientRegistrationRepository = mock(ClientRegistrationRepository.class);
OAuth2AuthorizedClientRepository authorizedClientRepository = mock(OAuth2AuthorizedClientRepository.class);
OAuth2AccessTokenResponseClient accessTokenResponseClient = mock(OAuth2AccessTokenResponseClient.class);
ClientRegistration clientRegistration = clientCredentials().registrationId(clientRegistrationId).build();
when(clientRegistrationRepository.findByRegistrationId(clientRegistrationId)).thenReturn(clientRegistration);
OAuth2AccessTokenResponse accessTokenResponse = OAuth2AccessTokenResponse.withToken("access-token-1234")
ClientRegistration clientRegistration = TestClientRegistrations.clientCredentials()
.registrationId(clientRegistrationId).build();
given(clientRegistrationRepository.findByRegistrationId(clientRegistrationId)).willReturn(clientRegistration);
// @formatter:off
OAuth2AccessTokenResponse accessTokenResponse = OAuth2AccessTokenResponse
.withToken("access-token-1234")
.tokenType(OAuth2AccessToken.TokenType.BEARER)
.expiresIn(300)
.build();
when(accessTokenResponseClient.getTokenResponse(any(OAuth2ClientCredentialsGrantRequest.class)))
.thenReturn(accessTokenResponse);
// @formatter:on
given(accessTokenResponseClient.getTokenResponse(any(OAuth2ClientCredentialsGrantRequest.class)))
.willReturn(accessTokenResponse);
OAuth2AuthorizedClientArgumentResolverConfig.CLIENT_REGISTRATION_REPOSITORY = clientRegistrationRepository;
OAuth2AuthorizedClientArgumentResolverConfig.AUTHORIZED_CLIENT_REPOSITORY = authorizedClientRepository;
OAuth2AuthorizedClientArgumentResolverConfig.ACCESS_TOKEN_RESPONSE_CLIENT = accessTokenResponseClient;
this.spring.register(OAuth2AuthorizedClientArgumentResolverConfig.class).autowire();
this.mockMvc.perform(get("/authorized-client").with(authentication(authentication)))
MockHttpServletRequestBuilder authenticatedRequest = get("/authorized-client")
.with(authentication(authentication));
// @formatter:off
this.mockMvc.perform(authenticatedRequest)
.andExpect(status().isOk())
.andExpect(content().string("resolved"));
// @formatter:on
verify(accessTokenResponseClient, times(1)).getTokenResponse(any(OAuth2ClientCredentialsGrantRequest.class));
}
// gh-5321
@Test
public void loadContextWhenOAuth2AuthorizedClientRepositoryRegisteredTwiceThenThrowNoUniqueBeanDefinitionException() {
assertThatExceptionOfType(BeanCreationException.class).isThrownBy(
() -> this.spring.register(OAuth2AuthorizedClientRepositoryRegisteredTwiceConfig.class).autowire())
.withRootCauseInstanceOf(NoUniqueBeanDefinitionException.class).withMessageContaining(
"Expected single matching bean of type '" + OAuth2AuthorizedClientRepository.class.getName()
+ "' but found 2: authorizedClientRepository1,authorizedClientRepository2");
}
@Test
public void loadContextWhenClientRegistrationRepositoryNotRegisteredThenThrowNoSuchBeanDefinitionException() {
assertThatExceptionOfType(Exception.class)
.isThrownBy(
() -> this.spring.register(ClientRegistrationRepositoryNotRegisteredConfig.class).autowire())
.withRootCauseInstanceOf(NoSuchBeanDefinitionException.class).withMessageContaining(
"No qualifying bean of type '" + ClientRegistrationRepository.class.getName() + "' available");
}
@Test
public void loadContextWhenClientRegistrationRepositoryRegisteredTwiceThenThrowNoUniqueBeanDefinitionException() {
// @formatter:off
assertThatExceptionOfType(Exception.class)
.isThrownBy(
() -> this.spring.register(ClientRegistrationRepositoryRegisteredTwiceConfig.class).autowire())
.withMessageContaining(
"expected single matching bean but found 2: clientRegistrationRepository1,clientRegistrationRepository2")
.withRootCauseInstanceOf(NoUniqueBeanDefinitionException.class);
// @formatter:on
}
@Test
public void loadContextWhenAccessTokenResponseClientRegisteredTwiceThenThrowNoUniqueBeanDefinitionException() {
// @formatter:off
assertThatExceptionOfType(Exception.class)
.isThrownBy(() -> this.spring.register(AccessTokenResponseClientRegisteredTwiceConfig.class).autowire())
.withRootCauseInstanceOf(NoUniqueBeanDefinitionException.class)
.withMessageContaining(
"expected single matching bean but found 2: accessTokenResponseClient1,accessTokenResponseClient2");
// @formatter:on
}
// gh-8700
@Test
public void requestWhenAuthorizedClientManagerConfiguredThenUsed() throws Exception {
String clientRegistrationId = "client1";
String principalName = "user1";
TestingAuthenticationToken authentication = new TestingAuthenticationToken(principalName, "password");
ClientRegistrationRepository clientRegistrationRepository = mock(ClientRegistrationRepository.class);
OAuth2AuthorizedClientRepository authorizedClientRepository = mock(OAuth2AuthorizedClientRepository.class);
OAuth2AuthorizedClientManager authorizedClientManager = mock(OAuth2AuthorizedClientManager.class);
ClientRegistration clientRegistration = TestClientRegistrations.clientRegistration()
.registrationId(clientRegistrationId).build();
OAuth2AuthorizedClient authorizedClient = new OAuth2AuthorizedClient(clientRegistration, principalName,
TestOAuth2AccessTokens.noScopes());
given(authorizedClientManager.authorize(any())).willReturn(authorizedClient);
OAuth2AuthorizedClientManagerRegisteredConfig.CLIENT_REGISTRATION_REPOSITORY = clientRegistrationRepository;
OAuth2AuthorizedClientManagerRegisteredConfig.AUTHORIZED_CLIENT_REPOSITORY = authorizedClientRepository;
OAuth2AuthorizedClientManagerRegisteredConfig.AUTHORIZED_CLIENT_MANAGER = authorizedClientManager;
this.spring.register(OAuth2AuthorizedClientManagerRegisteredConfig.class).autowire();
MockHttpServletRequestBuilder authenticatedRequest = get("/authorized-client")
.with(authentication(authentication));
// @formatter:off
this.mockMvc
.perform(authenticatedRequest)
.andExpect(status().isOk())
.andExpect(content().string("resolved"));
// @formatter:on
verify(authorizedClientManager).authorize(any());
verifyNoInteractions(clientRegistrationRepository);
verifyNoInteractions(authorizedClientRepository);
}
@EnableWebMvc
@EnableWebSecurity
static class OAuth2AuthorizedClientArgumentResolverConfig extends WebSecurityConfigurerAdapter {
static ClientRegistrationRepository CLIENT_REGISTRATION_REPOSITORY;
static OAuth2AuthorizedClientRepository AUTHORIZED_CLIENT_REPOSITORY;
static OAuth2AccessTokenResponseClient<OAuth2ClientCredentialsGrantRequest> ACCESS_TOKEN_RESPONSE_CLIENT;
@@ -145,38 +224,32 @@ public class OAuth2ClientConfigurationTests {
protected void configure(HttpSecurity http) {
}
@RestController
public class Controller {
@GetMapping("/authorized-client")
public String authorizedClient(@RegisteredOAuth2AuthorizedClient("client1") OAuth2AuthorizedClient authorizedClient) {
return authorizedClient != null ? "resolved" : "not-resolved";
}
}
@Bean
public ClientRegistrationRepository clientRegistrationRepository() {
ClientRegistrationRepository clientRegistrationRepository() {
return CLIENT_REGISTRATION_REPOSITORY;
}
@Bean
public OAuth2AuthorizedClientRepository authorizedClientRepository() {
OAuth2AuthorizedClientRepository authorizedClientRepository() {
return AUTHORIZED_CLIENT_REPOSITORY;
}
@Bean
public OAuth2AccessTokenResponseClient<OAuth2ClientCredentialsGrantRequest> accessTokenResponseClient() {
OAuth2AccessTokenResponseClient<OAuth2ClientCredentialsGrantRequest> accessTokenResponseClient() {
return ACCESS_TOKEN_RESPONSE_CLIENT;
}
}
// gh-5321
@Test
public void loadContextWhenOAuth2AuthorizedClientRepositoryRegisteredTwiceThenThrowNoUniqueBeanDefinitionException() {
assertThatThrownBy(() -> this.spring.register(OAuth2AuthorizedClientRepositoryRegisteredTwiceConfig.class).autowire())
.hasRootCauseInstanceOf(NoUniqueBeanDefinitionException.class)
.hasMessageContaining("Expected single matching bean of type '" + OAuth2AuthorizedClientRepository.class.getName() +
"' but found 2: authorizedClientRepository1,authorizedClientRepository2");
@RestController
class Controller {
@GetMapping("/authorized-client")
String authorizedClient(
@RegisteredOAuth2AuthorizedClient("client1") OAuth2AuthorizedClient authorizedClient) {
return (authorizedClient != null) ? "resolved" : "not-resolved";
}
}
}
@EnableWebMvc
@@ -195,31 +268,25 @@ public class OAuth2ClientConfigurationTests {
}
@Bean
public ClientRegistrationRepository clientRegistrationRepository() {
ClientRegistrationRepository clientRegistrationRepository() {
return mock(ClientRegistrationRepository.class);
}
@Bean
public OAuth2AuthorizedClientRepository authorizedClientRepository1() {
OAuth2AuthorizedClientRepository authorizedClientRepository1() {
return mock(OAuth2AuthorizedClientRepository.class);
}
@Bean
public OAuth2AuthorizedClientRepository authorizedClientRepository2() {
OAuth2AuthorizedClientRepository authorizedClientRepository2() {
return mock(OAuth2AuthorizedClientRepository.class);
}
@Bean
public OAuth2AccessTokenResponseClient<OAuth2ClientCredentialsGrantRequest> accessTokenResponseClient() {
OAuth2AccessTokenResponseClient<OAuth2ClientCredentialsGrantRequest> accessTokenResponseClient() {
return mock(OAuth2AccessTokenResponseClient.class);
}
}
@Test
public void loadContextWhenClientRegistrationRepositoryNotRegisteredThenThrowNoSuchBeanDefinitionException() {
assertThatThrownBy(() -> this.spring.register(ClientRegistrationRepositoryNotRegisteredConfig.class).autowire())
.hasRootCauseInstanceOf(NoSuchBeanDefinitionException.class)
.hasMessageContaining("No qualifying bean of type '" + ClientRegistrationRepository.class.getName() + "' available");
}
@EnableWebMvc
@@ -236,13 +303,7 @@ public class OAuth2ClientConfigurationTests {
.oauth2Login();
// @formatter:on
}
}
@Test
public void loadContextWhenClientRegistrationRepositoryRegisteredTwiceThenThrowNoUniqueBeanDefinitionException() {
assertThatThrownBy(() -> this.spring.register(ClientRegistrationRepositoryRegisteredTwiceConfig.class).autowire())
.hasRootCauseInstanceOf(NoUniqueBeanDefinitionException.class)
.hasMessageContaining("expected single matching bean but found 2: clientRegistrationRepository1,clientRegistrationRepository2");
}
@EnableWebMvc
@@ -261,31 +322,25 @@ public class OAuth2ClientConfigurationTests {
}
@Bean
public ClientRegistrationRepository clientRegistrationRepository1() {
ClientRegistrationRepository clientRegistrationRepository1() {
return mock(ClientRegistrationRepository.class);
}
@Bean
public ClientRegistrationRepository clientRegistrationRepository2() {
ClientRegistrationRepository clientRegistrationRepository2() {
return mock(ClientRegistrationRepository.class);
}
@Bean
public OAuth2AuthorizedClientRepository authorizedClientRepository() {
OAuth2AuthorizedClientRepository authorizedClientRepository() {
return mock(OAuth2AuthorizedClientRepository.class);
}
@Bean
public OAuth2AccessTokenResponseClient<OAuth2ClientCredentialsGrantRequest> accessTokenResponseClient() {
OAuth2AccessTokenResponseClient<OAuth2ClientCredentialsGrantRequest> accessTokenResponseClient() {
return mock(OAuth2AccessTokenResponseClient.class);
}
}
@Test
public void loadContextWhenAccessTokenResponseClientRegisteredTwiceThenThrowNoUniqueBeanDefinitionException() {
assertThatThrownBy(() -> this.spring.register(AccessTokenResponseClientRegisteredTwiceConfig.class).autowire())
.hasRootCauseInstanceOf(NoUniqueBeanDefinitionException.class)
.hasMessageContaining("expected single matching bean but found 2: accessTokenResponseClient1,accessTokenResponseClient2");
}
@EnableWebMvc
@@ -304,60 +359,31 @@ public class OAuth2ClientConfigurationTests {
}
@Bean
public ClientRegistrationRepository clientRegistrationRepository() {
ClientRegistrationRepository clientRegistrationRepository() {
return mock(ClientRegistrationRepository.class);
}
@Bean
public OAuth2AuthorizedClientRepository authorizedClientRepository() {
OAuth2AuthorizedClientRepository authorizedClientRepository() {
return mock(OAuth2AuthorizedClientRepository.class);
}
@Bean
public OAuth2AccessTokenResponseClient<OAuth2ClientCredentialsGrantRequest> accessTokenResponseClient1() {
OAuth2AccessTokenResponseClient<OAuth2ClientCredentialsGrantRequest> accessTokenResponseClient1() {
return mock(OAuth2AccessTokenResponseClient.class);
}
@Bean
public OAuth2AccessTokenResponseClient<OAuth2ClientCredentialsGrantRequest> accessTokenResponseClient2() {
OAuth2AccessTokenResponseClient<OAuth2ClientCredentialsGrantRequest> accessTokenResponseClient2() {
return mock(OAuth2AccessTokenResponseClient.class);
}
}
// gh-8700
@Test
public void requestWhenAuthorizedClientManagerConfiguredThenUsed() throws Exception {
String clientRegistrationId = "client1";
String principalName = "user1";
TestingAuthenticationToken authentication = new TestingAuthenticationToken(principalName, "password");
ClientRegistrationRepository clientRegistrationRepository = mock(ClientRegistrationRepository.class);
OAuth2AuthorizedClientRepository authorizedClientRepository = mock(OAuth2AuthorizedClientRepository.class);
OAuth2AuthorizedClientManager authorizedClientManager = mock(OAuth2AuthorizedClientManager.class);
ClientRegistration clientRegistration = clientRegistration().registrationId(clientRegistrationId).build();
OAuth2AuthorizedClient authorizedClient = new OAuth2AuthorizedClient(
clientRegistration, principalName, TestOAuth2AccessTokens.noScopes());
when(authorizedClientManager.authorize(any())).thenReturn(authorizedClient);
OAuth2AuthorizedClientManagerRegisteredConfig.CLIENT_REGISTRATION_REPOSITORY = clientRegistrationRepository;
OAuth2AuthorizedClientManagerRegisteredConfig.AUTHORIZED_CLIENT_REPOSITORY = authorizedClientRepository;
OAuth2AuthorizedClientManagerRegisteredConfig.AUTHORIZED_CLIENT_MANAGER = authorizedClientManager;
this.spring.register(OAuth2AuthorizedClientManagerRegisteredConfig.class).autowire();
this.mockMvc.perform(get("/authorized-client").with(authentication(authentication)))
.andExpect(status().isOk())
.andExpect(content().string("resolved"));
verify(authorizedClientManager).authorize(any());
verifyNoInteractions(clientRegistrationRepository);
verifyNoInteractions(authorizedClientRepository);
}
@EnableWebMvc
@EnableWebSecurity
static class OAuth2AuthorizedClientManagerRegisteredConfig extends WebSecurityConfigurerAdapter {
static ClientRegistrationRepository CLIENT_REGISTRATION_REPOSITORY;
static OAuth2AuthorizedClientRepository AUTHORIZED_CLIENT_REPOSITORY;
static OAuth2AuthorizedClientManager AUTHORIZED_CLIENT_MANAGER;
@@ -366,28 +392,32 @@ public class OAuth2ClientConfigurationTests {
protected void configure(HttpSecurity http) {
}
@RestController
public class Controller {
@GetMapping("/authorized-client")
public String authorizedClient(@RegisteredOAuth2AuthorizedClient("client1") OAuth2AuthorizedClient authorizedClient) {
return authorizedClient != null ? "resolved" : "not-resolved";
}
}
@Bean
public ClientRegistrationRepository clientRegistrationRepository() {
ClientRegistrationRepository clientRegistrationRepository() {
return CLIENT_REGISTRATION_REPOSITORY;
}
@Bean
public OAuth2AuthorizedClientRepository authorizedClientRepository() {
OAuth2AuthorizedClientRepository authorizedClientRepository() {
return AUTHORIZED_CLIENT_REPOSITORY;
}
@Bean
public OAuth2AuthorizedClientManager authorizedClientManager() {
OAuth2AuthorizedClientManager authorizedClientManager() {
return AUTHORIZED_CLIENT_MANAGER;
}
@RestController
class Controller {
@GetMapping("/authorized-client")
String authorizedClient(
@RegisteredOAuth2AuthorizedClient("client1") OAuth2AuthorizedClient authorizedClient) {
return (authorizedClient != null) ? "resolved" : "not-resolved";
}
}
}
}

View File

@@ -13,10 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.configuration;
import java.net.URL;
import java.net.URLClassLoader;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.beans.FatalBeanException;
import org.springframework.context.annotation.Bean;
import org.springframework.security.authentication.AuthenticationManager;
@@ -24,9 +29,6 @@ import org.springframework.security.config.annotation.authentication.builders.Au
import org.springframework.security.config.test.SpringTestRule;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import java.net.URL;
import java.net.URLClassLoader;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
@@ -34,6 +36,7 @@ import static org.mockito.Mockito.mock;
* @author Joe Grandja
*/
public class Sec2515Tests {
@Rule
public final SpringTestRule spring = new SpringTestRule();
@@ -43,6 +46,28 @@ public class Sec2515Tests {
this.spring.register(StackOverflowSecurityConfig.class).autowire();
}
@Test(expected = FatalBeanException.class)
public void loadConfigWhenAuthenticationManagerNotConfiguredAndRegisterBeanCustomNameThenThrowFatalBeanException() {
this.spring.register(CustomBeanNameStackOverflowSecurityConfig.class).autowire();
}
// SEC-2549
@Test
public void loadConfigWhenChildClassLoaderSetThenContextLoads() {
CanLoadWithChildConfig.AUTHENTICATION_MANAGER = mock(AuthenticationManager.class);
this.spring.register(CanLoadWithChildConfig.class);
AnnotationConfigWebApplicationContext context = (AnnotationConfigWebApplicationContext) this.spring
.getContext();
context.setClassLoader(new URLClassLoader(new URL[0], context.getClassLoader()));
this.spring.autowire();
assertThat(this.spring.getContext().getBean(AuthenticationManager.class)).isNotNull();
} // SEC-2515
@Test
public void loadConfigWhenAuthenticationManagerConfiguredAndRegisterBeanThenContextLoads() {
this.spring.register(SecurityConfig.class).autowire();
}
@EnableWebSecurity
static class StackOverflowSecurityConfig extends WebSecurityConfigurerAdapter {
@@ -51,49 +76,31 @@ public class Sec2515Tests {
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
@Test(expected = FatalBeanException.class)
public void loadConfigWhenAuthenticationManagerNotConfiguredAndRegisterBeanCustomNameThenThrowFatalBeanException() {
this.spring.register(CustomBeanNameStackOverflowSecurityConfig.class).autowire();
}
@EnableWebSecurity
static class CustomBeanNameStackOverflowSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
@Bean(name="custom")
@Bean(name = "custom")
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
// SEC-2549
@Test
public void loadConfigWhenChildClassLoaderSetThenContextLoads() {
CanLoadWithChildConfig.AUTHENTICATION_MANAGER = mock(AuthenticationManager.class);
this.spring.register(CanLoadWithChildConfig.class);
AnnotationConfigWebApplicationContext context = (AnnotationConfigWebApplicationContext) this.spring.getContext();
context.setClassLoader(new URLClassLoader(new URL[0], context.getClassLoader()));
this.spring.autowire();
assertThat(this.spring.getContext().getBean(AuthenticationManager.class)).isNotNull();
}
@EnableWebSecurity
static class CanLoadWithChildConfig extends WebSecurityConfigurerAdapter {
static AuthenticationManager AUTHENTICATION_MANAGER;
@Override
@Bean
public AuthenticationManager authenticationManager() {
return AUTHENTICATION_MANAGER;
}
}
// SEC-2515
@Test
public void loadConfigWhenAuthenticationManagerConfiguredAndRegisterBeanThenContextLoads() {
this.spring.register(SecurityConfig.class).autowire();
}
@EnableWebSecurity
@@ -109,5 +116,7 @@ public class Sec2515Tests {
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication();
}
}
}

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.configuration;
import javax.annotation.PreDestroy;
@@ -31,24 +32,27 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.test.SpringTestRule;
import org.springframework.security.oauth2.server.resource.authentication.BearerTokenAuthentication;
import org.springframework.security.oauth2.server.resource.authentication.TestBearerTokenAuthentications;
import org.springframework.security.oauth2.server.resource.web.reactive.function.client.ServletBearerExchangeFilterFunction;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.reactive.function.client.WebClient;
import static org.springframework.security.oauth2.server.resource.authentication.TestBearerTokenAuthentications.bearer;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.authentication;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
/**
* Tests for applications of {@link SecurityReactorContextConfiguration} in resource servers.
* Tests for applications of {@link SecurityReactorContextConfiguration} in resource
* servers.
*
* @author Josh Cummings
*/
public class SecurityReactorContextConfigurationResourceServerTests {
@Rule
public final SpringTestRule spring = new SpringTestRule();
@@ -58,45 +62,47 @@ public class SecurityReactorContextConfigurationResourceServerTests {
// gh-7418
@Test
public void requestWhenUsingFilterThenBearerTokenPropagated() throws Exception {
BearerTokenAuthentication authentication = bearer();
BearerTokenAuthentication authentication = TestBearerTokenAuthentications.bearer();
this.spring.register(BearerFilterConfig.class, WebServerConfig.class, Controller.class).autowire();
this.mockMvc.perform(get("/token")
.with(authentication(authentication)))
MockHttpServletRequestBuilder authenticatedRequest = get("/token").with(authentication(authentication));
// @formatter:off
this.mockMvc.perform(authenticatedRequest)
.andExpect(status().isOk())
.andExpect(content().string("Bearer token"));
// @formatter:on
}
// gh-7418
@Test
public void requestWhenNotUsingFilterThenBearerTokenNotPropagated() throws Exception {
BearerTokenAuthentication authentication = bearer();
BearerTokenAuthentication authentication = TestBearerTokenAuthentications.bearer();
this.spring.register(BearerFilterlessConfig.class, WebServerConfig.class, Controller.class).autowire();
this.mockMvc.perform(get("/token")
.with(authentication(authentication)))
MockHttpServletRequestBuilder authenticatedRequest = get("/token").with(authentication(authentication));
// @formatter:off
this.mockMvc.perform(authenticatedRequest)
.andExpect(status().isOk())
.andExpect(content().string(""));
// @formatter:on
}
@EnableWebSecurity
static class BearerFilterConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
}
@Bean
WebClient rest() {
ServletBearerExchangeFilterFunction bearer =
new ServletBearerExchangeFilterFunction();
return WebClient.builder()
.filter(bearer).build();
ServletBearerExchangeFilterFunction bearer = new ServletBearerExchangeFilterFunction();
return WebClient.builder().filter(bearer).build();
}
}
@EnableWebSecurity
static class BearerFilterlessConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
}
@@ -105,35 +111,43 @@ public class SecurityReactorContextConfigurationResourceServerTests {
WebClient rest() {
return WebClient.create();
}
}
@RestController
static class Controller {
private final WebClient rest;
private final String uri;
@Autowired
Controller(MockWebServer server, WebClient rest) {
Controller(MockWebServer server, WebClient rest) {
this.uri = server.url("/").toString();
this.rest = rest;
}
@GetMapping("/token")
public String token() {
String token() {
// @formatter:off
return this.rest.get()
.uri(this.uri)
.retrieve()
.bodyToMono(String.class)
.flatMap(result -> this.rest.get()
.flatMap((result) -> this.rest.get()
.uri(this.uri)
.retrieve()
.bodyToMono(String.class))
.bodyToMono(String.class)
)
.block();
// @formatter:on
}
}
@Configuration
static class WebServerConfig {
private final MockWebServer server = new MockWebServer();
@Bean
@@ -147,6 +161,7 @@ public class SecurityReactorContextConfigurationResourceServerTests {
void shutdown() throws Exception {
this.server.shutdown();
}
}
static class AuthorizationHeaderDispatcher extends Dispatcher {
@@ -157,9 +172,10 @@ public class SecurityReactorContextConfigurationResourceServerTests {
String header = request.getHeader("Authorization");
if (StringUtils.isBlank(header)) {
return response;
}
return response.setBody(header);
}
}
}

View File

@@ -13,17 +13,34 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.configuration;
import java.net.URI;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import reactor.core.CoreSubscriber;
import reactor.core.publisher.BaseSubscriber;
import reactor.core.publisher.Mono;
import reactor.core.publisher.Operators;
import reactor.test.StepVerifier;
import reactor.util.context.Context;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.security.authentication.TestingAuthenticationToken;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.SecurityReactorContextConfiguration.SecurityReactorContextSubscriber;
import org.springframework.security.config.test.SpringTestRule;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
@@ -34,23 +51,9 @@ import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.reactive.function.client.ClientRequest;
import org.springframework.web.reactive.function.client.ClientResponse;
import org.springframework.web.reactive.function.client.ExchangeFilterFunction;
import reactor.core.CoreSubscriber;
import reactor.core.publisher.BaseSubscriber;
import reactor.core.publisher.Mono;
import reactor.core.publisher.Operators;
import reactor.test.StepVerifier;
import reactor.util.context.Context;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.net.URI;
import java.util.HashMap;
import java.util.Map;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.entry;
import static org.springframework.http.HttpMethod.GET;
import static org.springframework.security.config.annotation.web.configuration.SecurityReactorContextConfiguration.SecurityReactorContextSubscriber.SECURITY_CONTEXT_ATTRIBUTES;
/**
* Tests for {@link SecurityReactorContextConfiguration}.
@@ -59,11 +62,14 @@ import static org.springframework.security.config.annotation.web.configuration.S
* @since 5.2
*/
public class SecurityReactorContextConfigurationTests {
private MockHttpServletRequest servletRequest;
private MockHttpServletResponse servletResponse;
private Authentication authentication;
private SecurityReactorContextConfiguration.SecurityReactorContextSubscriberRegistrar subscriberRegistrar =
new SecurityReactorContextConfiguration.SecurityReactorContextSubscriberRegistrar();
private SecurityReactorContextConfiguration.SecurityReactorContextSubscriberRegistrar subscriberRegistrar = new SecurityReactorContextConfiguration.SecurityReactorContextSubscriberRegistrar();
@Rule
public final SpringTestRule spring = new SpringTestRule();
@@ -83,26 +89,25 @@ public class SecurityReactorContextConfigurationTests {
@Test
public void createSubscriberIfNecessaryWhenSubscriberContextContainsSecurityContextAttributesThenReturnOriginalSubscriber() {
Context context = Context.of(SECURITY_CONTEXT_ATTRIBUTES, new HashMap<>());
Context context = Context.of(SecurityReactorContextSubscriber.SECURITY_CONTEXT_ATTRIBUTES, new HashMap<>());
BaseSubscriber<Object> originalSubscriber = new BaseSubscriber<Object>() {
@Override
public Context currentContext() {
return context;
}
};
CoreSubscriber<Object> resultSubscriber = this.subscriberRegistrar.createSubscriberIfNecessary(originalSubscriber);
CoreSubscriber<Object> resultSubscriber = this.subscriberRegistrar
.createSubscriberIfNecessary(originalSubscriber);
assertThat(resultSubscriber).isSameAs(originalSubscriber);
}
@Test
public void createSubscriberIfNecessaryWhenWebSecurityContextAvailableThenCreateWithParentContext() {
RequestContextHolder.setRequestAttributes(
new ServletRequestAttributes(this.servletRequest, this.servletResponse));
RequestContextHolder
.setRequestAttributes(new ServletRequestAttributes(this.servletRequest, this.servletResponse));
SecurityContextHolder.getContext().setAuthentication(this.authentication);
String testKey = "test_key";
String testValue = "test_value";
BaseSubscriber<Object> parent = new BaseSubscriber<Object>() {
@Override
public Context currentContext() {
@@ -110,25 +115,23 @@ public class SecurityReactorContextConfigurationTests {
}
};
CoreSubscriber<Object> subscriber = this.subscriberRegistrar.createSubscriberIfNecessary(parent);
Context resultContext = subscriber.currentContext();
assertThat(resultContext.getOrEmpty(testKey)).hasValue(testValue);
Map<Object, Object> securityContextAttributes = resultContext.getOrDefault(SECURITY_CONTEXT_ATTRIBUTES, null);
Map<Object, Object> securityContextAttributes = resultContext
.getOrDefault(SecurityReactorContextSubscriber.SECURITY_CONTEXT_ATTRIBUTES, null);
assertThat(securityContextAttributes).hasSize(3);
assertThat(securityContextAttributes).contains(
entry(HttpServletRequest.class, this.servletRequest),
assertThat(securityContextAttributes).contains(entry(HttpServletRequest.class, this.servletRequest),
entry(HttpServletResponse.class, this.servletResponse),
entry(Authentication.class, this.authentication));
}
@Test
public void createSubscriberIfNecessaryWhenParentContextContainsSecurityContextAttributesThenUseParentContext() {
RequestContextHolder.setRequestAttributes(
new ServletRequestAttributes(this.servletRequest, this.servletResponse));
RequestContextHolder
.setRequestAttributes(new ServletRequestAttributes(this.servletRequest, this.servletResponse));
SecurityContextHolder.getContext().setAuthentication(this.authentication);
Context parentContext = Context.of(SECURITY_CONTEXT_ATTRIBUTES, new HashMap<>());
Context parentContext = Context.of(SecurityReactorContextSubscriber.SECURITY_CONTEXT_ATTRIBUTES,
new HashMap<>());
BaseSubscriber<Object> parent = new BaseSubscriber<Object>() {
@Override
public Context currentContext() {
@@ -136,101 +139,97 @@ public class SecurityReactorContextConfigurationTests {
}
};
CoreSubscriber<Object> subscriber = this.subscriberRegistrar.createSubscriberIfNecessary(parent);
Context resultContext = subscriber.currentContext();
assertThat(resultContext).isSameAs(parentContext);
}
@Test
public void createSubscriberIfNecessaryWhenNotServletRequestAttributesThenStillCreate() {
RequestContextHolder.setRequestAttributes(
new RequestAttributes() {
@Override
public Object getAttribute(String name, int scope) {
return null;
}
RequestContextHolder.setRequestAttributes(new RequestAttributes() {
@Override
public Object getAttribute(String name, int scope) {
return null;
}
@Override
public void setAttribute(String name, Object value, int scope) {
}
@Override
public void setAttribute(String name, Object value, int scope) {
}
@Override
public void removeAttribute(String name, int scope) {
}
@Override
public void removeAttribute(String name, int scope) {
}
@Override
public String[] getAttributeNames(int scope) {
return new String[0];
}
@Override
public String[] getAttributeNames(int scope) {
return new String[0];
}
@Override
public void registerDestructionCallback(String name, Runnable callback, int scope) {
}
@Override
public void registerDestructionCallback(String name, Runnable callback, int scope) {
}
@Override
public Object resolveReference(String key) {
return null;
}
@Override
public Object resolveReference(String key) {
return null;
}
@Override
public String getSessionId() {
return null;
}
@Override
public String getSessionId() {
return null;
}
@Override
public Object getSessionMutex() {
return null;
}
});
CoreSubscriber<Object> subscriber = this.subscriberRegistrar.createSubscriberIfNecessary(Operators.emptySubscriber());
@Override
public Object getSessionMutex() {
return null;
}
});
CoreSubscriber<Object> subscriber = this.subscriberRegistrar
.createSubscriberIfNecessary(Operators.emptySubscriber());
assertThat(subscriber).isInstanceOf(SecurityReactorContextConfiguration.SecurityReactorContextSubscriber.class);
}
@Test
public void createPublisherWhenLastOperatorAddedThenSecurityContextAttributesAvailable() {
// Trigger the importing of SecurityReactorContextConfiguration via OAuth2ImportSelector
// Trigger the importing of SecurityReactorContextConfiguration via
// OAuth2ImportSelector
this.spring.register(SecurityConfig.class).autowire();
// Setup for SecurityReactorContextSubscriberRegistrar
RequestContextHolder.setRequestAttributes(
new ServletRequestAttributes(this.servletRequest, this.servletResponse));
RequestContextHolder
.setRequestAttributes(new ServletRequestAttributes(this.servletRequest, this.servletResponse));
SecurityContextHolder.getContext().setAuthentication(this.authentication);
ClientResponse clientResponseOk = ClientResponse.create(HttpStatus.OK).build();
ExchangeFilterFunction filter = (req, next) ->
Mono.subscriberContext()
.filter(ctx -> ctx.hasKey(SECURITY_CONTEXT_ATTRIBUTES))
.map(ctx -> ctx.get(SECURITY_CONTEXT_ATTRIBUTES))
.cast(Map.class)
.map(attributes -> {
if (attributes.containsKey(HttpServletRequest.class) &&
attributes.containsKey(HttpServletResponse.class) &&
attributes.containsKey(Authentication.class)) {
return clientResponseOk;
} else {
return ClientResponse.create(HttpStatus.NOT_FOUND).build();
}
});
ClientRequest clientRequest = ClientRequest.create(GET, URI.create("https://example.com")).build();
// @formatter:off
ExchangeFilterFunction filter = (req, next) -> Mono.subscriberContext()
.filter((ctx) -> ctx.hasKey(SecurityReactorContextSubscriber.SECURITY_CONTEXT_ATTRIBUTES))
.map((ctx) -> ctx.get(SecurityReactorContextSubscriber.SECURITY_CONTEXT_ATTRIBUTES))
.cast(Map.class)
.map((attributes) -> {
if (attributes.containsKey(HttpServletRequest.class)
&& attributes.containsKey(HttpServletResponse.class)
&& attributes.containsKey(Authentication.class)) {
return clientResponseOk;
}
else {
return ClientResponse.create(HttpStatus.NOT_FOUND).build();
}
});
// @formatter:on
ClientRequest clientRequest = ClientRequest.create(HttpMethod.GET, URI.create("https://example.com")).build();
MockExchangeFunction exchange = new MockExchangeFunction();
Map<Object, Object> expectedContextAttributes = new HashMap<>();
expectedContextAttributes.put(HttpServletRequest.class, this.servletRequest);
expectedContextAttributes.put(HttpServletResponse.class, this.servletResponse);
expectedContextAttributes.put(Authentication.class, this.authentication);
Mono<ClientResponse> clientResponseMono = filter.filter(clientRequest, exchange)
.flatMap(response -> filter.filter(clientRequest, exchange));
.flatMap((response) -> filter.filter(clientRequest, exchange));
// @formatter:off
StepVerifier.create(clientResponseMono)
.expectAccessibleContext()
.contains(SECURITY_CONTEXT_ATTRIBUTES, expectedContextAttributes)
.contains(SecurityReactorContextSubscriber.SECURITY_CONTEXT_ATTRIBUTES, expectedContextAttributes)
.then()
.expectNext(clientResponseOk)
.verifyComplete();
// @formatter:on
}
@EnableWebSecurity
@@ -239,5 +238,7 @@ public class SecurityReactorContextConfigurationTests {
@Override
protected void configure(HttpSecurity http) throws Exception {
}
}
}

View File

@@ -13,15 +13,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.configuration;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
package org.springframework.security.config.annotation.web.configuration;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -45,6 +44,10 @@ import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.model;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view;
/**
* @author Rob Winch
*/
@@ -62,10 +65,10 @@ public class WebMvcSecurityConfigurationTests {
@Before
public void setup() {
mockMvc = MockMvcBuilders.webAppContextSetup(context).build();
authentication = new TestingAuthenticationToken("user", "password",
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context).build();
this.authentication = new TestingAuthenticationToken("user", "password",
AuthorityUtils.createAuthorityList("ROLE_USER"));
SecurityContextHolder.getContext().setAuthentication(authentication);
SecurityContextHolder.getContext().setAuthentication(this.authentication);
}
@After
@@ -75,25 +78,23 @@ public class WebMvcSecurityConfigurationTests {
@Test
public void authenticationPrincipalResolved() throws Exception {
mockMvc.perform(get("/authentication-principal"))
.andExpect(assertResult(authentication.getPrincipal()))
this.mockMvc.perform(get("/authentication-principal"))
.andExpect(assertResult(this.authentication.getPrincipal()))
.andExpect(view().name("authentication-principal-view"));
}
@Test
public void deprecatedAuthenticationPrincipalResolved() throws Exception {
mockMvc.perform(get("/deprecated-authentication-principal"))
.andExpect(assertResult(authentication.getPrincipal()))
this.mockMvc.perform(get("/deprecated-authentication-principal"))
.andExpect(assertResult(this.authentication.getPrincipal()))
.andExpect(view().name("deprecated-authentication-principal-view"));
}
@Test
public void csrfToken() throws Exception {
CsrfToken csrfToken = new DefaultCsrfToken("headerName", "paramName", "token");
MockHttpServletRequestBuilder request = get("/csrf").requestAttr(
CsrfToken.class.getName(), csrfToken);
mockMvc.perform(request).andExpect(assertResult(csrfToken));
MockHttpServletRequestBuilder request = get("/csrf").requestAttr(CsrfToken.class.getName(), csrfToken);
this.mockMvc.perform(request).andExpect(assertResult(csrfToken));
}
private ResultMatcher assertResult(Object expected) {
@@ -104,32 +105,33 @@ public class WebMvcSecurityConfigurationTests {
static class TestController {
@RequestMapping("/authentication-principal")
public ModelAndView authenticationPrincipal(
@AuthenticationPrincipal String principal) {
ModelAndView authenticationPrincipal(@AuthenticationPrincipal String principal) {
return new ModelAndView("authentication-principal-view", "result", principal);
}
@RequestMapping("/deprecated-authentication-principal")
public ModelAndView deprecatedAuthenticationPrincipal(
ModelAndView deprecatedAuthenticationPrincipal(
@org.springframework.security.web.bind.annotation.AuthenticationPrincipal String principal) {
return new ModelAndView("deprecated-authentication-principal-view", "result",
principal);
return new ModelAndView("deprecated-authentication-principal-view", "result", principal);
}
@RequestMapping("/csrf")
public ModelAndView csrf(CsrfToken token) {
ModelAndView csrf(CsrfToken token) {
return new ModelAndView("view", "result", token);
}
}
@Configuration
@EnableWebMvc
@EnableWebSecurity
static class Config {
@Bean
public TestController testController() {
TestController testController() {
return new TestController();
}
}
}
}

View File

@@ -13,10 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.configuration.sec2377;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.security.config.annotation.web.configuration.sec2377.a.Sec2377AConfig;
import org.springframework.security.config.annotation.web.configuration.sec2377.b.Sec2377BConfig;
@@ -37,11 +39,9 @@ public class Sec2377Tests {
@Test
public void refreshContextWhenParentAndChildRegisteredThenNoException() {
this.parent.register(Sec2377AConfig.class).autowire();
ConfigurableApplicationContext context =
this.child.register(Sec2377BConfig.class).getContext();
ConfigurableApplicationContext context = this.child.register(Sec2377BConfig.class).getContext();
context.setParent(this.parent.getContext());
this.child.autowire();
}
}

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.configuration.sec2377.a;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.configuration.sec2377.b;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;

View File

@@ -16,8 +16,11 @@
package org.springframework.security.config.annotation.web.configurers;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import org.springframework.http.HttpMethod;
import org.springframework.security.access.AccessDecisionVoter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
@@ -26,67 +29,69 @@ import org.springframework.security.web.util.matcher.RequestMatcher;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.List;
public class AbstractConfigAttributeRequestMatcherRegistryTests {
private ConcreteAbstractRequestMatcherMappingConfigurer registry;
@Before
public void setup() {
registry = new ConcreteAbstractRequestMatcherMappingConfigurer();
this.registry = new ConcreteAbstractRequestMatcherMappingConfigurer();
}
@Test
public void testGetRequestMatcherIsTypeRegexMatcher(){
List<RequestMatcher> requestMatchers = registry.regexMatchers(HttpMethod.GET, "/a.*");
public void testGetRequestMatcherIsTypeRegexMatcher() {
List<RequestMatcher> requestMatchers = this.registry.regexMatchers(HttpMethod.GET, "/a.*");
for (RequestMatcher requestMatcher : requestMatchers) {
assertThat(requestMatcher).isInstanceOf(RegexRequestMatcher.class);
}
}
@Test
public void testRequestMatcherIsTypeRegexMatcher(){
List<RequestMatcher> requestMatchers = registry.regexMatchers( "/a.*");
public void testRequestMatcherIsTypeRegexMatcher() {
List<RequestMatcher> requestMatchers = this.registry.regexMatchers("/a.*");
for (RequestMatcher requestMatcher : requestMatchers) {
assertThat(requestMatcher).isInstanceOf(RegexRequestMatcher.class);
}
}
@Test
public void testGetRequestMatcherIsTypeAntPathRequestMatcher(){
List<RequestMatcher> requestMatchers = registry.antMatchers(HttpMethod.GET, "/a.*");
public void testGetRequestMatcherIsTypeAntPathRequestMatcher() {
List<RequestMatcher> requestMatchers = this.registry.antMatchers(HttpMethod.GET, "/a.*");
for (RequestMatcher requestMatcher : requestMatchers) {
assertThat(requestMatcher).isInstanceOf(AntPathRequestMatcher.class);
}
}
@Test
public void testRequestMatcherIsTypeAntPathRequestMatcher(){
List<RequestMatcher> requestMatchers = registry.antMatchers("/a.*");
public void testRequestMatcherIsTypeAntPathRequestMatcher() {
List<RequestMatcher> requestMatchers = this.registry.antMatchers("/a.*");
for (RequestMatcher requestMatcher : requestMatchers) {
assertThat(requestMatcher).isInstanceOf(AntPathRequestMatcher.class);
}
}
static class ConcreteAbstractRequestMatcherMappingConfigurer extends AbstractConfigAttributeRequestMatcherRegistry<List<RequestMatcher>> {
static class ConcreteAbstractRequestMatcherMappingConfigurer
extends AbstractConfigAttributeRequestMatcherRegistry<List<RequestMatcher>> {
List<AccessDecisionVoter> decisionVoters() {
return null;
}
@Override
protected List<RequestMatcher> chainRequestMatchersInternal(List<RequestMatcher> requestMatchers) {
return requestMatchers;
}
@Override
public List<RequestMatcher> mvcMatchers(String... mvcPatterns) {
return null;
}
@Override
public List<RequestMatcher> mvcMatchers(HttpMethod method, String... mvcPatterns) {
return null;
}
}
}

View File

@@ -13,10 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.configurers;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
@@ -40,6 +42,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
* @author Josh Cummings
*/
public class AnonymousConfigurerTests {
@Rule
public final SpringTestRule spring = new SpringTestRule();
@@ -49,9 +52,25 @@ public class AnonymousConfigurerTests {
@Test
public void requestWhenAnonymousTwiceInvokedThenDoesNotOverride() throws Exception {
this.spring.register(InvokeTwiceDoesNotOverride.class, PrincipalController.class).autowire();
this.mockMvc.perform(get("/")).andExpect(content().string("principal"));
}
this.mockMvc.perform(get("/"))
.andExpect(content().string("principal"));
@Test
public void requestWhenAnonymousPrincipalInLambdaThenPrincipalUsed() throws Exception {
this.spring.register(AnonymousPrincipalInLambdaConfig.class, PrincipalController.class).autowire();
this.mockMvc.perform(get("/")).andExpect(content().string("principal"));
}
@Test
public void requestWhenAnonymousDisabledInLambdaThenRespondsWithForbidden() throws Exception {
this.spring.register(AnonymousDisabledInLambdaConfig.class, PrincipalController.class).autowire();
this.mockMvc.perform(get("/")).andExpect(status().isForbidden());
}
@Test
public void requestWhenAnonymousWithDefaultsInLambdaThenRespondsWithOk() throws Exception {
this.spring.register(AnonymousWithDefaultsInLambdaConfig.class, PrincipalController.class).autowire();
this.mockMvc.perform(get("/")).andExpect(status().isOk());
}
@EnableWebSecurity
@@ -60,21 +79,16 @@ public class AnonymousConfigurerTests {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.anonymous()
.key("key")
.principal("principal")
.and()
.anonymous();
// @formatter:on
}
}
@Test
public void requestWhenAnonymousPrincipalInLambdaThenPrincipalUsed() throws Exception {
this.spring.register(AnonymousPrincipalInLambdaConfig.class, PrincipalController.class).autowire();
this.mockMvc.perform(get("/"))
.andExpect(content().string("principal"));
}
@EnableWebSecurity
@@ -85,29 +99,23 @@ public class AnonymousConfigurerTests {
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.anonymous(anonymous ->
.anonymous((anonymous) ->
anonymous
.principal("principal")
);
// @formatter:on
}
}
@Test
public void requestWhenAnonymousDisabledInLambdaThenRespondsWithForbidden() throws Exception {
this.spring.register(AnonymousDisabledInLambdaConfig.class, PrincipalController.class).autowire();
this.mockMvc.perform(get("/"))
.andExpect(status().isForbidden());
}
@EnableWebSecurity
static class AnonymousDisabledInLambdaConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.authorizeRequests(authorizeRequests ->
.authorizeRequests((authorizeRequests) ->
authorizeRequests
.anyRequest().permitAll()
)
@@ -115,6 +123,7 @@ public class AnonymousConfigurerTests {
// @formatter:on
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// @formatter:off
auth
@@ -122,23 +131,17 @@ public class AnonymousConfigurerTests {
.withUser(PasswordEncodedUser.user());
// @formatter:on
}
}
@Test
public void requestWhenAnonymousWithDefaultsInLambdaThenRespondsWithOk() throws Exception {
this.spring.register(AnonymousWithDefaultsInLambdaConfig.class, PrincipalController.class).autowire();
this.mockMvc.perform(get("/"))
.andExpect(status().isOk());
}
@EnableWebSecurity
static class AnonymousWithDefaultsInLambdaConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.authorizeRequests(authorizeRequests ->
.authorizeRequests((authorizeRequests) ->
authorizeRequests
.anyRequest().permitAll()
)
@@ -146,6 +149,7 @@ public class AnonymousConfigurerTests {
// @formatter:on
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// @formatter:off
auth
@@ -153,13 +157,17 @@ public class AnonymousConfigurerTests {
.withUser(PasswordEncodedUser.user());
// @formatter:on
}
}
@RestController
static class PrincipalController {
@GetMapping("/")
String principal(@AuthenticationPrincipal String principal) {
return principal;
}
}
}

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.configurers;
import javax.servlet.http.HttpServletResponse;
@@ -58,11 +59,15 @@ import static org.springframework.security.config.Customizer.withDefaults;
*
*/
public class AuthorizeRequestsTests {
AnnotationConfigWebApplicationContext context;
MockHttpServletRequest request;
MockHttpServletResponse response;
MockFilterChain chain;
MockServletContext servletContext;
@Autowired
@@ -89,15 +94,196 @@ public class AuthorizeRequestsTests {
public void antMatchersMethodAndNoPatterns() throws Exception {
loadConfig(AntMatchersNoPatternsConfig.class);
this.request.setMethod("POST");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_FORBIDDEN);
}
@Test
public void postWhenPostDenyAllInLambdaThenRespondsWithForbidden() throws Exception {
loadConfig(AntMatchersNoPatternsInLambdaConfig.class);
this.request.setMethod("POST");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_FORBIDDEN);
}
// SEC-2256
@Test
public void antMatchersPathVariables() throws Exception {
loadConfig(AntPatchersPathVariables.class);
this.request.setServletPath("/user/user");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
this.setup();
this.request.setServletPath("/user/deny");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_FORBIDDEN);
}
// SEC-2256
@Test
public void antMatchersPathVariablesCaseInsensitive() throws Exception {
loadConfig(AntPatchersPathVariables.class);
this.request.setServletPath("/USER/user");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
this.setup();
this.request.setServletPath("/USER/deny");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_FORBIDDEN);
}
// gh-3786
@Test
public void antMatchersPathVariablesCaseInsensitiveCamelCaseVariables() throws Exception {
loadConfig(AntMatchersPathVariablesCamelCaseVariables.class);
this.request.setServletPath("/USER/user");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
this.setup();
this.request.setServletPath("/USER/deny");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_FORBIDDEN);
}
// gh-3394
@Test
public void roleHiearchy() throws Exception {
loadConfig(RoleHiearchyConfig.class);
SecurityContext securityContext = new SecurityContextImpl();
securityContext.setAuthentication(new UsernamePasswordAuthenticationToken("test", "notused",
AuthorityUtils.createAuthorityList("ROLE_USER")));
this.request.getSession().setAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY,
securityContext);
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
}
@Test
public void mvcMatcher() throws Exception {
loadConfig(MvcMatcherConfig.class, LegacyMvcMatchingConfig.class);
this.request.setRequestURI("/path");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
setup();
this.request.setRequestURI("/path.html");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
setup();
this.request.setServletPath("/path/");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
}
@Test
public void requestWhenMvcMatcherDenyAllThenRespondsWithUnauthorized() throws Exception {
loadConfig(MvcMatcherInLambdaConfig.class, LegacyMvcMatchingConfig.class);
this.request.setRequestURI("/path");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
setup();
this.request.setRequestURI("/path.html");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
setup();
this.request.setServletPath("/path/");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
}
@Test
public void requestWhenMvcMatcherServletPathDenyAllThenMatchesOnServletPath() throws Exception {
loadConfig(MvcMatcherServletPathInLambdaConfig.class, LegacyMvcMatchingConfig.class);
this.request.setServletPath("/spring");
this.request.setRequestURI("/spring/path");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
setup();
this.request.setServletPath("/spring");
this.request.setRequestURI("/spring/path.html");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
setup();
this.request.setServletPath("/spring");
this.request.setRequestURI("/spring/path/");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
setup();
this.request.setServletPath("/foo");
this.request.setRequestURI("/foo/path");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
setup();
this.request.setServletPath("/");
this.request.setRequestURI("/path");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
}
@Test
public void mvcMatcherPathVariables() throws Exception {
loadConfig(MvcMatcherPathVariablesConfig.class);
this.request.setRequestURI("/user/user");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
this.setup();
this.request.setRequestURI("/user/deny");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
}
@Test
public void requestWhenMvcMatcherPathVariablesThenMatchesOnPathVariables() throws Exception {
loadConfig(MvcMatcherPathVariablesInLambdaConfig.class);
this.request.setRequestURI("/user/user");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
this.setup();
this.request.setRequestURI("/user/deny");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
}
@Test
public void mvcMatcherServletPath() throws Exception {
loadConfig(MvcMatcherServletPathConfig.class, LegacyMvcMatchingConfig.class);
this.request.setServletPath("/spring");
this.request.setRequestURI("/spring/path");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
setup();
this.request.setServletPath("/spring");
this.request.setRequestURI("/spring/path.html");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
setup();
this.request.setServletPath("/spring");
this.request.setRequestURI("/spring/path/");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
setup();
this.request.setServletPath("/foo");
this.request.setRequestURI("/foo/path");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
setup();
this.request.setServletPath("/");
this.request.setRequestURI("/path");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
}
public void loadConfig(Class<?>... configs) {
this.context = new AnnotationConfigWebApplicationContext();
this.context.register(configs);
this.context.setServletContext(this.servletContext);
this.context.refresh();
this.context.getAutowireCapableBeanFactory().autowireBean(this);
}
@EnableWebSecurity
@Configuration
static class AntMatchersNoPatternsConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
@@ -114,26 +300,18 @@ public class AuthorizeRequestsTests {
.inMemoryAuthentication();
// @formatter:on
}
}
@Test
public void postWhenPostDenyAllInLambdaThenRespondsWithForbidden() throws Exception {
loadConfig(AntMatchersNoPatternsInLambdaConfig.class);
this.request.setMethod("POST");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_FORBIDDEN);
}
@EnableWebSecurity
@Configuration
static class AntMatchersNoPatternsInLambdaConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.authorizeRequests(authorizeRequests ->
.authorizeRequests((authorizeRequests) ->
authorizeRequests
.antMatchers(HttpMethod.POST).denyAll()
);
@@ -147,49 +325,13 @@ public class AuthorizeRequestsTests {
.inMemoryAuthentication();
// @formatter:on
}
}
// SEC-2256
@Test
public void antMatchersPathVariables() throws Exception {
loadConfig(AntPatchersPathVariables.class);
this.request.setServletPath("/user/user");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
this.setup();
this.request.setServletPath("/user/deny");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_FORBIDDEN);
}
// SEC-2256
@Test
public void antMatchersPathVariablesCaseInsensitive() throws Exception {
loadConfig(AntPatchersPathVariables.class);
this.request.setServletPath("/USER/user");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
this.setup();
this.request.setServletPath("/USER/deny");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_FORBIDDEN);
}
@EnableWebSecurity
@Configuration
static class AntPatchersPathVariables extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
@@ -207,30 +349,13 @@ public class AuthorizeRequestsTests {
.inMemoryAuthentication();
// @formatter:on
}
}
// gh-3786
@Test
public void antMatchersPathVariablesCaseInsensitiveCamelCaseVariables() throws Exception {
loadConfig(AntMatchersPathVariablesCamelCaseVariables.class);
this.request.setServletPath("/USER/user");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
this.setup();
this.request.setServletPath("/USER/deny");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_FORBIDDEN);
}
@EnableWebSecurity
@Configuration
static class AntMatchersPathVariablesCamelCaseVariables extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
@@ -248,25 +373,13 @@ public class AuthorizeRequestsTests {
.inMemoryAuthentication();
// @formatter:on
}
}
// gh-3394
@Test
public void roleHiearchy() throws Exception {
loadConfig(RoleHiearchyConfig.class);
SecurityContext securityContext = new SecurityContextImpl();
securityContext.setAuthentication(new UsernamePasswordAuthenticationToken("test", "notused", AuthorityUtils.createAuthorityList("ROLE_USER")));
this.request.getSession().setAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY, securityContext);
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
}
@EnableWebSecurity
@Configuration
static class RoleHiearchyConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
@@ -285,44 +398,19 @@ public class AuthorizeRequestsTests {
}
@Bean
public RoleHierarchy roleHiearchy() {
RoleHierarchy roleHiearchy() {
RoleHierarchyImpl result = new RoleHierarchyImpl();
result.setHierarchy("ROLE_USER > ROLE_ADMIN");
return result;
}
}
@Test
public void mvcMatcher() throws Exception {
loadConfig(MvcMatcherConfig.class, LegacyMvcMatchingConfig.class);
this.request.setRequestURI("/path");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus())
.isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
setup();
this.request.setRequestURI("/path.html");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus())
.isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
setup();
this.request.setServletPath("/path/");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus())
.isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
}
@EnableWebSecurity
@Configuration
@EnableWebMvc
static class MvcMatcherConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
@@ -343,50 +431,27 @@ public class AuthorizeRequestsTests {
@RestController
static class PathController {
@RequestMapping("/path")
public String path() {
String path() {
return "path";
}
}
}
@Test
public void requestWhenMvcMatcherDenyAllThenRespondsWithUnauthorized() throws Exception {
loadConfig(MvcMatcherInLambdaConfig.class, LegacyMvcMatchingConfig.class);
this.request.setRequestURI("/path");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus())
.isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
setup();
this.request.setRequestURI("/path.html");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus())
.isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
setup();
this.request.setServletPath("/path/");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus())
.isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
}
@EnableWebSecurity
@Configuration
@EnableWebMvc
static class MvcMatcherInLambdaConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.httpBasic(withDefaults())
.authorizeRequests(authorizeRequests ->
.authorizeRequests((authorizeRequests) ->
authorizeRequests
.mvcMatchers("/path").denyAll()
);
@@ -403,63 +468,21 @@ public class AuthorizeRequestsTests {
@RestController
static class PathController {
@RequestMapping("/path")
public String path() {
String path() {
return "path";
}
}
}
@Test
public void mvcMatcherServletPath() throws Exception {
loadConfig(MvcMatcherServletPathConfig.class, LegacyMvcMatchingConfig.class);
this.request.setServletPath("/spring");
this.request.setRequestURI("/spring/path");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus())
.isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
setup();
this.request.setServletPath("/spring");
this.request.setRequestURI("/spring/path.html");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus())
.isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
setup();
this.request.setServletPath("/spring");
this.request.setRequestURI("/spring/path/");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus())
.isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
setup();
this.request.setServletPath("/foo");
this.request.setRequestURI("/foo/path");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
setup();
this.request.setServletPath("/");
this.request.setRequestURI("/path");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
}
@EnableWebSecurity
@Configuration
@EnableWebMvc
static class MvcMatcherServletPathConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
@@ -480,69 +503,27 @@ public class AuthorizeRequestsTests {
@RestController
static class PathController {
@RequestMapping("/path")
public String path() {
String path() {
return "path";
}
}
}
@Test
public void requestWhenMvcMatcherServletPathDenyAllThenMatchesOnServletPath() throws Exception {
loadConfig(MvcMatcherServletPathInLambdaConfig.class, LegacyMvcMatchingConfig.class);
this.request.setServletPath("/spring");
this.request.setRequestURI("/spring/path");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus())
.isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
setup();
this.request.setServletPath("/spring");
this.request.setRequestURI("/spring/path.html");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus())
.isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
setup();
this.request.setServletPath("/spring");
this.request.setRequestURI("/spring/path/");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus())
.isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
setup();
this.request.setServletPath("/foo");
this.request.setRequestURI("/foo/path");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
setup();
this.request.setServletPath("/");
this.request.setRequestURI("/path");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
}
@EnableWebSecurity
@Configuration
@EnableWebMvc
static class MvcMatcherServletPathInLambdaConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.httpBasic(withDefaults())
.authorizeRequests(authorizeRequests ->
.authorizeRequests((authorizeRequests) ->
authorizeRequests
.mvcMatchers("/path").servletPath("/spring").denyAll()
);
@@ -559,36 +540,21 @@ public class AuthorizeRequestsTests {
@RestController
static class PathController {
@RequestMapping("/path")
public String path() {
String path() {
return "path";
}
}
}
@Test
public void mvcMatcherPathVariables() throws Exception {
loadConfig(MvcMatcherPathVariablesConfig.class);
this.request.setRequestURI("/user/user");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
this.setup();
this.request.setRequestURI("/user/deny");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus())
.isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
}
@EnableWebSecurity
@Configuration
@EnableWebMvc
static class MvcMatcherPathVariablesConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
@@ -609,42 +575,27 @@ public class AuthorizeRequestsTests {
@RestController
static class PathController {
@RequestMapping("/path")
public String path() {
String path() {
return "path";
}
}
}
@Test
public void requestWhenMvcMatcherPathVariablesThenMatchesOnPathVariables() throws Exception {
loadConfig(MvcMatcherPathVariablesInLambdaConfig.class);
this.request.setRequestURI("/user/user");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
this.setup();
this.request.setRequestURI("/user/deny");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus())
.isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
}
@EnableWebSecurity
@Configuration
@EnableWebMvc
static class MvcMatcherPathVariablesInLambdaConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.httpBasic(withDefaults())
.authorizeRequests(authorizeRequests ->
.authorizeRequests((authorizeRequests) ->
authorizeRequests
.mvcMatchers("/user/{userName}").access("#userName == 'user'")
);
@@ -661,17 +612,21 @@ public class AuthorizeRequestsTests {
@RestController
static class PathController {
@RequestMapping("/path")
public String path() {
String path() {
return "path";
}
}
}
@EnableWebSecurity
@Configuration
@EnableWebMvc
static class MvcMatcherPathServletPathRequiredConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
@@ -692,27 +647,24 @@ public class AuthorizeRequestsTests {
@RestController
static class PathController {
@RequestMapping("/path")
public String path() {
String path() {
return "path";
}
}
}
@Configuration
static class LegacyMvcMatchingConfig implements WebMvcConfigurer {
@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
configurer.setUseSuffixPatternMatch(true);
}
}
public void loadConfig(Class<?>... configs) {
this.context = new AnnotationConfigWebApplicationContext();
this.context.register(configs);
this.context.setServletContext(this.servletContext);
this.context.refresh();
this.context.getAutowireCapableBeanFactory().autowireBean(this);
}
}

View File

@@ -18,6 +18,7 @@ package org.springframework.security.config.annotation.web.configurers;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.ObjectPostProcessor;
@@ -55,40 +56,45 @@ public class ChannelSecurityConfigurerTests {
public void configureWhenRegisteringObjectPostProcessorThenInvokedOnInsecureChannelProcessor() {
ObjectPostProcessorConfig.objectPostProcessor = spy(ReflectingObjectPostProcessor.class);
this.spring.register(ObjectPostProcessorConfig.class).autowire();
verify(ObjectPostProcessorConfig.objectPostProcessor)
.postProcess(any(InsecureChannelProcessor.class));
verify(ObjectPostProcessorConfig.objectPostProcessor).postProcess(any(InsecureChannelProcessor.class));
}
@Test
public void configureWhenRegisteringObjectPostProcessorThenInvokedOnSecureChannelProcessor() {
ObjectPostProcessorConfig.objectPostProcessor = spy(ReflectingObjectPostProcessor.class);
this.spring.register(ObjectPostProcessorConfig.class).autowire();
verify(ObjectPostProcessorConfig.objectPostProcessor)
.postProcess(any(SecureChannelProcessor.class));
verify(ObjectPostProcessorConfig.objectPostProcessor).postProcess(any(SecureChannelProcessor.class));
}
@Test
public void configureWhenRegisteringObjectPostProcessorThenInvokedOnChannelDecisionManagerImpl() {
ObjectPostProcessorConfig.objectPostProcessor = spy(ReflectingObjectPostProcessor.class);
this.spring.register(ObjectPostProcessorConfig.class).autowire();
verify(ObjectPostProcessorConfig.objectPostProcessor)
.postProcess(any(ChannelDecisionManagerImpl.class));
verify(ObjectPostProcessorConfig.objectPostProcessor).postProcess(any(ChannelDecisionManagerImpl.class));
}
@Test
public void configureWhenRegisteringObjectPostProcessorThenInvokedOnChannelProcessingFilter() {
ObjectPostProcessorConfig.objectPostProcessor = spy(ReflectingObjectPostProcessor.class);
this.spring.register(ObjectPostProcessorConfig.class).autowire();
verify(ObjectPostProcessorConfig.objectPostProcessor).postProcess(any(ChannelProcessingFilter.class));
}
verify(ObjectPostProcessorConfig.objectPostProcessor)
.postProcess(any(ChannelProcessingFilter.class));
@Test
public void requiresChannelWhenInvokesTwiceThenUsesOriginalRequiresSecure() throws Exception {
this.spring.register(DuplicateInvocationsDoesNotOverrideConfig.class).autowire();
this.mvc.perform(get("/")).andExpect(redirectedUrl("https://localhost/"));
}
@Test
public void requestWhenRequiresChannelConfiguredInLambdaThenRedirectsToHttps() throws Exception {
this.spring.register(RequiresChannelInLambdaConfig.class).autowire();
this.mvc.perform(get("/")).andExpect(redirectedUrl("https://localhost/"));
}
@EnableWebSecurity
static class ObjectPostProcessorConfig extends WebSecurityConfigurerAdapter {
static ObjectPostProcessor<Object> objectPostProcessor;
@Override
@@ -104,21 +110,16 @@ public class ChannelSecurityConfigurerTests {
static ObjectPostProcessor<Object> objectPostProcessor() {
return objectPostProcessor;
}
}
static class ReflectingObjectPostProcessor implements ObjectPostProcessor<Object> {
@Override
public <O> O postProcess(O object) {
return object;
}
}
@Test
public void requiresChannelWhenInvokesTwiceThenUsesOriginalRequiresSecure() throws Exception {
this.spring.register(DuplicateInvocationsDoesNotOverrideConfig.class).autowire();
mvc.perform(get("/"))
.andExpect(redirectedUrl("https://localhost/"));
}
@EnableWebSecurity
@@ -134,14 +135,7 @@ public class ChannelSecurityConfigurerTests {
.requiresChannel();
// @formatter:on
}
}
@Test
public void requestWhenRequiresChannelConfiguredInLambdaThenRedirectsToHttps() throws Exception {
this.spring.register(RequiresChannelInLambdaConfig.class).autowire();
mvc.perform(get("/"))
.andExpect(redirectedUrl("https://localhost/"));
}
@EnableWebSecurity
@@ -151,11 +145,13 @@ public class ChannelSecurityConfigurerTests {
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.requiresChannel(requiresChannel ->
.requiresChannel((requiresChannel) ->
requiresChannel
.anyRequest().requiresSecure()
);
// @formatter:on
}
}
}

View File

@@ -16,9 +16,13 @@
package org.springframework.security.config.annotation.web.configurers;
import java.util.Arrays;
import java.util.Collections;
import com.google.common.net.HttpHeaders;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
@@ -38,10 +42,7 @@ import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import java.util.Arrays;
import java.util.Collections;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.springframework.security.config.Customizer.withDefaults;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.options;
@@ -55,6 +56,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
* @author Eleftheria Stein
*/
public class CorsConfigurerTests {
@Rule
public final SpringTestRule spring = new SpringTestRule();
@@ -63,9 +65,119 @@ public class CorsConfigurerTests {
@Test
public void configureWhenNoMvcThenException() {
assertThatThrownBy(() -> this.spring.register(DefaultCorsConfig.class).autowire())
.isInstanceOf(BeanCreationException.class)
.hasMessageContaining("Please ensure Spring Security & Spring MVC are configured in a shared ApplicationContext");
assertThatExceptionOfType(BeanCreationException.class)
.isThrownBy(() -> this.spring.register(DefaultCorsConfig.class).autowire()).withMessageContaining(
"Please ensure Spring Security & Spring MVC are configured in a shared ApplicationContext");
}
@Test
public void getWhenCrossOriginAnnotationThenRespondsWithCorsHeaders() throws Exception {
this.spring.register(MvcCorsConfig.class).autowire();
this.mvc.perform(get("/").header(HttpHeaders.ORIGIN, "https://example.com"))
.andExpect(header().exists("Access-Control-Allow-Origin"))
.andExpect(header().exists("X-Content-Type-Options"));
}
@Test
public void optionsWhenCrossOriginAnnotationThenRespondsWithCorsHeaders() throws Exception {
this.spring.register(MvcCorsConfig.class).autowire();
this.mvc.perform(options("/")
.header(org.springframework.http.HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, HttpMethod.POST.name())
.header(HttpHeaders.ORIGIN, "https://example.com")).andExpect(status().isOk())
.andExpect(header().exists("Access-Control-Allow-Origin"))
.andExpect(header().exists("X-Content-Type-Options"));
}
@Test
public void getWhenDefaultsInLambdaAndCrossOriginAnnotationThenRespondsWithCorsHeaders() throws Exception {
this.spring.register(MvcCorsInLambdaConfig.class).autowire();
this.mvc.perform(get("/").header(HttpHeaders.ORIGIN, "https://example.com"))
.andExpect(header().exists("Access-Control-Allow-Origin"))
.andExpect(header().exists("X-Content-Type-Options"));
}
@Test
public void optionsWhenDefaultsInLambdaAndCrossOriginAnnotationThenRespondsWithCorsHeaders() throws Exception {
this.spring.register(MvcCorsInLambdaConfig.class).autowire();
this.mvc.perform(options("/")
.header(org.springframework.http.HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, HttpMethod.POST.name())
.header(HttpHeaders.ORIGIN, "https://example.com")).andExpect(status().isOk())
.andExpect(header().exists("Access-Control-Allow-Origin"))
.andExpect(header().exists("X-Content-Type-Options"));
}
@Test
public void getWhenCorsConfigurationSourceBeanThenRespondsWithCorsHeaders() throws Exception {
this.spring.register(ConfigSourceConfig.class).autowire();
this.mvc.perform(get("/").header(HttpHeaders.ORIGIN, "https://example.com"))
.andExpect(header().exists("Access-Control-Allow-Origin"))
.andExpect(header().exists("X-Content-Type-Options"));
}
@Test
public void optionsWhenCorsConfigurationSourceBeanThenRespondsWithCorsHeaders() throws Exception {
this.spring.register(ConfigSourceConfig.class).autowire();
this.mvc.perform(options("/")
.header(org.springframework.http.HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, HttpMethod.POST.name())
.header(HttpHeaders.ORIGIN, "https://example.com")).andExpect(status().isOk())
.andExpect(header().exists("Access-Control-Allow-Origin"))
.andExpect(header().exists("X-Content-Type-Options"));
}
@Test
public void getWhenMvcCorsInLambdaConfigAndCorsConfigurationSourceBeanThenRespondsWithCorsHeaders()
throws Exception {
this.spring.register(ConfigSourceInLambdaConfig.class).autowire();
this.mvc.perform(get("/").header(HttpHeaders.ORIGIN, "https://example.com"))
.andExpect(header().exists("Access-Control-Allow-Origin"))
.andExpect(header().exists("X-Content-Type-Options"));
}
@Test
public void optionsWhenMvcCorsInLambdaConfigAndCorsConfigurationSourceBeanThenRespondsWithCorsHeaders()
throws Exception {
this.spring.register(ConfigSourceInLambdaConfig.class).autowire();
this.mvc.perform(options("/")
.header(org.springframework.http.HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, HttpMethod.POST.name())
.header(HttpHeaders.ORIGIN, "https://example.com")).andExpect(status().isOk())
.andExpect(header().exists("Access-Control-Allow-Origin"))
.andExpect(header().exists("X-Content-Type-Options"));
}
@Test
public void getWhenCorsFilterBeanThenRespondsWithCorsHeaders() throws Exception {
this.spring.register(CorsFilterConfig.class).autowire();
this.mvc.perform(get("/").header(HttpHeaders.ORIGIN, "https://example.com"))
.andExpect(header().exists("Access-Control-Allow-Origin"))
.andExpect(header().exists("X-Content-Type-Options"));
}
@Test
public void optionsWhenCorsFilterBeanThenRespondsWithCorsHeaders() throws Exception {
this.spring.register(CorsFilterConfig.class).autowire();
this.mvc.perform(options("/")
.header(org.springframework.http.HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, HttpMethod.POST.name())
.header(HttpHeaders.ORIGIN, "https://example.com")).andExpect(status().isOk())
.andExpect(header().exists("Access-Control-Allow-Origin"))
.andExpect(header().exists("X-Content-Type-Options"));
}
@Test
public void getWhenConfigSourceInLambdaConfigAndCorsFilterBeanThenRespondsWithCorsHeaders() throws Exception {
this.spring.register(CorsFilterInLambdaConfig.class).autowire();
this.mvc.perform(get("/").header(HttpHeaders.ORIGIN, "https://example.com"))
.andExpect(header().exists("Access-Control-Allow-Origin"))
.andExpect(header().exists("X-Content-Type-Options"));
}
@Test
public void optionsWhenConfigSourceInLambdaConfigAndCorsFilterBeanThenRespondsWithCorsHeaders() throws Exception {
this.spring.register(CorsFilterInLambdaConfig.class).autowire();
this.mvc.perform(options("/")
.header(org.springframework.http.HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, HttpMethod.POST.name())
.header(HttpHeaders.ORIGIN, "https://example.com")).andExpect(status().isOk())
.andExpect(header().exists("Access-Control-Allow-Origin"))
.andExpect(header().exists("X-Content-Type-Options"));
}
@EnableWebSecurity
@@ -81,28 +193,7 @@ public class CorsConfigurerTests {
.cors();
// @formatter:on
}
}
@Test
public void getWhenCrossOriginAnnotationThenRespondsWithCorsHeaders() throws Exception {
this.spring.register(MvcCorsConfig.class).autowire();
this.mvc.perform(get("/")
.header(HttpHeaders.ORIGIN, "https://example.com"))
.andExpect(header().exists("Access-Control-Allow-Origin"))
.andExpect(header().exists("X-Content-Type-Options"));
}
@Test
public void optionsWhenCrossOriginAnnotationThenRespondsWithCorsHeaders() throws Exception {
this.spring.register(MvcCorsConfig.class).autowire();
this.mvc.perform(options("/")
.header(org.springframework.http.HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, HttpMethod.POST.name())
.header(HttpHeaders.ORIGIN, "https://example.com"))
.andExpect(status().isOk())
.andExpect(header().exists("Access-Control-Allow-Origin"))
.andExpect(header().exists("X-Content-Type-Options"));
}
@EnableWebMvc
@@ -121,37 +212,16 @@ public class CorsConfigurerTests {
}
@RestController
@CrossOrigin(methods = {
RequestMethod.GET, RequestMethod.POST
})
@CrossOrigin(methods = { RequestMethod.GET, RequestMethod.POST })
static class CorsController {
@RequestMapping("/")
String hello() {
return "Hello";
}
}
}
@Test
public void getWhenDefaultsInLambdaAndCrossOriginAnnotationThenRespondsWithCorsHeaders() throws Exception {
this.spring.register(MvcCorsInLambdaConfig.class).autowire();
this.mvc.perform(get("/")
.header(HttpHeaders.ORIGIN, "https://example.com"))
.andExpect(header().exists("Access-Control-Allow-Origin"))
.andExpect(header().exists("X-Content-Type-Options"));
}
@Test
public void optionsWhenDefaultsInLambdaAndCrossOriginAnnotationThenRespondsWithCorsHeaders() throws Exception {
this.spring.register(MvcCorsInLambdaConfig.class).autowire();
this.mvc.perform(options("/")
.header(org.springframework.http.HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, HttpMethod.POST.name())
.header(HttpHeaders.ORIGIN, "https://example.com"))
.andExpect(status().isOk())
.andExpect(header().exists("Access-Control-Allow-Origin"))
.andExpect(header().exists("X-Content-Type-Options"));
}
@EnableWebMvc
@@ -162,7 +232,7 @@ public class CorsConfigurerTests {
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.authorizeRequests(authorizeRequests ->
.authorizeRequests((authorizeRequests) ->
authorizeRequests
.anyRequest().authenticated()
)
@@ -171,37 +241,16 @@ public class CorsConfigurerTests {
}
@RestController
@CrossOrigin(methods = {
RequestMethod.GET, RequestMethod.POST
})
@CrossOrigin(methods = { RequestMethod.GET, RequestMethod.POST })
static class CorsController {
@RequestMapping("/")
String hello() {
return "Hello";
}
}
}
@Test
public void getWhenCorsConfigurationSourceBeanThenRespondsWithCorsHeaders() throws Exception {
this.spring.register(ConfigSourceConfig.class).autowire();
this.mvc.perform(get("/")
.header(HttpHeaders.ORIGIN, "https://example.com"))
.andExpect(header().exists("Access-Control-Allow-Origin"))
.andExpect(header().exists("X-Content-Type-Options"));
}
@Test
public void optionsWhenCorsConfigurationSourceBeanThenRespondsWithCorsHeaders() throws Exception {
this.spring.register(ConfigSourceConfig.class).autowire();
this.mvc.perform(options("/")
.header(org.springframework.http.HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, HttpMethod.POST.name())
.header(HttpHeaders.ORIGIN, "https://example.com"))
.andExpect(status().isOk())
.andExpect(header().exists("Access-Control-Allow-Origin"))
.andExpect(header().exists("X-Content-Type-Options"));
}
@EnableWebSecurity
@@ -223,36 +272,11 @@ public class CorsConfigurerTests {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.setAllowedOrigins(Collections.singletonList("*"));
corsConfiguration.setAllowedMethods(Arrays.asList(
RequestMethod.GET.name(),
RequestMethod.POST.name()));
corsConfiguration.setAllowedMethods(Arrays.asList(RequestMethod.GET.name(), RequestMethod.POST.name()));
source.registerCorsConfiguration("/**", corsConfiguration);
return source;
}
}
@Test
public void getWhenMvcCorsInLambdaConfigAndCorsConfigurationSourceBeanThenRespondsWithCorsHeaders()
throws Exception {
this.spring.register(ConfigSourceInLambdaConfig.class).autowire();
this.mvc.perform(get("/")
.header(HttpHeaders.ORIGIN, "https://example.com"))
.andExpect(header().exists("Access-Control-Allow-Origin"))
.andExpect(header().exists("X-Content-Type-Options"));
}
@Test
public void optionsWhenMvcCorsInLambdaConfigAndCorsConfigurationSourceBeanThenRespondsWithCorsHeaders()
throws Exception {
this.spring.register(ConfigSourceInLambdaConfig.class).autowire();
this.mvc.perform(options("/")
.header(org.springframework.http.HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, HttpMethod.POST.name())
.header(HttpHeaders.ORIGIN, "https://example.com"))
.andExpect(status().isOk())
.andExpect(header().exists("Access-Control-Allow-Origin"))
.andExpect(header().exists("X-Content-Type-Options"));
}
@EnableWebSecurity
@@ -262,7 +286,7 @@ public class CorsConfigurerTests {
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.authorizeRequests(authorizeRequests ->
.authorizeRequests((authorizeRequests) ->
authorizeRequests
.anyRequest().authenticated()
)
@@ -275,34 +299,11 @@ public class CorsConfigurerTests {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.setAllowedOrigins(Collections.singletonList("*"));
corsConfiguration.setAllowedMethods(Arrays.asList(
RequestMethod.GET.name(),
RequestMethod.POST.name()));
corsConfiguration.setAllowedMethods(Arrays.asList(RequestMethod.GET.name(), RequestMethod.POST.name()));
source.registerCorsConfiguration("/**", corsConfiguration);
return source;
}
}
@Test
public void getWhenCorsFilterBeanThenRespondsWithCorsHeaders() throws Exception {
this.spring.register(CorsFilterConfig.class).autowire();
this.mvc.perform(get("/")
.header(HttpHeaders.ORIGIN, "https://example.com"))
.andExpect(header().exists("Access-Control-Allow-Origin"))
.andExpect(header().exists("X-Content-Type-Options"));
}
@Test
public void optionsWhenCorsFilterBeanThenRespondsWithCorsHeaders() throws Exception {
this.spring.register(CorsFilterConfig.class).autowire();
this.mvc.perform(options("/")
.header(org.springframework.http.HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, HttpMethod.POST.name())
.header(HttpHeaders.ORIGIN, "https://example.com"))
.andExpect(status().isOk())
.andExpect(header().exists("Access-Control-Allow-Origin"))
.andExpect(header().exists("X-Content-Type-Options"));
}
@EnableWebSecurity
@@ -324,34 +325,11 @@ public class CorsConfigurerTests {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.setAllowedOrigins(Collections.singletonList("*"));
corsConfiguration.setAllowedMethods(Arrays.asList(
RequestMethod.GET.name(),
RequestMethod.POST.name()));
corsConfiguration.setAllowedMethods(Arrays.asList(RequestMethod.GET.name(), RequestMethod.POST.name()));
source.registerCorsConfiguration("/**", corsConfiguration);
return new CorsFilter(source);
}
}
@Test
public void getWhenConfigSourceInLambdaConfigAndCorsFilterBeanThenRespondsWithCorsHeaders() throws Exception {
this.spring.register(CorsFilterInLambdaConfig.class).autowire();
this.mvc.perform(get("/")
.header(HttpHeaders.ORIGIN, "https://example.com"))
.andExpect(header().exists("Access-Control-Allow-Origin"))
.andExpect(header().exists("X-Content-Type-Options"));
}
@Test
public void optionsWhenConfigSourceInLambdaConfigAndCorsFilterBeanThenRespondsWithCorsHeaders() throws Exception {
this.spring.register(CorsFilterInLambdaConfig.class).autowire();
this.mvc.perform(options("/")
.header(org.springframework.http.HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, HttpMethod.POST.name())
.header(HttpHeaders.ORIGIN, "https://example.com"))
.andExpect(status().isOk())
.andExpect(header().exists("Access-Control-Allow-Origin"))
.andExpect(header().exists("X-Content-Type-Options"));
}
@EnableWebSecurity
@@ -361,7 +339,7 @@ public class CorsConfigurerTests {
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.authorizeRequests(authorizeRequests ->
.authorizeRequests((authorizeRequests) ->
authorizeRequests
.anyRequest().authenticated()
)
@@ -374,11 +352,11 @@ public class CorsConfigurerTests {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.setAllowedOrigins(Collections.singletonList("*"));
corsConfiguration.setAllowedMethods(Arrays.asList(
RequestMethod.GET.name(),
RequestMethod.POST.name()));
corsConfiguration.setAllowedMethods(Arrays.asList(RequestMethod.GET.name(), RequestMethod.POST.name()));
source.registerCorsConfiguration("/**", corsConfiguration);
return new CorsFilter(source);
}
}
}

View File

@@ -48,21 +48,40 @@ public class CsrfConfigurerIgnoringRequestMatchersTests {
public final SpringTestRule spring = new SpringTestRule();
@Test
public void requestWhenIgnoringRequestMatchersThenAugmentedByConfiguredRequestMatcher()
throws Exception {
public void requestWhenIgnoringRequestMatchersThenAugmentedByConfiguredRequestMatcher() throws Exception {
this.spring.register(IgnoringRequestMatchers.class, BasicController.class).autowire();
this.mvc.perform(get("/path")).andExpect(status().isForbidden());
this.mvc.perform(post("/path")).andExpect(status().isOk());
}
this.mvc.perform(get("/path"))
.andExpect(status().isForbidden());
@Test
public void requestWhenIgnoringRequestMatchersInLambdaThenAugmentedByConfiguredRequestMatcher() throws Exception {
this.spring.register(IgnoringRequestInLambdaMatchers.class, BasicController.class).autowire();
this.mvc.perform(get("/path")).andExpect(status().isForbidden());
this.mvc.perform(post("/path")).andExpect(status().isOk());
}
this.mvc.perform(post("/path"))
.andExpect(status().isOk());
@Test
public void requestWhenIgnoringRequestMatcherThenUnionsWithConfiguredIgnoringAntMatchers() throws Exception {
this.spring.register(IgnoringPathsAndMatchers.class, BasicController.class).autowire();
this.mvc.perform(put("/csrf")).andExpect(status().isForbidden());
this.mvc.perform(post("/csrf")).andExpect(status().isOk());
this.mvc.perform(put("/no-csrf")).andExpect(status().isOk());
}
@Test
public void requestWhenIgnoringRequestMatcherInLambdaThenUnionsWithConfiguredIgnoringAntMatchers()
throws Exception {
this.spring.register(IgnoringPathsAndMatchersInLambdaConfig.class, BasicController.class).autowire();
this.mvc.perform(put("/csrf")).andExpect(status().isForbidden());
this.mvc.perform(post("/csrf")).andExpect(status().isOk());
this.mvc.perform(put("/no-csrf")).andExpect(status().isOk());
}
@EnableWebSecurity
static class IgnoringRequestMatchers extends WebSecurityConfigurerAdapter {
RequestMatcher requestMatcher =
request -> HttpMethod.POST.name().equals(request.getMethod());
RequestMatcher requestMatcher = (request) -> HttpMethod.POST.name().equals(request.getMethod());
@Override
protected void configure(HttpSecurity http) throws Exception {
@@ -73,58 +92,32 @@ public class CsrfConfigurerIgnoringRequestMatchersTests {
.ignoringRequestMatchers(this.requestMatcher);
// @formatter:on
}
}
@Test
public void requestWhenIgnoringRequestMatchersInLambdaThenAugmentedByConfiguredRequestMatcher()
throws Exception {
this.spring.register(IgnoringRequestInLambdaMatchers.class, BasicController.class).autowire();
this.mvc.perform(get("/path"))
.andExpect(status().isForbidden());
this.mvc.perform(post("/path"))
.andExpect(status().isOk());
}
@EnableWebSecurity
static class IgnoringRequestInLambdaMatchers extends WebSecurityConfigurerAdapter {
RequestMatcher requestMatcher =
request -> HttpMethod.POST.name().equals(request.getMethod());
RequestMatcher requestMatcher = (request) -> HttpMethod.POST.name().equals(request.getMethod());
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.csrf(csrf ->
.csrf((csrf) ->
csrf
.requireCsrfProtectionMatcher(new AntPathRequestMatcher("/path"))
.ignoringRequestMatchers(this.requestMatcher)
);
// @formatter:on
}
}
@Test
public void requestWhenIgnoringRequestMatcherThenUnionsWithConfiguredIgnoringAntMatchers()
throws Exception {
this.spring.register(IgnoringPathsAndMatchers.class, BasicController.class).autowire();
this.mvc.perform(put("/csrf"))
.andExpect(status().isForbidden());
this.mvc.perform(post("/csrf"))
.andExpect(status().isOk());
this.mvc.perform(put("/no-csrf"))
.andExpect(status().isOk());
}
@EnableWebSecurity
static class IgnoringPathsAndMatchers extends WebSecurityConfigurerAdapter {
RequestMatcher requestMatcher =
request -> HttpMethod.POST.name().equals(request.getMethod());
RequestMatcher requestMatcher = (request) -> HttpMethod.POST.name().equals(request.getMethod());
@Override
protected void configure(HttpSecurity http) throws Exception {
@@ -135,44 +128,31 @@ public class CsrfConfigurerIgnoringRequestMatchersTests {
.ignoringRequestMatchers(this.requestMatcher);
// @formatter:on
}
}
@Test
public void requestWhenIgnoringRequestMatcherInLambdaThenUnionsWithConfiguredIgnoringAntMatchers()
throws Exception {
this.spring.register(IgnoringPathsAndMatchersInLambdaConfig.class, BasicController.class).autowire();
this.mvc.perform(put("/csrf"))
.andExpect(status().isForbidden());
this.mvc.perform(post("/csrf"))
.andExpect(status().isOk());
this.mvc.perform(put("/no-csrf"))
.andExpect(status().isOk());
}
@EnableWebSecurity
static class IgnoringPathsAndMatchersInLambdaConfig extends WebSecurityConfigurerAdapter {
RequestMatcher requestMatcher =
request -> HttpMethod.POST.name().equals(request.getMethod());
RequestMatcher requestMatcher = (request) -> HttpMethod.POST.name().equals(request.getMethod());
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.csrf(csrf ->
.csrf((csrf) ->
csrf
.ignoringAntMatchers("/no-csrf")
.ignoringRequestMatchers(this.requestMatcher)
);
// @formatter:on
}
}
@RestController
public static class BasicController {
@RequestMapping("/path")
public String path() {
return "path";
@@ -187,5 +167,7 @@ public class CsrfConfigurerIgnoringRequestMatchersTests {
public String noCsrf() {
return "no-csrf";
}
}
}

View File

@@ -13,13 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.configurers;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
package org.springframework.security.config.annotation.web.configurers;
import org.junit.After;
import org.junit.Test;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
@@ -27,75 +26,80 @@ import org.springframework.context.annotation.Primary;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.servlet.support.csrf.CsrfRequestDataValueProcessor;
import org.springframework.web.servlet.support.RequestDataValueProcessor;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
/**
* @author Rob Winch
*
*/
public class CsrfConfigurerNoWebMvcTests {
ConfigurableApplicationContext context;
@After
public void teardown() {
if (context != null) {
context.close();
if (this.context != null) {
this.context.close();
}
}
@Test
public void missingDispatcherServletPreventsCsrfRequestDataValueProcessor() {
loadContext(EnableWebConfig.class);
assertThat(context.containsBeanDefinition("requestDataValueProcessor")).isTrue();
assertThat(this.context.containsBeanDefinition("requestDataValueProcessor")).isTrue();
}
@Test
public void findDispatcherServletPreventsCsrfRequestDataValueProcessor() {
loadContext(EnableWebMvcConfig.class);
assertThat(context.containsBeanDefinition("requestDataValueProcessor")).isTrue();
assertThat(this.context.containsBeanDefinition("requestDataValueProcessor")).isTrue();
}
@Test
public void overrideCsrfRequestDataValueProcessor() {
loadContext(EnableWebOverrideRequestDataConfig.class);
assertThat(context.getBean(RequestDataValueProcessor.class).getClass())
assertThat(this.context.getBean(RequestDataValueProcessor.class).getClass())
.isNotEqualTo(CsrfRequestDataValueProcessor.class);
}
@EnableWebSecurity
static class EnableWebConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) {
}
}
@EnableWebSecurity
static class EnableWebOverrideRequestDataConfig {
@Bean
@Primary
public RequestDataValueProcessor requestDataValueProcessor() {
return mock(RequestDataValueProcessor.class);
}
}
@EnableWebSecurity
static class EnableWebMvcConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) {
}
}
private void loadContext(Class<?> configs) {
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();
annotationConfigApplicationContext.register(configs);
annotationConfigApplicationContext.refresh();
this.context = annotationConfigApplicationContext;
}
@EnableWebSecurity
static class EnableWebConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) {
}
}
@EnableWebSecurity
static class EnableWebOverrideRequestDataConfig {
@Bean
@Primary
RequestDataValueProcessor requestDataValueProcessor() {
return mock(RequestDataValueProcessor.class);
}
}
@EnableWebSecurity
static class EnableWebMvcConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) {
}
}
}

View File

@@ -16,8 +16,14 @@
package org.springframework.security.config.annotation.web.configurers;
import java.net.URI;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
@@ -40,29 +46,33 @@ import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.support.RequestDataValueProcessor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.net.URI;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.springframework.security.config.Customizer.withDefaults;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user;
import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.authenticated;
import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.unauthenticated;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.head;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.options;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.request;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@@ -75,6 +85,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
* @author Sam Simmons
*/
public class CsrfConfigurerTests {
@Rule
public final SpringTestRule spring = new SpringTestRule();
@@ -83,100 +94,317 @@ public class CsrfConfigurerTests {
@Test
public void postWhenWebSecurityEnabledThenRespondsWithForbidden() throws Exception {
this.spring.register(CsrfAppliedDefaultConfig.class, AllowHttpMethodsFirewallConfig.class, BasicController.class)
this.spring
.register(CsrfAppliedDefaultConfig.class, AllowHttpMethodsFirewallConfig.class, BasicController.class)
.autowire();
this.mvc.perform(post("/"))
.andExpect(status().isForbidden());
this.mvc.perform(post("/")).andExpect(status().isForbidden());
}
@Test
public void putWhenWebSecurityEnabledThenRespondsWithForbidden() throws Exception {
this.spring.register(CsrfAppliedDefaultConfig.class, AllowHttpMethodsFirewallConfig.class, BasicController.class)
this.spring
.register(CsrfAppliedDefaultConfig.class, AllowHttpMethodsFirewallConfig.class, BasicController.class)
.autowire();
this.mvc.perform(put("/"))
.andExpect(status().isForbidden());
this.mvc.perform(put("/")).andExpect(status().isForbidden());
}
@Test
public void patchWhenWebSecurityEnabledThenRespondsWithForbidden() throws Exception {
this.spring.register(CsrfAppliedDefaultConfig.class, AllowHttpMethodsFirewallConfig.class, BasicController.class)
this.spring
.register(CsrfAppliedDefaultConfig.class, AllowHttpMethodsFirewallConfig.class, BasicController.class)
.autowire();
this.mvc.perform(patch("/"))
.andExpect(status().isForbidden());
this.mvc.perform(patch("/")).andExpect(status().isForbidden());
}
@Test
public void deleteWhenWebSecurityEnabledThenRespondsWithForbidden() throws Exception {
this.spring.register(CsrfAppliedDefaultConfig.class, AllowHttpMethodsFirewallConfig.class, BasicController.class)
this.spring
.register(CsrfAppliedDefaultConfig.class, AllowHttpMethodsFirewallConfig.class, BasicController.class)
.autowire();
this.mvc.perform(delete("/"))
.andExpect(status().isForbidden());
this.mvc.perform(delete("/")).andExpect(status().isForbidden());
}
@Test
public void invalidWhenWebSecurityEnabledThenRespondsWithForbidden() throws Exception {
this.spring.register(CsrfAppliedDefaultConfig.class, AllowHttpMethodsFirewallConfig.class, BasicController.class)
this.spring
.register(CsrfAppliedDefaultConfig.class, AllowHttpMethodsFirewallConfig.class, BasicController.class)
.autowire();
this.mvc.perform(request("INVALID", URI.create("/")))
.andExpect(status().isForbidden());
this.mvc.perform(request("INVALID", URI.create("/"))).andExpect(status().isForbidden());
}
@Test
public void getWhenWebSecurityEnabledThenRespondsWithOk() throws Exception {
this.spring.register(CsrfAppliedDefaultConfig.class, AllowHttpMethodsFirewallConfig.class, BasicController.class)
this.spring
.register(CsrfAppliedDefaultConfig.class, AllowHttpMethodsFirewallConfig.class, BasicController.class)
.autowire();
this.mvc.perform(get("/"))
.andExpect(status().isOk());
this.mvc.perform(get("/")).andExpect(status().isOk());
}
@Test
public void headWhenWebSecurityEnabledThenRespondsWithOk() throws Exception {
this.spring.register(CsrfAppliedDefaultConfig.class, AllowHttpMethodsFirewallConfig.class, BasicController.class)
this.spring
.register(CsrfAppliedDefaultConfig.class, AllowHttpMethodsFirewallConfig.class, BasicController.class)
.autowire();
this.mvc.perform(head("/"))
.andExpect(status().isOk());
this.mvc.perform(head("/")).andExpect(status().isOk());
}
@Test
public void traceWhenWebSecurityEnabledThenRespondsWithOk() throws Exception {
this.spring.register(CsrfAppliedDefaultConfig.class, AllowHttpMethodsFirewallConfig.class, BasicController.class)
this.spring
.register(CsrfAppliedDefaultConfig.class, AllowHttpMethodsFirewallConfig.class, BasicController.class)
.autowire();
this.mvc.perform(request(HttpMethod.TRACE, "/"))
.andExpect(status().isOk());
this.mvc.perform(request(HttpMethod.TRACE, "/")).andExpect(status().isOk());
}
@Test
public void optionsWhenWebSecurityEnabledThenRespondsWithOk() throws Exception {
this.spring.register(CsrfAppliedDefaultConfig.class, AllowHttpMethodsFirewallConfig.class, BasicController.class)
this.spring
.register(CsrfAppliedDefaultConfig.class, AllowHttpMethodsFirewallConfig.class, BasicController.class)
.autowire();
this.mvc.perform(options("/"))
.andExpect(status().isOk());
this.mvc.perform(options("/")).andExpect(status().isOk());
}
@Test
public void enableWebSecurityWhenDefaultConfigurationThenCreatesRequestDataValueProcessor() {
this.spring.register(CsrfAppliedDefaultConfig.class, AllowHttpMethodsFirewallConfig.class).autowire();
assertThat(this.spring.getContext().getBean(RequestDataValueProcessor.class)).isNotNull();
}
@Test
public void postWhenCsrfDisabledThenRespondsWithOk() throws Exception {
this.spring.register(DisableCsrfConfig.class, BasicController.class).autowire();
this.mvc.perform(post("/")).andExpect(status().isOk());
}
@Test
public void postWhenCsrfDisabledInLambdaThenRespondsWithOk() throws Exception {
this.spring.register(DisableCsrfInLambdaConfig.class, BasicController.class).autowire();
this.mvc.perform(post("/")).andExpect(status().isOk());
}
// SEC-2498
@Test
public void loginWhenCsrfDisabledThenRedirectsToPreviousPostRequest() throws Exception {
this.spring.register(DisableCsrfEnablesRequestCacheConfig.class).autowire();
MvcResult mvcResult = this.mvc.perform(post("/to-save")).andReturn();
this.mvc.perform(post("/login").param("username", "user").param("password", "password")
.session((MockHttpSession) mvcResult.getRequest().getSession())).andExpect(status().isFound())
.andExpect(redirectedUrl("http://localhost/to-save"));
}
@Test
public void loginWhenCsrfEnabledThenDoesNotRedirectToPreviousPostRequest() throws Exception {
CsrfDisablesPostRequestFromRequestCacheConfig.REPO = mock(CsrfTokenRepository.class);
DefaultCsrfToken csrfToken = new DefaultCsrfToken("X-CSRF-TOKEN", "_csrf", "token");
given(CsrfDisablesPostRequestFromRequestCacheConfig.REPO.loadToken(any())).willReturn(csrfToken);
given(CsrfDisablesPostRequestFromRequestCacheConfig.REPO.generateToken(any())).willReturn(csrfToken);
this.spring.register(CsrfDisablesPostRequestFromRequestCacheConfig.class).autowire();
MvcResult mvcResult = this.mvc.perform(post("/some-url")).andReturn();
this.mvc.perform(post("/login").param("username", "user").param("password", "password").with(csrf())
.session((MockHttpSession) mvcResult.getRequest().getSession())).andExpect(status().isFound())
.andExpect(redirectedUrl("/"));
verify(CsrfDisablesPostRequestFromRequestCacheConfig.REPO, atLeastOnce())
.loadToken(any(HttpServletRequest.class));
}
@Test
public void loginWhenCsrfEnabledThenRedirectsToPreviousGetRequest() throws Exception {
CsrfDisablesPostRequestFromRequestCacheConfig.REPO = mock(CsrfTokenRepository.class);
DefaultCsrfToken csrfToken = new DefaultCsrfToken("X-CSRF-TOKEN", "_csrf", "token");
given(CsrfDisablesPostRequestFromRequestCacheConfig.REPO.loadToken(any())).willReturn(csrfToken);
given(CsrfDisablesPostRequestFromRequestCacheConfig.REPO.generateToken(any())).willReturn(csrfToken);
this.spring.register(CsrfDisablesPostRequestFromRequestCacheConfig.class).autowire();
MvcResult mvcResult = this.mvc.perform(get("/some-url")).andReturn();
this.mvc.perform(post("/login").param("username", "user").param("password", "password").with(csrf())
.session((MockHttpSession) mvcResult.getRequest().getSession())).andExpect(status().isFound())
.andExpect(redirectedUrl("http://localhost/some-url"));
verify(CsrfDisablesPostRequestFromRequestCacheConfig.REPO, atLeastOnce())
.loadToken(any(HttpServletRequest.class));
}
// SEC-2422
@Test
public void postWhenCsrfEnabledAndSessionIsExpiredThenRespondsWithForbidden() throws Exception {
this.spring.register(InvalidSessionUrlConfig.class).autowire();
MvcResult mvcResult = this.mvc.perform(post("/").param("_csrf", "abc")).andExpect(status().isFound())
.andExpect(redirectedUrl("/error/sessionError")).andReturn();
this.mvc.perform(post("/").session((MockHttpSession) mvcResult.getRequest().getSession()))
.andExpect(status().isForbidden());
}
@Test
public void requireCsrfProtectionMatcherWhenRequestDoesNotMatchThenRespondsWithOk() throws Exception {
this.spring.register(RequireCsrfProtectionMatcherConfig.class, BasicController.class).autowire();
given(RequireCsrfProtectionMatcherConfig.MATCHER.matches(any())).willReturn(false);
this.mvc.perform(get("/")).andExpect(status().isOk());
}
@Test
public void requireCsrfProtectionMatcherWhenRequestMatchesThenRespondsWithForbidden() throws Exception {
RequireCsrfProtectionMatcherConfig.MATCHER = mock(RequestMatcher.class);
given(RequireCsrfProtectionMatcherConfig.MATCHER.matches(any())).willReturn(true);
this.spring.register(RequireCsrfProtectionMatcherConfig.class, BasicController.class).autowire();
this.mvc.perform(get("/")).andExpect(status().isForbidden());
}
@Test
public void requireCsrfProtectionMatcherInLambdaWhenRequestDoesNotMatchThenRespondsWithOk() throws Exception {
RequireCsrfProtectionMatcherInLambdaConfig.MATCHER = mock(RequestMatcher.class);
this.spring.register(RequireCsrfProtectionMatcherInLambdaConfig.class, BasicController.class).autowire();
given(RequireCsrfProtectionMatcherInLambdaConfig.MATCHER.matches(any())).willReturn(false);
this.mvc.perform(get("/")).andExpect(status().isOk());
}
@Test
public void requireCsrfProtectionMatcherInLambdaWhenRequestMatchesThenRespondsWithForbidden() throws Exception {
RequireCsrfProtectionMatcherInLambdaConfig.MATCHER = mock(RequestMatcher.class);
given(RequireCsrfProtectionMatcherInLambdaConfig.MATCHER.matches(any())).willReturn(true);
this.spring.register(RequireCsrfProtectionMatcherInLambdaConfig.class, BasicController.class).autowire();
this.mvc.perform(get("/")).andExpect(status().isForbidden());
}
@Test
public void getWhenCustomCsrfTokenRepositoryThenRepositoryIsUsed() throws Exception {
CsrfTokenRepositoryConfig.REPO = mock(CsrfTokenRepository.class);
given(CsrfTokenRepositoryConfig.REPO.loadToken(any()))
.willReturn(new DefaultCsrfToken("X-CSRF-TOKEN", "_csrf", "token"));
this.spring.register(CsrfTokenRepositoryConfig.class, BasicController.class).autowire();
this.mvc.perform(get("/")).andExpect(status().isOk());
verify(CsrfTokenRepositoryConfig.REPO).loadToken(any(HttpServletRequest.class));
}
@Test
public void logoutWhenCustomCsrfTokenRepositoryThenCsrfTokenIsCleared() throws Exception {
CsrfTokenRepositoryConfig.REPO = mock(CsrfTokenRepository.class);
this.spring.register(CsrfTokenRepositoryConfig.class, BasicController.class).autowire();
this.mvc.perform(post("/logout").with(csrf()).with(user("user")));
verify(CsrfTokenRepositoryConfig.REPO).saveToken(isNull(), any(HttpServletRequest.class),
any(HttpServletResponse.class));
}
@Test
public void loginWhenCustomCsrfTokenRepositoryThenCsrfTokenIsCleared() throws Exception {
CsrfTokenRepositoryConfig.REPO = mock(CsrfTokenRepository.class);
DefaultCsrfToken csrfToken = new DefaultCsrfToken("X-CSRF-TOKEN", "_csrf", "token");
given(CsrfTokenRepositoryConfig.REPO.loadToken(any())).willReturn(csrfToken);
given(CsrfTokenRepositoryConfig.REPO.generateToken(any())).willReturn(csrfToken);
this.spring.register(CsrfTokenRepositoryConfig.class, BasicController.class).autowire();
// @formatter:off
MockHttpServletRequestBuilder loginRequest = post("/login")
.with(csrf())
.param("username", "user")
.param("password", "password");
// @formatter:on
this.mvc.perform(loginRequest).andExpect(redirectedUrl("/"));
verify(CsrfTokenRepositoryConfig.REPO).saveToken(isNull(), any(HttpServletRequest.class),
any(HttpServletResponse.class));
}
@Test
public void getWhenCustomCsrfTokenRepositoryInLambdaThenRepositoryIsUsed() throws Exception {
CsrfTokenRepositoryInLambdaConfig.REPO = mock(CsrfTokenRepository.class);
given(CsrfTokenRepositoryInLambdaConfig.REPO.loadToken(any()))
.willReturn(new DefaultCsrfToken("X-CSRF-TOKEN", "_csrf", "token"));
this.spring.register(CsrfTokenRepositoryInLambdaConfig.class, BasicController.class).autowire();
this.mvc.perform(get("/")).andExpect(status().isOk());
verify(CsrfTokenRepositoryInLambdaConfig.REPO).loadToken(any(HttpServletRequest.class));
}
@Test
public void getWhenCustomAccessDeniedHandlerThenHandlerIsUsed() throws Exception {
AccessDeniedHandlerConfig.DENIED_HANDLER = mock(AccessDeniedHandler.class);
this.spring.register(AccessDeniedHandlerConfig.class, BasicController.class).autowire();
this.mvc.perform(post("/")).andExpect(status().isOk());
verify(AccessDeniedHandlerConfig.DENIED_HANDLER).handle(any(HttpServletRequest.class),
any(HttpServletResponse.class), any());
}
@Test
public void loginWhenNoCsrfTokenThenRespondsWithForbidden() throws Exception {
this.spring.register(FormLoginConfig.class).autowire();
// @formatter:off
MockHttpServletRequestBuilder loginRequest = post("/login")
.param("username", "user")
.param("password", "password");
this.mvc.perform(loginRequest)
.andExpect(status().isForbidden())
.andExpect(unauthenticated());
// @formatter:on
}
@Test
public void logoutWhenNoCsrfTokenThenRespondsWithForbidden() throws Exception {
this.spring.register(FormLoginConfig.class).autowire();
MockHttpServletRequestBuilder logoutRequest = post("/logout").with(user("username"));
// @formatter:off
this.mvc.perform(logoutRequest)
.andExpect(status().isForbidden())
.andExpect(authenticated());
// @formatter:on
}
// SEC-2543
@Test
public void logoutWhenCsrfEnabledAndGetRequestThenDoesNotLogout() throws Exception {
this.spring.register(FormLoginConfig.class).autowire();
MockHttpServletRequestBuilder logoutRequest = get("/logout").with(user("username"));
this.mvc.perform(logoutRequest).andExpect(authenticated());
}
@Test
public void logoutWhenGetRequestAndGetEnabledForLogoutThenLogsOut() throws Exception {
this.spring.register(LogoutAllowsGetConfig.class).autowire();
MockHttpServletRequestBuilder logoutRequest = get("/logout").with(user("username"));
this.mvc.perform(logoutRequest).andExpect(unauthenticated());
}
// SEC-2749
@Test
public void configureWhenRequireCsrfProtectionMatcherNullThenException() {
assertThatExceptionOfType(BeanCreationException.class)
.isThrownBy(() -> this.spring.register(NullRequireCsrfProtectionMatcherConfig.class).autowire())
.withRootCauseInstanceOf(IllegalArgumentException.class);
}
@Test
public void getWhenDefaultCsrfTokenRepositoryThenDoesNotCreateSession() throws Exception {
this.spring.register(DefaultDoesNotCreateSession.class).autowire();
MvcResult mvcResult = this.mvc.perform(get("/")).andReturn();
assertThat(mvcResult.getRequest().getSession(false)).isNull();
}
@Test
public void getWhenNullAuthenticationStrategyThenException() {
assertThatExceptionOfType(BeanCreationException.class)
.isThrownBy(() -> this.spring.register(NullAuthenticationStrategy.class).autowire())
.withRootCauseInstanceOf(IllegalArgumentException.class);
}
@Test
public void csrfAuthenticationStrategyConfiguredThenStrategyUsed() throws Exception {
CsrfAuthenticationStrategyConfig.STRATEGY = mock(SessionAuthenticationStrategy.class);
this.spring.register(CsrfAuthenticationStrategyConfig.class).autowire();
// @formatter:off
MockHttpServletRequestBuilder loginRequest = post("/login")
.with(csrf())
.param("username", "user")
.param("password", "password");
// @formatter:on
this.mvc.perform(loginRequest).andExpect(redirectedUrl("/"));
verify(CsrfAuthenticationStrategyConfig.STRATEGY, atLeastOnce()).onAuthentication(any(Authentication.class),
any(HttpServletRequest.class), any(HttpServletResponse.class));
}
@Configuration
static class AllowHttpMethodsFirewallConfig {
@Bean
StrictHttpFirewall strictHttpFirewall() {
StrictHttpFirewall result = new StrictHttpFirewall();
result.setUnsafeAllowAnyHttpMethod(true);
return result;
}
}
@EnableWebSecurity
@@ -185,14 +413,7 @@ public class CsrfConfigurerTests {
@Override
protected void configure(HttpSecurity http) {
}
}
@Test
public void postWhenCsrfDisabledThenRespondsWithOk() throws Exception {
this.spring.register(DisableCsrfConfig.class, BasicController.class).autowire();
this.mvc.perform(post("/"))
.andExpect(status().isOk());
}
@EnableWebSecurity
@@ -206,14 +427,7 @@ public class CsrfConfigurerTests {
.disable();
// @formatter:on
}
}
@Test
public void postWhenCsrfDisabledInLambdaThenRespondsWithOk() throws Exception {
this.spring.register(DisableCsrfInLambdaConfig.class, BasicController.class).autowire();
this.mvc.perform(post("/"))
.andExpect(status().isOk());
}
@EnableWebSecurity
@@ -226,21 +440,7 @@ public class CsrfConfigurerTests {
.csrf(AbstractHttpConfigurer::disable);
// @formatter:on
}
}
// SEC-2498
@Test
public void loginWhenCsrfDisabledThenRedirectsToPreviousPostRequest() throws Exception {
this.spring.register(DisableCsrfEnablesRequestCacheConfig.class).autowire();
MvcResult mvcResult = this.mvc.perform(post("/to-save")).andReturn();
this.mvc.perform(post("/login")
.param("username", "user")
.param("password", "password")
.session((MockHttpSession) mvcResult.getRequest().getSession()))
.andExpect(status().isFound())
.andExpect(redirectedUrl("http://localhost/to-save"));
}
@EnableWebSecurity
@@ -268,52 +468,12 @@ public class CsrfConfigurerTests {
.withUser(PasswordEncodedUser.user());
// @formatter:on
}
}
@Test
public void loginWhenCsrfEnabledThenDoesNotRedirectToPreviousPostRequest() throws Exception {
CsrfDisablesPostRequestFromRequestCacheConfig.REPO = mock(CsrfTokenRepository.class);
DefaultCsrfToken csrfToken = new DefaultCsrfToken("X-CSRF-TOKEN", "_csrf", "token");
when(CsrfDisablesPostRequestFromRequestCacheConfig.REPO.loadToken(any())).thenReturn(csrfToken);
when(CsrfDisablesPostRequestFromRequestCacheConfig.REPO.generateToken(any())).thenReturn(csrfToken);
this.spring.register(CsrfDisablesPostRequestFromRequestCacheConfig.class).autowire();
MvcResult mvcResult = this.mvc.perform(post("/some-url"))
.andReturn();
this.mvc.perform(post("/login")
.param("username", "user")
.param("password", "password")
.with(csrf())
.session((MockHttpSession) mvcResult.getRequest().getSession()))
.andExpect(status().isFound())
.andExpect(redirectedUrl("/"));
verify(CsrfDisablesPostRequestFromRequestCacheConfig.REPO, atLeastOnce()).loadToken(any(HttpServletRequest.class));
}
@Test
public void loginWhenCsrfEnabledThenRedirectsToPreviousGetRequest() throws Exception {
CsrfDisablesPostRequestFromRequestCacheConfig.REPO = mock(CsrfTokenRepository.class);
DefaultCsrfToken csrfToken = new DefaultCsrfToken("X-CSRF-TOKEN", "_csrf", "token");
when(CsrfDisablesPostRequestFromRequestCacheConfig.REPO.loadToken(any())).thenReturn(csrfToken);
when(CsrfDisablesPostRequestFromRequestCacheConfig.REPO.generateToken(any())).thenReturn(csrfToken);
this.spring.register(CsrfDisablesPostRequestFromRequestCacheConfig.class).autowire();
MvcResult mvcResult = this.mvc.perform(get("/some-url"))
.andReturn();
this.mvc.perform(post("/login")
.param("username", "user")
.param("password", "password")
.with(csrf())
.session((MockHttpSession) mvcResult.getRequest().getSession()))
.andExpect(status().isFound())
.andExpect(redirectedUrl("http://localhost/some-url"));
verify(CsrfDisablesPostRequestFromRequestCacheConfig.REPO, atLeastOnce()).loadToken(any(HttpServletRequest.class));
}
@EnableWebSecurity
static class CsrfDisablesPostRequestFromRequestCacheConfig extends WebSecurityConfigurerAdapter {
static CsrfTokenRepository REPO;
@Override
@@ -338,26 +498,12 @@ public class CsrfConfigurerTests {
.withUser(PasswordEncodedUser.user());
// @formatter:on
}
}
// SEC-2422
@Test
public void postWhenCsrfEnabledAndSessionIsExpiredThenRespondsWithForbidden() throws Exception {
this.spring.register(InvalidSessionUrlConfig.class).autowire();
MvcResult mvcResult = this.mvc.perform(post("/")
.param("_csrf", "abc"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("/error/sessionError"))
.andReturn();
this.mvc.perform(post("/")
.session((MockHttpSession) mvcResult.getRequest().getSession()))
.andExpect(status().isForbidden());
}
@EnableWebSecurity
static class InvalidSessionUrlConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
@@ -368,30 +514,12 @@ public class CsrfConfigurerTests {
.invalidSessionUrl("/error/sessionError");
// @formatter:on
}
}
@Test
public void requireCsrfProtectionMatcherWhenRequestDoesNotMatchThenRespondsWithOk() throws Exception {
this.spring.register(RequireCsrfProtectionMatcherConfig.class, BasicController.class).autowire();
when(RequireCsrfProtectionMatcherConfig.MATCHER.matches(any()))
.thenReturn(false);
this.mvc.perform(get("/"))
.andExpect(status().isOk());
}
@Test
public void requireCsrfProtectionMatcherWhenRequestMatchesThenRespondsWithForbidden() throws Exception {
RequireCsrfProtectionMatcherConfig.MATCHER = mock(RequestMatcher.class);
when(RequireCsrfProtectionMatcherConfig.MATCHER.matches(any())).thenReturn(true);
this.spring.register(RequireCsrfProtectionMatcherConfig.class, BasicController.class).autowire();
this.mvc.perform(get("/"))
.andExpect(status().isForbidden());
}
@EnableWebSecurity
static class RequireCsrfProtectionMatcherConfig extends WebSecurityConfigurerAdapter {
static RequestMatcher MATCHER;
@Override
@@ -402,87 +530,27 @@ public class CsrfConfigurerTests {
.requireCsrfProtectionMatcher(MATCHER);
// @formatter:on
}
}
@Test
public void requireCsrfProtectionMatcherInLambdaWhenRequestDoesNotMatchThenRespondsWithOk() throws Exception {
RequireCsrfProtectionMatcherInLambdaConfig.MATCHER = mock(RequestMatcher.class);
this.spring.register(RequireCsrfProtectionMatcherInLambdaConfig.class, BasicController.class).autowire();
when(RequireCsrfProtectionMatcherInLambdaConfig.MATCHER.matches(any()))
.thenReturn(false);
this.mvc.perform(get("/"))
.andExpect(status().isOk());
}
@Test
public void requireCsrfProtectionMatcherInLambdaWhenRequestMatchesThenRespondsWithForbidden() throws Exception {
RequireCsrfProtectionMatcherInLambdaConfig.MATCHER = mock(RequestMatcher.class);
when(RequireCsrfProtectionMatcherInLambdaConfig.MATCHER.matches(any())).thenReturn(true);
this.spring.register(RequireCsrfProtectionMatcherInLambdaConfig.class, BasicController.class).autowire();
this.mvc.perform(get("/"))
.andExpect(status().isForbidden());
}
@EnableWebSecurity
static class RequireCsrfProtectionMatcherInLambdaConfig extends WebSecurityConfigurerAdapter {
static RequestMatcher MATCHER;
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.csrf(csrf -> csrf.requireCsrfProtectionMatcher(MATCHER));
.csrf((csrf) -> csrf.requireCsrfProtectionMatcher(MATCHER));
// @formatter:on
}
}
@Test
public void getWhenCustomCsrfTokenRepositoryThenRepositoryIsUsed() throws Exception {
CsrfTokenRepositoryConfig.REPO = mock(CsrfTokenRepository.class);
when(CsrfTokenRepositoryConfig.REPO.loadToken(any()))
.thenReturn(new DefaultCsrfToken("X-CSRF-TOKEN", "_csrf", "token"));
this.spring.register(CsrfTokenRepositoryConfig.class, BasicController.class).autowire();
this.mvc.perform(get("/"))
.andExpect(status().isOk());
verify(CsrfTokenRepositoryConfig.REPO).loadToken(any(HttpServletRequest.class));
}
@Test
public void logoutWhenCustomCsrfTokenRepositoryThenCsrfTokenIsCleared() throws Exception {
CsrfTokenRepositoryConfig.REPO = mock(CsrfTokenRepository.class);
this.spring.register(CsrfTokenRepositoryConfig.class, BasicController.class).autowire();
this.mvc.perform(post("/logout")
.with(csrf())
.with(user("user")));
verify(CsrfTokenRepositoryConfig.REPO)
.saveToken(isNull(), any(HttpServletRequest.class), any(HttpServletResponse.class));
}
@Test
public void loginWhenCustomCsrfTokenRepositoryThenCsrfTokenIsCleared() throws Exception {
CsrfTokenRepositoryConfig.REPO = mock(CsrfTokenRepository.class);
DefaultCsrfToken csrfToken = new DefaultCsrfToken("X-CSRF-TOKEN", "_csrf", "token");
when(CsrfTokenRepositoryConfig.REPO.loadToken(any())).thenReturn(csrfToken);
when(CsrfTokenRepositoryConfig.REPO.generateToken(any())).thenReturn(csrfToken);
this.spring.register(CsrfTokenRepositoryConfig.class, BasicController.class).autowire();
this.mvc.perform(post("/login")
.with(csrf())
.param("username", "user")
.param("password", "password"))
.andExpect(redirectedUrl("/"));
verify(CsrfTokenRepositoryConfig.REPO)
.saveToken(isNull(), any(HttpServletRequest.class), any(HttpServletResponse.class));
}
@EnableWebSecurity
static class CsrfTokenRepositoryConfig extends WebSecurityConfigurerAdapter {
static CsrfTokenRepository REPO;
@Override
@@ -504,22 +572,12 @@ public class CsrfConfigurerTests {
.withUser(PasswordEncodedUser.user());
// @formatter:on
}
}
@Test
public void getWhenCustomCsrfTokenRepositoryInLambdaThenRepositoryIsUsed() throws Exception {
CsrfTokenRepositoryInLambdaConfig.REPO = mock(CsrfTokenRepository.class);
when(CsrfTokenRepositoryInLambdaConfig.REPO.loadToken(any()))
.thenReturn(new DefaultCsrfToken("X-CSRF-TOKEN", "_csrf", "token"));
this.spring.register(CsrfTokenRepositoryInLambdaConfig.class, BasicController.class).autowire();
this.mvc.perform(get("/"))
.andExpect(status().isOk());
verify(CsrfTokenRepositoryInLambdaConfig.REPO).loadToken(any(HttpServletRequest.class));
}
@EnableWebSecurity
static class CsrfTokenRepositoryInLambdaConfig extends WebSecurityConfigurerAdapter {
static CsrfTokenRepository REPO;
@Override
@@ -527,25 +585,15 @@ public class CsrfConfigurerTests {
// @formatter:off
http
.formLogin(withDefaults())
.csrf(csrf -> csrf.csrfTokenRepository(REPO));
.csrf((csrf) -> csrf.csrfTokenRepository(REPO));
// @formatter:on
}
}
@Test
public void getWhenCustomAccessDeniedHandlerThenHandlerIsUsed() throws Exception {
AccessDeniedHandlerConfig.DENIED_HANDLER = mock(AccessDeniedHandler.class);
this.spring.register(AccessDeniedHandlerConfig.class, BasicController.class).autowire();
this.mvc.perform(post("/"))
.andExpect(status().isOk());
verify(AccessDeniedHandlerConfig.DENIED_HANDLER)
.handle(any(HttpServletRequest.class), any(HttpServletResponse.class), any());
}
@EnableWebSecurity
static class AccessDeniedHandlerConfig extends WebSecurityConfigurerAdapter {
static AccessDeniedHandler DENIED_HANDLER;
@Override
@@ -556,37 +604,7 @@ public class CsrfConfigurerTests {
.accessDeniedHandler(DENIED_HANDLER);
// @formatter:on
}
}
@Test
public void loginWhenNoCsrfTokenThenRespondsWithForbidden() throws Exception {
this.spring.register(FormLoginConfig.class).autowire();
this.mvc.perform(post("/login")
.param("username", "user")
.param("password", "password"))
.andExpect(status().isForbidden())
.andExpect(unauthenticated());
}
@Test
public void logoutWhenNoCsrfTokenThenRespondsWithForbidden() throws Exception {
this.spring.register(FormLoginConfig.class).autowire();
this.mvc.perform(post("/logout")
.with(user("username")))
.andExpect(status().isForbidden())
.andExpect(authenticated());
}
// SEC-2543
@Test
public void logoutWhenCsrfEnabledAndGetRequestThenDoesNotLogout() throws Exception {
this.spring.register(FormLoginConfig.class).autowire();
this.mvc.perform(get("/logout")
.with(user("username")))
.andExpect(authenticated());
}
@EnableWebSecurity
@@ -599,15 +617,7 @@ public class CsrfConfigurerTests {
.formLogin();
// @formatter:on
}
}
@Test
public void logoutWhenGetRequestAndGetEnabledForLogoutThenLogsOut() throws Exception {
this.spring.register(LogoutAllowsGetConfig.class).autowire();
this.mvc.perform(get("/logout")
.with(user("username")))
.andExpect(unauthenticated());
}
@EnableWebSecurity
@@ -623,18 +633,12 @@ public class CsrfConfigurerTests {
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"));
// @formatter:on
}
}
// SEC-2749
@Test
public void configureWhenRequireCsrfProtectionMatcherNullThenException() {
assertThatThrownBy(() -> this.spring.register(NullRequireCsrfProtectionMatcherConfig.class).autowire())
.isInstanceOf(BeanCreationException.class)
.hasRootCauseInstanceOf(IllegalArgumentException.class);
}
@EnableWebSecurity
static class NullRequireCsrfProtectionMatcherConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
@@ -643,16 +647,7 @@ public class CsrfConfigurerTests {
.requireCsrfProtectionMatcher(null);
// @formatter:on
}
}
@Test
public void getWhenDefaultCsrfTokenRepositoryThenDoesNotCreateSession() throws Exception {
this.spring.register(DefaultDoesNotCreateSession.class).autowire();
MvcResult mvcResult = this.mvc.perform(get("/"))
.andReturn();
assertThat(mvcResult.getRequest().getSession(false)).isNull();
}
@EnableWebSecurity
@@ -679,10 +674,12 @@ public class CsrfConfigurerTests {
.withUser(PasswordEncodedUser.user());
// @formatter:on
}
}
@EnableWebSecurity
static class NullAuthenticationStrategy extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
@@ -691,17 +688,12 @@ public class CsrfConfigurerTests {
.sessionAuthenticationStrategy(null);
// @formatter:on
}
}
@Test
public void getWhenNullAuthenticationStrategyThenException() {
assertThatThrownBy(() -> this.spring.register(NullAuthenticationStrategy.class).autowire())
.isInstanceOf(BeanCreationException.class)
.hasRootCauseInstanceOf(IllegalArgumentException.class);
}
@EnableWebSecurity
static class CsrfAuthenticationStrategyConfig extends WebSecurityConfigurerAdapter {
static SessionAuthenticationStrategy STRATEGY;
@Override
@@ -723,32 +715,20 @@ public class CsrfConfigurerTests {
.withUser(PasswordEncodedUser.user());
// @formatter:on
}
}
@Test
public void csrfAuthenticationStrategyConfiguredThenStrategyUsed() throws Exception {
CsrfAuthenticationStrategyConfig.STRATEGY = mock(SessionAuthenticationStrategy.class);
this.spring.register(CsrfAuthenticationStrategyConfig.class).autowire();
this.mvc.perform(post("/login")
.with(csrf())
.param("username", "user")
.param("password", "password"))
.andExpect(redirectedUrl("/"));
verify(CsrfAuthenticationStrategyConfig.STRATEGY, atLeastOnce())
.onAuthentication(any(Authentication.class), any(HttpServletRequest.class), any(HttpServletResponse.class));
}
@RestController
static class BasicController {
@GetMapping("/")
public void rootGet() {
void rootGet() {
}
@PostMapping("/")
public void rootPost() {
void rootPost() {
}
}
}

View File

@@ -13,11 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.configurers;
import java.io.IOException;
import java.util.List;
import java.util.stream.Collectors;
import javax.servlet.Filter;
import javax.servlet.ServletException;
@@ -76,61 +78,30 @@ public class DefaultFiltersTests {
assertThat(this.spring.getContext().getBean(FilterChainProxy.class)).isNotNull();
}
@EnableWebSecurity
static class FilterChainProxyBuilderMissingConfig {
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
// @formatter:off
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER");
// @formatter:on
}
}
@Test
public void nullWebInvocationPrivilegeEvaluator() {
this.spring.register(NullWebInvocationPrivilegeEvaluatorConfig.class, UserDetailsServiceConfig.class);
List<SecurityFilterChain> filterChains = this.spring.getContext().getBean(FilterChainProxy.class).getFilterChains();
List<SecurityFilterChain> filterChains = this.spring.getContext().getBean(FilterChainProxy.class)
.getFilterChains();
assertThat(filterChains.size()).isEqualTo(1);
DefaultSecurityFilterChain filterChain = (DefaultSecurityFilterChain) filterChains.get(0);
assertThat(filterChain.getRequestMatcher()).isInstanceOf(AnyRequestMatcher.class);
assertThat(filterChain.getFilters().size()).isEqualTo(1);
long filter = filterChain.getFilters().stream()
.filter(it -> it instanceof UsernamePasswordAuthenticationFilter).count();
.filter((it) -> it instanceof UsernamePasswordAuthenticationFilter).count();
assertThat(filter).isEqualTo(1);
}
@Configuration
static class UserDetailsServiceConfig {
@Bean
public UserDetailsService userDetailsService() {
return new InMemoryUserDetailsManager(PasswordEncodedUser.user(), PasswordEncodedUser.admin());
}
}
@EnableWebSecurity
static class NullWebInvocationPrivilegeEvaluatorConfig extends WebSecurityConfigurerAdapter {
NullWebInvocationPrivilegeEvaluatorConfig() {
super(true);
}
protected void configure(HttpSecurity http) throws Exception {
http.formLogin();
}
}
@Test
public void filterChainProxyBuilderIgnoringResources() {
this.spring.register(FilterChainProxyBuilderIgnoringConfig.class, UserDetailsServiceConfig.class);
List<SecurityFilterChain> filterChains = this.spring.getContext().getBean(FilterChainProxy.class).getFilterChains();
List<SecurityFilterChain> filterChains = this.spring.getContext().getBean(FilterChainProxy.class)
.getFilterChains();
assertThat(filterChains.size()).isEqualTo(2);
DefaultSecurityFilterChain firstFilter = (DefaultSecurityFilterChain) filterChains.get(0);
DefaultSecurityFilterChain secondFilter = (DefaultSecurityFilterChain) filterChains.get(1);
assertThat(firstFilter.getFilters().isEmpty()).isEqualTo(true);
assertThat(secondFilter.getRequestMatcher()).isInstanceOf(AnyRequestMatcher.class);
List<? extends Class<? extends Filter>> classes = secondFilter.getFilters().stream().map(Filter::getClass)
.collect(Collectors.toList());
assertThat(classes.contains(WebAsyncManagerIntegrationFilter.class)).isTrue();
@@ -146,8 +117,61 @@ public class DefaultFiltersTests {
assertThat(classes.contains(FilterSecurityInterceptor.class)).isTrue();
}
@Test
public void defaultFiltersPermitAll() throws IOException, ServletException {
this.spring.register(DefaultFiltersConfigPermitAll.class, UserDetailsServiceConfig.class);
MockHttpServletResponse response = new MockHttpServletResponse();
MockHttpServletRequest request = new MockHttpServletRequest("POST", "");
request.setServletPath("/logout");
CsrfToken csrfToken = new DefaultCsrfToken("X-CSRF-TOKEN", "_csrf", "BaseSpringSpec_CSRFTOKEN");
new HttpSessionCsrfTokenRepository().saveToken(csrfToken, request, response);
request.setParameter(csrfToken.getParameterName(), csrfToken.getToken());
this.spring.getContext().getBean("springSecurityFilterChain", Filter.class).doFilter(request, response,
new MockFilterChain());
assertThat(response.getRedirectedUrl()).isEqualTo("/login?logout");
}
@EnableWebSecurity
static class FilterChainProxyBuilderMissingConfig {
@Autowired
void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
// @formatter:off
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER");
// @formatter:on
}
}
@Configuration
static class UserDetailsServiceConfig {
@Bean
UserDetailsService userDetailsService() {
return new InMemoryUserDetailsManager(PasswordEncodedUser.user(), PasswordEncodedUser.admin());
}
}
@EnableWebSecurity
static class NullWebInvocationPrivilegeEvaluatorConfig extends WebSecurityConfigurerAdapter {
NullWebInvocationPrivilegeEvaluatorConfig() {
super(true);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin();
}
}
@EnableWebSecurity
static class FilterChainProxyBuilderIgnoringConfig extends WebSecurityConfigurerAdapter {
@Override
public void configure(WebSecurity web) {
// @formatter:off
@@ -165,27 +189,16 @@ public class DefaultFiltersTests {
.anyRequest().hasRole("USER");
// @formatter:on
}
}
@Test
public void defaultFiltersPermitAll() throws IOException, ServletException {
this.spring.register(DefaultFiltersConfigPermitAll.class, UserDetailsServiceConfig.class);
MockHttpServletResponse response = new MockHttpServletResponse();
MockHttpServletRequest request = new MockHttpServletRequest("POST", "");
request.setServletPath("/logout");
CsrfToken csrfToken = new DefaultCsrfToken("X-CSRF-TOKEN", "_csrf", "BaseSpringSpec_CSRFTOKEN");
new HttpSessionCsrfTokenRepository().saveToken(csrfToken, request, response);
request.setParameter(csrfToken.getParameterName(), csrfToken.getToken());
this.spring.getContext().getBean("springSecurityFilterChain", Filter.class).doFilter(request, response,
new MockFilterChain());
assertThat(response.getRedirectedUrl()).isEqualTo("/login?logout");
}
@EnableWebSecurity
static class DefaultFiltersConfigPermitAll extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) {
}
}
}

View File

@@ -18,6 +18,7 @@ package org.springframework.security.config.annotation.web.configurers;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.mock.web.MockHttpSession;
@@ -39,6 +40,7 @@ import org.springframework.security.web.csrf.DefaultCsrfToken;
import org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
@@ -67,9 +69,7 @@ public class DefaultLoginPageConfigurerTests {
@Test
public void getWhenFormLoginEnabledThenRedirectsToLoginPage() throws Exception {
this.spring.register(DefaultLoginPageConfig.class).autowire();
this.mvc.perform(get("/"))
.andExpect(redirectedUrl("http://localhost/login"));
this.mvc.perform(get("/")).andExpect(redirectedUrl("http://localhost/login"));
}
@Test
@@ -77,48 +77,43 @@ public class DefaultLoginPageConfigurerTests {
this.spring.register(DefaultLoginPageConfig.class).autowire();
CsrfToken csrfToken = new DefaultCsrfToken("X-CSRF-TOKEN", "_csrf", "BaseSpringSpec_CSRFTOKEN");
String csrfAttributeName = HttpSessionCsrfTokenRepository.class.getName().concat(".CSRF_TOKEN");
this.mvc.perform(get("/login")
.sessionAttr(csrfAttributeName, csrfToken))
.andExpect(content().string(
"<!DOCTYPE html>\n" +
"<html lang=\"en\">\n" +
" <head>\n" +
" <meta charset=\"utf-8\">\n" +
" <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\">\n" +
" <meta name=\"description\" content=\"\">\n" +
" <meta name=\"author\" content=\"\">\n" +
" <title>Please sign in</title>\n" +
" <link href=\"https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css\" rel=\"stylesheet\" integrity=\"sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M\" crossorigin=\"anonymous\">\n" +
" <link href=\"https://getbootstrap.com/docs/4.0/examples/signin/signin.css\" rel=\"stylesheet\" crossorigin=\"anonymous\"/>\n" +
" </head>\n" +
" <body>\n" +
" <div class=\"container\">\n" +
" <form class=\"form-signin\" method=\"post\" action=\"/login\">\n" +
" <h2 class=\"form-signin-heading\">Please sign in</h2>\n" +
" <p>\n" +
" <label for=\"username\" class=\"sr-only\">Username</label>\n" +
" <input type=\"text\" id=\"username\" name=\"username\" class=\"form-control\" placeholder=\"Username\" required autofocus>\n" +
" </p>\n" +
" <p>\n" +
" <label for=\"password\" class=\"sr-only\">Password</label>\n" +
" <input type=\"password\" id=\"password\" name=\"password\" class=\"form-control\" placeholder=\"Password\" required>\n" +
" </p>\n" +
"<input name=\"" + csrfToken.getParameterName() + "\" type=\"hidden\" value=\"" + csrfToken.getToken() + "\" />\n" +
" <button class=\"btn btn-lg btn-primary btn-block\" type=\"submit\">Sign in</button>\n" +
" </form>\n" +
"</div>\n" +
"</body></html>"
));
// @formatter:off
this.mvc.perform(get("/login").sessionAttr(csrfAttributeName, csrfToken))
.andExpect(content().string("<!DOCTYPE html>\n"
+ "<html lang=\"en\">\n"
+ " <head>\n"
+ " <meta charset=\"utf-8\">\n"
+ " <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\">\n"
+ " <meta name=\"description\" content=\"\">\n"
+ " <meta name=\"author\" content=\"\">\n"
+ " <title>Please sign in</title>\n"
+ " <link href=\"https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css\" rel=\"stylesheet\" integrity=\"sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M\" crossorigin=\"anonymous\">\n"
+ " <link href=\"https://getbootstrap.com/docs/4.0/examples/signin/signin.css\" rel=\"stylesheet\" crossorigin=\"anonymous\"/>\n"
+ " </head>\n"
+ " <body>\n"
+ " <div class=\"container\">\n"
+ " <form class=\"form-signin\" method=\"post\" action=\"/login\">\n"
+ " <h2 class=\"form-signin-heading\">Please sign in</h2>\n"
+ " <p>\n"
+ " <label for=\"username\" class=\"sr-only\">Username</label>\n"
+ " <input type=\"text\" id=\"username\" name=\"username\" class=\"form-control\" placeholder=\"Username\" required autofocus>\n"
+ " </p>\n"
+ " <p>\n"
+ " <label for=\"password\" class=\"sr-only\">Password</label>\n"
+ " <input type=\"password\" id=\"password\" name=\"password\" class=\"form-control\" placeholder=\"Password\" required>\n"
+ " </p>\n"
+ "<input name=\"" + csrfToken.getParameterName() + "\" type=\"hidden\" value=\"" + csrfToken.getToken() + "\" />\n"
+ " <button class=\"btn btn-lg btn-primary btn-block\" type=\"submit\">Sign in</button>\n"
+ " </form>\n"
+ "</div>\n"
+ "</body></html>"));
// @formatter:on
}
@Test
public void loginWhenNoCredentialsThenRedirectedToLoginPageWithError() throws Exception {
this.spring.register(DefaultLoginPageConfig.class).autowire();
this.mvc.perform(post("/login")
.with(csrf()))
.andExpect(redirectedUrl("/login?error"));
this.mvc.perform(post("/login").with(csrf())).andExpect(redirectedUrl("/login?error"));
}
@Test
@@ -126,55 +121,50 @@ public class DefaultLoginPageConfigurerTests {
this.spring.register(DefaultLoginPageConfig.class).autowire();
CsrfToken csrfToken = new DefaultCsrfToken("X-CSRF-TOKEN", "_csrf", "BaseSpringSpec_CSRFTOKEN");
String csrfAttributeName = HttpSessionCsrfTokenRepository.class.getName().concat(".CSRF_TOKEN");
MvcResult mvcResult = this.mvc.perform(post("/login")
.with(csrf()))
.andReturn();
this.mvc.perform(get("/login?error")
.session((MockHttpSession) mvcResult.getRequest().getSession())
MvcResult mvcResult = this.mvc.perform(post("/login").with(csrf())).andReturn();
// @formatter:off
this.mvc.perform(get("/login?error").session((MockHttpSession) mvcResult.getRequest().getSession())
.sessionAttr(csrfAttributeName, csrfToken))
.andExpect(content().string(
"<!DOCTYPE html>\n" +
"<html lang=\"en\">\n" +
" <head>\n" +
" <meta charset=\"utf-8\">\n" +
" <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\">\n" +
" <meta name=\"description\" content=\"\">\n" +
" <meta name=\"author\" content=\"\">\n" +
" <title>Please sign in</title>\n" +
" <link href=\"https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css\" rel=\"stylesheet\" integrity=\"sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M\" crossorigin=\"anonymous\">\n" +
" <link href=\"https://getbootstrap.com/docs/4.0/examples/signin/signin.css\" rel=\"stylesheet\" crossorigin=\"anonymous\"/>\n" +
" </head>\n" +
" <body>\n" +
" <div class=\"container\">\n" +
" <form class=\"form-signin\" method=\"post\" action=\"/login\">\n" +
" <h2 class=\"form-signin-heading\">Please sign in</h2>\n" +
"<div class=\"alert alert-danger\" role=\"alert\">Bad credentials</div> <p>\n" +
" <label for=\"username\" class=\"sr-only\">Username</label>\n" +
" <input type=\"text\" id=\"username\" name=\"username\" class=\"form-control\" placeholder=\"Username\" required autofocus>\n" +
" </p>\n" +
" <p>\n" +
" <label for=\"password\" class=\"sr-only\">Password</label>\n" +
" <input type=\"password\" id=\"password\" name=\"password\" class=\"form-control\" placeholder=\"Password\" required>\n" +
" </p>\n" +
"<input name=\"" + csrfToken.getParameterName() + "\" type=\"hidden\" value=\"" + csrfToken.getToken() + "\" />\n" +
" <button class=\"btn btn-lg btn-primary btn-block\" type=\"submit\">Sign in</button>\n" +
" </form>\n" +
"</div>\n" +
"</body></html>"
));
.andExpect(content().string("<!DOCTYPE html>\n"
+ "<html lang=\"en\">\n"
+ " <head>\n"
+ " <meta charset=\"utf-8\">\n"
+ " <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\">\n"
+ " <meta name=\"description\" content=\"\">\n"
+ " <meta name=\"author\" content=\"\">\n"
+ " <title>Please sign in</title>\n"
+ " <link href=\"https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css\" rel=\"stylesheet\" integrity=\"sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M\" crossorigin=\"anonymous\">\n"
+ " <link href=\"https://getbootstrap.com/docs/4.0/examples/signin/signin.css\" rel=\"stylesheet\" crossorigin=\"anonymous\"/>\n"
+ " </head>\n"
+ " <body>\n"
+ " <div class=\"container\">\n"
+ " <form class=\"form-signin\" method=\"post\" action=\"/login\">\n"
+ " <h2 class=\"form-signin-heading\">Please sign in</h2>\n"
+ "<div class=\"alert alert-danger\" role=\"alert\">Bad credentials</div> <p>\n"
+ " <label for=\"username\" class=\"sr-only\">Username</label>\n"
+ " <input type=\"text\" id=\"username\" name=\"username\" class=\"form-control\" placeholder=\"Username\" required autofocus>\n"
+ " </p>\n" + " <p>\n"
+ " <label for=\"password\" class=\"sr-only\">Password</label>\n"
+ " <input type=\"password\" id=\"password\" name=\"password\" class=\"form-control\" placeholder=\"Password\" required>\n"
+ " </p>\n"
+ "<input name=\"" + csrfToken.getParameterName() + "\" type=\"hidden\" value=\"" + csrfToken.getToken() + "\" />\n"
+ " <button class=\"btn btn-lg btn-primary btn-block\" type=\"submit\">Sign in</button>\n"
+ " </form>\n"
+ "</div>\n"
+ "</body></html>"));
// @formatter:on
}
@Test
public void loginWhenValidCredentialsThenRedirectsToDefaultSuccessPage() throws Exception {
this.spring.register(DefaultLoginPageConfig.class).autowire();
this.mvc.perform(post("/login")
// @formatter:off
MockHttpServletRequestBuilder loginRequest = post("/login")
.with(csrf())
.param("username", "user")
.param("password", "password"))
.andExpect(redirectedUrl("/"));
.param("password", "password");
// @formatter:on
this.mvc.perform(loginRequest).andExpect(redirectedUrl("/"));
}
@Test
@@ -182,43 +172,212 @@ public class DefaultLoginPageConfigurerTests {
this.spring.register(DefaultLoginPageConfig.class).autowire();
CsrfToken csrfToken = new DefaultCsrfToken("X-CSRF-TOKEN", "_csrf", "BaseSpringSpec_CSRFTOKEN");
String csrfAttributeName = HttpSessionCsrfTokenRepository.class.getName().concat(".CSRF_TOKEN");
// @formatter:off
this.mvc.perform(get("/login?logout").sessionAttr(csrfAttributeName, csrfToken))
.andExpect(content().string("<!DOCTYPE html>\n"
+ "<html lang=\"en\">\n"
+ " <head>\n"
+ " <meta charset=\"utf-8\">\n"
+ " <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\">\n"
+ " <meta name=\"description\" content=\"\">\n"
+ " <meta name=\"author\" content=\"\">\n"
+ " <title>Please sign in</title>\n"
+ " <link href=\"https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css\" rel=\"stylesheet\" integrity=\"sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M\" crossorigin=\"anonymous\">\n"
+ " <link href=\"https://getbootstrap.com/docs/4.0/examples/signin/signin.css\" rel=\"stylesheet\" crossorigin=\"anonymous\"/>\n"
+ " </head>\n"
+ " <body>\n"
+ " <div class=\"container\">\n"
+ " <form class=\"form-signin\" method=\"post\" action=\"/login\">\n"
+ " <h2 class=\"form-signin-heading\">Please sign in</h2>\n"
+ "<div class=\"alert alert-success\" role=\"alert\">You have been signed out</div> <p>\n"
+ " <label for=\"username\" class=\"sr-only\">Username</label>\n"
+ " <input type=\"text\" id=\"username\" name=\"username\" class=\"form-control\" placeholder=\"Username\" required autofocus>\n"
+ " </p>\n"
+ " <p>\n"
+ " <label for=\"password\" class=\"sr-only\">Password</label>\n"
+ " <input type=\"password\" id=\"password\" name=\"password\" class=\"form-control\" placeholder=\"Password\" required>\n"
+ " </p>\n"
+ "<input name=\"" + csrfToken.getParameterName() + "\" type=\"hidden\" value=\"" + csrfToken.getToken() + "\" />\n"
+ " <button class=\"btn btn-lg btn-primary btn-block\" type=\"submit\">Sign in</button>\n"
+ " </form>\n"
+ "</div>\n"
+ "</body></html>"));
// @formatter:on
}
this.mvc.perform(get("/login?logout")
.sessionAttr(csrfAttributeName, csrfToken))
.andExpect(content().string(
"<!DOCTYPE html>\n" +
"<html lang=\"en\">\n" +
" <head>\n" +
" <meta charset=\"utf-8\">\n" +
" <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\">\n" +
" <meta name=\"description\" content=\"\">\n" +
" <meta name=\"author\" content=\"\">\n" +
" <title>Please sign in</title>\n" +
" <link href=\"https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css\" rel=\"stylesheet\" integrity=\"sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M\" crossorigin=\"anonymous\">\n" +
" <link href=\"https://getbootstrap.com/docs/4.0/examples/signin/signin.css\" rel=\"stylesheet\" crossorigin=\"anonymous\"/>\n" +
" </head>\n" +
" <body>\n" +
" <div class=\"container\">\n" +
" <form class=\"form-signin\" method=\"post\" action=\"/login\">\n" +
" <h2 class=\"form-signin-heading\">Please sign in</h2>\n" +
"<div class=\"alert alert-success\" role=\"alert\">You have been signed out</div> <p>\n" +
" <label for=\"username\" class=\"sr-only\">Username</label>\n" +
" <input type=\"text\" id=\"username\" name=\"username\" class=\"form-control\" placeholder=\"Username\" required autofocus>\n" +
" </p>\n" +
" <p>\n" +
" <label for=\"password\" class=\"sr-only\">Password</label>\n" +
" <input type=\"password\" id=\"password\" name=\"password\" class=\"form-control\" placeholder=\"Password\" required>\n" +
" </p>\n" +
"<input name=\"" + csrfToken.getParameterName() + "\" type=\"hidden\" value=\"" + csrfToken.getToken() + "\" />\n" +
" <button class=\"btn btn-lg btn-primary btn-block\" type=\"submit\">Sign in</button>\n" +
" </form>\n" +
"</div>\n" +
"</body></html>"
));
@Test
public void loginPageWhenLoggedOutAndCustomLogoutSuccessHandlerThenDoesNotRenderLoginPage() throws Exception {
this.spring.register(DefaultLoginPageCustomLogoutSuccessHandlerConfig.class).autowire();
this.mvc.perform(get("/login?logout")).andExpect(content().string(""));
}
@Test
public void loginPageWhenLoggedOutAndCustomLogoutSuccessUrlThenDoesNotRenderLoginPage() throws Exception {
this.spring.register(DefaultLoginPageCustomLogoutSuccessUrlConfig.class).autowire();
this.mvc.perform(get("/login?logout")).andExpect(content().string(""));
}
@Test
public void loginPageWhenRememberConfigureThenDefaultLoginPageWithRememberMeCheckbox() throws Exception {
this.spring.register(DefaultLoginPageWithRememberMeConfig.class).autowire();
CsrfToken csrfToken = new DefaultCsrfToken("X-CSRF-TOKEN", "_csrf", "BaseSpringSpec_CSRFTOKEN");
String csrfAttributeName = HttpSessionCsrfTokenRepository.class.getName().concat(".CSRF_TOKEN");
// @formatter:off
this.mvc.perform(get("/login").sessionAttr(csrfAttributeName, csrfToken))
.andExpect(content().string("<!DOCTYPE html>\n"
+ "<html lang=\"en\">\n"
+ " <head>\n"
+ " <meta charset=\"utf-8\">\n"
+ " <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\">\n"
+ " <meta name=\"description\" content=\"\">\n"
+ " <meta name=\"author\" content=\"\">\n"
+ " <title>Please sign in</title>\n"
+ " <link href=\"https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css\" rel=\"stylesheet\" integrity=\"sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M\" crossorigin=\"anonymous\">\n"
+ " <link href=\"https://getbootstrap.com/docs/4.0/examples/signin/signin.css\" rel=\"stylesheet\" crossorigin=\"anonymous\"/>\n"
+ " </head>\n"
+ " <body>\n"
+ " <div class=\"container\">\n"
+ " <form class=\"form-signin\" method=\"post\" action=\"/login\">\n"
+ " <h2 class=\"form-signin-heading\">Please sign in</h2>\n"
+ " <p>\n"
+ " <label for=\"username\" class=\"sr-only\">Username</label>\n"
+ " <input type=\"text\" id=\"username\" name=\"username\" class=\"form-control\" placeholder=\"Username\" required autofocus>\n"
+ " </p>\n"
+ " <p>\n"
+ " <label for=\"password\" class=\"sr-only\">Password</label>\n"
+ " <input type=\"password\" id=\"password\" name=\"password\" class=\"form-control\" placeholder=\"Password\" required>\n"
+ " </p>\n"
+ "<p><input type='checkbox' name='remember-me'/> Remember me on this computer.</p>\n"
+ "<input name=\"" + csrfToken.getParameterName() + "\" type=\"hidden\" value=\"" + csrfToken.getToken() + "\" />\n"
+ " <button class=\"btn btn-lg btn-primary btn-block\" type=\"submit\">Sign in</button>\n"
+ " </form>\n"
+ "</div>\n"
+ "</body></html>"));
// @formatter:on
}
@Test
public void loginPageWhenOpenIdLoginConfiguredThenOpedIdLoginPage() throws Exception {
this.spring.register(DefaultLoginPageWithOpenIDConfig.class).autowire();
CsrfToken csrfToken = new DefaultCsrfToken("X-CSRF-TOKEN", "_csrf", "BaseSpringSpec_CSRFTOKEN");
String csrfAttributeName = HttpSessionCsrfTokenRepository.class.getName().concat(".CSRF_TOKEN");
// @formatter:off
this.mvc.perform(get("/login").sessionAttr(csrfAttributeName, csrfToken))
.andExpect(content().string("<!DOCTYPE html>\n"
+ "<html lang=\"en\">\n"
+ " <head>\n"
+ " <meta charset=\"utf-8\">\n"
+ " <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\">\n"
+ " <meta name=\"description\" content=\"\">\n"
+ " <meta name=\"author\" content=\"\">\n"
+ " <title>Please sign in</title>\n"
+ " <link href=\"https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css\" rel=\"stylesheet\" integrity=\"sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M\" crossorigin=\"anonymous\">\n"
+ " <link href=\"https://getbootstrap.com/docs/4.0/examples/signin/signin.css\" rel=\"stylesheet\" crossorigin=\"anonymous\"/>\n"
+ " </head>\n"
+ " <body>\n"
+ " <div class=\"container\">\n"
+ " <form name=\"oidf\" class=\"form-signin\" method=\"post\" action=\"/login/openid\">\n"
+ " <h2 class=\"form-signin-heading\">Login with OpenID Identity</h2>\n"
+ " <p>\n"
+ " <label for=\"username\" class=\"sr-only\">Identity</label>\n"
+ " <input type=\"text\" id=\"username\" name=\"openid_identifier\" class=\"form-control\" placeholder=\"Username\" required autofocus>\n"
+ " </p>\n"
+ "<input name=\"" + csrfToken.getParameterName() + "\" type=\"hidden\" value=\"" + csrfToken.getToken() + "\" />\n"
+ " <button class=\"btn btn-lg btn-primary btn-block\" type=\"submit\">Sign in</button>\n"
+ " </form>\n"
+ "</div>\n"
+ "</body></html>"));
// @formatter:on
}
@Test
public void loginPageWhenOpenIdLoginAndFormLoginAndRememberMeConfiguredThenOpedIdLoginPage() throws Exception {
this.spring.register(DefaultLoginPageWithFormLoginOpenIDRememberMeConfig.class).autowire();
CsrfToken csrfToken = new DefaultCsrfToken("X-CSRF-TOKEN", "_csrf", "BaseSpringSpec_CSRFTOKEN");
String csrfAttributeName = HttpSessionCsrfTokenRepository.class.getName().concat(".CSRF_TOKEN");
// @formatter:off
this.mvc.perform(get("/login").sessionAttr(csrfAttributeName, csrfToken))
.andExpect(content().string("<!DOCTYPE html>\n"
+ "<html lang=\"en\">\n"
+ " <head>\n"
+ " <meta charset=\"utf-8\">\n"
+ " <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\">\n"
+ " <meta name=\"description\" content=\"\">\n"
+ " <meta name=\"author\" content=\"\">\n"
+ " <title>Please sign in</title>\n"
+ " <link href=\"https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css\" rel=\"stylesheet\" integrity=\"sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M\" crossorigin=\"anonymous\">\n"
+ " <link href=\"https://getbootstrap.com/docs/4.0/examples/signin/signin.css\" rel=\"stylesheet\" crossorigin=\"anonymous\"/>\n"
+ " </head>\n"
+ " <body>\n"
+ " <div class=\"container\">\n"
+ " <form class=\"form-signin\" method=\"post\" action=\"/login\">\n"
+ " <h2 class=\"form-signin-heading\">Please sign in</h2>\n" + " <p>\n"
+ " <label for=\"username\" class=\"sr-only\">Username</label>\n"
+ " <input type=\"text\" id=\"username\" name=\"username\" class=\"form-control\" placeholder=\"Username\" required autofocus>\n"
+ " </p>\n"
+ " <p>\n"
+ " <label for=\"password\" class=\"sr-only\">Password</label>\n"
+ " <input type=\"password\" id=\"password\" name=\"password\" class=\"form-control\" placeholder=\"Password\" required>\n"
+ " </p>\n"
+ "<p><input type='checkbox' name='remember-me'/> Remember me on this computer.</p>\n"
+ "<input name=\"" + csrfToken.getParameterName() + "\" type=\"hidden\" value=\"" + csrfToken.getToken() + "\" />\n"
+ " <button class=\"btn btn-lg btn-primary btn-block\" type=\"submit\">Sign in</button>\n"
+ " </form>\n"
+ " <form name=\"oidf\" class=\"form-signin\" method=\"post\" action=\"/login/openid\">\n"
+ " <h2 class=\"form-signin-heading\">Login with OpenID Identity</h2>\n"
+ " <p>\n" + " <label for=\"username\" class=\"sr-only\">Identity</label>\n"
+ " <input type=\"text\" id=\"username\" name=\"openid_identifier\" class=\"form-control\" placeholder=\"Username\" required autofocus>\n"
+ " </p>\n"
+ "<p><input type='checkbox' name='remember-me'/> Remember me on this computer.</p>\n"
+ "<input name=\"" + csrfToken.getParameterName() + "\" type=\"hidden\" value=\"" + csrfToken.getToken() + "\" />\n"
+ " <button class=\"btn btn-lg btn-primary btn-block\" type=\"submit\">Sign in</button>\n"
+ " </form>\n"
+ "</div>\n"
+ "</body></html>"));
// @formatter:on
}
@Test
public void configureWhenRegisteringObjectPostProcessorThenInvokedOnDefaultLoginPageGeneratingFilter() {
ObjectPostProcessorConfig.objectPostProcessor = spy(ReflectingObjectPostProcessor.class);
this.spring.register(ObjectPostProcessorConfig.class).autowire();
verify(ObjectPostProcessorConfig.objectPostProcessor).postProcess(any(DefaultLoginPageGeneratingFilter.class));
}
@Test
public void configureWhenRegisteringObjectPostProcessorThenInvokedOnUsernamePasswordAuthenticationFilter() {
ObjectPostProcessorConfig.objectPostProcessor = spy(ReflectingObjectPostProcessor.class);
this.spring.register(ObjectPostProcessorConfig.class).autowire();
verify(ObjectPostProcessorConfig.objectPostProcessor)
.postProcess(any(UsernamePasswordAuthenticationFilter.class));
}
@Test
public void configureWhenRegisteringObjectPostProcessorThenInvokedOnLoginUrlAuthenticationEntryPoint() {
ObjectPostProcessorConfig.objectPostProcessor = spy(ReflectingObjectPostProcessor.class);
this.spring.register(ObjectPostProcessorConfig.class).autowire();
verify(ObjectPostProcessorConfig.objectPostProcessor).postProcess(any(LoginUrlAuthenticationEntryPoint.class));
}
@Test
public void configureWhenRegisteringObjectPostProcessorThenInvokedOnExceptionTranslationFilter() {
ObjectPostProcessorConfig.objectPostProcessor = spy(ReflectingObjectPostProcessor.class);
this.spring.register(ObjectPostProcessorConfig.class).autowire();
verify(ObjectPostProcessorConfig.objectPostProcessor).postProcess(any(ExceptionTranslationFilter.class));
}
@Test
public void configureWhenAuthenticationEntryPointThenNoDefaultLoginPageGeneratingFilter() {
this.spring.register(DefaultLoginWithCustomAuthenticationEntryPointConfig.class).autowire();
FilterChainProxy filterChain = this.spring.getContext().getBean(FilterChainProxy.class);
assertThat(filterChain.getFilterChains().get(0).getFilters().stream()
.filter((filter) -> filter.getClass().isAssignableFrom(DefaultLoginPageGeneratingFilter.class)).count())
.isZero();
}
@EnableWebSecurity
static class DefaultLoginPageConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
@@ -238,19 +397,12 @@ public class DefaultLoginPageConfigurerTests {
.withUser(PasswordEncodedUser.user());
// @formatter:on
}
}
@Test
public void loginPageWhenLoggedOutAndCustomLogoutSuccessHandlerThenDoesNotRenderLoginPage() throws Exception {
this.spring.register(DefaultLoginPageCustomLogoutSuccessHandlerConfig.class).autowire();
this.mvc.perform(get("/login?logout"))
.andExpect(content().string(""));
}
@EnableWebSecurity
static class DefaultLoginPageCustomLogoutSuccessHandlerConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
@@ -264,18 +416,12 @@ public class DefaultLoginPageConfigurerTests {
.formLogin();
// @formatter:on
}
}
@Test
public void loginPageWhenLoggedOutAndCustomLogoutSuccessUrlThenDoesNotRenderLoginPage() throws Exception {
this.spring.register(DefaultLoginPageCustomLogoutSuccessUrlConfig.class).autowire();
this.mvc.perform(get("/login?logout"))
.andExpect(content().string(""));
}
@EnableWebSecurity
static class DefaultLoginPageCustomLogoutSuccessUrlConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
@@ -289,51 +435,12 @@ public class DefaultLoginPageConfigurerTests {
.formLogin();
// @formatter:on
}
}
@Test
public void loginPageWhenRememberConfigureThenDefaultLoginPageWithRememberMeCheckbox() throws Exception {
this.spring.register(DefaultLoginPageWithRememberMeConfig.class).autowire();
CsrfToken csrfToken = new DefaultCsrfToken("X-CSRF-TOKEN", "_csrf", "BaseSpringSpec_CSRFTOKEN");
String csrfAttributeName = HttpSessionCsrfTokenRepository.class.getName().concat(".CSRF_TOKEN");
this.mvc.perform(get("/login")
.sessionAttr(csrfAttributeName, csrfToken))
.andExpect(content().string(
"<!DOCTYPE html>\n" +
"<html lang=\"en\">\n" +
" <head>\n" +
" <meta charset=\"utf-8\">\n" +
" <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\">\n" +
" <meta name=\"description\" content=\"\">\n" +
" <meta name=\"author\" content=\"\">\n" +
" <title>Please sign in</title>\n" +
" <link href=\"https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css\" rel=\"stylesheet\" integrity=\"sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M\" crossorigin=\"anonymous\">\n" +
" <link href=\"https://getbootstrap.com/docs/4.0/examples/signin/signin.css\" rel=\"stylesheet\" crossorigin=\"anonymous\"/>\n" +
" </head>\n" +
" <body>\n" +
" <div class=\"container\">\n" +
" <form class=\"form-signin\" method=\"post\" action=\"/login\">\n" +
" <h2 class=\"form-signin-heading\">Please sign in</h2>\n" +
" <p>\n" +
" <label for=\"username\" class=\"sr-only\">Username</label>\n" +
" <input type=\"text\" id=\"username\" name=\"username\" class=\"form-control\" placeholder=\"Username\" required autofocus>\n" +
" </p>\n" +
" <p>\n" +
" <label for=\"password\" class=\"sr-only\">Password</label>\n" +
" <input type=\"password\" id=\"password\" name=\"password\" class=\"form-control\" placeholder=\"Password\" required>\n" +
" </p>\n" +
"<p><input type='checkbox' name='remember-me'/> Remember me on this computer.</p>\n" +
"<input name=\"" + csrfToken.getParameterName() + "\" type=\"hidden\" value=\"" + csrfToken.getToken() + "\" />\n" +
" <button class=\"btn btn-lg btn-primary btn-block\" type=\"submit\">Sign in</button>\n" +
" </form>\n" +
"</div>\n" +
"</body></html>"
));
}
@EnableWebSecurity
static class DefaultLoginPageWithRememberMeConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
@@ -346,47 +453,12 @@ public class DefaultLoginPageConfigurerTests {
.rememberMe();
// @formatter:on
}
}
@Test
public void loginPageWhenOpenIdLoginConfiguredThenOpedIdLoginPage() throws Exception {
this.spring.register(DefaultLoginPageWithOpenIDConfig.class).autowire();
CsrfToken csrfToken = new DefaultCsrfToken("X-CSRF-TOKEN", "_csrf", "BaseSpringSpec_CSRFTOKEN");
String csrfAttributeName = HttpSessionCsrfTokenRepository.class.getName().concat(".CSRF_TOKEN");
this.mvc.perform(get("/login")
.sessionAttr(csrfAttributeName, csrfToken))
.andExpect(content().string(
"<!DOCTYPE html>\n" +
"<html lang=\"en\">\n" +
" <head>\n" +
" <meta charset=\"utf-8\">\n" +
" <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\">\n" +
" <meta name=\"description\" content=\"\">\n" +
" <meta name=\"author\" content=\"\">\n" +
" <title>Please sign in</title>\n" +
" <link href=\"https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css\" rel=\"stylesheet\" integrity=\"sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M\" crossorigin=\"anonymous\">\n" +
" <link href=\"https://getbootstrap.com/docs/4.0/examples/signin/signin.css\" rel=\"stylesheet\" crossorigin=\"anonymous\"/>\n" +
" </head>\n" +
" <body>\n" +
" <div class=\"container\">\n" +
" <form name=\"oidf\" class=\"form-signin\" method=\"post\" action=\"/login/openid\">\n" +
" <h2 class=\"form-signin-heading\">Login with OpenID Identity</h2>\n" +
" <p>\n" +
" <label for=\"username\" class=\"sr-only\">Identity</label>\n" +
" <input type=\"text\" id=\"username\" name=\"openid_identifier\" class=\"form-control\" placeholder=\"Username\" required autofocus>\n" +
" </p>\n" +
"<input name=\"" + csrfToken.getParameterName() + "\" type=\"hidden\" value=\"" + csrfToken.getToken() + "\" />\n" +
" <button class=\"btn btn-lg btn-primary btn-block\" type=\"submit\">Sign in</button>\n" +
" </form>\n" +
"</div>\n" +
"</body></html>"
));
}
@EnableWebSecurity
static class DefaultLoginPageWithOpenIDConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
@@ -397,61 +469,12 @@ public class DefaultLoginPageConfigurerTests {
.openidLogin();
// @formatter:on
}
}
@Test
public void loginPageWhenOpenIdLoginAndFormLoginAndRememberMeConfiguredThenOpedIdLoginPage() throws Exception {
this.spring.register(DefaultLoginPageWithFormLoginOpenIDRememberMeConfig.class).autowire();
CsrfToken csrfToken = new DefaultCsrfToken("X-CSRF-TOKEN", "_csrf", "BaseSpringSpec_CSRFTOKEN");
String csrfAttributeName = HttpSessionCsrfTokenRepository.class.getName().concat(".CSRF_TOKEN");
this.mvc.perform(get("/login")
.sessionAttr(csrfAttributeName, csrfToken))
.andExpect(content().string(
"<!DOCTYPE html>\n" +
"<html lang=\"en\">\n" +
" <head>\n" +
" <meta charset=\"utf-8\">\n" +
" <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\">\n" +
" <meta name=\"description\" content=\"\">\n" +
" <meta name=\"author\" content=\"\">\n" +
" <title>Please sign in</title>\n" +
" <link href=\"https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css\" rel=\"stylesheet\" integrity=\"sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M\" crossorigin=\"anonymous\">\n" +
" <link href=\"https://getbootstrap.com/docs/4.0/examples/signin/signin.css\" rel=\"stylesheet\" crossorigin=\"anonymous\"/>\n" +
" </head>\n" +
" <body>\n" +
" <div class=\"container\">\n" +
" <form class=\"form-signin\" method=\"post\" action=\"/login\">\n" +
" <h2 class=\"form-signin-heading\">Please sign in</h2>\n" +
" <p>\n" +
" <label for=\"username\" class=\"sr-only\">Username</label>\n" +
" <input type=\"text\" id=\"username\" name=\"username\" class=\"form-control\" placeholder=\"Username\" required autofocus>\n" +
" </p>\n" +
" <p>\n" +
" <label for=\"password\" class=\"sr-only\">Password</label>\n" +
" <input type=\"password\" id=\"password\" name=\"password\" class=\"form-control\" placeholder=\"Password\" required>\n" +
" </p>\n" +
"<p><input type='checkbox' name='remember-me'/> Remember me on this computer.</p>\n" +
"<input name=\"" + csrfToken.getParameterName() + "\" type=\"hidden\" value=\"" + csrfToken.getToken() + "\" />\n" +
" <button class=\"btn btn-lg btn-primary btn-block\" type=\"submit\">Sign in</button>\n" +
" </form>\n" +
" <form name=\"oidf\" class=\"form-signin\" method=\"post\" action=\"/login/openid\">\n" +
" <h2 class=\"form-signin-heading\">Login with OpenID Identity</h2>\n" +
" <p>\n" +
" <label for=\"username\" class=\"sr-only\">Identity</label>\n" +
" <input type=\"text\" id=\"username\" name=\"openid_identifier\" class=\"form-control\" placeholder=\"Username\" required autofocus>\n" +
" </p>\n" +
"<p><input type='checkbox' name='remember-me'/> Remember me on this computer.</p>\n" +
"<input name=\"" + csrfToken.getParameterName() + "\" type=\"hidden\" value=\"" + csrfToken.getToken() + "\" />\n" +
" <button class=\"btn btn-lg btn-primary btn-block\" type=\"submit\">Sign in</button>\n" +
" </form>\n" +
"</div>\n" +
"</body></html>"
));
}
@EnableWebSecurity
static class DefaultLoginPageWithFormLoginOpenIDRememberMeConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
@@ -466,21 +489,12 @@ public class DefaultLoginPageConfigurerTests {
.openidLogin();
// @formatter:on
}
}
@Test
public void configureWhenAuthenticationEntryPointThenNoDefaultLoginPageGeneratingFilter() {
this.spring.register(DefaultLoginWithCustomAuthenticationEntryPointConfig.class).autowire();
FilterChainProxy filterChain = this.spring.getContext().getBean(FilterChainProxy.class);
assertThat(filterChain.getFilterChains().get(0).getFilters().stream()
.filter(filter -> filter.getClass().isAssignableFrom(DefaultLoginPageGeneratingFilter.class))
.count())
.isZero();
}
@EnableWebSecurity
static class DefaultLoginWithCustomAuthenticationEntryPointConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
@@ -494,46 +508,12 @@ public class DefaultLoginPageConfigurerTests {
.formLogin();
// @formatter:on
}
}
@Test
public void configureWhenRegisteringObjectPostProcessorThenInvokedOnDefaultLoginPageGeneratingFilter() {
ObjectPostProcessorConfig.objectPostProcessor = spy(ReflectingObjectPostProcessor.class);
this.spring.register(ObjectPostProcessorConfig.class).autowire();
verify(ObjectPostProcessorConfig.objectPostProcessor)
.postProcess(any(DefaultLoginPageGeneratingFilter.class));
}
@Test
public void configureWhenRegisteringObjectPostProcessorThenInvokedOnUsernamePasswordAuthenticationFilter() {
ObjectPostProcessorConfig.objectPostProcessor = spy(ReflectingObjectPostProcessor.class);
this.spring.register(ObjectPostProcessorConfig.class).autowire();
verify(ObjectPostProcessorConfig.objectPostProcessor)
.postProcess(any(UsernamePasswordAuthenticationFilter.class));
}
@Test
public void configureWhenRegisteringObjectPostProcessorThenInvokedOnLoginUrlAuthenticationEntryPoint() {
ObjectPostProcessorConfig.objectPostProcessor = spy(ReflectingObjectPostProcessor.class);
this.spring.register(ObjectPostProcessorConfig.class).autowire();
verify(ObjectPostProcessorConfig.objectPostProcessor)
.postProcess(any(LoginUrlAuthenticationEntryPoint.class));
}
@Test
public void configureWhenRegisteringObjectPostProcessorThenInvokedOnExceptionTranslationFilter() {
ObjectPostProcessorConfig.objectPostProcessor = spy(ReflectingObjectPostProcessor.class);
this.spring.register(ObjectPostProcessorConfig.class).autowire();
verify(ObjectPostProcessorConfig.objectPostProcessor)
.postProcess(any(ExceptionTranslationFilter.class));
}
@EnableWebSecurity
static class ObjectPostProcessorConfig extends WebSecurityConfigurerAdapter {
static ObjectPostProcessor<Object> objectPostProcessor;
@Override
@@ -550,12 +530,16 @@ public class DefaultLoginPageConfigurerTests {
static ObjectPostProcessor<Object> objectPostProcessor() {
return objectPostProcessor;
}
}
static class ReflectingObjectPostProcessor implements ObjectPostProcessor<Object> {
@Override
public <O> O postProcess(O object) {
return object;
}
}
}

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.configurers;
import org.junit.Rule;
@@ -43,6 +44,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
@RunWith(SpringJUnit4ClassRunner.class)
@SecurityTestExecutionListeners
public class ExceptionHandlingConfigurerAccessDeniedHandlerTests {
@Autowired
MockMvc mvc;
@@ -51,22 +53,33 @@ public class ExceptionHandlingConfigurerAccessDeniedHandlerTests {
@Test
@WithMockUser(roles = "ANYTHING")
public void getWhenAccessDeniedOverriddenThenCustomizesResponseByRequest()
throws Exception {
public void getWhenAccessDeniedOverriddenThenCustomizesResponseByRequest() throws Exception {
this.spring.register(RequestMatcherBasedAccessDeniedHandlerConfig.class).autowire();
this.mvc.perform(get("/hello")).andExpect(status().isIAmATeapot());
this.mvc.perform(get("/goodbye")).andExpect(status().isForbidden());
}
this.mvc.perform(get("/hello"))
.andExpect(status().isIAmATeapot());
@Test
@WithMockUser(roles = "ANYTHING")
public void getWhenAccessDeniedOverriddenInLambdaThenCustomizesResponseByRequest() throws Exception {
this.spring.register(RequestMatcherBasedAccessDeniedHandlerInLambdaConfig.class).autowire();
this.mvc.perform(get("/hello")).andExpect(status().isIAmATeapot());
this.mvc.perform(get("/goodbye")).andExpect(status().isForbidden());
}
this.mvc.perform(get("/goodbye"))
.andExpect(status().isForbidden());
@Test
@WithMockUser(roles = "ANYTHING")
public void getWhenAccessDeniedOverriddenByOnlyOneHandlerThenAllRequestsUseThatHandler() throws Exception {
this.spring.register(SingleRequestMatcherAccessDeniedHandlerConfig.class).autowire();
this.mvc.perform(get("/hello")).andExpect(status().isIAmATeapot());
this.mvc.perform(get("/goodbye")).andExpect(status().isIAmATeapot());
}
@EnableWebSecurity
static class RequestMatcherBasedAccessDeniedHandlerConfig extends WebSecurityConfigurerAdapter {
AccessDeniedHandler teapotDeniedHandler =
(request, response, exception) ->
response.setStatus(HttpStatus.I_AM_A_TEAPOT.value());
AccessDeniedHandler teapotDeniedHandler = (request, response, exception) -> response
.setStatus(HttpStatus.I_AM_A_TEAPOT.value());
@Override
protected void configure(HttpSecurity http) throws Exception {
@@ -84,36 +97,24 @@ public class ExceptionHandlingConfigurerAccessDeniedHandlerTests {
AnyRequestMatcher.INSTANCE);
// @formatter:on
}
}
@Test
@WithMockUser(roles = "ANYTHING")
public void getWhenAccessDeniedOverriddenInLambdaThenCustomizesResponseByRequest()
throws Exception {
this.spring.register(RequestMatcherBasedAccessDeniedHandlerInLambdaConfig.class).autowire();
this.mvc.perform(get("/hello"))
.andExpect(status().isIAmATeapot());
this.mvc.perform(get("/goodbye"))
.andExpect(status().isForbidden());
}
@EnableWebSecurity
static class RequestMatcherBasedAccessDeniedHandlerInLambdaConfig extends WebSecurityConfigurerAdapter {
AccessDeniedHandler teapotDeniedHandler =
(request, response, exception) ->
response.setStatus(HttpStatus.I_AM_A_TEAPOT.value());
AccessDeniedHandler teapotDeniedHandler = (request, response, exception) -> response
.setStatus(HttpStatus.I_AM_A_TEAPOT.value());
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.authorizeRequests(authorizeRequests ->
.authorizeRequests((authorizeRequests) ->
authorizeRequests
.anyRequest().denyAll()
)
.exceptionHandling(exceptionHandling ->
.exceptionHandling((exceptionHandling) ->
exceptionHandling
.defaultAccessDeniedHandlerFor(
this.teapotDeniedHandler,
@@ -126,26 +127,14 @@ public class ExceptionHandlingConfigurerAccessDeniedHandlerTests {
);
// @formatter:on
}
}
@Test
@WithMockUser(roles = "ANYTHING")
public void getWhenAccessDeniedOverriddenByOnlyOneHandlerThenAllRequestsUseThatHandler()
throws Exception {
this.spring.register(SingleRequestMatcherAccessDeniedHandlerConfig.class).autowire();
this.mvc.perform(get("/hello"))
.andExpect(status().isIAmATeapot());
this.mvc.perform(get("/goodbye"))
.andExpect(status().isIAmATeapot());
}
@EnableWebSecurity
static class SingleRequestMatcherAccessDeniedHandlerConfig extends WebSecurityConfigurerAdapter {
AccessDeniedHandler teapotDeniedHandler =
(request, response, exception) ->
response.setStatus(HttpStatus.I_AM_A_TEAPOT.value());
AccessDeniedHandler teapotDeniedHandler = (request, response, exception) -> response
.setStatus(HttpStatus.I_AM_A_TEAPOT.value());
@Override
protected void configure(HttpSecurity http) throws Exception {
@@ -160,5 +149,7 @@ public class ExceptionHandlingConfigurerAccessDeniedHandlerTests {
new AntPathRequestMatcher("/hello/**"));
// @formatter:on
}
}
}

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.configurers;
import javax.servlet.http.HttpServletRequest;
@@ -66,13 +67,154 @@ public class ExceptionHandlingConfigurerTests {
@Test
public void configureWhenRegisteringObjectPostProcessorThenInvokedOnExceptionTranslationFilter() {
this.spring.register(ObjectPostProcessorConfig.class, DefaultSecurityConfig.class).autowire();
verify(ObjectPostProcessorConfig.objectPostProcessor).postProcess(any(ExceptionTranslationFilter.class));
}
verify(ObjectPostProcessorConfig.objectPostProcessor)
.postProcess(any(ExceptionTranslationFilter.class));
// SEC-2199
@Test
public void getWhenAcceptHeaderIsApplicationXhtmlXmlThenRespondsWith302() throws Exception {
this.spring.register(HttpBasicAndFormLoginEntryPointsConfig.class).autowire();
this.mvc.perform(get("/").header(HttpHeaders.ACCEPT, MediaType.APPLICATION_XHTML_XML))
.andExpect(status().isFound());
}
// SEC-2199
@Test
public void getWhenAcceptHeaderIsImageGifThenRespondsWith302() throws Exception {
this.spring.register(HttpBasicAndFormLoginEntryPointsConfig.class).autowire();
this.mvc.perform(get("/").header(HttpHeaders.ACCEPT, MediaType.IMAGE_GIF)).andExpect(status().isFound());
}
// SEC-2199
@Test
public void getWhenAcceptHeaderIsImageJpgThenRespondsWith302() throws Exception {
this.spring.register(HttpBasicAndFormLoginEntryPointsConfig.class).autowire();
this.mvc.perform(get("/").header(HttpHeaders.ACCEPT, MediaType.IMAGE_JPEG)).andExpect(status().isFound());
}
// SEC-2199
@Test
public void getWhenAcceptHeaderIsImagePngThenRespondsWith302() throws Exception {
this.spring.register(HttpBasicAndFormLoginEntryPointsConfig.class).autowire();
this.mvc.perform(get("/").header(HttpHeaders.ACCEPT, MediaType.IMAGE_PNG)).andExpect(status().isFound());
}
// SEC-2199
@Test
public void getWhenAcceptHeaderIsTextHtmlThenRespondsWith302() throws Exception {
this.spring.register(HttpBasicAndFormLoginEntryPointsConfig.class).autowire();
this.mvc.perform(get("/").header(HttpHeaders.ACCEPT, MediaType.TEXT_HTML)).andExpect(status().isFound());
}
// SEC-2199
@Test
public void getWhenAcceptHeaderIsTextPlainThenRespondsWith302() throws Exception {
this.spring.register(HttpBasicAndFormLoginEntryPointsConfig.class).autowire();
this.mvc.perform(get("/").header(HttpHeaders.ACCEPT, MediaType.TEXT_PLAIN)).andExpect(status().isFound());
}
// SEC-2199
@Test
public void getWhenAcceptHeaderIsApplicationAtomXmlThenRespondsWith401() throws Exception {
this.spring.register(HttpBasicAndFormLoginEntryPointsConfig.class).autowire();
this.mvc.perform(get("/").header(HttpHeaders.ACCEPT, MediaType.APPLICATION_ATOM_XML))
.andExpect(status().isUnauthorized());
}
// SEC-2199
@Test
public void getWhenAcceptHeaderIsApplicationFormUrlEncodedThenRespondsWith401() throws Exception {
this.spring.register(HttpBasicAndFormLoginEntryPointsConfig.class).autowire();
this.mvc.perform(get("/").header(HttpHeaders.ACCEPT, MediaType.APPLICATION_FORM_URLENCODED))
.andExpect(status().isUnauthorized());
}
// SEC-2199
@Test
public void getWhenAcceptHeaderIsApplicationJsonThenRespondsWith401() throws Exception {
this.spring.register(HttpBasicAndFormLoginEntryPointsConfig.class).autowire();
this.mvc.perform(get("/").header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON))
.andExpect(status().isUnauthorized());
}
// SEC-2199
@Test
public void getWhenAcceptHeaderIsApplicationOctetStreamThenRespondsWith401() throws Exception {
this.spring.register(HttpBasicAndFormLoginEntryPointsConfig.class).autowire();
this.mvc.perform(get("/").header(HttpHeaders.ACCEPT, MediaType.APPLICATION_OCTET_STREAM))
.andExpect(status().isUnauthorized());
}
// SEC-2199
@Test
public void getWhenAcceptHeaderIsMultipartFormDataThenRespondsWith401() throws Exception {
this.spring.register(HttpBasicAndFormLoginEntryPointsConfig.class).autowire();
this.mvc.perform(get("/").header(HttpHeaders.ACCEPT, MediaType.MULTIPART_FORM_DATA))
.andExpect(status().isUnauthorized());
}
// SEC-2199
@Test
public void getWhenAcceptHeaderIsTextXmlThenRespondsWith401() throws Exception {
this.spring.register(HttpBasicAndFormLoginEntryPointsConfig.class).autowire();
this.mvc.perform(get("/").header(HttpHeaders.ACCEPT, MediaType.TEXT_XML)).andExpect(status().isUnauthorized());
}
// gh-4831
@Test
public void getWhenAcceptIsAnyThenRespondsWith401() throws Exception {
this.spring.register(DefaultSecurityConfig.class).autowire();
this.mvc.perform(get("/").header(HttpHeaders.ACCEPT, MediaType.ALL)).andExpect(status().isUnauthorized());
}
@Test
public void getWhenAcceptIsChromeThenRespondsWith302() throws Exception {
this.spring.register(DefaultSecurityConfig.class).autowire();
this.mvc.perform(get("/").header(HttpHeaders.ACCEPT,
"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8"))
.andExpect(status().isFound());
}
@Test
public void getWhenAcceptIsTextPlainAndXRequestedWithIsXHRThenRespondsWith401() throws Exception {
this.spring.register(HttpBasicAndFormLoginEntryPointsConfig.class).autowire();
this.mvc.perform(get("/").header("Accept", MediaType.TEXT_PLAIN).header("X-Requested-With", "XMLHttpRequest"))
.andExpect(status().isUnauthorized());
}
@Test
public void getWhenCustomContentNegotiationStrategyThenStrategyIsUsed() throws Exception {
this.spring.register(OverrideContentNegotiationStrategySharedObjectConfig.class, DefaultSecurityConfig.class)
.autowire();
this.mvc.perform(get("/"));
verify(OverrideContentNegotiationStrategySharedObjectConfig.CNS, atLeastOnce())
.resolveMediaTypes(any(NativeWebRequest.class));
}
@Test
public void getWhenUsingDefaultsAndUnauthenticatedThenRedirectsToLogin() throws Exception {
this.spring.register(DefaultHttpConfig.class).autowire();
this.mvc.perform(get("/").header(HttpHeaders.ACCEPT, "bogus/type"))
.andExpect(redirectedUrl("http://localhost/login"));
}
@Test
public void getWhenDeclaringHttpBasicBeforeFormLoginThenRespondsWith401() throws Exception {
this.spring.register(BasicAuthenticationEntryPointBeforeFormLoginConfig.class).autowire();
this.mvc.perform(get("/").header(HttpHeaders.ACCEPT, "bogus/type")).andExpect(status().isUnauthorized());
}
@Test
public void getWhenInvokingExceptionHandlingTwiceThenOriginalEntryPointUsed() throws Exception {
this.spring.register(InvokeTwiceDoesNotOverrideConfig.class).autowire();
this.mvc.perform(get("/"));
verify(InvokeTwiceDoesNotOverrideConfig.AEP).commence(any(HttpServletRequest.class),
any(HttpServletResponse.class), any(AuthenticationException.class));
}
@EnableWebSecurity
static class ObjectPostProcessorConfig extends WebSecurityConfigurerAdapter {
static ObjectPostProcessor<Object> objectPostProcessor = spy(ReflectingObjectPostProcessor.class);
@Override
@@ -87,189 +229,41 @@ public class ExceptionHandlingConfigurerTests {
static ObjectPostProcessor<Object> objectPostProcessor() {
return objectPostProcessor;
}
}
static class ReflectingObjectPostProcessor implements ObjectPostProcessor<Object> {
@Override
public <O> O postProcess(O object) {
return object;
}
}
// SEC-2199
@Test
public void getWhenAcceptHeaderIsApplicationXhtmlXmlThenRespondsWith302() throws Exception {
this.spring.register(HttpBasicAndFormLoginEntryPointsConfig.class).autowire();
this.mvc.perform(get("/")
.header(HttpHeaders.ACCEPT, MediaType.APPLICATION_XHTML_XML))
.andExpect(status().isFound());
}
// SEC-2199
@Test
public void getWhenAcceptHeaderIsImageGifThenRespondsWith302() throws Exception {
this.spring.register(HttpBasicAndFormLoginEntryPointsConfig.class).autowire();
this.mvc.perform(get("/")
.header(HttpHeaders.ACCEPT, MediaType.IMAGE_GIF))
.andExpect(status().isFound());
}
// SEC-2199
@Test
public void getWhenAcceptHeaderIsImageJpgThenRespondsWith302() throws Exception {
this.spring.register(HttpBasicAndFormLoginEntryPointsConfig.class).autowire();
this.mvc.perform(get("/")
.header(HttpHeaders.ACCEPT, MediaType.IMAGE_JPEG))
.andExpect(status().isFound());
}
// SEC-2199
@Test
public void getWhenAcceptHeaderIsImagePngThenRespondsWith302() throws Exception {
this.spring.register(HttpBasicAndFormLoginEntryPointsConfig.class).autowire();
this.mvc.perform(get("/")
.header(HttpHeaders.ACCEPT, MediaType.IMAGE_PNG))
.andExpect(status().isFound());
}
// SEC-2199
@Test
public void getWhenAcceptHeaderIsTextHtmlThenRespondsWith302() throws Exception {
this.spring.register(HttpBasicAndFormLoginEntryPointsConfig.class).autowire();
this.mvc.perform(get("/")
.header(HttpHeaders.ACCEPT, MediaType.TEXT_HTML))
.andExpect(status().isFound());
}
// SEC-2199
@Test
public void getWhenAcceptHeaderIsTextPlainThenRespondsWith302() throws Exception {
this.spring.register(HttpBasicAndFormLoginEntryPointsConfig.class).autowire();
this.mvc.perform(get("/")
.header(HttpHeaders.ACCEPT, MediaType.TEXT_PLAIN))
.andExpect(status().isFound());
}
// SEC-2199
@Test
public void getWhenAcceptHeaderIsApplicationAtomXmlThenRespondsWith401() throws Exception {
this.spring.register(HttpBasicAndFormLoginEntryPointsConfig.class).autowire();
this.mvc.perform(get("/")
.header(HttpHeaders.ACCEPT, MediaType.APPLICATION_ATOM_XML))
.andExpect(status().isUnauthorized());
}
// SEC-2199
@Test
public void getWhenAcceptHeaderIsApplicationFormUrlEncodedThenRespondsWith401() throws Exception {
this.spring.register(HttpBasicAndFormLoginEntryPointsConfig.class).autowire();
this.mvc.perform(get("/")
.header(HttpHeaders.ACCEPT, MediaType.APPLICATION_FORM_URLENCODED))
.andExpect(status().isUnauthorized());
}
// SEC-2199
@Test
public void getWhenAcceptHeaderIsApplicationJsonThenRespondsWith401() throws Exception {
this.spring.register(HttpBasicAndFormLoginEntryPointsConfig.class).autowire();
this.mvc.perform(get("/")
.header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON))
.andExpect(status().isUnauthorized());
}
// SEC-2199
@Test
public void getWhenAcceptHeaderIsApplicationOctetStreamThenRespondsWith401() throws Exception {
this.spring.register(HttpBasicAndFormLoginEntryPointsConfig.class).autowire();
this.mvc.perform(get("/")
.header(HttpHeaders.ACCEPT, MediaType.APPLICATION_OCTET_STREAM))
.andExpect(status().isUnauthorized());
}
// SEC-2199
@Test
public void getWhenAcceptHeaderIsMultipartFormDataThenRespondsWith401() throws Exception {
this.spring.register(HttpBasicAndFormLoginEntryPointsConfig.class).autowire();
this.mvc.perform(get("/")
.header(HttpHeaders.ACCEPT, MediaType.MULTIPART_FORM_DATA))
.andExpect(status().isUnauthorized());
}
// SEC-2199
@Test
public void getWhenAcceptHeaderIsTextXmlThenRespondsWith401() throws Exception {
this.spring.register(HttpBasicAndFormLoginEntryPointsConfig.class).autowire();
this.mvc.perform(get("/")
.header(HttpHeaders.ACCEPT, MediaType.TEXT_XML))
.andExpect(status().isUnauthorized());
}
// gh-4831
@Test
public void getWhenAcceptIsAnyThenRespondsWith401() throws Exception {
this.spring.register(DefaultSecurityConfig.class).autowire();
this.mvc.perform(get("/")
.header(HttpHeaders.ACCEPT, MediaType.ALL))
.andExpect(status().isUnauthorized());
}
@Test
public void getWhenAcceptIsChromeThenRespondsWith302() throws Exception {
this.spring.register(DefaultSecurityConfig.class).autowire();
this.mvc.perform(get("/")
.header(HttpHeaders.ACCEPT,
"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8"))
.andExpect(status().isFound());
}
@Test
public void getWhenAcceptIsTextPlainAndXRequestedWithIsXHRThenRespondsWith401() throws Exception {
this.spring.register(HttpBasicAndFormLoginEntryPointsConfig.class).autowire();
this.mvc.perform(get("/")
.header("Accept", MediaType.TEXT_PLAIN)
.header("X-Requested-With", "XMLHttpRequest"))
.andExpect(status().isUnauthorized());
}
@EnableWebSecurity
static class DefaultSecurityConfig {
@Bean
public InMemoryUserDetailsManager userDetailsManager() {
InMemoryUserDetailsManager userDetailsManager() {
// @formatter:off
return new InMemoryUserDetailsManager(User.withDefaultPasswordEncoder()
.username("user")
.password("password")
.roles("USER")
.build()
);
// @formatter:off
}
}
@EnableWebSecurity
static class HttpBasicAndFormLoginEntryPointsConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
@@ -282,53 +276,29 @@ public class ExceptionHandlingConfigurerTests {
.formLogin();
// @formatter:on
}
}
@Test
public void getWhenCustomContentNegotiationStrategyThenStrategyIsUsed() throws Exception {
this.spring.register(OverrideContentNegotiationStrategySharedObjectConfig.class,
DefaultSecurityConfig.class).autowire();
this.mvc.perform(get("/"));
verify(OverrideContentNegotiationStrategySharedObjectConfig.CNS, atLeastOnce())
.resolveMediaTypes(any(NativeWebRequest.class));
}
@EnableWebSecurity
static class OverrideContentNegotiationStrategySharedObjectConfig extends WebSecurityConfigurerAdapter {
static ContentNegotiationStrategy CNS = mock(ContentNegotiationStrategy.class);
@Bean
public static ContentNegotiationStrategy cns() {
static ContentNegotiationStrategy cns() {
return CNS;
}
}
@Test
public void getWhenUsingDefaultsAndUnauthenticatedThenRedirectsToLogin() throws Exception {
this.spring.register(DefaultHttpConfig.class).autowire();
this.mvc.perform(get("/")
.header(HttpHeaders.ACCEPT, "bogus/type"))
.andExpect(redirectedUrl("http://localhost/login"));
}
@EnableWebSecurity
static class DefaultHttpConfig extends WebSecurityConfigurerAdapter {
}
@Test
public void getWhenDeclaringHttpBasicBeforeFormLoginThenRespondsWith401() throws Exception {
this.spring.register(BasicAuthenticationEntryPointBeforeFormLoginConfig.class).autowire();
this.mvc.perform(get("/")
.header(HttpHeaders.ACCEPT, "bogus/type"))
.andExpect(status().isUnauthorized());
}
@EnableWebSecurity
static class BasicAuthenticationEntryPointBeforeFormLoginConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
@@ -341,35 +311,27 @@ public class ExceptionHandlingConfigurerTests {
.formLogin();
// @formatter:on
}
}
@Test
public void getWhenInvokingExceptionHandlingTwiceThenOriginalEntryPointUsed() throws Exception {
this.spring.register(InvokeTwiceDoesNotOverrideConfig.class).autowire();
this.mvc.perform(get("/"));
verify(InvokeTwiceDoesNotOverrideConfig.AEP)
.commence(any(HttpServletRequest.class),
any(HttpServletResponse.class), any(AuthenticationException.class));
}
@EnableWebSecurity
static class InvokeTwiceDoesNotOverrideConfig extends WebSecurityConfigurerAdapter {
static AuthenticationEntryPoint AEP = mock(AuthenticationEntryPoint.class);
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:on
// @formatter:off
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.exceptionHandling()
.authenticationEntryPoint(AEP)
.and()
.authenticationEntryPoint(AEP).and()
.exceptionHandling();
// @formatter:off
// @formatter:on
}
}
}

View File

@@ -18,6 +18,7 @@ package org.springframework.security.config.annotation.web.configurers;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.ObjectPostProcessor;
@@ -29,6 +30,7 @@ import org.springframework.security.config.annotation.web.configuration.WebSecur
import org.springframework.security.config.test.SpringTestRule;
import org.springframework.security.config.users.AuthenticationTestConfiguration;
import org.springframework.security.core.userdetails.PasswordEncodedUser;
import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders;
import org.springframework.security.web.PortMapper;
import org.springframework.security.web.access.ExceptionTranslationFilter;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
@@ -38,10 +40,10 @@ import org.springframework.security.web.savedrequest.RequestCache;
import org.springframework.test.web.servlet.MockMvc;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.springframework.security.config.Customizer.withDefaults;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.formLogin;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.logout;
@@ -58,6 +60,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
* @since 5.1
*/
public class FormLoginConfigurerTests {
@Rule
public final SpringTestRule spring = new SpringTestRule();
@@ -66,105 +69,317 @@ public class FormLoginConfigurerTests {
@Test
public void requestCache() throws Exception {
this.spring.register(RequestCacheConfig.class,
AuthenticationTestConfiguration.class).autowire();
this.spring.register(RequestCacheConfig.class, AuthenticationTestConfiguration.class).autowire();
RequestCacheConfig config = this.spring.getContext().getBean(RequestCacheConfig.class);
this.mockMvc.perform(formLogin())
.andExpect(authenticated());
this.mockMvc.perform(formLogin()).andExpect(authenticated());
verify(config.requestCache).getRequest(any(), any());
}
@EnableWebSecurity
static class RequestCacheConfig extends WebSecurityConfigurerAdapter {
private RequestCache requestCache = mock(RequestCache.class);
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.formLogin().and()
.requestCache()
.requestCache(this.requestCache);
}
}
@Test
public void requestCacheAsBean() throws Exception {
this.spring.register(RequestCacheBeanConfig.class,
AuthenticationTestConfiguration.class).autowire();
this.spring.register(RequestCacheBeanConfig.class, AuthenticationTestConfiguration.class).autowire();
RequestCache requestCache = this.spring.getContext().getBean(RequestCache.class);
this.mockMvc.perform(formLogin())
.andExpect(authenticated());
this.mockMvc.perform(formLogin()).andExpect(authenticated());
verify(requestCache).getRequest(any(), any());
}
@EnableWebSecurity
static class RequestCacheBeanConfig {
@Bean
RequestCache requestCache() {
return mock(RequestCache.class);
}
}
@Test
public void loginWhenFormLoginConfiguredThenHasDefaultUsernameAndPasswordParameterNames() throws Exception {
this.spring.register(FormLoginConfig.class).autowire();
this.mockMvc.perform(formLogin().user("username", "user").password("password", "password"))
// @formatter:off
SecurityMockMvcRequestBuilders.FormLoginRequestBuilder loginRequest = formLogin()
.user("username", "user")
.password("password", "password");
this.mockMvc.perform(loginRequest)
.andExpect(status().isFound())
.andExpect(redirectedUrl("/"));
// @formatter:on
}
@Test
public void loginWhenFormLoginConfiguredThenHasDefaultFailureUrl() throws Exception {
this.spring.register(FormLoginConfig.class).autowire();
// @formatter:off
this.mockMvc.perform(formLogin().user("invalid"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("/login?error"));
// @formatter:on
}
@Test
public void loginWhenFormLoginConfiguredThenHasDefaultSuccessUrl() throws Exception {
this.spring.register(FormLoginConfig.class).autowire();
// @formatter:off
this.mockMvc.perform(formLogin())
.andExpect(status().isFound())
.andExpect(redirectedUrl("/"));
// @formatter:on
}
@Test
public void getLoginPageWhenFormLoginConfiguredThenNotSecured() throws Exception {
this.spring.register(FormLoginConfig.class).autowire();
this.mockMvc.perform(get("/login"))
.andExpect(status().isFound());
this.mockMvc.perform(get("/login")).andExpect(status().isFound());
}
@Test
public void loginWhenFormLoginConfiguredThenSecured() throws Exception {
this.spring.register(FormLoginConfig.class).autowire();
this.mockMvc.perform(post("/login"))
.andExpect(status().isForbidden());
this.mockMvc.perform(post("/login")).andExpect(status().isForbidden());
}
@Test
public void requestProtectedWhenFormLoginConfiguredThenRedirectsToLogin() throws Exception {
this.spring.register(FormLoginConfig.class).autowire();
// @formatter:off
this.mockMvc.perform(get("/private"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("http://localhost/login"));
// @formatter:on
}
@Test
public void loginWhenFormLoginDefaultsInLambdaThenHasDefaultUsernameAndPasswordParameterNames() throws Exception {
this.spring.register(FormLoginInLambdaConfig.class).autowire();
// @formatter:off
SecurityMockMvcRequestBuilders.FormLoginRequestBuilder loginRequest = formLogin()
.user("username", "user")
.password("password", "password");
this.mockMvc.perform(loginRequest)
.andExpect(status().isFound())
.andExpect(redirectedUrl("/"));
// @formatter:on
}
@Test
public void loginWhenFormLoginDefaultsInLambdaThenHasDefaultFailureUrl() throws Exception {
this.spring.register(FormLoginInLambdaConfig.class).autowire();
// @formatter:off
this.mockMvc.perform(formLogin().user("invalid"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("/login?error"));
// @formatter:on
}
@Test
public void loginWhenFormLoginDefaultsInLambdaThenHasDefaultSuccessUrl() throws Exception {
this.spring.register(FormLoginInLambdaConfig.class).autowire();
// @formatter:off
this.mockMvc.perform(formLogin())
.andExpect(status().isFound())
.andExpect(redirectedUrl("/"));
// @formatter:on
}
@Test
public void getLoginPageWhenFormLoginDefaultsInLambdaThenNotSecured() throws Exception {
this.spring.register(FormLoginInLambdaConfig.class).autowire();
this.mockMvc.perform(get("/login")).andExpect(status().isOk());
}
@Test
public void loginWhenFormLoginDefaultsInLambdaThenSecured() throws Exception {
this.spring.register(FormLoginInLambdaConfig.class).autowire();
this.mockMvc.perform(post("/login")).andExpect(status().isForbidden());
}
@Test
public void requestProtectedWhenFormLoginDefaultsInLambdaThenRedirectsToLogin() throws Exception {
this.spring.register(FormLoginInLambdaConfig.class).autowire();
// @formatter:off
this.mockMvc.perform(get("/private"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("http://localhost/login"));
// @formatter:on
}
@Test
public void getLoginPageWhenFormLoginPermitAllThenPermittedAndNoRedirect() throws Exception {
this.spring.register(FormLoginConfigPermitAll.class).autowire();
// @formatter:off
this.mockMvc.perform(get("/login"))
.andExpect(status().isOk())
.andExpect(redirectedUrl(null));
// @formatter:on
}
@Test
public void getLoginPageWithErrorQueryWhenFormLoginPermitAllThenPermittedAndNoRedirect() throws Exception {
this.spring.register(FormLoginConfigPermitAll.class).autowire();
// @formatter:off
this.mockMvc.perform(get("/login?error"))
.andExpect(status().isOk())
.andExpect(redirectedUrl(null));
// @formatter:on
}
@Test
public void loginWhenFormLoginPermitAllAndInvalidUserThenRedirectsToLoginPageWithError() throws Exception {
this.spring.register(FormLoginConfigPermitAll.class).autowire();
// @formatter:off
this.mockMvc.perform(formLogin().user("invalid"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("/login?error"));
// @formatter:on
}
@Test
public void getLoginPageWhenCustomLoginPageThenPermittedAndNoRedirect() throws Exception {
this.spring.register(FormLoginDefaultsConfig.class).autowire();
this.mockMvc.perform(get("/authenticate")).andExpect(redirectedUrl(null));
}
@Test
public void getLoginPageWithErrorQueryWhenCustomLoginPageThenPermittedAndNoRedirect() throws Exception {
this.spring.register(FormLoginDefaultsConfig.class).autowire();
this.mockMvc.perform(get("/authenticate?error")).andExpect(redirectedUrl(null));
}
@Test
public void loginWhenCustomLoginPageAndInvalidUserThenRedirectsToCustomLoginPageWithError() throws Exception {
this.spring.register(FormLoginDefaultsConfig.class).autowire();
SecurityMockMvcRequestBuilders.FormLoginRequestBuilder request = formLogin("/authenticate").user("invalid");
// @formatter:off
this.mockMvc.perform(request)
.andExpect(status().isFound())
.andExpect(redirectedUrl("/authenticate?error"));
// @formatter:on
}
@Test
public void logoutWhenCustomLoginPageThenRedirectsToCustomLoginPage() throws Exception {
this.spring.register(FormLoginDefaultsConfig.class).autowire();
this.mockMvc.perform(logout()).andExpect(redirectedUrl("/authenticate?logout"));
}
@Test
public void getLoginPageWithLogoutQueryWhenCustomLoginPageThenPermittedAndNoRedirect() throws Exception {
this.spring.register(FormLoginDefaultsConfig.class).autowire();
this.mockMvc.perform(get("/authenticate?logout")).andExpect(redirectedUrl(null));
}
@Test
public void getLoginPageWhenCustomLoginPageInLambdaThenPermittedAndNoRedirect() throws Exception {
this.spring.register(FormLoginDefaultsInLambdaConfig.class).autowire();
this.mockMvc.perform(get("/authenticate")).andExpect(redirectedUrl(null));
}
@Test
public void loginWhenCustomLoginProcessingUrlThenRedirectsToHome() throws Exception {
this.spring.register(FormLoginLoginProcessingUrlConfig.class).autowire();
// @formatter:off
this.mockMvc.perform(formLogin("/loginCheck"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("/"));
// @formatter:on
}
@Test
public void loginWhenCustomLoginProcessingUrlInLambdaThenRedirectsToHome() throws Exception {
this.spring.register(FormLoginLoginProcessingUrlInLambdaConfig.class).autowire();
// @formatter:off
this.mockMvc.perform(formLogin("/loginCheck"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("/"));
// @formatter:on
}
@Test
public void requestWhenCustomPortMapperThenPortMapperUsed() throws Exception {
FormLoginUsesPortMapperConfig.PORT_MAPPER = mock(PortMapper.class);
given(FormLoginUsesPortMapperConfig.PORT_MAPPER.lookupHttpsPort(any())).willReturn(9443);
this.spring.register(FormLoginUsesPortMapperConfig.class).autowire();
// @formatter:off
this.mockMvc.perform(get("http://localhost:9090"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("https://localhost:9443/login"));
// @formatter:on
verify(FormLoginUsesPortMapperConfig.PORT_MAPPER).lookupHttpsPort(any());
}
@Test
public void failureUrlWhenPermitAllAndFailureHandlerThenSecured() throws Exception {
this.spring.register(PermitAllIgnoresFailureHandlerConfig.class).autowire();
// @formatter:off
this.mockMvc.perform(get("/login?error"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("http://localhost/login"));
// @formatter:on
}
@Test
public void formLoginWhenInvokedTwiceThenUsesOriginalUsernameParameter() throws Exception {
this.spring.register(DuplicateInvocationsDoesNotOverrideConfig.class).autowire();
SecurityMockMvcRequestBuilders.FormLoginRequestBuilder loginRequest = formLogin().user("custom-username",
"user");
this.mockMvc.perform(loginRequest).andExpect(authenticated());
}
@Test
public void loginWhenInvalidLoginAndFailureForwardUrlThenForwardsToFailureForwardUrl() throws Exception {
this.spring.register(FormLoginUserForwardAuthenticationSuccessAndFailureConfig.class).autowire();
SecurityMockMvcRequestBuilders.FormLoginRequestBuilder loginRequest = formLogin().user("invalid");
this.mockMvc.perform(loginRequest).andExpect(forwardedUrl("/failure_forward_url"));
}
@Test
public void loginWhenSuccessForwardUrlThenForwardsToSuccessForwardUrl() throws Exception {
this.spring.register(FormLoginUserForwardAuthenticationSuccessAndFailureConfig.class).autowire();
this.mockMvc.perform(formLogin()).andExpect(forwardedUrl("/success_forward_url"));
}
@Test
public void configureWhenRegisteringObjectPostProcessorThenInvokedOnUsernamePasswordAuthenticationFilter() {
ObjectPostProcessorConfig.objectPostProcessor = spy(ReflectingObjectPostProcessor.class);
this.spring.register(ObjectPostProcessorConfig.class).autowire();
verify(ObjectPostProcessorConfig.objectPostProcessor)
.postProcess(any(UsernamePasswordAuthenticationFilter.class));
}
@Test
public void configureWhenRegisteringObjectPostProcessorThenInvokedOnLoginUrlAuthenticationEntryPoint() {
ObjectPostProcessorConfig.objectPostProcessor = spy(ReflectingObjectPostProcessor.class);
this.spring.register(ObjectPostProcessorConfig.class).autowire();
verify(ObjectPostProcessorConfig.objectPostProcessor).postProcess(any(LoginUrlAuthenticationEntryPoint.class));
}
@Test
public void configureWhenRegisteringObjectPostProcessorThenInvokedOnExceptionTranslationFilter() {
ObjectPostProcessorConfig.objectPostProcessor = spy(ReflectingObjectPostProcessor.class);
this.spring.register(ObjectPostProcessorConfig.class).autowire();
verify(ObjectPostProcessorConfig.objectPostProcessor).postProcess(any(ExceptionTranslationFilter.class));
}
@EnableWebSecurity
static class RequestCacheConfig extends WebSecurityConfigurerAdapter {
private RequestCache requestCache = mock(RequestCache.class);
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.formLogin().and()
.requestCache()
.requestCache(this.requestCache);
// @formatter:on
}
}
@EnableWebSecurity
static class RequestCacheBeanConfig {
@Bean
RequestCache requestCache() {
return mock(RequestCache.class);
}
}
@EnableWebSecurity
static class FormLoginConfig extends WebSecurityConfigurerAdapter {
@Override
public void configure(WebSecurity web) {
// @formatter:off
@@ -194,67 +409,17 @@ public class FormLoginConfigurerTests {
.withUser(PasswordEncodedUser.user());
// @formatter:on
}
}
@Test
public void loginWhenFormLoginDefaultsInLambdaThenHasDefaultUsernameAndPasswordParameterNames() throws Exception {
this.spring.register(FormLoginInLambdaConfig.class).autowire();
this.mockMvc.perform(formLogin().user("username", "user").password("password", "password"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("/"));
}
@Test
public void loginWhenFormLoginDefaultsInLambdaThenHasDefaultFailureUrl() throws Exception {
this.spring.register(FormLoginInLambdaConfig.class).autowire();
this.mockMvc.perform(formLogin().user("invalid"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("/login?error"));
}
@Test
public void loginWhenFormLoginDefaultsInLambdaThenHasDefaultSuccessUrl() throws Exception {
this.spring.register(FormLoginInLambdaConfig.class).autowire();
this.mockMvc.perform(formLogin())
.andExpect(status().isFound())
.andExpect(redirectedUrl("/"));
}
@Test
public void getLoginPageWhenFormLoginDefaultsInLambdaThenNotSecured() throws Exception {
this.spring.register(FormLoginInLambdaConfig.class).autowire();
this.mockMvc.perform(get("/login"))
.andExpect(status().isOk());
}
@Test
public void loginWhenFormLoginDefaultsInLambdaThenSecured() throws Exception {
this.spring.register(FormLoginInLambdaConfig.class).autowire();
this.mockMvc.perform(post("/login"))
.andExpect(status().isForbidden());
}
@Test
public void requestProtectedWhenFormLoginDefaultsInLambdaThenRedirectsToLogin() throws Exception {
this.spring.register(FormLoginInLambdaConfig.class).autowire();
this.mockMvc.perform(get("/private"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("http://localhost/login"));
}
@EnableWebSecurity
static class FormLoginInLambdaConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.authorizeRequests(authorizeRequests ->
.authorizeRequests((authorizeRequests) ->
authorizeRequests
.anyRequest().hasRole("USER")
)
@@ -270,37 +435,12 @@ public class FormLoginConfigurerTests {
.withUser(PasswordEncodedUser.user());
// @formatter:on
}
}
@Test
public void getLoginPageWhenFormLoginPermitAllThenPermittedAndNoRedirect() throws Exception {
this.spring.register(FormLoginConfigPermitAll.class).autowire();
this.mockMvc.perform(get("/login"))
.andExpect(status().isOk())
.andExpect(redirectedUrl(null));
}
@Test
public void getLoginPageWithErrorQueryWhenFormLoginPermitAllThenPermittedAndNoRedirect() throws Exception {
this.spring.register(FormLoginConfigPermitAll.class).autowire();
this.mockMvc.perform(get("/login?error"))
.andExpect(status().isOk())
.andExpect(redirectedUrl(null));
}
@Test
public void loginWhenFormLoginPermitAllAndInvalidUserThenRedirectsToLoginPageWithError() throws Exception {
this.spring.register(FormLoginConfigPermitAll.class).autowire();
this.mockMvc.perform(formLogin().user("invalid"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("/login?error"));
}
@EnableWebSecurity
static class FormLoginConfigPermitAll extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
@@ -312,51 +452,12 @@ public class FormLoginConfigurerTests {
.permitAll();
// @formatter:on
}
}
@Test
public void getLoginPageWhenCustomLoginPageThenPermittedAndNoRedirect() throws Exception {
this.spring.register(FormLoginDefaultsConfig.class).autowire();
this.mockMvc.perform(get("/authenticate"))
.andExpect(redirectedUrl(null));
}
@Test
public void getLoginPageWithErrorQueryWhenCustomLoginPageThenPermittedAndNoRedirect() throws Exception {
this.spring.register(FormLoginDefaultsConfig.class).autowire();
this.mockMvc.perform(get("/authenticate?error"))
.andExpect(redirectedUrl(null));
}
@Test
public void loginWhenCustomLoginPageAndInvalidUserThenRedirectsToCustomLoginPageWithError() throws Exception {
this.spring.register(FormLoginDefaultsConfig.class).autowire();
this.mockMvc.perform(formLogin("/authenticate").user("invalid"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("/authenticate?error"));
}
@Test
public void logoutWhenCustomLoginPageThenRedirectsToCustomLoginPage() throws Exception {
this.spring.register(FormLoginDefaultsConfig.class).autowire();
this.mockMvc.perform(logout())
.andExpect(redirectedUrl("/authenticate?logout"));
}
@Test
public void getLoginPageWithLogoutQueryWhenCustomLoginPageThenPermittedAndNoRedirect() throws Exception {
this.spring.register(FormLoginDefaultsConfig.class).autowire();
this.mockMvc.perform(get("/authenticate?logout"))
.andExpect(redirectedUrl(null));
}
@EnableWebSecurity
static class FormLoginDefaultsConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
@@ -372,27 +473,21 @@ public class FormLoginConfigurerTests {
.permitAll();
// @formatter:on
}
}
@Test
public void getLoginPageWhenCustomLoginPageInLambdaThenPermittedAndNoRedirect() throws Exception {
this.spring.register(FormLoginDefaultsInLambdaConfig.class).autowire();
this.mockMvc.perform(get("/authenticate"))
.andExpect(redirectedUrl(null));
}
@EnableWebSecurity
static class FormLoginDefaultsInLambdaConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.authorizeRequests(authorizeRequests ->
.authorizeRequests((authorizeRequests) ->
authorizeRequests
.anyRequest().hasRole("USER")
)
.formLogin(formLogin ->
.formLogin((formLogin) ->
formLogin
.loginPage("/authenticate")
.permitAll()
@@ -400,19 +495,12 @@ public class FormLoginConfigurerTests {
.logout(LogoutConfigurer::permitAll);
// @formatter:on
}
}
@Test
public void loginWhenCustomLoginProcessingUrlThenRedirectsToHome() throws Exception {
this.spring.register(FormLoginLoginProcessingUrlConfig.class).autowire();
this.mockMvc.perform(formLogin("/loginCheck"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("/"));
}
@EnableWebSecurity
static class FormLoginLoginProcessingUrlConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
@@ -443,35 +531,28 @@ public class FormLoginConfigurerTests {
.withUser(PasswordEncodedUser.user());
// @formatter:on
}
}
@Test
public void loginWhenCustomLoginProcessingUrlInLambdaThenRedirectsToHome() throws Exception {
this.spring.register(FormLoginLoginProcessingUrlInLambdaConfig.class).autowire();
this.mockMvc.perform(formLogin("/loginCheck"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("/"));
}
@EnableWebSecurity
static class FormLoginLoginProcessingUrlInLambdaConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.authorizeRequests(authorizeRequests ->
.authorizeRequests((authorizeRequests) ->
authorizeRequests
.anyRequest().authenticated()
)
.formLogin(formLogin ->
.formLogin((formLogin) ->
formLogin
.loginProcessingUrl("/loginCheck")
.loginPage("/login")
.defaultSuccessUrl("/", true)
.permitAll()
)
.logout(logout ->
.logout((logout) ->
logout
.logoutSuccessUrl("/login")
.logoutUrl("/logout")
@@ -488,23 +569,12 @@ public class FormLoginConfigurerTests {
.withUser(PasswordEncodedUser.user());
// @formatter:on
}
}
@Test
public void requestWhenCustomPortMapperThenPortMapperUsed() throws Exception {
FormLoginUsesPortMapperConfig.PORT_MAPPER = mock(PortMapper.class);
when(FormLoginUsesPortMapperConfig.PORT_MAPPER.lookupHttpsPort(any())).thenReturn(9443);
this.spring.register(FormLoginUsesPortMapperConfig.class).autowire();
this.mockMvc.perform(get("http://localhost:9090"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("https://localhost:9443/login"));
verify(FormLoginUsesPortMapperConfig.PORT_MAPPER).lookupHttpsPort(any());
}
@EnableWebSecurity
static class FormLoginUsesPortMapperConfig extends WebSecurityConfigurerAdapter {
static PortMapper PORT_MAPPER;
@Override
@@ -520,23 +590,16 @@ public class FormLoginConfigurerTests {
.portMapper()
.portMapper(PORT_MAPPER);
// @formatter:on
LoginUrlAuthenticationEntryPoint authenticationEntryPoint =
(LoginUrlAuthenticationEntryPoint) http.getConfigurer(FormLoginConfigurer.class).getAuthenticationEntryPoint();
LoginUrlAuthenticationEntryPoint authenticationEntryPoint = (LoginUrlAuthenticationEntryPoint) http
.getConfigurer(FormLoginConfigurer.class).getAuthenticationEntryPoint();
authenticationEntryPoint.setForceHttps(true);
}
}
@Test
public void failureUrlWhenPermitAllAndFailureHandlerThenSecured() throws Exception {
this.spring.register(PermitAllIgnoresFailureHandlerConfig.class).autowire();
this.mockMvc.perform(get("/login?error"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("http://localhost/login"));
}
@EnableWebSecurity
static class PermitAllIgnoresFailureHandlerConfig extends WebSecurityConfigurerAdapter {
static AuthenticationFailureHandler FAILURE_HANDLER = mock(AuthenticationFailureHandler.class);
@Override
@@ -551,18 +614,12 @@ public class FormLoginConfigurerTests {
.permitAll();
// @formatter:on
}
}
@Test
public void formLoginWhenInvokedTwiceThenUsesOriginalUsernameParameter() throws Exception {
this.spring.register(DuplicateInvocationsDoesNotOverrideConfig.class).autowire();
this.mockMvc.perform(formLogin().user("custom-username", "user"))
.andExpect(authenticated());
}
@EnableWebSecurity
static class DuplicateInvocationsDoesNotOverrideConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
@@ -582,22 +639,7 @@ public class FormLoginConfigurerTests {
.withUser(PasswordEncodedUser.user());
// @formatter:on
}
}
@Test
public void loginWhenInvalidLoginAndFailureForwardUrlThenForwardsToFailureForwardUrl() throws Exception {
this.spring.register(FormLoginUserForwardAuthenticationSuccessAndFailureConfig.class).autowire();
this.mockMvc.perform(formLogin().user("invalid"))
.andExpect(forwardedUrl("/failure_forward_url"));
}
@Test
public void loginWhenSuccessForwardUrlThenForwardsToSuccessForwardUrl() throws Exception {
this.spring.register(FormLoginUserForwardAuthenticationSuccessAndFailureConfig.class).autowire();
this.mockMvc.perform(formLogin())
.andExpect(forwardedUrl("/success_forward_url"));
}
@EnableWebSecurity
@@ -627,37 +669,12 @@ public class FormLoginConfigurerTests {
.withUser(PasswordEncodedUser.user());
// @formatter:on
}
}
@Test
public void configureWhenRegisteringObjectPostProcessorThenInvokedOnUsernamePasswordAuthenticationFilter() {
ObjectPostProcessorConfig.objectPostProcessor = spy(ReflectingObjectPostProcessor.class);
this.spring.register(ObjectPostProcessorConfig.class).autowire();
verify(ObjectPostProcessorConfig.objectPostProcessor)
.postProcess(any(UsernamePasswordAuthenticationFilter.class));
}
@Test
public void configureWhenRegisteringObjectPostProcessorThenInvokedOnLoginUrlAuthenticationEntryPoint() {
ObjectPostProcessorConfig.objectPostProcessor = spy(ReflectingObjectPostProcessor.class);
this.spring.register(ObjectPostProcessorConfig.class).autowire();
verify(ObjectPostProcessorConfig.objectPostProcessor)
.postProcess(any(LoginUrlAuthenticationEntryPoint.class));
}
@Test
public void configureWhenRegisteringObjectPostProcessorThenInvokedOnExceptionTranslationFilter() {
ObjectPostProcessorConfig.objectPostProcessor = spy(ReflectingObjectPostProcessor.class);
this.spring.register(ObjectPostProcessorConfig.class).autowire();
verify(ObjectPostProcessorConfig.objectPostProcessor)
.postProcess(any(ExceptionTranslationFilter.class));
}
@EnableWebSecurity
static class ObjectPostProcessorConfig extends WebSecurityConfigurerAdapter {
static ObjectPostProcessor<Object> objectPostProcessor;
@Override
@@ -674,12 +691,16 @@ public class FormLoginConfigurerTests {
static ObjectPostProcessor<Object> objectPostProcessor() {
return objectPostProcessor;
}
}
static class ReflectingObjectPostProcessor implements ObjectPostProcessor<Object> {
@Override
public <O> O postProcess(O object) {
return object;
}
}
}

View File

@@ -18,7 +18,9 @@ package org.springframework.security.config.annotation.web.configurers;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
@@ -27,7 +29,6 @@ import org.springframework.security.config.test.SpringTestRule;
import org.springframework.security.web.header.HeaderWriterFilter;
import org.springframework.test.web.servlet.MockMvc;
import static org.springframework.http.HttpHeaders.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;
@@ -44,11 +45,24 @@ public class HeadersConfigurerEagerHeadersTests {
@Autowired
MockMvc mvc;
@Test
public void requestWhenHeadersEagerlyConfiguredThenHeadersAreWritten() throws Exception {
this.spring.register(HeadersAtTheBeginningOfRequestConfig.class).autowire();
this.mvc.perform(get("/").secure(true)).andExpect(header().string("X-Content-Type-Options", "nosniff"))
.andExpect(header().string("X-Frame-Options", "DENY"))
.andExpect(header().string("Strict-Transport-Security", "max-age=31536000 ; includeSubDomains"))
.andExpect(header().string(HttpHeaders.CACHE_CONTROL, "no-cache, no-store, max-age=0, must-revalidate"))
.andExpect(header().string(HttpHeaders.EXPIRES, "0"))
.andExpect(header().string(HttpHeaders.PRAGMA, "no-cache"))
.andExpect(header().string("X-XSS-Protection", "1; mode=block"));
}
@EnableWebSecurity
public static class HeadersAtTheBeginningOfRequestConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
//@ formatter:off
// @formatter:off
http
.headers()
.addObjectPostProcessor(new ObjectPostProcessor<HeaderWriterFilter>() {
@@ -58,21 +72,9 @@ public class HeadersConfigurerEagerHeadersTests {
return filter;
}
});
//@ formatter:on
// @formatter:on
}
}
@Test
public void requestWhenHeadersEagerlyConfiguredThenHeadersAreWritten() throws Exception {
this.spring.register(HeadersAtTheBeginningOfRequestConfig.class).autowire();
this.mvc.perform(get("/").secure(true))
.andExpect(header().string("X-Content-Type-Options", "nosniff"))
.andExpect(header().string("X-Frame-Options", "DENY"))
.andExpect(header().string("Strict-Transport-Security", "max-age=31536000 ; includeSubDomains"))
.andExpect(header().string(CACHE_CONTROL, "no-cache, no-store, max-age=0, must-revalidate"))
.andExpect(header().string(EXPIRES, "0"))
.andExpect(header().string(PRAGMA, "no-cache"))
.andExpect(header().string("X-XSS-Protection", "1; mode=block"));
}
}

View File

@@ -16,8 +16,12 @@
package org.springframework.security.config.annotation.web.configurers;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -34,15 +38,18 @@ import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import static org.mockito.Mockito.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.springframework.security.config.Customizer.withDefaults;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.httpBasic;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.cookie;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
/**
* Tests for {@link HttpBasicConfigurer}
@@ -61,13 +68,58 @@ public class HttpBasicConfigurerTests {
@Test
public void configureWhenRegisteringObjectPostProcessorThenInvokedOnBasicAuthenticationFilter() {
this.spring.register(ObjectPostProcessorConfig.class).autowire();
verify(ObjectPostProcessorConfig.objectPostProcessor).postProcess(any(BasicAuthenticationFilter.class));
}
verify(ObjectPostProcessorConfig.objectPostProcessor)
.postProcess(any(BasicAuthenticationFilter.class));
@Test
public void httpBasicWhenUsingDefaultsInLambdaThenResponseIncludesBasicChallenge() throws Exception {
this.spring.register(DefaultsLambdaEntryPointConfig.class).autowire();
// @formatter:off
this.mvc.perform(get("/"))
.andExpect(status().isUnauthorized())
.andExpect(header().string("WWW-Authenticate", "Basic realm=\"Realm\""));
// @formatter:on
}
// SEC-2198
@Test
public void httpBasicWhenUsingDefaultsThenResponseIncludesBasicChallenge() throws Exception {
this.spring.register(DefaultsEntryPointConfig.class).autowire();
// @formatter:off
this.mvc.perform(get("/"))
.andExpect(status().isUnauthorized())
.andExpect(header().string("WWW-Authenticate", "Basic realm=\"Realm\""));
// @formatter:on
}
@Test
public void httpBasicWhenUsingCustomAuthenticationEntryPointThenResponseIncludesBasicChallenge() throws Exception {
this.spring.register(CustomAuthenticationEntryPointConfig.class).autowire();
this.mvc.perform(get("/"));
verify(CustomAuthenticationEntryPointConfig.ENTRY_POINT).commence(any(HttpServletRequest.class),
any(HttpServletResponse.class), any(AuthenticationException.class));
}
@Test
public void httpBasicWhenInvokedTwiceThenUsesOriginalEntryPoint() throws Exception {
this.spring.register(DuplicateDoesNotOverrideConfig.class).autowire();
this.mvc.perform(get("/"));
verify(DuplicateDoesNotOverrideConfig.ENTRY_POINT).commence(any(HttpServletRequest.class),
any(HttpServletResponse.class), any(AuthenticationException.class));
}
// SEC-3019
@Test
public void httpBasicWhenRememberMeConfiguredThenSetsRememberMeCookie() throws Exception {
this.spring.register(BasicUsesRememberMeConfig.class).autowire();
MockHttpServletRequestBuilder rememberMeRequest = get("/").with(httpBasic("user", "password"))
.param("remember-me", "true");
this.mvc.perform(rememberMeRequest).andExpect(cookie().exists("remember-me"));
}
@EnableWebSecurity
static class ObjectPostProcessorConfig extends WebSecurityConfigurerAdapter {
static ObjectPostProcessor<Object> objectPostProcessor = spy(ReflectingObjectPostProcessor.class);
@Override
@@ -82,31 +134,26 @@ public class HttpBasicConfigurerTests {
static ObjectPostProcessor<Object> objectPostProcessor() {
return objectPostProcessor;
}
}
static class ReflectingObjectPostProcessor implements ObjectPostProcessor<Object> {
@Override
public <O> O postProcess(O object) {
return object;
}
}
@Test
public void httpBasicWhenUsingDefaultsInLambdaThenResponseIncludesBasicChallenge() throws Exception {
this.spring.register(DefaultsLambdaEntryPointConfig.class).autowire();
this.mvc.perform(get("/"))
.andExpect(status().isUnauthorized())
.andExpect(header().string("WWW-Authenticate", "Basic realm=\"Realm\""));
}
@EnableWebSecurity
static class DefaultsLambdaEntryPointConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.authorizeRequests(authorizeRequests ->
.authorizeRequests((authorizeRequests) ->
authorizeRequests
.anyRequest().authenticated()
)
@@ -121,20 +168,12 @@ public class HttpBasicConfigurerTests {
.inMemoryAuthentication();
// @formatter:on
}
}
//SEC-2198
@Test
public void httpBasicWhenUsingDefaultsThenResponseIncludesBasicChallenge() throws Exception {
this.spring.register(DefaultsEntryPointConfig.class).autowire();
this.mvc.perform(get("/"))
.andExpect(status().isUnauthorized())
.andExpect(header().string("WWW-Authenticate", "Basic realm=\"Realm\""));
}
@EnableWebSecurity
static class DefaultsEntryPointConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
@@ -153,22 +192,12 @@ public class HttpBasicConfigurerTests {
.inMemoryAuthentication();
// @formatter:on
}
}
@Test
public void httpBasicWhenUsingCustomAuthenticationEntryPointThenResponseIncludesBasicChallenge() throws Exception {
this.spring.register(CustomAuthenticationEntryPointConfig.class).autowire();
this.mvc.perform(get("/"));
verify(CustomAuthenticationEntryPointConfig.ENTRY_POINT)
.commence(any(HttpServletRequest.class),
any(HttpServletResponse.class),
any(AuthenticationException.class));
}
@EnableWebSecurity
static class CustomAuthenticationEntryPointConfig extends WebSecurityConfigurerAdapter {
static AuthenticationEntryPoint ENTRY_POINT = mock(AuthenticationEntryPoint.class);
@Override
@@ -190,22 +219,12 @@ public class HttpBasicConfigurerTests {
.inMemoryAuthentication();
// @formatter:on
}
}
@Test
public void httpBasicWhenInvokedTwiceThenUsesOriginalEntryPoint() throws Exception {
this.spring.register(DuplicateDoesNotOverrideConfig.class).autowire();
this.mvc.perform(get("/"));
verify(DuplicateDoesNotOverrideConfig.ENTRY_POINT)
.commence(any(HttpServletRequest.class),
any(HttpServletResponse.class),
any(AuthenticationException.class));
}
@EnableWebSecurity
static class DuplicateDoesNotOverrideConfig extends WebSecurityConfigurerAdapter {
static AuthenticationEntryPoint ENTRY_POINT = mock(AuthenticationEntryPoint.class);
@Override
@@ -229,17 +248,7 @@ public class HttpBasicConfigurerTests {
.inMemoryAuthentication();
// @formatter:on
}
}
//SEC-3019
@Test
public void httpBasicWhenRememberMeConfiguredThenSetsRememberMeCookie() throws Exception {
this.spring.register(BasicUsesRememberMeConfig.class).autowire();
this.mvc.perform(get("/")
.with(httpBasic("user", "password"))
.param("remember-me", "true"))
.andExpect(cookie().exists("remember-me"));
}
@EnableWebSecurity
@@ -256,15 +265,20 @@ public class HttpBasicConfigurerTests {
// @formatter:on
}
@Override
@Bean
public UserDetailsService userDetailsService() {
return new InMemoryUserDetailsManager(
// @formatter:off
User.withDefaultPasswordEncoder()
.username("user")
.password("password")
.roles("USER")
.build()
// @formatter:on
);
}
}
}

View File

@@ -13,15 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.configurers;
import static org.assertj.core.api.Assertions.assertThat;
package org.springframework.security.config.annotation.web.configurers;
import javax.servlet.http.HttpServletResponse;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
@@ -35,15 +35,20 @@ import org.springframework.security.config.annotation.web.configuration.WebSecur
import org.springframework.security.web.FilterChainProxy;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import static org.assertj.core.api.Assertions.assertThat;
/**
* @author Rob Winch
*
*/
public class HttpSecurityAntMatchersTests {
AnnotationConfigWebApplicationContext context;
MockHttpServletRequest request;
MockHttpServletResponse response;
MockFilterChain chain;
@Autowired
@@ -51,15 +56,15 @@ public class HttpSecurityAntMatchersTests {
@Before
public void setup() {
request = new MockHttpServletRequest("GET", "");
response = new MockHttpServletResponse();
chain = new MockFilterChain();
this.request = new MockHttpServletRequest("GET", "");
this.response = new MockHttpServletResponse();
this.chain = new MockFilterChain();
}
@After
public void cleanup() {
if (context != null) {
context.close();
if (this.context != null) {
this.context.close();
}
}
@@ -67,47 +72,60 @@ public class HttpSecurityAntMatchersTests {
@Test
public void antMatchersMethodAndNoPatterns() throws Exception {
loadConfig(AntMatchersNoPatternsConfig.class);
request.setMethod("POST");
springSecurityFilterChain.doFilter(request, response, chain);
assertThat(response.getStatus()).isEqualTo(HttpServletResponse.SC_FORBIDDEN);
}
@EnableWebSecurity
@Configuration
static class AntMatchersNoPatternsConfig extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception {
http
.requestMatchers()
.antMatchers(HttpMethod.POST)
.and()
.authorizeRequests()
.anyRequest().denyAll();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication();
}
this.request.setMethod("POST");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_FORBIDDEN);
}
// SEC-3135
@Test
public void antMatchersMethodAndEmptyPatterns() throws Exception {
loadConfig(AntMatchersEmptyPatternsConfig.class);
request.setMethod("POST");
this.request.setMethod("POST");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
}
springSecurityFilterChain.doFilter(request, response, chain);
public void loadConfig(Class<?>... configs) {
this.context = new AnnotationConfigWebApplicationContext();
this.context.register(configs);
this.context.refresh();
this.context.getAutowireCapableBeanFactory().autowireBean(this);
}
@EnableWebSecurity
@Configuration
static class AntMatchersNoPatternsConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.requestMatchers()
.antMatchers(HttpMethod.POST)
.and()
.authorizeRequests()
.anyRequest().denyAll();
// @formatter:on
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// @formatter:off
auth
.inMemoryAuthentication();
// @formatter:on
}
assertThat(response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
}
@EnableWebSecurity
@Configuration
static class AntMatchersEmptyPatternsConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.requestMatchers()
.antMatchers("/never/")
@@ -115,22 +133,17 @@ public class HttpSecurityAntMatchersTests {
.and()
.authorizeRequests()
.anyRequest().denyAll();
// @formatter:on
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// @formatter:off
auth
.inMemoryAuthentication();
// @formatter:on
}
}
public void loadConfig(Class<?>... configs) {
context = new AnnotationConfigWebApplicationContext();
context.register(configs);
context.refresh();
context.getAutowireCapableBeanFactory().autowireBean(this);
}
}

View File

@@ -13,13 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.configurers;
import static org.assertj.core.api.Assertions.assertThat;
package org.springframework.security.config.annotation.web.configurers;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.mock.web.MockFilterChain;
@@ -36,15 +36,20 @@ import org.springframework.security.web.FilterChainProxy;
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import static org.assertj.core.api.Assertions.assertThat;
/**
* @author Rob Winch
*
*/
public class HttpSecurityLogoutTests {
AnnotationConfigWebApplicationContext context;
MockHttpServletRequest request;
MockHttpServletResponse response;
MockFilterChain chain;
@Autowired
@@ -52,15 +57,15 @@ public class HttpSecurityLogoutTests {
@Before
public void setup() {
request = new MockHttpServletRequest("GET", "");
response = new MockHttpServletResponse();
chain = new MockFilterChain();
this.request = new MockHttpServletRequest("GET", "");
this.response = new MockHttpServletResponse();
this.chain = new MockFilterChain();
}
@After
public void cleanup() {
if (context != null) {
context.close();
if (this.context != null) {
this.context.close();
}
}
@@ -68,43 +73,45 @@ public class HttpSecurityLogoutTests {
@Test
public void clearAuthenticationFalse() throws Exception {
loadConfig(ClearAuthenticationFalseConfig.class);
SecurityContext currentContext = SecurityContextHolder.createEmptyContext();
currentContext.setAuthentication(new TestingAuthenticationToken("user", "password", "ROLE_USER"));
request.getSession().setAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY, currentContext);
request.setMethod("POST");
request.setServletPath("/logout");
springSecurityFilterChain.doFilter(request, response, chain);
this.request.getSession().setAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY,
currentContext);
this.request.setMethod("POST");
this.request.setServletPath("/logout");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(currentContext.getAuthentication()).isNotNull();
}
public void loadConfig(Class<?>... configs) {
this.context = new AnnotationConfigWebApplicationContext();
this.context.register(configs);
this.context.refresh();
this.context.getAutowireCapableBeanFactory().autowireBean(this);
}
@EnableWebSecurity
@Configuration
static class ClearAuthenticationFalseConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.csrf().disable()
.logout()
.clearAuthentication(false);
// @formatter:on
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// @formatter:off
auth
.inMemoryAuthentication();
// @formatter:on
}
}
public void loadConfig(Class<?>... configs) {
context = new AnnotationConfigWebApplicationContext();
context.register(configs);
context.refresh();
context.getAutowireCapableBeanFactory().autowireBean(this);
}
}

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.configurers;
import javax.servlet.http.HttpServletResponse;
@@ -47,10 +48,13 @@ import static org.springframework.security.config.Customizer.withDefaults;
*
*/
public class HttpSecurityRequestMatchersTests {
AnnotationConfigWebApplicationContext context;
MockHttpServletRequest request;
MockHttpServletResponse response;
MockFilterChain chain;
@Autowired
@@ -74,41 +78,108 @@ public class HttpSecurityRequestMatchersTests {
@Test
public void mvcMatcher() throws Exception {
loadConfig(MvcMatcherConfig.class, LegacyMvcMatchingConfig.class);
this.request.setServletPath("/path");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus())
.isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
setup();
this.request.setServletPath("/path.html");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus())
.isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
setup();
this.request.setServletPath("/path/");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus())
.isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
}
@Test
public void mvcMatcherGetFiltersNoUnsupportedMethodExceptionFromDummyRequest() {
loadConfig(MvcMatcherConfig.class);
assertThat(this.springSecurityFilterChain.getFilters("/path")).isNotEmpty();
}
assertThat(springSecurityFilterChain.getFilters("/path")).isNotEmpty();
@Test
public void requestMatchersMvcMatcher() throws Exception {
loadConfig(RequestMatchersMvcMatcherConfig.class, LegacyMvcMatchingConfig.class);
this.request.setServletPath("/path");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
setup();
this.request.setServletPath("/path.html");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
setup();
this.request.setServletPath("/path/");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
}
@Test
public void requestMatchersWhenMvcMatcherInLambdaThenPathIsSecured() throws Exception {
loadConfig(RequestMatchersMvcMatcherInLambdaConfig.class, LegacyMvcMatchingConfig.class);
this.request.setServletPath("/path");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
setup();
this.request.setServletPath("/path.html");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
setup();
this.request.setServletPath("/path/");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
}
@Test
public void requestMatchersMvcMatcherServletPath() throws Exception {
loadConfig(RequestMatchersMvcMatcherServeltPathConfig.class);
this.request.setServletPath("/spring");
this.request.setRequestURI("/spring/path");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
setup();
this.request.setServletPath("");
this.request.setRequestURI("/path");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
setup();
this.request.setServletPath("/other");
this.request.setRequestURI("/other/path");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
}
@Test
public void requestMatcherWhensMvcMatcherServletPathInLambdaThenPathIsSecured() throws Exception {
loadConfig(RequestMatchersMvcMatcherServletPathInLambdaConfig.class);
this.request.setServletPath("/spring");
this.request.setRequestURI("/spring/path");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
setup();
this.request.setServletPath("");
this.request.setRequestURI("/path");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
setup();
this.request.setServletPath("/other");
this.request.setRequestURI("/other/path");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
}
public void loadConfig(Class<?>... configs) {
this.context = new AnnotationConfigWebApplicationContext();
this.context.register(configs);
this.context.setServletContext(new MockServletContext());
this.context.refresh();
this.context.getAutowireCapableBeanFactory().autowireBean(this);
}
@EnableWebSecurity
@Configuration
@EnableWebMvc
static class MvcMatcherConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
@@ -130,44 +201,21 @@ public class HttpSecurityRequestMatchersTests {
@RestController
static class PathController {
@RequestMapping("/path")
public String path() {
String path() {
return "path";
}
}
}
@Test
public void requestMatchersMvcMatcher() throws Exception {
loadConfig(RequestMatchersMvcMatcherConfig.class, LegacyMvcMatchingConfig.class);
this.request.setServletPath("/path");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus())
.isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
setup();
this.request.setServletPath("/path.html");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus())
.isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
setup();
this.request.setServletPath("/path/");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus())
.isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
}
@EnableWebSecurity
@Configuration
@EnableWebMvc
static class RequestMatchersMvcMatcherConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
@@ -191,54 +239,31 @@ public class HttpSecurityRequestMatchersTests {
@RestController
static class PathController {
@RequestMapping("/path")
public String path() {
String path() {
return "path";
}
}
}
@Test
public void requestMatchersWhenMvcMatcherInLambdaThenPathIsSecured() throws Exception {
loadConfig(RequestMatchersMvcMatcherInLambdaConfig.class, LegacyMvcMatchingConfig.class);
this.request.setServletPath("/path");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus())
.isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
setup();
this.request.setServletPath("/path.html");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus())
.isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
setup();
this.request.setServletPath("/path/");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus())
.isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
}
@EnableWebSecurity
@Configuration
@EnableWebMvc
static class RequestMatchersMvcMatcherInLambdaConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.requestMatchers(requestMatchers ->
.requestMatchers((requestMatchers) ->
requestMatchers
.mvcMatchers("/path")
)
.httpBasic(withDefaults())
.authorizeRequests(authorizeRequests ->
.authorizeRequests((authorizeRequests) ->
authorizeRequests
.anyRequest().denyAll()
);
@@ -247,47 +272,21 @@ public class HttpSecurityRequestMatchersTests {
@RestController
static class PathController {
@RequestMapping("/path")
public String path() {
String path() {
return "path";
}
}
}
@Test
public void requestMatchersMvcMatcherServletPath() throws Exception {
loadConfig(RequestMatchersMvcMatcherServeltPathConfig.class);
this.request.setServletPath("/spring");
this.request.setRequestURI("/spring/path");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus())
.isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
setup();
this.request.setServletPath("");
this.request.setRequestURI("/path");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
setup();
this.request.setServletPath("/other");
this.request.setRequestURI("/other/path");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
}
@EnableWebSecurity
@Configuration
@EnableWebMvc
static class RequestMatchersMvcMatcherServeltPathConfig
extends WebSecurityConfigurerAdapter {
static class RequestMatchersMvcMatcherServeltPathConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
@@ -312,58 +311,32 @@ public class HttpSecurityRequestMatchersTests {
@RestController
static class PathController {
@RequestMapping("/path")
public String path() {
String path() {
return "path";
}
}
}
@Test
public void requestMatcherWhensMvcMatcherServletPathInLambdaThenPathIsSecured() throws Exception {
loadConfig(RequestMatchersMvcMatcherServletPathInLambdaConfig.class);
this.request.setServletPath("/spring");
this.request.setRequestURI("/spring/path");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus())
.isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
setup();
this.request.setServletPath("");
this.request.setRequestURI("/path");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
setup();
this.request.setServletPath("/other");
this.request.setRequestURI("/other/path");
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
}
@EnableWebSecurity
@Configuration
@EnableWebMvc
static class RequestMatchersMvcMatcherServletPathInLambdaConfig
extends WebSecurityConfigurerAdapter {
static class RequestMatchersMvcMatcherServletPathInLambdaConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.requestMatchers(requestMatchers ->
.requestMatchers((requestMatchers) ->
requestMatchers
.mvcMatchers("/path").servletPath("/spring")
.mvcMatchers("/never-match")
)
.httpBasic(withDefaults())
.authorizeRequests(authorizeRequests ->
.authorizeRequests((authorizeRequests) ->
authorizeRequests
.anyRequest().denyAll()
);
@@ -372,27 +345,24 @@ public class HttpSecurityRequestMatchersTests {
@RestController
static class PathController {
@RequestMapping("/path")
public String path() {
String path() {
return "path";
}
}
}
@Configuration
static class LegacyMvcMatchingConfig implements WebMvcConfigurer {
@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
configurer.setUseSuffixPatternMatch(true);
}
}
public void loadConfig(Class<?>... configs) {
this.context = new AnnotationConfigWebApplicationContext();
this.context.register(configs);
this.context.setServletContext(new MockServletContext());
this.context.refresh();
this.context.getAutowireCapableBeanFactory().autowireBean(this);
}
}

View File

@@ -13,10 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.configurers;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
import javax.servlet.Filter;
import org.junit.Rule;
@@ -38,7 +40,7 @@ import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.stereotype.Component;
import static org.assertj.core.api.Java6Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThat;
/**
* @author Rob Winch
@@ -54,91 +56,22 @@ public class Issue55Tests {
TestingAuthenticationToken token = new TestingAuthenticationToken("test", "this");
this.spring.register(WebSecurityConfigurerAdapterDefaultsAuthManagerConfig.class);
this.spring.getContext().getBean(FilterChainProxy.class);
FilterSecurityInterceptor filter = (FilterSecurityInterceptor) findFilter(FilterSecurityInterceptor.class, 0);
assertThat(filter.getAuthenticationManager().authenticate(token)).isEqualTo(CustomAuthenticationManager.RESULT);
}
@EnableWebSecurity
static class WebSecurityConfigurerAdapterDefaultsAuthManagerConfig {
@Component
public static class WebSecurityAdapter extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.authorizeRequests()
.anyRequest().hasRole("USER");
// @formatter:on
}
}
@Configuration
public static class AuthenticationManagerConfiguration {
@Bean
public AuthenticationManager authenticationManager() throws Exception {
return new CustomAuthenticationManager();
}
}
}
@Test
public void multiHttpWebSecurityConfigurerAdapterDefaultsToAutowired() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
public void multiHttpWebSecurityConfigurerAdapterDefaultsToAutowired()
throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
TestingAuthenticationToken token = new TestingAuthenticationToken("test", "this");
this.spring.register(MultiWebSecurityConfigurerAdapterDefaultsAuthManagerConfig.class);
this.spring.getContext().getBean(FilterChainProxy.class);
FilterSecurityInterceptor filter = (FilterSecurityInterceptor) findFilter(FilterSecurityInterceptor.class, 0);
assertThat(filter.getAuthenticationManager().authenticate(token)).isEqualTo(CustomAuthenticationManager.RESULT);
FilterSecurityInterceptor secondFilter = (FilterSecurityInterceptor) findFilter(FilterSecurityInterceptor.class, 1);
assertThat(secondFilter.getAuthenticationManager().authenticate(token)).isEqualTo(CustomAuthenticationManager.RESULT);
}
@EnableWebSecurity
static class MultiWebSecurityConfigurerAdapterDefaultsAuthManagerConfig {
@Component
@Order(1)
public static class ApiWebSecurityAdapter extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http.antMatcher("/api/**")
.authorizeRequests()
.anyRequest().hasRole("USER");
// @formatter:on
}
}
@Component
public static class WebSecurityAdapter extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.authorizeRequests()
.anyRequest().hasRole("USER");
// @formatter:on
}
}
@Configuration
public static class AuthenticationManagerConfiguration {
@Bean
public AuthenticationManager authenticationManager() throws Exception {
return new CustomAuthenticationManager();
}
}
}
static class CustomAuthenticationManager implements AuthenticationManager {
static Authentication RESULT = new TestingAuthenticationToken("test", "this", "ROLE_USER");
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
return RESULT;
}
FilterSecurityInterceptor secondFilter = (FilterSecurityInterceptor) findFilter(FilterSecurityInterceptor.class,
1);
assertThat(secondFilter.getAuthenticationManager().authenticate(token))
.isEqualTo(CustomAuthenticationManager.RESULT);
}
Filter findFilter(Class<?> filter, int index) {
@@ -154,4 +87,89 @@ public class Issue55Tests {
SecurityFilterChain filterChain(int index) {
return this.spring.getContext().getBean(FilterChainProxy.class).getFilterChains().get(index);
}
@EnableWebSecurity
static class WebSecurityConfigurerAdapterDefaultsAuthManagerConfig {
@Component
public static class WebSecurityAdapter extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.authorizeRequests()
.anyRequest().hasRole("USER");
// @formatter:on
}
}
@Configuration
public static class AuthenticationManagerConfiguration {
@Bean
public AuthenticationManager authenticationManager() throws Exception {
return new CustomAuthenticationManager();
}
}
}
@EnableWebSecurity
static class MultiWebSecurityConfigurerAdapterDefaultsAuthManagerConfig {
@Component
@Order(1)
public static class ApiWebSecurityAdapter extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http.antMatcher("/api/**")
.authorizeRequests()
.anyRequest().hasRole("USER");
// @formatter:on
}
}
@Component
public static class WebSecurityAdapter extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.authorizeRequests()
.anyRequest().hasRole("USER");
// @formatter:on
}
}
@Configuration
public static class AuthenticationManagerConfiguration {
@Bean
public AuthenticationManager authenticationManager() throws Exception {
return new CustomAuthenticationManager();
}
}
}
static class CustomAuthenticationManager implements AuthenticationManager {
static Authentication RESULT = new TestingAuthenticationToken("test", "this", "ROLE_USER");
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
return RESULT;
}
}
}

View File

@@ -16,8 +16,11 @@
package org.springframework.security.config.annotation.web.configurers;
import java.security.Principal;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.ObjectPostProcessor;
@@ -28,17 +31,17 @@ import org.springframework.security.config.test.SpringTestRule;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.AuthenticationUserDetailsService;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers;
import org.springframework.security.web.authentication.preauth.j2ee.J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource;
import org.springframework.security.web.authentication.preauth.j2ee.J2eePreAuthenticatedProcessingFilter;
import org.springframework.test.web.servlet.MockMvc;
import java.security.Principal;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.authenticated;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
@@ -60,7 +63,6 @@ public class JeeConfigurerTests {
public void configureWhenRegisteringObjectPostProcessorThenInvokedOnJ2eePreAuthenticatedProcessingFilter() {
ObjectPostProcessorConfig.objectPostProcessor = spy(ReflectingObjectPostProcessor.class);
this.spring.register(ObjectPostProcessorConfig.class).autowire();
verify(ObjectPostProcessorConfig.objectPostProcessor)
.postProcess(any(J2eePreAuthenticatedProcessingFilter.class));
}
@@ -69,13 +71,88 @@ public class JeeConfigurerTests {
public void configureWhenRegisteringObjectPostProcessorThenInvokedOnJ2eeBasedPreAuthenticatedWebAuthenticationDetailsSource() {
ObjectPostProcessorConfig.objectPostProcessor = spy(ReflectingObjectPostProcessor.class);
this.spring.register(ObjectPostProcessorConfig.class).autowire();
verify(ObjectPostProcessorConfig.objectPostProcessor)
.postProcess(any(J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource.class));
}
@Test
public void jeeWhenInvokedTwiceThenUsesOriginalMappableRoles() throws Exception {
this.spring.register(InvokeTwiceDoesNotOverride.class).autowire();
Principal user = mock(Principal.class);
given(user.getName()).willReturn("user");
// @formatter:off
MockHttpServletRequestBuilder authRequest = get("/")
.principal(user)
.with((request) -> {
request.addUserRole("ROLE_ADMIN");
request.addUserRole("ROLE_USER");
return request;
});
// @formatter:on
this.mvc.perform(authRequest).andExpect(authenticated().withRoles("USER"));
}
@Test
public void requestWhenJeeMappableRolesInLambdaThenAuthenticatedWithMappableRoles() throws Exception {
this.spring.register(JeeMappableRolesConfig.class).autowire();
Principal user = mock(Principal.class);
given(user.getName()).willReturn("user");
// @formatter:off
MockHttpServletRequestBuilder authRequest = get("/")
.principal(user)
.with((request) -> {
request.addUserRole("ROLE_ADMIN");
request.addUserRole("ROLE_USER");
return request;
});
// @formatter:on
this.mvc.perform(authRequest).andExpect(authenticated().withRoles("USER"));
}
@Test
public void requestWhenJeeMappableAuthoritiesInLambdaThenAuthenticatedWithMappableAuthorities() throws Exception {
this.spring.register(JeeMappableAuthoritiesConfig.class).autowire();
Principal user = mock(Principal.class);
given(user.getName()).willReturn("user");
// @formatter:off
MockHttpServletRequestBuilder authRequest = get("/")
.principal(user)
.with((request) -> {
request.addUserRole("ROLE_ADMIN");
request.addUserRole("ROLE_USER");
return request;
});
// @formatter:on
SecurityMockMvcResultMatchers.AuthenticatedMatcher authenticatedAsUser = authenticated()
.withAuthorities(AuthorityUtils.createAuthorityList("ROLE_USER"));
this.mvc.perform(authRequest).andExpect(authenticatedAsUser);
}
@Test
public void requestWhenCustomAuthenticatedUserDetailsServiceInLambdaThenCustomAuthenticatedUserDetailsServiceUsed()
throws Exception {
this.spring.register(JeeCustomAuthenticatedUserDetailsServiceConfig.class).autowire();
Principal user = mock(Principal.class);
User userDetails = new User("user", "N/A", true, true, true, true,
AuthorityUtils.createAuthorityList("ROLE_USER"));
given(user.getName()).willReturn("user");
given(JeeCustomAuthenticatedUserDetailsServiceConfig.authenticationUserDetailsService.loadUserDetails(any()))
.willReturn(userDetails);
// @formatter:off
MockHttpServletRequestBuilder authRequest = get("/")
.principal(user)
.with((request) -> {
request.addUserRole("ROLE_ADMIN");
request.addUserRole("ROLE_USER");
return request;
});
// @formatter:on
this.mvc.perform(authRequest).andExpect(authenticated().withRoles("USER"));
}
@EnableWebSecurity
static class ObjectPostProcessorConfig extends WebSecurityConfigurerAdapter {
static ObjectPostProcessor<Object> objectPostProcessor;
@Override
@@ -90,33 +167,21 @@ public class JeeConfigurerTests {
static ObjectPostProcessor<Object> objectPostProcessor() {
return objectPostProcessor;
}
}
static class ReflectingObjectPostProcessor implements ObjectPostProcessor<Object> {
@Override
public <O> O postProcess(O object) {
return object;
}
}
@Test
public void jeeWhenInvokedTwiceThenUsesOriginalMappableRoles() throws Exception {
this.spring.register(InvokeTwiceDoesNotOverride.class).autowire();
Principal user = mock(Principal.class);
when(user.getName()).thenReturn("user");
this.mvc.perform(get("/")
.principal(user)
.with(request -> {
request.addUserRole("ROLE_ADMIN");
request.addUserRole("ROLE_USER");
return request;
}))
.andExpect(authenticated().withRoles("USER"));
}
@EnableWebSecurity
static class InvokeTwiceDoesNotOverride extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
@@ -127,56 +192,27 @@ public class JeeConfigurerTests {
.jee();
// @formatter:on
}
}
@Test
public void requestWhenJeeMappableRolesInLambdaThenAuthenticatedWithMappableRoles() throws Exception {
this.spring.register(JeeMappableRolesConfig.class).autowire();
Principal user = mock(Principal.class);
when(user.getName()).thenReturn("user");
this.mvc.perform(get("/")
.principal(user)
.with(request -> {
request.addUserRole("ROLE_ADMIN");
request.addUserRole("ROLE_USER");
return request;
}))
.andExpect(authenticated().withRoles("USER"));
}
@EnableWebSecurity
public static class JeeMappableRolesConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.authorizeRequests(authorizeRequests ->
.authorizeRequests((authorizeRequests) ->
authorizeRequests
.anyRequest().hasRole("USER")
)
.jee(jee ->
.jee((jee) ->
jee
.mappableRoles("USER")
);
// @formatter:on
}
}
@Test
public void requestWhenJeeMappableAuthoritiesInLambdaThenAuthenticatedWithMappableAuthorities() throws Exception {
this.spring.register(JeeMappableAuthoritiesConfig.class).autowire();
Principal user = mock(Principal.class);
when(user.getName()).thenReturn("user");
this.mvc.perform(get("/")
.principal(user)
.with(request -> {
request.addUserRole("ROLE_ADMIN");
request.addUserRole("ROLE_USER");
return request;
}))
.andExpect(authenticated().withAuthorities(AuthorityUtils.createAuthorityList("ROLE_USER")));
}
@EnableWebSecurity
@@ -186,57 +222,40 @@ public class JeeConfigurerTests {
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.authorizeRequests(authorizeRequests ->
.authorizeRequests((authorizeRequests) ->
authorizeRequests
.anyRequest().hasRole("USER")
)
.jee(jee ->
.jee((jee) ->
jee
.mappableAuthorities("ROLE_USER")
);
// @formatter:on
}
}
@Test
public void requestWhenCustomAuthenticatedUserDetailsServiceInLambdaThenCustomAuthenticatedUserDetailsServiceUsed()
throws Exception {
this.spring.register(JeeCustomAuthenticatedUserDetailsServiceConfig.class).autowire();
Principal user = mock(Principal.class);
User userDetails = new User("user", "N/A", true, true, true, true,
AuthorityUtils.createAuthorityList("ROLE_USER"));
when(user.getName()).thenReturn("user");
when(JeeCustomAuthenticatedUserDetailsServiceConfig.authenticationUserDetailsService.loadUserDetails(any()))
.thenReturn(userDetails);
this.mvc.perform(get("/")
.principal(user)
.with(request -> {
request.addUserRole("ROLE_ADMIN");
request.addUserRole("ROLE_USER");
return request;
}))
.andExpect(authenticated().withRoles("USER"));
}
@EnableWebSecurity
public static class JeeCustomAuthenticatedUserDetailsServiceConfig extends WebSecurityConfigurerAdapter {
static AuthenticationUserDetailsService authenticationUserDetailsService =
mock(AuthenticationUserDetailsService.class);
static AuthenticationUserDetailsService authenticationUserDetailsService = mock(
AuthenticationUserDetailsService.class);
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.authorizeRequests(authorizeRequests ->
.authorizeRequests((authorizeRequests) ->
authorizeRequests
.anyRequest().hasRole("USER")
)
.jee(jee ->
.jee((jee) ->
jee
.authenticatedUserDetailsService(authenticationUserDetailsService)
);
// @formatter:on
}
}
}

View File

@@ -29,22 +29,20 @@ import org.springframework.security.test.context.annotation.SecurityTestExecutio
import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.security.web.authentication.logout.HeaderWriterLogoutHandler;
import org.springframework.security.web.header.writers.ClearSiteDataHeaderWriter;
import org.springframework.security.web.header.writers.ClearSiteDataHeaderWriter.Directive;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
import static org.springframework.security.web.header.writers.ClearSiteDataHeaderWriter.Directive.CACHE;
import static org.springframework.security.web.header.writers.ClearSiteDataHeaderWriter.Directive.COOKIES;
import static org.springframework.security.web.header.writers.ClearSiteDataHeaderWriter.Directive.EXECUTION_CONTEXTS;
import static org.springframework.security.web.header.writers.ClearSiteDataHeaderWriter.Directive.STORAGE;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;
/**
*
* Tests for {@link HeaderWriterLogoutHandler} that passing {@link ClearSiteDataHeaderWriter}
* implementation.
* Tests for {@link HeaderWriterLogoutHandler} that passing
* {@link ClearSiteDataHeaderWriter} implementation.
*
* @author Rafiullah Hamedy
*
@@ -55,8 +53,8 @@ public class LogoutConfigurerClearSiteDataTests {
private static final String CLEAR_SITE_DATA_HEADER = "Clear-Site-Data";
private static final ClearSiteDataHeaderWriter.Directive[] SOURCE =
{ CACHE, COOKIES, STORAGE, EXECUTION_CONTEXTS };
private static final Directive[] SOURCE = { Directive.CACHE, Directive.COOKIES, Directive.STORAGE,
Directive.EXECUTION_CONTEXTS };
private static final String HEADER_VALUE = "\"cache\", \"cookies\", \"storage\", \"executionContexts\"";
@@ -70,36 +68,38 @@ public class LogoutConfigurerClearSiteDataTests {
@WithMockUser
public void logoutWhenRequestTypeGetThenHeaderNotPresentt() throws Exception {
this.spring.register(HttpLogoutConfig.class).autowire();
this.mvc.perform(get("/logout").secure(true).with(csrf()))
.andExpect(header().doesNotExist(CLEAR_SITE_DATA_HEADER));
MockHttpServletRequestBuilder logoutRequest = get("/logout").secure(true).with(csrf());
this.mvc.perform(logoutRequest).andExpect(header().doesNotExist(CLEAR_SITE_DATA_HEADER));
}
@Test
@WithMockUser
public void logoutWhenRequestTypePostAndNotSecureThenHeaderNotPresent() throws Exception {
this.spring.register(HttpLogoutConfig.class).autowire();
this.mvc.perform(post("/logout").with(csrf()))
.andExpect(header().doesNotExist(CLEAR_SITE_DATA_HEADER));
MockHttpServletRequestBuilder logoutRequest = post("/logout").with(csrf());
this.mvc.perform(logoutRequest).andExpect(header().doesNotExist(CLEAR_SITE_DATA_HEADER));
}
@Test
@WithMockUser
public void logoutWhenRequestTypePostAndSecureThenHeaderIsPresent() throws Exception {
this.spring.register(HttpLogoutConfig.class).autowire();
this.mvc.perform(post("/logout").secure(true).with(csrf()))
.andExpect(header().stringValues(CLEAR_SITE_DATA_HEADER, HEADER_VALUE));
MockHttpServletRequestBuilder logoutRequest = post("/logout").secure(true).with(csrf());
this.mvc.perform(logoutRequest).andExpect(header().stringValues(CLEAR_SITE_DATA_HEADER, HEADER_VALUE));
}
@EnableWebSecurity
static class HttpLogoutConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.logout()
.addLogoutHandler(new HeaderWriterLogoutHandler(new ClearSiteDataHeaderWriter(SOURCE)));
// @formatter:on
}
}
}

View File

@@ -19,6 +19,7 @@ package org.springframework.security.config.annotation.web.configurers;
import org.apache.http.HttpHeaders;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
@@ -34,8 +35,9 @@ import org.springframework.security.web.authentication.logout.LogoutFilter;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
@@ -65,13 +67,241 @@ public class LogoutConfigurerTests {
@Test
public void configureWhenDefaultLogoutSuccessHandlerForHasNullLogoutHandlerThenException() {
assertThatThrownBy(() -> this.spring.register(NullLogoutSuccessHandlerConfig.class).autowire())
.isInstanceOf(BeanCreationException.class)
.hasRootCauseInstanceOf(IllegalArgumentException.class);
assertThatExceptionOfType(BeanCreationException.class)
.isThrownBy(() -> this.spring.register(NullLogoutSuccessHandlerConfig.class).autowire())
.withRootCauseInstanceOf(IllegalArgumentException.class);
}
@Test
public void configureWhenDefaultLogoutSuccessHandlerForHasNullLogoutHandlerInLambdaThenException() {
assertThatExceptionOfType(BeanCreationException.class)
.isThrownBy(() -> this.spring.register(NullLogoutSuccessHandlerInLambdaConfig.class).autowire())
.withRootCauseInstanceOf(IllegalArgumentException.class);
}
@Test
public void configureWhenDefaultLogoutSuccessHandlerForHasNullMatcherThenException() {
assertThatExceptionOfType(BeanCreationException.class)
.isThrownBy(() -> this.spring.register(NullMatcherConfig.class).autowire())
.withRootCauseInstanceOf(IllegalArgumentException.class);
}
@Test
public void configureWhenDefaultLogoutSuccessHandlerForHasNullMatcherInLambdaThenException() {
assertThatExceptionOfType(BeanCreationException.class)
.isThrownBy(() -> this.spring.register(NullMatcherInLambdaConfig.class).autowire())
.withRootCauseInstanceOf(IllegalArgumentException.class);
}
@Test
public void configureWhenRegisteringObjectPostProcessorThenInvokedOnLogoutFilter() {
this.spring.register(ObjectPostProcessorConfig.class).autowire();
verify(ObjectPostProcessorConfig.objectPostProcessor).postProcess(any(LogoutFilter.class));
}
@Test
public void logoutWhenInvokedTwiceThenUsesOriginalLogoutUrl() throws Exception {
this.spring.register(DuplicateDoesNotOverrideConfig.class).autowire();
MockHttpServletRequestBuilder logoutRequest = post("/custom/logout").with(csrf());
// @formatter:off
this.mvc.perform(logoutRequest)
.andExpect(status().isFound())
.andExpect(redirectedUrl("/login?logout"));
// @formatter:on
}
// SEC-2311
@Test
public void logoutWhenGetRequestAndCsrfDisabledThenRedirectsToLogin() throws Exception {
this.spring.register(CsrfDisabledConfig.class).autowire();
// @formatter:off
this.mvc.perform(get("/logout"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("/login?logout"));
// @formatter:on
}
@Test
public void logoutWhenPostRequestAndCsrfDisabledThenRedirectsToLogin() throws Exception {
this.spring.register(CsrfDisabledConfig.class).autowire();
// @formatter:off
this.mvc.perform(post("/logout"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("/login?logout"));
// @formatter:on
}
@Test
public void logoutWhenPutRequestAndCsrfDisabledThenRedirectsToLogin() throws Exception {
this.spring.register(CsrfDisabledConfig.class).autowire();
// @formatter:off
this.mvc.perform(put("/logout"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("/login?logout"));
// @formatter:on
}
@Test
public void logoutWhenDeleteRequestAndCsrfDisabledThenRedirectsToLogin() throws Exception {
this.spring.register(CsrfDisabledConfig.class).autowire();
// @formatter:off
this.mvc.perform(delete("/logout"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("/login?logout"));
// @formatter:on
}
@Test
public void logoutWhenGetRequestAndCsrfDisabledAndCustomLogoutUrlThenRedirectsToLogin() throws Exception {
this.spring.register(CsrfDisabledAndCustomLogoutConfig.class).autowire();
// @formatter:off
this.mvc.perform(get("/custom/logout"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("/login?logout"));
// @formatter:on
}
@Test
public void logoutWhenPostRequestAndCsrfDisabledAndCustomLogoutUrlThenRedirectsToLogin() throws Exception {
this.spring.register(CsrfDisabledAndCustomLogoutConfig.class).autowire();
// @formatter:off
this.mvc.perform(post("/custom/logout"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("/login?logout"));
// @formatter:on
}
@Test
public void logoutWhenPutRequestAndCsrfDisabledAndCustomLogoutUrlThenRedirectsToLogin() throws Exception {
this.spring.register(CsrfDisabledAndCustomLogoutConfig.class).autowire();
// @formatter:off
this.mvc.perform(put("/custom/logout"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("/login?logout"));
// @formatter:on
}
@Test
public void logoutWhenDeleteRequestAndCsrfDisabledAndCustomLogoutUrlThenRedirectsToLogin() throws Exception {
this.spring.register(CsrfDisabledAndCustomLogoutConfig.class).autowire();
// @formatter:off
this.mvc.perform(delete("/custom/logout"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("/login?logout"));
// @formatter:on
}
@Test
public void logoutWhenCustomLogoutUrlInLambdaThenRedirectsToLogin() throws Exception {
this.spring.register(CsrfDisabledAndCustomLogoutInLambdaConfig.class).autowire();
// @formatter:off
this.mvc.perform(get("/custom/logout"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("/login?logout"));
// @formatter:on
}
// SEC-3170
@Test
public void configureWhenLogoutHandlerNullThenException() {
assertThatExceptionOfType(BeanCreationException.class)
.isThrownBy(() -> this.spring.register(NullLogoutHandlerConfig.class).autowire())
.withRootCauseInstanceOf(IllegalArgumentException.class);
}
@Test
public void configureWhenLogoutHandlerNullInLambdaThenException() {
assertThatExceptionOfType(BeanCreationException.class)
.isThrownBy(() -> this.spring.register(NullLogoutHandlerInLambdaConfig.class).autowire())
.withRootCauseInstanceOf(IllegalArgumentException.class);
}
// SEC-3170
@Test
public void rememberMeWhenRememberMeServicesNotLogoutHandlerThenRedirectsToLogin() throws Exception {
this.spring.register(RememberMeNoLogoutHandler.class).autowire();
this.mvc.perform(post("/logout").with(csrf())).andExpect(status().isFound())
.andExpect(redirectedUrl("/login?logout"));
}
@Test
public void logoutWhenAcceptTextHtmlThenRedirectsToLogin() throws Exception {
this.spring.register(BasicSecurityConfig.class).autowire();
// @formatter:off
MockHttpServletRequestBuilder logoutRequest = post("/logout")
.with(csrf())
.with(user("user"))
.header(HttpHeaders.ACCEPT, MediaType.TEXT_HTML_VALUE);
this.mvc.perform(logoutRequest)
.andExpect(status().isFound())
.andExpect(redirectedUrl("/login?logout"));
// @formatter:on
}
// gh-3282
@Test
public void logoutWhenAcceptApplicationJsonThenReturnsStatusNoContent() throws Exception {
this.spring.register(BasicSecurityConfig.class).autowire();
// @formatter:off
MockHttpServletRequestBuilder request = post("/logout")
.with(csrf())
.with(user("user"))
.header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE);
// @formatter:on
this.mvc.perform(request).andExpect(status().isNoContent());
}
// gh-4831
@Test
public void logoutWhenAcceptAllThenReturnsStatusNoContent() throws Exception {
this.spring.register(BasicSecurityConfig.class).autowire();
// @formatter:off
MockHttpServletRequestBuilder logoutRequest = post("/logout")
.with(csrf())
.with(user("user"))
.header(HttpHeaders.ACCEPT, MediaType.ALL_VALUE);
// @formatter:on
this.mvc.perform(logoutRequest).andExpect(status().isNoContent());
}
// gh-3902
@Test
public void logoutWhenAcceptFromChromeThenRedirectsToLogin() throws Exception {
this.spring.register(BasicSecurityConfig.class).autowire();
// @formatter:off
MockHttpServletRequestBuilder request = post("/logout")
.with(csrf())
.with(user("user"))
.header(HttpHeaders.ACCEPT, "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
this.mvc.perform(request)
.andExpect(status().isFound())
.andExpect(redirectedUrl("/login?logout"));
// @formatter:on
}
// gh-3997
@Test
public void logoutWhenXMLHttpRequestThenReturnsStatusNoContent() throws Exception {
this.spring.register(BasicSecurityConfig.class).autowire();
// @formatter:off
MockHttpServletRequestBuilder request = post("/logout")
.with(csrf())
.with(user("user"))
.header(HttpHeaders.ACCEPT, "text/html,application/json")
.header("X-Requested-With", "XMLHttpRequest");
// @formatter:on
this.mvc.perform(request).andExpect(status().isNoContent());
}
@Test
public void logoutWhenDisabledThenLogoutUrlNotFound() throws Exception {
this.spring.register(LogoutDisabledConfig.class).autowire();
this.mvc.perform(post("/logout").with(csrf())).andExpect(status().isNotFound());
}
@EnableWebSecurity
static class NullLogoutSuccessHandlerConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
@@ -80,37 +310,27 @@ public class LogoutConfigurerTests {
.defaultLogoutSuccessHandlerFor(null, mock(RequestMatcher.class));
// @formatter:on
}
}
@Test
public void configureWhenDefaultLogoutSuccessHandlerForHasNullLogoutHandlerInLambdaThenException() {
assertThatThrownBy(() -> this.spring.register(NullLogoutSuccessHandlerInLambdaConfig.class).autowire())
.isInstanceOf(BeanCreationException.class)
.hasRootCauseInstanceOf(IllegalArgumentException.class);
}
@EnableWebSecurity
static class NullLogoutSuccessHandlerInLambdaConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.logout(logout ->
.logout((logout) ->
logout.defaultLogoutSuccessHandlerFor(null, mock(RequestMatcher.class))
);
// @formatter:on
}
}
@Test
public void configureWhenDefaultLogoutSuccessHandlerForHasNullMatcherThenException() {
assertThatThrownBy(() -> this.spring.register(NullMatcherConfig.class).autowire())
.isInstanceOf(BeanCreationException.class)
.hasRootCauseInstanceOf(IllegalArgumentException.class);
}
@EnableWebSecurity
static class NullMatcherConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
@@ -119,38 +339,27 @@ public class LogoutConfigurerTests {
.defaultLogoutSuccessHandlerFor(mock(LogoutSuccessHandler.class), null);
// @formatter:on
}
}
@Test
public void configureWhenDefaultLogoutSuccessHandlerForHasNullMatcherInLambdaThenException() {
assertThatThrownBy(() -> this.spring.register(NullMatcherInLambdaConfig.class).autowire())
.isInstanceOf(BeanCreationException.class)
.hasRootCauseInstanceOf(IllegalArgumentException.class);
}
@EnableWebSecurity
static class NullMatcherInLambdaConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.logout(logout ->
.logout((logout) ->
logout.defaultLogoutSuccessHandlerFor(mock(LogoutSuccessHandler.class), null)
);
// @formatter:on
}
}
@Test
public void configureWhenRegisteringObjectPostProcessorThenInvokedOnLogoutFilter() {
this.spring.register(ObjectPostProcessorConfig.class).autowire();
verify(ObjectPostProcessorConfig.objectPostProcessor)
.postProcess(any(LogoutFilter.class));
}
@EnableWebSecurity
static class ObjectPostProcessorConfig extends WebSecurityConfigurerAdapter {
static ObjectPostProcessor<Object> objectPostProcessor = spy(ReflectingObjectPostProcessor.class);
@Override
@@ -165,27 +374,21 @@ public class LogoutConfigurerTests {
static ObjectPostProcessor<Object> objectPostProcessor() {
return objectPostProcessor;
}
}
static class ReflectingObjectPostProcessor implements ObjectPostProcessor<Object> {
@Override
public <O> O postProcess(O object) {
return object;
}
}
@Test
public void logoutWhenInvokedTwiceThenUsesOriginalLogoutUrl() throws Exception {
this.spring.register(DuplicateDoesNotOverrideConfig.class).autowire();
this.mvc.perform(post("/custom/logout")
.with(csrf()))
.andExpect(status().isFound())
.andExpect(redirectedUrl("/login?logout"));
}
@EnableWebSecurity
static class DuplicateDoesNotOverrideConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
@@ -204,43 +407,7 @@ public class LogoutConfigurerTests {
.inMemoryAuthentication();
// @formatter:on
}
}
// SEC-2311
@Test
public void logoutWhenGetRequestAndCsrfDisabledThenRedirectsToLogin() throws Exception {
this.spring.register(CsrfDisabledConfig.class).autowire();
this.mvc.perform(get("/logout"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("/login?logout"));
}
@Test
public void logoutWhenPostRequestAndCsrfDisabledThenRedirectsToLogin() throws Exception {
this.spring.register(CsrfDisabledConfig.class).autowire();
this.mvc.perform(post("/logout"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("/login?logout"));
}
@Test
public void logoutWhenPutRequestAndCsrfDisabledThenRedirectsToLogin() throws Exception {
this.spring.register(CsrfDisabledConfig.class).autowire();
this.mvc.perform(put("/logout"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("/login?logout"));
}
@Test
public void logoutWhenDeleteRequestAndCsrfDisabledThenRedirectsToLogin() throws Exception {
this.spring.register(CsrfDisabledConfig.class).autowire();
this.mvc.perform(delete("/logout"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("/login?logout"));
}
@EnableWebSecurity
@@ -255,42 +422,7 @@ public class LogoutConfigurerTests {
.logout();
// @formatter:on
}
}
@Test
public void logoutWhenGetRequestAndCsrfDisabledAndCustomLogoutUrlThenRedirectsToLogin() throws Exception {
this.spring.register(CsrfDisabledAndCustomLogoutConfig.class).autowire();
this.mvc.perform(get("/custom/logout"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("/login?logout"));
}
@Test
public void logoutWhenPostRequestAndCsrfDisabledAndCustomLogoutUrlThenRedirectsToLogin() throws Exception {
this.spring.register(CsrfDisabledAndCustomLogoutConfig.class).autowire();
this.mvc.perform(post("/custom/logout"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("/login?logout"));
}
@Test
public void logoutWhenPutRequestAndCsrfDisabledAndCustomLogoutUrlThenRedirectsToLogin() throws Exception {
this.spring.register(CsrfDisabledAndCustomLogoutConfig.class).autowire();
this.mvc.perform(put("/custom/logout"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("/login?logout"));
}
@Test
public void logoutWhenDeleteRequestAndCsrfDisabledAndCustomLogoutUrlThenRedirectsToLogin() throws Exception {
this.spring.register(CsrfDisabledAndCustomLogoutConfig.class).autowire();
this.mvc.perform(delete("/custom/logout"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("/login?logout"));
}
@EnableWebSecurity
@@ -306,15 +438,7 @@ public class LogoutConfigurerTests {
.logoutUrl("/custom/logout");
// @formatter:on
}
}
@Test
public void logoutWhenCustomLogoutUrlInLambdaThenRedirectsToLogin() throws Exception {
this.spring.register(CsrfDisabledAndCustomLogoutInLambdaConfig.class).autowire();
this.mvc.perform(get("/custom/logout"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("/login?logout"));
}
@EnableWebSecurity
@@ -326,21 +450,15 @@ public class LogoutConfigurerTests {
http
.csrf()
.disable()
.logout(logout -> logout.logoutUrl("/custom/logout"));
.logout((logout) -> logout.logoutUrl("/custom/logout"));
// @formatter:on
}
}
// SEC-3170
@Test
public void configureWhenLogoutHandlerNullThenException() {
assertThatThrownBy(() -> this.spring.register(NullLogoutHandlerConfig.class).autowire())
.isInstanceOf(BeanCreationException.class)
.hasRootCauseInstanceOf(IllegalArgumentException.class);
}
@EnableWebSecurity
static class NullLogoutHandlerConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
@@ -349,39 +467,25 @@ public class LogoutConfigurerTests {
.addLogoutHandler(null);
// @formatter:on
}
}
@Test
public void configureWhenLogoutHandlerNullInLambdaThenException() {
assertThatThrownBy(() -> this.spring.register(NullLogoutHandlerInLambdaConfig.class).autowire())
.isInstanceOf(BeanCreationException.class)
.hasRootCauseInstanceOf(IllegalArgumentException.class);
}
@EnableWebSecurity
static class NullLogoutHandlerInLambdaConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.logout(logout -> logout.addLogoutHandler(null));
.logout((logout) -> logout.addLogoutHandler(null));
// @formatter:on
}
}
// SEC-3170
@Test
public void rememberMeWhenRememberMeServicesNotLogoutHandlerThenRedirectsToLogin() throws Exception {
this.spring.register(RememberMeNoLogoutHandler.class).autowire();
this.mvc.perform(post("/logout")
.with(csrf()))
.andExpect(status().isFound())
.andExpect(redirectedUrl("/login?logout"));
}
@EnableWebSecurity
static class RememberMeNoLogoutHandler extends WebSecurityConfigurerAdapter {
static RememberMeServices REMEMBER_ME = mock(RememberMeServices.class);
@Override
@@ -392,84 +496,17 @@ public class LogoutConfigurerTests {
.rememberMeServices(REMEMBER_ME);
// @formatter:on
}
}
@Test
public void logoutWhenAcceptTextHtmlThenRedirectsToLogin() throws Exception {
this.spring.register(BasicSecurityConfig.class).autowire();
this.mvc.perform(post("/logout")
.with(csrf())
.with(user("user"))
.header(HttpHeaders.ACCEPT, MediaType.TEXT_HTML_VALUE))
.andExpect(status().isFound())
.andExpect(redirectedUrl("/login?logout"));
}
// gh-3282
@Test
public void logoutWhenAcceptApplicationJsonThenReturnsStatusNoContent() throws Exception {
this.spring.register(BasicSecurityConfig.class).autowire();
this.mvc.perform(post("/logout")
.with(csrf())
.with(user("user"))
.header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE))
.andExpect(status().isNoContent());
}
// gh-4831
@Test
public void logoutWhenAcceptAllThenReturnsStatusNoContent() throws Exception {
this.spring.register(BasicSecurityConfig.class).autowire();
this.mvc.perform(post("/logout")
.with(csrf())
.with(user("user"))
.header(HttpHeaders.ACCEPT, MediaType.ALL_VALUE))
.andExpect(status().isNoContent());
}
// gh-3902
@Test
public void logoutWhenAcceptFromChromeThenRedirectsToLogin() throws Exception {
this.spring.register(BasicSecurityConfig.class).autowire();
this.mvc.perform(post("/logout")
.with(csrf()).with(user("user"))
.header(HttpHeaders.ACCEPT, "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("/login?logout"));
}
// gh-3997
@Test
public void logoutWhenXMLHttpRequestThenReturnsStatusNoContent() throws Exception {
this.spring.register(BasicSecurityConfig.class).autowire();
this.mvc.perform(post("/logout")
.with(csrf())
.with(user("user"))
.header(HttpHeaders.ACCEPT, "text/html,application/json")
.header("X-Requested-With", "XMLHttpRequest"))
.andExpect(status().isNoContent());
}
@EnableWebSecurity
static class BasicSecurityConfig extends WebSecurityConfigurerAdapter {
}
@Test
public void logoutWhenDisabledThenLogoutUrlNotFound() throws Exception {
this.spring.register(LogoutDisabledConfig.class).autowire();
this.mvc.perform(post("/logout")
.with(csrf()))
.andExpect(status().isNotFound());
}
@EnableWebSecurity
static class LogoutDisabledConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
@@ -478,5 +515,7 @@ public class LogoutConfigurerTests {
.disable();
// @formatter:on
}
}
}

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.configurers;
import ch.qos.logback.classic.Level;
@@ -45,6 +46,7 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilder
* @author Josh Cummings
*/
public class NamespaceDebugTests {
@Rule
public final SpringTestRule spring = new SpringTestRule();
@@ -60,10 +62,6 @@ public class NamespaceDebugTests {
verify(appender, atLeastOnce()).doAppend(any(ILoggingEvent.class));
}
@EnableWebSecurity(debug=true)
static class DebugWebSecurity extends WebSecurityConfigurerAdapter {
}
@Test
public void requestWhenDebugSetToFalseThenDoesNotLogDebugInformation() throws Exception {
Appender<ILoggingEvent> appender = mockAppenderFor("Spring Security Debugger");
@@ -73,10 +71,6 @@ public class NamespaceDebugTests {
verify(appender, never()).doAppend(any(ILoggingEvent.class));
}
@EnableWebSecurity
static class NoDebugWebSecurity extends WebSecurityConfigurerAdapter {
}
private Appender<ILoggingEvent> mockAppenderFor(String name) {
Appender<ILoggingEvent> appender = mock(Appender.class);
Logger logger = (Logger) LoggerFactory.getLogger(name);
@@ -88,4 +82,15 @@ public class NamespaceDebugTests {
private Class<?> filterChainClass() {
return this.spring.getContext().getBean("springSecurityFilterChain").getClass();
}
@EnableWebSecurity(debug = true)
static class DebugWebSecurity extends WebSecurityConfigurerAdapter {
}
@EnableWebSecurity
static class NoDebugWebSecurity extends WebSecurityConfigurerAdapter {
}
}

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.configurers;
import java.util.Optional;
@@ -39,7 +40,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
/**
* Tests to verify that all the functionality of <anonymous> attributes is present
* Tests to verify that all the functionality of &lt;anonymous&gt; attributes is present
*
* @author Rob Winch
* @author Josh Cummings
@@ -57,12 +58,36 @@ public class NamespaceHttpAnonymousTests {
public void anonymousRequestWhenUsingDefaultAnonymousConfigurationThenUsesAnonymousAuthentication()
throws Exception {
this.spring.register(AnonymousConfig.class, AnonymousController.class).autowire();
this.mvc.perform(get("/type"))
.andExpect(content().string(AnonymousAuthenticationToken.class.getSimpleName()));
this.mvc.perform(get("/type")).andExpect(content().string(AnonymousAuthenticationToken.class.getSimpleName()));
}
@Test
public void anonymousRequestWhenDisablingAnonymousThenDenies() throws Exception {
this.spring.register(AnonymousDisabledConfig.class, AnonymousController.class).autowire();
this.mvc.perform(get("/type")).andExpect(status().isForbidden());
}
@Test
public void requestWhenAnonymousThenSendsAnonymousConfiguredAuthorities() throws Exception {
this.spring.register(AnonymousGrantedAuthorityConfig.class, AnonymousController.class).autowire();
this.mvc.perform(get("/type")).andExpect(content().string(AnonymousAuthenticationToken.class.getSimpleName()));
}
@Test
public void anonymousRequestWhenAnonymousKeyConfiguredThenKeyIsUsed() throws Exception {
this.spring.register(AnonymousKeyConfig.class, AnonymousController.class).autowire();
this.mvc.perform(get("/key")).andExpect(content().string(String.valueOf("AnonymousKeyConfig".hashCode())));
}
@Test
public void anonymousRequestWhenAnonymousUsernameConfiguredThenUsernameIsUsed() throws Exception {
this.spring.register(AnonymousUsernameConfig.class, AnonymousController.class).autowire();
this.mvc.perform(get("/principal")).andExpect(content().string("AnonymousUsernameConfig"));
}
@EnableWebSecurity
static class AnonymousConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
@@ -72,18 +97,12 @@ public class NamespaceHttpAnonymousTests {
.anyRequest().denyAll();
// @formatter:on
}
}
@Test
public void anonymousRequestWhenDisablingAnonymousThenDenies()
throws Exception {
this.spring.register(AnonymousDisabledConfig.class, AnonymousController.class).autowire();
this.mvc.perform(get("/type"))
.andExpect(status().isForbidden());
}
@EnableWebSecurity
static class AnonymousDisabledConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
@@ -95,6 +114,7 @@ public class NamespaceHttpAnonymousTests {
// @formatter:on
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// @formatter:off
auth
@@ -103,18 +123,12 @@ public class NamespaceHttpAnonymousTests {
.withUser(PasswordEncodedUser.admin());
// @formatter:on
}
}
@Test
public void requestWhenAnonymousThenSendsAnonymousConfiguredAuthorities()
throws Exception {
this.spring.register(AnonymousGrantedAuthorityConfig.class, AnonymousController.class).autowire();
this.mvc.perform(get("/type"))
.andExpect(content().string(AnonymousAuthenticationToken.class.getSimpleName()));
}
@EnableWebSecurity
static class AnonymousGrantedAuthorityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
@@ -127,17 +141,12 @@ public class NamespaceHttpAnonymousTests {
.authorities("ROLE_ANON");
// @formatter:on
}
}
@Test
public void anonymousRequestWhenAnonymousKeyConfiguredThenKeyIsUsed() throws Exception {
this.spring.register(AnonymousKeyConfig.class, AnonymousController.class).autowire();
this.mvc.perform(get("/key"))
.andExpect(content().string(String.valueOf("AnonymousKeyConfig".hashCode())));
}
@EnableWebSecurity
static class AnonymousKeyConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
@@ -149,17 +158,12 @@ public class NamespaceHttpAnonymousTests {
.anonymous().key("AnonymousKeyConfig");
// @formatter:on
}
}
@Test
public void anonymousRequestWhenAnonymousUsernameConfiguredThenUsernameIsUsed() throws Exception {
this.spring.register(AnonymousUsernameConfig.class, AnonymousController.class).autowire();
this.mvc.perform(get("/principal"))
.andExpect(content().string("AnonymousUsernameConfig"));
}
@EnableWebSecurity
static class AnonymousUsernameConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
@@ -171,39 +175,33 @@ public class NamespaceHttpAnonymousTests {
.anonymous().principal("AnonymousUsernameConfig");
// @formatter:on
}
}
@RestController
static class AnonymousController {
@GetMapping("/type")
String type() {
return anonymousToken()
.map(AnonymousAuthenticationToken::getClass)
.map(Class::getSimpleName)
.orElse(null);
return anonymousToken().map(AnonymousAuthenticationToken::getClass).map(Class::getSimpleName).orElse(null);
}
@GetMapping("/key")
String key() {
return anonymousToken()
.map(AnonymousAuthenticationToken::getKeyHash)
.map(String::valueOf)
.orElse(null);
return anonymousToken().map(AnonymousAuthenticationToken::getKeyHash).map(String::valueOf).orElse(null);
}
@GetMapping("/principal")
String principal() {
return anonymousToken()
.map(AnonymousAuthenticationToken::getName)
.orElse(null);
return anonymousToken().map(AnonymousAuthenticationToken::getName).orElse(null);
}
Optional<AnonymousAuthenticationToken> anonymousToken() {
return Optional.of(SecurityContextHolder.getContext())
.map(SecurityContext::getAuthentication)
.filter(a -> a instanceof AnonymousAuthenticationToken)
return Optional.of(SecurityContextHolder.getContext()).map(SecurityContext::getAuthentication)
.filter((a) -> a instanceof AnonymousAuthenticationToken)
.map(AnonymousAuthenticationToken.class::cast);
}
}
}

Some files were not shown because too many files have changed in this diff Show More