AuthorizationManagerFactories.when
Closes gh-18920
This commit is contained in:
+45
-1
@@ -17,6 +17,13 @@
|
||||
package org.springframework.security.authorization;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Creates common {@link AuthorizationManagerFactory} instances.
|
||||
@@ -56,6 +63,38 @@ public final class AuthorizationManagerFactories {
|
||||
private final AllRequiredFactorsAuthorizationManager.Builder<T> factors = AllRequiredFactorsAuthorizationManager
|
||||
.builder();
|
||||
|
||||
private @Nullable Predicate<Authentication> whenCondition;
|
||||
|
||||
/**
|
||||
* Apply the required factors only when the given condition is true for the
|
||||
* current {@link Authentication}. When the condition is false, no additional
|
||||
* factors are required (equivalent to permit-all for the additional
|
||||
* authorization). Implemented using
|
||||
* {@link ConditionalAuthorizationManager#when(java.util.function.Predicate)}.
|
||||
* @param condition the condition to evaluate (must not be null)
|
||||
* @return the {@link AdditionalRequiredFactorsBuilder} to further customize
|
||||
* @since 7.1
|
||||
*/
|
||||
public AdditionalRequiredFactorsBuilder<T> when(Predicate<Authentication> condition) {
|
||||
Assert.notNull(condition, "condition cannot be null");
|
||||
this.whenCondition = condition;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Customize the condition that determines if the required factors are evaluated.
|
||||
* @param condition a function that takes the current condition and returns the
|
||||
* new condition
|
||||
* @return the {@link AdditionalRequiredFactorsBuilder} to further customize
|
||||
* @since 7.1
|
||||
*/
|
||||
public AdditionalRequiredFactorsBuilder<T> withWhen(
|
||||
Function<@Nullable Predicate<Authentication>, @Nullable Predicate<Authentication>> condition) {
|
||||
Assert.notNull(condition, "condition cannot be null");
|
||||
this.whenCondition = condition.apply(this.whenCondition);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add additional authorities that will be required.
|
||||
* @param additionalAuthorities the additional authorities.
|
||||
@@ -89,7 +128,12 @@ public final class AuthorizationManagerFactories {
|
||||
*/
|
||||
public DefaultAuthorizationManagerFactory<T> build() {
|
||||
DefaultAuthorizationManagerFactory<T> result = new DefaultAuthorizationManagerFactory<>();
|
||||
AllRequiredFactorsAuthorizationManager<T> additionalChecks = this.factors.build();
|
||||
AuthorizationManager<T> additionalChecks = this.factors.build();
|
||||
if (this.whenCondition != null) {
|
||||
additionalChecks = ConditionalAuthorizationManager.<T>when(this.whenCondition)
|
||||
.whenTrue(additionalChecks)
|
||||
.build();
|
||||
}
|
||||
result.setAdditionalAuthorization(additionalChecks);
|
||||
return result;
|
||||
}
|
||||
|
||||
+55
@@ -19,8 +19,10 @@ package org.springframework.security.authorization;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.security.authentication.TestAuthentication;
|
||||
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
@@ -311,6 +313,59 @@ public class AuthorizationManagerFactoryTests {
|
||||
.isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void builderWhenWhenConditionThenAdditionalFactorsRequiredOnlyWhenConditionTrue() {
|
||||
AuthorizationManagerFactory<String> factory = AuthorizationManagerFactories.<String>multiFactor()
|
||||
.requireFactors("ROLE_ADMIN")
|
||||
.when((auth) -> "admin".equals(auth.getName()))
|
||||
.build();
|
||||
// When condition is true (admin user), ROLE_ADMIN is required in addition to
|
||||
// hasRole("USER")
|
||||
assertThat(factory.hasRole("USER").authorize(() -> TestAuthentication.authenticatedAdmin(), "").isGranted())
|
||||
.isTrue();
|
||||
// When condition is false (non-admin user), additional factors are not required
|
||||
assertUserGranted(factory.hasRole("USER"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void builderWhenWhenConditionFalseThenUserWithoutRequiredFactorGranted() {
|
||||
AuthorizationManagerFactory<String> factory = AuthorizationManagerFactories.<String>multiFactor()
|
||||
.requireFactors("ROLE_ADMIN")
|
||||
.when((auth) -> "admin".equals(auth.getName()))
|
||||
.build();
|
||||
// Non-admin user does not need ROLE_ADMIN for hasRole("USER")
|
||||
assertThat(factory.hasRole("USER").authorize(() -> TestAuthentication.authenticatedUser(), "").isGranted())
|
||||
.isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void builderWhenWithWhenConditionThenConditionIsCustomized() {
|
||||
AuthorizationManagerFactory<String> factory = AuthorizationManagerFactories.<String>multiFactor()
|
||||
.requireFactors("ROLE_ADMIN")
|
||||
.when((auth) -> "admin".equals(auth.getName()))
|
||||
.withWhen((current) -> (auth) -> current != null && current.test(auth) && auth.isAuthenticated())
|
||||
.build();
|
||||
// When condition is true (admin user and authenticated), ROLE_ADMIN is required
|
||||
assertThat(factory.hasRole("USER").authorize(() -> TestAuthentication.authenticatedAdmin(), "").isGranted())
|
||||
.isTrue();
|
||||
// When condition is false (admin user but not authenticated), additional factors
|
||||
// are not required
|
||||
TestingAuthenticationToken unauthenticatedAdmin = new TestingAuthenticationToken("admin", "password",
|
||||
"ROLE_USER");
|
||||
unauthenticatedAdmin.setAuthenticated(false);
|
||||
assertThat(factory.hasRole("USER").authorize(() -> unauthenticatedAdmin, "").isGranted()).isTrue();
|
||||
// When condition is false (non-admin user), additional factors are not required
|
||||
assertUserGranted(factory.hasRole("USER"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void builderWhenWithWhenNullThenIllegalArgumentException() {
|
||||
AuthorizationManagerFactories.AdditionalRequiredFactorsBuilder<Object> builder = AuthorizationManagerFactories
|
||||
.multiFactor();
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> builder.withWhen(null))
|
||||
.withMessage("condition cannot be null");
|
||||
}
|
||||
|
||||
private void assertUserGranted(AuthorizationManager<String> manager) {
|
||||
assertThat(manager.authorize(() -> TestAuthentication.authenticatedUser(), "").isGranted()).isTrue();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user