diff --git a/test/src/main/java/org/springframework/security/test/context/support/WithMockUser.java b/test/src/main/java/org/springframework/security/test/context/support/WithMockUser.java index 818d9f0e7c..9144915ada 100644 --- a/test/src/main/java/org/springframework/security/test/context/support/WithMockUser.java +++ b/test/src/main/java/org/springframework/security/test/context/support/WithMockUser.java @@ -70,14 +70,33 @@ public @interface WithMockUser { 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. + *

+ *

+ * If {@link #authorities()} is specified this property cannot be changed from the default. + *

* * @return */ String[] roles() default { "USER" }; + /** + *

+ * The authorities to use. A {@link GrantedAuthority} will be created for each value. + *

+ * + *

+ * If this property is specified then {@link #roles()} is not used. This differs from + * {@link #roles()} in that it does not prefix the values passed in automatically. + *

+ * + * @return + */ + String[] authorities() default {}; + /** * The password to be used. The default is "password". * @return diff --git a/test/src/main/java/org/springframework/security/test/context/support/WithMockUserSecurityContextFactory.java b/test/src/main/java/org/springframework/security/test/context/support/WithMockUserSecurityContextFactory.java index 30a5881a85..9ac88da90d 100644 --- a/test/src/main/java/org/springframework/security/test/context/support/WithMockUserSecurityContextFactory.java +++ b/test/src/main/java/org/springframework/security/test/context/support/WithMockUserSecurityContextFactory.java @@ -16,6 +16,7 @@ package org.springframework.security.test.context.support; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; @@ -44,16 +45,26 @@ final class WithMockUserSecurityContextFactory implements throw new IllegalArgumentException(withUser + " cannot have null username on both username and value properites"); } - List authorities = new ArrayList(); - for (String role : withUser.roles()) { - if (role.startsWith("ROLE_")) { - throw new IllegalArgumentException("roles cannot start with ROLE_ Got " - + role); + + List grantedAuthorities = new ArrayList(); + for (String authority : withUser.authorities()) { + grantedAuthorities.add(new SimpleGrantedAuthority(authority)); + } + + if(grantedAuthorities.isEmpty()) { + for (String role : withUser.roles()) { + if (role.startsWith("ROLE_")) { + throw new IllegalArgumentException("roles cannot start with ROLE_ Got " + + role); + } + grantedAuthorities.add(new SimpleGrantedAuthority("ROLE_" + role)); } - authorities.add(new SimpleGrantedAuthority("ROLE_" + role)); + } else if(!(withUser.roles().length == 1 && "USER".equals(withUser.roles()[0]))) { + throw new IllegalStateException("You cannot define roles attribute "+ Arrays.asList(withUser.roles())+" with authorities attribute "+ Arrays.asList(withUser.authorities())); } + User principal = new User(username, withUser.password(), true, true, true, true, - authorities); + grantedAuthorities); Authentication authentication = new UsernamePasswordAuthenticationToken( principal, principal.getPassword(), principal.getAuthorities()); SecurityContext context = SecurityContextHolder.createEmptyContext(); diff --git a/test/src/test/java/org/springframework/security/test/context/showcase/WithMockUserTests.java b/test/src/test/java/org/springframework/security/test/context/showcase/WithMockUserTests.java index f95137c77a..9cd1a206e4 100644 --- a/test/src/test/java/org/springframework/security/test/context/showcase/WithMockUserTests.java +++ b/test/src/test/java/org/springframework/security/test/context/showcase/WithMockUserTests.java @@ -67,6 +67,13 @@ public class WithMockUserTests { .contains("ROLE_ADMIN"); } + @Test + @WithMockUser(username = "admin", authorities = { "ADMIN", "USER" }) + public void getMessageWithMockUserCustomAuthorities() { + String message = messageService.getMessage(); + assertThat(message).contains("admin").contains("ADMIN").contains("USER").doesNotContain("ROLE_"); + } + @EnableGlobalMethodSecurity(prePostEnabled = true) @ComponentScan(basePackageClasses = HelloMessageService.class) static class Config { diff --git a/test/src/test/java/org/springframework/security/test/context/support/WithMockUserSecurityContextFactoryTests.java b/test/src/test/java/org/springframework/security/test/context/support/WithMockUserSecurityContextFactoryTests.java index 2cf94b7070..6c844092c9 100644 --- a/test/src/test/java/org/springframework/security/test/context/support/WithMockUserSecurityContextFactoryTests.java +++ b/test/src/test/java/org/springframework/security/test/context/support/WithMockUserSecurityContextFactoryTests.java @@ -47,6 +47,7 @@ public class WithMockUserSecurityContextFactoryTests { when(withUser.value()).thenReturn("valueUser"); when(withUser.password()).thenReturn("password"); when(withUser.roles()).thenReturn(new String[] { "USER" }); + when(withUser.authorities()).thenReturn(new String[] {}); assertThat(factory.createSecurityContext(withUser).getAuthentication().getName()) .isEqualTo(withUser.value()); @@ -58,6 +59,7 @@ public class WithMockUserSecurityContextFactoryTests { when(withUser.username()).thenReturn("customUser"); when(withUser.password()).thenReturn("password"); when(withUser.roles()).thenReturn(new String[] { "USER" }); + when(withUser.authorities()).thenReturn(new String[] {}); assertThat(factory.createSecurityContext(withUser).getAuthentication().getName()) .isEqualTo(withUser.username()); @@ -68,6 +70,7 @@ public class WithMockUserSecurityContextFactoryTests { when(withUser.value()).thenReturn("valueUser"); when(withUser.password()).thenReturn("password"); when(withUser.roles()).thenReturn(new String[] { "USER", "CUSTOM" }); + when(withUser.authorities()).thenReturn(new String[] {}); assertThat( factory.createSecurityContext(withUser).getAuthentication() @@ -75,11 +78,35 @@ public class WithMockUserSecurityContextFactoryTests { "ROLE_USER", "ROLE_CUSTOM"); } + @Test + public void authoritiesWorks() { + when(withUser.value()).thenReturn("valueUser"); + when(withUser.password()).thenReturn("password"); + when(withUser.roles()).thenReturn(new String[] { "USER" }); + when(withUser.authorities()).thenReturn(new String[] { "USER", "CUSTOM" }); + + assertThat( + factory.createSecurityContext(withUser).getAuthentication() + .getAuthorities()).onProperty("authority").containsOnly( + "USER", "CUSTOM"); + } + + @Test(expected = IllegalStateException.class) + public void authoritiesAndRolesInvalid() { + when(withUser.value()).thenReturn("valueUser"); + when(withUser.password()).thenReturn("password"); + when(withUser.roles()).thenReturn(new String[] { "CUSTOM" }); + when(withUser.authorities()).thenReturn(new String[] { "USER", "CUSTOM" }); + + factory.createSecurityContext(withUser); + } + @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" }); + when(withUser.authorities()).thenReturn(new String[] {}); factory.createSecurityContext(withUser); }