diff --git a/core/src/main/java/org/acegisecurity/acl/basic/cache/EhCacheBasedAclEntryCache.java b/core/src/main/java/org/acegisecurity/acl/basic/cache/EhCacheBasedAclEntryCache.java index 3b21bc2ac8..4fd8d96b9f 100644 --- a/core/src/main/java/org/acegisecurity/acl/basic/cache/EhCacheBasedAclEntryCache.java +++ b/core/src/main/java/org/acegisecurity/acl/basic/cache/EhCacheBasedAclEntryCache.java @@ -21,40 +21,43 @@ import net.sf.acegisecurity.acl.basic.BasicAclEntryCache; import net.sf.ehcache.Cache; import net.sf.ehcache.CacheException; -import net.sf.ehcache.CacheManager; import net.sf.ehcache.Element; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.dao.DataRetrievalFailureException; /** - * Caches BasicAclEntrys using BasicAclEntrys using a Spring IoC defined EHCACHE. * * @author Ben Alex * @version $Id$ */ public class EhCacheBasedAclEntryCache implements BasicAclEntryCache, - InitializingBean, DisposableBean { + InitializingBean { //~ Static fields/initializers ============================================= private static final Log logger = LogFactory.getLog(EhCacheBasedAclEntryCache.class); - private static final String CACHE_NAME = "ehCacheBasedAclEntryCache"; //~ Instance fields ======================================================== private Cache cache; - private CacheManager manager; - private int minutesToIdle = 5; //~ Methods ================================================================ + public void setCache(Cache cache) { + this.cache = cache; + } + + public Cache getCache() { + return cache; + } + public BasicAclEntry[] getEntriesFromCache( AclObjectIdentity aclObjectIdentity) { Element element = null; @@ -85,43 +88,12 @@ public class EhCacheBasedAclEntryCache implements BasicAclEntryCache, return holder.getBasicAclEntries(); } - public void setMinutesToIdle(int minutesToIdle) { - this.minutesToIdle = minutesToIdle; - } - - /** - * Specifies how many minutes an entry will remain in the cache from when - * it was last accessed. - * - *

- * Defaults to 5 minutes. - *

- * - * @return Returns the minutes an element remains in the cache - */ - public int getMinutesToIdle() { - return minutesToIdle; - } - public void afterPropertiesSet() throws Exception { - if (CacheManager.getInstance().cacheExists(CACHE_NAME)) { - // don’t remove the cache - cache = CacheManager.getInstance().getCache(CACHE_NAME); - } else { - manager = CacheManager.create(); - - // Cache name, max memory, overflowToDisk, eternal, timeToLive, timeToIdle - cache = new Cache(CACHE_NAME, Integer.MAX_VALUE, false, false, - minutesToIdle * 60, minutesToIdle * 60); - - manager.addCache(cache); + if (cache == null) { + throw new IllegalArgumentException("cache mandatory"); } } - public void destroy() throws Exception { - manager.removeCache(CACHE_NAME); - } - public void putEntriesInCache(BasicAclEntry[] basicAclEntry) { BasicAclEntryHolder holder = new BasicAclEntryHolder(basicAclEntry); Element element = new Element(basicAclEntry[0].getAclObjectIdentity(), diff --git a/core/src/main/java/org/acegisecurity/providers/cas/cache/EhCacheBasedTicketCache.java b/core/src/main/java/org/acegisecurity/providers/cas/cache/EhCacheBasedTicketCache.java index 8f49acb298..c68d9e0fb4 100644 --- a/core/src/main/java/org/acegisecurity/providers/cas/cache/EhCacheBasedTicketCache.java +++ b/core/src/main/java/org/acegisecurity/providers/cas/cache/EhCacheBasedTicketCache.java @@ -20,36 +20,32 @@ import net.sf.acegisecurity.providers.cas.StatelessTicketCache; import net.sf.ehcache.Cache; import net.sf.ehcache.CacheException; -import net.sf.ehcache.CacheManager; import net.sf.ehcache.Element; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.dao.DataRetrievalFailureException; /** - * Caches tickets using EHCACHE. + * Caches tickets using a Spring IoC defined EHCACHE. * * @author Ben Alex * @version $Id$ */ public class EhCacheBasedTicketCache implements StatelessTicketCache, - InitializingBean, DisposableBean { + InitializingBean { //~ Static fields/initializers ============================================= private static final Log logger = LogFactory.getLog(EhCacheBasedTicketCache.class); - private static final String CACHE_NAME = "ehCacheBasedTicketCache"; //~ Instance fields ======================================================== private Cache cache; - private CacheManager manager; - private int minutesToIdle = 20; //~ Methods ================================================================ @@ -75,43 +71,20 @@ public class EhCacheBasedTicketCache implements StatelessTicketCache, } } - public void setMinutesToIdle(int minutesToIdle) { - this.minutesToIdle = minutesToIdle; + public void setCache(Cache cache) { + this.cache = cache; } - /** - * Specifies how many minutes an entry will remain in the cache from when - * it was last accessed. This is effectively the session duration. - * - *

- * Defaults to 20 minutes. - *

- * - * @return Returns the minutes an element remains in the cache - */ - public int getMinutesToIdle() { - return minutesToIdle; + public Cache getCache() { + return cache; } public void afterPropertiesSet() throws Exception { - if (CacheManager.getInstance().cacheExists(CACHE_NAME)) { - // don’t remove the cache - cache = CacheManager.getInstance().getCache(CACHE_NAME); - } else { - manager = CacheManager.create(); - - // Cache name, max memory, overflowToDisk, eternal, timeToLive, timeToIdle - cache = new Cache(CACHE_NAME, Integer.MAX_VALUE, false, false, - minutesToIdle * 60, minutesToIdle * 60); - - manager.addCache(cache); + if (cache == null) { + throw new IllegalArgumentException("cache mandatory"); } } - public void destroy() throws Exception { - manager.removeCache(CACHE_NAME); - } - public void putTicketInCache(CasAuthenticationToken token) { Element element = new Element(token.getCredentials().toString(), token); diff --git a/core/src/main/java/org/acegisecurity/providers/dao/cache/EhCacheBasedUserCache.java b/core/src/main/java/org/acegisecurity/providers/dao/cache/EhCacheBasedUserCache.java index a74c2bc78c..a59726b7d2 100644 --- a/core/src/main/java/org/acegisecurity/providers/dao/cache/EhCacheBasedUserCache.java +++ b/core/src/main/java/org/acegisecurity/providers/dao/cache/EhCacheBasedUserCache.java @@ -20,56 +20,40 @@ import net.sf.acegisecurity.providers.dao.UserCache; import net.sf.ehcache.Cache; import net.sf.ehcache.CacheException; -import net.sf.ehcache.CacheManager; import net.sf.ehcache.Element; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.dao.DataRetrievalFailureException; /** - * Caches User objects using User objects using a Spring IoC defined EHCACHE. * * @author Ben Alex * @version $Id$ */ -public class EhCacheBasedUserCache implements UserCache, InitializingBean, - DisposableBean { +public class EhCacheBasedUserCache implements UserCache, InitializingBean { //~ Static fields/initializers ============================================= private static final Log logger = LogFactory.getLog(EhCacheBasedUserCache.class); - private static final String CACHE_NAME = "ehCacheBasedUserCache"; //~ Instance fields ======================================================== private Cache cache; - private CacheManager manager; - private int minutesToIdle = 5; //~ Methods ================================================================ - public void setMinutesToIdle(int minutesToIdle) { - this.minutesToIdle = minutesToIdle; + public void setCache(Cache cache) { + this.cache = cache; } - /** - * Specifies how many minutes an entry will remain in the cache from when - * it was last accessed. This is effectively the session duration. - * - *

- * Defaults to 5 minutes. - *

- * - * @return Returns the minutes an element remains in the cache - */ - public int getMinutesToIdle() { - return minutesToIdle; + public Cache getCache() { + return cache; } public UserDetails getUserFromCache(String username) { @@ -95,24 +79,11 @@ public class EhCacheBasedUserCache implements UserCache, InitializingBean, } public void afterPropertiesSet() throws Exception { - if (CacheManager.getInstance().cacheExists(CACHE_NAME)) { - // don’t remove the cache - cache = CacheManager.getInstance().getCache(CACHE_NAME); - } else { - manager = CacheManager.create(); - - // Cache name, max memory, overflowToDisk, eternal, timeToLive, timeToIdle - cache = new Cache(CACHE_NAME, Integer.MAX_VALUE, false, false, - minutesToIdle * 60, minutesToIdle * 60); - - manager.addCache(cache); + if (cache == null) { + throw new IllegalArgumentException("cache mandatory"); } } - public void destroy() throws Exception { - manager.removeCache(CACHE_NAME); - } - public void putUserInCache(UserDetails user) { Element element = new Element(user.getUsername(), user); diff --git a/core/src/test/java/org/acegisecurity/acl/basic/cache/EhCacheBasedAclEntryCacheTests.java b/core/src/test/java/org/acegisecurity/acl/basic/cache/EhCacheBasedAclEntryCacheTests.java index b0834549af..3e8cf0d809 100644 --- a/core/src/test/java/org/acegisecurity/acl/basic/cache/EhCacheBasedAclEntryCacheTests.java +++ b/core/src/test/java/org/acegisecurity/acl/basic/cache/EhCacheBasedAclEntryCacheTests.java @@ -17,11 +17,16 @@ package net.sf.acegisecurity.acl.basic.cache; import junit.framework.TestCase; +import net.sf.acegisecurity.MockApplicationContext; import net.sf.acegisecurity.acl.basic.AclObjectIdentity; import net.sf.acegisecurity.acl.basic.BasicAclEntry; import net.sf.acegisecurity.acl.basic.NamedEntityObjectIdentity; import net.sf.acegisecurity.acl.basic.SimpleAclEntry; +import net.sf.ehcache.Cache; + +import org.springframework.context.ApplicationContext; + /** * Tests {@link EhCacheBasedAclEntryCache}. @@ -65,9 +70,7 @@ public class EhCacheBasedAclEntryCacheTests extends TestCase { public void testCacheOperation() throws Exception { EhCacheBasedAclEntryCache cache = new EhCacheBasedAclEntryCache(); - cache.afterPropertiesSet(); - - // execute a second time to test detection of existing instance + cache.setCache(getCache()); cache.afterPropertiesSet(); cache.putEntriesInCache(new BasicAclEntry[] {OBJECT_100_SCOTT, OBJECT_100_MARISSA}); @@ -83,13 +86,28 @@ public class EhCacheBasedAclEntryCacheTests extends TestCase { assertEquals(OBJECT_200_PETER, cache.getEntriesFromCache( new NamedEntityObjectIdentity("OBJECT", "200"))[0]); - - cache.destroy(); + assertNull(cache.getEntriesFromCache( + new NamedEntityObjectIdentity("OBJECT", "NOT_IN_CACHE"))); } - public void testGettersSetters() { + public void testStartupDetectsMissingCache() throws Exception { EhCacheBasedAclEntryCache cache = new EhCacheBasedAclEntryCache(); - cache.setMinutesToIdle(15); - assertEquals(15, cache.getMinutesToIdle()); + + try { + cache.afterPropertiesSet(); + fail("Should have thrown IllegalArgumentException"); + } catch (IllegalArgumentException expected) { + assertTrue(true); + } + + Cache myCache = getCache(); + cache.setCache(myCache); + assertEquals(myCache, cache.getCache()); + } + + private Cache getCache() { + ApplicationContext ctx = MockApplicationContext.getContext(); + + return (Cache) ctx.getBean("eHCacheBackend"); } } diff --git a/core/src/test/java/org/acegisecurity/providers/cas/cache/EhCacheBasedTicketCacheTests.java b/core/src/test/java/org/acegisecurity/providers/cas/cache/EhCacheBasedTicketCacheTests.java index 4da1ff33b9..660ba7931a 100644 --- a/core/src/test/java/org/acegisecurity/providers/cas/cache/EhCacheBasedTicketCacheTests.java +++ b/core/src/test/java/org/acegisecurity/providers/cas/cache/EhCacheBasedTicketCacheTests.java @@ -19,9 +19,14 @@ import junit.framework.TestCase; import net.sf.acegisecurity.GrantedAuthority; import net.sf.acegisecurity.GrantedAuthorityImpl; +import net.sf.acegisecurity.MockApplicationContext; import net.sf.acegisecurity.providers.cas.CasAuthenticationToken; import net.sf.acegisecurity.providers.dao.User; +import net.sf.ehcache.Cache; + +import org.springframework.context.ApplicationContext; + import java.util.List; import java.util.Vector; @@ -55,8 +60,8 @@ public class EhCacheBasedTicketCacheTests extends TestCase { public void testCacheOperation() throws Exception { EhCacheBasedTicketCache cache = new EhCacheBasedTicketCache(); + cache.setCache(getCache()); cache.afterPropertiesSet(); - cache.afterPropertiesSet(); // second run for test coverage // Check it gets stored in the cache cache.putTicketInCache(getToken()); @@ -70,14 +75,27 @@ public class EhCacheBasedTicketCacheTests extends TestCase { // Check it doesn't return values for null or unknown service tickets assertNull(cache.getByTicketId(null)); assertNull(cache.getByTicketId("UNKNOWN_SERVICE_TICKET")); - - cache.destroy(); } - public void testGettersSetters() { + public void testStartupDetectsMissingCache() throws Exception { EhCacheBasedTicketCache cache = new EhCacheBasedTicketCache(); - cache.setMinutesToIdle(5); - assertEquals(5, cache.getMinutesToIdle()); + + try { + cache.afterPropertiesSet(); + fail("Should have thrown IllegalArgumentException"); + } catch (IllegalArgumentException expected) { + assertTrue(true); + } + + Cache myCache = getCache(); + cache.setCache(myCache); + assertEquals(myCache, cache.getCache()); + } + + private Cache getCache() { + ApplicationContext ctx = MockApplicationContext.getContext(); + + return (Cache) ctx.getBean("eHCacheBackend"); } private CasAuthenticationToken getToken() { diff --git a/core/src/test/java/org/acegisecurity/providers/dao/cache/EhCacheBasedUserCacheTests.java b/core/src/test/java/org/acegisecurity/providers/dao/cache/EhCacheBasedUserCacheTests.java index 4c99535dd1..80ffe11137 100644 --- a/core/src/test/java/org/acegisecurity/providers/dao/cache/EhCacheBasedUserCacheTests.java +++ b/core/src/test/java/org/acegisecurity/providers/dao/cache/EhCacheBasedUserCacheTests.java @@ -19,8 +19,13 @@ import junit.framework.TestCase; import net.sf.acegisecurity.GrantedAuthority; import net.sf.acegisecurity.GrantedAuthorityImpl; +import net.sf.acegisecurity.MockApplicationContext; import net.sf.acegisecurity.providers.dao.User; +import net.sf.ehcache.Cache; + +import org.springframework.context.ApplicationContext; + /** * Tests {@link EhCacheBasedUserCache}. @@ -51,6 +56,7 @@ public class EhCacheBasedUserCacheTests extends TestCase { public void testCacheOperation() throws Exception { EhCacheBasedUserCache cache = new EhCacheBasedUserCache(); + cache.setCache(getCache()); cache.afterPropertiesSet(); // Check it gets stored in the cache @@ -65,14 +71,27 @@ public class EhCacheBasedUserCacheTests extends TestCase { // Check it doesn't return values for null or unknown users assertNull(cache.getUserFromCache(null)); assertNull(cache.getUserFromCache("UNKNOWN_USER")); - - cache.destroy(); } - public void testGettersSetters() { + public void testStartupDetectsMissingCache() throws Exception { EhCacheBasedUserCache cache = new EhCacheBasedUserCache(); - cache.setMinutesToIdle(15); - assertEquals(15, cache.getMinutesToIdle()); + + try { + cache.afterPropertiesSet(); + fail("Should have thrown IllegalArgumentException"); + } catch (IllegalArgumentException expected) { + assertTrue(true); + } + + Cache myCache = getCache(); + cache.setCache(myCache); + assertEquals(myCache, cache.getCache()); + } + + private Cache getCache() { + ApplicationContext ctx = MockApplicationContext.getContext(); + + return (Cache) ctx.getBean("eHCacheBackend"); } private User getUser() { diff --git a/core/src/test/resources/org/acegisecurity/applicationContext.xml b/core/src/test/resources/org/acegisecurity/applicationContext.xml index 86d1f55a75..a59ee01240 100644 --- a/core/src/test/resources/org/acegisecurity/applicationContext.xml +++ b/core/src/test/resources/org/acegisecurity/applicationContext.xml @@ -26,4 +26,18 @@ + + + + + + + + + + testingCache + + + + diff --git a/doc/docbook/index.xml b/doc/docbook/index.xml index dc9768b86c..bd77f185fc 100644 --- a/doc/docbook/index.xml +++ b/doc/docbook/index.xml @@ -110,36 +110,17 @@ release. These are: - - Replacing the Ant build with a Maven build. When this - happens the lib directory will no longer be - distributed in ZIP releases or hosted in CVS. - - "Remember me" functionality. Some discussion on this can be found at http://sourceforge.net/mailarchive/forum.php?thread_id=5177499&forum_id=40659. - - A sample web application which demonstrates the access - control list package. - - Implementation of an ObjectDefinitionSource that retrieves its details from a database. - - - Deprecation of Acegi Security's various EH-CACHE-based cache - implementations. Instead Acegi Security will provide new cache - implementations which use Spring Framework's new (currently in - CVS) EhCacheManagerFactoryBean factory. The - deprecated classes may be removed from the 1.0.0 release. - Whilst this list is subject to change and not in any particular @@ -982,7 +963,7 @@ public aspect DomainObjectInstanceSecurityAspect implements InitializingBean { authorities that have been granted to the principal. The principal and its credentials are populated by the client code, whilst the granted authorities are populated by the - AuthenticationManager. + AuthenticationManager. @@ -1232,10 +1213,30 @@ public aspect DomainObjectInstanceSecurityAspect implements InitializingBean { <property name="userCache"><ref bean="userCache"/></property> </bean> +<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"/> + +<bean id="userCacheBackend" class="org.springframework.cache.ehcache.EhCacheFactoryBean"> + <property name="cacheManager"> + <ref local="cacheManager"/> + </property> + <property name="cacheName"> + <value>userCache</value> + </property> +</bean> + <bean id="userCache" class="net.sf.acegisecurity.providers.dao.cache.EhCacheBasedUserCache"> - <property name="minutesToIdle"><value>5</value></property> + <property name="cache"><ref local="userCacheBackend"/></property> </bean> + All Acegi Security EH-CACHE implementations (including + EhCacheBasedUserCache) require an EH-CACHE + Cache object. The Cache object + can be obtained from wherever you like, although we recommend you use + Spring's factory classes as shown in the above configuration. If using + Spring's factory classes, please refer to the Spring documentation for + further details on how to optimise the cache storage location, memory + usage, eviction policies, timeouts etc. + For a class to be able to provide the DaoAuthenticationProvider with access to an authentication repository, it must implement the @@ -3415,8 +3416,19 @@ $CATALINA_HOME/bin/startup.sh <!-- <property name="trustStore"><value>/some/path/to/your/lib/security/cacerts</value></property> --> </bean> +<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"/> + +<bean id="ticketCacheBackend" class="org.springframework.cache.ehcache.EhCacheFactoryBean"> + <property name="cacheManager"> + <ref local="cacheManager"/> + </property> + <property name="cacheName"> + <value>ticketCache</value> + </property> +</bean> + <bean id="statelessTicketCache" class="net.sf.acegisecurity.providers.cas.cache.EhCacheBasedTicketCache"> - <property name="minutesToIdle"><value>20</value></property> + <property name="cache"><ref local="ticketCacheBackend"/></property> </bean> <bean id="casAuthoritiesPopulator" class="net.sf.acegisecurity.providers.cas.populator.DaoCasAuthoritiesPopulator"> @@ -3785,7 +3797,7 @@ $CATALINA_HOME/bin/startup.sh The net.sf.acegisecurity.acl package is very simple, comprising only a handful of interfaces and a single class, as shown in Figure 5. It provides the basic foundation for access control - list (ACL) lookups. + list (ACL) lookups. @@ -3847,7 +3859,7 @@ public AclEntry[] getAcls(java.lang.Object domainInstance, Authentication authen Integer Masked ACLs Acegi Security System for Spring includes a production-quality - ACL provider implementation, which is shown in Figure 6. + ACL provider implementation, which is shown in Figure 6. diff --git a/doc/xdocs/changes.xml b/doc/xdocs/changes.xml index 8298b31d60..1efccf8e2f 100644 --- a/doc/xdocs/changes.xml +++ b/doc/xdocs/changes.xml @@ -49,6 +49,7 @@ Improved performance of JBoss container adapter (see reference docs) Made DaoAuthenticationProvider detect null in Authentication.principal Improved JaasAuthenticationProvider startup error detection + Refactored EH-CACHE implementations to use Spring IoC defined caches instead Fixed AbstractProcessingFilter to use removeAttribute (JRun compatibility) Fixed GrantedAuthorityEffectiveAclResolver support of UserDetails principals Moved MethodSecurityInterceptor to ...intercept.method.aopalliance package diff --git a/doc/xdocs/upgrade/upgrade-06-07.html b/doc/xdocs/upgrade/upgrade-06-07.html index 0cb0b9b9e5..3a5182e13d 100644 --- a/doc/xdocs/upgrade/upgrade-06-07.html +++ b/doc/xdocs/upgrade/upgrade-06-07.html @@ -34,6 +34,15 @@ applications: net.sf.acegisecurity.intercept.method.MethodSecurityInterceptor to net.sf.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor. A simple find and replace will suffice to update your application contexts. + +
  • All of the EH-CACHE cache implementations provided with Acegi Security have + now been refactored to use a net.sf.ehcache.Cache obtained from + EhCacheManagerFactoryBean, which is included with Spring 1.1.1 and above. + See http://opensource.atlassian.com/confluence/spring/display/DISC/Caching+the+result+of+methods+using+Spring+and+EHCache + for more about this bean, or the Contacts sample application for how to + configure the EH-CACHE implementations provided with Acegi Security. + Note the "cache" property is now required, and the old internally-managed + cache properties have been removed.
  • diff --git a/samples/contacts/src/main/webapp/cas/WEB-INF/applicationContext-acegi-security.xml b/samples/contacts/src/main/webapp/cas/WEB-INF/applicationContext-acegi-security.xml index db9d6bdebe..8f55a4bff5 100644 --- a/samples/contacts/src/main/webapp/cas/WEB-INF/applicationContext-acegi-security.xml +++ b/samples/contacts/src/main/webapp/cas/WEB-INF/applicationContext-acegi-security.xml @@ -52,8 +52,19 @@
    + + + + + + + + ticketCache + + + - 20 + diff --git a/samples/contacts/src/main/webapp/filter/WEB-INF/applicationContext-acegi-security.xml b/samples/contacts/src/main/webapp/filter/WEB-INF/applicationContext-acegi-security.xml index 277415095b..85f2bb2f71 100644 --- a/samples/contacts/src/main/webapp/filter/WEB-INF/applicationContext-acegi-security.xml +++ b/samples/contacts/src/main/webapp/filter/WEB-INF/applicationContext-acegi-security.xml @@ -34,8 +34,19 @@ + + + + + + + + userCache + + + - 5 +