ehcache / ehcache3

Ehcache 3.x line
http://www.ehcache.org
Apache License 2.0
2.02k stars 581 forks source link

ehcache 2 to 3 migration of net.sf.ehcache.hibernate.SingletonEhCacheProvider #3129

Open sarnobat opened 1 year ago

sarnobat commented 1 year ago

I'm trying to upgrade from 2 to 3 and the (large) codebase contains:

net.sf.ehcache.hibernate.SingletonEhCacheProvider

inside xml-based bean containers:

                <prop key="hibernate.cache.provider_class">net.sf.ehcache.hibernate.SingletonEhCacheProvider</prop>

and I don't see in the migration guide any hints on what is an acceptable way to achieve this:

https://www.ehcache.org/documentation/3.3/migration-guide.html

I'm using Spring 3.2.18 and hibernate as low as 3.3:

./WEB-INF/lib/hibernate-3.2.3.ga.jar
./WEB-INF/lib/hibernate-annotations-3.3.0.ga.jar
./WEB-INF/lib/hibernate-commons-annotations-4.0.1.Final.jar
./WEB-INF/lib/hibernate-validator-5.1.3.Final.jar
./WEB-INF/lib/spring-aop-3.2.18.RELEASE.jar
./WEB-INF/lib/spring-beans-3.2.18.RELEASE.jar
./WEB-INF/lib/spring-context-3.2.18.RELEASE.jar
./WEB-INF/lib/spring-context-support-3.2.18.RELEASE.jar
./WEB-INF/lib/spring-core-3.2.18.RELEASE.jar
./WEB-INF/lib/spring-expression-3.2.18.RELEASE.jar
./WEB-INF/lib/spring-jdbc-3.2.18.RELEASE.jar
./WEB-INF/lib/spring-jms-3.0.3.RELEASE.jar
./WEB-INF/lib/spring-orm-3.2.18.RELEASE.jar
./WEB-INF/lib/spring-oxm-3.2.18.RELEASE.jar
./WEB-INF/lib/spring-security-config-3.1.2.RELEASE.jar
./WEB-INF/lib/spring-security-core-3.2.10.RELEASE.jar
./WEB-INF/lib/spring-security-saml2-core-1.0.0.RC2.jar
./WEB-INF/lib/spring-security-web-3.2.10.RELEASE.jar
./WEB-INF/lib/spring-test-3.2.18.RELEASE.jar
./WEB-INF/lib/spring-tx-3.2.18.RELEASE.jar
./WEB-INF/lib/spring-web-3.2.18.RELEASE.jar
./WEB-INF/lib/spring-webmvc-3.2.18.RELEASE.jar
./WEB-INF/lib/spring-ws-core-2.1.4.RELEASE-all.jar

1) What is the easiest way to use ehcache 3 with code that currently uses net.sf.ehcache.hibernate.SingletonEhCacheProvider? 2) Is there a compatibility matrix? I see lots of search results about Hibernate 4+, Spring/Spring Boot at higher versions than my code has.

(note: this is legacy code not written by me :) And we do have plans to modernize but there's a more immediate security concern with ehcache 2 that I need to address)

chrisdennis commented 1 year ago

The way to do this in a modern setup would be to use Ehcache 3 natively as a JSR-107 provider. I'm not sure I can think of a trivial way to use Ehcache 3 as a caching provider for Hibernate 3.3 (Ehcache 3 was released 8 years after Hibernate 3.3).

Before we explore various crazy bridging options... what's the security problem with Ehcache 2?

sarnobat commented 1 year ago

Thank you for the quick response. Here is the security issue: CVE-2020-36518

chrisdennis commented 1 year ago

So that's a vulnerability in Jackson - I think that's only used in the management code for the clustered parts of Ehcache 2.x. Can you tell me how you're installing Ehcache 2.x, what your configuration looks like, and where the scanner is finding the library?

sarnobat commented 1 year ago

(thanks again, will try and get this info from a colleague before I go on a few weeks travel)

EDIT: Here is the info as I understand it (let me know if more is needed - it's the first time I've seen this code!):

1) How I'm using Ehcache 2.X

import org.ehcache.core.Ehcache;
import org.ehcache.config.CacheConfiguration;
import org.apache.commons.lang3.StringUtils;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;

    @Cacheable(value = MY_FEATURE_SETTINGS_CACHE_NAME, condition = "#root.target.isMyFeatureSettingsCacheEnabled()")
    public List<MyFeatureSetting> getMyFeatureSettings(Long id, MyFeatureSettingType MyFeatureSettingType) throws DomainException {

        try {
            return MyFeatureSettingDao.getMyFeatureSetting(acctId, MyFeatureSettingType);
        } catch (Exception e) {
            throw new DomainException("Failed to getMyFeatureSetting(), acctId=" + acctId, e);
        }
    }

2) What the Configuration looks like (sample)

<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd">

    <diskStore path="java.io.tmpdir"/>
.........
    <defaultCache
            maxElementsInMemory="10000"
            eternal="false"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            overflowToDisk="false"
            diskPersistent="false"
            memoryStoreEvictionPolicy="LRU"
    />
</ehcache>

3) Where the scanner is finding the library

applicationContext.xml (with trade secrets redacted)


    <cache:annotation-driven key-generator="myCacheKeyGenerator"/>

    <bean id="myCacheKeyGenerator" class="com.mycompany.CacheKeyGenerator">
        <property name="configManager" ref="myConfigManager"/>
    </bean>

    <bean id="cacheManager" class="org.springframework.cache.support.CompositeCacheManager">
        <property name="cacheManagers"><list>
            <ref bean="myCacheManager"/>
            <ref bean="core.simpleCacheManager"/>
        </list></property>
        <property name="fallbackToNoOpCache" value="true"/>
    </bean>

    <bean id="myCacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">
        <property name="cacheManager" ref="myCacheFactoryBean"/>
    </bean>

    <bean id="myCacheFactoryBean" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"
          p:config-location="classpath:core-ehcache.xml"
          p:cacheManagerName="coreEhCacheManager"
          p:shared="true">
    </bean>

import com.mycompany.ConfigManager;
import org.springframework.cache.interceptor.DefaultKeyGenerator;

public class CacheKeyGenerator extends DefaultKeyGenerator {

    private ConfigManager configManager;

    @Override
    public Object generate(Object target, Method method, Object... params) {
        try {
            if(customCacheEnabled()){
                return generateKey(params);
            }
        } catch(Exception e){
            log.error("Exception using Custom Cache Key Generator, Falling back to Default Key Generator", e);
        }
        return super.generate(target, method, params);
    }

    public static Object generateKey(Object... params) {
        if (params.length == 0) {
            return CacheKey.EMPTY;
        }
        if (params.length == 1) {
            Object param = params[0];
            if (param != null && !param.getClass().isArray()) {
                return param;
            }
        }
        return new CacheKey(params);
    }
}