diff --git a/source/java/org/alfresco/repo/action/executer/ImporterActionExecuter.java b/source/java/org/alfresco/repo/action/executer/ImporterActionExecuter.java index 5d46ff5fbf..c47e36d7bc 100644 --- a/source/java/org/alfresco/repo/action/executer/ImporterActionExecuter.java +++ b/source/java/org/alfresco/repo/action/executer/ImporterActionExecuter.java @@ -69,6 +69,7 @@ public class ImporterActionExecuter extends ActionExecuterAbstractBase public static final String NAME = "import"; public static final String PARAM_ENCODING = "encoding"; public static final String PARAM_DESTINATION_FOLDER = "destination"; + public static final String ARCHIVE_CONTAINS_SUSPICIOUS_PATHS_ERROR = "Archive contains suspicious paths. Please review it's contents and make sure it doesn't contain entries with absolute paths or paths containing references to the parent folder (i.e. \"..\")"; private static final int BUFFER_SIZE = 16384; private static final String TEMP_FILE_PREFIX = "alf"; @@ -348,6 +349,12 @@ public class ImporterActionExecuter extends ActionExecuterAbstractBase { fileName = entry.getName(); fileName = fileName.replace('/', File.separatorChar); + + if (fileName.startsWith("/") || fileName.indexOf(":" + File.separator) == 1 || fileName.contains(".." + File.separator)) + { + throw new AlfrescoRuntimeException(ARCHIVE_CONTAINS_SUSPICIOUS_PATHS_ERROR); + } + destFileName = extractDir + fileName; File destFile = new File(destFileName); String parent = destFile.getParent(); diff --git a/source/test-java/org/alfresco/repo/action/ActionTestSuite.java b/source/test-java/org/alfresco/repo/action/ActionTestSuite.java index 383512eaa0..28a41fc511 100644 --- a/source/test-java/org/alfresco/repo/action/ActionTestSuite.java +++ b/source/test-java/org/alfresco/repo/action/ActionTestSuite.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2013 Alfresco Software Limited. + * Copyright (C) 2005-2015 Alfresco Software Limited. * * This file is part of Alfresco * @@ -25,6 +25,7 @@ import org.alfresco.repo.action.evaluator.IsSubTypeEvaluatorTest; import org.alfresco.repo.action.executer.AddFeaturesActionExecuterTest; import org.alfresco.repo.action.executer.ContentMetadataEmbedderTest; import org.alfresco.repo.action.executer.ContentMetadataExtracterTest; +import org.alfresco.repo.action.executer.ImporterActionExecuterTest; import org.alfresco.repo.action.executer.MailActionExecuterTest; import org.alfresco.repo.action.executer.RemoveFeaturesActionExecuterTest; import org.alfresco.repo.action.executer.SetPropertyValueActionExecuterTest; @@ -67,6 +68,7 @@ import org.junit.runners.Suite.SuiteClasses; ActionTrackingServiceImplTest.class, // intermittent - pending ALF-9773 & ALF-9774 MailActionExecuterTest.class, ActionServiceImpl2Test.class, + ImporterActionExecuterTest.class }) public class ActionTestSuite { diff --git a/source/test-java/org/alfresco/repo/action/executer/ImporterActionExecuterTest.java b/source/test-java/org/alfresco/repo/action/executer/ImporterActionExecuterTest.java new file mode 100644 index 0000000000..a78736ceda --- /dev/null +++ b/source/test-java/org/alfresco/repo/action/executer/ImporterActionExecuterTest.java @@ -0,0 +1,119 @@ +/* + * 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.action.executer; + +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.io.File; +import java.io.IOException; + +import org.alfresco.error.AlfrescoRuntimeException; +import org.alfresco.model.ContentModel; +import org.alfresco.repo.action.ActionImpl; +import org.alfresco.repo.content.MimetypeMap; +import org.alfresco.repo.security.authentication.AuthenticationUtil; +import org.alfresco.repo.transaction.RetryingTransactionHelper; +import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback; +import org.alfresco.service.ServiceRegistry; +import org.alfresco.service.cmr.action.Action; +import org.alfresco.service.cmr.repository.ContentData; +import org.alfresco.service.cmr.repository.ContentService; +import org.alfresco.service.cmr.repository.NodeRef; +import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.service.cmr.repository.StoreRef; +import org.alfresco.service.namespace.QName; +import org.alfresco.util.GUID; +import org.alfresco.util.test.junitrules.ApplicationContextInit; +import org.junit.Test; + +/** + * This class contains tests for {@link ImporterActionExecuter}. + * + * @author abalmus + */ +public class ImporterActionExecuterTest +{ + @Test + public void testImportArchiveWithSuspiciousPaths() throws IOException + { + final ApplicationContextInit applicationContextInit = new ApplicationContextInit(); + final ServiceRegistry serviceRegistry = (ServiceRegistry) applicationContextInit.getApplicationContext().getBean(ServiceRegistry.SERVICE_REGISTRY); + final NodeService nodeService = serviceRegistry.getNodeService(); + final ContentService contentService = serviceRegistry.getContentService(); + final RetryingTransactionHelper retryingTransactionHelper = serviceRegistry.getTransactionService().getRetryingTransactionHelper(); + + final File file = new File("./source/test-resources/import-archive-test/SuspiciousPathsArchive.zip"); + + retryingTransactionHelper.doInTransaction(new RetryingTransactionCallback() + { + public Void execute() + { + AuthenticationUtil.setRunAsUserSystem(); + + StoreRef storeRef = nodeService.createStore(StoreRef.PROTOCOL_WORKSPACE, "Test_" + System.nanoTime()); + + NodeRef rootNodeRef = nodeService.getRootNode(storeRef); + + NodeRef zipFileNodeRef = nodeService.createNode(rootNodeRef, ContentModel.ASSOC_CHILDREN, + QName.createQName("http://www.alfresco.org/test/ImporterActionExecuterTest", "testAssocQName1"), + ContentModel.TYPE_CONTENT).getChildRef(); + + NodeRef targetFolderNodeRef = nodeService.createNode(rootNodeRef, ContentModel.ASSOC_CHILDREN, + QName.createQName("http://www.alfresco.org/test/ImporterActionExecuterTest", "testAssocQName2"), + ContentModel.TYPE_FOLDER).getChildRef(); + + contentService.getWriter(zipFileNodeRef, ContentModel.PROP_CONTENT, true).putContent(file); + + ContentData contentData = (ContentData) nodeService.getProperty(zipFileNodeRef, ContentModel.PROP_CONTENT); + ContentData newContentData = ContentData.setMimetype(contentData, MimetypeMap.MIMETYPE_ZIP); + + nodeService.setProperty(zipFileNodeRef, ContentModel.PROP_CONTENT, newContentData); + + Action action = new ActionImpl(zipFileNodeRef, GUID.generate(), "ImporterActionExecuterTestActionDefinition"); + action.setParameterValue(ImporterActionExecuter.PARAM_DESTINATION_FOLDER, targetFolderNodeRef); + action.setParameterValue(ImporterActionExecuter.PARAM_ENCODING, "UTF-8"); + + ImporterActionExecuter executer = new ImporterActionExecuter(); + executer.setNodeService(nodeService); + executer.setContentService(contentService); + + try + { + executer.execute(action, zipFileNodeRef); + fail("An AlfrescoRuntimeException should have occured."); + } + catch (AlfrescoRuntimeException e) + { + assertTrue(e.getMessage().contains(ImporterActionExecuter.ARCHIVE_CONTAINS_SUSPICIOUS_PATHS_ERROR)); + } + finally + { + nodeService.deleteNode(targetFolderNodeRef); + nodeService.deleteNode(zipFileNodeRef); + nodeService.deleteStore(storeRef); + + AuthenticationUtil.clearCurrentSecurityContext(); + } + + return null; + } + }); + } +} diff --git a/source/test-resources/import-archive-test/SuspiciousPathsArchive.zip b/source/test-resources/import-archive-test/SuspiciousPathsArchive.zip new file mode 100644 index 0000000000..a0456d3f0f Binary files /dev/null and b/source/test-resources/import-archive-test/SuspiciousPathsArchive.zip differ