Browse Source

SEC-2015: Add spring-security-test

Rob Winch 11 years ago
parent
commit
8baf82532c
48 changed files with 4647 additions and 10 deletions
  1. 2 0
      samples/hellomvc-jc/build.gradle
  2. 6 0
      samples/hellomvc-jc/pom.xml
  3. 110 3
      samples/hellomvc-jc/src/test/java/org/springframework/security/samples/config/SecurityConfigTests.java
  4. 6 6
      samples/messages-jc/pom.xml
  5. 2 1
      settings.gradle
  6. 132 0
      test/pom.xml
  7. 110 0
      test/src/main/java/org/springframework/security/test/context/TestSecurityContextHolder.java
  8. 83 0
      test/src/main/java/org/springframework/security/test/context/support/WithMockUser.java
  9. 57 0
      test/src/main/java/org/springframework/security/test/context/support/WithMockUserSecurityContextFactory.java
  10. 62 0
      test/src/main/java/org/springframework/security/test/context/support/WithSecurityContext.java
  11. 47 0
      test/src/main/java/org/springframework/security/test/context/support/WithSecurityContextFactory.java
  12. 107 0
      test/src/main/java/org/springframework/security/test/context/support/WithSecurityContextTestExcecutionListener.java
  13. 65 0
      test/src/main/java/org/springframework/security/test/context/support/WithUserDetails.java
  14. 54 0
      test/src/main/java/org/springframework/security/test/context/support/WithUserDetailsSecurityContextFactory.java
  15. 213 0
      test/src/main/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestBuilders.java
  16. 491 0
      test/src/main/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessors.java
  17. 226 0
      test/src/main/java/org/springframework/security/test/web/servlet/response/SecurityMockMvcResultMatchers.java
  18. 105 0
      test/src/main/java/org/springframework/security/test/web/support/WebTestUtils.java
  19. 64 0
      test/src/test/java/org/springframework/security/test/context/TestSecurityContextHolderTests.java
  20. 81 0
      test/src/test/java/org/springframework/security/test/context/support/WithMockUserSecurityContextFactoryTests.java
  21. 36 0
      test/src/test/java/org/springframework/security/test/context/support/WithMockUserTests.java
  22. 73 0
      test/src/test/java/org/springframework/security/test/context/support/WithSecurityContextTestExcecutionListenerTests.java
  23. 70 0
      test/src/test/java/org/springframework/security/test/context/support/WithUserDetailsSecurityContextFactoryTests.java
  24. 33 0
      test/src/test/java/org/springframework/security/test/context/support/WithUserDetailsTests.java
  25. 91 0
      test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestBuildersFormLoginTests.java
  26. 84 0
      test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestBuildersFormLogoutTests.java
  27. 81 0
      test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsAuthenticationTests.java
  28. 87 0
      test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsCsrfTests.java
  29. 80 0
      test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsSecurityContextTests.java
  30. 81 0
      test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsTestSecurityContextTests.java
  31. 83 0
      test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsUserDetailsTests.java
  32. 142 0
      test/src/test/java/org/springframework/security/test/web/servlet/request/SecurityMockMvcRequestPostProcessorsUserTests.java
  33. 98 0
      test/src/test/java/org/springframework/security/test/web/servlet/showcase/csrf/CsrfShowcaseTests.java
  34. 108 0
      test/src/test/java/org/springframework/security/test/web/servlet/showcase/csrf/CustomCsrfShowcaseTests.java
  35. 92 0
      test/src/test/java/org/springframework/security/test/web/servlet/showcase/csrf/DefaultCsrfShowcaseTests.java
  36. 107 0
      test/src/test/java/org/springframework/security/test/web/servlet/showcase/login/AuthenticationTests.java
  37. 132 0
      test/src/test/java/org/springframework/security/test/web/servlet/showcase/login/CustomConfigAuthenticationTests.java
  38. 112 0
      test/src/test/java/org/springframework/security/test/web/servlet/showcase/login/CustomLoginRequestBuilderAuthenticationTests.java
  39. 106 0
      test/src/test/java/org/springframework/security/test/web/servlet/showcase/secured/DefaultfSecurityRequestsTests.java
  40. 141 0
      test/src/test/java/org/springframework/security/test/web/servlet/showcase/secured/SecurityRequestsTests.java
  41. 120 0
      test/src/test/java/org/springframework/security/test/web/servlet/showcase/secured/WithUserAuthenticationTests.java
  42. 119 0
      test/src/test/java/org/springframework/security/test/web/servlet/showcase/secured/WithUserClassLevelAuthenticationTests.java
  43. 129 0
      test/src/test/java/org/springframework/security/test/web/servlet/showcase/secured/WithUserDetailsAuthenticationTests.java
  44. 128 0
      test/src/test/java/org/springframework/security/test/web/servlet/showcase/secured/WithUserDetailsClassLevelAuthenticationTests.java
  45. 152 0
      test/src/test/java/org/springframework/security/test/web/support/WebTestUtilsTests.java
  46. 18 0
      test/template.mf
  47. 13 0
      test/test.gradle
  48. 108 0
      web/src/main/java/org/springframework/security/web/savedrequest/RequestCacheAdapter.java

