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')")
|
@PreAuthorize("hasRole('USER')")
|
||||||
void preAuthorizeUser();
|
void preAuthorizeUser();
|
||||||
|
|
||||||
|
@PreAuthorize("hasAllRoles('USER', 'ADMIN')")
|
||||||
|
void hasAllRolesUserAdmin();
|
||||||
|
|
||||||
|
@PreAuthorize("hasAllAuthorities('ROLE_USER', 'ROLE_ADMIN')")
|
||||||
|
void hasAllAuthoritiesRoleUserRoleAdmin();
|
||||||
|
|
||||||
@PreAuthorize("hasPermission(#object,'read')")
|
@PreAuthorize("hasPermission(#object,'read')")
|
||||||
String hasPermission(String object);
|
String hasPermission(String object);
|
||||||
|
|
||||||
|
|||||||
+8
@@ -203,4 +203,12 @@ public class MethodSecurityServiceImpl implements MethodSecurityService {
|
|||||||
return "ok";
|
return "ok";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void hasAllRolesUserAdmin() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void hasAllAuthoritiesRoleUserRoleAdmin() {
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+46
@@ -282,6 +282,52 @@ public class PrePostMethodSecurityConfigurationTests {
|
|||||||
verify(strategy, atLeastOnce()).getContext();
|
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")
|
@WithMockUser(authorities = "PREFIX_ADMIN")
|
||||||
@Test
|
@Test
|
||||||
public void preAuthorizeAdminWhenRoleAdminAndCustomPrefixThenPasses() {
|
public void preAuthorizeAdminWhenRoleAdminAndCustomPrefixThenPasses() {
|
||||||
|
|||||||
+10
@@ -124,6 +124,11 @@ public abstract class SecurityExpressionRoot<T extends @Nullable Object> impleme
|
|||||||
return isGranted(this.authorizationManagerFactory.hasAnyAuthority(authorities));
|
return isGranted(this.authorizationManagerFactory.hasAnyAuthority(authorities));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final boolean hasAllAuthorities(String... authorities) {
|
||||||
|
AuthorizationManager<T> manager = this.authorizationManagerFactory.hasAllAuthorities(authorities);
|
||||||
|
return isGranted(manager);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final boolean hasRole(String role) {
|
public final boolean hasRole(String role) {
|
||||||
if (this.authorizationManagerFactory instanceof DefaultAuthorizationManagerFactory<T>) {
|
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));
|
return isGranted(this.authorizationManagerFactory.hasAnyRole(roles));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final boolean hasAllRoles(String... roles) {
|
||||||
|
AuthorizationManager<T> manager = this.authorizationManagerFactory.hasAllRoles(roles);
|
||||||
|
return isGranted(manager);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final Authentication getAuthentication() {
|
public final Authentication getAuthentication() {
|
||||||
return this.authentication.get();
|
return this.authentication.get();
|
||||||
|
|||||||
+16
@@ -128,6 +128,14 @@ public class SecurityExpressionRootTests {
|
|||||||
assertThat(this.root.hasAnyRole("ROLE_A")).isTrue();
|
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
|
@Test
|
||||||
public void hasAuthorityDoesNotAddDefaultPrefix() {
|
public void hasAuthorityDoesNotAddDefaultPrefix() {
|
||||||
assertThat(this.root.hasAuthority("A")).isFalse();
|
assertThat(this.root.hasAuthority("A")).isFalse();
|
||||||
@@ -135,6 +143,14 @@ public class SecurityExpressionRootTests {
|
|||||||
assertThat(this.root.hasAnyAuthority("ROLE_A", "NOT")).isTrue();
|
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
|
@Test
|
||||||
void isAuthenticatedWhenAuthenticatedNullThenException() {
|
void isAuthenticatedWhenAuthenticatedNullThenException() {
|
||||||
this.root = new SecurityExpressionRoot((Authentication) null) {
|
this.root = new SecurityExpressionRoot((Authentication) null) {
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
[[jc-method]]
|
[[jc-method]]
|
||||||
= Method Security
|
= Method Security
|
||||||
:figures: servlet/authorization
|
: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
|
* `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
|
* `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
|
* `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
|
* `hasPermission` - A hook into your `PermissionEvaluator` instance for doing object-level authorization
|
||||||
|
|
||||||
And here is a brief look at the most common fields:
|
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
|
== Core
|
||||||
|
|
||||||
* Removed `AuthorizationManager#check` in favor of `AuthorizationManager#authorize`
|
* 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 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
|
* Added `Authentication.Builder` for mutating and merging `Authentication` instances
|
||||||
* Moved Access API (`AccessDecisionManager`, `AccessDecisionVoter`, etc.) to a new module, `spring-security-access`
|
* Moved Access API (`AccessDecisionManager`, `AccessDecisionVoter`, etc.) to a new module, `spring-security-access`
|
||||||
|
|||||||
Reference in New Issue
Block a user