diff options
author | andre.schmid <andre.schmid@est.tech> | 2019-09-27 13:27:11 +0100 |
---|---|---|
committer | Ofir Sonsino <ofir.sonsino@intl.att.com> | 2019-10-30 09:47:54 +0000 |
commit | bf5eeb23a769a2e2b75f432b74f10fdbcfd2f161 (patch) | |
tree | fa27998ee6efef6f7651315cbf71271130fca025 /openecomp-be | |
parent | 19773b769c6762a12876064c70a34cc31d2b12da (diff) |
Fix zip slip security flaw
Apply zip slip checking in zip operations throughout the system.
Centralizes most of the zip logic in one class. Create tests to zip
functionalities and zip slip problem.
Change-Id: I721f3d44b34fe6d242c9537f5a515ce1bb534c9a
Issue-ID: SDC-1401
Signed-off-by: andre.schmid <andre.schmid@est.tech>
Diffstat (limited to 'openecomp-be')
17 files changed, 249 insertions, 390 deletions
diff --git a/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/main/java/org/openecomp/sdcrests/vsp/rest/data/PackageArchive.java b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/main/java/org/openecomp/sdcrests/vsp/rest/data/PackageArchive.java index 97bc375eb8..4f4258ad53 100644 --- a/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/main/java/org/openecomp/sdcrests/vsp/rest/data/PackageArchive.java +++ b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/main/java/org/openecomp/sdcrests/vsp/rest/data/PackageArchive.java @@ -19,7 +19,6 @@ */ package org.openecomp.sdcrests.vsp.rest.data; -import java.io.IOException; import java.security.cert.CertificateException; import java.util.List; import java.util.Map; @@ -29,6 +28,7 @@ import org.apache.commons.lang3.tuple.Pair; import org.apache.cxf.jaxrs.ext.multipart.Attachment; import org.openecomp.core.utilities.file.FileContentHandler; import org.openecomp.sdc.common.utils.CommonUtil; +import org.openecomp.sdc.common.zip.exception.ZipException; import org.openecomp.sdc.logging.api.Logger; import org.openecomp.sdc.logging.api.LoggerFactory; import org.openecomp.sdc.vendorsoftwareproduct.security.SecurityManager; @@ -61,7 +61,7 @@ public class PackageArchive { try { handlerPair = CommonUtil.getFileContentMapFromOrchestrationCandidateZip( outerPackageFileBytes); - } catch (IOException exception) { + } catch (final ZipException exception) { LOG.error("Error reading files inside archive", exception); } } diff --git a/openecomp-be/backend/openecomp-sdc-validation-manager/src/main/java/org/openecomp/sdc/validation/impl/UploadValidationManagerImpl.java b/openecomp-be/backend/openecomp-sdc-validation-manager/src/main/java/org/openecomp/sdc/validation/impl/UploadValidationManagerImpl.java index 42c77b96d8..90f8ad369b 100644 --- a/openecomp-be/backend/openecomp-sdc-validation-manager/src/main/java/org/openecomp/sdc/validation/impl/UploadValidationManagerImpl.java +++ b/openecomp-be/backend/openecomp-sdc-validation-manager/src/main/java/org/openecomp/sdc/validation/impl/UploadValidationManagerImpl.java @@ -20,7 +20,11 @@ package org.openecomp.sdc.validation.impl; -import org.apache.commons.collections4.CollectionUtils; +import java.io.IOException; +import java.io.InputStream; +import java.util.List; +import java.util.Map; +import java.util.Objects; import org.apache.commons.collections4.MapUtils; import org.openecomp.core.utilities.file.FileContentHandler; import org.openecomp.core.utilities.file.FileUtils; @@ -30,6 +34,8 @@ import org.openecomp.sdc.common.errors.ErrorCategory; import org.openecomp.sdc.common.errors.ErrorCode; import org.openecomp.sdc.common.errors.Messages; import org.openecomp.sdc.common.utils.SdcCommon; +import org.openecomp.sdc.common.zip.ZipUtils; +import org.openecomp.sdc.common.zip.exception.ZipException; import org.openecomp.sdc.datatypes.error.ErrorMessage; import org.openecomp.sdc.heat.datatypes.structure.ValidationStructureList; import org.openecomp.sdc.heat.services.tree.HeatTreeManager; @@ -38,79 +44,35 @@ import org.openecomp.sdc.validation.UploadValidationManager; import org.openecomp.sdc.validation.types.ValidationFileResponse; import org.openecomp.sdc.validation.util.ValidationManagerUtil; -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.zip.ZipEntry; -import java.util.zip.ZipInputStream; - /** * Created by TALIO on 4/20/2016. */ public class UploadValidationManagerImpl implements UploadValidationManager { - private static FileContentHandler getFileContentMapFromZip(byte[] uploadFileData) - throws IOException, CoreException { - - ZipEntry zipEntry; - List<String> folderList = new ArrayList<>(); - FileContentHandler mapFileContent = new FileContentHandler(); - try (ZipInputStream inputZipStream = new ZipInputStream(new ByteArrayInputStream(uploadFileData))) { - - byte[] fileByteContent; - String currentEntryName; - - while ((zipEntry = inputZipStream.getNextEntry()) != null) { - currentEntryName = zipEntry.getName(); - // else, get the file content (as byte array) and save it in a map. - fileByteContent = FileUtils.toByteArray(inputZipStream); - - int index = lastIndexFileSeparatorIndex(currentEntryName); - String currSubstringWithoutSeparator = - currentEntryName.substring(index + 1, currentEntryName.length()); - if (index != -1) { - if (currSubstringWithoutSeparator.length() > 0) { - mapFileContent.addFile(currentEntryName.substring(index + 1, currentEntryName.length()), - fileByteContent); - } else { - folderList.add(currentEntryName); - } - } else { - mapFileContent.addFile(currentEntryName, fileByteContent); - } - } - } catch (RuntimeException exception) { - throw new IOException(exception); + + private static FileContentHandler getFileContentMapFromZip(byte[] uploadFileData) throws IOException { + final Map<String, byte[]> zipFileAndByteMap; + try { + zipFileAndByteMap = ZipUtils.readZip(uploadFileData, true); + } catch (final ZipException e) { + throw new IOException(e); } - if (CollectionUtils.isNotEmpty(folderList)) { + final boolean zipHasFolders = zipFileAndByteMap.values().stream().anyMatch(Objects::isNull); + if (zipHasFolders) { throw new CoreException((new ErrorCode.ErrorCodeBuilder()) .withMessage(Messages.ZIP_SHOULD_NOT_CONTAIN_FOLDERS.getErrorMessage()) .withId(Messages.ZIP_SHOULD_NOT_CONTAIN_FOLDERS.getErrorMessage()) .withCategory(ErrorCategory.APPLICATION).build()); - } + final FileContentHandler mapFileContent = new FileContentHandler(); + zipFileAndByteMap.entrySet().stream() + .filter(entry -> entry.getValue() != null) + .forEach(zipEntry -> mapFileContent.addFile(zipEntry.getKey(), zipEntry.getValue())); return mapFileContent; } - private static int lastIndexFileSeparatorIndex(String filePath) { - int length = filePath.length() - 1; - - for (int i = length; i >= 0; i--) { - char currChar = filePath.charAt(i); - if (currChar == '/' || currChar == File.separatorChar || currChar == File.pathSeparatorChar) { - return i; - } - } - // if we've reached to the start of the string and didn't find file separator - return -1 - return -1; - } - @Override public ValidationFileResponse validateFile(String type, InputStream fileToValidate) throws IOException { diff --git a/openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/impl/orchestration/OrchestrationTemplateCSARHandler.java b/openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/impl/orchestration/OrchestrationTemplateCSARHandler.java index 61d1799aa0..8f0029aa83 100644 --- a/openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/impl/orchestration/OrchestrationTemplateCSARHandler.java +++ b/openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/impl/orchestration/OrchestrationTemplateCSARHandler.java @@ -32,6 +32,7 @@ import org.openecomp.sdc.common.errors.CoreException; import org.openecomp.sdc.common.errors.Messages; import org.openecomp.sdc.common.utils.CommonUtil; import org.openecomp.sdc.common.utils.SdcCommon; +import org.openecomp.sdc.common.zip.exception.ZipException; import org.openecomp.sdc.datatypes.error.ErrorLevel; import org.openecomp.sdc.datatypes.error.ErrorMessage; import org.openecomp.sdc.vendorsoftwareproduct.dao.type.OrchestrationTemplateCandidateData; @@ -58,7 +59,7 @@ public class OrchestrationTemplateCSARHandler extends BaseOrchestrationTemplateH folderList = fileContentMapFromOrchestrationCandidateZip.getRight(); Validator validator = ValidatorFactory.getValidator(contentMap); uploadFileResponse.addStructureErrors(validator.validateContent(contentMap, folderList)); - } catch (IOException exception) { + } catch (final ZipException | IOException exception) { logger.error(exception.getMessage(), exception); uploadFileResponse.addStructureError( SdcCommon.UPLOAD_FILE, diff --git a/openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/test/java/org/openecomp/sdc/vendorsoftwareproduct/upload/csar/UploadCSARFileTest.java b/openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/test/java/org/openecomp/sdc/vendorsoftwareproduct/upload/csar/UploadCSARFileTest.java index 122809896e..7a183c0dbb 100644 --- a/openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/test/java/org/openecomp/sdc/vendorsoftwareproduct/upload/csar/UploadCSARFileTest.java +++ b/openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/test/java/org/openecomp/sdc/vendorsoftwareproduct/upload/csar/UploadCSARFileTest.java @@ -18,7 +18,9 @@ package org.openecomp.sdc.vendorsoftwareproduct.upload.csar; import static junit.framework.TestCase.assertTrue; +import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doReturn; @@ -161,7 +163,7 @@ public class UploadCSARFileTest { onboardPackageInfo = new OnboardPackageInfo(csarFileName, OnboardingTypesEnum.CSAR.toString(), convertFileInputStream(inputStream)); uploadFileResponse = candidateManager.upload(vspDetails, onboardPackageInfo); - assertEquals(expectedErrorsNumber, uploadFileResponse.getErrors().size()); + assertThat(String.format("Expecting %s error(s) in file '%s'", expectedErrorsNumber, csarFileName), uploadFileResponse.getErrors().size(), is(expectedErrorsNumber)); } return uploadFileResponse; } diff --git a/openecomp-be/lib/openecomp-common-lib/src/main/java/org/openecomp/sdc/common/utils/CommonUtil.java b/openecomp-be/lib/openecomp-common-lib/src/main/java/org/openecomp/sdc/common/utils/CommonUtil.java index ae7d44efd8..8610ecb74b 100644 --- a/openecomp-be/lib/openecomp-common-lib/src/main/java/org/openecomp/sdc/common/utils/CommonUtil.java +++ b/openecomp-be/lib/openecomp-common-lib/src/main/java/org/openecomp/sdc/common/utils/CommonUtil.java @@ -20,62 +20,50 @@ package org.openecomp.sdc.common.utils; import com.google.common.collect.Multimap; - +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.io.FilenameUtils; import org.apache.commons.lang3.tuple.ImmutablePair; import org.apache.commons.lang3.tuple.Pair; import org.openecomp.core.utilities.file.FileContentHandler; -import org.openecomp.core.utilities.file.FileUtils; import org.openecomp.core.utilities.orchestration.OnboardingTypesEnum; import org.openecomp.sdc.common.errors.CoreException; import org.openecomp.sdc.common.errors.ErrorCategory; import org.openecomp.sdc.common.errors.ErrorCode; import org.openecomp.sdc.common.errors.Messages; - -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.IOException; -import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; -import java.util.zip.ZipEntry; -import java.util.zip.ZipException; -import java.util.zip.ZipInputStream; +import org.openecomp.sdc.common.zip.ZipUtils; +import org.openecomp.sdc.common.zip.exception.ZipException; public class CommonUtil { - static final String DEFAULT = "default"; - static final String _DEFAULT = "_default"; private CommonUtil() { // prevent instantiation } - public static FileContentHandler validateAndUploadFileContent(OnboardingTypesEnum type, - byte[] uploadedFileData) - throws IOException { - return getFileContentMapFromOrchestrationCandidateZipAndValidateNoFolders(type, - uploadedFileData); - } - /** - * Gets files out of the zip AND validates zip is flat (no folders) + * Reads the files from the zip AND validates zip is flat (no folders). * - * @param uploadFileData zip file + * @param type the onboarding type + * @param uploadedFileData zip file bytes * @return FileContentHandler if input is valid and has no folders + * @throws IOException when the zip could not be read */ - private static FileContentHandler getFileContentMapFromOrchestrationCandidateZipAndValidateNoFolders( - OnboardingTypesEnum type, byte[] uploadFileData) - throws IOException { - Pair<FileContentHandler, List<String>> pair = - getFileContentMapFromOrchestrationCandidateZip(uploadFileData); - + public static FileContentHandler validateAndUploadFileContent(final OnboardingTypesEnum type, + final byte[] uploadedFileData) throws IOException { + final Pair<FileContentHandler, List<String>> pair; + try { + pair = getFileContentMapFromOrchestrationCandidateZip(uploadedFileData); + } catch (final ZipException e) { + throw new IOException(e); + } if (isFileOriginFromZip(type.toString())) { validateNoFolders(pair.getRight()); } @@ -84,47 +72,22 @@ public class CommonUtil { } public static Pair<FileContentHandler, List<String>> getFileContentMapFromOrchestrationCandidateZip( - byte[] uploadFileData) - throws IOException { - ZipEntry zipEntry; - List<String> folderList = new ArrayList<>(); - FileContentHandler mapFileContent = new FileContentHandler(); - try (ByteArrayInputStream in = new ByteArrayInputStream(uploadFileData); - ZipInputStream inputZipStream = new ZipInputStream(in)) { - byte[] fileByteContent; - String currentEntryName; - - while ((zipEntry = inputZipStream.getNextEntry()) != null) { - assertEntryNotVulnerable(zipEntry); - currentEntryName = zipEntry.getName(); - fileByteContent = FileUtils.toByteArray(inputZipStream); - - int index = lastIndexFileSeparatorIndex(currentEntryName); - if (index != -1) { - folderList.add(currentEntryName); - } - if (isFile(currentEntryName)) { - mapFileContent.addFile(currentEntryName, fileByteContent); - } + byte[] uploadFileData) throws ZipException { + final Map<String, byte[]> zipFileMap = ZipUtils.readZip(uploadFileData, true); + final List<String> folderList = new ArrayList<>(); + final FileContentHandler mapFileContent = new FileContentHandler(); + + zipFileMap.forEach((key, value) -> { + if (value == null) { + folderList.add(key); + } else { + mapFileContent.addFile(key, value); } - - } catch (RuntimeException exception) { - throw new IOException(exception); - } + }); return new ImmutablePair<>(mapFileContent, folderList); } - private static void assertEntryNotVulnerable(ZipEntry entry) throws ZipException { - if (entry.getName().contains("../")) { - throw new ZipException("Path traversal attempt discovered."); - } - } - - private static boolean isFile(String currentEntryName) { - return !(currentEntryName.endsWith("\\") || currentEntryName.endsWith("/")); - } - private static void validateNoFolders(List<String> folderList) { if (CollectionUtils.isNotEmpty(folderList)) { throw new CoreException((new ErrorCode.ErrorCodeBuilder()) @@ -134,19 +97,6 @@ public class CommonUtil { } } - private static int lastIndexFileSeparatorIndex(String filePath) { - int length = filePath.length() - 1; - - for (int i = length; i >= 0; i--) { - char currChar = filePath.charAt(i); - if (currChar == '/' || currChar == File.separatorChar || currChar == File.pathSeparatorChar) { - return i; - } - } - // if we've reached to the start of the string and didn't find file separator - return -1 - return -1; - } - private static boolean validateFilesExtensions(Set<String> allowedExtensions, FileContentHandler files) { for (String fileName : files.getFileList()) { diff --git a/openecomp-be/lib/openecomp-common-lib/src/test/java/org/openecomp/sdc/common/utils/CommonUtilTest.java b/openecomp-be/lib/openecomp-common-lib/src/test/java/org/openecomp/sdc/common/utils/CommonUtilTest.java index bc0bd137a0..119616a9be 100644 --- a/openecomp-be/lib/openecomp-common-lib/src/test/java/org/openecomp/sdc/common/utils/CommonUtilTest.java +++ b/openecomp-be/lib/openecomp-common-lib/src/test/java/org/openecomp/sdc/common/utils/CommonUtilTest.java @@ -16,23 +16,21 @@ package org.openecomp.sdc.common.utils; -import org.testng.annotations.Test; +import static org.onap.sdc.tosca.services.CommonUtil.DEFAULT; +import static org.onap.sdc.tosca.services.CommonUtil.UNDERSCORE_DEFAULT; +import static org.testng.Assert.assertTrue; import java.util.HashMap; import java.util.Map; - -import static org.testng.Assert.assertTrue; +import org.testng.annotations.Test; public class CommonUtilTest { @Test public void testGetObjectAsMap() { - Map<String, String> obj = new HashMap<>(1); - obj.put(CommonUtil.DEFAULT, ""); - Map<String, Object> newMap = CommonUtil.getObjectAsMap(obj); - - boolean exists = newMap.containsKey(CommonUtil._DEFAULT); - - assertTrue(exists); + final Map<String, String> obj = new HashMap<>(1); + obj.put(DEFAULT, ""); + assertTrue(CommonUtil.getObjectAsMap(obj).containsKey(UNDERSCORE_DEFAULT)); } + } diff --git a/openecomp-be/lib/openecomp-core-lib/openecomp-utilities-lib/pom.xml b/openecomp-be/lib/openecomp-core-lib/openecomp-utilities-lib/pom.xml index ce88037706..b86964f61f 100644 --- a/openecomp-be/lib/openecomp-core-lib/openecomp-utilities-lib/pom.xml +++ b/openecomp-be/lib/openecomp-core-lib/openecomp-utilities-lib/pom.xml @@ -66,6 +66,18 @@ <version>${commons.codec.version}</version> </dependency> <dependency> + <groupId>org.hamcrest</groupId> + <artifactId>hamcrest</artifactId> + <version>${hamcrest.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.hamcrest</groupId> + <artifactId>hamcrest-library</artifactId> + <version>${hamcrest.version}</version> + <scope>test</scope> + </dependency> + <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <scope>test</scope> @@ -85,6 +97,12 @@ <artifactId>openecomp-sdc-logging-api</artifactId> <version>${project.version}</version> </dependency> + <dependency> + <groupId>org.openecomp.sdc</groupId> + <artifactId>common-app-api</artifactId> + <version>${project.version}</version> + <scope>compile</scope> + </dependency> </dependencies> </project> diff --git a/openecomp-be/lib/openecomp-core-lib/openecomp-utilities-lib/src/main/java/org/openecomp/core/utilities/file/FileUtils.java b/openecomp-be/lib/openecomp-core-lib/openecomp-utilities-lib/src/main/java/org/openecomp/core/utilities/file/FileUtils.java index c807d1b979..31338dcda4 100644 --- a/openecomp-be/lib/openecomp-core-lib/openecomp-utilities-lib/src/main/java/org/openecomp/core/utilities/file/FileUtils.java +++ b/openecomp-be/lib/openecomp-core-lib/openecomp-utilities-lib/src/main/java/org/openecomp/core/utilities/file/FileUtils.java @@ -16,11 +16,6 @@ package org.openecomp.core.utilities.file; -import org.apache.commons.io.FilenameUtils; -import org.apache.commons.io.IOUtils; -import org.onap.sdc.tosca.services.YamlUtil; -import org.openecomp.core.utilities.json.JsonUtil; - import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileOutputStream; @@ -28,11 +23,20 @@ import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.nio.file.Path; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Objects; import java.util.function.Function; -import java.util.zip.ZipEntry; -import java.util.zip.ZipException; -import java.util.zip.ZipInputStream; -import java.util.*; +import org.apache.commons.io.FilenameUtils; +import org.apache.commons.io.IOUtils; +import org.onap.sdc.tosca.services.YamlUtil; +import org.openecomp.core.utilities.json.JsonUtil; +import org.openecomp.sdc.common.zip.ZipUtils; +import org.openecomp.sdc.common.zip.exception.ZipException; /** * The type File utils. @@ -220,26 +224,14 @@ public class FileUtils { * * @param zipData the zip data * @return the file content map from zip - * @throws IOException the io exception + * @throws ZipException when an error occurs while extracting zip files */ - public static FileContentHandler getFileContentMapFromZip(byte[] zipData) throws IOException { - - try (ZipInputStream inputZipStream = new ZipInputStream(new ByteArrayInputStream(zipData))) { - - FileContentHandler mapFileContent = new FileContentHandler(); - - ZipEntry zipEntry; - - while ((zipEntry = inputZipStream.getNextEntry()) != null) { - assertEntryNotVulnerable(zipEntry); - mapFileContent.addFile(zipEntry.getName(), FileUtils.toByteArray(inputZipStream)); - } - - return mapFileContent; - - } catch (RuntimeException exception) { - throw new IOException(exception); - } + public static FileContentHandler getFileContentMapFromZip(byte[] zipData) + throws ZipException { + final Map<String, byte[]> zipFileAndByteMap = ZipUtils.readZip(zipData, true); + final FileContentHandler mapFileContent = new FileContentHandler(); + mapFileContent.setFiles(zipFileAndByteMap); + return mapFileContent; } @@ -286,20 +278,28 @@ public class FileUtils { * @return a map containing file names and their absolute paths * @throws IOException the io exception */ - public static Map<String, String> writeFilesFromFileContentHandler(FileContentHandler - fileContentHandler, - Path dir) - throws IOException { - + public static Map<String, String> writeFilesFromFileContentHandler(final FileContentHandler fileContentHandler, + final Path dir) throws IOException { File file; - File dirFile = dir.toFile(); - Map<String, String> filePaths = new HashMap<>(); - for (Map.Entry<String, byte[]> fileEntry : fileContentHandler.getFiles().entrySet()) { + final File dirFile = dir.toFile(); + final Map<String, String> filePaths = new HashMap<>(); + for (final Map.Entry<String, byte[]> fileEntry : fileContentHandler.getFiles().entrySet()) { file = new File(dirFile, fileEntry.getKey()); - file.getParentFile().mkdirs(); filePaths.put(fileEntry.getKey(), file.getAbsolutePath()); - try (FileOutputStream fop = new FileOutputStream(file.getAbsolutePath());) { - fop.write(fileEntry.getValue()); + final byte[] fileBytes = fileEntry.getValue(); + if (fileBytes == null) { + if (!file.exists() && !file.mkdirs()) { + throw new IOException("Could not create directory " + file.getAbsolutePath()); + } + continue; + } else { + if (!file.getParentFile().exists() && !file.getParentFile().mkdirs()) { + throw new IOException("Could not create parent directory for " + file.getAbsolutePath()); + } + } + + try (final FileOutputStream fop = new FileOutputStream(file.getAbsolutePath());) { + fop.write(fileBytes); fop.flush(); } } @@ -318,10 +318,4 @@ public class FileUtils { fileExtension.equalsIgnoreCase(FileExtension.YAML.getDisplayName()); } - private static void assertEntryNotVulnerable(ZipEntry entry) throws ZipException { - if (entry.getName().contains("../")) { - throw new ZipException("Path traversal attempt discovered."); - } - } - } diff --git a/openecomp-be/lib/openecomp-core-lib/openecomp-utilities-lib/src/test/java/org/openecomp/core/utilities/file/FileUtilsTest.java b/openecomp-be/lib/openecomp-core-lib/openecomp-utilities-lib/src/test/java/org/openecomp/core/utilities/file/FileUtilsTest.java index a4928ac739..facfe57622 100644 --- a/openecomp-be/lib/openecomp-core-lib/openecomp-utilities-lib/src/test/java/org/openecomp/core/utilities/file/FileUtilsTest.java +++ b/openecomp-be/lib/openecomp-core-lib/openecomp-utilities-lib/src/test/java/org/openecomp/core/utilities/file/FileUtilsTest.java @@ -17,8 +17,12 @@ package org.openecomp.core.utilities.file; import static junit.framework.TestCase.assertTrue; -import static org.junit.Assert.assertEquals; +import static org.hamcrest.Matchers.aMapWithSize; +import static org.hamcrest.Matchers.anEmptyMap; +import static org.hamcrest.Matchers.not; +import static org.hamcrest.core.Is.is; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertThat; import java.io.File; import java.io.IOException; @@ -34,6 +38,7 @@ import java.util.stream.Stream; import org.apache.commons.io.IOUtils; import org.junit.Assert; import org.junit.Test; +import org.openecomp.sdc.common.zip.exception.ZipException; /** * @author EVITALIY @@ -74,25 +79,22 @@ public class FileUtilsTest { } @Test - public void testWriteFilesFromFileContentHandler() throws IOException { - Path dir = Files.createTempDirectory("CSAR_" + System.currentTimeMillis()); + public void testWriteFilesFromFileContentHandler() throws IOException, ZipException { + final Path tempDirectory = Files.createTempDirectory("CSAR_" + System.currentTimeMillis()); try { - byte[] uploadedFileData = IOUtils.toByteArray( - FileUtilsTest.class.getResource("resource-Spgw-csar-ZTE" + - ".csar")); - FileContentHandler contentMap = FileUtils.getFileContentMapFromZip(uploadedFileData); - Map<String, String> filePaths = FileUtils.writeFilesFromFileContentHandler(contentMap, - dir); - - assertFalse(filePaths.isEmpty()); - assertEquals(filePaths.size(), 18); - for (Map.Entry<String, String> fileEntry : filePaths.entrySet()) { - File f = new File(fileEntry.getValue()); - assertTrue(f.exists()); + byte[] uploadedFileData = + IOUtils.toByteArray(FileUtilsTest.class.getResource("resource-Spgw-csar-ZTE.csar")); + final FileContentHandler contentMap = FileUtils.getFileContentMapFromZip(uploadedFileData); + final Map<String, String> filePaths = FileUtils.writeFilesFromFileContentHandler(contentMap, tempDirectory); + + assertThat("The file map should not be empty", filePaths, is(not(anEmptyMap()))); + assertThat("The file map should have size 20", filePaths, is(aMapWithSize(20))); + for (final Map.Entry<String, String> fileEntry : filePaths.entrySet()) { + final File f = new File(fileEntry.getValue()); + assertThat(String.format("The file '%s' is expected to", f.getAbsolutePath()), f.exists(), is(true)); } - } - finally { - org.apache.commons.io.FileUtils.deleteDirectory(dir.toFile()); + } finally { + org.apache.commons.io.FileUtils.deleteDirectory(tempDirectory.toFile()); } } @@ -106,22 +108,22 @@ public class FileUtilsTest { @Test public void testGetFileWithoutExtention() { - Assert.assertEquals(FileUtils.getFileWithoutExtention("test.txt"), "test"); + Assert.assertEquals("test", FileUtils.getFileWithoutExtention("test.txt")); } @Test public void testGetFileWithoutExtentionContainsNoExtension() { - Assert.assertEquals(FileUtils.getFileWithoutExtention("test"), "test"); + Assert.assertEquals("test", FileUtils.getFileWithoutExtention("test")); } @Test public void testGetFileExtention() { - Assert.assertEquals(FileUtils.getFileExtension("test.txt"), "txt"); + Assert.assertEquals("txt", FileUtils.getFileExtension("test.txt")); } @Test public void testGetNetworkPackageName() { - Assert.assertEquals(FileUtils.getNetworkPackageName("heat.zip"), "heat"); + Assert.assertEquals("heat", FileUtils.getNetworkPackageName("heat.zip")); } @Test @@ -191,6 +193,6 @@ public class FileUtilsTest { } Assert.assertNotNull(inputStream); - Assert.assertEquals(builder.toString(), "hello-test"); + Assert.assertEquals("hello-test", builder.toString()); } } diff --git a/openecomp-be/lib/openecomp-sdc-enrichment-lib/openecomp-sdc-enrichment-impl/src/main/java/org/openecomp/sdc/enrichment/impl/external/artifact/MonitoringMibEnricher.java b/openecomp-be/lib/openecomp-sdc-enrichment-lib/openecomp-sdc-enrichment-impl/src/main/java/org/openecomp/sdc/enrichment/impl/external/artifact/MonitoringMibEnricher.java index dac9eae9ad..ca1fbe11b7 100644 --- a/openecomp-be/lib/openecomp-sdc-enrichment-lib/openecomp-sdc-enrichment-impl/src/main/java/org/openecomp/sdc/enrichment/impl/external/artifact/MonitoringMibEnricher.java +++ b/openecomp-be/lib/openecomp-sdc-enrichment-lib/openecomp-sdc-enrichment-impl/src/main/java/org/openecomp/sdc/enrichment/impl/external/artifact/MonitoringMibEnricher.java @@ -16,6 +16,19 @@ package org.openecomp.sdc.enrichment.impl.external.artifact; +import static org.openecomp.sdc.tosca.services.ToscaConstants.SERVICE_TEMPLATE_FILTER_PROPERTY_NAME; +import static org.openecomp.sdc.tosca.services.ToscaConstants.SUBSTITUTE_SERVICE_TEMPLATE_PROPERTY_NAME; + +import java.io.File; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; import org.onap.sdc.tosca.datatypes.model.Directive; import org.onap.sdc.tosca.datatypes.model.NodeTemplate; import org.onap.sdc.tosca.datatypes.model.ServiceTemplate; @@ -29,6 +42,7 @@ import org.openecomp.core.model.types.ServiceArtifact; import org.openecomp.core.utilities.file.FileContentHandler; import org.openecomp.core.utilities.file.FileUtils; import org.openecomp.sdc.common.errors.Messages; +import org.openecomp.sdc.common.zip.exception.ZipException; import org.openecomp.sdc.datatypes.error.ErrorLevel; import org.openecomp.sdc.datatypes.error.ErrorMessage; import org.openecomp.sdc.enrichment.EnrichmentInfo; @@ -45,13 +59,6 @@ import org.openecomp.sdc.vendorsoftwareproduct.dao.type.ComponentEntity; import org.openecomp.sdc.vendorsoftwareproduct.dao.type.ComponentMonitoringUploadEntity; import org.openecomp.sdc.versioning.dao.types.Version; -import java.io.File; -import java.io.IOException; -import java.util.*; - -import static org.openecomp.sdc.tosca.services.ToscaConstants.SERVICE_TEMPLATE_FILTER_PROPERTY_NAME; -import static org.openecomp.sdc.tosca.services.ToscaConstants.SUBSTITUTE_SERVICE_TEMPLATE_PROPERTY_NAME; - public class MonitoringMibEnricher implements ExternalArtifactEnricherInterface { private EnrichedServiceModelDao enrichedServiceModelDao; @@ -265,8 +272,8 @@ public class MonitoringMibEnricher implements ExternalArtifactEnricherInterface try { mibs = FileUtils .getFileContentMapFromZip(FileUtils.toByteArray(monitoringArtifactInfo.getContent())); - } catch (IOException ioException) { - log.error("Failed to get file content map from zip ", ioException); + } catch (ZipException ex) { + log.error("Failed to get file content map from zip ", ex); ErrorMessage.ErrorMessageUtil .addMessage(mibServiceArtifact.getName() + "." + type.name(), errors) .add(new ErrorMessage(ErrorLevel.ERROR, Messages.INVALID_ZIP_FILE.getErrorMessage())); diff --git a/openecomp-be/lib/openecomp-sdc-externaltesting-lib/openecomp-sdc-externaltesting-impl/src/main/java/org/openecomp/core/externaltesting/impl/ExternalTestingManagerImpl.java b/openecomp-be/lib/openecomp-sdc-externaltesting-lib/openecomp-sdc-externaltesting-impl/src/main/java/org/openecomp/core/externaltesting/impl/ExternalTestingManagerImpl.java index e112ef432c..22ac1e8ed8 100644 --- a/openecomp-be/lib/openecomp-sdc-externaltesting-lib/openecomp-sdc-externaltesting-impl/src/main/java/org/openecomp/core/externaltesting/impl/ExternalTestingManagerImpl.java +++ b/openecomp-be/lib/openecomp-sdc-externaltesting-lib/openecomp-sdc-externaltesting-impl/src/main/java/org/openecomp/core/externaltesting/impl/ExternalTestingManagerImpl.java @@ -18,17 +18,21 @@ package org.openecomp.core.externaltesting.impl; import com.amdocs.zusammen.utils.fileutils.json.JsonUtil; import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.common.collect.ImmutableSet; import com.google.gson.GsonBuilder; import com.google.gson.JsonObject; import com.google.gson.JsonParseException; +import java.util.Map.Entry; import lombok.EqualsAndHashCode; -import org.apache.commons.io.IOUtils; +import org.apache.commons.io.FilenameUtils; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.Pair; import org.onap.sdc.tosca.services.YamlUtil; import org.openecomp.core.externaltesting.api.*; import org.openecomp.core.externaltesting.errors.ExternalTestingException; +import org.openecomp.sdc.common.zip.ZipUtils; +import org.openecomp.sdc.common.zip.exception.ZipException; import org.openecomp.sdc.heat.datatypes.manifest.FileData; import org.openecomp.sdc.heat.datatypes.manifest.ManifestContent; import org.openecomp.sdc.vendorsoftwareproduct.OrchestrationTemplateCandidateManager; @@ -58,7 +62,6 @@ import java.util.*; import java.util.stream.Collectors; import java.util.stream.Stream; import java.util.zip.ZipEntry; -import java.util.zip.ZipInputStream; import java.util.zip.ZipOutputStream; public class ExternalTestingManagerImpl implements ExternalTestingManager { @@ -97,6 +100,8 @@ public class ExternalTestingManagerImpl implements ExternalTestingManager { private static final String SDC_CSAR = "sdc-csar"; private static final String SDC_HEAT = "sdc-heat"; + private final ImmutableSet<String> relevantArchiveFileExtensionSet = + ImmutableSet.of("yaml", "meta", "yml", "json", "env"); private VersioningManager versioningManager; @@ -721,10 +726,8 @@ public class ExternalTestingManagerImpl implements ExternalTestingManager { private void processArchive(final VtpTestExecutionRequest test, final MultiValueMap<String, Object> body, final byte[] zip) { // We need to make one pass through the zip input stream. Pull out files that match our expectations into a temporary - // map that we can process over. These are not huge files so we shouldn't need to worry about memory. - - List<String> extensions = Arrays.asList(".yaml", ".meta", ".yml", ".json", ".env"); - final Map<String, byte[]> contentWeCareAbout = extractRelevantContent(zip, extensions); + // map that we can process over. These are not huge files so we shouldn't need to worry about memory. + final Map<String, byte[]> contentWeCareAbout = extractRelevantContent(zip); // VTP does not support concurrent executions of the same test with the same associated file name. // It writes files to /tmp and if we were to send two requests with the same file, the results are unpredictable. @@ -891,34 +894,30 @@ public class ExternalTestingManagerImpl implements ExternalTestingManager { * @param zip csar/heat zip to iterate over * @return relevant content from the archive file as a map. */ - private Map<String, byte[]> extractRelevantContent(final byte[] zip, final List<String> extensions) { - final Map<String, byte[]> rv = new HashMap<>(); // FYI, rv = return value. - try (ByteArrayInputStream is = new ByteArrayInputStream(zip)) { - try (ZipInputStream zipStream = new ZipInputStream(is)) { - ZipEntry entry; - while ((entry = zipStream.getNextEntry()) != null) { - final String entryName = entry.getName(); - - // NOTE: leaving this debugging in for dublin... - logger.debug("archive contains entry {}", entryName); - - extractIfMatching(extensions, rv, zipStream, entryName); - } - } - } - catch (IOException ex) { - logger.error("error encountered processing archive", ex); - throw new ExternalTestingException(SDC_RESOLVER_ERR, 500, ex.getMessage()); + private Map<String, byte[]> extractRelevantContent(final byte[] zip) { + final Map<String, byte[]> zipFileAndByteMap; + try { + zipFileAndByteMap = ZipUtils.readZip(zip, false); + } catch (final ZipException ex) { + logger.error("An error occurred while processing archive", ex); + throw new ExternalTestingException(SDC_RESOLVER_ERR, 500, ex.getMessage(), ex); } - return rv; + + return zipFileAndByteMap.entrySet().stream() + .filter(stringEntry -> hasRelevantExtension(stringEntry.getKey())) + .collect(Collectors.toMap(Entry::getKey, Entry::getValue)); } - private void extractIfMatching(List<String> extensions, Map<String, byte[]> rv, ZipInputStream zipStream, String entryName) throws IOException { - int idx = entryName.lastIndexOf('.'); - if ((idx >= 0) && (extensions.contains(entryName.substring(idx)))) { - byte[] content = IOUtils.toByteArray(zipStream); - rv.put(entryName, content); - } + /** + * Checks if the file matches with a expected extension. + * + * @param filePath the file path + * @return {@code true} if the file extension matches with {@link #relevantArchiveFileExtensionSet}, {@code false} + * otherwise + */ + private boolean hasRelevantExtension(final String filePath) { + final String entryExtension = FilenameUtils.getExtension(filePath); + return StringUtils.isNotEmpty(entryExtension) && (relevantArchiveFileExtensionSet.contains(entryExtension)); } /** diff --git a/openecomp-be/lib/openecomp-sdc-externaltesting-lib/openecomp-sdc-externaltesting-impl/src/test/java/org/openecomp/core/externaltesting/impl/ExternalTestingManagerImplTest.java b/openecomp-be/lib/openecomp-sdc-externaltesting-lib/openecomp-sdc-externaltesting-impl/src/test/java/org/openecomp/core/externaltesting/impl/ExternalTestingManagerImplTest.java index 04ddf6e2d4..c429709182 100644 --- a/openecomp-be/lib/openecomp-sdc-externaltesting-lib/openecomp-sdc-externaltesting-impl/src/test/java/org/openecomp/core/externaltesting/impl/ExternalTestingManagerImplTest.java +++ b/openecomp-be/lib/openecomp-sdc-externaltesting-lib/openecomp-sdc-externaltesting-impl/src/test/java/org/openecomp/core/externaltesting/impl/ExternalTestingManagerImplTest.java @@ -18,6 +18,16 @@ package org.openecomp.core.externaltesting.impl; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Optional; +import java.util.UUID; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.tuple.Pair; @@ -25,28 +35,37 @@ import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.*; +import org.mockito.ArgumentMatchers; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; import org.mockito.junit.MockitoJUnitRunner; -import org.openecomp.core.externaltesting.api.*; +import org.openecomp.core.externaltesting.api.ClientConfiguration; +import org.openecomp.core.externaltesting.api.ExternalTestingManager; +import org.openecomp.core.externaltesting.api.RemoteTestingEndpointDefinition; +import org.openecomp.core.externaltesting.api.TestTreeNode; +import org.openecomp.core.externaltesting.api.VtpNameDescriptionPair; +import org.openecomp.core.externaltesting.api.VtpTestCase; +import org.openecomp.core.externaltesting.api.VtpTestExecutionRequest; +import org.openecomp.core.externaltesting.api.VtpTestExecutionResponse; import org.openecomp.core.externaltesting.errors.ExternalTestingException; import org.openecomp.sdc.vendorsoftwareproduct.OrchestrationTemplateCandidateManager; import org.openecomp.sdc.vendorsoftwareproduct.VendorSoftwareProductManager; import org.openecomp.sdc.versioning.VersioningManager; import org.openecomp.sdc.versioning.dao.types.Version; import org.springframework.core.ParameterizedTypeReference; -import org.springframework.http.*; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; import org.springframework.util.LinkedMultiValueMap; import org.springframework.web.client.HttpServerErrorException; import org.springframework.web.client.HttpStatusCodeException; import org.springframework.web.client.ResourceAccessException; import org.springframework.web.client.RestTemplate; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.nio.charset.Charset; -import java.util.*; - @RunWith(MockitoJUnitRunner.class) public class ExternalTestingManagerImplTest { diff --git a/openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-core/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/services/impl/filedatastructuremodule/CandidateServiceImpl.java b/openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-core/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/services/impl/filedatastructuremodule/CandidateServiceImpl.java index 3255e186e4..07dc53dfae 100644 --- a/openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-core/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/services/impl/filedatastructuremodule/CandidateServiceImpl.java +++ b/openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-core/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/services/impl/filedatastructuremodule/CandidateServiceImpl.java @@ -44,6 +44,8 @@ import org.openecomp.sdc.common.errors.ErrorCategory; import org.openecomp.sdc.common.errors.ErrorCode; import org.openecomp.sdc.common.errors.Messages; import org.openecomp.sdc.common.utils.SdcCommon; +import org.openecomp.sdc.common.zip.ZipUtils; +import org.openecomp.sdc.common.zip.exception.ZipSlipException; import org.openecomp.sdc.datatypes.error.ErrorLevel; import org.openecomp.sdc.datatypes.error.ErrorMessage; import org.openecomp.sdc.heat.datatypes.manifest.FileData; @@ -426,6 +428,11 @@ public class CandidateServiceImpl implements CandidateService { new ByteArrayInputStream(contentData.array()))) { ZipEntry zipEntry; while ((zipEntry = zipStream.getNextEntry()) != null) { + try { + ZipUtils.checkForZipSlipInRead(zipEntry); + } catch (ZipSlipException e) { + throw new IOException(e); + } ZipEntry locZipEntry = new ZipEntry(zipEntry.getName()); zos.putNextEntry(locZipEntry); byte[] buf = new byte[1024]; diff --git a/openecomp-be/lib/openecomp-tosca-lib/src/main/java/org/openecomp/sdc/tosca/services/impl/ToscaAnalyzerServiceImpl.java b/openecomp-be/lib/openecomp-tosca-lib/src/main/java/org/openecomp/sdc/tosca/services/impl/ToscaAnalyzerServiceImpl.java index 14cf90a272..1bc547aed7 100644 --- a/openecomp-be/lib/openecomp-tosca-lib/src/main/java/org/openecomp/sdc/tosca/services/impl/ToscaAnalyzerServiceImpl.java +++ b/openecomp-be/lib/openecomp-tosca-lib/src/main/java/org/openecomp/sdc/tosca/services/impl/ToscaAnalyzerServiceImpl.java @@ -58,6 +58,8 @@ import org.openecomp.core.utilities.file.FileContentHandler; import org.openecomp.core.utilities.file.FileUtils; import org.openecomp.sdc.common.errors.CoreException; import org.openecomp.sdc.common.errors.SdcRuntimeException; +import org.openecomp.sdc.common.zip.ZipUtils; +import org.openecomp.sdc.common.zip.exception.ZipSlipException; import org.openecomp.sdc.tosca.datatypes.ToscaElementTypes; import org.openecomp.sdc.tosca.datatypes.ToscaFlatData; import org.openecomp.sdc.tosca.datatypes.ToscaServiceModel; @@ -123,6 +125,7 @@ public class ToscaAnalyzerServiceImpl implements ToscaAnalyzerService { try (ZipInputStream inputZipStream = new ZipInputStream(new ByteArrayInputStream(toscaCsarPackage))) { ZipEntry zipEntry; while ((zipEntry = inputZipStream.getNextEntry()) != null) { + ZipUtils.checkForZipSlipInRead(zipEntry); byte[] fileContent = FileUtils.toByteArray(inputZipStream); String currentEntryName = zipEntry.getName(); if (!isFile(currentEntryName)) { @@ -141,7 +144,7 @@ public class ToscaAnalyzerServiceImpl implements ToscaAnalyzerService { handleToscaCsarWithoutToscaMetadata(toscaServiceModel); } - } catch (IOException exc) { + } catch (IOException | ZipSlipException exc) { throw new SdcRuntimeException(exc.getMessage(), exc); } return toscaServiceModel; diff --git a/openecomp-be/tools/zusammen-tools/src/main/java/org/openecomp/core/tools/exportinfo/ExportDataCommand.java b/openecomp-be/tools/zusammen-tools/src/main/java/org/openecomp/core/tools/exportinfo/ExportDataCommand.java index 5060f4bce2..2907d1e0cc 100644 --- a/openecomp-be/tools/zusammen-tools/src/main/java/org/openecomp/core/tools/exportinfo/ExportDataCommand.java +++ b/openecomp-be/tools/zusammen-tools/src/main/java/org/openecomp/core/tools/exportinfo/ExportDataCommand.java @@ -28,7 +28,6 @@ import com.datastax.driver.core.Session; import com.google.common.collect.Sets; import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; -import java.io.File; import java.io.IOException; import java.io.InputStream; import java.nio.file.Path; @@ -52,8 +51,9 @@ import org.openecomp.core.tools.commands.Command; import org.openecomp.core.tools.commands.CommandName; import org.openecomp.core.tools.importinfo.ImportProperties; import org.openecomp.core.tools.util.Utils; -import org.openecomp.core.tools.util.ZipUtils; import org.openecomp.core.zusammen.impl.CassandraConnectionInitializer; +import org.openecomp.sdc.common.zip.ZipUtils; +import org.openecomp.sdc.common.zip.exception.ZipException; import org.openecomp.sdc.logging.api.Logger; import org.openecomp.sdc.logging.api.LoggerFactory; import org.yaml.snakeyaml.Yaml; @@ -157,14 +157,14 @@ public final class ExportDataCommand extends Command { }, executor); } - private static void zipPath(Path rootDir) throws IOException { - LocalDateTime date = LocalDateTime.now(); - DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME; - String dateStr = date.format(formatter); - dateStr = dateStr.replaceAll(":", "_"); - String zipFile = System.getProperty("user.home") + File.separatorChar + "onboarding_import" + dateStr + ".zip"; - ZipUtils.createZip(zipFile, rootDir); - Utils.printMessage(LOGGER, "Exported file :" + zipFile); + private static void zipPath(final Path rootDir) throws ZipException { + final LocalDateTime date = LocalDateTime.now(); + final DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME; + final String dateStr = date.format(formatter).replace(":", "_"); + final Path zipFile = Paths.get(System.getProperty("user.home"),String.format("onboarding_import%s.zip", dateStr)); + ZipUtils.createZipFromPath(rootDir, zipFile); + Utils.printMessage(LOGGER, "Zip file was created " + zipFile.toString()); + Utils.printMessage(LOGGER, "Exported file :" + zipFile.toString()); } diff --git a/openecomp-be/tools/zusammen-tools/src/main/java/org/openecomp/core/tools/importinfo/ImportDataCommand.java b/openecomp-be/tools/zusammen-tools/src/main/java/org/openecomp/core/tools/importinfo/ImportDataCommand.java index 1f5281a66e..cff8eb98cf 100644 --- a/openecomp-be/tools/zusammen-tools/src/main/java/org/openecomp/core/tools/importinfo/ImportDataCommand.java +++ b/openecomp-be/tools/zusammen-tools/src/main/java/org/openecomp/core/tools/importinfo/ImportDataCommand.java @@ -35,8 +35,9 @@ import org.openecomp.core.tools.commands.Command; import org.openecomp.core.tools.commands.CommandName; import org.openecomp.core.tools.exportinfo.ExportDataCommand; import org.openecomp.core.tools.util.Utils; -import org.openecomp.core.tools.util.ZipUtils; import org.openecomp.core.zusammen.impl.CassandraConnectionInitializer; +import org.openecomp.sdc.common.zip.ZipUtils; +import org.openecomp.sdc.common.zip.exception.ZipException; import org.openecomp.sdc.logging.api.Logger; import org.openecomp.sdc.logging.api.LoggerFactory; @@ -66,7 +67,7 @@ public class ImportDataCommand extends Command { files.forEach(new ImportSingleTable()::importFile); } FileUtils.forceDelete(outputFolder.toFile()); // leaves directory clean - } catch (IOException e) { + } catch (final IOException | ZipException e) { Utils.logError(LOGGER, e); } return true; diff --git a/openecomp-be/tools/zusammen-tools/src/main/java/org/openecomp/core/tools/util/ZipUtils.java b/openecomp-be/tools/zusammen-tools/src/main/java/org/openecomp/core/tools/util/ZipUtils.java deleted file mode 100644 index f58f18d93c..0000000000 --- a/openecomp-be/tools/zusammen-tools/src/main/java/org/openecomp/core/tools/util/ZipUtils.java +++ /dev/null @@ -1,104 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * SDC - * ================================================================================ - * Copyright (C) 2017 - 2019 AT&T Intellectual Property. All rights reserved. - * ================================================================================ - * 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. - * ============LICENSE_END========================================================= - */ - -package org.openecomp.core.tools.util; - -import com.google.common.io.ByteStreams; -import org.openecomp.sdc.logging.api.Logger; -import org.openecomp.sdc.logging.api.LoggerFactory; - -import java.io.*; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.zip.ZipEntry; -import java.util.zip.ZipException; -import java.util.zip.ZipInputStream; -import java.util.zip.ZipOutputStream; - -public class ZipUtils { - - private static final Logger logger = LoggerFactory.getLogger(ZipUtils.class); - - private ZipUtils() { - // prevent instantiation - } - - public static void createZip(String zipFileName, Path dir) throws IOException { - File dirObj = dir.toFile(); - Path zippedFile = Files.createFile(Paths.get(zipFileName)); - try ( - FileOutputStream fileOutputStream = new FileOutputStream(File.separator + zippedFile.toFile()); - BufferedOutputStream bos = new BufferedOutputStream(fileOutputStream); - ZipOutputStream out = new ZipOutputStream(bos)) { - File[] files = dirObj.listFiles(); - for (File file : files) { - out.putNextEntry(new ZipEntry(file.getName())); - Files.copy(Paths.get(file.getPath()), out); - out.closeEntry(); - } - Utils.printMessage(logger, "Zip file was created " + zipFileName); - } - } - - public static void unzip(Path zipFile, Path outputFolder) throws IOException { - if (zipFile == null || outputFolder == null) { - return; - } - createDirectoryIfNotExists(outputFolder); - - try (FileInputStream fileInputStream = new FileInputStream(zipFile.toFile()); - ZipInputStream stream = new ZipInputStream(fileInputStream)) { - - ZipEntry entry; - while ((entry = stream.getNextEntry()) != null) { - assertEntryNotVulnerable(entry); - String fileName = entry.getName(); - File newFile = new File(outputFolder.toString() + File.separator + fileName); - if (entry.isDirectory()) { - createDirectoryIfNotExists(newFile.toPath()); - } else { - persistFile(stream, newFile); - } - } - } - - } - - private static void persistFile(ZipInputStream stream, File newFile) throws IOException { - new File(newFile.getParent()).mkdirs(); - try (FileOutputStream outputStream = new FileOutputStream(newFile)) { - ByteStreams.copy(stream, outputStream); - } - } - - private static void createDirectoryIfNotExists(Path path) throws IOException { - if (!path.toFile().exists()) { - Files.createDirectories(path); - } - } - - private static void assertEntryNotVulnerable(ZipEntry entry) throws ZipException { - if (entry.getName().contains("../")) { - throw new ZipException("Path traversal attempt discovered."); - } - } -} - |