Merge Formatting Changes
Issue gh-8945
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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>() {
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
* <http>
|
||||
* <intercept-url pattern="/resources/**" access="permitAll"/>
|
||||
* <intercept-url pattern="/**" access="authenticated"/>
|
||||
* <logout
|
||||
* logout-success-url="/login?logout"
|
||||
* logout-url="/logout"
|
||||
* <form-login
|
||||
* <form-login
|
||||
* authentication-failure-url="/login?error"
|
||||
* login-page="/login"
|
||||
* login-processing-url="/login" <!-- but only POST -->
|
||||
* 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 username="admin" password="password" authorities="ROLE_USER,ROLE_ADMIN"/>
|
||||
* </user-service>
|
||||
* </authentication-provider>
|
||||
* </authentication-manager>
|
||||
* </code>
|
||||
* />
|
||||
* </http>
|
||||
* <authentication-manager>
|
||||
* <authentication-provider>
|
||||
* <user-service>
|
||||
* <user username="user" password="password" authorities="ROLE_USER"/>
|
||||
* </user-service>
|
||||
* </authentication-provider>
|
||||
* </authentication-manager>
|
||||
* </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>
|
||||
* <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
|
||||
* logout-success-url="/login?logout"
|
||||
* logout-url="/logout"
|
||||
* <form-login
|
||||
* authentication-failure-url="/login?error"
|
||||
* login-page="/login"
|
||||
* 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 username="admin" password="password" authorities=
|
||||
"ROLE_USER,ROLE_ADMIN"/>
|
||||
* </user-service>
|
||||
* </authentication-provider>
|
||||
* </authentication-manager>
|
||||
* </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
|
||||
* <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
|
||||
* logout-success-url="/login?logout"
|
||||
* logout-url="/logout"
|
||||
* <form-login
|
||||
* <form-login
|
||||
* authentication-failure-url="/login?error"
|
||||
* login-page="/login"
|
||||
* login-processing-url="/login" <!-- but only POST -->
|
||||
* 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 username="admin" password="password" authorities="ROLE_USER,ROLE_ADMIN"/>
|
||||
* </user-service>
|
||||
* </authentication-provider>
|
||||
* </authentication-manager>
|
||||
* />
|
||||
* </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>
|
||||
*
|
||||
* @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
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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 <http> 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();
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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"));
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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 <anonymous> 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
Reference in New Issue
Block a user