|
@@ -16,6 +16,9 @@
|
|
|
|
|
|
package org.springframework.security.authorization;
|
|
package org.springframework.security.authorization;
|
|
|
|
|
|
|
|
+import java.util.ArrayList;
|
|
|
|
+import java.util.List;
|
|
|
|
+
|
|
import org.jspecify.annotations.Nullable;
|
|
import org.jspecify.annotations.Nullable;
|
|
|
|
|
|
import org.springframework.security.access.hierarchicalroles.NullRoleHierarchy;
|
|
import org.springframework.security.access.hierarchicalroles.NullRoleHierarchy;
|
|
@@ -23,6 +26,7 @@ import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
|
|
import org.springframework.security.authentication.AuthenticationTrustResolver;
|
|
import org.springframework.security.authentication.AuthenticationTrustResolver;
|
|
import org.springframework.security.authentication.AuthenticationTrustResolverImpl;
|
|
import org.springframework.security.authentication.AuthenticationTrustResolverImpl;
|
|
import org.springframework.util.Assert;
|
|
import org.springframework.util.Assert;
|
|
|
|
+import org.springframework.util.CollectionUtils;
|
|
|
|
|
|
/**
|
|
/**
|
|
* A factory for creating different kinds of {@link AuthorizationManager} instances.
|
|
* A factory for creating different kinds of {@link AuthorizationManager} instances.
|
|
@@ -30,6 +34,7 @@ import org.springframework.util.Assert;
|
|
* @param <T> the type of object that the authorization check is being done on
|
|
* @param <T> the type of object that the authorization check is being done on
|
|
* @author Steve Riesenberg
|
|
* @author Steve Riesenberg
|
|
* @author Andrey Litvitski
|
|
* @author Andrey Litvitski
|
|
|
|
+ * @author Rob Winch
|
|
* @since 7.0
|
|
* @since 7.0
|
|
*/
|
|
*/
|
|
public final class DefaultAuthorizationManagerFactory<T extends @Nullable Object>
|
|
public final class DefaultAuthorizationManagerFactory<T extends @Nullable Object>
|
|
@@ -41,7 +46,7 @@ public final class DefaultAuthorizationManagerFactory<T extends @Nullable Object
|
|
|
|
|
|
private String rolePrefix = "ROLE_";
|
|
private String rolePrefix = "ROLE_";
|
|
|
|
|
|
- private String[] requiredAuthorities = new String[0];
|
|
|
|
|
|
+ private @Nullable AuthorizationManager<T> additionalAuthorization;
|
|
|
|
|
|
/**
|
|
/**
|
|
* Sets the {@link AuthenticationTrustResolver} used to check the user's
|
|
* Sets the {@link AuthenticationTrustResolver} used to check the user's
|
|
@@ -73,32 +78,29 @@ public final class DefaultAuthorizationManagerFactory<T extends @Nullable Object
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
- * Sets authorities required for authorization managers that apply to authenticated
|
|
|
|
- * users.
|
|
|
|
- * <p>
|
|
|
|
- * Does not affect {@code anonymous}, {@code permitAll}, or {@code denyAll}.
|
|
|
|
- * <p>
|
|
|
|
- * 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.
|
|
|
|
|
|
+ * Sets additional authorization to be applied to the returned
|
|
|
|
+ * {@link AuthorizationManager} for the following methods:
|
|
|
|
+ *
|
|
|
|
+ * <ul>
|
|
|
|
+ * <li>{@link #hasRole(String)}</li>
|
|
|
|
+ * <li>{@link #hasAnyRole(String...)}</li>
|
|
|
|
+ * <li>{@link #hasAllRoles(String...)}</li>
|
|
|
|
+ * <li>{@link #hasAuthority(String)}</li>
|
|
|
|
+ * <li>{@link #hasAnyAuthority(String...)}</li>
|
|
|
|
+ * <li>{@link #hasAllAuthorities(String...)}</li>
|
|
|
|
+ * <li>{@link #authenticated()}</li>
|
|
|
|
+ * <li>{@link #fullyAuthenticated()}</li>
|
|
|
|
+ * <li>{@link #rememberMe()}</li>
|
|
|
|
+ * </ul>
|
|
|
|
+ *
|
|
* <p>
|
|
* <p>
|
|
- * Does not affect {@code anonymous}, {@code permitAll}, or {@code denyAll}.
|
|
|
|
- * @param authorities the required authorities
|
|
|
|
- * @param <T> the secured object type
|
|
|
|
- * @return a factory configured with the required authorities
|
|
|
|
|
|
+ * This does not affect {@code anonymous}, {@code permitAll}, or {@code denyAll}.
|
|
|
|
+ * </p>
|
|
|
|
+ * @param additionalAuthorization the {@link AuthorizationManager} to be applied.
|
|
|
|
+ * Default is null (no additional authorization).
|
|
*/
|
|
*/
|
|
- public static <T> AuthorizationManagerFactory<T> withAuthorities(String... authorities) {
|
|
|
|
- DefaultAuthorizationManagerFactory<T> factory = new DefaultAuthorizationManagerFactory<>();
|
|
|
|
- factory.setRequiredAuthorities(authorities);
|
|
|
|
- return factory;
|
|
|
|
|
|
+ public void setAdditionalAuthorization(@Nullable AuthorizationManager<T> additionalAuthorization) {
|
|
|
|
+ this.additionalAuthorization = additionalAuthorization;
|
|
}
|
|
}
|
|
|
|
|
|
@Override
|
|
@Override
|
|
@@ -108,76 +110,140 @@ public final class DefaultAuthorizationManagerFactory<T extends @Nullable Object
|
|
|
|
|
|
@Override
|
|
@Override
|
|
public AuthorizationManager<T> hasAnyRole(String... roles) {
|
|
public AuthorizationManager<T> hasAnyRole(String... roles) {
|
|
- return withRequiredAuthorities(
|
|
|
|
- withRoleHierarchy(AuthorityAuthorizationManager.hasAnyRole(this.rolePrefix, roles)));
|
|
|
|
|
|
+ return createManager(AuthorityAuthorizationManager.hasAnyRole(this.rolePrefix, roles));
|
|
}
|
|
}
|
|
|
|
|
|
@Override
|
|
@Override
|
|
public AuthorizationManager<T> hasAllRoles(String... roles) {
|
|
public AuthorizationManager<T> hasAllRoles(String... roles) {
|
|
- return withRequiredAuthorities(withRoleHierarchy(
|
|
|
|
- AllAuthoritiesAuthorizationManager.hasAllPrefixedAuthorities(this.rolePrefix, roles)));
|
|
|
|
|
|
+ return createManager(AllAuthoritiesAuthorizationManager.hasAllPrefixedAuthorities(this.rolePrefix, roles));
|
|
}
|
|
}
|
|
|
|
|
|
@Override
|
|
@Override
|
|
public AuthorizationManager<T> hasAuthority(String authority) {
|
|
public AuthorizationManager<T> hasAuthority(String authority) {
|
|
- return withRequiredAuthorities(withRoleHierarchy(AuthorityAuthorizationManager.hasAuthority(authority)));
|
|
|
|
|
|
+ return createManager(AuthorityAuthorizationManager.hasAuthority(authority));
|
|
}
|
|
}
|
|
|
|
|
|
@Override
|
|
@Override
|
|
public AuthorizationManager<T> hasAnyAuthority(String... authorities) {
|
|
public AuthorizationManager<T> hasAnyAuthority(String... authorities) {
|
|
- return withRequiredAuthorities(withRoleHierarchy(AuthorityAuthorizationManager.hasAnyAuthority(authorities)));
|
|
|
|
|
|
+ return createManager(AuthorityAuthorizationManager.hasAnyAuthority(authorities));
|
|
}
|
|
}
|
|
|
|
|
|
@Override
|
|
@Override
|
|
public AuthorizationManager<T> hasAllAuthorities(String... authorities) {
|
|
public AuthorizationManager<T> hasAllAuthorities(String... authorities) {
|
|
- return withRequiredAuthorities(
|
|
|
|
- withRoleHierarchy(AllAuthoritiesAuthorizationManager.hasAllAuthorities(authorities)));
|
|
|
|
|
|
+ return createManager(AllAuthoritiesAuthorizationManager.hasAllAuthorities(authorities));
|
|
}
|
|
}
|
|
|
|
|
|
@Override
|
|
@Override
|
|
public AuthorizationManager<T> authenticated() {
|
|
public AuthorizationManager<T> authenticated() {
|
|
- return withRequiredAuthorities(withTrustResolver(AuthenticatedAuthorizationManager.authenticated()));
|
|
|
|
|
|
+ return createManager(AuthenticatedAuthorizationManager.authenticated());
|
|
}
|
|
}
|
|
|
|
|
|
@Override
|
|
@Override
|
|
public AuthorizationManager<T> fullyAuthenticated() {
|
|
public AuthorizationManager<T> fullyAuthenticated() {
|
|
- return withRequiredAuthorities(withTrustResolver(AuthenticatedAuthorizationManager.fullyAuthenticated()));
|
|
|
|
|
|
+ return createManager(AuthenticatedAuthorizationManager.fullyAuthenticated());
|
|
}
|
|
}
|
|
|
|
|
|
@Override
|
|
@Override
|
|
public AuthorizationManager<T> rememberMe() {
|
|
public AuthorizationManager<T> rememberMe() {
|
|
- return withRequiredAuthorities(withTrustResolver(AuthenticatedAuthorizationManager.rememberMe()));
|
|
|
|
|
|
+ return createManager(AuthenticatedAuthorizationManager.rememberMe());
|
|
}
|
|
}
|
|
|
|
|
|
@Override
|
|
@Override
|
|
public AuthorizationManager<T> anonymous() {
|
|
public AuthorizationManager<T> anonymous() {
|
|
- return withTrustResolver(AuthenticatedAuthorizationManager.anonymous());
|
|
|
|
|
|
+ return createManager(AuthenticatedAuthorizationManager.anonymous());
|
|
}
|
|
}
|
|
|
|
|
|
- private AuthorityAuthorizationManager<T> withRoleHierarchy(AuthorityAuthorizationManager<T> authorizationManager) {
|
|
|
|
|
|
+ /**
|
|
|
|
+ * Creates a {@link Builder} that helps build an {@link AuthorizationManager} to set
|
|
|
|
+ * on {@link #setAdditionalAuthorization(AuthorizationManager)} for common scenarios.
|
|
|
|
+ * <p>
|
|
|
|
+ * Does not affect {@code anonymous}, {@code permitAll}, or {@code denyAll}.
|
|
|
|
+ * @param <T> the secured object type
|
|
|
|
+ * @return a factory configured with the required authorities
|
|
|
|
+ */
|
|
|
|
+ public static <T> Builder<T> builder() {
|
|
|
|
+ return new Builder<>();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private AuthorizationManager<T> createManager(AuthorityAuthorizationManager<T> authorizationManager) {
|
|
authorizationManager.setRoleHierarchy(this.roleHierarchy);
|
|
authorizationManager.setRoleHierarchy(this.roleHierarchy);
|
|
- return authorizationManager;
|
|
|
|
|
|
+ return withAdditionalAuthorization(authorizationManager);
|
|
}
|
|
}
|
|
|
|
|
|
- private AllAuthoritiesAuthorizationManager<T> withRoleHierarchy(
|
|
|
|
- AllAuthoritiesAuthorizationManager<T> authorizationManager) {
|
|
|
|
|
|
+ private AuthorizationManager<T> createManager(AllAuthoritiesAuthorizationManager<T> authorizationManager) {
|
|
authorizationManager.setRoleHierarchy(this.roleHierarchy);
|
|
authorizationManager.setRoleHierarchy(this.roleHierarchy);
|
|
- return authorizationManager;
|
|
|
|
|
|
+ return withAdditionalAuthorization(authorizationManager);
|
|
}
|
|
}
|
|
|
|
|
|
- private AuthenticatedAuthorizationManager<T> withTrustResolver(
|
|
|
|
- AuthenticatedAuthorizationManager<T> authorizationManager) {
|
|
|
|
|
|
+ private AuthorizationManager<T> createManager(AuthenticatedAuthorizationManager<T> authorizationManager) {
|
|
authorizationManager.setTrustResolver(this.trustResolver);
|
|
authorizationManager.setTrustResolver(this.trustResolver);
|
|
- return authorizationManager;
|
|
|
|
|
|
+ return withAdditionalAuthorization(authorizationManager);
|
|
}
|
|
}
|
|
|
|
|
|
- private AuthorizationManager<T> withRequiredAuthorities(AuthorizationManager<T> manager) {
|
|
|
|
- if (this.requiredAuthorities == null || this.requiredAuthorities.length == 0) {
|
|
|
|
|
|
+ private AuthorizationManager<T> withAdditionalAuthorization(AuthorizationManager<T> manager) {
|
|
|
|
+ if (this.additionalAuthorization == null) {
|
|
return manager;
|
|
return manager;
|
|
}
|
|
}
|
|
- AuthorizationManager<T> required = withRoleHierarchy(
|
|
|
|
- AllAuthoritiesAuthorizationManager.hasAllAuthorities(this.requiredAuthorities));
|
|
|
|
- return AuthorizationManagers.allOf(new AuthorizationDecision(false), manager, required);
|
|
|
|
|
|
+ return AuthorizationManagers.allOf(new AuthorizationDecision(false), this.additionalAuthorization, manager);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * A builder that allows creating {@link DefaultAuthorizationManagerFactory} with
|
|
|
|
+ * additional authorization for common scenarios.
|
|
|
|
+ *
|
|
|
|
+ * @param <T> the type for the {@link DefaultAuthorizationManagerFactory}
|
|
|
|
+ * @author Rob Winch
|
|
|
|
+ */
|
|
|
|
+ public static final class Builder<T> {
|
|
|
|
+
|
|
|
|
+ private final List<String> additionalAuthorities = new ArrayList<>();
|
|
|
|
+
|
|
|
|
+ private RoleHierarchy roleHierarchy = new NullRoleHierarchy();
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Add additional authorities that will be required.
|
|
|
|
+ * @param additionalAuthorities the additional authorities.
|
|
|
|
+ * @return the {@link Builder} to further customize.
|
|
|
|
+ */
|
|
|
|
+ public Builder<T> requireAdditionalAuthorities(String... additionalAuthorities) {
|
|
|
|
+ Assert.notEmpty(additionalAuthorities, "additionalAuthorities cannot be empty");
|
|
|
|
+ for (String additionalAuthority : additionalAuthorities) {
|
|
|
|
+ this.additionalAuthorities.add(additionalAuthority);
|
|
|
|
+ }
|
|
|
|
+ return this;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * The {@link RoleHierarchy} to use.
|
|
|
|
+ * @param roleHierarchy the non-null {@link RoleHierarchy} to use. Default is
|
|
|
|
+ * {@link NullRoleHierarchy}.
|
|
|
|
+ * @return the Builder to further customize.
|
|
|
|
+ */
|
|
|
|
+ public Builder<T> roleHierarchy(RoleHierarchy roleHierarchy) {
|
|
|
|
+ Assert.notNull(roleHierarchy, "roleHierarchy cannot be null");
|
|
|
|
+ this.roleHierarchy = roleHierarchy;
|
|
|
|
+ return this;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Builds a {@link DefaultAuthorizationManagerFactory} that has the
|
|
|
|
+ * {@link #setAdditionalAuthorization(AuthorizationManager)} set.
|
|
|
|
+ * @return the {@link DefaultAuthorizationManagerFactory}.
|
|
|
|
+ */
|
|
|
|
+ public DefaultAuthorizationManagerFactory<T> build() {
|
|
|
|
+ Assert.state(!CollectionUtils.isEmpty(this.additionalAuthorities), "additionalAuthorities cannot be empty");
|
|
|
|
+ DefaultAuthorizationManagerFactory<T> result = new DefaultAuthorizationManagerFactory<>();
|
|
|
|
+ AllAuthoritiesAuthorizationManager<T> additionalChecks = AllAuthoritiesAuthorizationManager
|
|
|
|
+ .hasAllAuthorities(this.additionalAuthorities);
|
|
|
|
+ result.setRoleHierarchy(this.roleHierarchy);
|
|
|
|
+ additionalChecks.setRoleHierarchy(this.roleHierarchy);
|
|
|
|
+ result.setAdditionalAuthorization(additionalChecks);
|
|
|
|
+ return result;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private Builder() {
|
|
|
|
+ }
|
|
|
|
+
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
}
|