From 702538ebceb3c713bdb8978f65b6a5910917a1ea Mon Sep 17 00:00:00 2001 From: Josh Cummings Date: Mon, 14 Oct 2024 11:27:11 -0600 Subject: [PATCH] AuthorizationEventPublisher Accepts AuthorizationResult Closes gh-15915 Co-authored-by: Max Batischev --- ...ePostMethodSecurityConfigurationTests.java | 4 ++ .../AuthorizeHttpRequestsConfigurerTests.java | 6 ++- .../AuthorizationEventPublisher.java | 31 ++++++++++++- .../SpringAuthorizationEventPublisher.java | 10 ++++- .../event/AuthorizationDeniedEvent.java | 12 +++++ .../event/AuthorizationEvent.java | 42 +++++++++++++++--- .../event/AuthorizationGrantedEvent.java | 13 ++++++ ...rizationManagerAfterMethodInterceptor.java | 7 +-- ...izationManagerBeforeMethodInterceptor.java | 7 +-- .../NoOpAuthorizationEventPublisher.java | 44 +++++++++++++++++++ ...ionManagerAfterMethodInterceptorTests.java | 5 ++- ...onManagerBeforeMethodInterceptorTests.java | 4 +- gradle.properties | 1 - .../AuthorizationChannelInterceptor.java | 6 +++ .../AuthorizationChannelInterceptorTests.java | 7 ++- .../access/intercept/AuthorizationFilter.java | 25 ++++++++--- .../intercept/AuthorizationFilterTests.java | 5 ++- 17 files changed, 196 insertions(+), 33 deletions(-) create mode 100644 core/src/main/java/org/springframework/security/authorization/method/NoOpAuthorizationEventPublisher.java diff --git a/config/src/test/java/org/springframework/security/config/annotation/method/configuration/PrePostMethodSecurityConfigurationTests.java b/config/src/test/java/org/springframework/security/config/annotation/method/configuration/PrePostMethodSecurityConfigurationTests.java index 73e65c78a7..17d8f8a3a9 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/method/configuration/PrePostMethodSecurityConfigurationTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/method/configuration/PrePostMethodSecurityConfigurationTests.java @@ -75,6 +75,7 @@ import org.springframework.security.access.prepost.PreFilter; import org.springframework.security.authorization.AuthorizationDecision; import org.springframework.security.authorization.AuthorizationEventPublisher; import org.springframework.security.authorization.AuthorizationManager; +import org.springframework.security.authorization.AuthorizationResult; import org.springframework.security.authorization.method.AuthorizationAdvisor; import org.springframework.security.authorization.method.AuthorizationAdvisorProxyFactory; import org.springframework.security.authorization.method.AuthorizationAdvisorProxyFactory.TargetVisitor; @@ -110,6 +111,7 @@ import static org.assertj.core.api.Assertions.assertThatNoException; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.clearInvocations; +import static org.mockito.Mockito.doCallRealMethod; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; @@ -1293,6 +1295,8 @@ public class PrePostMethodSecurityConfigurationTests { @Bean AuthorizationEventPublisher authorizationEventPublisher() { + doCallRealMethod().when(this.publisher) + .publishAuthorizationEvent(any(), any(), any(AuthorizationResult.class)); return this.publisher; } diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/AuthorizeHttpRequestsConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/AuthorizeHttpRequestsConfigurerTests.java index 168f89f137..68c752a394 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/AuthorizeHttpRequestsConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/AuthorizeHttpRequestsConfigurerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2023 the original author or authors. + * Copyright 2002-2024 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. @@ -42,6 +42,7 @@ import org.springframework.security.authorization.AuthorizationDecision; import org.springframework.security.authorization.AuthorizationEventPublisher; import org.springframework.security.authorization.AuthorizationManager; import org.springframework.security.authorization.AuthorizationObservationContext; +import org.springframework.security.authorization.AuthorizationResult; import org.springframework.security.config.ObjectPostProcessor; import org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry; import org.springframework.security.config.annotation.web.builders.HttpSecurity; @@ -78,6 +79,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.mockito.Mockito.any; import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.doCallRealMethod; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; @@ -1241,6 +1243,8 @@ public class AuthorizeHttpRequestsConfigurerTests { @Bean AuthorizationEventPublisher authorizationEventPublisher() { + doCallRealMethod().when(this.publisher) + .publishAuthorizationEvent(any(), any(), any(AuthorizationResult.class)); return this.publisher; } diff --git a/core/src/main/java/org/springframework/security/authorization/AuthorizationEventPublisher.java b/core/src/main/java/org/springframework/security/authorization/AuthorizationEventPublisher.java index de972c59b2..b230d70a97 100644 --- a/core/src/main/java/org/springframework/security/authorization/AuthorizationEventPublisher.java +++ b/core/src/main/java/org/springframework/security/authorization/AuthorizationEventPublisher.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2024 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. @@ -42,8 +42,37 @@ public interface AuthorizationEventPublisher { * @param object the secured object * @param decision the decision about whether the user may access the secured object * @param the secured object's type + * @deprecated use + * {@link #publishAuthorizationEvent(Supplier, Object, AuthorizationResult)} instead */ + @Deprecated void publishAuthorizationEvent(Supplier authentication, T object, AuthorizationDecision decision); + /** + * Publish the given details in the form of an event, typically + * {@link AuthorizationGrantedEvent} or {@link AuthorizationDeniedEvent}. + * + * Note that success events can be very noisy if enabled by default. Because of this + * implementations may choose to drop success events by default. + * @param authentication a {@link Supplier} for the current user + * @param object the secured object + * @param result {@link AuthorizationResult} the result about whether the user may + * access the secured object + * @param the secured object's type + * @since 6.4 + */ + default void publishAuthorizationEvent(Supplier authentication, T object, + AuthorizationResult result) { + if (result == null) { + publishAuthorizationEvent(authentication, object, null); + return; + } + if (result instanceof AuthorizationDecision decision) { + publishAuthorizationEvent(authentication, object, decision); + return; + } + throw new UnsupportedOperationException("result must be of type AuthorizationDecision"); + } + } diff --git a/core/src/main/java/org/springframework/security/authorization/SpringAuthorizationEventPublisher.java b/core/src/main/java/org/springframework/security/authorization/SpringAuthorizationEventPublisher.java index 2ef21a2873..43e37c5523 100644 --- a/core/src/main/java/org/springframework/security/authorization/SpringAuthorizationEventPublisher.java +++ b/core/src/main/java/org/springframework/security/authorization/SpringAuthorizationEventPublisher.java @@ -55,10 +55,16 @@ public final class SpringAuthorizationEventPublisher implements AuthorizationEve @Override public void publishAuthorizationEvent(Supplier authentication, T object, AuthorizationDecision decision) { - if (decision == null || decision.isGranted()) { + publishAuthorizationEvent(authentication, object, (AuthorizationResult) decision); + } + + @Override + public void publishAuthorizationEvent(Supplier authentication, T object, + AuthorizationResult result) { + if (result == null || result.isGranted()) { return; } - AuthorizationDeniedEvent failure = new AuthorizationDeniedEvent<>(authentication, object, decision); + AuthorizationDeniedEvent failure = new AuthorizationDeniedEvent<>(authentication, object, result); this.eventPublisher.publishEvent(failure); } diff --git a/core/src/main/java/org/springframework/security/authorization/event/AuthorizationDeniedEvent.java b/core/src/main/java/org/springframework/security/authorization/event/AuthorizationDeniedEvent.java index df964c6196..94e7d6a231 100644 --- a/core/src/main/java/org/springframework/security/authorization/event/AuthorizationDeniedEvent.java +++ b/core/src/main/java/org/springframework/security/authorization/event/AuthorizationDeniedEvent.java @@ -20,6 +20,7 @@ import java.util.function.Supplier; import org.springframework.context.ApplicationEvent; import org.springframework.security.authorization.AuthorizationDecision; +import org.springframework.security.authorization.AuthorizationResult; import org.springframework.security.core.Authentication; /** @@ -31,10 +32,21 @@ import org.springframework.security.core.Authentication; */ public class AuthorizationDeniedEvent extends AuthorizationEvent { + /** + * @deprecated Please use an {@link AuthorizationResult} constructor instead + */ + @Deprecated public AuthorizationDeniedEvent(Supplier authentication, T object, AuthorizationDecision decision) { super(authentication, object, decision); } + /** + * @since 6.4 + */ + public AuthorizationDeniedEvent(Supplier authentication, T object, AuthorizationResult result) { + super(authentication, object, result); + } + /** * Get the object to which access was requested * @return the object to which access was requested diff --git a/core/src/main/java/org/springframework/security/authorization/event/AuthorizationEvent.java b/core/src/main/java/org/springframework/security/authorization/event/AuthorizationEvent.java index fd046a1312..a848dff491 100644 --- a/core/src/main/java/org/springframework/security/authorization/event/AuthorizationEvent.java +++ b/core/src/main/java/org/springframework/security/authorization/event/AuthorizationEvent.java @@ -20,6 +20,7 @@ import java.util.function.Supplier; import org.springframework.context.ApplicationEvent; import org.springframework.security.authorization.AuthorizationDecision; +import org.springframework.security.authorization.AuthorizationResult; import org.springframework.security.core.Authentication; import org.springframework.util.Assert; @@ -34,19 +35,32 @@ public class AuthorizationEvent extends ApplicationEvent { private final Supplier authentication; - private final AuthorizationDecision decision; + private final AuthorizationResult result; /** * Construct an {@link AuthorizationEvent} * @param authentication the principal requiring access * @param object the object to which access was requested - * @param decision whether authorization was granted or denied + * @param result whether authorization was granted or denied */ - public AuthorizationEvent(Supplier authentication, Object object, AuthorizationDecision decision) { + public AuthorizationEvent(Supplier authentication, Object object, AuthorizationDecision result) { super(object); Assert.notNull(authentication, "authentication supplier cannot be null"); this.authentication = authentication; - this.decision = decision; + this.result = result; + } + + /** + * Construct an {@link AuthorizationEvent} + * @param authentication the principal requiring access + * @param object the object to which access was requested + * @param result whether authorization was granted or denied + */ + public AuthorizationEvent(Supplier authentication, Object object, AuthorizationResult result) { + super(object); + Assert.notNull(authentication, "authentication supplier cannot be null"); + this.authentication = authentication; + this.result = result; } /** @@ -68,9 +82,27 @@ public class AuthorizationEvent extends ApplicationEvent { /** * Get the response to the principal's request * @return the response to the principal's request + * @deprecated please use {@link #getAuthorizationResult()} */ + @Deprecated public AuthorizationDecision getAuthorizationDecision() { - return this.decision; + if (this.result == null) { + return null; + } + if (this.result instanceof AuthorizationDecision decision) { + return decision; + } + throw new IllegalArgumentException( + "Please either call getAuthorizationResult or ensure that the result is of type AuthorizationDecision"); + } + + /** + * Get the response to the principal's request + * @return the response to the principal's request + * @since 6.4 + */ + public AuthorizationResult getAuthorizationResult() { + return this.result; } } diff --git a/core/src/main/java/org/springframework/security/authorization/event/AuthorizationGrantedEvent.java b/core/src/main/java/org/springframework/security/authorization/event/AuthorizationGrantedEvent.java index f44bbb391e..693bc7e4a7 100644 --- a/core/src/main/java/org/springframework/security/authorization/event/AuthorizationGrantedEvent.java +++ b/core/src/main/java/org/springframework/security/authorization/event/AuthorizationGrantedEvent.java @@ -20,6 +20,7 @@ import java.util.function.Supplier; import org.springframework.context.ApplicationEvent; import org.springframework.security.authorization.AuthorizationDecision; +import org.springframework.security.authorization.AuthorizationResult; import org.springframework.security.core.Authentication; /** @@ -31,11 +32,23 @@ import org.springframework.security.core.Authentication; */ public class AuthorizationGrantedEvent extends AuthorizationEvent { + /** + * @deprecated please use a constructor that takes an + * {@link org.springframework.security.authorization.AuthorizationResult} + */ + @Deprecated public AuthorizationGrantedEvent(Supplier authentication, T object, AuthorizationDecision decision) { super(authentication, object, decision); } + /** + * @since 6.4 + */ + public AuthorizationGrantedEvent(Supplier authentication, T object, AuthorizationResult result) { + super(authentication, object, result); + } + /** * Get the object to which access was requested * @return the object to which access was requested diff --git a/core/src/main/java/org/springframework/security/authorization/method/AuthorizationManagerAfterMethodInterceptor.java b/core/src/main/java/org/springframework/security/authorization/method/AuthorizationManagerAfterMethodInterceptor.java index 63448a6472..0be0d776c6 100644 --- a/core/src/main/java/org/springframework/security/authorization/method/AuthorizationManagerAfterMethodInterceptor.java +++ b/core/src/main/java/org/springframework/security/authorization/method/AuthorizationManagerAfterMethodInterceptor.java @@ -60,7 +60,7 @@ public final class AuthorizationManagerAfterMethodInterceptor implements Authori private int order; - private AuthorizationEventPublisher eventPublisher = AuthorizationManagerAfterMethodInterceptor::noPublish; + private AuthorizationEventPublisher eventPublisher = new NoOpAuthorizationEventPublisher(); /** * Creates an instance. @@ -209,9 +209,4 @@ public final class AuthorizationManagerAfterMethodInterceptor implements Authori return authentication; } - private static void noPublish(Supplier authentication, T object, - AuthorizationDecision decision) { - - } - } diff --git a/core/src/main/java/org/springframework/security/authorization/method/AuthorizationManagerBeforeMethodInterceptor.java b/core/src/main/java/org/springframework/security/authorization/method/AuthorizationManagerBeforeMethodInterceptor.java index cb753e34cd..421b55dad7 100644 --- a/core/src/main/java/org/springframework/security/authorization/method/AuthorizationManagerBeforeMethodInterceptor.java +++ b/core/src/main/java/org/springframework/security/authorization/method/AuthorizationManagerBeforeMethodInterceptor.java @@ -65,7 +65,7 @@ public final class AuthorizationManagerBeforeMethodInterceptor implements Author private int order = AuthorizationInterceptorsOrder.FIRST.getOrder(); - private AuthorizationEventPublisher eventPublisher = AuthorizationManagerBeforeMethodInterceptor::noPublish; + private AuthorizationEventPublisher eventPublisher = new NoOpAuthorizationEventPublisher(); /** * Creates an instance. @@ -299,9 +299,4 @@ public final class AuthorizationManagerBeforeMethodInterceptor implements Author return authentication; } - private static void noPublish(Supplier authentication, T object, - AuthorizationDecision decision) { - - } - } diff --git a/core/src/main/java/org/springframework/security/authorization/method/NoOpAuthorizationEventPublisher.java b/core/src/main/java/org/springframework/security/authorization/method/NoOpAuthorizationEventPublisher.java new file mode 100644 index 0000000000..fff9b0255e --- /dev/null +++ b/core/src/main/java/org/springframework/security/authorization/method/NoOpAuthorizationEventPublisher.java @@ -0,0 +1,44 @@ +/* + * Copyright 2002-2024 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.method; + +import java.util.function.Supplier; + +import org.springframework.security.authorization.AuthorizationDecision; +import org.springframework.security.authorization.AuthorizationEventPublisher; +import org.springframework.security.authorization.AuthorizationResult; +import org.springframework.security.core.Authentication; + +/** + * An {@link AuthorizationEventPublisher} implementation that does nothing. + * + * @author Max Batischev + * @since 6.4 + */ +final class NoOpAuthorizationEventPublisher implements AuthorizationEventPublisher { + + @Override + public void publishAuthorizationEvent(Supplier authentication, T object, + AuthorizationDecision decision) { + } + + @Override + public void publishAuthorizationEvent(Supplier authentication, T object, + AuthorizationResult result) { + } + +} diff --git a/core/src/test/java/org/springframework/security/authorization/method/AuthorizationManagerAfterMethodInterceptorTests.java b/core/src/test/java/org/springframework/security/authorization/method/AuthorizationManagerAfterMethodInterceptorTests.java index e34b45a33c..950911ffc5 100644 --- a/core/src/test/java/org/springframework/security/authorization/method/AuthorizationManagerAfterMethodInterceptorTests.java +++ b/core/src/test/java/org/springframework/security/authorization/method/AuthorizationManagerAfterMethodInterceptorTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2023 the original author or authors. + * Copyright 2002-2024 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. @@ -42,6 +42,7 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType; 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.doCallRealMethod; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; @@ -127,6 +128,8 @@ public class AuthorizationManagerAfterMethodInterceptorTests { AuthorizationManagerAfterMethodInterceptor advice = new AuthorizationManagerAfterMethodInterceptor( Pointcut.TRUE, AuthenticatedAuthorizationManager.authenticated()); AuthorizationEventPublisher eventPublisher = mock(AuthorizationEventPublisher.class); + doCallRealMethod().when(eventPublisher) + .publishAuthorizationEvent(any(Supplier.class), any(), any(AuthorizationResult.class)); advice.setAuthorizationEventPublisher(eventPublisher); SecurityContext securityContext = new SecurityContextImpl(); diff --git a/core/src/test/java/org/springframework/security/authorization/method/AuthorizationManagerBeforeMethodInterceptorTests.java b/core/src/test/java/org/springframework/security/authorization/method/AuthorizationManagerBeforeMethodInterceptorTests.java index 8022609ac7..5f6d5fc70b 100644 --- a/core/src/test/java/org/springframework/security/authorization/method/AuthorizationManagerBeforeMethodInterceptorTests.java +++ b/core/src/test/java/org/springframework/security/authorization/method/AuthorizationManagerBeforeMethodInterceptorTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2023 the original author or authors. + * Copyright 2002-2024 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. @@ -41,6 +41,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.doCallRealMethod; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; @@ -121,6 +122,7 @@ public class AuthorizationManagerBeforeMethodInterceptorTests { AuthorizationManagerBeforeMethodInterceptor advice = new AuthorizationManagerBeforeMethodInterceptor( Pointcut.TRUE, AuthenticatedAuthorizationManager.authenticated()); AuthorizationEventPublisher eventPublisher = mock(AuthorizationEventPublisher.class); + doCallRealMethod().when(eventPublisher).publishAuthorizationEvent(any(), any(), any(AuthorizationResult.class)); advice.setAuthorizationEventPublisher(eventPublisher); SecurityContext securityContext = new SecurityContextImpl(); diff --git a/gradle.properties b/gradle.properties index b56058f98a..30c658319d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -13,7 +13,6 @@ # See the License for the specific language governing permissions and # limitations under the License. # - springBootVersion=3.3.3 version=6.4.0-SNAPSHOT samplesBranch=main diff --git a/messaging/src/main/java/org/springframework/security/messaging/access/intercept/AuthorizationChannelInterceptor.java b/messaging/src/main/java/org/springframework/security/messaging/access/intercept/AuthorizationChannelInterceptor.java index c61e3b660e..2af2b1cc56 100644 --- a/messaging/src/main/java/org/springframework/security/messaging/access/intercept/AuthorizationChannelInterceptor.java +++ b/messaging/src/main/java/org/springframework/security/messaging/access/intercept/AuthorizationChannelInterceptor.java @@ -30,6 +30,7 @@ import org.springframework.security.authentication.AuthenticationCredentialsNotF import org.springframework.security.authorization.AuthorizationDecision; import org.springframework.security.authorization.AuthorizationEventPublisher; import org.springframework.security.authorization.AuthorizationManager; +import org.springframework.security.authorization.AuthorizationResult; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolderStrategy; @@ -114,6 +115,11 @@ public final class AuthorizationChannelInterceptor implements ChannelInterceptor } + @Override + public void publishAuthorizationEvent(Supplier authentication, T object, + AuthorizationResult result) { + } + } } diff --git a/messaging/src/test/java/org/springframework/security/messaging/access/intercept/AuthorizationChannelInterceptorTests.java b/messaging/src/test/java/org/springframework/security/messaging/access/intercept/AuthorizationChannelInterceptorTests.java index fc354ed212..f31c9065a0 100644 --- a/messaging/src/test/java/org/springframework/security/messaging/access/intercept/AuthorizationChannelInterceptorTests.java +++ b/messaging/src/test/java/org/springframework/security/messaging/access/intercept/AuthorizationChannelInterceptorTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2024 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. @@ -30,6 +30,7 @@ import org.springframework.security.authentication.TestingAuthenticationToken; import org.springframework.security.authorization.AuthorizationDecision; import org.springframework.security.authorization.AuthorizationEventPublisher; import org.springframework.security.authorization.AuthorizationManager; +import org.springframework.security.authorization.AuthorizationResult; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; @@ -38,6 +39,7 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType; 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.lenient; import static org.mockito.Mockito.verify; /** @@ -102,6 +104,9 @@ public class AuthorizationChannelInterceptorTests { public void preSendWhenAuthorizationEventPublisherThenPublishes() { this.interceptor.setAuthorizationEventPublisher(this.eventPublisher); given(this.authorizationManager.check(any(), any())).willReturn(new AuthorizationDecision(true)); + lenient().doCallRealMethod() + .when(this.eventPublisher) + .publishAuthorizationEvent(any(), any(), any(AuthorizationResult.class)); this.interceptor.preSend(this.message, this.channel); verify(this.eventPublisher).publishAuthorizationEvent(any(), any(), any()); } diff --git a/web/src/main/java/org/springframework/security/web/access/intercept/AuthorizationFilter.java b/web/src/main/java/org/springframework/security/web/access/intercept/AuthorizationFilter.java index bc09dc0573..cfc2f00140 100644 --- a/web/src/main/java/org/springframework/security/web/access/intercept/AuthorizationFilter.java +++ b/web/src/main/java/org/springframework/security/web/access/intercept/AuthorizationFilter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2023 the original author or authors. + * Copyright 2002-2024 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. @@ -33,6 +33,7 @@ import org.springframework.security.authorization.AuthorizationDecision; import org.springframework.security.authorization.AuthorizationDeniedException; import org.springframework.security.authorization.AuthorizationEventPublisher; import org.springframework.security.authorization.AuthorizationManager; +import org.springframework.security.authorization.AuthorizationResult; import org.springframework.security.authorization.event.AuthorizationDeniedEvent; import org.springframework.security.authorization.event.AuthorizationGrantedEvent; import org.springframework.security.core.Authentication; @@ -55,7 +56,7 @@ public class AuthorizationFilter extends GenericFilterBean { private final AuthorizationManager authorizationManager; - private AuthorizationEventPublisher eventPublisher = AuthorizationFilter::noPublish; + private AuthorizationEventPublisher eventPublisher = new NoopAuthorizationEventPublisher(); private boolean observeOncePerRequest = false; @@ -195,11 +196,6 @@ public class AuthorizationFilter extends GenericFilterBean { this.filterAsyncDispatch = shouldFilterAllDispatcherTypes; } - private static void noPublish(Supplier authentication, T object, - AuthorizationDecision decision) { - - } - public boolean isObserveOncePerRequest() { return this.observeOncePerRequest; } @@ -235,4 +231,19 @@ public class AuthorizationFilter extends GenericFilterBean { this.filterAsyncDispatch = filterAsyncDispatch; } + private static class NoopAuthorizationEventPublisher implements AuthorizationEventPublisher { + + @Override + public void publishAuthorizationEvent(Supplier authentication, T object, + AuthorizationDecision decision) { + + } + + @Override + public void publishAuthorizationEvent(Supplier authentication, T object, + AuthorizationResult result) { + } + + } + } diff --git a/web/src/test/java/org/springframework/security/web/access/intercept/AuthorizationFilterTests.java b/web/src/test/java/org/springframework/security/web/access/intercept/AuthorizationFilterTests.java index e24fb6fd03..28f0a75f7f 100644 --- a/web/src/test/java/org/springframework/security/web/access/intercept/AuthorizationFilterTests.java +++ b/web/src/test/java/org/springframework/security/web/access/intercept/AuthorizationFilterTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2024 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. @@ -38,6 +38,7 @@ import org.springframework.security.authorization.AuthenticatedAuthorizationMana import org.springframework.security.authorization.AuthorizationDecision; import org.springframework.security.authorization.AuthorizationEventPublisher; import org.springframework.security.authorization.AuthorizationManager; +import org.springframework.security.authorization.AuthorizationResult; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContextHolder; @@ -53,6 +54,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.BDDMockito.given; import static org.mockito.BDDMockito.willThrow; +import static org.mockito.Mockito.doCallRealMethod; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; @@ -186,6 +188,7 @@ public class AuthorizationFilterTests { SecurityContextHolder.setContext(securityContext); AuthorizationEventPublisher eventPublisher = mock(AuthorizationEventPublisher.class); + doCallRealMethod().when(eventPublisher).publishAuthorizationEvent(any(), any(), any(AuthorizationResult.class)); authorizationFilter.setAuthorizationEventPublisher(eventPublisher); authorizationFilter.doFilter(mockRequest, mockResponse, mockFilterChain); verify(eventPublisher).publishAuthorizationEvent(any(Supplier.class), any(HttpServletRequest.class),