Browse Source

Merge remote-tracking branch 'origin/5.8.x'

Josh Cummings 2 years ago
parent
commit
eeb28e4f91

+ 21 - 2
web/src/main/java/org/springframework/security/web/access/intercept/RequestMatcherDelegatingAuthorizationManager.java

@@ -48,6 +48,8 @@ public final class RequestMatcherDelegatingAuthorizationManager implements Autho
 
 	private final List<RequestMatcherEntry<AuthorizationManager<RequestAuthorizationContext>>> mappings;
 
+	private AuthorizationManager<RequestAuthorizationContext> defaultManager = (authentication, request) -> null;
+
 	private RequestMatcherDelegatingAuthorizationManager(
 			List<RequestMatcherEntry<AuthorizationManager<RequestAuthorizationContext>>> mappings) {
 		Assert.notEmpty(mappings, "mappings cannot be empty");
@@ -81,8 +83,10 @@ public final class RequestMatcherDelegatingAuthorizationManager implements Autho
 						new RequestAuthorizationContext(request, matchResult.getVariables()));
 			}
 		}
-		this.logger.trace("Abstaining since did not find matching RequestMatcher");
-		return null;
+		if (this.logger.isTraceEnabled()) {
+			this.logger.trace(LogMessage.format("Checking authorization on %s using %s", request, this.defaultManager));
+		}
+		return this.defaultManager.check(authentication, new RequestAuthorizationContext(request));
 	}
 
 	/**
@@ -93,6 +97,21 @@ public final class RequestMatcherDelegatingAuthorizationManager implements Autho
 		return new Builder();
 	}
 
+	/**
+	 * Use this {@link AuthorizationManager} if the request fails to match any other
+	 * configured {@link AuthorizationManager}.
+	 *
+	 * <p>
+	 * This is specifically handy when considering whether to accept or deny requests by
+	 * default. The default is to abstain from deciding on requests that don't match
+	 * configuration.
+	 * @param authorizationManager the {@link AuthorizationManager} to use
+	 * @since 5.8
+	 */
+	public void setDefaultAuthorizationManager(AuthorizationManager<RequestAuthorizationContext> authorizationManager) {
+		this.defaultManager = authorizationManager;
+	}
+
 	/**
 	 * A builder for {@link RequestMatcherDelegatingAuthorizationManager}.
 	 */

+ 19 - 0
web/src/test/java/org/springframework/security/web/access/intercept/RequestMatcherDelegatingAuthorizationManagerTests.java

@@ -24,6 +24,7 @@ import org.springframework.mock.web.MockHttpServletRequest;
 import org.springframework.security.authentication.TestingAuthenticationToken;
 import org.springframework.security.authorization.AuthorityAuthorizationManager;
 import org.springframework.security.authorization.AuthorizationDecision;
+import org.springframework.security.authorization.AuthorizationManager;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher;
 import org.springframework.security.web.util.matcher.AnyRequestMatcher;
@@ -31,6 +32,10 @@ import org.springframework.security.web.util.matcher.RequestMatcherEntry;
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.BDDMockito.given;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
 
 /**
  * Tests for {@link RequestMatcherDelegatingAuthorizationManager}.
@@ -115,6 +120,20 @@ public class RequestMatcherDelegatingAuthorizationManagerTests {
 		assertThat(unmapped.isGranted()).isFalse();
 	}
 
+	@Test
+	public void checkWhenNoMatchesThenUsesDefaultAuthorizationManager() {
+		RequestMatcherDelegatingAuthorizationManager manager = RequestMatcherDelegatingAuthorizationManager.builder()
+				.add((request) -> false, (authentication, context) -> new AuthorizationDecision(false)).build();
+		AuthorizationManager<RequestAuthorizationContext> defaultManager = mock(AuthorizationManager.class);
+		given(defaultManager.check(any(), any())).willReturn(new AuthorizationDecision(true));
+		manager.setDefaultAuthorizationManager(defaultManager);
+		Supplier<Authentication> authentication = () -> new TestingAuthenticationToken("user", "password");
+		AuthorizationDecision decision = manager.check(authentication, new MockHttpServletRequest(null, "/endpoint"));
+		assertThat(decision).isNotNull();
+		assertThat(decision.isGranted()).isTrue();
+		verify(defaultManager).check(any(), any());
+	}
+
 	@Test
 	public void addWhenMappingsConsumerNullThenException() {
 		assertThatIllegalArgumentException()