+ 2 - 0
samples/hellomvc-jc/build.gradle

@@ -22,4 +22,6 @@ dependencies {
     runtime "opensymphony:sitemesh:2.4.2",
     runtime "opensymphony:sitemesh:2.4.2",
             'cglib:cglib-nodep:2.2.2',
             'cglib:cglib-nodep:2.2.2',
             'ch.qos.logback:logback-classic:0.9.30'
             'ch.qos.logback:logback-classic:0.9.30'
+
+    testCompile project(":spring-security-test")
 }
 }

+ 6 - 0
samples/hellomvc-jc/pom.xml

@@ -208,6 +208,12 @@
       <version>1.9.5</version>
       <version>1.9.5</version>
       <scope>test</scope>
       <scope>test</scope>
     </dependency>
     </dependency>
+    <dependency>
+      <groupId>org.springframework.security</groupId>
+      <artifactId>spring-security-test</artifactId>
+      <version>4.0.0.CI-SNAPSHOT</version>
+      <scope>test</scope>
+    </dependency>
     <dependency>
     <dependency>
       <groupId>org.springframework</groupId>
       <groupId>org.springframework</groupId>
       <artifactId>spring-test</artifactId>
       <artifactId>spring-test</artifactId>

+ 110 - 3
samples/hellomvc-jc/src/test/java/org/springframework/security/samples/config/SecurityConfigTests.java

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright 2002-2013 the original author or authors.
+ * Copyright 2002-2014 the original author or authors.
  *
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * you may not use this file except in compliance with the License.
@@ -15,19 +15,126 @@
  */
  */
 package org.springframework.security.samples.config;
 package org.springframework.security.samples.config;
 
 
+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.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.Test;
 import org.junit.runner.RunWith;
 import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.samples.mvc.config.WebMvcConfiguration;
+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.ContextConfiguration;
+import org.springframework.test.context.TestExecutionListeners;
 import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
 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.request.MockHttpServletRequestBuilder;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+import org.springframework.web.context.WebApplicationContext;
 
 
 /**
 /**
  * @author Rob Winch
  * @author Rob Winch
  *
  *
  */
  */
 @RunWith(SpringJUnit4ClassRunner.class)
 @RunWith(SpringJUnit4ClassRunner.class)
-@ContextConfiguration(classes=SecurityConfig.class)
+@ContextConfiguration(classes={RootConfiguration.class, WebMvcConfiguration.class})
+@WebAppConfiguration
+@TestExecutionListeners(listeners={ServletTestExecutionListener.class,
+        DependencyInjectionTestExecutionListener.class,
+        DirtiesContextTestExecutionListener.class,
+        TransactionalTestExecutionListener.class,
+        WithSecurityContextTestExcecutionListener.class})
 public class SecurityConfigTests {
 public class SecurityConfigTests {
+    private MockMvc mvc;
+
+    @Autowired
+    private WebApplicationContext context;
+
+    @Autowired
+    private Filter springSecurityFilterChain;
+
+    @Before
+    public void setup() {
+        mvc = MockMvcBuilders
+                .webAppContextSetup(context)
+                .addFilters(springSecurityFilterChain)
+                .defaultRequest(get("/").with(testSecurityContext()))
+                .build();
+    }
+
+    @Test
+    public void requestProtectedResourceRequiresAuthentication() throws Exception {
+        mvc.perform(get("/"))
+            .andExpect(redirectedUrl("http://localhost/login"));
+    }
+
+    @Test
+    public void loginSuccess() throws Exception {
+        mvc.perform(formLogin())
+            .andExpect(redirectedUrl("/"));
+    }
+
+    @Test
+    public void loginFailure() throws Exception {
+        mvc.perform(formLogin().password("invalid"))
+            .andExpect(redirectedUrl("/login?error"));
+    }
+
+    @Test
+    @WithMockUser
+    public void requestProtectedResourceWithUser() throws Exception {
+        mvc.perform(get("/"))
+            .andExpect(status().isOk());
+    }
+
+    @Test
+    @WithMockUser
+    public void composeMessageRequiresCsrfToken() throws Exception {
+        MockHttpServletRequestBuilder composeMessage =
+            post("/")
+                .param("summary", "New Message")
+                .param("text", "This is a new message");
+
+        mvc.perform(composeMessage)
+            .andExpect(status().isForbidden());
+    }
+
+    @Test
+    @WithMockUser
+    public void composeMessage() throws Exception {
+        MockHttpServletRequestBuilder composeMessage =
+            post("/")
+                .param("summary", "New Message")
+                .param("text", "This is a new message")
+                .with(csrf());
+
+        mvc.perform(composeMessage)
+            .andExpect(redirectedUrlPattern("/*"));
+    }
+
+    @Test
+    @WithMockUser
+    public void logoutRequiresCsrfToken() throws Exception {
+        mvc.perform(post("/logout"))
+            .andExpect(status().isForbidden());
+    }
 
 
     @Test
     @Test
-    public void securityConfigurationLoads() {}
+    @WithMockUser
+    public void logoutSuccess() throws Exception {
+        mvc.perform(logout())
+            .andExpect(redirectedUrl("/login?logout"))
+            .andExpect(unauthenticated());
+    }
 }
 }

