diff --git a/core/src/main/java/org/springframework/security/authorization/AuthorizationManagers.java b/core/src/main/java/org/springframework/security/authorization/AuthorizationManagers.java
new file mode 100644
index 0000000000..a2809155ed
--- /dev/null
+++ b/core/src/main/java/org/springframework/security/authorization/AuthorizationManagers.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2002-2022 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.security.authorization;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A factory class to create an {@link AuthorizationManager} instances.
+ *
+ * @author Evgeniy Cheban
+ * @since 5.8
+ */
+public final class AuthorizationManagers {
+
+ /**
+ * Creates an {@link AuthorizationManager} that grants access if at least one
+ * {@link AuthorizationManager} granted or abstained, if managers are
+ * empty then denied decision is returned.
+ * @param the type of object that is being authorized
+ * @param managers the {@link AuthorizationManager}s to use
+ * @return the {@link AuthorizationManager} to use
+ */
+ @SafeVarargs
+ public static AuthorizationManager anyOf(AuthorizationManager... managers) {
+ return (authentication, object) -> {
+ List decisions = new ArrayList<>();
+ for (AuthorizationManager manager : managers) {
+ AuthorizationDecision decision = manager.check(authentication, object);
+ if (decision == null || decision.isGranted()) {
+ return decision;
+ }
+ decisions.add(decision);
+ }
+ return new CompositeAuthorizationDecision(false, decisions);
+ };
+ }
+
+ /**
+ * Creates an {@link AuthorizationManager} that grants access if all
+ * {@link AuthorizationManager}s granted or abstained, if managers are
+ * empty then granted decision is returned.
+ * @param the type of object that is being authorized
+ * @param managers the {@link AuthorizationManager}s to use
+ * @return the {@link AuthorizationManager} to use
+ */
+ @SafeVarargs
+ public static AuthorizationManager allOf(AuthorizationManager... managers) {
+ return (authentication, object) -> {
+ List decisions = new ArrayList<>();
+ for (AuthorizationManager manager : managers) {
+ AuthorizationDecision decision = manager.check(authentication, object);
+ if (decision != null && !decision.isGranted()) {
+ return decision;
+ }
+ decisions.add(decision);
+ }
+ return new CompositeAuthorizationDecision(true, decisions);
+ };
+ }
+
+ private AuthorizationManagers() {
+ }
+
+ private static final class CompositeAuthorizationDecision extends AuthorizationDecision {
+
+ private final List decisions;
+
+ private CompositeAuthorizationDecision(boolean granted, List decisions) {
+ super(granted);
+ this.decisions = decisions;
+ }
+
+ @Override
+ public String toString() {
+ return "CompositeAuthorizationDecision [decisions=" + this.decisions + ']';
+ }
+
+ }
+
+}
diff --git a/core/src/test/java/org/springframework/security/authorization/AuthorizationManagersTests.java b/core/src/test/java/org/springframework/security/authorization/AuthorizationManagersTests.java
new file mode 100644
index 0000000000..48bdf646e1
--- /dev/null
+++ b/core/src/test/java/org/springframework/security/authorization/AuthorizationManagersTests.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2002-2022 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.security.authorization;
+
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * Tests for {@link AuthorizationManagers}.
+ *
+ * @author Evgeniy Cheban
+ */
+class AuthorizationManagersTests {
+
+ @Test
+ void checkAnyOfWhenOneGrantedThenGrantedDecision() {
+ AuthorizationManager> composed = AuthorizationManagers.anyOf((a, o) -> new AuthorizationDecision(false),
+ (a, o) -> new AuthorizationDecision(true));
+ AuthorizationDecision decision = composed.check(null, null);
+ assertThat(decision).isNotNull();
+ assertThat(decision.isGranted()).isTrue();
+ }
+
+ @Test
+ void checkAnyOfWhenOneAbstainedThenAbstainedDecision() {
+ AuthorizationManager> composed = AuthorizationManagers.anyOf((a, o) -> new AuthorizationDecision(false),
+ (a, o) -> null);
+ AuthorizationDecision decision = composed.check(null, null);
+ assertThat(decision).isNull();
+ }
+
+ @Test
+ void checkAnyOfWhenEmptyThenDeniedDecision() {
+ AuthorizationManager> composed = AuthorizationManagers.anyOf();
+ AuthorizationDecision decision = composed.check(null, null);
+ assertThat(decision).isNotNull();
+ assertThat(decision.isGranted()).isFalse();
+ }
+
+ @Test
+ void checkAllOfWhenAllGrantedThenGrantedDecision() {
+ AuthorizationManager> composed = AuthorizationManagers.allOf((a, o) -> new AuthorizationDecision(true),
+ (a, o) -> new AuthorizationDecision(true));
+ AuthorizationDecision decision = composed.check(null, null);
+ assertThat(decision).isNotNull();
+ assertThat(decision.isGranted()).isTrue();
+ }
+
+ @Test
+ void checkAllOfWhenOneAbstainedThenGrantedDecision() {
+ AuthorizationManager> composed = AuthorizationManagers.allOf((a, o) -> new AuthorizationDecision(true),
+ (a, o) -> null);
+ AuthorizationDecision decision = composed.check(null, null);
+ assertThat(decision).isNotNull();
+ assertThat(decision.isGranted()).isTrue();
+ }
+
+ @Test
+ void checkAllOfWhenOneDeniedThenDeniedDecision() {
+ AuthorizationManager> composed = AuthorizationManagers.allOf((a, o) -> new AuthorizationDecision(true),
+ (a, o) -> new AuthorizationDecision(false));
+ AuthorizationDecision decision = composed.check(null, null);
+ assertThat(decision).isNotNull();
+ assertThat(decision.isGranted()).isFalse();
+ }
+
+ @Test
+ void checkAllOfWhenEmptyThenGrantedDecision() {
+ AuthorizationManager> composed = AuthorizationManagers.allOf();
+ AuthorizationDecision decision = composed.check(null, null);
+ assertThat(decision).isNotNull();
+ assertThat(decision.isGranted()).isTrue();
+ }
+
+}