2
0
Эх сурвалжийг харах

SEC-1522: Treat empty attribute collection the same as null when returned by SecurityMetadataSource. Both are now treated as public invocations.

Luke Taylor 15 жил өмнө
parent
commit
b854e67952

+ 8 - 9
core/src/main/java/org/springframework/security/access/SecurityMetadataSource.java

@@ -31,13 +31,12 @@ public interface SecurityMetadataSource extends AopInfrastructureBean {
     //~ Methods ========================================================================================================
 
     /**
-     * Accesses the <code>ConfigAttribute</code>s that apply to a given secure object.
-     * <p>
-     * Returns <code>null</code> if no attributes apply.
+     * Accesses the {@code ConfigAttribute}s that apply to a given secure object.
      *
      * @param object the object being secured
      *
-     * @return the attributes that apply to the passed in secured object or null if there are no applicable attributes.
+     * @return the attributes that apply to the passed in secured object. Can return either {@code null} or an
+     *         empty collection if there are no applicable attributes.
      *
      * @throws IllegalArgumentException if the passed object is not of a type supported by the
      *         <code>SecurityMetadataSource</code> implementation
@@ -45,18 +44,18 @@ public interface SecurityMetadataSource extends AopInfrastructureBean {
     Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException;
 
     /**
-     * If available, returns all of the <code>ConfigAttribute</code>s defined by the implementing class.
+     * If available, returns all of the {@code ConfigAttribute}s defined by the implementing class.
      * <p>
      * This is used by the {@link AbstractSecurityInterceptor} to perform startup time validation of each
-     * <code>ConfigAttribute</code> configured against it.
+     * {@code ConfigAttribute} configured against it.
      *
-     * @return the <code>ConfigAttribute</code>s or <code>null</code> if unsupported
+     * @return the {@code ConfigAttribute}s or {@code null} if unsupported
      */
     Collection<ConfigAttribute> getAllConfigAttributes();
 
     /**
-     * Indicates whether the <code>SecurityMetadataSource</code> implementation is able to provide
-     * <code>ConfigAttribute</code>s for the indicated secure object type.
+     * Indicates whether the {@code SecurityMetadataSource} implementation is able to provide
+     * {@code ConfigAttribute}s for the indicated secure object type.
      *
      * @param clazz the class that is being queried
      *

+ 7 - 8
core/src/main/java/org/springframework/security/access/intercept/AbstractSecurityInterceptor.java

@@ -170,7 +170,7 @@ public abstract class AbstractSecurityInterceptor implements InitializingBean, A
 
         Collection<ConfigAttribute> attributes = this.obtainSecurityMetadataSource().getAttributes(object);
 
-        if (attributes == null) {
+        if (attributes == null || attributes.isEmpty()) {
             if (rejectPublicInvocations) {
                 throw new IllegalArgumentException("Secure object invocation " + object +
                         " was denied as public invocations are not allowed via this interceptor. "
@@ -203,8 +203,7 @@ public abstract class AbstractSecurityInterceptor implements InitializingBean, A
             this.accessDecisionManager.decide(authenticated, object, attributes);
         }
         catch (AccessDeniedException accessDeniedException) {
-            publishEvent(new AuthorizationFailureEvent(object, attributes, authenticated,
-                    accessDeniedException));
+            publishEvent(new AuthorizationFailureEvent(object, attributes, authenticated, accessDeniedException));
 
             throw accessDeniedException;
         }
@@ -266,8 +265,8 @@ public abstract class AbstractSecurityInterceptor implements InitializingBean, A
                         token.getAttributes(), returnedObject);
             }
             catch (AccessDeniedException accessDeniedException) {
-                AuthorizationFailureEvent event = new AuthorizationFailureEvent(token.getSecureObject(), token
-                        .getAttributes(), token.getAuthentication(), accessDeniedException);
+                AuthorizationFailureEvent event = new AuthorizationFailureEvent(token.getSecureObject(),
+                        token.getAttributes(), token.getAuthentication(), accessDeniedException);
                 publishEvent(event);
 
                 throw accessDeniedException;
@@ -310,7 +309,7 @@ public abstract class AbstractSecurityInterceptor implements InitializingBean, A
     /**
      * Helper method which generates an exception containing the passed reason,
      * and publishes an event to the application context.
-     * <p/>
+     * <p>
      * Always throws an exception.
      *
      * @param reason        to be provided in the exception detail
@@ -346,12 +345,12 @@ public abstract class AbstractSecurityInterceptor implements InitializingBean, A
     /**
      * Indicates the type of secure objects the subclass will be presenting to
      * the abstract parent for processing. This is used to ensure collaborators
-     * wired to the <code>AbstractSecurityInterceptor</code> all support the
+     * wired to the {@code AbstractSecurityInterceptor} all support the
      * indicated secure object class.
      *
      * @return the type of secure object the subclass provides services for
      */
-    public abstract Class<? extends Object> getSecureObjectClass();
+    public abstract Class<?> getSecureObjectClass();
 
     public boolean isAlwaysReauthenticate() {
         return alwaysReauthenticate;

+ 16 - 26
core/src/test/java/org/springframework/security/access/intercept/AbstractSecurityInterceptorTests.java

@@ -15,54 +15,44 @@
 
 package org.springframework.security.access.intercept;
 
-import org.jmock.Expectations;
-import org.jmock.Mockery;
-import org.jmock.integration.junit4.JUnit4Mockery;
+import static org.mockito.Mockito.mock;
+
 import org.junit.Test;
 import org.springframework.security.access.AccessDecisionManager;
 import org.springframework.security.access.SecurityMetadataSource;
-import org.springframework.security.access.intercept.AbstractSecurityInterceptor;
-import org.springframework.security.access.intercept.RunAsManager;
 import org.springframework.security.authentication.AuthenticationManager;
 import org.springframework.security.util.SimpleMethodInvocation;
 
 
 /**
- * Tests some {@link AbstractSecurityInterceptor} methods. Most of the  testing for this class is found in the
- * <code>MethodSecurityInterceptorTests</code> class.
+ * Tests some {@link AbstractSecurityInterceptor} methods. Most of the testing for this class is found in the
+ * {@code MethodSecurityInterceptorTests} class.
  *
  * @author Ben Alex
  */
 public class AbstractSecurityInterceptorTests {
-    private Mockery jmock = new JUnit4Mockery();
-
     //~ Methods ========================================================================================================
 
     @Test(expected=IllegalArgumentException.class)
     public void detectsIfInvocationPassedIncompatibleSecureObject() throws Exception {
         MockSecurityInterceptorWhichOnlySupportsStrings si = new MockSecurityInterceptorWhichOnlySupportsStrings();
 
-        si.setRunAsManager(jmock.mock(RunAsManager.class));
-        si.setAuthenticationManager(jmock.mock(AuthenticationManager.class));
-        si.setAfterInvocationManager(jmock.mock(AfterInvocationManager.class));
-        si.setAccessDecisionManager(jmock.mock(AccessDecisionManager.class));
-        si.setSecurityMetadataSource(jmock.mock(SecurityMetadataSource.class));
-
-        jmock.checking(new Expectations() {{ ignoring(anything()); }});
+        si.setRunAsManager(mock(RunAsManager.class));
+        si.setAuthenticationManager(mock(AuthenticationManager.class));
+        si.setAfterInvocationManager(mock(AfterInvocationManager.class));
+        si.setAccessDecisionManager(mock(AccessDecisionManager.class));
+        si.setSecurityMetadataSource(mock(SecurityMetadataSource.class));
         si.beforeInvocation(new SimpleMethodInvocation());
     }
 
     @Test(expected=IllegalArgumentException.class)
     public void detectsViolationOfGetSecureObjectClassMethod() throws Exception {
         MockSecurityInterceptorReturnsNull si = new MockSecurityInterceptorReturnsNull();
-        si.setRunAsManager(jmock.mock(RunAsManager.class));
-        si.setAuthenticationManager(jmock.mock(AuthenticationManager.class));
-        si.setAfterInvocationManager(jmock.mock(AfterInvocationManager.class));
-        si.setAccessDecisionManager(jmock.mock(AccessDecisionManager.class));
-        si.setSecurityMetadataSource(jmock.mock(SecurityMetadataSource.class));
-
-        jmock.checking(new Expectations() {{ ignoring(anything()); }});
-
+        si.setRunAsManager(mock(RunAsManager.class));
+        si.setAuthenticationManager(mock(AuthenticationManager.class));
+        si.setAfterInvocationManager(mock(AfterInvocationManager.class));
+        si.setAccessDecisionManager(mock(AccessDecisionManager.class));
+        si.setSecurityMetadataSource(mock(SecurityMetadataSource.class));
         si.afterPropertiesSet();
     }
 
@@ -71,7 +61,7 @@ public class AbstractSecurityInterceptorTests {
     private class MockSecurityInterceptorReturnsNull extends AbstractSecurityInterceptor {
         private SecurityMetadataSource securityMetadataSource;
 
-        public Class<? extends Object> getSecureObjectClass() {
+        public Class<?> getSecureObjectClass() {
             return null;
         }
 
@@ -87,7 +77,7 @@ public class AbstractSecurityInterceptorTests {
     private class MockSecurityInterceptorWhichOnlySupportsStrings extends AbstractSecurityInterceptor {
         private SecurityMetadataSource securityMetadataSource;
 
-        public Class<? extends Object> getSecureObjectClass() {
+        public Class<?> getSecureObjectClass() {
             return String.class;
         }