SEC-2984: WithMockUser authorities doc

This commit is contained in:
Rob Winch 2015-07-16 08:48:53 -05:00
parent e4517016ca
commit b96cee7950

View File

@ -14,7 +14,7 @@ public class HelloMessageService implements MessageService {
@PreAuthorize("authenticated") @PreAuthorize("authenticated")
public String getMessage() { public String getMessage() {
Authentication authentication = SecurityContextHolder.getContext() Authentication authentication = SecurityContextHolder.getContext()
.getAuthentication(); .getAuthentication();
return "Hello " + authentication; return "Hello " + authentication;
} }
} }
@ -56,7 +56,7 @@ If we ran the following test, we would expect the following test will pass:
---- ----
@Test(expected = AuthenticationCredentialsNotFoundException.class) @Test(expected = AuthenticationCredentialsNotFoundException.class)
public void getMessageUnauthenticated() { public void getMessageUnauthenticated() {
messageService.getMessage(); messageService.getMessage();
} }
---- ----
@ -72,8 +72,8 @@ The following test will be ran as a user with the username "user", the password
@Test @Test
@WithMockUser @WithMockUser
public void getMessageWithMockUser() { public void getMessageWithMockUser() {
String message = messageService.getMessage(); String message = messageService.getMessage();
... ...
} }
---- ----
@ -94,7 +94,7 @@ The following test would run with the username "customUser". Again, the user doe
@WithMockUser("customUsername") @WithMockUser("customUsername")
public void getMessageWithMockUserCustomUsername() { public void getMessageWithMockUserCustomUsername() {
String message = messageService.getMessage(); String message = messageService.getMessage();
... ...
} }
---- ----
@ -111,6 +111,19 @@ public void getMessageWithMockUserCustomUser() {
} }
---- ----
If we do not want the value to automatically be prefixed with ROLE_ we can leverage the authorities attribute.
For example, this test will be invoked with the username "admin" and the authorities "USER" and "ADMIN".
[source,java]
----
@Test
@WithMockUser(username = "admin", authorities = { "ADMIN", "USER" })
public void getMessageWithMockUserCustomAuthorities() {
String message = messageService.getMessage();
...
}
----
Of course it can be a bit tedious placing the annotation on every test method. Of course it can be a bit tedious placing the annotation on every test method.
Instead, we can place the annotation at the class level and every test will use the specified user. Instead, we can place the annotation at the class level and every test will use the specified user.
For example, the following would run every test with a user with the username "admin", the password "password", and the roles "ROLE_USER" and "ROLE_ADMIN". For example, the following would run every test with a user with the username "admin", the password "password", and the roles "ROLE_USER" and "ROLE_ADMIN".
@ -191,7 +204,7 @@ You can find our `WithMockCustomUserSecurityContextFactory` implementation below
[source,java] [source,java]
---- ----
public class WithMockCustomUserSecurityContextFactory public class WithMockCustomUserSecurityContextFactory
implements WithSecurityContextFactory<WithMockCustomUser> { implements WithSecurityContextFactory<WithMockCustomUser> {
@Override @Override
public SecurityContext createSecurityContext(WithMockCustomUser customUser) { public SecurityContext createSecurityContext(WithMockCustomUser customUser) {
SecurityContext context = SecurityContextHolder.createEmptyContext(); SecurityContext context = SecurityContextHolder.createEmptyContext();
@ -214,24 +227,24 @@ For example, the `WithUserDetailsSecurityContextFactory` uses the `@Autowired` a
[source,java] [source,java]
---- ----
final class WithUserDetailsSecurityContextFactory final class WithUserDetailsSecurityContextFactory
implements WithSecurityContextFactory<WithUserDetails> { implements WithSecurityContextFactory<WithUserDetails> {
private UserDetailsService userDetailsService; private UserDetailsService userDetailsService;
@Autowired @Autowired
public WithUserDetailsSecurityContextFactory(UserDetailsService userDetailsService) { public WithUserDetailsSecurityContextFactory(UserDetailsService userDetailsService) {
this.userDetailsService = userDetailsService; this.userDetailsService = userDetailsService;
} }
public SecurityContext createSecurityContext(WithUserDetails withUser) { public SecurityContext createSecurityContext(WithUserDetails withUser) {
String username = withUser.value(); String username = withUser.value();
Assert.hasLength(username, "value() must be non empty String"); Assert.hasLength(username, "value() must be non empty String");
UserDetails principal = userDetailsService.loadUserByUsername(username); UserDetails principal = userDetailsService.loadUserByUsername(username);
Authentication authentication = new UsernamePasswordAuthenticationToken(principal, principal.getPassword(), principal.getAuthorities()); Authentication authentication = new UsernamePasswordAuthenticationToken(principal, principal.getPassword(), principal.getAuthorities());
SecurityContext context = SecurityContextHolder.createEmptyContext(); SecurityContext context = SecurityContextHolder.createEmptyContext();
context.setAuthentication(authentication); context.setAuthentication(authentication);
return context; return context;
} }
} }
---- ----
@ -260,20 +273,20 @@ import static org.springframework.security.test.web.servlet.setup.SecurityMockMv
@WebAppConfiguration @WebAppConfiguration
public class CsrfShowcaseTests { public class CsrfShowcaseTests {
@Autowired @Autowired
private WebApplicationContext context; private WebApplicationContext context;
private MockMvc mvc; private MockMvc mvc;
@Before @Before
public void setup() { public void setup() {
mvc = MockMvcBuilders mvc = MockMvcBuilders
.webAppContextSetup(context) .webAppContextSetup(context)
.apply(springSecurity()) // <1> .apply(springSecurity()) // <1>
.build(); .build();
} }
... ...
---- ----
<1> `SecurityMockMvcConfigurers.springSecurity()` will perform all of the initial setup we need to integrate Spring Security with Spring MVC Test <1> `SecurityMockMvcConfigurers.springSecurity()` will perform all of the initial setup we need to integrate Spring Security with Spring MVC Test
@ -299,7 +312,7 @@ To specify a valid CSRF token as a request parameter using the following:
[source,java] [source,java]
---- ----
mvc mvc
.perform(post("/").with(csrf())) .perform(post("/").with(csrf()))
---- ----
If you like you can include CSRF token in the header instead: If you like you can include CSRF token in the header instead:
@ -307,7 +320,7 @@ If you like you can include CSRF token in the header instead:
[source,java] [source,java]
---- ----
mvc mvc
.perform(post("/").with(csrf().asHeader())) .perform(post("/").with(csrf().asHeader()))
---- ----
You can also test providing an invalid CSRF token using the following: You can also test providing an invalid CSRF token using the following:
@ -315,7 +328,7 @@ You can also test providing an invalid CSRF token using the following:
[source,java] [source,java]
---- ----
mvc mvc
.perform(post("/").with(csrf().useInvalidToken())) .perform(post("/").with(csrf().useInvalidToken()))
---- ----
[[test-mockmvc-securitycontextholder]] [[test-mockmvc-securitycontextholder]]
@ -336,7 +349,7 @@ For example, the following will run as a user (which does not need to exist) wit
[source,java] [source,java]
---- ----
mvc mvc
.perform(get("/").with(user("user"))) .perform(get("/").with(user("user")))
---- ----
You can easily make customizations. You can easily make customizations.
@ -345,7 +358,7 @@ For example, the following will run as a user (which does not need to exist) wit
[source,java] [source,java]
---- ----
mvc mvc
.perform(get("/admin").with(user("admin").password("pass").roles("USER","ADMIN"))) .perform(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. If you have a custom `UserDetails` that you would like to use, you can easily specify that as well.
@ -354,7 +367,7 @@ For example, the following will use the specified `UserDetails` (which does not
[source,java] [source,java]
---- ----
mvc mvc
.perform(get("/").with(user(userDetails))) .perform(get("/").with(user(userDetails)))
---- ----
If you want a custom `Authentication` (which does not need to exist) you can do so using the following: If you want a custom `Authentication` (which does not need to exist) you can do so using the following:
@ -362,7 +375,7 @@ If you want a custom `Authentication` (which does not need to exist) you can do
[source,java] [source,java]
---- ----
mvc mvc
.perform(get("/").with(authentication(authentication))) .perform(get("/").with(authentication(authentication)))
---- ----
You can even customize the `SecurityContext` using the following: You can even customize the `SecurityContext` using the following:
@ -370,7 +383,7 @@ You can even customize the `SecurityContext` using the following:
[source,java] [source,java]
---- ----
mvc mvc
.perform(get("/").with(securityContext(securityContext))) .perform(get("/").with(securityContext(securityContext)))
---- ----
We can also ensure to run as a specific user for every request by using `MockMvcBuilders`'s default request. We can also ensure to run as a specific user for every request by using `MockMvcBuilders`'s default request.
@ -379,10 +392,10 @@ For example, the following will run as a user (which does not need to exist) wit
[source,java] [source,java]
---- ----
mvc = MockMvcBuilders mvc = MockMvcBuilders
.webAppContextSetup(context) .webAppContextSetup(context)
.defaultRequest(get("/").with(user("user").roles("ADMIN"))) .defaultRequest(get("/").with(user("user").roles("ADMIN")))
.apply(springSecurity()) .apply(springSecurity())
.build(); .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. If you find you are using the same user in many of your tests, it is recommended to move the user to a method.
@ -404,7 +417,7 @@ import static sample.CustomSecurityMockMvcRequestPostProcessors.*;
... ...
mvc mvc
.perform(get("/").with(rob())) .perform(get("/").with(rob()))
---- ----
===== Running as a User in Spring MVC Test with Annotations ===== Running as a User in Spring MVC Test with Annotations
@ -417,9 +430,9 @@ For example, the following will run the test with the user with username "user",
@Test @Test
@WithMockUser @WithMockUser
public void requestProtectedUrlWithUser() throws Exception { public void requestProtectedUrlWithUser() throws Exception {
mvc mvc
.perform(get("/")) .perform(get("/"))
... ...
} }
---- ----
@ -430,9 +443,9 @@ Alternatively, the following will run the test with the user with username "user
@Test @Test
@WithMockUser(roles="ADMIN") @WithMockUser(roles="ADMIN")
public void requestProtectedUrlWithUser() throws Exception { public void requestProtectedUrlWithUser() throws Exception {
mvc mvc
.perform(get("/")) .perform(get("/"))
... ...
} }
---- ----
@ -445,7 +458,7 @@ For example, the snippet below:
[source,java] [source,java]
---- ----
mvc mvc
.perform(get("/").with(httpBasic("user","password"))) .perform(get("/").with(httpBasic("user","password")))
---- ----
will attempt to use HTTP Basic to authenticate a user with the username "user" and the password "password" by ensuring the following header is populated on the HTTP Request: will attempt to use HTTP Basic to authenticate a user with the username "user" and the password "password" by ensuring the following header is populated on the HTTP Request:
@ -474,7 +487,7 @@ For example, the following will submit a POST to "/login" with the username "use
[source,java] [source,java]
---- ----
mvc mvc
.perform(formLogin()) .perform(formLogin())
---- ----
It is easy to customize the request. It is easy to customize the request.
@ -483,7 +496,7 @@ For example, the following will submit a POST to "/auth" with the username "admi
[source,java] [source,java]
---- ----
mvc mvc
.perform(formLogin("/auth").user("admin").password("pass")) .perform(formLogin("/auth").user("admin").password("pass"))
---- ----
We can also customize the parameters names that the username and password are included on. We can also customize the parameters names that the username and password are included on.
@ -492,7 +505,7 @@ For example, this is the above request modified to include the username on the H
[source,java] [source,java]
---- ----
mvc mvc
.perform(formLogin("/auth").user("a","admin").password("p","pass")) .perform(formLogin("/auth").user("a","admin").password("p","pass"))
---- ----
[[test-logout]] [[test-logout]]
@ -504,7 +517,7 @@ For example, the following will submit a POST to "/logout" with a valid CSRF tok
[source,java] [source,java]
---- ----
mvc mvc
.perform(logout()) .perform(logout())
---- ----
You can also customize the URL to post to. You can also customize the URL to post to.
@ -513,7 +526,7 @@ For example, the snippet below will submit a POST to "/signout" with a valid CSR
[source,java] [source,java]
---- ----
mvc mvc
.perform(logout("/signout")) .perform(logout("/signout"))
---- ----
=== SecurityMockMvcResultMatchers === SecurityMockMvcResultMatchers
@ -536,8 +549,8 @@ You can easily do this with Spring Security's testing support using something li
[source,java] [source,java]
---- ----
mvc mvc
.perform(formLogin().password("invalid")) .perform(formLogin().password("invalid"))
.andExpect(unauthenticated()); .andExpect(unauthenticated());
---- ----
==== Authenticated Assertion ==== Authenticated Assertion
@ -549,8 +562,8 @@ We could verify that a form based login was successful with the following snippe
[source,java] [source,java]
---- ----
mvc mvc
.perform(formLogin()) .perform(formLogin())
.andExpect(authenticated()); .andExpect(authenticated());
---- ----
If we wanted to assert the roles of the user, we could refine our previous code as shown below: If we wanted to assert the roles of the user, we could refine our previous code as shown below:
@ -558,8 +571,8 @@ If we wanted to assert the roles of the user, we could refine our previous code
[source,java] [source,java]
---- ----
mvc mvc
.perform(formLogin().user("admin")) .perform(formLogin().user("admin"))
.andExpect(authenticated().withRoles("USER","ADMIN")); .andExpect(authenticated().withRoles("USER","ADMIN"));
---- ----
Alternatively, we could verify the username: Alternatively, we could verify the username:
@ -567,8 +580,8 @@ Alternatively, we could verify the username:
[source,java] [source,java]
---- ----
mvc mvc
.perform(formLogin().user("admin")) .perform(formLogin().user("admin"))
.andExpect(authenticated().withUsername("admin")); .andExpect(authenticated().withUsername("admin"));
---- ----
We can also combine the assertions: We can also combine the assertions:
@ -576,6 +589,6 @@ We can also combine the assertions:
[source,java] [source,java]
---- ----
mvc mvc
.perform(formLogin().user("admin").roles("USER","ADMIN")) .perform(formLogin().user("admin").roles("USER","ADMIN"))
.andExpect(authenticated().withUsername("admin")); .andExpect(authenticated().withUsername("admin"));
---- ----