1
0
mirror of synced 2026-08-31 14:35:18 +00:00

Make withRoles Check Only Roles

This commit clarifies the semantics of withRoles,
which is to check the role-based authorities in an
authentication.

Closes gh-17843
This commit is contained in:
Josh Cummings
2025-09-03 16:25:16 -06:00
parent bd119ac411
commit de10e08348
4 changed files with 44 additions and 23 deletions
@@ -18,7 +18,9 @@ package org.springframework.security.test.web.servlet.response;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Predicate;
import org.jspecify.annotations.NullUnmarked;
import org.jspecify.annotations.Nullable;
@@ -94,6 +96,8 @@ public final class SecurityMockMvcResultMatchers {
private @Nullable Collection<? extends GrantedAuthority> expectedGrantedAuthorities;
private Predicate<GrantedAuthority> ignoreAuthorities = (authority) -> false;
private @Nullable Consumer<Authentication> assertAuthentication;
AuthenticatedMatcher() {
@@ -132,7 +136,8 @@ public final class SecurityMockMvcResultMatchers {
}
if (this.expectedGrantedAuthorities != null) {
AssertionErrors.assertTrue("Authentication cannot be null", auth != null);
Collection<? extends GrantedAuthority> authorities = auth.getAuthorities();
Collection<? extends GrantedAuthority> authorities = new ArrayList<>(auth.getAuthorities());
authorities.removeIf(this.ignoreAuthorities);
AssertionErrors.assertTrue(
authorities + " does not contain the same authorities as " + this.expectedGrantedAuthorities,
authorities.containsAll(this.expectedGrantedAuthorities));
@@ -212,16 +217,43 @@ public final class SecurityMockMvcResultMatchers {
}
/**
* Specifies the {@link Authentication#getAuthorities()}
* Specifies the expected roles.
* <p>
* Since a set of authorities can contain more than just roles, this method
* differs from {@link #withAuthorities} in that it only verifies the authorities
* prefixed by {@code ROLE_}. Other authorities are ignored.
* <p>
* If you want to validate more than just roles, please use
* {@link #withAuthorities}.
* @param roles 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<>();
return withRoles("ROLE_", roles);
}
/**
* Specifies the expected roles.
* <p>
* Since a set of authorities can contain more than just roles, this method
* differs from {@link #withAuthorities} in that it only verifies the authorities
* prefixed by {@code ROLE_}. Other authorities are ignored.
* <p>
* If you want to validate more than just roles, please use
* {@link #withAuthorities}.
* @param rolePrefix the role prefix
* @param roles the roles. Each value is automatically prefixed with the
* {@code rolePrefix}
* @return the {@link AuthenticatedMatcher} for further customization
* @since 7.0
*/
public AuthenticatedMatcher withRoles(String rolePrefix, String[] roles) {
List<GrantedAuthority> withPrefix = new ArrayList<>();
for (String role : roles) {
authorities.add(new SimpleGrantedAuthority("ROLE_" + role));
withPrefix.add(new SimpleGrantedAuthority(rolePrefix + role));
}
return withAuthorities(authorities);
this.ignoreAuthorities = (authority) -> !authority.getAuthority().startsWith(rolePrefix);
return withAuthorities(withPrefix);
}
}