This is an automated email from the ASF dual-hosted git repository. ntimofeev pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/cayenne.git
The following commit(s) were added to refs/heads/master by this push: new 63a3918 Use whitelist for Hessian serialization new 1f7e3ad Merge remote-tracking branch 'parent/pr/414' into asf-master 63a3918 is described below commit 63a3918153563753d3b8b9febe41748b680e8660 Author: Nikita Timofeev <stari...@gmail.com> AuthorDate: Tue Feb 11 17:40:24 2020 +0300 Use whitelist for Hessian serialization --- .../remote/hessian/ClientSerializerFactory.java | 10 ++-- .../cayenne/rop/HttpClientConnectionProvider.java | 4 +- .../rop/http/HessianROPSerializationServiceIT.java | 3 +- .../configuration/rop/server/ROPServerModule.java | 13 ++++- .../cayenne/remote/hessian/HessianConfig.java | 56 ++++++++++++++++++---- .../java/org/apache/cayenne/rop/ROPConstants.java | 5 ++ .../ServerHessianSerializationServiceProvider.java | 24 +++++++++- pom.xml | 2 +- 8 files changed, 97 insertions(+), 20 deletions(-) diff --git a/cayenne-client/src/main/java/org/apache/cayenne/remote/hessian/ClientSerializerFactory.java b/cayenne-client/src/main/java/org/apache/cayenne/remote/hessian/ClientSerializerFactory.java index 0f81bc8..02212e8 100644 --- a/cayenne-client/src/main/java/org/apache/cayenne/remote/hessian/ClientSerializerFactory.java +++ b/cayenne-client/src/main/java/org/apache/cayenne/remote/hessian/ClientSerializerFactory.java @@ -19,13 +19,13 @@ package org.apache.cayenne.remote.hessian; +import com.caucho.hessian.io.FieldDeserializer2Factory; import org.apache.cayenne.DataRow; import org.apache.cayenne.util.PersistentObjectList; import org.apache.cayenne.util.PersistentObjectMap; import com.caucho.hessian.io.AbstractSerializerFactory; import com.caucho.hessian.io.Deserializer; -import com.caucho.hessian.io.HessianProtocolException; import com.caucho.hessian.io.JavaDeserializer; import com.caucho.hessian.io.Serializer; @@ -41,23 +41,23 @@ public class ClientSerializerFactory extends AbstractSerializerFactory { private Deserializer mapDeserializer; @Override - public Serializer getSerializer(Class cl) throws HessianProtocolException { + public Serializer getSerializer(Class cl) { return null; } @Override - public Deserializer getDeserializer(Class cl) throws HessianProtocolException { + public Deserializer getDeserializer(Class cl) { //turns out Hessian uses its own (incorrect) serialization mechanism for maps if (PersistentObjectMap.class.isAssignableFrom(cl)) { if (mapDeserializer == null) { - mapDeserializer = new JavaDeserializer(cl); + mapDeserializer = new JavaDeserializer(cl, FieldDeserializer2Factory.create()); } return mapDeserializer; } if (PersistentObjectList.class.isAssignableFrom(cl)) { if (listDeserializer == null) { - listDeserializer = new JavaDeserializer(cl); + listDeserializer = new JavaDeserializer(cl, FieldDeserializer2Factory.create()); } return listDeserializer; } diff --git a/cayenne-client/src/main/java/org/apache/cayenne/rop/HttpClientConnectionProvider.java b/cayenne-client/src/main/java/org/apache/cayenne/rop/HttpClientConnectionProvider.java index 3093c34..3138c43 100644 --- a/cayenne-client/src/main/java/org/apache/cayenne/rop/HttpClientConnectionProvider.java +++ b/cayenne-client/src/main/java/org/apache/cayenne/rop/HttpClientConnectionProvider.java @@ -33,7 +33,7 @@ public class HttpClientConnectionProvider implements Provider<ClientConnection> protected RuntimeProperties runtimeProperties; @Inject - protected ROPSerializationService serializationService; + protected Provider<ROPSerializationService> serializationServiceProvider; @Override public ClientConnection get() throws DIRuntimeException { @@ -41,7 +41,7 @@ public class HttpClientConnectionProvider implements Provider<ClientConnection> .get(ClientConstants.ROP_SERVICE_SHARED_SESSION_PROPERTY); HttpROPConnector ropConnector = createHttpRopConnector(); - ProxyRemoteService remoteService = new ProxyRemoteService(serializationService, ropConnector); + ProxyRemoteService remoteService = new ProxyRemoteService(serializationServiceProvider.get(), ropConnector); HttpClientConnection clientConnection = new HttpClientConnection(remoteService, sharedSession); ropConnector.setClientConnection(clientConnection); diff --git a/cayenne-client/src/test/java/org/apache/cayenne/rop/http/HessianROPSerializationServiceIT.java b/cayenne-client/src/test/java/org/apache/cayenne/rop/http/HessianROPSerializationServiceIT.java index 97d35e7..9f86a1c 100644 --- a/cayenne-client/src/test/java/org/apache/cayenne/rop/http/HessianROPSerializationServiceIT.java +++ b/cayenne-client/src/test/java/org/apache/cayenne/rop/http/HessianROPSerializationServiceIT.java @@ -32,6 +32,7 @@ import org.junit.Test; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; +import java.util.Collections; import static org.junit.Assert.*; @@ -107,7 +108,7 @@ public class HessianROPSerializationServiceIT extends ClientCase { } private ROPSerializationService createServerSerializationService() { - return new ServerHessianSerializationServiceProvider().get(); + return new ServerHessianSerializationServiceProvider(() -> context.getChannel(), Collections.emptyList()).get(); } } diff --git a/cayenne-rop-server/src/main/java/org/apache/cayenne/configuration/rop/server/ROPServerModule.java b/cayenne-rop-server/src/main/java/org/apache/cayenne/configuration/rop/server/ROPServerModule.java index 20938d7..896ff89 100644 --- a/cayenne-rop-server/src/main/java/org/apache/cayenne/configuration/rop/server/ROPServerModule.java +++ b/cayenne-rop-server/src/main/java/org/apache/cayenne/configuration/rop/server/ROPServerModule.java @@ -22,9 +22,11 @@ import java.util.Map; import org.apache.cayenne.configuration.Constants; import org.apache.cayenne.di.Binder; +import org.apache.cayenne.di.ListBuilder; import org.apache.cayenne.di.MapBuilder; import org.apache.cayenne.di.Module; import org.apache.cayenne.remote.RemoteService; +import org.apache.cayenne.rop.ROPConstants; import org.apache.cayenne.rop.ROPSerializationService; import org.apache.cayenne.rop.ServerHessianSerializationServiceProvider; import org.apache.cayenne.rop.ServerHttpRemoteService; @@ -46,6 +48,14 @@ public class ROPServerModule implements Module { return binder.bindMap(String.class, Constants.SERVER_ROP_EVENT_BRIDGE_PROPERTIES_MAP); } + /** + * @since 4.2 + */ + public static ListBuilder<String> contributeSerializationWhitelist(Binder binder) { + return binder.bindList(String.class, ROPConstants.SERIALIZATION_WHITELIST); + } + + public ROPServerModule() {} /** @@ -60,8 +70,9 @@ public class ROPServerModule implements Module { } public void configure(Binder binder) { + contributeSerializationWhitelist(binder); + MapBuilder<String> mapBuilder = contributeROPBridgeProperties(binder); if(eventBridgeProperties != null) { - MapBuilder<String> mapBuilder = contributeROPBridgeProperties(binder); mapBuilder.putAll(eventBridgeProperties); } binder.bind(RemoteService.class).to(ServerHttpRemoteService.class); diff --git a/cayenne-rop-server/src/main/java/org/apache/cayenne/remote/hessian/HessianConfig.java b/cayenne-rop-server/src/main/java/org/apache/cayenne/remote/hessian/HessianConfig.java index 8c4a9c2..615474d 100644 --- a/cayenne-rop-server/src/main/java/org/apache/cayenne/remote/hessian/HessianConfig.java +++ b/cayenne-rop-server/src/main/java/org/apache/cayenne/remote/hessian/HessianConfig.java @@ -21,8 +21,13 @@ package org.apache.cayenne.remote.hessian; import java.lang.reflect.Constructor; import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; import org.apache.cayenne.CayenneRuntimeException; +import org.apache.cayenne.map.DataMap; import org.apache.cayenne.map.EntityResolver; import org.apache.cayenne.util.Util; @@ -47,21 +52,57 @@ public class HessianConfig { * and have a default constructor. * @param resolver if not null, EntityResolver will be injected into all factories * that implement <em>setEntityResolver(EntityResolver)</em> method. + * @see #createFactory(String[], EntityResolver, Collection) */ public static SerializerFactory createFactory( String[] factoryNames, EntityResolver resolver) { + return createFactory(factoryNames, resolver, Collections.emptyList()); + } + + /** + * Creates a Hessian SerializerFactory configured with zero or more + * AbstractSerializerFactory extensions. Extensions are specified as class names. This + * method can inject EntityResolver if an extension factory class defines + * <em>setEntityResolver(EntityResolver)</em> method. + * + * @param factoryNames an array of factory class names. Each class must be a concrete + * subclass of <em>com.caucho.hessian.io.AbstractSerializerFactory</em> + * and have a default constructor. + * @param resolver if not null, EntityResolver will be injected into all factories + * that implement <em>setEntityResolver(EntityResolver)</em> method. + * @param additionalWhitelist serialization whitelist, examples: "java.util.*", "com.foo.io.Bean" + * @see #createFactory(String[], EntityResolver) + * + * @since 4.2 + */ + public static SerializerFactory createFactory( + String[] factoryNames, + EntityResolver resolver, + Collection<String> additionalWhitelist) { SerializerFactory factory = new CayenneSerializerFactory(); - if (factoryNames != null && factoryNames.length > 0) { + List<String> whitelist = new ArrayList<>(additionalWhitelist); + if(resolver != null) { + whitelist.add("org.apache.cayenne.*"); + for (DataMap dataMap : resolver.getDataMaps()) { + whitelist.add(dataMap.getDefaultPackage() + ".*"); + } + } - for (String factoryName : factoryNames) { + if(!whitelist.isEmpty()) { + for (String pattern : whitelist) { + factory.getClassFactory().allow(pattern); + } + factory.getClassFactory().setWhitelist(true); + } + if (factoryNames != null && factoryNames.length > 0) { + for (String factoryName : factoryNames) { try { factory.addFactory(loadFactory(factoryName, resolver)); - } - catch (Exception e) { + } catch (Exception e) { throw new CayenneRuntimeException("Error configuring factory class " + factoryName, e); } @@ -83,16 +124,14 @@ public class HessianConfig { + " is not a AbstractSerializerFactory"); } - Constructor c = factoryClass.getDeclaredConstructor(); + Constructor<?> c = factoryClass.getDeclaredConstructor(); if (!Util.isAccessible(c)) { c.setAccessible(true); } AbstractSerializerFactory object = (AbstractSerializerFactory) c.newInstance(); - if (resolver != null) { try { - Method setter = factoryClass.getDeclaredMethod( "setEntityResolver", EntityResolver.class); @@ -102,8 +141,7 @@ public class HessianConfig { } setter.invoke(object, resolver); - } - catch (Exception e) { + } catch (Exception ignore) { // ignore injection exception } } diff --git a/cayenne-rop-server/src/main/java/org/apache/cayenne/rop/ROPConstants.java b/cayenne-rop-server/src/main/java/org/apache/cayenne/rop/ROPConstants.java index b8e234a..7bf9267 100644 --- a/cayenne-rop-server/src/main/java/org/apache/cayenne/rop/ROPConstants.java +++ b/cayenne-rop-server/src/main/java/org/apache/cayenne/rop/ROPConstants.java @@ -25,4 +25,9 @@ public class ROPConstants { public static final String ESTABLISH_SESSION_OPERATION = "establish_session"; public static final String ESTABLISH_SHARED_SESSION_OPERATION = "establish_shared_session"; + + /** + * @since 4.2 + */ + public static final String SERIALIZATION_WHITELIST = "serialization_whitelist"; } diff --git a/cayenne-rop-server/src/main/java/org/apache/cayenne/rop/ServerHessianSerializationServiceProvider.java b/cayenne-rop-server/src/main/java/org/apache/cayenne/rop/ServerHessianSerializationServiceProvider.java index dccb0c4..5d683fe 100644 --- a/cayenne-rop-server/src/main/java/org/apache/cayenne/rop/ServerHessianSerializationServiceProvider.java +++ b/cayenne-rop-server/src/main/java/org/apache/cayenne/rop/ServerHessianSerializationServiceProvider.java @@ -18,20 +18,42 @@ ****************************************************************/ package org.apache.cayenne.rop; +import java.util.List; + +import org.apache.cayenne.DataChannel; import org.apache.cayenne.di.DIRuntimeException; +import org.apache.cayenne.di.Inject; import org.apache.cayenne.di.Provider; import org.apache.cayenne.remote.hessian.HessianConfig; import org.apache.cayenne.remote.hessian.service.ServerSerializerFactory; public class ServerHessianSerializationServiceProvider implements Provider<ROPSerializationService> { + private final Provider<DataChannel> dataChannelProvider; + + private final List<String> serializationWhitelist; + public static final String[] SERVER_SERIALIZER_FACTORIES = new String[] { ServerSerializerFactory.class.getName() }; + /** + * @since 4.2 + */ + public ServerHessianSerializationServiceProvider(@Inject Provider<DataChannel> dataChannelProvider, + @Inject(ROPConstants.SERIALIZATION_WHITELIST) List<String> serializationWhitelist) { + this.dataChannelProvider = dataChannelProvider; + this.serializationWhitelist = serializationWhitelist; + } + @Override public ROPSerializationService get() throws DIRuntimeException { return new HessianROPSerializationService( - HessianConfig.createFactory(SERVER_SERIALIZER_FACTORIES, null)); + HessianConfig.createFactory( + SERVER_SERIALIZER_FACTORIES, + dataChannelProvider.get().getEntityResolver(), + serializationWhitelist + ) + ); } } diff --git a/pom.xml b/pom.xml index 649f987..3e86ca8 100644 --- a/pom.xml +++ b/pom.xml @@ -342,7 +342,7 @@ <dependency> <groupId>com.caucho</groupId> <artifactId>hessian</artifactId> - <version>4.0.51</version> + <version>4.0.63</version> <scope>provided</scope> </dependency> <dependency>