SEC-1697: Don't publish authorization success events in AbstractSecurityInterceptor by default.

This commit is contained in:
Luke Taylor 2011-04-06 13:54:32 +01:00
parent 74b0c1780e
commit 01c9c4e4db
3 changed files with 31 additions and 4 deletions

View File

@ -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

View File

@ -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)

View File

@ -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