diff --git a/config/alfresco/bootstrap-context.xml b/config/alfresco/bootstrap-context.xml
index 8bbdd6869c..deac0d0a46 100644
--- a/config/alfresco/bootstrap-context.xml
+++ b/config/alfresco/bootstrap-context.xml
@@ -107,6 +107,9 @@
+
+
+
diff --git a/source/java/org/alfresco/repo/admin/UnserializerValidatorBootstrap.java b/source/java/org/alfresco/repo/admin/UnserializerValidatorBootstrap.java
new file mode 100644
index 0000000000..4590bef764
--- /dev/null
+++ b/source/java/org/alfresco/repo/admin/UnserializerValidatorBootstrap.java
@@ -0,0 +1,240 @@
+/*
+ * Copyright (C) 2005-2015 Alfresco Software Limited.
+ *
+ * This file is part of Alfresco
+ *
+ * Alfresco is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Alfresco is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Alfresco. If not, see .
+ */
+package org.alfresco.repo.admin;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectOutputStream;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+
+import org.alfresco.error.AlfrescoRuntimeException;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.context.ApplicationEvent;
+import org.springframework.extensions.surf.util.AbstractLifecycleBean;
+
+/**
+ * Bootstrap unserializer validator: a bootstrap bean that checks that the
+ * classes that would favor Java unserialize remote code execution are not
+ * available. Check is needed because libs could be introduced by the
+ * application server.
+ *
+ *
See MNT-15170 for details.
+ *
+ * Checked conditions:
+ * org.apache.xalan.xsltc.trax.TemplatesImpl and
+ * org.springframework.core.SerializableTypeWrapper;
+ * org.apache.commons.collections.functors.InvokerTransformer
+ * org.apache.commons.collections.functors.InstantiateFactory
+ * org.apache.commons.collections.functors.InstantiateTransformer
+ * org.apache.commons.collections.functors.PrototypeCloneFactory
+ * org.apache.commons.collections.functors.PrototypeSerializationFactory
+ * org.apache.commons.collections.functors.WhileClosure
+ * org.apache.commons.collections.functors.CloneTransformer
+ * org.apache.commons.collections.functors.ForClosure
+ */
+public class UnserializerValidatorBootstrap extends AbstractLifecycleBean
+{
+
+ private static Log logger = LogFactory.getLog(UnserializerValidatorBootstrap.class);
+
+ private static final String ERR_UNEXPECTED_ERROR = "unserializer.validator.err.unexpectederror";
+
+ // Bootstrap performed?
+ private boolean bootstrapPerformed = false;
+
+ /**
+ * @deprecated Was never used
+ */
+ public void setLog(boolean logEnabled)
+ {
+ // Ignore
+ }
+
+ /**
+ * Determine if bootstrap was performed?
+ *
+ * @return true => bootstrap was performed
+ */
+ public boolean hasPerformedBootstrap()
+ {
+ return bootstrapPerformed;
+ }
+
+ private boolean classInPath(String className)
+ {
+ try
+ {
+ Class.forName(className, false, this.getClass().getClassLoader());
+
+ // it exists on the classpath
+ return true;
+ }
+ catch (ClassNotFoundException e)
+ {
+
+ // it does not exist on the classpath
+ return false;
+ }
+ }
+
+ /**
+ * Check if Java unserialize remote code execution is already fixed on this
+ * commons collections version.
+ *
+ * @return
+ */
+ private boolean isCommonsCollectionsDeserializerFixed()
+ {
+
+ try
+ {
+ Class> invokerTransformerClass = Class.forName(
+ "org.apache.commons.collections.functors.InvokerTransformer", true, this
+ .getClass().getClassLoader());
+
+ if (invokerTransformerClass != null)
+ {
+ Constructor> invokerTransformerConstructor = invokerTransformerClass
+ .getConstructor(String.class, Class[].class, Object[].class);
+
+ Object invokerTransformerInstance = invokerTransformerConstructor.newInstance(null,
+ null, null);
+
+ ObjectOutputStream objectOut = null;
+ ByteArrayOutputStream byteOut = null;
+ try
+ {
+ // Write the object out to a byte array
+ byteOut = new ByteArrayOutputStream();
+ objectOut = new ObjectOutputStream(byteOut);
+ objectOut.writeObject(invokerTransformerInstance);
+ objectOut.flush();
+ }
+ catch (UnsupportedOperationException e)
+ {
+ // Expected: Serialization support is disabled for security
+ // reasons.
+ return true;
+ }
+ catch (IOException e)
+ {
+ throw new AlfrescoRuntimeException(ERR_UNEXPECTED_ERROR, e);
+ }
+ finally
+ {
+ if (objectOut != null)
+ {
+ try
+ {
+ objectOut.close();
+ }
+ catch (Throwable e)
+ {
+ }
+ }
+ if (byteOut != null)
+ {
+ try
+ {
+ byteOut.close();
+ }
+ catch (Throwable e)
+ {
+ }
+ }
+ }
+ }
+ }
+ catch (SecurityException e)
+ {
+ // This is and expected, acceptable exception that we can ignore.
+ }
+ catch (ClassNotFoundException e)
+ {
+ // This is and expected, acceptable exception that we can ignore.
+ }
+ catch (InstantiationException e)
+ {
+ // This is and expected, acceptable exception that we can ignore.
+ }
+ catch (IllegalAccessException e)
+ {
+ // This is and expected, acceptable exception that we can ignore.
+ }
+ catch (NoSuchMethodException e)
+ {
+ throw new AlfrescoRuntimeException(ERR_UNEXPECTED_ERROR, e);
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw new AlfrescoRuntimeException(ERR_UNEXPECTED_ERROR, e);
+ }
+ catch (InvocationTargetException e)
+ {
+ // This is and expected, acceptable exception that we can ignore.
+ }
+
+ return false;
+ }
+
+ /**
+ * Bootstrap unserializer validator.
+ */
+ public void bootstrap()
+ {
+ if (classInPath("org.apache.xalan.xsltc.trax.TemplatesImpl") && classInPath("org.springframework.core.SerializableTypeWrapper"))
+ {
+ throw new AlfrescoRuntimeException(
+ "Bootstrap failed: both org.apache.xalan.xsltc.trax.TemplatesImpl and org.springframework.core.SerializableTypeWrapper appear at the same time in classpath ");
+ }
+
+ // Check if Java unserialize remote code execution is available and not
+ // fixed on this commons collections
+ if ((classInPath("org.apache.commons.collections.functors.InvokerTransformer")
+ || classInPath("org.apache.commons.collections.functors.InstantiateFactory")
+ || classInPath("org.apache.commons.collections.functors.InstantiateTransformer")
+ || classInPath("org.apache.commons.collections.functors.PrototypeCloneFactory")
+ || classInPath("org.apache.commons.collections.functors.PrototypeSerializationFactory")
+ || classInPath("org.apache.commons.collections.functors.WhileClosure")
+ || classInPath("org.apache.commons.collections.functors.CloneTransformer") || classInPath("org.apache.commons.collections.functors.ForClosure"))
+ && !isCommonsCollectionsDeserializerFixed())
+ {
+ throw new AlfrescoRuntimeException(
+ "Bootstrap failed: org.apache.commons.collections.functors.* unsafe serialization classes found in classpath.");
+ }
+
+ // a bootstrap was performed
+ bootstrapPerformed = true;
+ }
+
+ @Override
+ protected void onBootstrap(ApplicationEvent event)
+ {
+ bootstrap();
+ }
+
+ @Override
+ protected void onShutdown(ApplicationEvent event)
+ {
+ // NOOP
+ }
+
+}