Skip to content

Commit f02a7d2

Browse files
committed
Separate Testing Servlet Docs
Issue gh-10367
1 parent f39d272 commit f02a7d2

File tree

14 files changed

+820
-818
lines changed

14 files changed

+820
-818
lines changed

docs/modules/ROOT/nav.adoc

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,18 @@
8383
*** xref:servlet/configuration/xml-namespace.adoc[Namespace Configuration]
8484
** xref:servlet/test/index.adoc[Testing]
8585
*** xref:servlet/test/method.adoc[Method Security]
86-
*** xref:servlet/test/mockmvc.adoc[MockMvc Support]
86+
*** xref:servlet/test/mockmvc/index.adoc[MockMvc Support]
87+
*** xref:servlet/test/mockmvc/setup.adoc[MockMvc Setup]
88+
*** xref:servlet/test/mockmvc/request-post-processors.adoc[Security RequestPostProcessors]
89+
**** xref:servlet/test/mockmvc/authentication.adoc[Mocking Users]
90+
**** xref:servlet/test/mockmvc/csrf.adoc[Mocking CSRF]
91+
**** xref:servlet/test/mockmvc/form-login.adoc[Mocking Form Login]
92+
**** xref:servlet/test/mockmvc/http-basic.adoc[Mocking HTTP Basic]
93+
**** xref:servlet/test/mockmvc/oauth2.adoc[Mocking OAuth2]
94+
**** xref:servlet/test/mockmvc/logout.adoc[Mocking Logout]
95+
*** xref:servlet/test/mockmvc/request-builders.adoc[Security RequestBuilders]
96+
*** xref:servlet/test/mockmvc/result-matchers.adoc[Security ResultMatchers]
97+
*** xref:servlet/test/mockmvc/result-handlers.adoc[Security ResultHandlers]
8798
** xref:servlet/appendix/index.adoc[Appendix]
8899
*** xref:servlet/appendix/database-schema.adoc[Database Schemas]
89100
*** xref:servlet/appendix/namespace.adoc[XML Namespace]

docs/modules/ROOT/pages/servlet/authentication/logout.adoc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ If not configured a status code 200 will be returned by default.
140140
== Further Logout-Related References
141141

