From 68742e170cc56b1ca6406da42c48d1872609f67a Mon Sep 17 00:00:00 2001 From: Andrey Litvitski Date: Mon, 22 Sep 2025 00:15:13 +0300 Subject: [PATCH] Support Automatically Checking for Required Authorities in Authorization Rules Closes: gh-17900 Signed-off-by: Andrey Litvitski --- .../DefaultAuthorizationManagerFactory.java | 60 ++++++++++++++++--- 1 file changed, 52 insertions(+), 8 deletions(-) diff --git a/core/src/main/java/org/springframework/security/authorization/DefaultAuthorizationManagerFactory.java b/core/src/main/java/org/springframework/security/authorization/DefaultAuthorizationManagerFactory.java index 09ad052a95..d9c21b9ead 100644 --- a/core/src/main/java/org/springframework/security/authorization/DefaultAuthorizationManagerFactory.java +++ b/core/src/main/java/org/springframework/security/authorization/DefaultAuthorizationManagerFactory.java @@ -29,6 +29,7 @@ import org.springframework.util.Assert; * * @param the type of object that the authorization check is being done on * @author Steve Riesenberg + * @author Andrey Litvitski * @since 7.0 */ public final class DefaultAuthorizationManagerFactory @@ -40,6 +41,8 @@ public final class DefaultAuthorizationManagerFactory + * Does not affect {@code anonymous}, {@code permitAll}, or {@code denyAll}. + *

+ * Evaluated with the configured {@link RoleHierarchy}. + * @param requiredAuthorities the required authorities (must not be {@code null}) + */ + public void setRequiredAuthorities(String[] requiredAuthorities) { + Assert.notNull(requiredAuthorities, "requiredAuthorities cannot be null"); + this.requiredAuthorities = requiredAuthorities; + } + + /** + * Creates a factory that requires the given authorities for authorization managers + * that apply to authenticated users. + *

+ * Does not affect {@code anonymous}, {@code permitAll}, or {@code denyAll}. + * @param authorities the required authorities + * @param the secured object type + * @return a factory configured with the required authorities + */ + public static AuthorizationManagerFactory withAuthorities(String... authorities) { + DefaultAuthorizationManagerFactory factory = new DefaultAuthorizationManagerFactory<>(); + factory.setRequiredAuthorities(authorities); + return factory; + } + @Override public AuthorizationManager hasRole(String role) { return hasAnyRole(role); @@ -76,42 +108,45 @@ public final class DefaultAuthorizationManagerFactory hasAnyRole(String... roles) { - return withRoleHierarchy(AuthorityAuthorizationManager.hasAnyRole(this.rolePrefix, roles)); + return withRequiredAuthorities( + withRoleHierarchy(AuthorityAuthorizationManager.hasAnyRole(this.rolePrefix, roles))); } @Override public AuthorizationManager hasAllRoles(String... roles) { - return withRoleHierarchy(AllAuthoritiesAuthorizationManager.hasAllPrefixedAuthorities(this.rolePrefix, roles)); + return withRequiredAuthorities(withRoleHierarchy( + AllAuthoritiesAuthorizationManager.hasAllPrefixedAuthorities(this.rolePrefix, roles))); } @Override public AuthorizationManager hasAuthority(String authority) { - return withRoleHierarchy(AuthorityAuthorizationManager.hasAuthority(authority)); + return withRequiredAuthorities(withRoleHierarchy(AuthorityAuthorizationManager.hasAuthority(authority))); } @Override public AuthorizationManager hasAnyAuthority(String... authorities) { - return withRoleHierarchy(AuthorityAuthorizationManager.hasAnyAuthority(authorities)); + return withRequiredAuthorities(withRoleHierarchy(AuthorityAuthorizationManager.hasAnyAuthority(authorities))); } @Override public AuthorizationManager hasAllAuthorities(String... authorities) { - return withRoleHierarchy(AllAuthoritiesAuthorizationManager.hasAllAuthorities(authorities)); + return withRequiredAuthorities( + withRoleHierarchy(AllAuthoritiesAuthorizationManager.hasAllAuthorities(authorities))); } @Override public AuthorizationManager authenticated() { - return withTrustResolver(AuthenticatedAuthorizationManager.authenticated()); + return withRequiredAuthorities(withTrustResolver(AuthenticatedAuthorizationManager.authenticated())); } @Override public AuthorizationManager fullyAuthenticated() { - return withTrustResolver(AuthenticatedAuthorizationManager.fullyAuthenticated()); + return withRequiredAuthorities(withTrustResolver(AuthenticatedAuthorizationManager.fullyAuthenticated())); } @Override public AuthorizationManager rememberMe() { - return withTrustResolver(AuthenticatedAuthorizationManager.rememberMe()); + return withRequiredAuthorities(withTrustResolver(AuthenticatedAuthorizationManager.rememberMe())); } @Override @@ -136,4 +171,13 @@ public final class DefaultAuthorizationManagerFactory withRequiredAuthorities(AuthorizationManager manager) { + if (this.requiredAuthorities == null || this.requiredAuthorities.length == 0) { + return manager; + } + AuthorizationManager required = withRoleHierarchy( + AllAuthoritiesAuthorizationManager.hasAllAuthorities(this.requiredAuthorities)); + return AuthorizationManagers.allOf(new AuthorizationDecision(false), manager, required); + } + }