+ 6 - 6
samples/messages-jc/pom.xml

@@ -133,12 +133,6 @@
       <version>4.0.2.RELEASE</version>
       <version>4.0.2.RELEASE</version>
       <scope>compile</scope>
       <scope>compile</scope>
     </dependency>
     </dependency>
-    <dependency>
-      <groupId>org.springframework</groupId>
-      <artifactId>spring-core</artifactId>
-      <version>4.0.2.RELEASE</version>
-      <scope>compile</scope>
-    </dependency>
     <dependency>
     <dependency>
       <groupId>org.springframework</groupId>
       <groupId>org.springframework</groupId>
       <artifactId>spring-core</artifactId>
       <artifactId>spring-core</artifactId>
@@ -151,6 +145,12 @@
         </exclusion>
         </exclusion>
       </exclusions>
       </exclusions>
     </dependency>
     </dependency>
+    <dependency>
+      <groupId>org.springframework</groupId>
+      <artifactId>spring-core</artifactId>
+      <version>4.0.2.RELEASE</version>
+      <scope>compile</scope>
+    </dependency>
     <dependency>
     <dependency>
       <groupId>org.springframework</groupId>
       <groupId>org.springframework</groupId>
       <artifactId>spring-instrument</artifactId>
       <artifactId>spring-instrument</artifactId>

+ 2 - 1
settings.gradle

