();
+ for(String role : withUser.roles()) {
+ if(role.startsWith("ROLE_")) {
+ throw new IllegalArgumentException("roles cannot start with ROLE_ Got " + role);
+ }
+ authorities.add(new SimpleGrantedAuthority("ROLE_"+role));
+ }
+ User principal = new User(username, withUser.password(), true, true, true, true, authorities);
+ Authentication authentication = new UsernamePasswordAuthenticationToken(principal, principal.getPassword(), principal.getAuthorities());
+ SecurityContext context = SecurityContextHolder.createEmptyContext();
+ context.setAuthentication(authentication);
+ return context;
+ }
+}
\ No newline at end of file
diff --git a/test/src/main/java/org/springframework/security/test/context/support/WithSecurityContext.java b/test/src/main/java/org/springframework/security/test/context/support/WithSecurityContext.java
new file mode 100644
index 0000000000..81e8345e5c
--- /dev/null
+++ b/test/src/main/java/org/springframework/security/test/context/support/WithSecurityContext.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2002-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.security.test.context.support;
+
+import java.lang.annotation.Annotation;
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.core.context.SecurityContext;
+
+/**
+ *
+ * An annotation to determine what {@link SecurityContext} to use. The
+ * {@link #factory()} attribute must be provided with an instance of
+ * {@link WithUserDetailsSecurityContextFactory}.
+ *
+ *
+ *
+ * Typically this annotation will be used as an meta-annotation as done with
+ * {@link WithMockUser} and {@link WithUserDetails}.
+ *
+ *
+ *
+ * If you would like to create your own implementation of
+ * {@link WithSecurityContextFactory} you can do so by implementing the
+ * interface. You can also use {@link Autowired} and other Spring semantics on
+ * the {@link WithSecurityContextFactory} implementation.
+ *
+ *
+ * @author Rob Winch
+ * @since 4.0
+ */
+@Target({ElementType.ANNOTATION_TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Inherited
+@Documented
+public @interface WithSecurityContext {
+ /**
+ * The {@link WithUserDetailsSecurityContextFactory} to use to create the {@link SecurityContext}. It can contain {@link Autowired} and other Spring annotations.
+ *
+ * @return
+ */
+ Class extends WithSecurityContextFactory extends Annotation>> factory();
+}
\ No newline at end of file
diff --git a/test/src/main/java/org/springframework/security/test/context/support/WithSecurityContextFactory.java b/test/src/main/java/org/springframework/security/test/context/support/WithSecurityContextFactory.java
new file mode 100644
index 0000000000..5cbd656c6d
--- /dev/null
+++ b/test/src/main/java/org/springframework/security/test/context/support/WithSecurityContextFactory.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2002-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.security.test.context.support;
+
+import java.lang.annotation.Annotation;
+
+import org.springframework.security.core.context.SecurityContext;
+import org.springframework.security.test.context.TestSecurityContextHolder;
+
+/**
+ * An API that works with WithUserTestExcecutionListener for creating a
+ * {@link SecurityContext} that is populated in the
+ * {@link TestSecurityContextHolder}.
+ *
+ * @author Rob Winch
+ *
+ * @param
+ * @see WithSecurityContext
+ * @see WithMockUser
+ * @see WithUserDetails
+ * @since 4.0
+ */
+public interface WithSecurityContextFactory {
+
+ /**
+ * Create a {@link SecurityContext} given an Annotation.
+ *
+ * @param annotation
+ * the {@link Annotation} to create the {@link SecurityContext}
+ * from. Cannot be null.
+ * @return the {@link SecurityContext} to use. Cannot be null.
+ */
+ SecurityContext createSecurityContext(A annotation);
+}
\ No newline at end of file
diff --git a/test/src/main/java/org/springframework/security/test/context/support/WithSecurityContextTestExcecutionListener.java b/test/src/main/java/org/springframework/security/test/context/support/WithSecurityContextTestExcecutionListener.java
new file mode 100644
index 0000000000..8e64727c40
--- /dev/null
+++ b/test/src/main/java/org/springframework/security/test/context/support/WithSecurityContextTestExcecutionListener.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2002-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.security.test.context.support;
+
+import java.lang.annotation.Annotation;
+
+import org.springframework.context.ApplicationContext;
+import org.springframework.core.annotation.AnnotationUtils;
+import org.springframework.security.core.context.SecurityContext;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.test.context.TestSecurityContextHolder;
+import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors;
+import org.springframework.test.context.TestContext;
+import org.springframework.test.context.TestExecutionListener;
+import org.springframework.test.context.support.AbstractTestExecutionListener;
+import org.springframework.test.web.servlet.MockMvc;
+
+/**
+ * A {@link TestExecutionListener} that will find annotations that are annotated
+ * with {@link WithSecurityContext} on a test method or at the class level. If found, the
+ * {@link WithSecurityContext#factory()} is used to create a {@link SecurityContext} that
+ * will be used with this test. If using with {@link MockMvc} the
+ * {@link SecurityMockMvcRequestPostProcessors#testSecurityContext()} needs to be used
+ * too.
+ *
+ * @author Rob Winch
+ * @since 4.0
+ */
+public class WithSecurityContextTestExcecutionListener extends
+ AbstractTestExecutionListener {
+
+ /**
+ * Sets up the {@link SecurityContext} for each test method. First the
+ * specific method is inspected for a {@link WithSecurityContext} or {@link Annotation}
+ * that has {@link WithSecurityContext} on it. If that is not found, the class is
+ * inspected. If still not found, then no {@link SecurityContext} is
+ * populated.
+ */
+ @Override
+ public void beforeTestMethod(TestContext testContext) throws Exception {
+ Annotation[] methodAnnotations = AnnotationUtils
+ .getAnnotations(testContext.getTestMethod());
+ ApplicationContext context = testContext.getApplicationContext();
+ SecurityContext securityContext = createSecurityContext(
+ methodAnnotations, context);
+ if (securityContext == null) {
+ Annotation[] classAnnotations = testContext.getTestClass()
+ .getAnnotations();
+ securityContext = createSecurityContext(classAnnotations, context);
+ }
+ if (securityContext != null) {
+ TestSecurityContextHolder.setContext(securityContext);
+ }
+ }
+
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ private SecurityContext createSecurityContext(Annotation[] annotations,
+ ApplicationContext context) {
+ for (Annotation a : annotations) {
+ WithSecurityContext withUser = AnnotationUtils.findAnnotation(
+ a.annotationType(), WithSecurityContext.class);
+ if (withUser != null) {
+ WithSecurityContextFactory factory = createFactory(
+ withUser, context);
+ try {
+ return factory.createSecurityContext(a);
+ } catch (RuntimeException e) {
+ throw new IllegalStateException("Unable to create SecurityContext using "+ a, e);
+ }
+ }
+ }
+ return null;
+ }
+
+ private WithSecurityContextFactory extends Annotation> createFactory(
+ WithSecurityContext withUser, ApplicationContext context) {
+ Class extends WithSecurityContextFactory extends Annotation>> clazz = withUser
+ .factory();
+ try {
+ return context.getAutowireCapableBeanFactory().createBean(clazz);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Clears out the {@link TestSecurityContextHolder} and the
+ * {@link SecurityContextHolder} after each test method.
+ */
+ @Override
+ public void afterTestMethod(TestContext testContext) throws Exception {
+ TestSecurityContextHolder.clearContext();
+ }
+}
\ No newline at end of file
diff --git a/test/src/main/java/org/springframework/security/test/context/support/WithUserDetails.java b/test/src/main/java/org/springframework/security/test/context/support/WithUserDetails.java
new file mode 100644
index 0000000000..15c4eb6eb2
--- /dev/null
+++ b/test/src/main/java/org/springframework/security/test/context/support/WithUserDetails.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2002-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.security.test.context.support;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.context.SecurityContext;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.test.web.servlet.MockMvc;
+
+/**
+ * When used with {@link WithSecurityContextTestExcecutionListener} this annotation can be
+ * added to a test method to emulate running with a {@link UserDetails} returned
+ * from the {@link UserDetailsService}. In order to work with {@link MockMvc}
+ * The {@link SecurityContext} that is used will have the following properties:
+ *
+ *
+ * - The {@link SecurityContext} created with be that of
+ * {@link SecurityContextHolder#createEmptyContext()}
+ * - It will be populated with an {@link UsernamePasswordAuthenticationToken}
+ * that uses the username of either {@link #value()} or {@link #username()},
+ * {@link GrantedAuthority} that are specified by {@link #roles()}, and a
+ * password specified by {@link #password()}.
+ *
+ *
+ * @see WithMockUser
+ *
+ * @author Rob Winch
+ * @since 4.0
+ */
+@Target({ElementType.METHOD, ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Inherited
+@Documented
+@WithSecurityContext(factory=WithUserDetailsSecurityContextFactory.class)
+public @interface WithUserDetails {
+ /**
+ * The username to look up in the {@link UserDetailsService}
+ *
+ * @return
+ */
+ String value() default "user";
+}
\ No newline at end of file
diff --git a/test/src/main/java/org/springframework/security/test/context/support/WithUserDetailsSecurityContextFactory.java b/test/src/main/java/org/springframework/security/test/context/support/WithUserDetailsSecurityContextFactory.java
new file mode 100644
index 0000000000..b3b05bb5af
--- /dev/null
+++ b/test/src/main/java/org/springframework/security/test/context/support/WithUserDetailsSecurityContextFactory.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2002-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.security.test.context.support;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContext;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.util.Assert;
+
+/**
+ * A {@link WithUserDetailsSecurityContextFactory} that works with {@link WithUserDetails}.
+ *
+ * @see WithUserDetails
+ *
+ * @author Rob Winch
+ * @since 4.0
+ */
+
+final class WithUserDetailsSecurityContextFactory implements WithSecurityContextFactory {
+
+ private UserDetailsService userDetailsService;
+
+ @Autowired
+ public WithUserDetailsSecurityContextFactory(UserDetailsService userDetailsService) {
+ this.userDetailsService = userDetailsService;
+ }
+
+ public SecurityContext createSecurityContext(WithUserDetails withUser) {
+ String username = withUser.value();
+ Assert.hasLength(username, "value() must be non empty String");
+ UserDetails principal = userDetailsService.loadUserByUsername(username);
+ Authentication authentication = new UsernamePasswordAuthenticationToken(principal, principal.getPassword(), principal.getAuthorities());
+ SecurityContext context = SecurityContextHolder.createEmptyContext();
+ context.setAuthentication(authentication);
+ return context;
+ }
+}
\ No newline at end of file
diff --git a/test/src/main/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestBuilders.java b/test/src/main/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestBuilders.java
new file mode 100644
index 0000000000..92e0979790
--- /dev/null
+++ b/test/src/main/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestBuilders.java
@@ -0,0 +1,213 @@
+/*
+ * Copyright 2002-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.security.test.web.servlet.request;
+
+import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
+
+import javax.servlet.ServletContext;
+
+import org.springframework.mock.web.MockHttpServletRequest;
+import org.springframework.security.web.csrf.CsrfToken;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.RequestBuilder;
+import org.springframework.test.web.servlet.request.RequestPostProcessor;
+
+/**
+ * Contains Spring Security related {@link MockMvc} {@link RequestBuilder}s.
+ *
+ * @author Rob Winch
+ * @since 4.0
+ *
+ */
+public final class SecurityMockMvcRequestBuilders {
+
+ /**
+ * Creates a request (including any necessary {@link CsrfToken}) that will
+ * submit a form based login to POST "/login".
+ *
+ * @return the FormLoginRequestBuilder for further customizations
+ */
+ public static FormLoginRequestBuilder formLogin() {
+ return new FormLoginRequestBuilder();
+ }
+
+ /**
+ * Creates a request (including any necessary {@link CsrfToken}) that will
+ * submit a form based login to POST {@code loginProcessingUrl}.
+ *
+ * @param loginProcessingUrl
+ * the URL to POST to
+ *
+ * @return the FormLoginRequestBuilder for further customizations
+ */
+ public static FormLoginRequestBuilder formLogin(String loginProcessingUrl) {
+ return formLogin().loginProcessingUrl(loginProcessingUrl);
+ }
+
+ /**
+ * Creates a logout request.
+ *
+ * @return the LogoutRequestBuilder for additional customizations
+ */
+ public static LogoutRequestBuilder logout() {
+ return new LogoutRequestBuilder();
+ }
+
+ /**
+ * Creates a logout request (including any necessary {@link CsrfToken}) to
+ * the specified {@code logoutUrl}
+ *
+ * @return the LogoutRequestBuilder for additional customizations
+ */
+ public static LogoutRequestBuilder logout(String logoutUrl) {
+ return new LogoutRequestBuilder().logoutUrl(logoutUrl);
+ }
+
+ /**
+ * Creates a logout request (including any necessary {@link CsrfToken})
+ *
+ * @author Rob Winch
+ * @since 4.0
+ */
+ public static final class LogoutRequestBuilder implements RequestBuilder {
+ private String logoutUrl = "/logout";
+ private RequestPostProcessor postProcessor = csrf();
+
+ public MockHttpServletRequest buildRequest(ServletContext servletContext) {
+ MockHttpServletRequest request = post(logoutUrl)
+ .buildRequest(servletContext);
+ return postProcessor.postProcessRequest(request);
+ }
+
+ /**
+ * Specifies the logout URL to POST to. Defaults to "/logout".
+ *
+ * @param logoutUrl the logout URL to POST to. Defaults to "/logout".
+ * @return the {@link LogoutRequestBuilder} for additional customizations
+ */
+ public LogoutRequestBuilder logoutUrl(String logoutUrl) {
+ this.logoutUrl = logoutUrl;
+ return this;
+ }
+
+ private LogoutRequestBuilder() {}
+ }
+
+ /**
+ * Creates a form based login request including any necessary {@link CsrfToken}.
+ *
+ * @author Rob Winch
+ * @since 4.0
+ */
+ public static final class FormLoginRequestBuilder implements RequestBuilder {
+ private String usernameParam = "username";
+ private String passwordParam = "password";
+ private String username = "user";
+ private String password = "password";
+ private String loginProcessingUrl = "/login";
+ private RequestPostProcessor postProcessor = csrf();
+
+ public MockHttpServletRequest buildRequest(ServletContext servletContext) {
+ MockHttpServletRequest request = post(loginProcessingUrl)
+ .param(usernameParam,username)
+ .param(passwordParam, password)
+ .buildRequest(servletContext);
+ return postProcessor.postProcessRequest(request);
+ }
+
+ /**
+ * Specifies the URL to POST to. Default is "/login"
+ *
+ * @param loginProcessingUrl the URL to POST to. Default is "/login"
+ * @return
+ */
+ public FormLoginRequestBuilder loginProcessingUrl(String loginProcessingUrl) {
+ this.loginProcessingUrl = loginProcessingUrl;
+ return this;
+ }
+
+ /**
+ * The HTTP parameter to place the username. Default is "username".
+ * @param usernameParameter the HTTP parameter to place the username. Default is "username".
+ * @return the {@link FormLoginRequestBuilder} for additional customizations
+ */
+ public FormLoginRequestBuilder userParameter(String usernameParameter) {
+ this.usernameParam = usernameParameter;
+ return this;
+ }
+
+ /**
+ * The HTTP parameter to place the password. Default is "password".
+ * @param passwordParameter the HTTP parameter to place the password. Default is "password".
+ * @return the {@link FormLoginRequestBuilder} for additional customizations
+ */
+ public FormLoginRequestBuilder passwordParam(String passwordParameter) {
+ this.passwordParam = passwordParameter;
+ return this;
+ }
+
+ /**
+ * The value of the password parameter. Default is "password".
+ * @param password the value of the password parameter. Default is "password".
+ * @return the {@link FormLoginRequestBuilder} for additional customizations
+ */
+ public FormLoginRequestBuilder password(String password) {
+ this.password = password;
+ return this;
+ }
+
+ /**
+ * The value of the username parameter. Default is "user".
+ * @param username the value of the username parameter. Default is "user".
+ * @return the {@link FormLoginRequestBuilder} for additional customizations
+ */
+ public FormLoginRequestBuilder user(String username) {
+ this.username = username;
+ return this;
+ }
+
+ /**
+ * Specify both the password parameter name and the password.
+ *
+ * @param passwordParameter the HTTP parameter to place the password. Default is "password".
+ * @param password the value of the password parameter. Default is "password".
+ * @return the {@link FormLoginRequestBuilder} for additional customizations
+ */
+ public FormLoginRequestBuilder password(String passwordParameter, String password) {
+ passwordParam(passwordParameter);
+ this.password = password;
+ return this;
+ }
+
+ /**
+ * Specify both the password parameter name and the password.
+ *
+ * @param usernameParameter the HTTP parameter to place the username. Default is "username".
+ * @param username the value of the username parameter. Default is "user".
+ * @return the {@link FormLoginRequestBuilder} for additional customizations
+ */
+ public FormLoginRequestBuilder user(String usernameParameter, String username) {
+ userParameter(usernameParameter);
+ this.username = username;
+ return this;
+ }
+
+ private FormLoginRequestBuilder() {}
+ }
+
+ private SecurityMockMvcRequestBuilders() {}
+}
diff --git a/test/src/main/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessors.java b/test/src/main/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessors.java
new file mode 100644
index 0000000000..f783a5db36
--- /dev/null
+++ b/test/src/main/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessors.java
@@ -0,0 +1,491 @@
+/*
+ * Copyright 2002-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.security.test.web.servlet.request;
+
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.springframework.mock.web.MockHttpServletRequest;
+import org.springframework.mock.web.MockHttpServletResponse;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.authority.AuthorityUtils;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.security.core.context.SecurityContext;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.userdetails.User;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.crypto.codec.Base64;
+import org.springframework.security.test.context.TestSecurityContextHolder;
+import org.springframework.security.test.web.support.WebTestUtils;
+import org.springframework.security.web.context.HttpRequestResponseHolder;
+import org.springframework.security.web.context.SecurityContextRepository;
+import org.springframework.security.web.csrf.CsrfToken;
+import org.springframework.security.web.csrf.CsrfTokenRepository;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.request.RequestPostProcessor;
+import org.springframework.util.Assert;
+
+/**
+ * Contains {@link MockMvc} {@link RequestPostProcessor} implementations for
+ * Spring Security.
+ *
+ * @author Rob Winch
+ * @since 4.0
+ */
+public final class SecurityMockMvcRequestPostProcessors {
+
+ /**
+ * Creates a {@link RequestPostProcessor} that will automatically populate a
+ * valid {@link CsrfToken} in the request.
+ *
+ * @return the {@link CsrfRequestPostProcessor} for further customizations.
+ */
+ public static CsrfRequestPostProcessor csrf() {
+ return new CsrfRequestPostProcessor();
+ }
+
+ /**
+ * Creates a {@link RequestPostProcessor} that can be used to ensure that
+ * the resulting request is ran with the user in the
+ * {@link TestSecurityContextHolder}.
+ *
+ * @return the {@link RequestPostProcessor} to sue
+ */
+ public static RequestPostProcessor testSecurityContext() {
+ return new TestSecurityContextHolderPostProcessor();
+ }
+
+ /**
+ * Establish a {@link SecurityContext} that has a
+ * {@link UsernamePasswordAuthenticationToken} for the
+ * {@link Authentication#getPrincipal()} and a {@link User} for the
+ * {@link UsernamePasswordAuthenticationToken#getPrincipal()}. All details
+ * are declarative and do not require that the user actually exists.
+ *
+ * @param username
+ * the username to populate
+ * @return the {@link UserRequestPostProcessor} for additional customization
+ */
+ public static UserRequestPostProcessor user(String username) {
+ return new UserRequestPostProcessor(username);
+ }
+
+ /**
+ * Establish a {@link SecurityContext} that has a
+ * {@link UsernamePasswordAuthenticationToken} for the
+ * {@link Authentication#getPrincipal()} and a custom {@link UserDetails}
+ * for the {@link UsernamePasswordAuthenticationToken#getPrincipal()}. All
+ * details are declarative and do not require that the user actually exists.
+ *
+ * @param user
+ * the UserDetails to populate
+ * @return the {@link RequestPostProcessor} to use
+ */
+ public static RequestPostProcessor user(UserDetails user) {
+ return new UserDetailsRequestPostProcessor(user);
+ }
+
+ /**
+ * Establish a {@link SecurityContext} that uses the specified {@link Authentication} for the
+ * {@link Authentication#getPrincipal()} and a custom {@link UserDetails}. All
+ * details are declarative and do not require that the user actually exists.
+ *
+ * @param user
+ * the UserDetails to populate
+ * @return the {@link RequestPostProcessor} to use
+ */
+ public static RequestPostProcessor authentication(
+ Authentication authentication) {
+ return new AuthenticationRequestPostProcessor(authentication);
+ }
+
+ /**
+ * Establish the specified {@link SecurityContext} to be used.
+ */
+ public static RequestPostProcessor securityContext(
+ SecurityContext securityContext) {
+ return new SecurityContextRequestPostProcessor(securityContext);
+ }
+
+ /**
+ * Convenience mechanism for setting the Authorization header to use HTTP
+ * Basic with the given username and password. This method will
+ * automatically perform the necessary Base64 encoding.
+ *
+ * @param username
+ * the username to include in the Authorization header.
+ * @param password the password to include in the Authorization header.
+ * @return the {@link RequestPostProcessor} to use
+ */
+ public static RequestPostProcessor httpBasic(String username, String password) {
+ return new HttpBasicRequestPostProcessor(username, password);
+ }
+
+ /**
+ * Populates a valid {@link CsrfToken} into the request.
+ *
+ * @author Rob Winch
+ * @since 4.0
+ */
+ public static class CsrfRequestPostProcessor implements
+ RequestPostProcessor {
+
+ private boolean asHeader;
+
+ private boolean useInvalidToken;
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.springframework.test.web.servlet.request.RequestPostProcessor
+ * #postProcessRequest
+ * (org.springframework.mock.web.MockHttpServletRequest)
+ */
+ public MockHttpServletRequest postProcessRequest(
+ MockHttpServletRequest request) {
+
+ CsrfTokenRepository repository = WebTestUtils
+ .getCsrfTokenRepository(request);
+ CsrfToken token = repository.generateToken(request);
+ repository.saveToken(token, request, new MockHttpServletResponse());
+ String tokenValue = useInvalidToken ? "invalid" + token.getToken() : token.getToken();
+ if(asHeader) {
+ request.addHeader(token.getHeaderName(), tokenValue);
+ } else {
+ request.setParameter(token.getParameterName(), tokenValue);
+ }
+ return request;
+ }
+
+ /**
+ * Instead of using the {@link CsrfToken} as a request parameter
+ * (default) will populate the {@link CsrfToken} as a header.
+ *
+ * @return the {@link CsrfRequestPostProcessor} for additional customizations
+ */
+ public CsrfRequestPostProcessor asHeader() {
+ this.asHeader = true;
+ return this;
+ }
+
+ /**
+ * Populates an invalid token value on the request.
+ *
+ * @return the {@link CsrfRequestPostProcessor} for additional customizations
+ */
+ public CsrfRequestPostProcessor useInvalidToken() {
+ this.useInvalidToken = true;
+ return this;
+ }
+
+ private CsrfRequestPostProcessor() {}
+ }
+
+ /**
+ * Support class for {@link RequestPostProcessor}'s that establish a Spring
+ * Security context
+ */
+ private static abstract class SecurityContextRequestPostProcessorSupport {
+
+ /**
+ * Saves the specified {@link Authentication} into an empty
+ * {@link SecurityContext} using the {@link SecurityContextRepository}.
+ *
+ * @param authentication the {@link Authentication} to save
+ * @param request the {@link HttpServletRequest} to use
+ */
+ final void save(Authentication authentication,
+ HttpServletRequest request) {
+ SecurityContext securityContext = SecurityContextHolder
+ .createEmptyContext();
+ securityContext.setAuthentication(authentication);
+ save(securityContext, request);
+ }
+
+ /**
+ * Saves the {@link SecurityContext} using the
+ * {@link SecurityContextRepository}
+ *
+ * @param securityContext the {@link SecurityContext} to save
+ * @param request the {@link HttpServletRequest} to use
+ */
+ final void save(SecurityContext securityContext,
+ HttpServletRequest request) {
+ HttpServletResponse response = new MockHttpServletResponse();
+
+ HttpRequestResponseHolder requestResponseHolder = new HttpRequestResponseHolder(
+ request, response);
+ SecurityContextRepository securityContextRepository = WebTestUtils
+ .getSecurityContextRepository(request);
+ securityContextRepository.loadContext(requestResponseHolder);
+
+ request = requestResponseHolder.getRequest();
+ response = requestResponseHolder.getResponse();
+
+ securityContextRepository.saveContext(securityContext, request,
+ response);
+ }
+ }
+
+ /**
+ * Associates the {@link SecurityContext} found in
+ * {@link TestSecurityContextHolder#getContext()} with the
+ * {@link MockHttpServletRequest}.
+ *
+ * @author Rob Winch
+ * @since 4.0
+ */
+ private final static class TestSecurityContextHolderPostProcessor extends
+ SecurityContextRequestPostProcessorSupport implements
+ RequestPostProcessor {
+
+ public MockHttpServletRequest postProcessRequest(
+ MockHttpServletRequest request) {
+ save(TestSecurityContextHolder.getContext(), request);
+ return request;
+ }
+ }
+
+ /**
+ * Associates the specified {@link SecurityContext} with the
+ * {@link MockHttpServletRequest}.
+ *
+ * @author Rob Winch
+ * @since 4.0
+ */
+ private final static class SecurityContextRequestPostProcessor extends
+ SecurityContextRequestPostProcessorSupport implements
+ RequestPostProcessor {
+
+ private final SecurityContext securityContext;
+
+ private SecurityContextRequestPostProcessor(
+ SecurityContext securityContext) {
+ this.securityContext = securityContext;
+ }
+
+ public MockHttpServletRequest postProcessRequest(
+ MockHttpServletRequest request) {
+ save(this.securityContext, request);
+ return request;
+ }
+ }
+
+ /**
+ * Sets the specified {@link Authentication} on an empty
+ * {@link SecurityContext} and associates it to the
+ * {@link MockHttpServletRequest}
+ *
+ * @author Rob Winch
+ * @since 4.0
+ *
+ */
+ private final static class AuthenticationRequestPostProcessor extends
+ SecurityContextRequestPostProcessorSupport implements
+ RequestPostProcessor {
+ private final Authentication authentication;
+
+ private AuthenticationRequestPostProcessor(Authentication authentication) {
+ this.authentication = authentication;
+ }
+
+ public MockHttpServletRequest postProcessRequest(
+ MockHttpServletRequest request) {
+ SecurityContext context = SecurityContextHolder.getContext();
+ context.setAuthentication(authentication);
+ save(authentication, request);
+ return request;
+ }
+ }
+
+ /**
+ * Creates a {@link UsernamePasswordAuthenticationToken} and sets the
+ * {@link UserDetails} as the principal and associates it to the
+ * {@link MockHttpServletRequest}.
+ *
+ * @author Rob Winch
+ * @since 4.0
+ */
+ private final static class UserDetailsRequestPostProcessor implements
+ RequestPostProcessor {
+ private final RequestPostProcessor delegate;
+
+ public UserDetailsRequestPostProcessor(UserDetails user) {
+ Authentication token = new UsernamePasswordAuthenticationToken(user, user.getPassword(), user.getAuthorities());
+
+ delegate = new AuthenticationRequestPostProcessor(token);
+ }
+
+ public MockHttpServletRequest postProcessRequest(
+ MockHttpServletRequest request) {
+ return delegate.postProcessRequest(request);
+ }
+ }
+
+ /**
+ * Creates a {@link UsernamePasswordAuthenticationToken} and sets the
+ * principal to be a {@link User} and associates it to the
+ * {@link MockHttpServletRequest}.
+ *
+ * @author Rob Winch
+ * @since 4.0
+ */
+ public final static class UserRequestPostProcessor extends
+ SecurityContextRequestPostProcessorSupport implements
+ RequestPostProcessor {
+
+ private String username;
+
+ private String password = "password";
+
+ private static final String ROLE_PREFIX = "ROLE_";
+
+ private Collection extends GrantedAuthority> authorities = AuthorityUtils
+ .createAuthorityList("ROLE_USER");
+
+ private boolean enabled = true;
+
+ private boolean accountNonExpired = true;
+
+ private boolean credentialsNonExpired = true;
+
+ private boolean accountNonLocked = true;
+
+ /**
+ * Creates a new instance with the given username
+ * @param username the username to use
+ */
+ private UserRequestPostProcessor(String username) {
+ Assert.notNull(username, "username cannot be null");
+ this.username = username;
+ }
+
+ /**
+ * Specify the roles of the user to authenticate as. This method is
+ * similar to {@link #authorities(GrantedAuthority...)}, but just not as
+ * flexible.
+ *
+ * @param roles
+ * The roles to populate. Note that if the role does not
+ * start with {@link #rolePrefix(String)} it will
+ * automatically be prepended. This means by default
+ * {@code roles("ROLE_USER")} and {@code roles("USER")} are
+ * equivalent.
+ * @see #authorities(GrantedAuthority...)
+ * @see #rolePrefix(String)
+ * @return the UserRequestPostProcessor for further customizations
+ */
+ public UserRequestPostProcessor roles(String... roles) {
+ List authorities = new ArrayList(
+ roles.length);
+ for (String role : roles) {
+ if (role.startsWith(ROLE_PREFIX)) {
+ throw new IllegalArgumentException("Role should not start with "+ROLE_PREFIX + " since this method automatically prefixes with this value. Got "+ role);
+ } else {
+ authorities.add(new SimpleGrantedAuthority(ROLE_PREFIX
+ + role));
+ }
+ }
+ this.authorities = authorities;
+ return this;
+ }
+
+ /**
+ * Populates the user's {@link GrantedAuthority}'s. The default is
+ * ROLE_USER.
+ *
+ * @param authorities
+ * @see #roles(String...)
+ * @return the UserRequestPostProcessor for further customizations
+ */
+ public UserRequestPostProcessor authorities(
+ GrantedAuthority... authorities) {
+ return authorities(Arrays.asList(authorities));
+ }
+
+ /**
+ * Populates the user's {@link GrantedAuthority}'s. The default is
+ * ROLE_USER.
+ *
+ * @param authorities
+ * @see #roles(String...)
+ * @return the UserRequestPostProcessor for further customizations
+ */
+ public UserRequestPostProcessor authorities(
+ Collection extends GrantedAuthority> authorities) {
+ this.authorities = authorities;
+ return this;
+ }
+
+ /**
+ * Populates the user's password. The default is "password"
+ *
+ * @param password
+ * the user's password
+ * @return the UserRequestPostProcessor for further customizations
+ */
+ public UserRequestPostProcessor password(String password) {
+ this.password = password;
+ return this;
+ }
+
+ public MockHttpServletRequest postProcessRequest(
+ MockHttpServletRequest request) {
+ UserDetailsRequestPostProcessor delegate = new UserDetailsRequestPostProcessor(createUser());
+ return delegate.postProcessRequest(request);
+ }
+
+ /**
+ * Creates a new {@link User}
+ * @return the {@link User} for the principal
+ */
+ private User createUser() {
+ return new User(username, password, enabled, accountNonExpired,
+ credentialsNonExpired, accountNonLocked, authorities);
+ }
+ }
+
+ private static class HttpBasicRequestPostProcessor implements RequestPostProcessor {
+ private String headerValue;
+
+ private HttpBasicRequestPostProcessor(String username, String password) {
+ byte[] toEncode;
+ try {
+ toEncode = (username + ":" + password).getBytes("UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException(e);
+ }
+ this.headerValue = "Basic " + new String(Base64.encode(toEncode));
+ }
+
+ public MockHttpServletRequest postProcessRequest(
+ MockHttpServletRequest request) {
+ request.addHeader("Authorization", headerValue);
+ return request;
+ }
+ }
+
+ private SecurityMockMvcRequestPostProcessors() { }
+}
\ No newline at end of file
diff --git a/test/src/main/java/org/springframework/security/test/web/servlet/response/SecurityMockMvcResultMatchers.java b/test/src/main/java/org/springframework/security/test/web/servlet/response/SecurityMockMvcResultMatchers.java
new file mode 100644
index 0000000000..342e5fc9c3
--- /dev/null
+++ b/test/src/main/java/org/springframework/security/test/web/servlet/response/SecurityMockMvcResultMatchers.java
@@ -0,0 +1,226 @@
+/*
+ * Copyright 2002-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.security.test.web.servlet.response;
+
+import static org.springframework.test.util.AssertionErrors.assertEquals;
+import static org.springframework.test.util.AssertionErrors.assertTrue;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.security.core.context.SecurityContext;
+import org.springframework.security.test.web.support.WebTestUtils;
+import org.springframework.security.web.context.HttpRequestResponseHolder;
+import org.springframework.security.web.context.SecurityContextRepository;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.MvcResult;
+import org.springframework.test.web.servlet.ResultMatcher;
+
+/**
+ * Security related {@link MockMvc} {@link ResultMatcher}s.
+ *
+ * @author Rob Winch
+ * @since 4.0
+ */
+public final class SecurityMockMvcResultMatchers {
+
+ /**
+ * {@link ResultMatcher} that verifies that a specified user is
+ * authenticated.
+ *
+ * @return the {@link AuthenticatedMatcher} to use
+ */
+ public static AuthenticatedMatcher authenticated() {
+ return new AuthenticatedMatcher();
+ }
+
+ /**
+ * {@link ResultMatcher} that verifies that no user is authenticated.
+ *
+ * @return the {@link AuthenticatedMatcher} to use
+ */
+ public static ResultMatcher unauthenticated() {
+ return new UnAuthenticatedMatcher();
+ }
+
+ private static abstract class AuthenticationMatcher> implements ResultMatcher {
+
+ protected SecurityContext load(MvcResult result) {
+ HttpRequestResponseHolder holder = new HttpRequestResponseHolder(result.getRequest(), result.getResponse());
+ SecurityContextRepository repository = WebTestUtils.getSecurityContextRepository(result.getRequest());
+ return repository.loadContext(holder);
+ }
+ }
+
+ /**
+ * A {@link MockMvc} {@link ResultMatcher} that verifies a specific user is
+ * associated to the {@link MvcResult}.
+ *
+ * @author Rob Winch
+ * @since 4.0
+ */
+ public static final class AuthenticatedMatcher extends AuthenticationMatcher {
+
+ private SecurityContext expectedContext;
+ private Authentication expectedAuthentication;
+ private Object expectedAuthenticationPrincipal;
+ private String expectedAuthenticationName;
+ private Collection expectedGrantedAuthorities;
+
+
+ public void match(MvcResult result) throws Exception {
+ SecurityContext context = load(result);
+
+ Authentication auth = context.getAuthentication();
+
+ assertTrue("Authentication should not be null", auth != null);
+
+ if(this.expectedContext != null) {
+ assertEquals(this.expectedContext + " does not equal " + context, this.expectedContext, context);
+ }
+
+ if(this.expectedAuthentication != null) {
+ assertEquals(this.expectedAuthentication + " does not equal " + context.getAuthentication(), this.expectedAuthentication, context.getAuthentication());
+ }
+
+ if(this.expectedAuthenticationPrincipal != null) {
+ assertTrue("Authentication cannot be null", context.getAuthentication() != null);
+ assertEquals(this.expectedAuthenticationPrincipal + " does not equal " + context.getAuthentication().getPrincipal(), this.expectedAuthenticationPrincipal, context.getAuthentication().getPrincipal());
+ }
+
+ if(this.expectedAuthenticationName != null) {
+ assertTrue("Authentication cannot be null", auth != null);
+ String name = auth.getName();
+ assertEquals(this.expectedAuthenticationName + " does not equal " + name, this.expectedAuthenticationName, name);
+ }
+
+ if(this.expectedGrantedAuthorities != null) {
+ assertTrue("Authentication cannot be null", auth != null);
+ Collection extends GrantedAuthority> authorities = auth.getAuthorities();
+ assertEquals(this.expectedGrantedAuthorities + " does not equal " + authorities, this.expectedGrantedAuthorities, authorities);
+ }
+ }
+
+ /**
+ * Specifies the expected username
+ *
+ * @param expected
+ * the expected username
+ * @return the {@link AuthenticatedMatcher} for further customization
+ */
+ public AuthenticatedMatcher withUsername(String expected) {
+ return withAuthenticationName(expected);
+ }
+
+ /**
+ * Specifies the expected {@link SecurityContext}
+ *
+ * @param expected
+ * the expected {@link SecurityContext}
+ * @return the {@link AuthenticatedMatcher} for further customization
+ */
+ public AuthenticatedMatcher withSecurityContext(SecurityContext expected) {
+ this.expectedContext = expected;
+ return this;
+ }
+
+ /**
+ * Specifies the expected {@link Authentication}
+ *
+ * @param expected
+ * the expected {@link Authentication}
+ * @return the {@link AuthenticatedMatcher} for further customization
+ */
+ public AuthenticatedMatcher withAuthentication(Authentication expected) {
+ this.expectedAuthentication = expected;
+ return this;
+ }
+
+ /**
+ * Specifies the expected principal
+ *
+ * @param expected
+ * the expected principal
+ * @return the {@link AuthenticatedMatcher} for further customization
+ */
+ public AuthenticatedMatcher withAuthenticationPrincipal(Object expected) {
+ this.expectedAuthenticationPrincipal = expected;
+ return this;
+ }
+
+ /**
+ * Specifies the expected {@link Authentication#getName()}
+ *
+ * @param expected
+ * the expected {@link Authentication#getName()}
+ * @return the {@link AuthenticatedMatcher} for further customization
+ */
+ public AuthenticatedMatcher withAuthenticationName(String expected) {
+ this.expectedAuthenticationName = expected;
+ return this;
+ }
+
+ /**
+ * Specifies the {@link Authentication#getAuthorities()}
+ *
+ * @param expected the {@link Authentication#getAuthorities()}
+ * @return the {@link AuthenticatedMatcher} for further customization
+ */
+ public AuthenticatedMatcher withAuthorities(Collection expected) {
+ this.expectedGrantedAuthorities = expected;
+ return this;
+ }
+
+ /**
+ * Specifies the {@link Authentication#getAuthorities()}
+ *
+ * @param expected the roles. Each value is automatically prefixed with "ROLE_"
+ * @return the {@link AuthenticatedMatcher} for further customization
+ */
+ public AuthenticatedMatcher withRoles(String... roles) {
+ Collection authorities = new ArrayList();
+ for(String role : roles) {
+ authorities.add(new SimpleGrantedAuthority("ROLE_"+role));
+ }
+ return withAuthorities(authorities);
+ }
+
+ AuthenticatedMatcher() {}
+ }
+
+ /**
+ * A {@link MockMvc} {@link ResultMatcher} that verifies no
+ * {@link Authentication} is associated with the {@link MvcResult}.
+ *
+ * @author Rob Winch
+ * @since 4.0
+ */
+ private static final class UnAuthenticatedMatcher extends AuthenticationMatcher{
+
+ public void match(MvcResult result) throws Exception {
+ SecurityContext context = load(result);
+
+ assertEquals("",null,context.getAuthentication());
+ }
+
+ private UnAuthenticatedMatcher() {}
+ }
+
+ private SecurityMockMvcResultMatchers() {}
+}
\ No newline at end of file
diff --git a/test/src/main/java/org/springframework/security/test/web/support/WebTestUtils.java b/test/src/main/java/org/springframework/security/test/web/support/WebTestUtils.java
new file mode 100644
index 0000000000..a98c06a2b5
--- /dev/null
+++ b/test/src/main/java/org/springframework/security/test/web/support/WebTestUtils.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2002-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.security.test.web.support;
+
+import java.util.List;
+
+import javax.servlet.Filter;
+import javax.servlet.http.HttpServletRequest;
+
+import org.springframework.beans.factory.NoSuchBeanDefinitionException;
+import org.springframework.security.web.FilterChainProxy;
+import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
+import org.springframework.security.web.context.SecurityContextPersistenceFilter;
+import org.springframework.security.web.context.SecurityContextRepository;
+import org.springframework.security.web.csrf.CsrfFilter;
+import org.springframework.security.web.csrf.CsrfTokenRepository;
+import org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository;
+import org.springframework.test.util.ReflectionTestUtils;
+import org.springframework.web.context.WebApplicationContext;
+import org.springframework.web.context.support.WebApplicationContextUtils;
+
+/**
+ * A utility class for testing spring security
+ *
+ * @author Rob Winch
+ * @since 4.0
+ */
+public abstract class WebTestUtils {
+ private static final SecurityContextRepository DEFAULT_CONTEXT_REPO = new HttpSessionSecurityContextRepository();
+ private static final CsrfTokenRepository DEFAULT_TOKEN_REPO = new HttpSessionCsrfTokenRepository();
+
+ /**
+ * Gets the {@link SecurityContextRepository} for the specified
+ * {@link HttpServletRequest}. If one is not found, a default
+ * {@link HttpSessionSecurityContextRepository} is used.
+ *
+ * @param request
+ * the {@link HttpServletRequest} to obtain the
+ * {@link SecurityContextRepository}
+ * @return the {@link SecurityContextRepository} for the specified
+ * {@link HttpServletRequest}
+ */
+ public static SecurityContextRepository getSecurityContextRepository(HttpServletRequest request) {
+ SecurityContextPersistenceFilter filter = findFilter(request, SecurityContextPersistenceFilter.class);
+ if(filter == null) {
+ return DEFAULT_CONTEXT_REPO;
+ }
+ return (SecurityContextRepository) ReflectionTestUtils.getField(filter, "repo");
+ }
+
+ /**
+ * Gets the {@link CsrfTokenRepository} for the specified
+ * {@link HttpServletRequest}. If one is not found, the default
+ * {@link HttpSessionCsrfTokenRepository} is used.
+ *
+ * @param request
+ * the {@link HttpServletRequest} to obtain the
+ * {@link CsrfTokenRepository}
+ * @return the {@link CsrfTokenRepository} for the specified
+ * {@link HttpServletRequest}
+ */
+ public static CsrfTokenRepository getCsrfTokenRepository(HttpServletRequest request) {
+ CsrfFilter filter = findFilter(request, CsrfFilter.class);
+ if(filter == null) {
+ return DEFAULT_TOKEN_REPO;
+ }
+ return (CsrfTokenRepository) ReflectionTestUtils.getField(filter, "tokenRepository");
+ }
+
+ @SuppressWarnings("unchecked")
+ private static T findFilter(HttpServletRequest request, Class filterClass) {
+ WebApplicationContext webApplicationContext = WebApplicationContextUtils.getWebApplicationContext(request.getServletContext());
+ if(webApplicationContext == null) {
+ return null;
+ }
+ FilterChainProxy springSecurityFilterChain = null;
+ try {
+ springSecurityFilterChain = webApplicationContext.getBean(FilterChainProxy.class);
+ } catch(NoSuchBeanDefinitionException notFound) {
+ return null;
+ }
+ List filters = (List) ReflectionTestUtils.invokeMethod(springSecurityFilterChain,"getFilters", request);
+ for(Filter filter : filters) {
+ if(filterClass.isAssignableFrom(filter.getClass())) {
+ return (T) filter;
+ }
+ }
+ return null;
+ }
+
+ private WebTestUtils() {}
+}
\ No newline at end of file
diff --git a/test/src/test/java/org/springframework/security/test/context/TestSecurityContextHolderTests.java b/test/src/test/java/org/springframework/security/test/context/TestSecurityContextHolderTests.java
new file mode 100644
index 0000000000..663df85542
--- /dev/null
+++ b/test/src/test/java/org/springframework/security/test/context/TestSecurityContextHolderTests.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2002-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.security.test.context;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.springframework.security.core.context.SecurityContext;
+import org.springframework.security.core.context.SecurityContextHolder;
+
+public class TestSecurityContextHolderTests {
+
+ private SecurityContext context;
+
+ @Before
+ public void setup() {
+ context = SecurityContextHolder.createEmptyContext();
+ }
+
+ @After
+ public void cleanup() {
+ TestSecurityContextHolder.clearContext();
+ }
+
+ @Test
+ public void clearContextClearsBoth() {
+ SecurityContextHolder.setContext(context);
+ TestSecurityContextHolder.setContext(context);
+
+ TestSecurityContextHolder.clearContext();
+
+ assertThat(SecurityContextHolder.getContext()).isNotSameAs(context);
+ assertThat(TestSecurityContextHolder.getContext()).isNotSameAs(context);
+ }
+
+ @Test
+ public void getContextDefaultsNonNull() {
+ assertThat(TestSecurityContextHolder.getContext()).isNotNull();
+ assertThat(SecurityContextHolder.getContext()).isNotNull();
+ }
+
+ @Test
+ public void setContextSetsBoth() {
+ TestSecurityContextHolder.setContext(context);
+
+ assertThat(TestSecurityContextHolder.getContext()).isSameAs(context);
+ assertThat(SecurityContextHolder.getContext()).isSameAs(context);
+ }
+}
\ No newline at end of file
diff --git a/test/src/test/java/org/springframework/security/test/context/support/WithMockUserSecurityContextFactoryTests.java b/test/src/test/java/org/springframework/security/test/context/support/WithMockUserSecurityContextFactoryTests.java
new file mode 100644
index 0000000000..a9422c29c1
--- /dev/null
+++ b/test/src/test/java/org/springframework/security/test/context/support/WithMockUserSecurityContextFactoryTests.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2002-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.security.test.context.support;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.mockito.Mockito.*;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+
+@RunWith(MockitoJUnitRunner.class)
+public class WithMockUserSecurityContextFactoryTests {
+
+ @Mock
+ private WithMockUser withUser;
+
+ private WithMockUserSecurityContextFactory factory;
+
+ @Before
+ public void setup() {
+ factory = new WithMockUserSecurityContextFactory();
+ }
+
+ @Test(expected=IllegalArgumentException.class)
+ public void usernameNull() {
+ factory.createSecurityContext(withUser);
+ }
+
+ @Test
+ public void valueDefaultsUsername() {
+ when(withUser.value()).thenReturn("valueUser");
+ when(withUser.password()).thenReturn("password");
+ when(withUser.roles()).thenReturn(new String[] { "USER"});
+
+ assertThat(factory.createSecurityContext(withUser).getAuthentication().getName()).isEqualTo(withUser.value());
+ }
+
+ @Test
+ public void usernamePrioritizedOverValue() {
+ when(withUser.value()).thenReturn("valueUser");
+ when(withUser.username()).thenReturn("customUser");
+ when(withUser.password()).thenReturn("password");
+ when(withUser.roles()).thenReturn(new String[] { "USER"});
+
+ assertThat(factory.createSecurityContext(withUser).getAuthentication().getName()).isEqualTo(withUser.username());
+ }
+
+ @Test
+ public void rolesWorks() {
+ when(withUser.value()).thenReturn("valueUser");
+ when(withUser.password()).thenReturn("password");
+ when(withUser.roles()).thenReturn(new String[] { "USER", "CUSTOM"});
+
+ assertThat(factory.createSecurityContext(withUser).getAuthentication().getAuthorities()).onProperty("authority").containsOnly("ROLE_USER","ROLE_CUSTOM");
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void rolesWithRolePrefixFails() {
+ when(withUser.value()).thenReturn("valueUser");
+ when(withUser.password()).thenReturn("password");
+ when(withUser.roles()).thenReturn(new String[] { "ROLE_FAIL"});
+
+ factory.createSecurityContext(withUser);
+ }
+}
\ No newline at end of file
diff --git a/test/src/test/java/org/springframework/security/test/context/support/WithMockUserTests.java b/test/src/test/java/org/springframework/security/test/context/support/WithMockUserTests.java
new file mode 100644
index 0000000000..4e8103dfab
--- /dev/null
+++ b/test/src/test/java/org/springframework/security/test/context/support/WithMockUserTests.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2002-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.security.test.context.support;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+import org.junit.Test;
+import org.springframework.core.annotation.AnnotationUtils;
+
+public class WithMockUserTests {
+
+ @Test
+ public void defaults() {
+ WithMockUser mockUser = AnnotationUtils.findAnnotation(Annotated.class, WithMockUser.class);
+ assertThat(mockUser.value()).isEqualTo("user");
+ assertThat(mockUser.username()).isEmpty();
+ assertThat(mockUser.password()).isEqualTo("password");
+ assertThat(mockUser.roles()).containsOnly("USER");
+ }
+
+ @WithMockUser
+ private class Annotated {}
+}
\ No newline at end of file
diff --git a/test/src/test/java/org/springframework/security/test/context/support/WithSecurityContextTestExcecutionListenerTests.java b/test/src/test/java/org/springframework/security/test/context/support/WithSecurityContextTestExcecutionListenerTests.java
new file mode 100644
index 0000000000..157de2b5bb
--- /dev/null
+++ b/test/src/test/java/org/springframework/security/test/context/support/WithSecurityContextTestExcecutionListenerTests.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2002-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.security.test.context.support;
+
+import static org.mockito.Mockito.when;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.springframework.context.ConfigurableApplicationContext;
+import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.test.context.TestSecurityContextHolder;
+import org.springframework.test.context.TestContext;
+import org.springframework.util.ReflectionUtils;
+
+@RunWith(MockitoJUnitRunner.class)
+public class WithSecurityContextTestExcecutionListenerTests {
+ private ConfigurableApplicationContext context;
+
+ @Mock
+ private TestContext testContext;
+
+ private WithSecurityContextTestExcecutionListener listener;
+
+ @Before
+ public void setup() {
+ listener = new WithSecurityContextTestExcecutionListener();
+ context = new AnnotationConfigApplicationContext(Config.class);
+ }
+
+ @After
+ public void cleanup() {
+ TestSecurityContextHolder.clearContext();
+ if(context != null) {
+ context.close();
+ }
+ }
+
+ @Test
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ public void beforeTestMethodNullSecurityContextNoError() throws Exception {
+ Class testClass = FakeTest.class;
+ when(testContext.getApplicationContext()).thenReturn(context);
+ when(testContext.getTestClass()).thenReturn(testClass);
+ when(testContext.getTestMethod()).thenReturn(ReflectionUtils.findMethod(testClass, "testNoAnnotation"));
+
+ listener.beforeTestMethod(testContext);
+ }
+
+ static class FakeTest {
+ public void testNoAnnotation() {}
+ }
+
+ @Configuration
+ static class Config {}
+}
diff --git a/test/src/test/java/org/springframework/security/test/context/support/WithUserDetailsSecurityContextFactoryTests.java b/test/src/test/java/org/springframework/security/test/context/support/WithUserDetailsSecurityContextFactoryTests.java
new file mode 100644
index 0000000000..b1b6fb141a
--- /dev/null
+++ b/test/src/test/java/org/springframework/security/test/context/support/WithUserDetailsSecurityContextFactoryTests.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2002-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.security.test.context.support;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.mockito.Mockito.when;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.context.SecurityContext;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsService;
+
+@RunWith(MockitoJUnitRunner.class)
+public class WithUserDetailsSecurityContextFactoryTests {
+
+ @Mock
+ private UserDetailsService userDetailsService;
+ @Mock
+ private UserDetails userDetails;
+
+ @Mock
+ private WithUserDetails withUserDetails;
+
+ private WithUserDetailsSecurityContextFactory factory;
+
+ @Before
+ public void setup() {
+ factory = new WithUserDetailsSecurityContextFactory(userDetailsService);
+ }
+
+ @Test(expected=IllegalArgumentException.class)
+ public void createSecurityContextNullValue() {
+ factory.createSecurityContext(withUserDetails);
+ }
+
+ @Test(expected=IllegalArgumentException.class)
+ public void createSecurityContextEmptyValue() {
+ when(withUserDetails.value()).thenReturn("");
+ factory.createSecurityContext(withUserDetails);
+ }
+
+ @Test
+ public void createSecurityContextWithExistingUser() {
+ String username = "user";
+ when(withUserDetails.value()).thenReturn(username);
+ when(userDetailsService.loadUserByUsername(username)).thenReturn(userDetails);
+
+ SecurityContext context = factory.createSecurityContext(withUserDetails);
+ assertThat(context.getAuthentication()).isInstanceOf(UsernamePasswordAuthenticationToken.class);
+ assertThat(context.getAuthentication().getPrincipal()).isEqualTo(userDetails);
+ }
+}
\ No newline at end of file
diff --git a/test/src/test/java/org/springframework/security/test/context/support/WithUserDetailsTests.java b/test/src/test/java/org/springframework/security/test/context/support/WithUserDetailsTests.java
new file mode 100644
index 0000000000..f159bca8a7
--- /dev/null
+++ b/test/src/test/java/org/springframework/security/test/context/support/WithUserDetailsTests.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2002-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.security.test.context.support;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+import org.junit.Test;
+import org.springframework.core.annotation.AnnotationUtils;
+
+public class WithUserDetailsTests {
+
+ @Test
+ public void defaults() {
+ WithUserDetails userDetails = AnnotationUtils.findAnnotation(Annotated.class, WithUserDetails.class);
+ assertThat(userDetails.value()).isEqualTo("user");
+ }
+
+ @WithUserDetails
+ private static class Annotated {}
+}
diff --git a/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestBuildersFormLoginTests.java b/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestBuildersFormLoginTests.java
new file mode 100644
index 0000000000..6159f5326b
--- /dev/null
+++ b/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestBuildersFormLoginTests.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2002-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.security.test.web.servlet.request;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.verify;
+import static org.fest.assertions.Assertions.assertThat;
+import static org.powermock.api.mockito.PowerMockito.spy;
+import static org.powermock.api.mockito.PowerMockito.when;
+import static org.powermock.api.mockito.PowerMockito.doReturn;
+import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.formLogin;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+import org.springframework.mock.web.MockHttpServletRequest;
+import org.springframework.mock.web.MockServletContext;
+import org.springframework.security.test.web.support.WebTestUtils;
+import org.springframework.security.web.csrf.CsrfTokenRepository;
+import org.springframework.security.web.csrf.DefaultCsrfToken;
+
+
+@RunWith(PowerMockRunner.class)
+@PrepareForTest({WebTestUtils.class,SecurityMockMvcRequestBuildersFormLoginTests.class})
+public class SecurityMockMvcRequestBuildersFormLoginTests {
+ @Mock
+ private CsrfTokenRepository repository;
+ private DefaultCsrfToken token;
+ private MockServletContext servletContext;
+
+ @Before
+ public void setup() throws Exception {
+ token = new DefaultCsrfToken("header", "param", "token");
+ servletContext = new MockServletContext();
+ mockWebTestUtils();
+ }
+
+ @Test
+ public void defaults() throws Exception {
+ MockHttpServletRequest request = formLogin().buildRequest(servletContext);
+
+ assertThat(request.getParameter("username")).isEqualTo("user");
+ assertThat(request.getParameter("password")).isEqualTo("password");
+ assertThat(request.getMethod()).isEqualTo("POST");
+ assertThat(request.getParameter(token.getParameterName())).isEqualTo(token.getToken());
+ assertThat(request.getRequestURI()).isEqualTo("/login");
+ verify(repository).saveToken(eq(token), any(HttpServletRequest.class), any(HttpServletResponse.class));
+ }
+
+
+ @Test
+ public void custom() throws Exception {
+ MockHttpServletRequest request = formLogin("/j_spring_security_login")
+ .user("j_username","admin")
+ .password("j_password","secret")
+ .buildRequest(servletContext);
+
+ assertThat(request.getParameter("j_username")).isEqualTo("admin");
+ assertThat(request.getParameter("j_password")).isEqualTo("secret");
+ assertThat(request.getMethod()).isEqualTo("POST");
+ assertThat(request.getParameter(token.getParameterName())).isEqualTo(token.getToken());
+ assertThat(request.getRequestURI()).isEqualTo("/j_spring_security_login");
+ verify(repository).saveToken(eq(token), any(HttpServletRequest.class), any(HttpServletResponse.class));
+ }
+
+ private void mockWebTestUtils() throws Exception {
+ spy(WebTestUtils.class);
+ doReturn(repository).when(WebTestUtils.class,"getCsrfTokenRepository",any(HttpServletRequest.class));
+ when(repository.generateToken(any(HttpServletRequest.class))).thenReturn(token);
+ }
+}
diff --git a/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestBuildersFormLogoutTests.java b/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestBuildersFormLogoutTests.java
new file mode 100644
index 0000000000..313e3db8a6
--- /dev/null
+++ b/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestBuildersFormLogoutTests.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2002-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.security.test.web.servlet.request;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.verify;
+import static org.fest.assertions.Assertions.assertThat;
+import static org.powermock.api.mockito.PowerMockito.spy;
+import static org.powermock.api.mockito.PowerMockito.when;
+import static org.powermock.api.mockito.PowerMockito.doReturn;
+import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.logout;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+import org.springframework.mock.web.MockHttpServletRequest;
+import org.springframework.mock.web.MockServletContext;
+import org.springframework.security.test.web.support.WebTestUtils;
+import org.springframework.security.web.csrf.CsrfTokenRepository;
+import org.springframework.security.web.csrf.DefaultCsrfToken;
+
+
+@RunWith(PowerMockRunner.class)
+@PrepareForTest({WebTestUtils.class,SecurityMockMvcRequestBuildersFormLogoutTests.class})
+public class SecurityMockMvcRequestBuildersFormLogoutTests {
+ @Mock
+ private CsrfTokenRepository repository;
+ private DefaultCsrfToken token;
+ private MockServletContext servletContext;
+
+ @Before
+ public void setup() {
+ token = new DefaultCsrfToken("header", "param", "token");
+ servletContext = new MockServletContext();
+ }
+
+ @Test
+ public void defaults() throws Exception {
+ mockWebTestUtils();
+ MockHttpServletRequest request = logout().buildRequest(servletContext);
+
+ assertThat(request.getMethod()).isEqualTo("POST");
+ assertThat(request.getParameter(token.getParameterName())).isEqualTo(token.getToken());
+ assertThat(request.getRequestURI()).isEqualTo("/logout");
+ verify(repository).saveToken(eq(token), any(HttpServletRequest.class), any(HttpServletResponse.class));
+ }
+
+ @Test
+ public void custom() throws Exception {
+ mockWebTestUtils();
+ MockHttpServletRequest request = logout("/admin/logout").buildRequest(servletContext);
+
+ assertThat(request.getMethod()).isEqualTo("POST");
+ assertThat(request.getParameter(token.getParameterName())).isEqualTo(token.getToken());
+ assertThat(request.getRequestURI()).isEqualTo("/admin/logout");
+ verify(repository).saveToken(eq(token), any(HttpServletRequest.class), any(HttpServletResponse.class));
+ }
+
+ private void mockWebTestUtils() throws Exception {
+ spy(WebTestUtils.class);
+ doReturn(repository).when(WebTestUtils.class,"getCsrfTokenRepository",any(HttpServletRequest.class));
+ when(repository.generateToken(any(HttpServletRequest.class))).thenReturn(token);
+ }
+}
diff --git a/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsAuthenticationTests.java b/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsAuthenticationTests.java
new file mode 100644
index 0000000000..681ffc8c22
--- /dev/null
+++ b/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsAuthenticationTests.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2002-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.security.test.web.servlet.request;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+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.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.authentication;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.powermock.core.classloader.annotations.PrepareOnlyThisForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+import org.springframework.mock.web.MockHttpServletRequest;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContext;
+import org.springframework.security.test.context.TestSecurityContextHolder;
+import org.springframework.security.test.web.support.WebTestUtils;
+import org.springframework.security.web.context.SecurityContextRepository;
+
+@RunWith(PowerMockRunner.class)
+@PrepareOnlyThisForTest(WebTestUtils.class)
+public class SecurityMockMvcRequestPostProcessorsAuthenticationTests {
+ @Captor
+ private ArgumentCaptor contextCaptor;
+ @Mock
+ private SecurityContextRepository repository;
+
+ private MockHttpServletRequest request;
+
+ @Mock
+ private Authentication authentication;
+
+ @Before
+ public void setup() {
+ request = new MockHttpServletRequest();
+ mockWebTestUtils();
+ }
+
+ @After
+ public void cleanup() {
+ TestSecurityContextHolder.clearContext();
+ }
+
+ @Test
+ public void userDetails() {
+ authentication(authentication).postProcessRequest(request);
+
+ verify(repository).saveContext(contextCaptor.capture(), eq(request), any(HttpServletResponse.class));
+ SecurityContext context = contextCaptor.getValue();
+ assertThat(context.getAuthentication()).isSameAs(authentication);
+ }
+
+ private void mockWebTestUtils() {
+ spy(WebTestUtils.class);
+ when(WebTestUtils.getSecurityContextRepository(request)).thenReturn(repository);
+ }
+}
\ No newline at end of file
diff --git a/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsCsrfTests.java b/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsCsrfTests.java
new file mode 100644
index 0000000000..d09064cdf0
--- /dev/null
+++ b/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsCsrfTests.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2002-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.security.test.web.servlet.request;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
+import static org.powermock.api.mockito.PowerMockito.*;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.powermock.core.classloader.annotations.PrepareOnlyThisForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+import org.springframework.mock.web.MockHttpServletRequest;
+import org.springframework.security.test.web.support.WebTestUtils;
+import org.springframework.security.web.csrf.CsrfTokenRepository;
+import org.springframework.security.web.csrf.DefaultCsrfToken;
+
+@RunWith(PowerMockRunner.class)
+@PrepareOnlyThisForTest(WebTestUtils.class)
+public class SecurityMockMvcRequestPostProcessorsCsrfTests {
+ @Mock
+ private CsrfTokenRepository repository;
+ private DefaultCsrfToken token;
+
+ private MockHttpServletRequest request;
+
+ @Before
+ public void setup() {
+ token = new DefaultCsrfToken("header", "param", "token");
+ request = new MockHttpServletRequest();
+ mockWebTestUtils();
+ }
+
+ @Test
+ public void csrfWithParam() {
+ MockHttpServletRequest postProcessedRequest = csrf().postProcessRequest(request);
+
+ assertThat(postProcessedRequest.getParameter(token.getParameterName())).isEqualTo(token.getToken());
+ assertThat(postProcessedRequest.getHeader(token.getHeaderName())).isNull();
+ }
+
+ @Test
+ public void csrfWithHeader() {
+ MockHttpServletRequest postProcessedRequest = csrf().asHeader().postProcessRequest(request);
+
+ assertThat(postProcessedRequest.getParameter(token.getParameterName())).isNull();
+ assertThat(postProcessedRequest.getHeader(token.getHeaderName())).isEqualTo(token.getToken());
+ }
+
+ @Test
+ public void csrfWithInvalidParam() {
+ MockHttpServletRequest postProcessedRequest = csrf().useInvalidToken().postProcessRequest(request);
+
+ assertThat(postProcessedRequest.getParameter(token.getParameterName())).isNotEmpty().isNotEqualTo(token.getToken());
+ assertThat(postProcessedRequest.getHeader(token.getHeaderName())).isNull();
+ }
+
+ @Test
+ public void csrfWithInvalidHeader() {
+ MockHttpServletRequest postProcessedRequest = csrf().asHeader().useInvalidToken().postProcessRequest(request);
+
+ assertThat(postProcessedRequest.getParameter(token.getParameterName())).isNull();
+ assertThat(postProcessedRequest.getHeader(token.getHeaderName())).isNotEmpty().isNotEqualTo(token.getToken());
+ }
+
+ private void mockWebTestUtils() {
+ spy(WebTestUtils.class);
+ when(WebTestUtils.getCsrfTokenRepository(request)).thenReturn(repository);
+ when(repository.loadToken(request)).thenReturn(token);
+ when(repository.generateToken(request)).thenReturn(token);
+ }
+}
diff --git a/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsSecurityContextTests.java b/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsSecurityContextTests.java
new file mode 100644
index 0000000000..f6081b2580
--- /dev/null
+++ b/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsSecurityContextTests.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2002-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.security.test.web.servlet.request;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+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.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.securityContext;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.powermock.core.classloader.annotations.PrepareOnlyThisForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+import org.springframework.mock.web.MockHttpServletRequest;
+import org.springframework.security.core.context.SecurityContext;
+import org.springframework.security.test.context.TestSecurityContextHolder;
+import org.springframework.security.test.web.support.WebTestUtils;
+import org.springframework.security.web.context.SecurityContextRepository;
+
+@RunWith(PowerMockRunner.class)
+@PrepareOnlyThisForTest(WebTestUtils.class)
+public class SecurityMockMvcRequestPostProcessorsSecurityContextTests {
+ @Captor
+ private ArgumentCaptor contextCaptor;
+ @Mock
+ private SecurityContextRepository repository;
+
+ private MockHttpServletRequest request;
+
+ @Mock
+ private SecurityContext expectedContext;
+
+ @Before
+ public void setup() {
+ request = new MockHttpServletRequest();
+ mockWebTestUtils();
+ }
+
+ @After
+ public void cleanup() {
+ TestSecurityContextHolder.clearContext();
+ }
+
+ @Test
+ public void userDetails() {
+ securityContext(expectedContext).postProcessRequest(request);
+
+ verify(repository).saveContext(contextCaptor.capture(), eq(request), any(HttpServletResponse.class));
+ SecurityContext context = contextCaptor.getValue();
+ assertThat(context).isSameAs(this.expectedContext);
+ }
+
+ private void mockWebTestUtils() {
+ spy(WebTestUtils.class);
+ when(WebTestUtils.getSecurityContextRepository(request)).thenReturn(repository);
+ }
+}
\ No newline at end of file
diff --git a/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsTestSecurityContextTests.java b/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsTestSecurityContextTests.java
new file mode 100644
index 0000000000..39b1457f22
--- /dev/null
+++ b/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsTestSecurityContextTests.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2002-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.security.test.web.servlet.request;
+
+import static org.powermock.api.mockito.PowerMockito.*;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.any;
+import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.testSecurityContext;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.powermock.core.classloader.annotations.PrepareOnlyThisForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+import org.springframework.mock.web.MockHttpServletRequest;
+import org.springframework.security.core.context.SecurityContext;
+import org.springframework.security.test.context.TestSecurityContextHolder;
+import org.springframework.security.test.web.support.WebTestUtils;
+import org.springframework.security.web.context.SecurityContextRepository;
+
+@RunWith(PowerMockRunner.class)
+@PrepareOnlyThisForTest(WebTestUtils.class)
+public class SecurityMockMvcRequestPostProcessorsTestSecurityContextTests {
+ @Mock
+ private SecurityContext context;
+ @Mock
+ private SecurityContextRepository repository;
+
+ private MockHttpServletRequest request;
+
+ @Before
+ public void setup() {
+ request = new MockHttpServletRequest();
+ mockWebTestUtils();
+ }
+
+ @After
+ public void cleanup() {
+ TestSecurityContextHolder.clearContext();
+ }
+
+ @Test
+ public void testSecurityContextSaves() {
+ TestSecurityContextHolder.setContext(context);
+
+ testSecurityContext().postProcessRequest(request);
+
+ verify(repository).saveContext(eq(context), eq(request), any(HttpServletResponse.class));
+ }
+
+ // Ensure it does not fail if TestSecurityContextHolder is not initialized
+ @Test
+ public void testSecurityContextNoContext() {
+ testSecurityContext().postProcessRequest(request);
+
+ verify(repository).saveContext(any(SecurityContext.class), eq(request), any(HttpServletResponse.class));
+ }
+
+ private void mockWebTestUtils() {
+ spy(WebTestUtils.class);
+ when(WebTestUtils.getSecurityContextRepository(request)).thenReturn(repository);
+ }
+}
\ No newline at end of file
diff --git a/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsUserDetailsTests.java b/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsUserDetailsTests.java
new file mode 100644
index 0000000000..2576e33d2e
--- /dev/null
+++ b/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsUserDetailsTests.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2002-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.security.test.web.servlet.request;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+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.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.powermock.core.classloader.annotations.PrepareOnlyThisForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+import org.springframework.mock.web.MockHttpServletRequest;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.context.SecurityContext;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.test.context.TestSecurityContextHolder;
+import org.springframework.security.test.web.support.WebTestUtils;
+import org.springframework.security.web.context.SecurityContextRepository;
+
+@RunWith(PowerMockRunner.class)
+@PrepareOnlyThisForTest(WebTestUtils.class)
+public class SecurityMockMvcRequestPostProcessorsUserDetailsTests {
+ @Captor
+ private ArgumentCaptor contextCaptor;
+ @Mock
+ private SecurityContextRepository repository;
+
+ private MockHttpServletRequest request;
+
+ @Mock
+ private UserDetails userDetails;
+
+ @Before
+ public void setup() {
+ request = new MockHttpServletRequest();
+ mockWebTestUtils();
+ }
+
+ @After
+ public void cleanup() {
+ TestSecurityContextHolder.clearContext();
+ }
+
+ @Test
+ public void userDetails() {
+ user(userDetails).postProcessRequest(request);
+
+ verify(repository).saveContext(contextCaptor.capture(), eq(request), any(HttpServletResponse.class));
+ SecurityContext context = contextCaptor.getValue();
+ assertThat(context.getAuthentication()).isInstanceOf(UsernamePasswordAuthenticationToken.class);
+ assertThat(context.getAuthentication().getPrincipal()).isSameAs(userDetails);
+ }
+
+ private void mockWebTestUtils() {
+ spy(WebTestUtils.class);
+ when(WebTestUtils.getSecurityContextRepository(request)).thenReturn(repository);
+ }
+}
\ No newline at end of file
diff --git a/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsUserTests.java b/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsUserTests.java
new file mode 100644
index 0000000000..fe5caa6eb5
--- /dev/null
+++ b/test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsUserTests.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright 2002-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.security.test.web.servlet.request;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+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.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user;
+
+import java.util.Arrays;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.powermock.core.classloader.annotations.PrepareOnlyThisForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+import org.springframework.mock.web.MockHttpServletRequest;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.context.SecurityContext;
+import org.springframework.security.test.context.TestSecurityContextHolder;
+import org.springframework.security.test.web.support.WebTestUtils;
+import org.springframework.security.web.context.SecurityContextRepository;
+
+@RunWith(PowerMockRunner.class)
+@PrepareOnlyThisForTest(WebTestUtils.class)
+public class SecurityMockMvcRequestPostProcessorsUserTests {
+ @Captor
+ private ArgumentCaptor contextCaptor;
+ @Mock
+ private SecurityContextRepository repository;
+
+ private MockHttpServletRequest request;
+
+ @Mock
+ private GrantedAuthority authority1;
+ @Mock
+ private GrantedAuthority authority2;
+
+ @Before
+ public void setup() {
+ request = new MockHttpServletRequest();
+ mockWebTestUtils();
+ }
+
+ @After
+ public void cleanup() {
+ TestSecurityContextHolder.clearContext();
+ }
+
+ @Test
+ public void userWithDefaults() {
+ String username = "userabc";
+
+ user(username).postProcessRequest(request);
+
+ verify(repository).saveContext(contextCaptor.capture(), eq(request), any(HttpServletResponse.class));
+ SecurityContext context = contextCaptor.getValue();
+ assertThat(context.getAuthentication()).isInstanceOf(UsernamePasswordAuthenticationToken.class);
+ assertThat(context.getAuthentication().getName()).isEqualTo(username);
+ assertThat(context.getAuthentication().getCredentials()).isEqualTo("password");
+ assertThat(context.getAuthentication().getAuthorities()).onProperty("authority").containsOnly("ROLE_USER");
+ }
+
+
+ @Test
+ public void userWithCustom() {
+ String username = "customuser";
+
+ user(username)
+ .roles("CUSTOM","ADMIN")
+ .password("newpass")
+ .postProcessRequest(request);
+
+ verify(repository).saveContext(contextCaptor.capture(), eq(request), any(HttpServletResponse.class));
+ SecurityContext context = contextCaptor.getValue();
+ assertThat(context.getAuthentication()).isInstanceOf(UsernamePasswordAuthenticationToken.class);
+ assertThat(context.getAuthentication().getName()).isEqualTo(username);
+ assertThat(context.getAuthentication().getCredentials()).isEqualTo("newpass");
+ assertThat(context.getAuthentication().getAuthorities()).onProperty("authority").containsOnly("ROLE_CUSTOM","ROLE_ADMIN");
+ }
+
+ @Test
+ public void userCustomAuthoritiesVarargs() {
+ String username = "customuser";
+
+ user(username)
+ .authorities(authority1,authority2)
+ .postProcessRequest(request);
+
+ verify(repository).saveContext(contextCaptor.capture(), eq(request), any(HttpServletResponse.class));
+ SecurityContext context = contextCaptor.getValue();
+ assertThat(context.getAuthentication().getAuthorities()).containsOnly(authority1,authority2);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void userRolesWithRolePrefixErrors() {
+ user("user")
+ .roles("ROLE_INVALID")
+ .postProcessRequest(request);
+ }
+
+ @Test
+ public void userCustomAuthoritiesList() {
+ String username = "customuser";
+
+ user(username)
+ .authorities(Arrays.asList(authority1,authority2))
+ .postProcessRequest(request);
+
+ verify(repository).saveContext(contextCaptor.capture(), eq(request), any(HttpServletResponse.class));
+ SecurityContext context = contextCaptor.getValue();
+ assertThat(context.getAuthentication().getAuthorities()).containsOnly(authority1,authority2);
+ }
+
+ private void mockWebTestUtils() {
+ spy(WebTestUtils.class);
+ when(WebTestUtils.getSecurityContextRepository(request)).thenReturn(repository);
+ }
+}
\ No newline at end of file
diff --git a/test/src/test/java/org/springframework/security/test/web/servlet/showcase/csrf/CsrfShowcaseTests.java b/test/src/test/java/org/springframework/security/test/web/servlet/showcase/csrf/CsrfShowcaseTests.java
new file mode 100644
index 0000000000..d6a338be02
--- /dev/null
+++ b/test/src/test/java/org/springframework/security/test/web/servlet/showcase/csrf/CsrfShowcaseTests.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2002-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.security.test.web.servlet.showcase.csrf;
+import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.*;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
+
+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.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import org.springframework.security.config.annotation.web.servlet.configuration.EnableWebMvcSecurity;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.context.web.WebAppConfiguration;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+import org.springframework.web.context.WebApplicationContext;
+import org.springframework.web.servlet.config.annotation.EnableWebMvc;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration(classes=CsrfShowcaseTests.Config.class)
+@WebAppConfiguration
+public class CsrfShowcaseTests {
+
+ @Autowired
+ private WebApplicationContext context;
+
+ @Autowired
+ private Filter springSecurityFilterChain;
+
+ private MockMvc mvc;
+
+ @Before
+ public void setup() {
+ mvc = MockMvcBuilders
+ .webAppContextSetup(context)
+ .addFilters(springSecurityFilterChain)
+ .build();
+ }
+
+ @Test
+ public void postWithCsrfWorks() throws Exception {
+ mvc
+ .perform(post("/").with(csrf()))
+ .andExpect(status().isNotFound());
+ }
+
+ @Test
+ public void postWithCsrfWorksWithPut() throws Exception {
+ mvc
+ .perform(put("/").with(csrf()))
+ .andExpect(status().isNotFound());
+ }
+
+ @Test
+ public void postWithNoCsrfForbidden() throws Exception {
+ mvc
+ .perform(post("/"))
+ .andExpect(status().isForbidden());
+ }
+
+ @Configuration
+ @EnableWebMvcSecurity
+ @EnableWebMvc
+ static class Config extends WebSecurityConfigurerAdapter {
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ }
+
+ @Autowired
+ public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
+ auth
+ .inMemoryAuthentication()
+ .withUser("user").password("password").roles("USER");
+ }
+ }
+}
diff --git a/test/src/test/java/org/springframework/security/test/web/servlet/showcase/csrf/CustomCsrfShowcaseTests.java b/test/src/test/java/org/springframework/security/test/web/servlet/showcase/csrf/CustomCsrfShowcaseTests.java
new file mode 100644
index 0000000000..262285dc6c
--- /dev/null
+++ b/test/src/test/java/org/springframework/security/test/web/servlet/showcase/csrf/CustomCsrfShowcaseTests.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2002-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.security.test.web.servlet.showcase.csrf;
+import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.*;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
+
+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.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import org.springframework.security.config.annotation.web.servlet.configuration.EnableWebMvcSecurity;
+import org.springframework.security.web.csrf.CsrfTokenRepository;
+import org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.context.web.WebAppConfiguration;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+import org.springframework.web.context.WebApplicationContext;
+import org.springframework.web.servlet.config.annotation.EnableWebMvc;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration(classes=CustomCsrfShowcaseTests.Config.class)
+@WebAppConfiguration
+public class CustomCsrfShowcaseTests {
+
+ @Autowired
+ private WebApplicationContext context;
+
+ @Autowired
+ private Filter springSecurityFilterChain;
+
+ @Autowired
+ private CsrfTokenRepository repository;
+
+ private MockMvc mvc;
+
+ @Before
+ public void setup() {
+ mvc = MockMvcBuilders
+ .webAppContextSetup(context)
+ .defaultRequest(get("/").with(csrf()))
+ .addFilters(springSecurityFilterChain)
+ .build();
+ }
+
+ @Test
+ public void postWithCsrfWorks() throws Exception {
+ mvc
+ .perform(post("/").with(csrf()))
+ .andExpect(status().isNotFound());
+ }
+
+ @Test
+ public void postWithCsrfWorksWithPut() throws Exception {
+ mvc
+ .perform(put("/").with(csrf()))
+ .andExpect(status().isNotFound());
+ }
+
+ @Configuration
+ @EnableWebMvcSecurity
+ @EnableWebMvc
+ static class Config extends WebSecurityConfigurerAdapter {
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ http
+ .csrf()
+ .csrfTokenRepository(repo());
+ }
+
+ @Autowired
+ public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
+ auth
+ .inMemoryAuthentication()
+ .withUser("user").password("password").roles("USER");
+ }
+
+ @Bean
+ public CsrfTokenRepository repo() {
+ HttpSessionCsrfTokenRepository repo = new HttpSessionCsrfTokenRepository();
+ repo.setParameterName("custom_csrf");
+ return repo;
+ }
+ }
+}
diff --git a/test/src/test/java/org/springframework/security/test/web/servlet/showcase/csrf/DefaultCsrfShowcaseTests.java b/test/src/test/java/org/springframework/security/test/web/servlet/showcase/csrf/DefaultCsrfShowcaseTests.java
new file mode 100644
index 0000000000..43d898fdf8
--- /dev/null
+++ b/test/src/test/java/org/springframework/security/test/web/servlet/showcase/csrf/DefaultCsrfShowcaseTests.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2002-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.security.test.web.servlet.showcase.csrf;
+import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.*;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
+
+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.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import org.springframework.security.config.annotation.web.servlet.configuration.EnableWebMvcSecurity;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.context.web.WebAppConfiguration;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+import org.springframework.web.context.WebApplicationContext;
+import org.springframework.web.servlet.config.annotation.EnableWebMvc;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration(classes=DefaultCsrfShowcaseTests.Config.class)
+@WebAppConfiguration
+public class DefaultCsrfShowcaseTests {
+
+ @Autowired
+ private WebApplicationContext context;
+
+ @Autowired
+ private Filter springSecurityFilterChain;
+
+ private MockMvc mvc;
+
+ @Before
+ public void setup() {
+ mvc = MockMvcBuilders
+ .webAppContextSetup(context)
+ .defaultRequest(get("/").with(csrf()))
+ .addFilters(springSecurityFilterChain)
+ .build();
+ }
+
+ @Test
+ public void postWithCsrfWorks() throws Exception {
+ mvc
+ .perform(post("/"))
+ .andExpect(status().isNotFound());
+ }
+
+ @Test
+ public void postWithCsrfWorksWithPut() throws Exception {
+ mvc
+ .perform(put("/"))
+ .andExpect(status().isNotFound());
+ }
+
+ @Configuration
+ @EnableWebMvcSecurity
+ @EnableWebMvc
+ static class Config extends WebSecurityConfigurerAdapter {
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ }
+
+ @Autowired
+ public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
+ auth
+ .inMemoryAuthentication()
+ .withUser("user").password("password").roles("USER");
+ }
+ }
+}
diff --git a/test/src/test/java/org/springframework/security/test/web/servlet/showcase/login/AuthenticationTests.java b/test/src/test/java/org/springframework/security/test/web/servlet/showcase/login/AuthenticationTests.java
new file mode 100644
index 0000000000..8d02d52abe
--- /dev/null
+++ b/test/src/test/java/org/springframework/security/test/web/servlet/showcase/login/AuthenticationTests.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2002-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.security.test.web.servlet.showcase.login;
+
+import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.*;
+import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.*;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
+import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.*;
+
+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.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import org.springframework.security.config.annotation.web.servlet.configuration.EnableWebMvcSecurity;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.context.web.WebAppConfiguration;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+import org.springframework.web.context.WebApplicationContext;
+import org.springframework.web.servlet.config.annotation.EnableWebMvc;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration(classes=AuthenticationTests.Config.class)
+@WebAppConfiguration
+public class AuthenticationTests {
+
+ @Autowired
+ private WebApplicationContext context;
+
+ @Autowired
+ private Filter springSecurityFilterChain;
+
+ private MockMvc mvc;
+
+ @Before
+ public void setup() {
+ mvc = MockMvcBuilders
+ .webAppContextSetup(context)
+ .addFilters(springSecurityFilterChain)
+ .build();
+ }
+
+ @Test
+ public void requiresAuthentication() throws Exception {
+ mvc
+ .perform(get("/"))
+ .andExpect(status().isMovedTemporarily());
+ }
+
+ @Test
+ public void httpBasicAuthenticationSuccess() throws Exception {
+ mvc
+ .perform(get("/secured/butnotfound").with(httpBasic("user","password")))
+ .andExpect(status().isNotFound())
+ .andExpect(authenticated().withUsername("user"));
+ }
+
+ @Test
+ public void authenticationSuccess() throws Exception {
+ mvc
+ .perform(formLogin())
+ .andExpect(status().isMovedTemporarily())
+ .andExpect(redirectedUrl("/"))
+ .andExpect(authenticated().withUsername("user"));
+ }
+
+ @Test
+ public void authenticationFailed() throws Exception {
+ mvc
+ .perform(formLogin().user("user").password("invalid"))
+ .andExpect(status().isMovedTemporarily())
+ .andExpect(redirectedUrl("/login?error"))
+ .andExpect(unauthenticated());
+ }
+
+ @Configuration
+ @EnableWebMvcSecurity
+ @EnableWebMvc
+ static class Config extends WebSecurityConfigurerAdapter {
+ @Autowired
+ public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
+ auth
+ .inMemoryAuthentication()
+ .withUser("user").password("password").roles("USER");
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/src/test/java/org/springframework/security/test/web/servlet/showcase/login/CustomConfigAuthenticationTests.java b/test/src/test/java/org/springframework/security/test/web/servlet/showcase/login/CustomConfigAuthenticationTests.java
new file mode 100644
index 0000000000..22e5d83fec
--- /dev/null
+++ b/test/src/test/java/org/springframework/security/test/web/servlet/showcase/login/CustomConfigAuthenticationTests.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright 2002-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.security.test.web.servlet.showcase.login;
+
+import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.*;
+import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.*;
+import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.*;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
+
+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.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import org.springframework.security.config.annotation.web.servlet.configuration.EnableWebMvcSecurity;
+import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
+import org.springframework.security.web.context.SecurityContextRepository;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.context.web.WebAppConfiguration;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+import org.springframework.web.context.WebApplicationContext;
+import org.springframework.web.servlet.config.annotation.EnableWebMvc;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration(classes=CustomConfigAuthenticationTests.Config.class)
+@WebAppConfiguration
+public class CustomConfigAuthenticationTests {
+
+ @Autowired
+ private WebApplicationContext context;
+
+ @Autowired
+ private Filter springSecurityFilterChain;
+
+ @Autowired
+ private SecurityContextRepository securityContextRepository;
+
+ private MockMvc mvc;
+
+ @Before
+ public void setup() {
+ mvc = MockMvcBuilders
+ .webAppContextSetup(context)
+ .defaultRequest(get("/"))
+ .addFilters(springSecurityFilterChain)
+ .build();
+ }
+
+ @Test
+ public void authenticationSuccess() throws Exception {
+ mvc
+ .perform(formLogin("/authenticate").user("user","user").password("pass","password"))
+ .andExpect(status().isMovedTemporarily())
+ .andExpect(redirectedUrl("/"))
+ .andExpect(authenticated().withUsername("user"));
+ }
+
+
+ @Test
+ public void withUserSuccess() throws Exception {
+ mvc
+ .perform(get("/").with(user("user")))
+ .andExpect(status().isNotFound())
+ .andExpect(authenticated().withUsername("user"));
+ }
+
+ @Test
+ public void authenticationFailed() throws Exception {
+ mvc
+ .perform(formLogin("/authenticate").user("user","notfound").password("pass","invalid"))
+ .andExpect(status().isMovedTemporarily())
+ .andExpect(redirectedUrl("/authenticate?error"))
+ .andExpect(unauthenticated());
+ }
+
+ @Configuration
+ @EnableWebMvcSecurity
+ @EnableWebMvc
+ static class Config extends WebSecurityConfigurerAdapter {
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ http
+ .authorizeRequests()
+ .anyRequest().authenticated()
+ .and()
+ .securityContext()
+ .securityContextRepository(securityContextRepository())
+ .and()
+ .formLogin()
+ .usernameParameter("user")
+ .passwordParameter("pass")
+ .loginPage("/authenticate");
+ }
+
+ @Autowired
+ public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
+ auth
+ .inMemoryAuthentication()
+ .withUser("user").password("password").roles("USER");
+ }
+
+ @Bean
+ public SecurityContextRepository securityContextRepository() {
+ HttpSessionSecurityContextRepository repo = new HttpSessionSecurityContextRepository();
+ repo.setSpringSecurityContextKey("CUSTOM");
+ return repo;
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/src/test/java/org/springframework/security/test/web/servlet/showcase/login/CustomLoginRequestBuilderAuthenticationTests.java b/test/src/test/java/org/springframework/security/test/web/servlet/showcase/login/CustomLoginRequestBuilderAuthenticationTests.java
new file mode 100644
index 0000000000..9952b78296
--- /dev/null
+++ b/test/src/test/java/org/springframework/security/test/web/servlet/showcase/login/CustomLoginRequestBuilderAuthenticationTests.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2002-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.security.test.web.servlet.showcase.login;
+
+import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.*;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
+
+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.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import org.springframework.security.config.annotation.web.servlet.configuration.EnableWebMvcSecurity;
+import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders;
+import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.FormLoginRequestBuilder;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.context.web.WebAppConfiguration;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+import org.springframework.web.context.WebApplicationContext;
+import org.springframework.web.servlet.config.annotation.EnableWebMvc;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration(classes=CustomLoginRequestBuilderAuthenticationTests.Config.class)
+@WebAppConfiguration
+public class CustomLoginRequestBuilderAuthenticationTests {
+
+ @Autowired
+ private WebApplicationContext context;
+
+ @Autowired
+ private Filter springSecurityFilterChain;
+
+ private MockMvc mvc;
+
+ @Before
+ public void setup() {
+ mvc = MockMvcBuilders
+ .webAppContextSetup(context)
+ .addFilters(springSecurityFilterChain)
+ .build();
+ }
+
+ @Test
+ public void authenticationSuccess() throws Exception {
+ mvc
+ .perform(login())
+ .andExpect(status().isMovedTemporarily())
+ .andExpect(redirectedUrl("/"))
+ .andExpect(authenticated().withUsername("user"));
+ }
+
+ @Test
+ public void authenticationFailed() throws Exception {
+ mvc
+ .perform(login().user("notfound").password("invalid"))
+ .andExpect(status().isMovedTemporarily())
+ .andExpect(redirectedUrl("/authenticate?error"))
+ .andExpect(unauthenticated());
+ }
+
+ static FormLoginRequestBuilder login() {
+ return SecurityMockMvcRequestBuilders
+ .formLogin("/authenticate")
+ .userParameter("user")
+ .passwordParam("pass");
+ }
+
+ @Configuration
+ @EnableWebMvcSecurity
+ @EnableWebMvc
+ static class Config extends WebSecurityConfigurerAdapter {
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ http
+ .authorizeRequests()
+ .anyRequest().authenticated()
+ .and()
+ .formLogin()
+ .usernameParameter("user")
+ .passwordParameter("pass")
+ .loginPage("/authenticate");
+ }
+
+ @Autowired
+ public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
+ auth
+ .inMemoryAuthentication()
+ .withUser("user").password("password").roles("USER");
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/src/test/java/org/springframework/security/test/web/servlet/showcase/secured/DefaultfSecurityRequestsTests.java b/test/src/test/java/org/springframework/security/test/web/servlet/showcase/secured/DefaultfSecurityRequestsTests.java
new file mode 100644
index 0000000000..8224ba096b
--- /dev/null
+++ b/test/src/test/java/org/springframework/security/test/web/servlet/showcase/secured/DefaultfSecurityRequestsTests.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2002-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.security.test.web.servlet.showcase.secured;
+
+import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.*;
+import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.*;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
+
+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.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import org.springframework.security.config.annotation.web.servlet.configuration.EnableWebMvcSecurity;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.context.web.WebAppConfiguration;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+import org.springframework.web.context.WebApplicationContext;
+import org.springframework.web.servlet.config.annotation.EnableWebMvc;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration(classes=DefaultfSecurityRequestsTests.Config.class)
+@WebAppConfiguration
+public class DefaultfSecurityRequestsTests {
+
+ @Autowired
+ private WebApplicationContext context;
+
+ @Autowired
+ private Filter springSecurityFilterChain;
+
+ private MockMvc mvc;
+
+ @Before
+ public void setup() {
+ mvc = MockMvcBuilders
+ .webAppContextSetup(context)
+ .defaultRequest(get("/").with(user("user").roles("ADMIN")))
+ .addFilters(springSecurityFilterChain)
+ .build();
+ }
+
+ @Test
+ public void requestProtectedUrlWithUser() throws Exception {
+ mvc
+ .perform(get("/"))
+ // Ensure we got past Security
+ .andExpect(status().isNotFound())
+ // Ensure it appears we are authenticated with user
+ .andExpect(authenticated().withUsername("user"));
+ }
+
+ @Test
+ public void requestProtectedUrlWithAdmin() throws Exception {
+ mvc
+ .perform(get("/admin"))
+ // Ensure we got past Security
+ .andExpect(status().isNotFound())
+ // Ensure it appears we are authenticated with user
+ .andExpect(authenticated().withUsername("user"));
+ }
+
+ @Configuration
+ @EnableWebMvcSecurity
+ @EnableWebMvc
+ static class Config extends WebSecurityConfigurerAdapter {
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ http
+ .authorizeRequests()
+ .antMatchers("/admin/**").hasRole("ADMIN")
+ .anyRequest().authenticated()
+ .and()
+ .formLogin();
+ }
+
+ @Autowired
+ public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
+ auth
+ .inMemoryAuthentication()
+ .withUser("user").password("password").roles("USER");
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/src/test/java/org/springframework/security/test/web/servlet/showcase/secured/SecurityRequestsTests.java b/test/src/test/java/org/springframework/security/test/web/servlet/showcase/secured/SecurityRequestsTests.java
new file mode 100644
index 0000000000..82af6745f5
--- /dev/null
+++ b/test/src/test/java/org/springframework/security/test/web/servlet/showcase/secured/SecurityRequestsTests.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2002-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.security.test.web.servlet.showcase.secured;
+
+import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.*;
+import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.*;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
+
+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.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.authentication.TestingAuthenticationToken;
+import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import org.springframework.security.config.annotation.web.servlet.configuration.EnableWebMvcSecurity;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.context.web.WebAppConfiguration;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+import org.springframework.web.context.WebApplicationContext;
+import org.springframework.web.servlet.config.annotation.EnableWebMvc;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration(classes=SecurityRequestsTests.Config.class)
+@WebAppConfiguration
+public class SecurityRequestsTests {
+
+ @Autowired
+ private WebApplicationContext context;
+
+ @Autowired
+ private Filter springSecurityFilterChain;
+
+ @Autowired
+ private UserDetailsService userDetailsService;
+
+ private MockMvc mvc;
+
+ @Before
+ public void setup() {
+ mvc = MockMvcBuilders
+ .webAppContextSetup(context)
+ .addFilters(springSecurityFilterChain)
+ .build();
+ }
+
+ @Test
+ public void requestProtectedUrlWithUser() throws Exception {
+ mvc
+ .perform(get("/").with(user("user")))
+ // Ensure we got past Security
+ .andExpect(status().isNotFound())
+ // Ensure it appears we are authenticated with user
+ .andExpect(authenticated().withUsername("user"));
+ }
+
+ @Test
+ public void requestProtectedUrlWithAdmin() throws Exception {
+ mvc
+ .perform(get("/admin").with(user("admin").roles("ADMIN")))
+ // Ensure we got past Security
+ .andExpect(status().isNotFound())
+ // Ensure it appears we are authenticated with admin
+ .andExpect(authenticated().withUsername("admin"));
+ }
+
+ @Test
+ public void requestProtectedUrlWithUserDetails() throws Exception {
+ UserDetails user = userDetailsService.loadUserByUsername("user");
+ mvc
+ .perform(get("/").with(user(user)))
+ // Ensure we got past Security
+ .andExpect(status().isNotFound())
+ // Ensure it appears we are authenticated with user
+ .andExpect(authenticated().withAuthenticationPrincipal(user));
+ }
+
+ @Test
+ public void requestProtectedUrlWithAuthentication() throws Exception {
+ Authentication authentication = new TestingAuthenticationToken("test", "notused", "ROLE_USER");
+ mvc
+ .perform(get("/").with(authentication(authentication)))
+ // Ensure we got past Security
+ .andExpect(status().isNotFound())
+ // Ensure it appears we are authenticated with user
+ .andExpect(authenticated().withAuthentication(authentication));
+ }
+
+ @Configuration
+ @EnableWebMvcSecurity
+ @EnableWebMvc
+ static class Config extends WebSecurityConfigurerAdapter {
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ http
+ .authorizeRequests()
+ .antMatchers("/admin/**").hasRole("ADMIN")
+ .anyRequest().authenticated()
+ .and()
+ .formLogin();
+ }
+
+ @Autowired
+ public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
+ auth
+ .inMemoryAuthentication()
+ .withUser("user").password("password").roles("USER");
+ }
+
+ @Override
+ @Bean
+ public UserDetailsService userDetailsServiceBean() throws Exception {
+ return super.userDetailsServiceBean();
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/src/test/java/org/springframework/security/test/web/servlet/showcase/secured/WithUserAuthenticationTests.java b/test/src/test/java/org/springframework/security/test/web/servlet/showcase/secured/WithUserAuthenticationTests.java
new file mode 100644
index 0000000000..dcc6a75ced
--- /dev/null
+++ b/test/src/test/java/org/springframework/security/test/web/servlet/showcase/secured/WithUserAuthenticationTests.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2002-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.security.test.web.servlet.showcase.secured;
+
+import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.*;
+import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.*;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
+
+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.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import org.springframework.security.config.annotation.web.servlet.configuration.EnableWebMvcSecurity;
+import org.springframework.security.test.context.support.WithMockUser;
+import org.springframework.security.test.context.support.WithSecurityContextTestExcecutionListener;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.TestExecutionListeners;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
+import org.springframework.test.context.support.DirtiesContextTestExecutionListener;
+import org.springframework.test.context.transaction.TransactionalTestExecutionListener;
+import org.springframework.test.context.web.ServletTestExecutionListener;
+import org.springframework.test.context.web.WebAppConfiguration;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+import org.springframework.web.context.WebApplicationContext;
+import org.springframework.web.servlet.config.annotation.EnableWebMvc;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration(classes=WithUserAuthenticationTests.Config.class)
+@WebAppConfiguration
+@TestExecutionListeners(listeners={ServletTestExecutionListener.class,
+ DependencyInjectionTestExecutionListener.class,
+ DirtiesContextTestExecutionListener.class,
+ TransactionalTestExecutionListener.class,
+ WithSecurityContextTestExcecutionListener.class})
+public class WithUserAuthenticationTests {
+
+ @Autowired
+ private WebApplicationContext context;
+
+ @Autowired
+ private Filter springSecurityFilterChain;
+
+ private MockMvc mvc;
+
+ @Before
+ public void setup() {
+ mvc = MockMvcBuilders
+ .webAppContextSetup(context)
+ .addFilters(springSecurityFilterChain)
+ .defaultRequest(get("/").with(testSecurityContext()))
+ .build();
+ }
+
+ @Test
+ @WithMockUser
+ public void requestProtectedUrlWithUser() throws Exception {
+ mvc
+ .perform(get("/"))
+ // Ensure we got past Security
+ .andExpect(status().isNotFound())
+ // Ensure it appears we are authenticated with user
+ .andExpect(authenticated().withUsername("user"));
+ }
+
+ @Test
+ @WithMockUser(roles="ADMIN")
+ public void requestProtectedUrlWithAdmin() throws Exception {
+ mvc
+ .perform(get("/admin"))
+ // Ensure we got past Security
+ .andExpect(status().isNotFound())
+ // Ensure it appears we are authenticated with user
+ .andExpect(authenticated().withUsername("user").withRoles("ADMIN"));
+ }
+
+ @Configuration
+ @EnableWebMvcSecurity
+ @EnableWebMvc
+ static class Config extends WebSecurityConfigurerAdapter {
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ http
+ .authorizeRequests()
+ .antMatchers("/admin/**").hasRole("ADMIN")
+ .anyRequest().authenticated()
+ .and()
+ .formLogin();
+ }
+
+ @Autowired
+ public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
+ auth
+ .inMemoryAuthentication()
+ .withUser("user").password("password").roles("USER");
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/src/test/java/org/springframework/security/test/web/servlet/showcase/secured/WithUserClassLevelAuthenticationTests.java b/test/src/test/java/org/springframework/security/test/web/servlet/showcase/secured/WithUserClassLevelAuthenticationTests.java
new file mode 100644
index 0000000000..99a49861a4
--- /dev/null
+++ b/test/src/test/java/org/springframework/security/test/web/servlet/showcase/secured/WithUserClassLevelAuthenticationTests.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2002-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.security.test.web.servlet.showcase.secured;
+
+import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.*;
+import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.*;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
+
+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.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import org.springframework.security.config.annotation.web.servlet.configuration.EnableWebMvcSecurity;
+import org.springframework.security.test.context.support.WithMockUser;
+import org.springframework.security.test.context.support.WithSecurityContextTestExcecutionListener;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.TestExecutionListeners;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
+import org.springframework.test.context.support.DirtiesContextTestExecutionListener;
+import org.springframework.test.context.transaction.TransactionalTestExecutionListener;
+import org.springframework.test.context.web.ServletTestExecutionListener;
+import org.springframework.test.context.web.WebAppConfiguration;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+import org.springframework.web.context.WebApplicationContext;
+import org.springframework.web.servlet.config.annotation.EnableWebMvc;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration(classes=WithUserClassLevelAuthenticationTests.Config.class)
+@WebAppConfiguration
+@TestExecutionListeners(listeners={ServletTestExecutionListener.class,
+ DependencyInjectionTestExecutionListener.class,
+ DirtiesContextTestExecutionListener.class,
+ TransactionalTestExecutionListener.class,
+ WithSecurityContextTestExcecutionListener.class})
+@WithMockUser(roles="ADMIN")
+public class WithUserClassLevelAuthenticationTests {
+
+ @Autowired
+ private WebApplicationContext context;
+
+ @Autowired
+ private Filter springSecurityFilterChain;
+
+ private MockMvc mvc;
+
+ @Before
+ public void setup() {
+ mvc = MockMvcBuilders
+ .webAppContextSetup(context)
+ .addFilters(springSecurityFilterChain)
+ .defaultRequest(get("/").with(testSecurityContext()))
+ .build();
+ }
+
+ @Test
+ public void requestProtectedUrlWithUser() throws Exception {
+ mvc
+ .perform(get("/"))
+ // Ensure we got past Security
+ .andExpect(status().isNotFound())
+ // Ensure it appears we are authenticated with user
+ .andExpect(authenticated().withUsername("user"));
+ }
+
+ @Test
+ public void requestProtectedUrlWithAdmin() throws Exception {
+ mvc
+ .perform(get("/admin"))
+ // Ensure we got past Security
+ .andExpect(status().isNotFound())
+ // Ensure it appears we are authenticated with user
+ .andExpect(authenticated().withUsername("user").withRoles("ADMIN"));
+ }
+
+ @Configuration
+ @EnableWebMvcSecurity
+ @EnableWebMvc
+ static class Config extends WebSecurityConfigurerAdapter {
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ http
+ .authorizeRequests()
+ .antMatchers("/admin/**").hasRole("ADMIN")
+ .anyRequest().authenticated()
+ .and()
+ .formLogin();
+ }
+
+ @Autowired
+ public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
+ auth
+ .inMemoryAuthentication()
+ .withUser("user").password("password").roles("USER");
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/src/test/java/org/springframework/security/test/web/servlet/showcase/secured/WithUserDetailsAuthenticationTests.java b/test/src/test/java/org/springframework/security/test/web/servlet/showcase/secured/WithUserDetailsAuthenticationTests.java
new file mode 100644
index 0000000000..66ef676989
--- /dev/null
+++ b/test/src/test/java/org/springframework/security/test/web/servlet/showcase/secured/WithUserDetailsAuthenticationTests.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2002-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.security.test.web.servlet.showcase.secured;
+
+import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.testSecurityContext;
+import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.authenticated;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+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.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import org.springframework.security.config.annotation.web.servlet.configuration.EnableWebMvcSecurity;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.test.context.support.WithUserDetails;
+import org.springframework.security.test.context.support.WithSecurityContextTestExcecutionListener;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.TestExecutionListeners;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
+import org.springframework.test.context.support.DirtiesContextTestExecutionListener;
+import org.springframework.test.context.transaction.TransactionalTestExecutionListener;
+import org.springframework.test.context.web.ServletTestExecutionListener;
+import org.springframework.test.context.web.WebAppConfiguration;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+import org.springframework.web.context.WebApplicationContext;
+import org.springframework.web.servlet.config.annotation.EnableWebMvc;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration(classes=WithUserDetailsAuthenticationTests.Config.class)
+@WebAppConfiguration
+@TestExecutionListeners(listeners={ServletTestExecutionListener.class,
+ DependencyInjectionTestExecutionListener.class,
+ DirtiesContextTestExecutionListener.class,
+ TransactionalTestExecutionListener.class,
+ WithSecurityContextTestExcecutionListener.class})
+public class WithUserDetailsAuthenticationTests {
+
+ @Autowired
+ private WebApplicationContext context;
+
+ @Autowired
+ private Filter springSecurityFilterChain;
+
+ private MockMvc mvc;
+
+ @Before
+ public void setup() {
+ mvc = MockMvcBuilders
+ .webAppContextSetup(context)
+ .addFilters(springSecurityFilterChain)
+ .defaultRequest(get("/").with(testSecurityContext()))
+ .build();
+ }
+
+ @Test
+ @WithUserDetails
+ public void requestProtectedUrlWithUser() throws Exception {
+ mvc
+ .perform(get("/"))
+ // Ensure we got past Security
+ .andExpect(status().isNotFound())
+ // Ensure it appears we are authenticated with user
+ .andExpect(authenticated().withUsername("user"));
+ }
+
+ @Test
+ @WithUserDetails("admin")
+ public void requestProtectedUrlWithAdmin() throws Exception {
+ mvc
+ .perform(get("/admin"))
+ // Ensure we got past Security
+ .andExpect(status().isNotFound())
+ // Ensure it appears we are authenticated with user
+ .andExpect(authenticated().withUsername("admin").withRoles("ADMIN","USER"));
+ }
+
+ @Configuration
+ @EnableWebMvcSecurity
+ @EnableWebMvc
+ static class Config extends WebSecurityConfigurerAdapter {
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ http
+ .authorizeRequests()
+ .antMatchers("/admin/**").hasRole("ADMIN")
+ .anyRequest().authenticated()
+ .and()
+ .formLogin();
+ }
+
+ @Bean
+ @Override
+ public UserDetailsService userDetailsServiceBean() throws Exception {
+ return super.userDetailsServiceBean();
+ }
+
+ @Autowired
+ public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
+ auth
+ .inMemoryAuthentication()
+ .withUser("user").password("password").roles("USER").and()
+ .withUser("admin").password("password").roles("USER","ADMIN");
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/src/test/java/org/springframework/security/test/web/servlet/showcase/secured/WithUserDetailsClassLevelAuthenticationTests.java b/test/src/test/java/org/springframework/security/test/web/servlet/showcase/secured/WithUserDetailsClassLevelAuthenticationTests.java
new file mode 100644
index 0000000000..4dbf3871f2
--- /dev/null
+++ b/test/src/test/java/org/springframework/security/test/web/servlet/showcase/secured/WithUserDetailsClassLevelAuthenticationTests.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2002-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.security.test.web.servlet.showcase.secured;
+
+import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.testSecurityContext;
+import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.authenticated;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+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.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import org.springframework.security.config.annotation.web.servlet.configuration.EnableWebMvcSecurity;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.test.context.support.WithUserDetails;
+import org.springframework.security.test.context.support.WithSecurityContextTestExcecutionListener;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.TestExecutionListeners;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
+import org.springframework.test.context.support.DirtiesContextTestExecutionListener;
+import org.springframework.test.context.transaction.TransactionalTestExecutionListener;
+import org.springframework.test.context.web.ServletTestExecutionListener;
+import org.springframework.test.context.web.WebAppConfiguration;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+import org.springframework.web.context.WebApplicationContext;
+import org.springframework.web.servlet.config.annotation.EnableWebMvc;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration(classes=WithUserDetailsClassLevelAuthenticationTests.Config.class)
+@WebAppConfiguration
+@TestExecutionListeners(listeners={ServletTestExecutionListener.class,
+ DependencyInjectionTestExecutionListener.class,
+ DirtiesContextTestExecutionListener.class,
+ TransactionalTestExecutionListener.class,
+ WithSecurityContextTestExcecutionListener.class})
+@WithUserDetails("admin")
+public class WithUserDetailsClassLevelAuthenticationTests {
+
+ @Autowired
+ private WebApplicationContext context;
+
+ @Autowired
+ private Filter springSecurityFilterChain;
+
+ private MockMvc mvc;
+
+ @Before
+ public void setup() {
+ mvc = MockMvcBuilders
+ .webAppContextSetup(context)
+ .addFilters(springSecurityFilterChain)
+ .defaultRequest(get("/").with(testSecurityContext()))
+ .build();
+ }
+
+ @Test
+ public void requestRootUrlWithAdmin() throws Exception {
+ mvc
+ .perform(get("/"))
+ // Ensure we got past Security
+ .andExpect(status().isNotFound())
+ // Ensure it appears we are authenticated with user
+ .andExpect(authenticated().withUsername("admin").withRoles("ADMIN","USER"));
+ }
+
+ @Test
+ public void requestProtectedUrlWithAdmin() throws Exception {
+ mvc
+ .perform(get("/admin"))
+ // Ensure we got past Security
+ .andExpect(status().isNotFound())
+ // Ensure it appears we are authenticated with user
+ .andExpect(authenticated().withUsername("admin").withRoles("ADMIN","USER"));
+ }
+
+ @Configuration
+ @EnableWebMvcSecurity
+ @EnableWebMvc
+ static class Config extends WebSecurityConfigurerAdapter {
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ http
+ .authorizeRequests()
+ .antMatchers("/admin/**").hasRole("ADMIN")
+ .anyRequest().authenticated()
+ .and()
+ .formLogin();
+ }
+
+ @Bean
+ @Override
+ public UserDetailsService userDetailsServiceBean() throws Exception {
+ return super.userDetailsServiceBean();
+ }
+
+ @Autowired
+ public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
+ auth
+ .inMemoryAuthentication()
+ .withUser("user").password("password").roles("USER").and()
+ .withUser("admin").password("password").roles("USER","ADMIN");
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/src/test/java/org/springframework/security/test/web/support/WebTestUtilsTests.java b/test/src/test/java/org/springframework/security/test/web/support/WebTestUtilsTests.java
new file mode 100644
index 0000000000..055ef8270d
--- /dev/null
+++ b/test/src/test/java/org/springframework/security/test/web/support/WebTestUtilsTests.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright 2002-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.security.test.web.support;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.springframework.security.test.web.support.WebTestUtils.getCsrfTokenRepository;
+import static org.springframework.security.test.web.support.WebTestUtils.getSecurityContextRepository;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.springframework.context.ConfigurableApplicationContext;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.mock.web.MockHttpServletRequest;
+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.context.HttpSessionSecurityContextRepository;
+import org.springframework.security.web.context.SecurityContextRepository;
+import org.springframework.security.web.csrf.CsrfTokenRepository;
+import org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository;
+import org.springframework.web.context.WebApplicationContext;
+import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
+
+@RunWith(MockitoJUnitRunner.class)
+public class WebTestUtilsTests {
+ @Mock
+ private SecurityContextRepository contextRepo;
+ @Mock
+ private CsrfTokenRepository csrfRepo;
+
+ private MockHttpServletRequest request;
+ private ConfigurableApplicationContext context;
+
+ @Before
+ public void setup() {
+ request = new MockHttpServletRequest();
+ }
+
+ @After
+ public void cleanup() {
+ if(context != null) {
+ context.close();
+ }
+ }
+
+ @Test
+ public void getCsrfTokenRepositorytNoWac() {
+ assertThat(getCsrfTokenRepository(request)).isInstanceOf(HttpSessionCsrfTokenRepository.class);
+ }
+
+ @Test
+ public void getCsrfTokenRepositorytNoSecurity() {
+ loadConfig(Config.class);
+ assertThat(getCsrfTokenRepository(request)).isInstanceOf(HttpSessionCsrfTokenRepository.class);
+ }
+
+ @Test
+ public void getCsrfTokenRepositorytSecurityNoCsrf() {
+ loadConfig(SecurityNoCsrfConfig.class);
+ assertThat(getCsrfTokenRepository(request)).isInstanceOf(HttpSessionCsrfTokenRepository.class);
+ }
+
+ @Test
+ public void getCsrfTokenRepositorytSecurityCustomRepo() {
+ CustomSecurityConfig.CONTEXT_REPO = contextRepo;
+ CustomSecurityConfig.CSRF_REPO = csrfRepo;
+ loadConfig(CustomSecurityConfig.class);
+ assertThat(getCsrfTokenRepository(request)).isSameAs(csrfRepo);
+ }
+
+ // getSecurityContextRepository
+
+ @Test
+ public void getSecurityContextRepositoryNoWac() {
+ assertThat(getSecurityContextRepository(request)).isInstanceOf(HttpSessionSecurityContextRepository.class);
+ }
+
+ @Test
+ public void getSecurityContextRepositoryNoSecurity() {
+ loadConfig(Config.class);
+ assertThat(getSecurityContextRepository(request)).isInstanceOf(HttpSessionSecurityContextRepository.class);
+ }
+
+ @Test
+ public void getSecurityContextRepositorySecurityNoCsrf() {
+ loadConfig(SecurityNoCsrfConfig.class);
+ assertThat(getSecurityContextRepository(request)).isInstanceOf(HttpSessionSecurityContextRepository.class);
+ }
+
+ @Test
+ public void getSecurityContextRepositorySecurityCustomRepo() {
+ CustomSecurityConfig.CONTEXT_REPO = contextRepo;
+ CustomSecurityConfig.CSRF_REPO = csrfRepo;
+ loadConfig(CustomSecurityConfig.class);
+ assertThat(getSecurityContextRepository(request)).isSameAs(contextRepo);
+ }
+
+ private void loadConfig(Class> config) {
+ AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
+ context.register(config);
+ context.refresh();
+ this.context = context;
+ request.getServletContext().setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, context);
+ }
+
+ @Configuration
+ static class Config {}
+
+ @Configuration
+ @EnableWebSecurity
+ static class SecurityNoCsrfConfig extends WebSecurityConfigurerAdapter {
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ http.csrf().disable();
+ }
+ }
+
+ @Configuration
+ @EnableWebSecurity
+ static class CustomSecurityConfig extends WebSecurityConfigurerAdapter {
+ static CsrfTokenRepository CSRF_REPO;
+ static SecurityContextRepository CONTEXT_REPO;
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ http
+ .csrf()
+ .csrfTokenRepository(CSRF_REPO)
+ .and()
+ .securityContext()
+ .securityContextRepository(CONTEXT_REPO);
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/template.mf b/test/template.mf
new file mode 100644
index 0000000000..d2a39fe73c
--- /dev/null
+++ b/test/template.mf
@@ -0,0 +1,18 @@
+Implementation-Title: org.springframework.security.test
+Implementation-Version: ${version}
+Bundle-SymbolicName: org.springframework.security.test
+Bundle-Name: Spring Security Test
+Bundle-Vendor: SpringSource
+Bundle-Version: ${version}
+Bundle-ManifestVersion: 2
+Ignored-Existing-Headers:
+ Import-Package,
+ Export-Package
+Import-Template:
+ org.apache.commons.logging.*;version="${cloggingRange}",
+ org.springframework.security.core.*;version="${secRange}",
+ org.springframework.security.authentication.*;version="${secRange}",
+ org.springframework.security.web.*;version="${secRange}",
+ org.springframework.beans.factory;version="${springRange}",
+ org.springframework.util;version="${springRange}",
+ javax.servlet.*;version="0"
diff --git a/test/test.gradle b/test/test.gradle
new file mode 100644
index 0000000000..df85d572bc
--- /dev/null
+++ b/test/test.gradle
@@ -0,0 +1,13 @@
+// OpenID Module build file
+
+dependencies {
+ compile project(':spring-security-core'),
+ project(':spring-security-web'),
+ "org.springframework:spring-test:$springVersion"
+
+ provided "javax.servlet:javax.servlet-api:$servletApiVersion"
+
+ testCompile project(':spring-security-config'),
+ "org.springframework:spring-webmvc:$springVersion",
+ powerMockDependencies
+}
diff --git a/web/src/main/java/org/springframework/security/web/savedrequest/RequestCacheAdapter.java b/web/src/main/java/org/springframework/security/web/savedrequest/RequestCacheAdapter.java
new file mode 100644
index 0000000000..85df5c1f91
--- /dev/null
+++ b/web/src/main/java/org/springframework/security/web/savedrequest/RequestCacheAdapter.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2002-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.security.web.savedrequest;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.springframework.util.Assert;
+
+public class RequestCacheAdapter implements RequestCache {
+
+ private final RequestCache delegate;
+
+ public RequestCacheAdapter() {
+ this(new HttpSessionRequestCache());
+ }
+
+ public RequestCacheAdapter(RequestCache delegate) {
+ Assert.notNull(delegate, "delegate cannot be null");
+ this.delegate = delegate;
+ }
+
+ public void saveRequest(HttpServletRequest request,
+ HttpServletResponse response) {
+ delegate.saveRequest(request, response);
+ }
+
+ public SavedRequest getRequest(HttpServletRequest request,
+ HttpServletResponse response) {
+ SavedRequest result = delegate.getRequest(request, response);
+ Cookie[] cookies = request.getCookies();
+ return new SavedRequestAdapter(result, cookies == null ? null : Arrays.asList(cookies));
+ }
+
+ public HttpServletRequest getMatchingRequest(HttpServletRequest request,
+ HttpServletResponse response) {
+ return delegate.getMatchingRequest(request, response);
+ }
+
+ public void removeRequest(HttpServletRequest request,
+ HttpServletResponse response) {
+ delegate.removeRequest(request, response);
+ }
+
+ private static class SavedRequestAdapter implements SavedRequest {
+ private SavedRequest delegate;
+ private List cookies;
+
+ public SavedRequestAdapter(SavedRequest delegate, List cookies) {
+ this.delegate = delegate;
+ this.cookies = cookies;
+ }
+
+ public String getRedirectUrl() {
+ return delegate.getRedirectUrl();
+ }
+
+ public List getCookies() {
+ return cookies;
+ }
+
+ public String getMethod() {
+ return delegate.getMethod();
+ }
+
+ public List getHeaderValues(String name) {
+ return delegate.getHeaderValues(name);
+ }
+
+ public Collection getHeaderNames() {
+ return delegate.getHeaderNames();
+ }
+
+ public List getLocales() {
+ return delegate.getLocales();
+ }
+
+ public String[] getParameterValues(String name) {
+ return delegate.getParameterValues(name);
+ }
+
+ public Map getParameterMap() {
+ return delegate.getParameterMap();
+ }
+
+ private static final long serialVersionUID = 1184951442151447331L;
+ }
+}