diff --git a/core/src/main/java/org/springframework/security/authorization/AuthorizationManagers.java b/core/src/main/java/org/springframework/security/authorization/AuthorizationManagers.java index 6fa0ba80491..d106f4f81f4 100644 --- a/core/src/main/java/org/springframework/security/authorization/AuthorizationManagers.java +++ b/core/src/main/java/org/springframework/security/authorization/AuthorizationManagers.java @@ -56,6 +56,36 @@ public static AuthorizationManager anyOf(AuthorizationManager... manag }; } + /** + * Creates an {@link AuthorizationManager} that grants access if at least one + * {@link AuthorizationManager}s granted, if managers are + * empty or all abstained, default decision is returned. + * @param the type of object that is being authorized + * @param defaultDecision default decision to be returned in case no managers are provided. + * @param managers the {@link AuthorizationManager}s to use + * @return the {@link AuthorizationManager} to use + */ + @SafeVarargs + public static AuthorizationManager anyOf(AuthorizationDecision defaultDecision, AuthorizationManager... managers) { + return (authentication, object) -> { + List decisions = new ArrayList<>(); + for (AuthorizationManager manager : managers) { + AuthorizationDecision decision = manager.check(authentication, object); + if (decision == null) { + continue; + } + if (decision.isGranted()) { + return decision; + } + decisions.add(decision); + } + if (decisions.isEmpty()) { + return defaultDecision; + } + return new CompositeAuthorizationDecision(false, decisions); + }; + } + /** * Creates an {@link AuthorizationManager} that grants access if all * {@link AuthorizationManager}s granted or abstained, if managers are @@ -85,6 +115,36 @@ public static AuthorizationManager allOf(AuthorizationManager... manag }; } + /** + * Creates an {@link AuthorizationManager} that grants access if all + * {@link AuthorizationManager}s granted, if managers are + * empty or all abstained, default decision is returned. + * @param the type of object that is being authorized + * @param defaultDecision default decision to be returned in case no managers are provided. + * @param managers the {@link AuthorizationManager}s to use + * @return the {@link AuthorizationManager} to use + */ + @SafeVarargs + public static AuthorizationManager allOf(AuthorizationDecision defaultDecision, AuthorizationManager... managers) { + return (authentication, object) -> { + List decisions = new ArrayList<>(); + for (AuthorizationManager manager : managers) { + AuthorizationDecision decision = manager.check(authentication, object); + if (decision == null) { + continue; + } + if (!decision.isGranted()) { + return decision; + } + decisions.add(decision); + } + if (decisions.isEmpty()) { + return defaultDecision; + } + return new CompositeAuthorizationDecision(true, decisions); + }; + } + private AuthorizationManagers() { } diff --git a/core/src/test/java/org/springframework/security/authorization/AuthorizationManagersTests.java b/core/src/test/java/org/springframework/security/authorization/AuthorizationManagersTests.java index b05b2f41066..5fa2a5691f0 100644 --- a/core/src/test/java/org/springframework/security/authorization/AuthorizationManagersTests.java +++ b/core/src/test/java/org/springframework/security/authorization/AuthorizationManagersTests.java @@ -54,6 +54,26 @@ void checkAnyOfWhenEmptyThenDeniedDecision() { assertThat(decision.isGranted()).isFalse(); } + @Test + void checkAnyOfWhenNoManagersThenDefaultDecision() { + AuthorizationDecision defaultDecision = new AuthorizationDecision(true); + AuthorizationManager composed = AuthorizationManagers.anyOf(defaultDecision); + AuthorizationDecision decision = composed.check(null, null); + assertThat(decision).isNotNull(); + assertThat(decision.isGranted()).isTrue(); + assertThat(decision).isSameAs(defaultDecision); + } + + @Test + void checkAnyOfWhenAllAbstainThenDefaultDecision() { + AuthorizationDecision defaultDecision = new AuthorizationDecision(true); + AuthorizationManager composed = AuthorizationManagers.anyOf(defaultDecision, (a, o) -> null, (a, o) -> null); + AuthorizationDecision decision = composed.check(null, null); + assertThat(decision).isNotNull(); + assertThat(decision.isGranted()).isTrue(); + assertThat(decision).isSameAs(defaultDecision); + } + @Test void checkAllOfWhenAllGrantedThenGrantedDecision() { AuthorizationManager composed = AuthorizationManagers.allOf((a, o) -> new AuthorizationDecision(true), @@ -90,4 +110,24 @@ void checkAllOfWhenEmptyThenGrantedDecision() { assertThat(decision.isGranted()).isTrue(); } + @Test + void checkAllOfWhenNoManagersThenDefaultDecision() { + AuthorizationDecision defaultDecision = new AuthorizationDecision(true); + AuthorizationManager composed = AuthorizationManagers.allOf(defaultDecision); + AuthorizationDecision decision = composed.check(null, null); + assertThat(decision).isNotNull(); + assertThat(decision.isGranted()).isTrue(); + assertThat(decision).isSameAs(defaultDecision); + } + + @Test + void checkAllOfWhenAllAbstainThenDefaultDecision() { + AuthorizationDecision defaultDecision = new AuthorizationDecision(true); + AuthorizationManager composed = AuthorizationManagers.allOf(defaultDecision, (a, o) -> null, (a, o) -> null); + AuthorizationDecision decision = composed.check(null, null); + assertThat(decision).isNotNull(); + assertThat(decision.isGranted()).isTrue(); + assertThat(decision).isSameAs(defaultDecision); + } + }