@@ -9,7 +9,8 @@ def String[] modules = [
     'openid',
     'openid',
     'taglibs',
     'taglibs',
     'aspects',
     'aspects',
-    'crypto'
+    'crypto',
+    'test'
 ]
 ]
 
 
 def String[] samples = [
 def String[] samples = [

+ 132 - 0
test/pom.xml

@@ -0,0 +1,132 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.springframework.security</groupId>
+  <artifactId>spring-security-test</artifactId>
+  <version>4.0.0.CI-SNAPSHOT</version>
+  <name>spring-security-test</name>
+  <description>spring-security-test</description>
+  <url>http://spring.io/spring-security</url>
+  <organization>
+    <name>spring.io</name>
+    <url>http://spring.io/</url>
+  </organization>
+  <licenses>
+    <license>
+      <name>The Apache Software License, Version 2.0</name>
+      <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
+      <distribution>repo</distribution>
+    </license>
+  </licenses>
+  <developers>
+    <developer>
+      <id>rwinch</id>
+      <name>Rob Winch</name>
+      <email>rwinch@gopivotal.com</email>
+    </developer>
+  </developers>
+  <scm>
+    <connection>scm:git:git://github.com/spring-projects/spring-security</connection>
+    <developerConnection>scm:git:git://github.com/spring-projects/spring-security</developerConnection>
+    <url>https://github.com/spring-projects/spring-security</url>
+  </scm>
+  <build>
+    <plugins>
+      <plugin>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <configuration>
+          <source>1.7</source>
+          <target>1.7</target>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+  <repositories>
+    <repository>
+      <id>spring-snasphot</id>
+      <url>https://repo.spring.io/snapshot</url>
+    </repository>
+  </repositories>
+  <dependencies>
+    <dependency>
+      <groupId>org.springframework.security</groupId>
+      <artifactId>spring-security-core</artifactId>
+      <version>4.0.0.CI-SNAPSHOT</version>
+      <scope>compile</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework.security</groupId>
+      <artifactId>spring-security-web</artifactId>
+      <version>4.0.0.CI-SNAPSHOT</version>
+      <scope>compile</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework</groupId>
+      <artifactId>spring-core</artifactId>
+      <version>4.0.2.RELEASE</version>
+      <scope>compile</scope>
+      <exclusions>
+        <exclusion>
+          <artifactId>commons-logging</artifactId>
+          <groupId>commons-logging</groupId>
+        </exclusion>
+      </exclusions>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework</groupId>
+      <artifactId>spring-test</artifactId>
+      <version>4.0.2.RELEASE</version>
+      <scope>compile</scope>
+    </dependency>
+    <dependency>
+      <groupId>commons-logging</groupId>
+      <artifactId>commons-logging</artifactId>
+      <version>1.1.1</version>
+      <scope>compile</scope>
+      <optional>true</optional>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.tomcat</groupId>
+      <artifactId>tomcat-servlet-api</artifactId>
+      <version>3.0.1</version>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>ch.qos.logback</groupId>
+      <artifactId>logback-classic</artifactId>
+      <version>0.9.29</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>4.11</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.easytesting</groupId>
+      <artifactId>fest-assert</artifactId>
+      <version>1.4</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-core</artifactId>
+      <version>1.9.5</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>jcl-over-slf4j</artifactId>
+      <version>1.7.5</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework.security</groupId>
+      <artifactId>spring-security-config</artifactId>
+      <version>4.0.0.CI-SNAPSHOT</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+</project>

+ 110 - 0
test/src/main/java/org/springframework/security/test/context/TestSecurityContextHolder.java

@@ -0,0 +1,110 @@
+/*
+ * 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 javax.servlet.FilterChain;
+
+import org.springframework.security.core.context.SecurityContext;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.test.context.support.WithSecurityContextTestExcecutionListener;
+import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors;
+import org.springframework.security.web.context.SecurityContextPersistenceFilter;
+import org.springframework.security.web.context.SecurityContextRepository;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.util.Assert;
+
+/**
+ * The {@link TestSecurityContextHolder} is very similar to
+ * {@link SecurityContextHolder}, but is necessary for testing. For example, we
+ * cannot populate the desired {@link SecurityContext} in
+ * {@link SecurityContextHolder} for web based testing. In a web request, the
+ * {@link SecurityContextPersistenceFilter} will override the
+ * {@link SecurityContextHolder} with the value returned by the
+ * {@link SecurityContextRepository}. At the end of the {@link FilterChain} the
+ * {@link SecurityContextPersistenceFilter} will clear out the
+ * {@link SecurityContextHolder}. This means if we make multiple web requests,
+ * we will not know which {@link SecurityContext} to use on subsequent requests.
+ *
+ * Typical usage is as follows:
+ *
+ * <ul>
+ * <li>Before a test is executed, the {@link TestSecurityContextHolder} is
+ * populated. Typically this is done using the
+ * {@link WithSecurityContextTestExcecutionListener}</li>
+ * <li>The test is ran. When used with {@link MockMvc} it is typically used with
+ * {@link SecurityMockMvcRequestPostProcessors#testSecurityContext()}. Which ensures
+ * the {@link SecurityContext} from {@link TestSecurityContextHolder} is
+ * properly populated.</li>
+ * <li>After the test is executed, the {@link TestSecurityContextHolder} and the
+ * {@link SecurityContextHolder} are cleared out</li>
+ * </ul>
+ *
+ * @author Rob Winch
+ * @since 4.0
+ *
+ */
+public final class TestSecurityContextHolder {
+
+    private static final ThreadLocal<SecurityContext> contextHolder = new ThreadLocal<SecurityContext>();
+
+    /**
+     * Clears the {@link SecurityContext} from {@link TestSecurityContextHolder}
+     * and {@link SecurityContextHolder}.
+     */
+    public static void clearContext() {
+        contextHolder.remove();
+        SecurityContextHolder.clearContext();
+    }
+
+    /**
+     * Gets the {@link SecurityContext} from {@link TestSecurityContextHolder}.
+     *
+     * @return the {@link SecurityContext} from {@link TestSecurityContextHolder}.
+     */
+    public static SecurityContext getContext() {
+        SecurityContext ctx = contextHolder.get();
+
+        if (ctx == null) {
+            ctx = getDefaultContext();
+            contextHolder.set(ctx);
+        }
+
+        return ctx;
+    }
+
+    /**
+     * Sets the {@link SecurityContext} on {@link TestSecurityContextHolder} and {@link SecurityContextHolder}.
+     * @param context the {@link SecurityContext} to use
+     */
+    public static void setContext(SecurityContext context) {
+        Assert.notNull(context,
+                "Only non-null SecurityContext instances are permitted");
+        contextHolder.set(context);
+        SecurityContextHolder.setContext(context);
+    }
+
+    /**
+     * Gets the default {@link SecurityContext} by delegating to the {@link SecurityContextHolder}
+     *
+     * @return the default {@link SecurityContext}
+     */
+    private static SecurityContext getDefaultContext() {
+        return SecurityContextHolder.getContext();
+    }
+
+    private TestSecurityContextHolder() {
+    }
+}

+ 83 - 0
test/src/main/java/org/springframework/security/test/context/support/WithMockUser.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.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.test.web.servlet.MockMvc;
+
+/**
+ * When used with {@link WithSecurityContextTestExcecutionListener} this annotation can be
+ * added to a test method to emulate running with a mocked user. In order to work with {@link MockMvc}  The
+ * {@link SecurityContext} that is used will have the following properties:
+ *
+ * <ul>
+ * <li>The {@link SecurityContext} created with be that of
+ * {@link SecurityContextHolder#createEmptyContext()}</li>
+ * <li>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()}.
+ * </ul>
+ *
+ * @see WithUserDetails
+ *
+ * @author Rob Winch
+ * @since 4.0
+ */
+@Target({ ElementType.METHOD, ElementType.TYPE })
+@Retention(RetentionPolicy.RUNTIME)
+@Inherited
+@Documented
+@WithSecurityContext(factory = WithMockUserSecurityContextFactory.class)
+public @interface WithMockUser {
+    /**
+     * Convenience mechanism for specifying the username. The default is "user". If {@link #username()} is specified it will be used instead of {@link #value()}
+     * @return
+     */
+    String value() default "user";
+
+    /**
+     * The username to be used. Note that {@link #value()} is a synonym for {@link #username()}, but if {@link #username()} is specified it will take precedence.
+     * @return
+     */
+    String username() default "";
+
+    /**
+     * The roles to use. The default is "USER". A {@link GrantedAuthority} will
+     * be created for each value within roles. Each value in roles will
+     * automatically be prefixed with "ROLE_". For example, the default will
+     * result in "ROLE_USER" being used.
+     *
+     * @return
+     */
+    String[] roles() default { "USER" };
+
+    /**
+     * The password to be used. The default is "password".
+     * @return
+     */
+    String password() default "password";
+}

+ 57 - 0
test/src/main/java/org/springframework/security/test/context/support/WithMockUserSecurityContextFactory.java

@@ -0,0 +1,57 @@
+/*
+ * 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.util.ArrayList;
+import java.util.List;
+
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+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.core.context.SecurityContextHolder;
+import org.springframework.security.core.userdetails.User;
+import org.springframework.util.StringUtils;
+
+/**
+ * A {@link WithUserDetailsSecurityContextFactory} that works with {@link WithMockUser}.
+ *
+ * @author Rob Winch
+ * @since 4.0
+ * @see WithMockUser
+ */
+final class WithMockUserSecurityContextFactory implements WithSecurityContextFactory<WithMockUser> {
+
+    public SecurityContext createSecurityContext(WithMockUser withUser) {
+        String username = StringUtils.hasLength(withUser.username()) ? withUser.username() : withUser.value();
+        if(username == null) {
+            throw new IllegalArgumentException(withUser + " cannot have null username on both username and value properites");
+        }
+        List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
+        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;
+    }
+}

+ 62 - 0
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;
+
+/**
+ * <p>
+ * An annotation to determine what {@link SecurityContext} to use. The
+ * {@link #factory()} attribute must be provided with an instance of
+ * {@link WithUserDetailsSecurityContextFactory}.
+ * </p>
+ *
+ * <p>
+ * Typically this annotation will be used as an meta-annotation as done with
+ * {@link WithMockUser} and {@link WithUserDetails}.
+ * </p>
+ *
+ * <p>
+ * 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.
+ * </p>
+ *
+ * @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();
+}

+ 47 - 0
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 <A>
+ * @see WithSecurityContext
+ * @see WithMockUser
+ * @see WithUserDetails
+ * @since 4.0
+ */
+public interface WithSecurityContextFactory<A extends Annotation> {
+
+    /**
+     * 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);
+}

+ 107 - 0
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();
+    }
+}

+ 65 - 0
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:
+ *
+ * <ul>
+ * <li>The {@link SecurityContext} created with be that of
+ * {@link SecurityContextHolder#createEmptyContext()}</li>
+ * <li>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()}.
+ * </ul>
+ *
+ * @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";
+}

+ 54 - 0
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<WithUserDetails> {
+
+    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;
+    }
+}

+ 213 - 0
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() {}
+}

+ 491 - 0
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<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>(
+                    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() { }
+}

+ 226 - 0
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<T extends AuthenticationMatcher<T>> 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<AuthenticatedMatcher> {
+
+        private SecurityContext expectedContext;
+        private Authentication expectedAuthentication;
+        private Object expectedAuthenticationPrincipal;
+        private String expectedAuthenticationName;
+        private Collection<GrantedAuthority> 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<GrantedAuthority> 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<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
+            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<UnAuthenticatedMatcher>{
+
+        public void match(MvcResult result) throws Exception {
+            SecurityContext context = load(result);
+
+            assertEquals("",null,context.getAuthentication());
+        }
+
+        private UnAuthenticatedMatcher() {}
+    }
+
+    private SecurityMockMvcResultMatchers() {}
+}

+ 105 - 0
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 extends Filter> T findFilter(HttpServletRequest request, Class<T> 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<Filter> filters = (List<Filter>) ReflectionTestUtils.invokeMethod(springSecurityFilterChain,"getFilters", request);
+        for(Filter filter : filters) {
+            if(filterClass.isAssignableFrom(filter.getClass())) {
+                return (T) filter;
+            }
+        }
+        return null;
+    }
+
+    private WebTestUtils() {}
+}

+ 64 - 0
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);
+    }
+}

+ 81 - 0
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);
+    }
+}

+ 36 - 0
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 {}
+}

+ 73 - 0
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 {}
+}

+ 70 - 0
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);
+    }
+}

+ 33 - 0
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 {}
+}

+ 91 - 0
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);
+    }
+}

+ 84 - 0
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);
+    }
+}

+ 81 - 0
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<SecurityContext> 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);
+    }
+}

+ 87 - 0
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);
+    }
+}

+ 80 - 0
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<SecurityContext> 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);
+    }
+}

+ 81 - 0
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);
+    }
+}

+ 83 - 0
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<SecurityContext> 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);
+    }
+}

+ 142 - 0
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<SecurityContext> 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);
+    }
+}

+ 98 - 0
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");
+        }
+    }
+}

+ 108 - 0
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;
+        }
+    }
+}

+ 92 - 0
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");
+        }
+    }
+}

+ 107 - 0
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");
+        }
+    }
+}

+ 132 - 0
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;
+        }
+    }
+}

+ 112 - 0
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");
+        }
+    }
+}

+ 106 - 0
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");
+        }
+    }
+}

+ 141 - 0
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();
+        }
+    }
+}

+ 120 - 0
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");
+        }
+    }
+}

+ 119 - 0
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");
+        }
+    }
+}

+ 129 - 0
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");
+        }
+    }
+}

+ 128 - 0
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");
+        }
+    }
+}

+ 152 - 0
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);
+        }
+    }
+}

+ 18 - 0
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"

+ 13 - 0
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
+}

+ 108 - 0
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<Cookie> cookies;
+
+        public SavedRequestAdapter(SavedRequest delegate, List<Cookie> cookies) {
+            this.delegate = delegate;
+            this.cookies = cookies;
+        }
+
+        public String getRedirectUrl() {
+            return delegate.getRedirectUrl();
+        }
+
+        public List<Cookie> getCookies() {
+            return cookies;
+        }
+
+        public String getMethod() {
+            return delegate.getMethod();
+        }
+
+        public List<String> getHeaderValues(String name) {
+            return delegate.getHeaderValues(name);
+        }
+
+        public Collection<String> getHeaderNames() {
+            return delegate.getHeaderNames();
+        }
+
+        public List<Locale> getLocales() {
+            return delegate.getLocales();
+        }
+
+        public String[] getParameterValues(String name) {
+            return delegate.getParameterValues(name);
+        }
+
+        public Map<String, String[]> getParameterMap() {
+            return delegate.getParameterMap();
+        }
+
+        private static final long serialVersionUID = 1184951442151447331L;
+    }
+}