Add hasAll(Roles|Authorities) to SecurityExpressionRoot
This adds support for hasAllRoles and hasAllAuthorities to method security expressions. Issue gh-17932
This commit is contained in:
+6
@@ -93,6 +93,12 @@ public interface MethodSecurityService {
|
||||
@PreAuthorize("hasRole('USER')")
|
||||
void preAuthorizeUser();
|
||||
|
||||
@PreAuthorize("hasAllRoles('USER', 'ADMIN')")
|
||||
void hasAllRolesUserAdmin();
|
||||
|
||||
@PreAuthorize("hasAllAuthorities('ROLE_USER', 'ROLE_ADMIN')")
|
||||
void hasAllAuthoritiesRoleUserRoleAdmin();
|
||||
|
||||
@PreAuthorize("hasPermission(#object,'read')")
|
||||
String hasPermission(String object);
|
||||
|
||||
|
||||
+8
@@ -203,4 +203,12 @@ public class MethodSecurityServiceImpl implements MethodSecurityService {
|
||||
return "ok";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hasAllRolesUserAdmin() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hasAllAuthoritiesRoleUserRoleAdmin() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+46
@@ -282,6 +282,52 @@ public class PrePostMethodSecurityConfigurationTests {
|
||||
verify(strategy, atLeastOnce()).getContext();
|
||||
}
|
||||
|
||||
@WithMockUser(roles = { "ADMIN", "USER" })
|
||||
@Test
|
||||
public void hasAllAuthoritiesRoleUserRoleAdminWhenGranted() {
|
||||
this.spring.register(MethodSecurityServiceConfig.class).autowire();
|
||||
this.methodSecurityService.hasAllAuthoritiesRoleUserRoleAdmin();
|
||||
}
|
||||
|
||||
@WithMockUser(roles = { "USER" })
|
||||
@Test
|
||||
public void hasAllAuthoritiesRoleUserRoleAdminWhenMissingOneThenDenied() {
|
||||
this.spring.register(MethodSecurityServiceConfig.class).autowire();
|
||||
assertThatExceptionOfType(AccessDeniedException.class)
|
||||
.isThrownBy(this.methodSecurityService::hasAllAuthoritiesRoleUserRoleAdmin);
|
||||
}
|
||||
|
||||
@WithMockUser(roles = { "OTHER" })
|
||||
@Test
|
||||
public void hasAllAuthoritiesRoleUserRoleAdminWhenAllThenDenied() {
|
||||
this.spring.register(MethodSecurityServiceConfig.class).autowire();
|
||||
assertThatExceptionOfType(AccessDeniedException.class)
|
||||
.isThrownBy(this.methodSecurityService::hasAllAuthoritiesRoleUserRoleAdmin);
|
||||
}
|
||||
|
||||
@WithMockUser(roles = { "ADMIN", "USER" })
|
||||
@Test
|
||||
public void hasAllRolesRoleUserRoleAdminWhenGranted() {
|
||||
this.spring.register(MethodSecurityServiceConfig.class).autowire();
|
||||
this.methodSecurityService.hasAllRolesUserAdmin();
|
||||
}
|
||||
|
||||
@WithMockUser(roles = { "USER" })
|
||||
@Test
|
||||
public void hasAllRolesRoleUserRoleAdminWhenMissingOneThenDenied() {
|
||||
this.spring.register(MethodSecurityServiceConfig.class).autowire();
|
||||
assertThatExceptionOfType(AccessDeniedException.class)
|
||||
.isThrownBy(this.methodSecurityService::hasAllRolesUserAdmin);
|
||||
}
|
||||
|
||||
@WithMockUser(roles = { "OTHER" })
|
||||
@Test
|
||||
public void hasAllRolesRoleUserRoleAdminWhenAllThenDenied() {
|
||||
this.spring.register(MethodSecurityServiceConfig.class).autowire();
|
||||
assertThatExceptionOfType(AccessDeniedException.class)
|
||||
.isThrownBy(this.methodSecurityService::hasAllRolesUserAdmin);
|
||||
}
|
||||
|
||||
@WithMockUser(authorities = "PREFIX_ADMIN")
|
||||
@Test
|
||||
public void preAuthorizeAdminWhenRoleAdminAndCustomPrefixThenPasses() {
|
||||
|
||||
+10
@@ -124,6 +124,11 @@ public abstract class SecurityExpressionRoot<T extends @Nullable Object> impleme
|
||||
return isGranted(this.authorizationManagerFactory.hasAnyAuthority(authorities));
|
||||
}
|
||||
|
||||
public final boolean hasAllAuthorities(String... authorities) {
|
||||
AuthorizationManager<T> manager = this.authorizationManagerFactory.hasAllAuthorities(authorities);
|
||||
return isGranted(manager);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean hasRole(String role) {
|
||||
if (this.authorizationManagerFactory instanceof DefaultAuthorizationManagerFactory<T>) {
|
||||
@@ -155,6 +160,11 @@ public abstract class SecurityExpressionRoot<T extends @Nullable Object> impleme
|
||||
return isGranted(this.authorizationManagerFactory.hasAnyRole(roles));
|
||||
}
|
||||
|
||||
public final boolean hasAllRoles(String... roles) {
|
||||
AuthorizationManager<T> manager = this.authorizationManagerFactory.hasAllRoles(roles);
|
||||
return isGranted(manager);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Authentication getAuthentication() {
|
||||
return this.authentication.get();
|
||||
|
||||
+16
@@ -128,6 +128,14 @@ public class SecurityExpressionRootTests {
|
||||
assertThat(this.root.hasAnyRole("ROLE_A")).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hasAllRoles() {
|
||||
assertThat(this.root.hasAllRoles("A")).isTrue();
|
||||
assertThat(this.root.hasAllRoles("A", "B")).isTrue();
|
||||
assertThat(this.root.hasAllRoles("NO")).isFalse();
|
||||
assertThat(this.root.hasAllRoles("A", "NO")).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hasAuthorityDoesNotAddDefaultPrefix() {
|
||||
assertThat(this.root.hasAuthority("A")).isFalse();
|
||||
@@ -135,6 +143,14 @@ public class SecurityExpressionRootTests {
|
||||
assertThat(this.root.hasAnyAuthority("ROLE_A", "NOT")).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hasAllAuthorities() {
|
||||
assertThat(this.root.hasAllAuthorities("ROLE_A")).isTrue();
|
||||
assertThat(this.root.hasAllAuthorities("ROLE_A", "ROLE_B")).isTrue();
|
||||
assertThat(this.root.hasAllAuthorities("ROLE_NO")).isFalse();
|
||||
assertThat(this.root.hasAllAuthorities("ROLE_A", "ROLE_NO")).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void isAuthenticatedWhenAuthenticatedNullThenException() {
|
||||
this.root = new SecurityExpressionRoot((Authentication) null) {
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
[[jc-method]]
|
||||
= Method Security
|
||||
:figures: servlet/authorization
|
||||
@@ -1828,6 +1827,8 @@ What follows is a quick overview of the most common methods:
|
||||
* `hasRole` - A shortcut for `hasAuthority` that prefixes `ROLE_` or whatever is configured as the default prefix
|
||||
* `hasAnyAuthority` - The method 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
|
||||
* `hasAllAuthorities` - The method requires that the `Authentication` have ``GrantedAuthority``s that matches all of the given values
|
||||
* `hasAllRoles` - A shortcut for `hasAllAuthorities` that prefixes `ROLE_` or whatever is configured as the default prefix
|
||||
* `hasPermission` - A hook into your `PermissionEvaluator` instance for doing object-level authorization
|
||||
|
||||
And here is a brief look at the most common fields:
|
||||
|
||||
@@ -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[] along with corresponding methods for xref:servlet/authorization/authorize-http-requests.adoc#authorize-requests[Authorizing `HttpServletRequests`]
|
||||
* 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`] and xref:servlet/authorization/method-security.adoc#using-authorization-expression-fields-and-methods[method security expressions].
|
||||
* 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