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
19 changed files with 498 additions and 239 deletions

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));
}
}