Permalink
Browse files

Removes commons-collections from the classpath completely. With commo…

…ns collections on the classpath, it is possible to execute malicious code (see http://foxglovesecurity.com/2015/11/06/what-do-weblogic-websphere-jboss-jenkins-opennms-and-your-application-have-in-common-this-vulnerability/ for more information) through the setting of variables through the REST API.

Furthermore, a new property 'rest.variables.allow.serializable' for the REST application has been added so one can decide to disable the setting of serializable objects as variables completely.

Thanks Teemu Kääriäinen for providing us the information and test to reproduce (and fix) the issue!
  • Loading branch information...
jbarrez committed Dec 10, 2015
1 parent ccd54fa commit ddf9b515550c26bc6f884b91e4563e035497f0c2
@@ -111,10 +111,6 @@
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
- <dependency>
- <groupId>commons-collections</groupId>
- <artifactId>commons-collections</artifactId>
- </dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
@@ -51,8 +51,8 @@
import org.activiti.bpmn.model.UserTask;
import org.activiti.editor.constants.EditorJsonConstants;
import org.activiti.editor.constants.StencilConstants;
+import org.activiti.editor.language.json.converter.util.CollectionUtils;
import org.activiti.editor.language.json.converter.util.JsonConverterUtil;
-import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -53,8 +53,8 @@
import org.activiti.bpmn.model.ValuedDataObject;
import org.activiti.editor.constants.EditorJsonConstants;
import org.activiti.editor.constants.StencilConstants;
+import org.activiti.editor.language.json.converter.util.CollectionUtils;
import org.activiti.editor.language.json.converter.util.JsonConverterUtil;
-import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -38,7 +38,7 @@
import org.activiti.bpmn.model.ValuedDataObject;
import org.activiti.editor.constants.EditorJsonConstants;
import org.activiti.editor.constants.StencilConstants;
-import org.apache.commons.collections.CollectionUtils;
+import org.activiti.editor.language.json.converter.util.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormatter;
@@ -17,7 +17,7 @@
import org.activiti.bpmn.model.BaseElement;
import org.activiti.bpmn.model.FlowElement;
import org.activiti.bpmn.model.UserTask;
-import org.apache.commons.collections.CollectionUtils;
+import org.activiti.editor.language.json.converter.util.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import com.fasterxml.jackson.databind.JsonNode;
@@ -0,0 +1,31 @@
+/* Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.activiti.editor.language.json.converter.util;
+
+import java.util.Collection;
+
+/**
+ * @author Joram Barrez
+ */
+public class CollectionUtils {
+
+ public static boolean isEmpty(@SuppressWarnings("rawtypes") Collection collection) {
+ return (collection == null || collection.isEmpty());
+ }
+
+ public static boolean isNotEmpty(@SuppressWarnings("rawtypes") Collection collection) {
+ return !CollectionUtils.isEmpty(collection);
+ }
+
+
+}
@@ -19,6 +19,7 @@
import java.io.ObjectOutputStream;
import java.util.Map;
+import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletResponse;
import org.activiti.engine.ActivitiException;
@@ -34,6 +35,7 @@
import org.activiti.rest.service.api.engine.variable.RestVariable.RestVariableScope;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.env.Environment;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
@@ -44,11 +46,21 @@
public class BaseExecutionVariableResource {
@Autowired
+ protected Environment env;
+
+ @Autowired
protected RestResponseFactory restResponseFactory;
@Autowired
protected RuntimeService runtimeService;
+ protected boolean isSerializableVariableAllowed;
+
+ @PostConstruct
+ protected void postConstruct() {
+ isSerializableVariableAllowed = env.getProperty("rest.variables.allow.serializable", Boolean.class, true);
+ }
+
protected byte[] getVariableDataByteArray(Execution execution, String variableName, String scope,
HttpServletResponse response) {
@@ -139,12 +151,14 @@ protected RestVariable setBinaryVariable(MultipartHttpServletRequest request,
byte[] variableBytes = IOUtils.toByteArray(file.getInputStream());
setVariable(execution, variableName, variableBytes, scope, isNew);
+ } else if (isSerializableVariableAllowed) {
+ // Try deserializing the object
+ ObjectInputStream stream = new ObjectInputStream(file.getInputStream());
+ Object value = stream.readObject();
+ setVariable(execution, variableName, value, scope, isNew);
+ stream.close();
} else {
- // Try deserializing the object
- ObjectInputStream stream = new ObjectInputStream(file.getInputStream());
- Object value = stream.readObject();
- setVariable(execution, variableName, value, scope, isNew);
- stream.close();
+ throw new ActivitiContentNotSupportedException("Serialized objects are not allowed");
}
if (responseVariableType == RestResponseFactory.VARIABLE_PROCESS) {
@@ -0,0 +1,35 @@
+/* Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.activiti.rest.conf;
+
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.PropertySource;
+import org.springframework.context.annotation.PropertySources;
+
+/**
+ * @author Joram Barrez
+ */
+@Configuration
+@ComponentScan(basePackages = {
+ "org.activiti.rest.conf.common",
+ "org.activiti.rest.conf.engine"
+})
+@PropertySources({
+ @PropertySource(value = "classpath:disable-object-variable-serialization.properties", ignoreResourceNotFound = false)
+})
+public class ObjectVariableSerializationDisabledApplicationConfiguration {
+
+
+
+}
@@ -38,9 +38,10 @@
import org.activiti.engine.impl.test.PvmTestCase;
import org.activiti.engine.impl.test.TestHelper;
import org.activiti.engine.runtime.ProcessInstance;
-import org.activiti.rest.WebConfigurer;
import org.activiti.rest.conf.ApplicationConfiguration;
import org.activiti.rest.service.api.RestUrlBuilder;
+import org.activiti.rest.util.TestServerUtil;
+import org.activiti.rest.util.TestServerUtil.TestServer;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpHeaders;
import org.apache.http.HttpResponse;
@@ -59,17 +60,12 @@
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.message.BasicHeader;
import org.eclipse.jetty.server.Server;
-import org.eclipse.jetty.server.session.HashSessionIdManager;
-import org.eclipse.jetty.server.session.HashSessionManager;
-import org.eclipse.jetty.server.session.SessionHandler;
-import org.eclipse.jetty.servlet.ServletContextHandler;
import org.joda.time.format.DateTimeFormatter;
import org.joda.time.format.ISODateTimeFormat;
import org.junit.Assert;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
-import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
@@ -81,13 +77,13 @@
private static Logger log = LoggerFactory.getLogger(BaseSpringRestTestCase.class);
- protected static final int HTTP_SERVER_PORT = 9797;
- protected static final String SERVER_URL_PREFIX = "http://localhost:9797/service/";
- protected static final RestUrlBuilder URL_BUILDER = RestUrlBuilder.usingBaseUrl(SERVER_URL_PREFIX);
protected static final List<String> TABLENAMES_EXCLUDED_FROM_DB_CLEAN_CHECK = Arrays.asList(
"ACT_GE_PROPERTY"
);
+ protected static String SERVER_URL_PREFIX;
+ protected static RestUrlBuilder URL_BUILDER;
+
protected static Server server;
protected static ApplicationContext appContext;
protected ObjectMapper objectMapper = new ObjectMapper();
@@ -112,7 +108,12 @@
protected ISO8601DateFormat dateFormat = new ISO8601DateFormat();
static {
- createAndStartServer();
+
+ TestServer testServer = TestServerUtil.createAndStartServer(ApplicationConfiguration.class);
+ server = testServer.getServer();
+ appContext = testServer.getApplicationContext();
+ SERVER_URL_PREFIX = testServer.getServerUrlPrefix();
+ URL_BUILDER = RestUrlBuilder.usingBaseUrl(SERVER_URL_PREFIX);
// Lookup services
processEngine = appContext.getBean("processEngine", ProcessEngine.class);
@@ -202,40 +203,6 @@ protected void createUsers() {
identityService.createMembership(user.getId(), group.getId());
}
- public static void createAndStartServer() {
- server = new Server(HTTP_SERVER_PORT);
-
- HashSessionIdManager idmanager = new HashSessionIdManager();
- server.setSessionIdManager(idmanager);
-
- AnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext();
- applicationContext.register(ApplicationConfiguration.class);
- applicationContext.refresh();
-
- appContext = applicationContext;
-
- try {
- server.setHandler(getServletContextHandler(applicationContext));
- server.start();
- } catch (Exception e) {
- log.error("Error starting server", e);
- }
- }
-
- private static ServletContextHandler getServletContextHandler(AnnotationConfigWebApplicationContext context) throws IOException {
- ServletContextHandler contextHandler = new ServletContextHandler();
- WebConfigurer configurer = new WebConfigurer();
- configurer.setContext(context);
- contextHandler.addEventListener(configurer);
-
- // Create the SessionHandler (wrapper) to handle the sessions
- HashSessionManager manager = new HashSessionManager();
- SessionHandler sessions = new SessionHandler(manager);
- contextHandler.setHandler(sessions);
-
- return contextHandler;
- }
-
/**
* IMPORTANT: calling method is responsible for calling close() on returned {@link HttpResponse} to free the connection.
*/
Oops, something went wrong.

0 comments on commit ddf9b51

Please sign in to comment.