Polish Authorization Event Support

- Added spring-security-config support
- Renamed classes
- Changed contracts to include the authenticated user and secured
object
- Added method security support

Issue gh-9288
This commit is contained in:
Josh Cummings 2022-03-29 11:52:08 -06:00
parent bd9434882f
commit 061f69eb70
No known key found for this signature in database
GPG Key ID: A306A51F43B8E5A5
19 changed files with 498 additions and 239 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* 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.
@ -17,16 +17,16 @@
package org.springframework.security.config.annotation.method.configuration;
import org.springframework.aop.Advisor;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Role;
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler;
import org.springframework.security.authorization.AuthorizationEventPublisher;
import org.springframework.security.authorization.SpringAuthorizationEventPublisher;
import org.springframework.security.authorization.method.AuthorizationManagerAfterMethodInterceptor;
import org.springframework.security.authorization.method.AuthorizationManagerBeforeMethodInterceptor;
import org.springframework.security.authorization.method.PostAuthorizeAuthorizationManager;
@ -45,7 +45,7 @@ import org.springframework.security.config.core.GrantedAuthorityDefaults;
*/
@Configuration(proxyBeanMethods = false)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
final class PrePostMethodSecurityConfiguration implements ApplicationContextAware {
final class PrePostMethodSecurityConfiguration {
private final PreFilterAuthorizationMethodInterceptor preFilterAuthorizationMethodInterceptor = new PreFilterAuthorizationMethodInterceptor();
@ -61,7 +61,8 @@ final class PrePostMethodSecurityConfiguration implements ApplicationContextAwar
private final DefaultMethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
PrePostMethodSecurityConfiguration() {
@Autowired
PrePostMethodSecurityConfiguration(ApplicationContext context) {
this.preAuthorizeAuthorizationManager.setExpressionHandler(this.expressionHandler);
this.preAuthorizeAuthorizationMethodInterceptor = AuthorizationManagerBeforeMethodInterceptor
.preAuthorize(this.preAuthorizeAuthorizationManager);
@ -70,6 +71,10 @@ final class PrePostMethodSecurityConfiguration implements ApplicationContextAwar
.postAuthorize(this.postAuthorizeAuthorizationManager);
this.preFilterAuthorizationMethodInterceptor.setExpressionHandler(this.expressionHandler);
this.postFilterAuthorizationMethodInterceptor.setExpressionHandler(this.expressionHandler);
this.expressionHandler.setApplicationContext(context);
AuthorizationEventPublisher publisher = new SpringAuthorizationEventPublisher(context);
this.preAuthorizeAuthorizationMethodInterceptor.setAuthorizationEventPublisher(publisher);
this.postAuthorizeAuthorizaitonMethodInterceptor.setAuthorizationEventPublisher(publisher);
}
@Bean
@ -109,9 +114,10 @@ final class PrePostMethodSecurityConfiguration implements ApplicationContextAwar
this.expressionHandler.setDefaultRolePrefix(grantedAuthorityDefaults.getRolePrefix());
}
@Override
public void setApplicationContext(ApplicationContext context) throws BeansException {
this.expressionHandler.setApplicationContext(context);
@Autowired(required = false)
void setAuthorizationEventPublisher(AuthorizationEventPublisher eventPublisher) {
this.preAuthorizeAuthorizationMethodInterceptor.setAuthorizationEventPublisher(eventPublisher);
this.postAuthorizeAuthorizaitonMethodInterceptor.setAuthorizationEventPublisher(eventPublisher);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* 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.
@ -26,7 +26,9 @@ import org.springframework.http.HttpMethod;
import org.springframework.security.authorization.AuthenticatedAuthorizationManager;
import org.springframework.security.authorization.AuthorityAuthorizationManager;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.AuthorizationEventPublisher;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.authorization.SpringAuthorizationEventPublisher;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry;
import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
@ -52,12 +54,20 @@ public final class AuthorizeHttpRequestsConfigurer<H extends HttpSecurityBuilder
private final AuthorizationManagerRequestMatcherRegistry registry;
private final AuthorizationEventPublisher publisher;
/**
* Creates an instance.
* @param context the {@link ApplicationContext} to use
*/
public AuthorizeHttpRequestsConfigurer(ApplicationContext context) {
this.registry = new AuthorizationManagerRequestMatcherRegistry(context);
if (context.getBeanNamesForType(AuthorizationEventPublisher.class).length > 0) {
this.publisher = context.getBean(AuthorizationEventPublisher.class);
}
else {
this.publisher = new SpringAuthorizationEventPublisher(context);
}
}
/**
@ -74,6 +84,7 @@ public final class AuthorizeHttpRequestsConfigurer<H extends HttpSecurityBuilder
public void configure(H http) {
AuthorizationManager<HttpServletRequest> authorizationManager = this.registry.createAuthorizationManager();
AuthorizationFilter authorizationFilter = new AuthorizationFilter(authorizationManager);
authorizationFilter.setAuthorizationEventPublisher(this.publisher);
http.addFilter(postProcess(authorizationFilter));
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* 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.
@ -20,6 +20,7 @@ import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Supplier;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
@ -32,6 +33,7 @@ import org.springframework.aop.support.JdkRegexpMethodPointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Role;
import org.springframework.core.annotation.AnnotationConfigurationException;
import org.springframework.security.access.AccessDeniedException;
@ -43,9 +45,11 @@ import org.springframework.security.access.annotation.Jsr250BusinessServiceImpl;
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.AuthorizationEventPublisher;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.authorization.method.AuthorizationInterceptorsOrder;
import org.springframework.security.authorization.method.AuthorizationManagerBeforeMethodInterceptor;
import org.springframework.security.authorization.method.MethodInvocationResult;
import org.springframework.security.config.core.GrantedAuthorityDefaults;
import org.springframework.security.config.test.SpringTestContext;
import org.springframework.security.config.test.SpringTestContextExtension;
@ -58,6 +62,9 @@ import org.springframework.test.context.junit.jupiter.SpringExtension;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
/**
* Tests for {@link PrePostMethodSecurityConfiguration}.
@ -350,6 +357,27 @@ public class PrePostMethodSecurityConfigurationTests {
.isThrownBy(() -> this.businessService.repeatedAnnotations());
}
@WithMockUser
@Test
public void preAuthorizeWhenAuthorizationEventPublisherThenUses() {
this.spring.register(MethodSecurityServiceConfig.class, AuthorizationEventPublisherConfig.class).autowire();
assertThatExceptionOfType(AccessDeniedException.class)
.isThrownBy(() -> this.methodSecurityService.preAuthorize());
AuthorizationEventPublisher publisher = this.spring.getContext().getBean(AuthorizationEventPublisher.class);
verify(publisher).publishAuthorizationEvent(any(Supplier.class), any(MethodInvocation.class),
any(AuthorizationDecision.class));
}
@WithMockUser
@Test
public void postAuthorizeWhenAuthorizationEventPublisherThenUses() {
this.spring.register(MethodSecurityServiceConfig.class, AuthorizationEventPublisherConfig.class).autowire();
this.methodSecurityService.postAnnotation("grant");
AuthorizationEventPublisher publisher = this.spring.getContext().getBean(AuthorizationEventPublisher.class);
verify(publisher).publishAuthorizationEvent(any(Supplier.class), any(MethodInvocationResult.class),
any(AuthorizationDecision.class));
}
// gh-10305
@WithMockUser
@Test
@ -484,4 +512,16 @@ public class PrePostMethodSecurityConfigurationTests {
}
@Configuration
static class AuthorizationEventPublisherConfig {
private final AuthorizationEventPublisher publisher = mock(AuthorizationEventPublisher.class);
@Bean
AuthorizationEventPublisher authorizationEventPublisher() {
return this.publisher;
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* 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.
@ -16,12 +16,19 @@
package org.springframework.security.config.annotation.web.configurers;
import java.util.function.Supplier;
import javax.servlet.http.HttpServletRequest;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.AuthorizationEventPublisher;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry;
@ -129,9 +136,9 @@ public class AuthorizeHttpRequestsConfigurerTests {
@Test
public void configureWhenObjectPostProcessorRegisteredThenInvokedOnAuthorizationManagerAndAuthorizationFilter() {
this.spring.register(ObjectPostProcessorConfig.class).autowire();
verify(ObjectPostProcessorConfig.objectPostProcessor)
.postProcess(any(RequestMatcherDelegatingAuthorizationManager.class));
verify(ObjectPostProcessorConfig.objectPostProcessor).postProcess(any(AuthorizationFilter.class));
ObjectPostProcessor objectPostProcessor = this.spring.getContext().getBean(ObjectPostProcessor.class);
verify(objectPostProcessor).postProcess(any(RequestMatcherDelegatingAuthorizationManager.class));
verify(objectPostProcessor).postProcess(any(AuthorizationFilter.class));
}
@Test
@ -369,6 +376,15 @@ public class AuthorizeHttpRequestsConfigurerTests {
this.mvc.perform(get("/")).andExpect(status().isUnauthorized());
}
@Test
public void getWhenCustomAuthorizationEventPublisherThenUses() throws Exception {
this.spring.register(AuthenticatedConfig.class, AuthorizationEventPublisherConfig.class).autowire();
this.mvc.perform(get("/")).andExpect(status().isUnauthorized());
AuthorizationEventPublisher publisher = this.spring.getContext().getBean(AuthorizationEventPublisher.class);
verify(publisher).publishAuthorizationEvent(any(Supplier.class), any(HttpServletRequest.class),
any(AuthorizationDecision.class));
}
@Test
public void getWhenAnyRequestAuthenticatedConfiguredAndUserLoggedInThenRespondsWithOk() throws Exception {
this.spring.register(AuthenticatedConfig.class, BasicController.class).autowire();
@ -495,7 +511,7 @@ public class AuthorizeHttpRequestsConfigurerTests {
@EnableWebSecurity
static class ObjectPostProcessorConfig {
static ObjectPostProcessor<Object> objectPostProcessor = spy(ReflectingObjectPostProcessor.class);
ObjectPostProcessor<Object> objectPostProcessor = spy(ReflectingObjectPostProcessor.class);
@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
@ -509,8 +525,8 @@ public class AuthorizeHttpRequestsConfigurerTests {
}
@Bean
static ObjectPostProcessor<Object> objectPostProcessor() {
return objectPostProcessor;
ObjectPostProcessor<Object> objectPostProcessor() {
return this.objectPostProcessor;
}
}
@ -698,6 +714,18 @@ public class AuthorizeHttpRequestsConfigurerTests {
}
@Configuration
static class AuthorizationEventPublisherConfig {
private final AuthorizationEventPublisher publisher = mock(AuthorizationEventPublisher.class);
@Bean
AuthorizationEventPublisher authorizationEventPublisher() {
return this.publisher;
}
}
@RestController
static class BasicController {

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* 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.
@ -16,14 +16,34 @@
package org.springframework.security.authorization;
import java.util.function.Supplier;
import org.springframework.security.authorization.event.AuthorizationDeniedEvent;
import org.springframework.security.authorization.event.AuthorizationGrantedEvent;
import org.springframework.security.core.Authentication;
/**
* A contract for publishing authorization events
*
* @author Parikshit Dutta
* @since 5.5
* @author Josh Cummings
* @since 5.7
* @see AuthorizationManager
*/
public interface AuthorizationEventPublisher {
void publishAuthorizationSuccess(AuthorizationDecision authorizationDecision);
void publishAuthorizationFailure(AuthorizationDecision authorizationDecision);
/**
* 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 decision the decision about whether the user may access the secured object
* @param <T> the secured object's type
*/
<T> void publishAuthorizationEvent(Supplier<Authentication> authentication, T object,
AuthorizationDecision decision);
}

View File

@ -1,61 +0,0 @@
/*
* Copyright 2002-2021 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.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.security.authorization.event.AuthorizationFailureEvent;
import org.springframework.security.authorization.event.AuthorizationSuccessEvent;
/**
* Default implementation of {@link AuthorizationEventPublisher}
*
* @author Parikshit Dutta
* @since 5.5
*/
public class DefaultAuthorizationEventPublisher implements AuthorizationEventPublisher, ApplicationEventPublisherAware {
private ApplicationEventPublisher applicationEventPublisher;
public DefaultAuthorizationEventPublisher() {
this(null);
}
public DefaultAuthorizationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.applicationEventPublisher = applicationEventPublisher;
}
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.applicationEventPublisher = applicationEventPublisher;
}
@Override
public void publishAuthorizationSuccess(AuthorizationDecision authorizationDecision) {
if (this.applicationEventPublisher != null) {
this.applicationEventPublisher.publishEvent(new AuthorizationSuccessEvent(authorizationDecision));
}
}
@Override
public void publishAuthorizationFailure(AuthorizationDecision authorizationDecision) {
if (this.applicationEventPublisher != null) {
this.applicationEventPublisher.publishEvent(new AuthorizationFailureEvent(authorizationDecision));
}
}
}

View File

@ -0,0 +1,65 @@
/*
* 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.function.Supplier;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.security.authorization.event.AuthorizationDeniedEvent;
import org.springframework.security.authorization.event.AuthorizationGrantedEvent;
import org.springframework.security.core.Authentication;
import org.springframework.util.Assert;
/**
* An implementation of {@link AuthorizationEventPublisher} that uses Spring's event
* publishing support.
*
* Because {@link AuthorizationGrantedEvent}s typically require additional business logic
* to decide whether to publish, this implementation only publishes
* {@link AuthorizationDeniedEvent}s.
*
* @author Parikshit Dutta
* @author Josh Cummings
* @since 5.7
*/
public final class SpringAuthorizationEventPublisher implements AuthorizationEventPublisher {
private final ApplicationEventPublisher eventPublisher;
/**
* Construct this publisher using Spring's {@link ApplicationEventPublisher}
* @param eventPublisher
*/
public SpringAuthorizationEventPublisher(ApplicationEventPublisher eventPublisher) {
Assert.notNull(eventPublisher, "eventPublisher cannot be null");
this.eventPublisher = eventPublisher;
}
/**
* {@inheritDoc}
*/
@Override
public <T> void publishAuthorizationEvent(Supplier<Authentication> authentication, T object,
AuthorizationDecision decision) {
if (decision == null || decision.isGranted()) {
return;
}
AuthorizationDeniedEvent<T> failure = new AuthorizationDeniedEvent<>(authentication, object, decision);
this.eventPublisher.publishEvent(failure);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* 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.
@ -16,19 +16,37 @@
package org.springframework.security.authorization.event;
import java.util.function.Supplier;
import org.springframework.context.ApplicationEvent;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.core.Authentication;
/**
* An {@link ApplicationEvent} which indicates failed authorization.
*
* @author Parikshit Dutta
* @since 5.5
* @author Josh Cummings
* @since 5.7
*/
public class AuthorizationFailureEvent extends ApplicationEvent {
public class AuthorizationDeniedEvent<T> extends ApplicationEvent {
public AuthorizationFailureEvent(AuthorizationDecision authorizationDecision) {
super(authorizationDecision);
private final Supplier<Authentication> authentication;
private final AuthorizationDecision decision;
public AuthorizationDeniedEvent(Supplier<Authentication> authentication, T object, AuthorizationDecision decision) {
super(object);
this.authentication = authentication;
this.decision = decision;
}
public Supplier<Authentication> getAuthentication() {
return this.authentication;
}
public AuthorizationDecision getAuthorizationDecision() {
return this.decision;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* 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.
@ -16,19 +16,40 @@
package org.springframework.security.authorization.event;
import java.util.function.Supplier;
import org.springframework.context.ApplicationEvent;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.core.Authentication;
import org.springframework.util.Assert;
/**
* An {@link ApplicationEvent} which indicates successful authorization.
*
* @author Parikshit Dutta
* @since 5.5
* @author Josh Cummings
* @since 5.7
*/
public class AuthorizationSuccessEvent extends ApplicationEvent {
public class AuthorizationGrantedEvent<T> extends ApplicationEvent {
public AuthorizationSuccessEvent(AuthorizationDecision authorizationDecision) {
super(authorizationDecision);
private final Supplier<Authentication> authentication;
private final AuthorizationDecision decision;
public AuthorizationGrantedEvent(Supplier<Authentication> authentication, T object,
AuthorizationDecision decision) {
super(object);
Assert.notNull(authentication, "authentication supplier cannot be null");
this.authentication = authentication;
this.decision = decision;
}
public Supplier<Authentication> getAuthentication() {
return this.authentication;
}
public AuthorizationDecision getAuthorizationDecision() {
return this.decision;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* 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.
@ -33,6 +33,7 @@ import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.prepost.PostAuthorize;
import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.AuthorizationEventPublisher;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
@ -66,6 +67,8 @@ public final class AuthorizationManagerAfterMethodInterceptor
private int order;
private AuthorizationEventPublisher eventPublisher = AuthorizationManagerAfterMethodInterceptor::noPublish;
/**
* Creates an instance.
* @param pointcut the {@link Pointcut} to use
@ -122,6 +125,17 @@ public final class AuthorizationManagerAfterMethodInterceptor
this.order = order;
}
/**
* Use this {@link AuthorizationEventPublisher} to publish the
* {@link AuthorizationManager} result.
* @param eventPublisher
* @since 5.7
*/
public void setAuthorizationEventPublisher(AuthorizationEventPublisher eventPublisher) {
Assert.notNull(eventPublisher, "eventPublisher cannot be null");
this.eventPublisher = eventPublisher;
}
/**
* {@inheritDoc}
*/
@ -142,8 +156,9 @@ public final class AuthorizationManagerAfterMethodInterceptor
private void attemptAuthorization(MethodInvocation mi, Object result) {
this.logger.debug(LogMessage.of(() -> "Authorizing method invocation " + mi));
AuthorizationDecision decision = this.authorizationManager.check(AUTHENTICATION_SUPPLIER,
new MethodInvocationResult(mi, result));
MethodInvocationResult object = new MethodInvocationResult(mi, result);
AuthorizationDecision decision = this.authorizationManager.check(AUTHENTICATION_SUPPLIER, object);
this.eventPublisher.publishAuthorizationEvent(AUTHENTICATION_SUPPLIER, object, decision);
if (decision != null && !decision.isGranted()) {
this.logger.debug(LogMessage.of(() -> "Failed to authorize " + mi + " with authorization manager "
+ this.authorizationManager + " and decision " + decision));
@ -152,4 +167,9 @@ public final class AuthorizationManagerAfterMethodInterceptor
this.logger.debug(LogMessage.of(() -> "Authorized method invocation " + mi));
}
private static <T> void noPublish(Supplier<Authentication> authentication, T object,
AuthorizationDecision decision) {
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* 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.
@ -38,6 +38,7 @@ import org.springframework.security.access.annotation.Secured;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.AuthorizationEventPublisher;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
@ -71,6 +72,8 @@ public final class AuthorizationManagerBeforeMethodInterceptor
private int order = AuthorizationInterceptorsOrder.FIRST.getOrder();
private AuthorizationEventPublisher eventPublisher = AuthorizationManagerBeforeMethodInterceptor::noPublish;
/**
* Creates an instance.
* @param pointcut the {@link Pointcut} to use
@ -168,6 +171,17 @@ public final class AuthorizationManagerBeforeMethodInterceptor
this.order = order;
}
/**
* Use this {@link AuthorizationEventPublisher} to publish the
* {@link AuthorizationManager} result.
* @param eventPublisher
* @since 5.7
*/
public void setAuthorizationEventPublisher(AuthorizationEventPublisher eventPublisher) {
Assert.notNull(eventPublisher, "eventPublisher cannot be null");
this.eventPublisher = eventPublisher;
}
/**
* {@inheritDoc}
*/
@ -189,6 +203,7 @@ public final class AuthorizationManagerBeforeMethodInterceptor
private void attemptAuthorization(MethodInvocation mi) {
this.logger.debug(LogMessage.of(() -> "Authorizing method invocation " + mi));
AuthorizationDecision decision = this.authorizationManager.check(AUTHENTICATION_SUPPLIER, mi);
this.eventPublisher.publishAuthorizationEvent(AUTHENTICATION_SUPPLIER, mi, decision);
if (decision != null && !decision.isGranted()) {
this.logger.debug(LogMessage.of(() -> "Failed to authorize " + mi + " with authorization manager "
+ this.authorizationManager + " and decision " + decision));
@ -197,4 +212,9 @@ public final class AuthorizationManagerBeforeMethodInterceptor
this.logger.debug(LogMessage.of(() -> "Authorized method invocation " + mi));
}
private static <T> void noPublish(Supplier<Authentication> authentication, T object,
AuthorizationDecision decision) {
}
}

View File

@ -1,70 +0,0 @@
/*
* Copyright 2002-2021 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.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.security.authorization.event.AuthorizationFailureEvent;
import org.springframework.security.authorization.event.AuthorizationSuccessEvent;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.isA;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
/**
* Tests for {@link DefaultAuthorizationEventPublisher}
*
* @author Parikshit Dutta
*/
public class DefaultAuthorizationEventPublisherTests {
ApplicationEventPublisher applicationEventPublisher;
DefaultAuthorizationEventPublisher authorizationEventPublisher;
@BeforeEach
public void init() {
this.applicationEventPublisher = mock(ApplicationEventPublisher.class);
this.authorizationEventPublisher = new DefaultAuthorizationEventPublisher();
this.authorizationEventPublisher.setApplicationEventPublisher(this.applicationEventPublisher);
}
@Test
public void testAuthenticationSuccessIsPublished() {
this.authorizationEventPublisher.publishAuthorizationSuccess(mock(AuthorizationDecision.class));
verify(this.applicationEventPublisher).publishEvent(isA(AuthorizationSuccessEvent.class));
}
@Test
public void testAuthenticationFailureIsPublished() {
this.authorizationEventPublisher.publishAuthorizationFailure(mock(AuthorizationDecision.class));
verify(this.applicationEventPublisher).publishEvent(isA(AuthorizationFailureEvent.class));
}
@Test
public void testNullPublisherNotInvoked() {
this.authorizationEventPublisher.setApplicationEventPublisher(null);
this.authorizationEventPublisher.publishAuthorizationSuccess(mock(AuthorizationDecision.class));
this.authorizationEventPublisher.publishAuthorizationFailure(mock(AuthorizationDecision.class));
verify(this.applicationEventPublisher, never()).publishEvent(any());
}
}

View File

@ -0,0 +1,67 @@
/*
* 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.function.Supplier;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.security.authentication.TestAuthentication;
import org.springframework.security.authorization.event.AuthorizationDeniedEvent;
import org.springframework.security.core.Authentication;
import static org.mockito.ArgumentMatchers.isA;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions;
/**
* Tests for {@link SpringAuthorizationEventPublisher}
*
* @author Parikshit Dutta
*/
public class SpringAuthorizationEventPublisherTests {
Supplier<Authentication> authentication = () -> TestAuthentication.authenticatedUser();
ApplicationEventPublisher applicationEventPublisher;
SpringAuthorizationEventPublisher authorizationEventPublisher;
@BeforeEach
public void init() {
this.applicationEventPublisher = mock(ApplicationEventPublisher.class);
this.authorizationEventPublisher = new SpringAuthorizationEventPublisher(this.applicationEventPublisher);
}
@Test
public void testAuthenticationSuccessIsNotPublished() {
AuthorizationDecision decision = new AuthorizationDecision(true);
this.authorizationEventPublisher.publishAuthorizationEvent(this.authentication, mock(Object.class), decision);
verifyNoInteractions(this.applicationEventPublisher);
}
@Test
public void testAuthenticationFailureIsPublished() {
AuthorizationDecision decision = new AuthorizationDecision(false);
this.authorizationEventPublisher.publishAuthorizationEvent(this.authentication, mock(Object.class), decision);
verify(this.applicationEventPublisher).publishEvent(isA(AuthorizationDeniedEvent.class));
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* 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.
@ -16,11 +16,20 @@
package org.springframework.security.authorization.method;
import java.util.function.Supplier;
import org.aopalliance.intercept.MethodInvocation;
import org.junit.jupiter.api.Test;
import org.springframework.aop.Pointcut;
import org.springframework.security.authentication.TestingAuthenticationToken;
import org.springframework.security.authorization.AuthenticatedAuthorizationManager;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.AuthorizationEventPublisher;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.context.SecurityContextImpl;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
@ -66,4 +75,32 @@ public class AuthorizationManagerAfterMethodInterceptorTests {
any(MethodInvocationResult.class));
}
@Test
public void configureWhenAuthorizationEventPublisherIsNullThenIllegalArgument() {
AuthorizationManagerAfterMethodInterceptor advice = new AuthorizationManagerAfterMethodInterceptor(
Pointcut.TRUE, AuthenticatedAuthorizationManager.authenticated());
assertThatIllegalArgumentException().isThrownBy(() -> advice.setAuthorizationEventPublisher(null))
.withMessage("eventPublisher cannot be null");
}
@Test
public void invokeWhenAuthorizationEventPublisherThenUses() throws Throwable {
AuthorizationManagerAfterMethodInterceptor advice = new AuthorizationManagerAfterMethodInterceptor(
Pointcut.TRUE, AuthenticatedAuthorizationManager.authenticated());
AuthorizationEventPublisher eventPublisher = mock(AuthorizationEventPublisher.class);
advice.setAuthorizationEventPublisher(eventPublisher);
SecurityContext securityContext = new SecurityContextImpl();
securityContext.setAuthentication(new TestingAuthenticationToken("user", "password", "ROLE_USER"));
SecurityContextHolder.setContext(securityContext);
MethodInvocation mockMethodInvocation = mock(MethodInvocation.class);
MethodInvocationResult result = new MethodInvocationResult(mockMethodInvocation, new Object());
given(mockMethodInvocation.proceed()).willReturn(result.getResult());
advice.invoke(mockMethodInvocation);
verify(eventPublisher).publishAuthorizationEvent(any(Supplier.class), any(MethodInvocationResult.class),
any(AuthorizationDecision.class));
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* 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.
@ -16,13 +16,24 @@
package org.springframework.security.authorization.method;
import java.util.function.Supplier;
import org.aopalliance.intercept.MethodInvocation;
import org.junit.jupiter.api.Test;
import org.springframework.aop.Pointcut;
import org.springframework.security.authentication.TestingAuthenticationToken;
import org.springframework.security.authorization.AuthenticatedAuthorizationManager;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.AuthorizationEventPublisher;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.context.SecurityContextImpl;
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;
@ -59,4 +70,32 @@ public class AuthorizationManagerBeforeMethodInterceptorTests {
mockMethodInvocation);
}
@Test
public void configureWhenAuthorizationEventPublisherIsNullThenIllegalArgument() {
AuthorizationManagerBeforeMethodInterceptor advice = new AuthorizationManagerBeforeMethodInterceptor(
Pointcut.TRUE, AuthenticatedAuthorizationManager.authenticated());
assertThatIllegalArgumentException().isThrownBy(() -> advice.setAuthorizationEventPublisher(null))
.withMessage("eventPublisher cannot be null");
}
@Test
public void invokeWhenAuthorizationEventPublisherThenUses() throws Throwable {
AuthorizationManagerBeforeMethodInterceptor advice = new AuthorizationManagerBeforeMethodInterceptor(
Pointcut.TRUE, AuthenticatedAuthorizationManager.authenticated());
AuthorizationEventPublisher eventPublisher = mock(AuthorizationEventPublisher.class);
advice.setAuthorizationEventPublisher(eventPublisher);
SecurityContext securityContext = new SecurityContextImpl();
securityContext.setAuthentication(new TestingAuthenticationToken("user", "password", "ROLE_USER"));
SecurityContextHolder.setContext(securityContext);
MethodInvocation mockMethodInvocation = mock(MethodInvocation.class);
MethodInvocationResult result = new MethodInvocationResult(mockMethodInvocation, new Object());
given(mockMethodInvocation.proceed()).willReturn(result.getResult());
advice.invoke(mockMethodInvocation);
verify(eventPublisher).publishAuthorizationEvent(any(Supplier.class), any(MethodInvocation.class),
any(AuthorizationDecision.class));
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* 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.
@ -17,14 +17,21 @@
package org.springframework.security.web.access.intercept;
import java.io.IOException;
import java.util.function.Supplier;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.AuthorizationEventPublisher;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.authorization.event.AuthorizationDeniedEvent;
import org.springframework.security.authorization.event.AuthorizationGrantedEvent;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.util.Assert;
@ -41,6 +48,8 @@ public class AuthorizationFilter extends OncePerRequestFilter {
private final AuthorizationManager<HttpServletRequest> authorizationManager;
private AuthorizationEventPublisher eventPublisher = AuthorizationFilter::noPublish;
/**
* Creates an instance.
* @param authorizationManager the {@link AuthorizationManager} to use
@ -54,7 +63,11 @@ public class AuthorizationFilter extends OncePerRequestFilter {
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
this.authorizationManager.verify(this::getAuthentication, request);
AuthorizationDecision decision = this.authorizationManager.check(this::getAuthentication, request);
this.eventPublisher.publishAuthorizationEvent(this::getAuthentication, request, decision);
if (decision != null && !decision.isGranted()) {
throw new AccessDeniedException("Access Denied");
}
filterChain.doFilter(request, response);
}
@ -67,6 +80,17 @@ public class AuthorizationFilter extends OncePerRequestFilter {
return authentication;
}
/**
* Use this {@link AuthorizationEventPublisher} to publish
* {@link AuthorizationDeniedEvent}s and {@link AuthorizationGrantedEvent}s.
* @param eventPublisher the {@link ApplicationEventPublisher} to use
* @since 5.7
*/
public void setAuthorizationEventPublisher(AuthorizationEventPublisher eventPublisher) {
Assert.notNull(eventPublisher, "eventPublisher cannot be null");
this.eventPublisher = eventPublisher;
}
/**
* Gets the {@link AuthorizationManager} used by this filter
* @return the {@link AuthorizationManager}
@ -75,4 +99,9 @@ public class AuthorizationFilter extends OncePerRequestFilter {
return this.authorizationManager;
}
private static <T> void noPublish(Supplier<Authentication> authentication, T object,
AuthorizationDecision decision) {
}
}

View File

@ -28,7 +28,6 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.core.log.LogMessage;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.AuthorizationEventPublisher;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.util.matcher.RequestMatcher;
@ -49,8 +48,6 @@ public final class RequestMatcherDelegatingAuthorizationManager implements Autho
private final Map<RequestMatcher, AuthorizationManager<RequestAuthorizationContext>> mappings;
private AuthorizationEventPublisher authorizationEventPublisher;
private RequestMatcherDelegatingAuthorizationManager(
Map<RequestMatcher, AuthorizationManager<RequestAuthorizationContext>> mappings) {
Assert.notEmpty(mappings, "mappings cannot be empty");
@ -81,36 +78,14 @@ public final class RequestMatcherDelegatingAuthorizationManager implements Autho
if (this.logger.isTraceEnabled()) {
this.logger.trace(LogMessage.format("Checking authorization on %s using %s", request, manager));
}
AuthorizationDecision authorizationDecision = manager.check(authentication,
return manager.check(authentication,
new RequestAuthorizationContext(request, matchResult.getVariables()));
publishAuthorizationEvent(authorizationDecision);
return authorizationDecision;
}
}
this.logger.trace("Abstaining since did not find matching RequestMatcher");
return null;
}
private void publishAuthorizationEvent(AuthorizationDecision authorizationDecision) {
if (this.authorizationEventPublisher != null) {
if (authorizationDecision.isGranted()) {
this.authorizationEventPublisher.publishAuthorizationSuccess(authorizationDecision);
}
else {
this.authorizationEventPublisher.publishAuthorizationFailure(authorizationDecision);
}
}
}
/**
* Set implementation of an {@link AuthorizationEventPublisher}
* @param authorizationEventPublisher
*/
public void setAuthorizationEventPublisher(AuthorizationEventPublisher authorizationEventPublisher) {
Assert.notNull(authorizationEventPublisher, "AuthorizationEventPublisher cannot be null");
this.authorizationEventPublisher = authorizationEventPublisher;
}
/**
* Creates a builder for {@link RequestMatcherDelegatingAuthorizationManager}.
* @return the new {@link Builder} instance

View File

@ -31,6 +31,8 @@ import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
import org.springframework.security.authentication.TestingAuthenticationToken;
import org.springframework.security.authorization.AuthenticatedAuthorizationManager;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.AuthorizationEventPublisher;
import org.springframework.security.authorization.AuthorizationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
@ -39,8 +41,10 @@ import org.springframework.security.core.context.SecurityContextImpl;
import static org.assertj.core.api.Assertions.assertThat;
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.ArgumentMatchers.eq;
import static org.mockito.BDDMockito.given;
import static org.mockito.BDDMockito.willThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
@ -61,6 +65,8 @@ public class AuthorizationFilterTests {
@Test
public void filterWhenAuthorizationManagerVerifyPassesThenNextFilter() throws Exception {
AuthorizationManager<HttpServletRequest> mockAuthorizationManager = mock(AuthorizationManager.class);
given(mockAuthorizationManager.check(any(Supplier.class), any(HttpServletRequest.class)))
.willReturn(new AuthorizationDecision(true));
AuthorizationFilter filter = new AuthorizationFilter(mockAuthorizationManager);
TestingAuthenticationToken authenticationToken = new TestingAuthenticationToken("user", "password");
@ -75,7 +81,7 @@ public class AuthorizationFilterTests {
filter.doFilter(mockRequest, mockResponse, mockFilterChain);
ArgumentCaptor<Supplier<Authentication>> authenticationCaptor = ArgumentCaptor.forClass(Supplier.class);
verify(mockAuthorizationManager).verify(authenticationCaptor.capture(), eq(mockRequest));
verify(mockAuthorizationManager).check(authenticationCaptor.capture(), eq(mockRequest));
Supplier<Authentication> authentication = authenticationCaptor.getValue();
assertThat(authentication.get()).isEqualTo(authenticationToken);
@ -96,7 +102,7 @@ public class AuthorizationFilterTests {
MockHttpServletResponse mockResponse = new MockHttpServletResponse();
FilterChain mockFilterChain = mock(FilterChain.class);
willThrow(new AccessDeniedException("Access Denied")).given(mockAuthorizationManager).verify(any(),
willThrow(new AccessDeniedException("Access Denied")).given(mockAuthorizationManager).check(any(),
eq(mockRequest));
assertThatExceptionOfType(AccessDeniedException.class)
@ -104,7 +110,7 @@ public class AuthorizationFilterTests {
.withMessage("Access Denied");
ArgumentCaptor<Supplier<Authentication>> authenticationCaptor = ArgumentCaptor.forClass(Supplier.class);
verify(mockAuthorizationManager).verify(authenticationCaptor.capture(), eq(mockRequest));
verify(mockAuthorizationManager).check(authenticationCaptor.capture(), eq(mockRequest));
Supplier<Authentication> authentication = authenticationCaptor.getValue();
assertThat(authentication.get()).isEqualTo(authenticationToken);
@ -132,4 +138,31 @@ public class AuthorizationFilterTests {
assertThat(authorizationFilter.getAuthorizationManager()).isSameAs(authorizationManager);
}
@Test
public void configureWhenAuthorizationEventPublisherIsNullThenIllegalArgument() {
AuthorizationManager<HttpServletRequest> authorizationManager = mock(AuthorizationManager.class);
AuthorizationFilter authorizationFilter = new AuthorizationFilter(authorizationManager);
assertThatIllegalArgumentException().isThrownBy(() -> authorizationFilter.setAuthorizationEventPublisher(null))
.withMessage("eventPublisher cannot be null");
}
@Test
public void doFilterWhenAuthorizationEventPublisherThenUses() throws Exception {
AuthorizationFilter authorizationFilter = new AuthorizationFilter(
AuthenticatedAuthorizationManager.authenticated());
MockHttpServletRequest mockRequest = new MockHttpServletRequest(null, "/path");
MockHttpServletResponse mockResponse = new MockHttpServletResponse();
FilterChain mockFilterChain = mock(FilterChain.class);
SecurityContext securityContext = new SecurityContextImpl();
securityContext.setAuthentication(new TestingAuthenticationToken("user", "password", "ROLE_USER"));
SecurityContextHolder.setContext(securityContext);
AuthorizationEventPublisher eventPublisher = mock(AuthorizationEventPublisher.class);
authorizationFilter.setAuthorizationEventPublisher(eventPublisher);
authorizationFilter.doFilter(mockRequest, mockResponse, mockFilterChain);
verify(eventPublisher).publishAuthorizationEvent(any(Supplier.class), any(HttpServletRequest.class),
any(AuthorizationDecision.class));
}
}

View File

@ -24,15 +24,12 @@ 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.AuthorizationEventPublisher;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher;
import org.springframework.security.web.util.matcher.AnyRequestMatcher;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
/**
* Tests for {@link RequestMatcherDelegatingAuthorizationManager}.
@ -126,40 +123,4 @@ public class RequestMatcherDelegatingAuthorizationManagerTests {
.withMessage("mappingsConsumer cannot be null");
}
@Test
public void testAuthorizationEventPublisherIsNotNull() {
RequestMatcherDelegatingAuthorizationManager manager = RequestMatcherDelegatingAuthorizationManager.builder()
.add(new MvcRequestMatcher(null, "/grant"), (a, o) -> new AuthorizationDecision(true)).build();
assertThatIllegalArgumentException().isThrownBy(() -> manager.setAuthorizationEventPublisher(null))
.withMessage("AuthorizationEventPublisher cannot be null");
}
@Test
public void testAuthorizationSuccessEventWhenAuthorizationGranted() {
RequestMatcherDelegatingAuthorizationManager manager = RequestMatcherDelegatingAuthorizationManager.builder()
.add(new MvcRequestMatcher(null, "/grant"), (a, o) -> new AuthorizationDecision(true)).build();
AuthorizationEventPublisher authorizationEventPublisher = mock(AuthorizationEventPublisher.class);
manager.setAuthorizationEventPublisher(authorizationEventPublisher);
Supplier<Authentication> authentication = () -> new TestingAuthenticationToken("user", "password", "ROLE_USER");
AuthorizationDecision grant = manager.check(authentication, new MockHttpServletRequest(null, "/grant"));
verify(authorizationEventPublisher).publishAuthorizationSuccess(grant);
}
@Test
public void testAuthorizationFailureEventWhenAuthorizationNotGranted() {
RequestMatcherDelegatingAuthorizationManager manager = RequestMatcherDelegatingAuthorizationManager.builder()
.add(new MvcRequestMatcher(null, "/deny"), (a, o) -> new AuthorizationDecision(false)).build();
AuthorizationEventPublisher authorizationEventPublisher = mock(AuthorizationEventPublisher.class);
manager.setAuthorizationEventPublisher(authorizationEventPublisher);
Supplier<Authentication> authentication = () -> new TestingAuthenticationToken("user", "password", "ROLE_USER");
AuthorizationDecision grant = manager.check(authentication, new MockHttpServletRequest(null, "/deny"));
verify(authorizationEventPublisher).publishAuthorizationFailure(grant);
}
}