310 lines
6.4 KiB
Plaintext
310 lines
6.4 KiB
Plaintext
[[test-mockmvc-securitycontextholder]]
|
|
= Running a Test as a User in Spring MVC Test
|
|
|
|
It is often desirable to run tests as a specific user.
|
|
There are two simple ways to populate the user:
|
|
|
|
* <<test-mockmvc-securitycontextholder-rpp,Running as a User in Spring MVC Test with RequestPostProcessor>>
|
|
* <<running-as-a-user-in-spring-mvc-test-with-annotations,Running as a User in Spring MVC Test with Annotations>>
|
|
|
|
[[test-mockmvc-securitycontextholder-rpp]]
|
|
== Running as a User in Spring MVC Test with RequestPostProcessor
|
|
|
|
You have a number of options to associate a user to the current `HttpServletRequest`.
|
|
The following example runs as a user (which does not need to exist) whose username is `user`, whose password is `password`, and whose role is `ROLE_USER`:
|
|
|
|
[tabs]
|
|
======
|
|
Java::
|
|
+
|
|
[source,java,role="primary"]
|
|
----
|
|
mvc
|
|
.perform(get("/").with(user("user")))
|
|
----
|
|
|
|
Kotlin::
|
|
+
|
|
[source,kotlin,role="secondary"]
|
|
----
|
|
mvc.get("/") {
|
|
with(user("user"))
|
|
}
|
|
----
|
|
======
|
|
|
|
[NOTE]
|
|
====
|
|
The support works by associating the user to the `HttpServletRequest`.
|
|
To associate the request to the `SecurityContextHolder`, you need to ensure that the `SecurityContextPersistenceFilter` is associated with the `MockMvc` instance.
|
|
You can do so in a number of ways:
|
|
|
|
* Invoking xref:servlet/test/mockmvc/setup.adoc#test-mockmvc-setup[`apply(springSecurity())`]
|
|
* Adding Spring Security's `FilterChainProxy` to `MockMvc`
|
|
* Manually adding `SecurityContextPersistenceFilter` to the `MockMvc` instance may make sense when using `MockMvcBuilders.standaloneSetup`
|
|
====
|
|
|
|
|
|
|
|
You can easily make customizations.
|
|
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".
|
|
|
|
[tabs]
|
|
======
|
|
Java::
|
|
+
|
|
[source,java,role="primary"]
|
|
----
|
|
mvc
|
|
.perform(get("/admin").with(user("admin").password("pass").roles("USER","ADMIN")))
|
|
----
|
|
|
|
Kotlin::
|
|
+
|
|
[source,kotlin,role="secondary"]
|
|
----
|
|
mvc.get("/admin") {
|
|
with(user("admin").password("pass").roles("USER","ADMIN"))
|
|
}
|
|
----
|
|
======
|
|
|
|
If you have a custom `UserDetails` that you would like to use, you can easily specify that as well.
|
|
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`:
|
|
|
|
[tabs]
|
|
======
|
|
Java::
|
|
+
|
|
[source,java,role="primary"]
|
|
----
|
|
mvc
|
|
.perform(get("/").with(user(userDetails)))
|
|
----
|
|
|
|
Kotlin::
|
|
+
|
|
[source,kotlin,role="secondary"]
|
|
----
|
|
mvc.get("/") {
|
|
with(user(userDetails))
|
|
}
|
|
----
|
|
======
|
|
|
|
You can run as anonymous user using the following:
|
|
|
|
[tabs]
|
|
======
|
|
Java::
|
|
+
|
|
[source,java,role="primary"]
|
|
----
|
|
mvc
|
|
.perform(get("/").with(anonymous()))
|
|
----
|
|
|
|
Kotlin::
|
|
+
|
|
[source,kotlin,role="secondary"]
|
|
----
|
|
mvc.get("/") {
|
|
with(anonymous())
|
|
}
|
|
----
|
|
======
|
|
|
|
This is especially useful if you are running with a default user and wish to process a few requests as an anonymous user.
|
|
|
|
If you want a custom `Authentication` (which does not need to exist) you can do so using the following:
|
|
|
|
[tabs]
|
|
======
|
|
Java::
|
|
+
|
|
[source,java,role="primary"]
|
|
----
|
|
mvc
|
|
.perform(get("/").with(authentication(authentication)))
|
|
----
|
|
|
|
Kotlin::
|
|
+
|
|
[source,kotlin,role="secondary"]
|
|
----
|
|
mvc.get("/") {
|
|
with(authentication(authentication))
|
|
}
|
|
----
|
|
======
|
|
|
|
You can even customize the `SecurityContext` using the following:
|
|
|
|
[tabs]
|
|
======
|
|
Java::
|
|
+
|
|
[source,java,role="primary"]
|
|
----
|
|
mvc
|
|
.perform(get("/").with(securityContext(securityContext)))
|
|
----
|
|
|
|
Kotlin::
|
|
+
|
|
[source,kotlin,role="secondary"]
|
|
----
|
|
mvc.get("/") {
|
|
with(securityContext(securityContext))
|
|
}
|
|
----
|
|
======
|
|
|
|
We can also ensure to run as a specific user for every request by using ``MockMvcBuilders``'s default request.
|
|
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":
|
|
|
|
[tabs]
|
|
======
|
|
Java::
|
|
+
|
|
[source,java,role="primary"]
|
|
----
|
|
mvc = MockMvcBuilders
|
|
.webAppContextSetup(context)
|
|
.defaultRequest(get("/").with(user("user").roles("ADMIN")))
|
|
.apply(springSecurity())
|
|
.build();
|
|
----
|
|
|
|
Kotlin::
|
|
+
|
|
[source,kotlin,role="secondary"]
|
|
----
|
|
mvc = MockMvcBuilders
|
|
.webAppContextSetup(context)
|
|
.defaultRequest<DefaultMockMvcBuilder>(get("/").with(user("user").roles("ADMIN")))
|
|
.apply<DefaultMockMvcBuilder>(springSecurity())
|
|
.build()
|
|
----
|
|
======
|
|
|
|
If you find you are using the same user in many of your tests, it is recommended to move the user to a method.
|
|
For example, you can specify the following in your own class named `CustomSecurityMockMvcRequestPostProcessors`:
|
|
|
|
[tabs]
|
|
======
|
|
Java::
|
|
+
|
|
[source,java,role="primary"]
|
|
----
|
|
public static RequestPostProcessor rob() {
|
|
return user("rob").roles("ADMIN");
|
|
}
|
|
----
|
|
|
|
Kotlin::
|
|
+
|
|
[source,kotlin,role="secondary"]
|
|
----
|
|
fun rob(): RequestPostProcessor {
|
|
return user("rob").roles("ADMIN")
|
|
}
|
|
----
|
|
======
|
|
|
|
Now you can perform a static import on `CustomSecurityMockMvcRequestPostProcessors` and use that within your tests:
|
|
|
|
[tabs]
|
|
======
|
|
Java::
|
|
+
|
|
[source,java,role="primary"]
|
|
----
|
|
import static sample.CustomSecurityMockMvcRequestPostProcessors.*;
|
|
|
|
...
|
|
|
|
mvc
|
|
.perform(get("/").with(rob()))
|
|
----
|
|
|
|
Kotlin::
|
|
+
|
|
[source,kotlin,role="secondary"]
|
|
----
|
|
import sample.CustomSecurityMockMvcRequestPostProcessors.*
|
|
|
|
//...
|
|
|
|
mvc.get("/") {
|
|
with(rob())
|
|
}
|
|
----
|
|
======
|
|
|
|
[[test-mockmvc-withmockuser]]
|
|
== Running as a User in Spring MVC Test with Annotations
|
|
|
|
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].
|
|
For example, the following will run the test with the user with username "user", password "password", and role "ROLE_USER":
|
|
|
|
[tabs]
|
|
======
|
|
Java::
|
|
+
|
|
[source,java,role="primary"]
|
|
----
|
|
@Test
|
|
@WithMockUser
|
|
public void requestProtectedUrlWithUser() throws Exception {
|
|
mvc
|
|
.perform(get("/"))
|
|
...
|
|
}
|
|
----
|
|
|
|
Kotlin::
|
|
+
|
|
[source,kotlin,role="secondary"]
|
|
----
|
|
@Test
|
|
@WithMockUser
|
|
fun requestProtectedUrlWithUser() {
|
|
mvc
|
|
.get("/")
|
|
// ...
|
|
}
|
|
----
|
|
======
|
|
|
|
Alternatively, the following will run the test with the user with username "user", password "password", and role "ROLE_ADMIN":
|
|
|
|
[tabs]
|
|
======
|
|
Java::
|
|
+
|
|
[source,java,role="primary"]
|
|
----
|
|
@Test
|
|
@WithMockUser(roles="ADMIN")
|
|
public void requestProtectedUrlWithUser() throws Exception {
|
|
mvc
|
|
.perform(get("/"))
|
|
...
|
|
}
|
|
----
|
|
|
|
Kotlin::
|
|
+
|
|
[source,kotlin,role="secondary"]
|
|
----
|
|
@Test
|
|
@WithMockUser(roles = ["ADMIN"])
|
|
fun requestProtectedUrlWithUser() {
|
|
mvc
|
|
.get("/")
|
|
// ...
|
|
}
|
|
----
|
|
======
|