Add AuthorizationManagerFactory.hasAll(Authorities|Roles)
Closes gh-17932
This commit is contained in:
+22
@@ -296,6 +296,17 @@ public final class AuthorizeHttpRequestsConfigurer<H extends HttpSecurityBuilder
|
||||
return access(this.authorizationManagerFactory.hasAnyRole(roles));
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies that a user requires all the provided roles.
|
||||
* @param roles the roles that the user should have (i.e. ADMIN, USER, etc). Each
|
||||
* role should not start with ROLE_ since it is automatically prepended already
|
||||
* @return the {@link AuthorizationManagerRequestMatcherRegistry} for further
|
||||
* customizations
|
||||
*/
|
||||
public AuthorizationManagerRequestMatcherRegistry hasAllRoles(String... roles) {
|
||||
return access(this.authorizationManagerFactory.hasAllRoles(roles));
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies a user requires an authority.
|
||||
* @param authority the authority that should be required
|
||||
@@ -317,6 +328,17 @@ public final class AuthorizeHttpRequestsConfigurer<H extends HttpSecurityBuilder
|
||||
return access(this.authorizationManagerFactory.hasAnyAuthority(authorities));
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies that a user requires all the provided authorities.
|
||||
* @param authorities the authorities that the user should have (i.e. ROLE_USER,
|
||||
* ROLE_ADMIN, etc)
|
||||
* @return the {@link AuthorizationManagerRequestMatcherRegistry} for further
|
||||
* customizations
|
||||
*/
|
||||
public AuthorizationManagerRequestMatcherRegistry hasAllAuthorities(String... authorities) {
|
||||
return access(this.authorizationManagerFactory.hasAllAuthorities(authorities));
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify that URLs are allowed by any authenticated user.
|
||||
* @return the {@link AuthorizationManagerRequestMatcherRegistry} for further
|
||||
|
||||
+6
@@ -190,9 +190,11 @@ public class AuthorizeHttpRequestsConfigurerTests {
|
||||
verify(authorizationManagerFactory).permitAll();
|
||||
verify(authorizationManagerFactory).denyAll();
|
||||
verify(authorizationManagerFactory).hasRole("ADMIN");
|
||||
verify(authorizationManagerFactory).hasAllRoles("hasAllRoles1", "hasAllRoles2");
|
||||
verify(authorizationManagerFactory).hasAnyRole("USER", "ADMIN");
|
||||
verify(authorizationManagerFactory).hasAuthority("write");
|
||||
verify(authorizationManagerFactory).hasAnyAuthority("resource.read", "read");
|
||||
verify(authorizationManagerFactory).hasAllAuthorities("hasAllAuthorities1", "hasAllAuthorities2");
|
||||
verify(authorizationManagerFactory).authenticated();
|
||||
verify(authorizationManagerFactory).fullyAuthenticated();
|
||||
verify(authorizationManagerFactory).rememberMe();
|
||||
@@ -823,8 +825,10 @@ public class AuthorizeHttpRequestsConfigurerTests {
|
||||
given(authorizationManagerFactory.denyAll()).willReturn(authorizationManager);
|
||||
given(authorizationManagerFactory.hasRole(anyString())).willReturn(authorizationManager);
|
||||
given(authorizationManagerFactory.hasAnyRole(any(String[].class))).willReturn(authorizationManager);
|
||||
given(authorizationManagerFactory.hasAllRoles(any(String[].class))).willReturn(authorizationManager);
|
||||
given(authorizationManagerFactory.hasAuthority(anyString())).willReturn(authorizationManager);
|
||||
given(authorizationManagerFactory.hasAnyAuthority(any(String[].class))).willReturn(authorizationManager);
|
||||
given(authorizationManagerFactory.hasAllAuthorities(any(String[].class))).willReturn(authorizationManager);
|
||||
given(authorizationManagerFactory.authenticated()).willReturn(authorizationManager);
|
||||
given(authorizationManagerFactory.fullyAuthenticated()).willReturn(authorizationManager);
|
||||
given(authorizationManagerFactory.rememberMe()).willReturn(authorizationManager);
|
||||
@@ -1116,8 +1120,10 @@ public class AuthorizeHttpRequestsConfigurerTests {
|
||||
.requestMatchers("/private").denyAll()
|
||||
.requestMatchers("/admin").hasRole("ADMIN")
|
||||
.requestMatchers("/user").hasAnyRole("USER", "ADMIN")
|
||||
.requestMatchers("/hasAllRoles").hasAllRoles("hasAllRoles1", "hasAllRoles2")
|
||||
.requestMatchers(HttpMethod.POST, "/resource").hasAuthority("write")
|
||||
.requestMatchers("/resource").hasAnyAuthority("resource.read", "read")
|
||||
.requestMatchers("/hasAllAuthorities").hasAllAuthorities("hasAllAuthorities1", "hasAllAuthorities2")
|
||||
.requestMatchers("/authenticated").authenticated()
|
||||
.requestMatchers("/fully-authenticated").fullyAuthenticated()
|
||||
.requestMatchers("/remember-me").rememberMe()
|
||||
|
||||
+22
@@ -65,6 +65,17 @@ public interface AuthorizationManagerFactory<T extends @Nullable Object> {
|
||||
return AuthorityAuthorizationManager.hasAnyRole(roles);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an {@link AuthorizationManager} that requires users to have all the
|
||||
* provided roles.
|
||||
* @param roles the roles (automatically prepended with ROLE_) that the user must have
|
||||
* to allow access (i.e. USER, ADMIN, etc.)
|
||||
* @return A new {@link AuthorizationManager} instance
|
||||
*/
|
||||
default AuthorizationManager<T> hasAllRoles(String... roles) {
|
||||
return AllAuthoritiesAuthorizationManager.hasAllRoles(roles);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an {@link AuthorizationManager} that requires users to have the specified
|
||||
* authority.
|
||||
@@ -87,6 +98,17 @@ public interface AuthorizationManagerFactory<T extends @Nullable Object> {
|
||||
return AuthorityAuthorizationManager.hasAnyAuthority(authorities);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an {@link AuthorizationManager} that requires users to have all the
|
||||
* provided authorities.
|
||||
* @param authorities the authorities that the user must have to allow access (i.e.
|
||||
* USER, ADMIN, etc.)
|
||||
* @return A new {@link AuthorizationManager} instance
|
||||
*/
|
||||
default AuthorizationManager<T> hasAllAuthorities(String... authorities) {
|
||||
return AllAuthoritiesAuthorizationManager.hasAllAuthorities(authorities);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an {@link AuthorizationManager} that allows any authenticated user.
|
||||
* @return A new {@link AuthorizationManager} instance
|
||||
|
||||
+16
@@ -79,6 +79,11 @@ public final class DefaultAuthorizationManagerFactory<T extends @Nullable Object
|
||||
return withRoleHierarchy(AuthorityAuthorizationManager.hasAnyRole(this.rolePrefix, roles));
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthorizationManager<T> hasAllRoles(String... roles) {
|
||||
return withRoleHierarchy(AllAuthoritiesAuthorizationManager.hasAllPrefixedAuthorities(this.rolePrefix, roles));
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthorizationManager<T> hasAuthority(String authority) {
|
||||
return withRoleHierarchy(AuthorityAuthorizationManager.hasAuthority(authority));
|
||||
@@ -89,6 +94,11 @@ public final class DefaultAuthorizationManagerFactory<T extends @Nullable Object
|
||||
return withRoleHierarchy(AuthorityAuthorizationManager.hasAnyAuthority(authorities));
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthorizationManager<T> hasAllAuthorities(String... authorities) {
|
||||
return withRoleHierarchy(AllAuthoritiesAuthorizationManager.hasAllAuthorities(authorities));
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthorizationManager<T> authenticated() {
|
||||
return withTrustResolver(AuthenticatedAuthorizationManager.authenticated());
|
||||
@@ -114,6 +124,12 @@ public final class DefaultAuthorizationManagerFactory<T extends @Nullable Object
|
||||
return authorizationManager;
|
||||
}
|
||||
|
||||
private AllAuthoritiesAuthorizationManager<T> withRoleHierarchy(
|
||||
AllAuthoritiesAuthorizationManager<T> authorizationManager) {
|
||||
authorizationManager.setRoleHierarchy(this.roleHierarchy);
|
||||
return authorizationManager;
|
||||
}
|
||||
|
||||
private AuthenticatedAuthorizationManager<T> withTrustResolver(
|
||||
AuthenticatedAuthorizationManager<T> authorizationManager) {
|
||||
authorizationManager.setTrustResolver(this.trustResolver);
|
||||
|
||||
+14
@@ -55,6 +55,13 @@ public class AuthorizationManagerFactoryTests {
|
||||
assertThat(authorizationManager).isInstanceOf(AuthorityAuthorizationManager.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hasAllRolesReturnsAllAuthoritiesAuthorizationManagerByDefault() {
|
||||
AuthorizationManagerFactory<String> factory = new DefaultAuthorizationManagerFactory<>();
|
||||
AuthorizationManager<String> authorizationManager = factory.hasAllRoles("authority1", "authority2");
|
||||
assertThat(authorizationManager).isInstanceOf(AllAuthoritiesAuthorizationManager.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hasAuthorityReturnsAuthorityAuthorizationManagerByDefault() {
|
||||
AuthorizationManagerFactory<String> factory = new DefaultAuthorizationManagerFactory<>();
|
||||
@@ -69,6 +76,13 @@ public class AuthorizationManagerFactoryTests {
|
||||
assertThat(authorizationManager).isInstanceOf(AuthorityAuthorizationManager.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hasAllAuthoritiesReturnsAllAuthoritiesAuthorizationManagerByDefault() {
|
||||
AuthorizationManagerFactory<String> factory = new DefaultAuthorizationManagerFactory<>();
|
||||
AuthorizationManager<String> authorizationManager = factory.hasAllAuthorities("authority1", "authority2");
|
||||
assertThat(authorizationManager).isInstanceOf(AllAuthoritiesAuthorizationManager.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticatedReturnsAuthenticatedAuthorizationManagerByDefault() {
|
||||
AuthorizationManagerFactory<String> factory = new DefaultAuthorizationManagerFactory<>();
|
||||
|
||||
@@ -157,8 +157,10 @@ public interface AuthorizationManagerFactory<T> {
|
||||
AuthorizationManager<T> denyAll();
|
||||
AuthorizationManager<T> hasRole(String role);
|
||||
AuthorizationManager<T> hasAnyRole(String... roles);
|
||||
AuthorizationManager<T> hasAllRoles(String... roles);
|
||||
AuthorizationManager<T> hasAuthority(String authority);
|
||||
AuthorizationManager<T> hasAnyAuthority(String... authorities);
|
||||
AuthorizationManager<T> hasAllAuthorities(String... authorities);
|
||||
AuthorizationManager<T> authenticated();
|
||||
AuthorizationManager<T> fullyAuthenticated();
|
||||
AuthorizationManager<T> rememberMe();
|
||||
|
||||
@@ -720,7 +720,9 @@ As a quick summary, here are the authorization rules built into the DSL:
|
||||
* `hasAuthority` - The request requires that the `Authentication` have xref:servlet/authorization/architecture.adoc#authz-authorities[a `GrantedAuthority`] that matches the given value
|
||||
* `hasRole` - A shortcut for `hasAuthority` that prefixes `ROLE_` or whatever is configured as the default prefix
|
||||
* `hasAnyAuthority` - The request requires that the `Authentication` have a `GrantedAuthority` that matches any of the given values
|
||||
* `hasAnyRole` - A shortcut for `hasAnyAuthority` that prefixes `ROLE_` or whatever is configured as the default prefix
|
||||
* `hasAnyRole` - A shortcut for `hasAnyAuthority` that prefixes `ROLE_` or whatever is configured as the default prefix* `hasAnyAuthority` - The request requires that the `Authentication` have a `GrantedAuthority` that matches any of the given values
|
||||
* `hasAllRoles` - A shortcut for `hasAllAuthorities` that prefixes `ROLE_` or whatever is configured as the default prefix
|
||||
* `hasAllAuthorities` - The request requires that the `Authentication` have a `GrantedAuthority` that matches all of the given values
|
||||
* `access` - The request uses this custom `AuthorizationManager` to determine access
|
||||
|
||||
Having now learned the patterns, rules, and how they can be paired together, you should be able to understand what is going on in this more complex example:
|
||||
@@ -746,7 +748,7 @@ SecurityFilterChain web(HttpSecurity http) throws Exception {
|
||||
.dispatcherTypeMatchers(FORWARD, ERROR).permitAll() // <2>
|
||||
.requestMatchers("/static/**", "/signup", "/about").permitAll() // <3>
|
||||
.requestMatchers("/admin/**").hasRole("ADMIN") // <4>
|
||||
.requestMatchers("/db/**").access(allOf(hasAuthority("db"), hasRole("ADMIN"))) // <5>
|
||||
.requestMatchers("/db/**").hasAllAuthorities("db", "ROLE_ADMIN") // <5>
|
||||
.anyRequest().denyAll() // <6>
|
||||
);
|
||||
|
||||
@@ -762,7 +764,7 @@ Specifically, any user can access a request if the URL starts with "/static/", e
|
||||
<4> Any URL that starts with "/admin/" will be restricted to users who have the role "ROLE_ADMIN".
|
||||
You will notice that since we are invoking the `hasRole` method we do not need to specify the "ROLE_" prefix.
|
||||
<5> Any URL that starts with "/db/" requires the user to have both been granted the "db" permission as well as be a "ROLE_ADMIN".
|
||||
You will notice that since we are using the `hasRole` expression we do not need to specify the "ROLE_" prefix.
|
||||
You will notice that since we are using the `hasAllAuthorities` expression we must specify the "ROLE_" prefix.
|
||||
<6> Any URL that has not already been matched on is denied access.
|
||||
This is a good strategy if you do not want to accidentally forget to update your authorization rules.
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ Each section that follows will indicate the more notable removals as well as the
|
||||
== Core
|
||||
|
||||
* Removed `AuthorizationManager#check` in favor of `AuthorizationManager#authorize`
|
||||
* Added javadoc:org.springframework.security.authorization.AllAuthoritiesAuthorizationManager[] and javadoc:org.springframework.security.authorization.AllAuthoritiesReactiveAuthorizationManager[]
|
||||
* Added javadoc:org.springframework.security.authorization.AllAuthoritiesAuthorizationManager[] and javadoc:org.springframework.security.authorization.AllAuthoritiesReactiveAuthorizationManager[] along with corresponding methods for xref:servlet/authorization/authorize-http-requests.adoc#authorize-requests[Authorizing `HttpServletRequests`]
|
||||
* Added xref:servlet/authorization/architecture.adoc#authz-authorization-manager-factory[`AuthorizationManagerFactory`] for creating `AuthorizationManager` instances in xref:servlet/authorization/authorize-http-requests.adoc#customizing-authorization-managers[request-based] and xref:servlet/authorization/method-security.adoc#customizing-authorization-managers[method-based] authorization components
|
||||
* Added `Authentication.Builder` for mutating and merging `Authentication` instances
|
||||
* Moved Access API (`AccessDecisionManager`, `AccessDecisionVoter`, etc.) to a new module, `spring-security-access`
|
||||
|
||||
Reference in New Issue
Block a user