SEC-1697: Don't publish authorization success events in AbstractSecurityInterceptor by default.
This commit is contained in:
parent
74b0c1780e
commit
01c9c4e4db
|
@ -109,6 +109,7 @@ public abstract class AbstractSecurityInterceptor implements InitializingBean, A
|
||||||
private boolean alwaysReauthenticate = false;
|
private boolean alwaysReauthenticate = false;
|
||||||
private boolean rejectPublicInvocations = false;
|
private boolean rejectPublicInvocations = false;
|
||||||
private boolean validateConfigAttributes = true;
|
private boolean validateConfigAttributes = true;
|
||||||
|
private boolean publishAuthorizationSuccess = false;
|
||||||
|
|
||||||
//~ Methods ========================================================================================================
|
//~ Methods ========================================================================================================
|
||||||
|
|
||||||
|
@ -212,7 +213,9 @@ public abstract class AbstractSecurityInterceptor implements InitializingBean, A
|
||||||
logger.debug("Authorization successful");
|
logger.debug("Authorization successful");
|
||||||
}
|
}
|
||||||
|
|
||||||
publishEvent(new AuthorizedEvent(object, attributes, authenticated));
|
if (publishAuthorizationSuccess) {
|
||||||
|
publishEvent(new AuthorizedEvent(object, attributes, authenticated));
|
||||||
|
}
|
||||||
|
|
||||||
// Attempt to run as a different user
|
// Attempt to run as a different user
|
||||||
Authentication runAs = this.runAsManager.buildRunAs(authenticated, object, attributes);
|
Authentication runAs = this.runAsManager.buildRunAs(authenticated, object, attributes);
|
||||||
|
@ -402,6 +405,16 @@ public abstract class AbstractSecurityInterceptor implements InitializingBean, A
|
||||||
this.messages = new MessageSourceAccessor(messageSource);
|
this.messages = new MessageSourceAccessor(messageSource);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Only {@code AuthorizationFailureEvent} will be published.
|
||||||
|
* If you set this property to {@code true}, {@code AuthorizedEvent}s will also be published.
|
||||||
|
*
|
||||||
|
* @param publishAuthorizationSuccess default value is {@code false}
|
||||||
|
*/
|
||||||
|
public void setPublishAuthorizationSuccess(boolean publishAuthorizationSuccess) {
|
||||||
|
this.publishAuthorizationSuccess = publishAuthorizationSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* By rejecting public invocations (and setting this property to <tt>true</tt>), essentially you are ensuring
|
* By rejecting public invocations (and setting this property to <tt>true</tt>), essentially you are ensuring
|
||||||
* that every secure object invocation advised by <code>AbstractSecurityInterceptor</code> has a configuration
|
* that every secure object invocation advised by <code>AbstractSecurityInterceptor</code> has a configuration
|
||||||
|
|
|
@ -26,12 +26,15 @@ import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.springframework.aop.framework.ProxyFactory;
|
import org.springframework.aop.framework.ProxyFactory;
|
||||||
|
import org.springframework.context.ApplicationEventPublisher;
|
||||||
import org.springframework.security.ITargetObject;
|
import org.springframework.security.ITargetObject;
|
||||||
import org.springframework.security.TargetObject;
|
import org.springframework.security.TargetObject;
|
||||||
import org.springframework.security.access.AccessDecisionManager;
|
import org.springframework.security.access.AccessDecisionManager;
|
||||||
import org.springframework.security.access.AccessDeniedException;
|
import org.springframework.security.access.AccessDeniedException;
|
||||||
import org.springframework.security.access.ConfigAttribute;
|
import org.springframework.security.access.ConfigAttribute;
|
||||||
import org.springframework.security.access.SecurityConfig;
|
import org.springframework.security.access.SecurityConfig;
|
||||||
|
import org.springframework.security.access.event.AuthorizationFailureEvent;
|
||||||
|
import org.springframework.security.access.event.AuthorizedEvent;
|
||||||
import org.springframework.security.access.intercept.AfterInvocationManager;
|
import org.springframework.security.access.intercept.AfterInvocationManager;
|
||||||
import org.springframework.security.access.intercept.RunAsManager;
|
import org.springframework.security.access.intercept.RunAsManager;
|
||||||
import org.springframework.security.access.intercept.RunAsUserToken;
|
import org.springframework.security.access.intercept.RunAsUserToken;
|
||||||
|
@ -58,6 +61,7 @@ public class MethodSecurityInterceptorTests {
|
||||||
private AccessDecisionManager adm;
|
private AccessDecisionManager adm;
|
||||||
private MethodSecurityMetadataSource mds;
|
private MethodSecurityMetadataSource mds;
|
||||||
private AuthenticationManager authman;
|
private AuthenticationManager authman;
|
||||||
|
private ApplicationEventPublisher eventPublisher;
|
||||||
|
|
||||||
//~ Methods ========================================================================================================
|
//~ Methods ========================================================================================================
|
||||||
|
|
||||||
|
@ -69,9 +73,11 @@ public class MethodSecurityInterceptorTests {
|
||||||
adm = mock(AccessDecisionManager.class);
|
adm = mock(AccessDecisionManager.class);
|
||||||
authman = mock(AuthenticationManager.class);
|
authman = mock(AuthenticationManager.class);
|
||||||
mds = mock(MethodSecurityMetadataSource.class);
|
mds = mock(MethodSecurityMetadataSource.class);
|
||||||
|
eventPublisher = mock(ApplicationEventPublisher.class);
|
||||||
interceptor.setAccessDecisionManager(adm);
|
interceptor.setAccessDecisionManager(adm);
|
||||||
interceptor.setAuthenticationManager(authman);
|
interceptor.setAuthenticationManager(authman);
|
||||||
interceptor.setSecurityMetadataSource(mds);
|
interceptor.setSecurityMetadataSource(mds);
|
||||||
|
interceptor.setApplicationEventPublisher(eventPublisher);
|
||||||
createTarget(false);
|
createTarget(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -210,6 +216,7 @@ public class MethodSecurityInterceptorTests {
|
||||||
@Test
|
@Test
|
||||||
public void callSucceedsIfAccessDecisionManagerGrantsAccess() throws Exception {
|
public void callSucceedsIfAccessDecisionManagerGrantsAccess() throws Exception {
|
||||||
token.setAuthenticated(true);
|
token.setAuthenticated(true);
|
||||||
|
interceptor.setPublishAuthorizationSuccess(true);
|
||||||
SecurityContextHolder.getContext().setAuthentication(token);
|
SecurityContextHolder.getContext().setAuthentication(token);
|
||||||
mdsReturnsUserRole();
|
mdsReturnsUserRole();
|
||||||
|
|
||||||
|
@ -217,9 +224,10 @@ public class MethodSecurityInterceptorTests {
|
||||||
|
|
||||||
// Note we check the isAuthenticated remained true in following line
|
// Note we check the isAuthenticated remained true in following line
|
||||||
assertEquals("hello org.springframework.security.authentication.TestingAuthenticationToken true", result);
|
assertEquals("hello org.springframework.security.authentication.TestingAuthenticationToken true", result);
|
||||||
|
verify(eventPublisher).publishEvent(any(AuthorizedEvent.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected=AccessDeniedException.class)
|
@Test
|
||||||
public void callIsntMadeWhenAccessDecisionManagerRejectsAccess() throws Exception {
|
public void callIsntMadeWhenAccessDecisionManagerRejectsAccess() throws Exception {
|
||||||
SecurityContextHolder.getContext().setAuthentication(token);
|
SecurityContextHolder.getContext().setAuthentication(token);
|
||||||
// Use mocked target to make sure invocation doesn't happen (not in expectations so test would fail)
|
// Use mocked target to make sure invocation doesn't happen (not in expectations so test would fail)
|
||||||
|
@ -228,7 +236,12 @@ public class MethodSecurityInterceptorTests {
|
||||||
when(authman.authenticate(token)).thenReturn(token);
|
when(authman.authenticate(token)).thenReturn(token);
|
||||||
doThrow(new AccessDeniedException("rejected")).when(adm).decide(any(Authentication.class), any(MethodInvocation.class), any(List.class));
|
doThrow(new AccessDeniedException("rejected")).when(adm).decide(any(Authentication.class), any(MethodInvocation.class), any(List.class));
|
||||||
|
|
||||||
advisedTarget.makeUpperCase("HELLO");
|
try {
|
||||||
|
advisedTarget.makeUpperCase("HELLO");
|
||||||
|
fail();
|
||||||
|
} catch (AccessDeniedException expected) {
|
||||||
|
}
|
||||||
|
verify(eventPublisher).publishEvent(any(AuthorizationFailureEvent.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected=IllegalArgumentException.class)
|
@Test(expected=IllegalArgumentException.class)
|
||||||
|
|
|
@ -105,7 +105,8 @@ public class FilterSecurityInterceptorTests {
|
||||||
|
|
||||||
interceptor.invoke(fi);
|
interceptor.invoke(fi);
|
||||||
|
|
||||||
verify(publisher).publishEvent(any(AuthorizedEvent.class));
|
// SEC-1697
|
||||||
|
verify(publisher, never()).publishEvent(any(AuthorizedEvent.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
Loading…
Reference in New Issue