142142
- <<ns-logout, Logout Handling>>
143-
- xref:servlet/test/mockmvc.adoc#test-logout[ Testing Logout]
143+
- xref:servlet/test/mockmvc/logout.adoc#test-logout[ Testing Logout]
144144
- xref:servlet/integrations/servlet-api.adoc#servletapi-logout[ HttpServletRequest.logout()]
145145
- xref:servlet/authentication/rememberme.adoc#remember-me-impls[Remember-Me Interfaces and Implementations]
146146
- xref:servlet/exploits/csrf.adoc#servlet-considerations-csrf-logout[ Logging Out] in section CSRF Caveats
Lines changed: 274 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,274 @@
1+
[[test-mockmvc-securitycontextholder]]
2+
= Running a Test as a User in Spring MVC Test
3+
4+
It is often desirable to run tests as a specific user.
5+
There are two simple ways of populating the user:
6+
7+
* <<Running as a User in Spring MVC Test with RequestPostProcessor,Running as a User in Spring MVC Test with RequestPostProcessor>>
8+
* <<Running as a User in Spring MVC Test with Annotations,Running as a User in Spring MVC Test with Annotations>>
9+
10+
[[test-mockmvc-securitycontextholder-rpp]]
11+
== Running as a User in Spring MVC Test with RequestPostProcessor
12+
13+
There are a number of options available to associate a user to the current `HttpServletRequest`.
14+
For example, the following will run as a user (which does not need to exist) with the username "user", the password "password", and the role "ROLE_USER":
15+
16+
[NOTE]
17+
====
18+
The support works by associating the user to the `HttpServletRequest`.
19+
To associate the request to the `SecurityContextHolder` you need to ensure that the `SecurityContextPersistenceFilter` is associated with the `MockMvc` instance.
20+
A few ways to do this are:
21+
22+
* Invoking xref:servlet/test/mockmvc/setup.adoc#test-mockmvc-setup[`apply(springSecurity())`]
23+
* Adding Spring Security's `FilterChainProxy` to `MockMvc`
24+
* Manually adding `SecurityContextPersistenceFilter` to the `MockMvc` instance may make sense when using `MockMvcBuilders.standaloneSetup`
25+
====
26+
27+
====
28+
.Java
29+
[source,java,role="primary"]
30+
----
31+
mvc
32+
.perform(get("/").with(user("user")))
33+
----
34+
35+
.Kotlin
36+
[source,kotlin,role="secondary"]
37+
----
38+
mvc.get("/") {
39+
with(user("user"))
40+
}
41+
----
42+
====
43+
44+
You can easily make customizations.
45+
For example, the following will run as a user (which does not need to exist) with the username "admin", the password "pass", and the roles "ROLE_USER" and "ROLE_ADMIN".
46+
47+
====
48+
.Java
49+
[source,java,role="primary"]
50+
----
51+
mvc
52+
.perform(get("/admin").with(user("admin").password("pass").roles("USER","ADMIN")))
53+
----
54+
55+
.Kotlin
56+
[source,kotlin,role="secondary"]
57+
----
58+
mvc.get("/admin") {
59+
with(user("admin").password("pass").roles("USER","ADMIN"))
60+
}
61+
----
62+
====
63+
64+
If you have a custom `UserDetails` that you would like to use, you can easily specify that as well.
65+
For example, the following will use the specified `UserDetails` (which does not need to exist) to run with a `UsernamePasswordAuthenticationToken` that has a principal of the specified `UserDetails`:
66+
67+
====
68+
.Java
69+
[source,java,role="primary"]
70+
----
71+
mvc
72+
.perform(get("/").with(user(userDetails)))
73+
----
74+
75+
.Kotlin
76+
[source,kotlin,role="secondary"]
77+
----
78+
mvc.get("/") {
79+
with(user(userDetails))
80+
}
81+
----
82+
====
83+
84+
You can run as anonymous user using the following:
85+
86+
====
87+
.Java
88+
[source,java,role="primary"]
89+
----
90+
mvc
91+
.perform(get("/").with(anonymous()))
92+
----
93+
94+
.Kotlin
95+
[source,kotlin,role="secondary"]
96+
----
97+
mvc.get("/") {
98+
with(anonymous())
99+
}
100+
----
101+
====
102+
103+
This is especially useful if you are running with a default user and wish to process a few requests as an anonymous user.
104+
105+
If you want a custom `Authentication` (which does not need to exist) you can do so using the following:
106+
107+
====
108+
.Java
109+
[source,java,role="primary"]
110+
----
111+
mvc
112+
.perform(get("/").with(authentication(authentication)))
113+
----
114+
115+
.Kotlin
116+
[source,kotlin,role="secondary"]
117+
----
118+
mvc.get("/") {
119+
with(authentication(authentication))
120+
}
121+
----
122+
====
123+
124+
You can even customize the `SecurityContext` using the following:
125+
126+
====
127+
.Java
128+
[source,java,role="primary"]
129+
----
130+
mvc
131+
.perform(get("/").with(securityContext(securityContext)))
132+
----
133+
134+
.Kotlin
135+
[source,kotlin,role="secondary"]
136+
----
137+
mvc.get("/") {
138+
with(securityContext(securityContext))
139+
}
140+
----
141+
====
142+
143+
We can also ensure to run as a specific user for every request by using ``MockMvcBuilders``'s default request.
144+
For example, the following will run as a user (which does not need to exist) with the username "admin", the password "password", and the role "ROLE_ADMIN":
145+
146+
====
147+
.Java
148+
[source,java,role="primary"]
149+
----
150+
mvc = MockMvcBuilders
151+
.webAppContextSetup(context)
152+
.defaultRequest(get("/").with(user("user").roles("ADMIN")))
153+
.apply(springSecurity())
154+
.build();
155+
----
156+
157+
.Kotlin
158+
[source,kotlin,role="secondary"]
159+
----
160+
mvc = MockMvcBuilders
161+
.webAppContextSetup(context)
162+
.defaultRequest<DefaultMockMvcBuilder>(get("/").with(user("user").roles("ADMIN")))
163+
.apply<DefaultMockMvcBuilder>(springSecurity())
164+
.build()
165+
----
166+
====
167+
168+
If you find you are using the same user in many of your tests, it is recommended to move the user to a method.
169+
For example, you can specify the following in your own class named `CustomSecurityMockMvcRequestPostProcessors`:
170+
171+
====
172+
.Java
173+
[source,java,role="primary"]
174+
----
175+
public static RequestPostProcessor rob() {
176+
return user("rob").roles("ADMIN");
177+
}
178+
----
179+
180+
.Kotlin
181+
[source,kotlin,role="secondary"]
182+
----
183+
fun rob(): RequestPostProcessor {
184+
return user("rob").roles("ADMIN")
185+
}
186+
----
187+
====
188+
189+
Now you can perform a static import on `CustomSecurityMockMvcRequestPostProcessors` and use that within your tests:
190+
191+
====
192+
.Java
193+
[source,java,role="primary"]
194+
----
195+
import static sample.CustomSecurityMockMvcRequestPostProcessors.*;
196+
197+
...
198+
199+
mvc
200+
.perform(get("/").with(rob()))
201+
----
202+
203+
.Kotlin
204+
[source,kotlin,role="secondary"]
205+
----
206+
import sample.CustomSecurityMockMvcRequestPostProcessors.*
207+
208+
//...
209+
210+
mvc.get("/") {
211+
with(rob())
212+
}
213+
----
214+
====
215+
216+
[[test-mockmvc-withmockuser]]
217+
== Running as a User in Spring MVC Test with Annotations
218+
219+
As an alternative to using a `RequestPostProcessor` to create your user, you can use annotations described in xref:servlet/test/method.adoc[Testing Method Security].
220+
For example, the following will run the test with the user with username "user", password "password", and role "ROLE_USER":
221+
222+
====
223+
.Java
224+
[source,java,role="primary"]
225+
----
226+
@Test
227+
@WithMockUser
228+
public void requestProtectedUrlWithUser() throws Exception {
229+
mvc
230+
.perform(get("/"))
231+
...
232+
}
233+
----
234+
235+
.Kotlin
236+
[source,kotlin,role="secondary"]
237+
----
238+
@Test
239+
@WithMockUser
240+
fun requestProtectedUrlWithUser() {
241+
mvc
242+
.get("/")
243+
// ...
244+
}
245+
----
246+
====
247+
248+
Alternatively, the following will run the test with the user with username "user", password "password", and role "ROLE_ADMIN":
249+
250+
====
251+
.Java
252+
[source,java,role="primary"]
253+
----
254+
@Test
255+
@WithMockUser(roles="ADMIN")
256+
public void requestProtectedUrlWithUser() throws Exception {
257+
mvc
258+
.perform(get("/"))
259+
...
260+
}
261+
----
262+
263+
.Kotlin
264+
[source,kotlin,role="secondary"]
265+
----
266+
@Test
267+
@WithMockUser(roles = ["ADMIN"])
268+
fun requestProtectedUrlWithUser() {
269+
mvc
270+
.get("/")
271+
// ...
272+
}
273+
----
274+
====
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
[[test-mockmvc-csrf]]
2+
= Testing with CSRF Protection
3+
4+
When testing any non-safe HTTP methods and using Spring Security's CSRF protection, you must be sure to include a valid CSRF Token in the request.
5+
To specify a valid CSRF token as a request parameter use the CSRF xref:servlet/test/mockmvc/request-post-processors.adoc[`RequestPostProcessor`] like so:
6+
7+
====
8+
.Java
9+
[source,java,role="primary"]
10+
----
11+
mvc
12+
.perform(post("/").with(csrf()))
13+
----
14+
15+
.Kotlin
16+
[source,kotlin,role="secondary"]
17+
----
18+
mvc.post("/") {
19+
with(csrf())
20+
}
21+
----
22+
====
23+
24+
If you like you can include CSRF token in the header instead:
25+
26+
====
27+
.Java
28+
[source,java,role="primary"]
29+
----
30+
mvc
31+
.perform(post("/").with(csrf().asHeader()))
32+
----
33+
34+
.Kotlin
35+
[source,kotlin,role="secondary"]
36+
----
37+
mvc.post("/") {
38+
with(csrf().asHeader())
39+
}
40+
----
41+
====
42+
43+
You can also test providing an invalid CSRF token using the following:
44+
45+
====
46+
.Java
47+
[source,java,role="primary"]
48+
----
49+
mvc
50+
.perform(post("/").with(csrf().useInvalidToken()))
51+
----
52+
53+
.Kotlin
54+
[source,kotlin,role="secondary"]
55+
----
56+
mvc.post("/") {
57+
with(csrf().useInvalidToken())
58+
}
59+
----
60+
====

0 commit comments

Comments
 (0)