Implement 'Signed Large CSAR' support 95/122795/10
authorvasraz <vasyl.razinkov@est.tech>
Thu, 29 Jul 2021 13:41:18 +0000 (14:41 +0100)
committerMichael Morris <michael.morris@est.tech>
Thu, 5 Aug 2021 11:25:09 +0000 (11:25 +0000)
Change-Id: I33cc381b86c6a10e20d521c0d3dcc76c28344b8f
Signed-off-by: Vasyl Razinkov <vasyl.razinkov@est.tech>
Issue-ID: SDC-3652
Issue-ID: SDC-3653
Signed-off-by: André Schmid <andre.schmid@est.tech>
14 files changed:
common-be/src/main/java/org/openecomp/sdc/be/csar/storage/CsarSizeReducer.java
common-be/src/test/java/org/openecomp/sdc/be/csar/storage/CsarSizeReducerTest.java
common-be/src/test/resources/csarSizeReducer/dummyToNotReduce.csar [new file with mode: 0644]
common-be/src/test/resources/csarSizeReducer/dummyToReduce.csar [moved from common-be/src/test/resources/csarSizeReducer/dummy.csar with 100% similarity]
common-be/src/test/resources/csarSizeReducer/dummyToReduce.zip [new file with mode: 0644]
openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/main/java/org/openecomp/sdcrests/vsp/rest/services/OrchestrationTemplateCandidateImpl.java
openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/test/java/org/openecomp/sdcrests/vsp/rest/services/OrchestrationTemplateCandidateImplTest.java
openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/impl/orchestration/OrchestrationTemplateCSARHandler.java
openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/impl/orchestration/csar/validation/CsarSecurityValidator.java
openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/security/SecurityManager.java
openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/test/java/org/openecomp/sdc/vendorsoftwareproduct/impl/orchestration/csar/validation/CsarSecurityValidatorTest.java
openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/test/java/org/openecomp/sdc/vendorsoftwareproduct/security/SecurityManagerTest.java
openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/test/resources/cert/2-file-signed-package/2-file-signed-package.zip [new file with mode: 0644]
openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/test/resources/cert/3-file-signed-package/3-file-signed-package.zip [new file with mode: 0644]

index cf35c8c..1fef373 100644 (file)
 
 package org.openecomp.sdc.be.csar.storage;
 
+import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
+
 import java.io.BufferedOutputStream;
 import java.io.IOException;
 import java.nio.file.Files;
 import java.nio.file.Path;
+import java.util.List;
+import java.util.Set;
 import java.util.UUID;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.function.Consumer;
+import java.util.stream.Collectors;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipFile;
 import java.util.zip.ZipOutputStream;
+import lombok.Getter;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.io.FilenameUtils;
 import org.openecomp.sdc.be.csar.storage.exception.CsarSizeReducerException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -35,6 +45,12 @@ import org.slf4j.LoggerFactory;
 public class CsarSizeReducer implements PackageSizeReducer {
 
     private static final Logger LOGGER = LoggerFactory.getLogger(CsarSizeReducer.class);
+    private static final Set<String> ALLOWED_SIGNATURE_EXTENSIONS = Set.of("cms");
+    private static final Set<String> ALLOWED_CERTIFICATE_EXTENSIONS = Set.of("cert", "crt");
+    private static final String CSAR_EXTENSION = "csar";
+    private static final String UNEXPECTED_PROBLEM_HAPPENED_WHILE_READING_THE_CSAR = "An unexpected problem happened while reading the CSAR '%s'";
+    @Getter
+    private final AtomicBoolean reduced = new AtomicBoolean(false);
 
     private final CsarPackageReducerConfiguration configuration;
 
@@ -44,38 +60,31 @@ public class CsarSizeReducer implements PackageSizeReducer {
 
     @Override
     public byte[] reduce(final Path csarPackagePath) {
+        if (hasSignedPackageStructure(csarPackagePath)) {
+            return reduce(csarPackagePath, this::signedZipProcessingConsumer);
+        } else {
+            return reduce(csarPackagePath, this::unsignedZipProcessingConsumer);
+        }
+    }
+
+    private byte[] reduce(final Path csarPackagePath, final ZipProcessFunction zipProcessingFunction) {
         final var reducedCsarPath = Path.of(csarPackagePath + "." + UUID.randomUUID());
 
         try (final var zf = new ZipFile(csarPackagePath.toString());
             final var zos = new ZipOutputStream(new BufferedOutputStream(Files.newOutputStream(reducedCsarPath)))) {
-
-            zf.entries().asIterator().forEachRemaining(entry -> {
-                final var entryName = entry.getName();
-                try {
-                    if (!entry.isDirectory()) {
-                        zos.putNextEntry(new ZipEntry(entryName));
-                        if (isCandidateToRemove(entry)) {
-                            // replace with EMPTY string to avoid package description inconsistency/validation errors
-                            zos.write("".getBytes());
-                        } else {
-                            zos.write(zf.getInputStream(entry).readAllBytes());
-                        }
-                    }
-                    zos.closeEntry();
-                } catch (final IOException ei) {
-                    final var errorMsg = String.format("Failed to extract '%s' from zip '%s'", entryName, csarPackagePath);
-                    throw new CsarSizeReducerException(errorMsg, ei);
-                }
-            });
-
+            zf.entries().asIterator().forEachRemaining(zipProcessingFunction.getProcessZipConsumer(csarPackagePath, zf, zos));
         } catch (final IOException ex1) {
             rollback(reducedCsarPath);
-            final var errorMsg = String.format("An unexpected problem happened while reading the CSAR '%s'", csarPackagePath);
+            final var errorMsg = String.format(UNEXPECTED_PROBLEM_HAPPENED_WHILE_READING_THE_CSAR, csarPackagePath);
             throw new CsarSizeReducerException(errorMsg, ex1);
         }
         final byte[] reducedCsarBytes;
         try {
-            reducedCsarBytes = Files.readAllBytes(reducedCsarPath);
+            if (reduced.get()) {
+                reducedCsarBytes = Files.readAllBytes(reducedCsarPath);
+            } else {
+                reducedCsarBytes = Files.readAllBytes(csarPackagePath);
+            }
         } catch (final IOException e) {
             final var errorMsg = String.format("Could not read bytes of file '%s'", csarPackagePath);
             throw new CsarSizeReducerException(errorMsg, e);
@@ -90,6 +99,51 @@ public class CsarSizeReducer implements PackageSizeReducer {
         return reducedCsarBytes;
     }
 
+    private Consumer<ZipEntry> signedZipProcessingConsumer(final Path csarPackagePath, final ZipFile zf, final ZipOutputStream zos) {
+        return zipEntry -> {
+            final var entryName = zipEntry.getName();
+            try {
+                zos.putNextEntry(new ZipEntry(entryName));
+                if (!zipEntry.isDirectory()) {
+                    if (entryName.toLowerCase().endsWith(CSAR_EXTENSION)) {
+                        final var internalCsarExtractPath = Path.of(csarPackagePath + "." + UUID.randomUUID());
+                        Files.copy(zf.getInputStream(zipEntry), internalCsarExtractPath, REPLACE_EXISTING);
+                        zos.write(reduce(internalCsarExtractPath, this::unsignedZipProcessingConsumer));
+                        Files.delete(internalCsarExtractPath);
+                    } else {
+                        zos.write(zf.getInputStream(zipEntry).readAllBytes());
+                    }
+                }
+                zos.closeEntry();
+            } catch (final IOException ei) {
+                final var errorMsg = String.format("Failed to extract '%s' from zip '%s'", entryName, csarPackagePath);
+                throw new CsarSizeReducerException(errorMsg, ei);
+            }
+        };
+    }
+
+    private Consumer<ZipEntry> unsignedZipProcessingConsumer(final Path csarPackagePath, final ZipFile zf, final ZipOutputStream zos) {
+        return zipEntry -> {
+            final var entryName = zipEntry.getName();
+            try {
+                zos.putNextEntry(new ZipEntry(entryName));
+                if (!zipEntry.isDirectory()) {
+                    if (isCandidateToRemove(zipEntry)) {
+                        // replace with EMPTY string to avoid package description inconsistency/validation errors
+                        zos.write("".getBytes());
+                        reduced.set(true);
+                    } else {
+                        zos.write(zf.getInputStream(zipEntry).readAllBytes());
+                    }
+                }
+                zos.closeEntry();
+            } catch (final IOException ei) {
+                final var errorMsg = String.format("Failed to extract '%s' from zip '%s'", entryName, csarPackagePath);
+                throw new CsarSizeReducerException(errorMsg, ei);
+            }
+        };
+    }
+
     private void rollback(final Path reducedCsarPath) {
         if (Files.exists(reducedCsarPath)) {
             try {
@@ -106,4 +160,59 @@ public class CsarSizeReducer implements PackageSizeReducer {
             || zipEntry.getSize() > configuration.getSizeLimit();
     }
 
+    private boolean hasSignedPackageStructure(final Path csarPackagePath) {
+        final List<Path> packagePathList;
+        try (final var zf = new ZipFile(csarPackagePath.toString())) {
+            packagePathList = zf.stream()
+                .filter(zipEntry -> !zipEntry.isDirectory())
+                .map(ZipEntry::getName).map(Path::of)
+                .collect(Collectors.toList());
+        } catch (final IOException e) {
+            final var errorMsg = String.format(UNEXPECTED_PROBLEM_HAPPENED_WHILE_READING_THE_CSAR, csarPackagePath);
+            throw new CsarSizeReducerException(errorMsg, e);
+        }
+
+        if (CollectionUtils.isEmpty(packagePathList)) {
+            return false;
+        }
+        final int numberOfFiles = packagePathList.size();
+        if (numberOfFiles == 2) {
+            return hasOneInternalPackageFile(packagePathList) && hasOneSignatureFile(packagePathList);
+        }
+        if (numberOfFiles == 3) {
+            return hasOneInternalPackageFile(packagePathList) && hasOneSignatureFile(packagePathList) && hasOneCertificateFile(packagePathList);
+        }
+        return false;
+    }
+
+    private boolean hasOneInternalPackageFile(final List<Path> packagePathList) {
+        return packagePathList.parallelStream()
+            .map(Path::toString)
+            .map(FilenameUtils::getExtension)
+            .map(String::toLowerCase)
+            .filter(extension -> extension.endsWith(CSAR_EXTENSION)).count() == 1;
+    }
+
+    private boolean hasOneSignatureFile(final List<Path> packagePathList) {
+        return packagePathList.parallelStream()
+            .map(Path::toString)
+            .map(FilenameUtils::getExtension)
+            .map(String::toLowerCase)
+            .filter(ALLOWED_SIGNATURE_EXTENSIONS::contains).count() == 1;
+    }
+
+    private boolean hasOneCertificateFile(final List<Path> packagePathList) {
+        return packagePathList.parallelStream()
+            .map(Path::toString)
+            .map(FilenameUtils::getExtension)
+            .map(String::toLowerCase)
+            .filter(ALLOWED_CERTIFICATE_EXTENSIONS::contains).count() == 1;
+    }
+
+    @FunctionalInterface
+    private interface ZipProcessFunction {
+
+        Consumer<ZipEntry> getProcessZipConsumer(Path csarPackagePath, ZipFile zf, ZipOutputStream zos);
+    }
+
 }
index c758644..eaa5ffe 100644 (file)
@@ -23,7 +23,9 @@ package org.openecomp.sdc.be.csar.storage;
 
 import static org.junit.jupiter.api.Assertions.assertArrayEquals;
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
 import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
 import static org.mockito.Mockito.when;
 
 import java.nio.charset.StandardCharsets;
@@ -32,7 +34,8 @@ import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
 import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
@@ -51,15 +54,16 @@ class CsarSizeReducerTest {
         MockitoAnnotations.openMocks(this);
     }
 
-    @Test
-    void reduceByPathAndSizeTest() throws ZipException {
+    @ParameterizedTest
+    @ValueSource(strings = {"dummyToReduce.zip", "dummyToReduce.csar", "dummyToNotReduce.csar"})
+    void reduceByPathAndSizeTest(String fileName) throws ZipException {
         final var pathToReduce1 = Path.of("Files/images");
         final var pathToReduce2 = Path.of("Files/Scripts/my_script.sh");
         final var sizeLimit = 150000L;
         when(csarPackageReducerConfiguration.getSizeLimit()).thenReturn(sizeLimit);
         when(csarPackageReducerConfiguration.getFoldersToStrip()).thenReturn(Set.of(pathToReduce1, pathToReduce2));
 
-        final var csarPath = Path.of("src/test/resources/csarSizeReducer/dummy.csar");
+        final var csarPath = Path.of("src/test/resources/csarSizeReducer/" + fileName);
 
         final Map<String, byte[]> originalCsar = ZipUtils.readZip(csarPath.toFile(), false);
 
@@ -74,14 +78,47 @@ class CsarSizeReducerTest {
             assertTrue(reducedCsar.containsKey(originalFilePath),
                 String.format("No file should be removed, but it is missing original file '%s'", originalFilePath));
 
-            if (originalFilePath.startsWith(pathToReduce1.toString()) || originalFilePath.startsWith(pathToReduce2.toString())
-                || originalBytes.length > sizeLimit) {
-                assertArrayEquals("".getBytes(StandardCharsets.UTF_8), reducedCsar.get(originalFilePath),
-                    String.format("File '%s' expected to be reduced to empty string", originalFilePath));
+            final String extention = fileName.substring(fileName.lastIndexOf('.') + 1);
+            switch (extention.toLowerCase()) {
+                case "zip":
+                    verifyZIP(pathToReduce1, pathToReduce2, sizeLimit, reducedCsar, originalFilePath, originalBytes);
+                    break;
+                case "csar":
+                    verifyCSAR(pathToReduce1, pathToReduce2, sizeLimit, reducedCsar, originalFilePath, originalBytes);
+                    break;
+                default:
+                    fail("Unexpected file extention");
+                    break;
+            }
+        }
+    }
+
+    private void verifyCSAR(final Path pathToReduce1, final Path pathToReduce2, final long sizeLimit, final Map<String, byte[]> reducedCsar,
+                            final String originalFilePath, final byte[] originalBytes) {
+        if (originalFilePath.startsWith(pathToReduce1.toString()) || originalFilePath.startsWith(pathToReduce2.toString())
+            || originalBytes.length > sizeLimit) {
+            assertArrayEquals("".getBytes(StandardCharsets.UTF_8), reducedCsar.get(originalFilePath),
+                String.format("File '%s' expected to be reduced to empty string", originalFilePath));
+        } else {
+            assertArrayEquals(originalBytes, reducedCsar.get(originalFilePath),
+                String.format("File '%s' expected to be equal", originalFilePath));
+        }
+    }
+
+    private void verifyZIP(final Path pathToReduce1, final Path pathToReduce2, final long sizeLimit, final Map<String, byte[]> reducedCsar,
+                           final String originalFilePath, final byte[] originalBytes) {
+        if (originalFilePath.startsWith(pathToReduce1.toString()) || originalFilePath.startsWith(pathToReduce2.toString())
+            || originalBytes.length > sizeLimit) {
+            assertArrayEquals("".getBytes(StandardCharsets.UTF_8), reducedCsar.get(originalFilePath),
+                String.format("File '%s' expected to be reduced to empty string", originalFilePath));
+        } else {
+            if (originalFilePath.endsWith(".csar") && csarSizeReducer.getReduced().get()) {
+                assertNotEquals(originalBytes.length, reducedCsar.get(originalFilePath).length,
+                    String.format("File '%s' expected to be NOT equal", originalFilePath));
             } else {
                 assertArrayEquals(originalBytes, reducedCsar.get(originalFilePath),
                     String.format("File '%s' expected to be equal", originalFilePath));
             }
         }
     }
-}
\ No newline at end of file
+}
diff --git a/common-be/src/test/resources/csarSizeReducer/dummyToNotReduce.csar b/common-be/src/test/resources/csarSizeReducer/dummyToNotReduce.csar
new file mode 100644 (file)
index 0000000..d440413
Binary files /dev/null and b/common-be/src/test/resources/csarSizeReducer/dummyToNotReduce.csar differ
diff --git a/common-be/src/test/resources/csarSizeReducer/dummyToReduce.zip b/common-be/src/test/resources/csarSizeReducer/dummyToReduce.zip
new file mode 100644 (file)
index 0000000..fecb45a
Binary files /dev/null and b/common-be/src/test/resources/csarSizeReducer/dummyToReduce.zip differ
index 10f6012..19f2c5d 100644 (file)
@@ -160,17 +160,21 @@ public class OrchestrationTemplateCandidateImpl implements OrchestrationTemplate
             try {
                 packageInputStream = fileToUpload.getDataHandler().getInputStream();
             } catch (final IOException e) {
-                return Response.status(INTERNAL_SERVER_ERROR).entity(buildUploadResponseWithError(new ErrorMessage(ErrorLevel.ERROR, UNEXPECTED_PROBLEM_HAPPENED_WHILE_GETTING.formatMessage(filename)))).build();
+                return Response.status(INTERNAL_SERVER_ERROR).entity(buildUploadResponseWithError(
+                    new ErrorMessage(ErrorLevel.ERROR, UNEXPECTED_PROBLEM_HAPPENED_WHILE_GETTING.formatMessage(filename)))).build();
             }
             try {
                 artifactInfo = artifactStorageManager.upload(vspId, versionId, packageInputStream);
             } catch (final BusinessException e) {
-                return Response.status(INTERNAL_SERVER_ERROR).entity(buildUploadResponseWithError(new ErrorMessage(ErrorLevel.ERROR, ERROR_HAS_OCCURRED_WHILE_PERSISTING_THE_ARTIFACT.formatMessage(filename)))).build();
+                return Response.status(INTERNAL_SERVER_ERROR).entity(buildUploadResponseWithError(
+                    new ErrorMessage(ErrorLevel.ERROR, ERROR_HAS_OCCURRED_WHILE_PERSISTING_THE_ARTIFACT.formatMessage(filename)))).build();
             }
             try {
                 fileToUploadBytes = packageSizeReducer.reduce(artifactInfo.getPath());
             } catch (final BusinessException e) {
-                return Response.status(INTERNAL_SERVER_ERROR).entity(buildUploadResponseWithError(new ErrorMessage(ErrorLevel.ERROR, ERROR_HAS_OCCURRED_WHILE_REDUCING_THE_ARTIFACT_SIZE.formatMessage(artifactInfo.getPath())))).build();
+                return Response.status(INTERNAL_SERVER_ERROR).entity(buildUploadResponseWithError(
+                    new ErrorMessage(ErrorLevel.ERROR, ERROR_HAS_OCCURRED_WHILE_REDUCING_THE_ARTIFACT_SIZE.formatMessage(artifactInfo.getPath()))))
+                    .build();
             }
         } else {
             fileToUploadBytes = fileToUpload.getObject(byte[].class);
@@ -183,10 +187,12 @@ public class OrchestrationTemplateCandidateImpl implements OrchestrationTemplate
         }
         final var onboardPackageInfo = onboardingPackageProcessor.getOnboardPackageInfo().orElse(null);
         if (onboardPackageInfo == null) {
-            return Response.ok(buildUploadResponseWithError(new ErrorMessage(ErrorLevel.ERROR, PACKAGE_PROCESS_ERROR.formatMessage(filename)))).build();
+            final UploadFileResponseDto uploadFileResponseDto = buildUploadResponseWithError(
+                new ErrorMessage(ErrorLevel.ERROR, PACKAGE_PROCESS_ERROR.formatMessage(filename)));
+            return Response.ok(uploadFileResponseDto).build();
         }
-        final var vspDetails = new VspDetails(ValidationUtils.sanitizeInputString(vspId),
-            new Version(ValidationUtils.sanitizeInputString(versionId)));
+        final var version = new Version(ValidationUtils.sanitizeInputString(versionId));
+        final var vspDetails = new VspDetails(ValidationUtils.sanitizeInputString(vspId), version);
         return processOnboardPackage(onboardPackageInfo, vspDetails, errorMessages);
     }
 
@@ -224,7 +230,8 @@ public class OrchestrationTemplateCandidateImpl implements OrchestrationTemplate
         } else {
             zipFile = vendorSoftwareProductManager.get(vspId, new Version((versionId)));
             if (!zipFile.isPresent()) {
-                ErrorMessage errorMessage = new ErrorMessage(ErrorLevel.ERROR, getErrorWithParameters(NO_FILE_WAS_UPLOADED_OR_FILE_NOT_EXIST.getErrorMessage(), ""));
+                ErrorMessage errorMessage = new ErrorMessage(ErrorLevel.ERROR,
+                    getErrorWithParameters(NO_FILE_WAS_UPLOADED_OR_FILE_NOT_EXIST.getErrorMessage(), ""));
                 LOGGER.error(errorMessage.getMessage());
                 return Response.status(NOT_FOUND).build();
             }
@@ -255,7 +262,8 @@ public class OrchestrationTemplateCandidateImpl implements OrchestrationTemplate
         FilesDataStructure fileDataStructure = copyFilesDataStructureDtoToFilesDataStructure(fileDataStructureDto);
         ValidationResponse response = candidateManager.updateFilesDataStructure(vspId, new Version(versionId), fileDataStructure);
         if (!response.isValid()) {
-            return Response.status(EXPECTATION_FAILED).entity(new MapValidationResponseToDto().applyMapping(response, ValidationResponseDto.class)).build();
+            return Response.status(EXPECTATION_FAILED).entity(new MapValidationResponseToDto().applyMapping(response, ValidationResponseDto.class))
+                .build();
         }
         return Response.ok(fileDataStructureDto).build();
     }
index b89756e..edf29b7 100644 (file)
@@ -74,7 +74,10 @@ import org.openecomp.sdcrests.vendorsoftwareproducts.types.UploadFileResponseDto
 class OrchestrationTemplateCandidateImplTest {
 
     private final Logger logger = LoggerFactory.getLogger(OrchestrationTemplateCandidateImplTest.class);
-
+    private final String candidateId = UUID.randomUUID().toString();
+    private final String softwareProductId = UUID.randomUUID().toString();
+    private final String versionId = UUID.randomUUID().toString();
+    private final String user = "cs0008";
     @Mock
     private OrchestrationTemplateCandidateManager candidateManager;
     @Mock
@@ -85,15 +88,8 @@ class OrchestrationTemplateCandidateImplTest {
     private ArtifactStorageManager artifactStorageManager;
     @Mock
     private PackageSizeReducer packageSizeReducer;
-
     private OrchestrationTemplateCandidateImpl orchestrationTemplateCandidate;
 
-    private final String candidateId = UUID.randomUUID().toString();
-    private final String softwareProductId = UUID.randomUUID().toString();
-    private final String versionId = UUID.randomUUID().toString();
-
-    private final String user = "cs0008";
-
     @BeforeEach
     public void setUp() {
         try {
index f106239..f1cab48 100644 (file)
@@ -25,6 +25,7 @@ import java.io.IOException;
 import java.util.Optional;
 import org.openecomp.core.utilities.file.FileContentHandler;
 import org.openecomp.core.utilities.orchestration.OnboardingTypesEnum;
+import org.openecomp.sdc.be.csar.storage.ArtifactInfo;
 import org.openecomp.sdc.common.errors.CoreException;
 import org.openecomp.sdc.common.errors.Messages;
 import org.openecomp.sdc.common.utils.SdcCommon;
@@ -49,7 +50,8 @@ public class OrchestrationTemplateCSARHandler extends BaseOrchestrationTemplateH
         final UploadFileResponse uploadFileResponse = new UploadFileResponse();
         if (onboardPackageInfo.getPackageType() == OnboardingTypesEnum.SIGNED_CSAR) {
             final OnboardSignedPackage originalOnboardPackage = (OnboardSignedPackage) onboardPackageInfo.getOriginalOnboardPackage();
-            validatePackageSecurity(originalOnboardPackage).ifPresent(packageSignatureResponse -> {
+            final ArtifactInfo artifactInfo = onboardPackageInfo.getArtifactInfo();
+            validatePackageSecurity(originalOnboardPackage, artifactInfo).ifPresent(packageSignatureResponse -> {
                 if (packageSignatureResponse.hasErrors()) {
                     uploadFileResponse.addStructureErrors(packageSignatureResponse.getErrors());
                 }
@@ -74,11 +76,11 @@ public class OrchestrationTemplateCSARHandler extends BaseOrchestrationTemplateH
         return uploadFileResponse;
     }
 
-    private Optional<UploadFileResponse> validatePackageSecurity(final OnboardSignedPackage originalOnboardPackage) {
+    private Optional<UploadFileResponse> validatePackageSecurity(final OnboardSignedPackage signedPackage, final ArtifactInfo artifactInfo) {
         final UploadFileResponse uploadFileResponseDto = new UploadFileResponse();
         try {
             final CsarSecurityValidator csarSecurityValidator = new CsarSecurityValidator();
-            if (!csarSecurityValidator.verifyPackageSignature(originalOnboardPackage)) {
+            if (!csarSecurityValidator.verifyPackageSignature(signedPackage, artifactInfo)) {
                 final ErrorMessage errorMessage = new ErrorMessage(ErrorLevel.ERROR, Messages.FAILED_TO_VERIFY_SIGNATURE.getErrorMessage());
                 logger.error(errorMessage.getMessage());
                 uploadFileResponseDto.addStructureError(SdcCommon.UPLOAD_FILE, errorMessage);
@@ -86,7 +88,7 @@ public class OrchestrationTemplateCSARHandler extends BaseOrchestrationTemplateH
             }
         } catch (final SecurityManagerException e) {
             final ErrorMessage errorMessage = new ErrorMessage(ErrorLevel.ERROR, e.getMessage());
-            logger.error("Could not validate package signature {}", originalOnboardPackage.getFilename(), e);
+            logger.error("Could not validate package signature {}", signedPackage.getFilename(), e);
             uploadFileResponseDto.addStructureError(SdcCommon.UPLOAD_FILE, errorMessage);
             return Optional.of(uploadFileResponseDto);
         }
index 81a17f3..bf5abe3 100644 (file)
@@ -19,7 +19,8 @@
 package org.openecomp.sdc.vendorsoftwareproduct.impl.orchestration.csar.validation;
 
 import java.util.Optional;
-import org.openecomp.core.utilities.file.FileContentHandler;
+import lombok.NoArgsConstructor;
+import org.openecomp.sdc.be.csar.storage.ArtifactInfo;
 import org.openecomp.sdc.vendorsoftwareproduct.security.SecurityManager;
 import org.openecomp.sdc.vendorsoftwareproduct.security.SecurityManagerException;
 import org.openecomp.sdc.vendorsoftwareproduct.types.OnboardSignedPackage;
@@ -27,13 +28,11 @@ import org.openecomp.sdc.vendorsoftwareproduct.types.OnboardSignedPackage;
 /**
  * Validates the package security
  */
+@NoArgsConstructor
 public class CsarSecurityValidator {
 
     private SecurityManager securityManager = SecurityManager.getInstance();
 
-    public CsarSecurityValidator() {
-    }
-
     //for tests purpose
     CsarSecurityValidator(final SecurityManager securityManager) {
         this.securityManager = securityManager;
@@ -45,15 +44,24 @@ public class CsarSecurityValidator {
      * @return true if signature verified
      * @throws SecurityManagerException when a certificate error occurs.
      */
-    public boolean verifyPackageSignature(final OnboardSignedPackage signedPackage) throws SecurityManagerException {
-        final FileContentHandler fileContentHandler = signedPackage.getFileContentHandler();
-        final byte[] signatureBytes = fileContentHandler.getFileContent(signedPackage.getSignatureFilePath());
-        final byte[] archiveBytes = fileContentHandler.getFileContent(signedPackage.getInternalPackageFilePath());
-        byte[] certificateBytes = null;
-        final Optional<String> certificateFilePath = signedPackage.getCertificateFilePath();
-        if (certificateFilePath.isPresent()) {
-            certificateBytes = fileContentHandler.getFileContent(certificateFilePath.get());
+    public boolean verifyPackageSignature(final OnboardSignedPackage signedPackage, final ArtifactInfo artifactInfo) throws SecurityManagerException {
+        if (isArtifactInfoPresent(artifactInfo)) {
+            return securityManager.verifyPackageSignedData(signedPackage, artifactInfo);
+        } else {
+            final var fileContentHandler = signedPackage.getFileContentHandler();
+            final byte[] signatureBytes = fileContentHandler.getFileContent(signedPackage.getSignatureFilePath());
+            final byte[] archiveBytes = fileContentHandler.getFileContent(signedPackage.getInternalPackageFilePath());
+            byte[] certificateBytes = null;
+            final Optional<String> certificateFilePath = signedPackage.getCertificateFilePath();
+            if (certificateFilePath.isPresent()) {
+                certificateBytes = fileContentHandler.getFileContent(certificateFilePath.get());
+            }
+            return securityManager.verifySignedData(signatureBytes, certificateBytes, archiveBytes);
         }
-        return securityManager.verifySignedData(signatureBytes, certificateBytes, archiveBytes);
     }
+
+    private boolean isArtifactInfoPresent(final ArtifactInfo artifactInfo) {
+        return artifactInfo != null && artifactInfo.getPath() != null;
+    }
+
 }
index d60b54b..fec15b5 100644 (file)
  */
 package org.openecomp.sdc.vendorsoftwareproduct.security;
 
+import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
+
 import com.google.common.collect.ImmutableSet;
 import java.io.ByteArrayInputStream;
 import java.io.File;
 import java.io.FileInputStream;
-import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
+import java.nio.file.Files;
+import java.nio.file.Path;
 import java.security.GeneralSecurityException;
 import java.security.InvalidAlgorithmParameterException;
 import java.security.NoSuchAlgorithmException;
@@ -48,22 +51,28 @@ import java.util.Collection;
 import java.util.HashSet;
 import java.util.Optional;
 import java.util.Set;
+import java.util.UUID;
+import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.function.Predicate;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
+import java.util.zip.ZipFile;
 import org.bouncycastle.asn1.cms.ContentInfo;
 import org.bouncycastle.cert.X509CertificateHolder;
 import org.bouncycastle.cms.CMSException;
 import org.bouncycastle.cms.CMSProcessableByteArray;
+import org.bouncycastle.cms.CMSProcessableFile;
 import org.bouncycastle.cms.CMSSignedData;
-import org.bouncycastle.cms.CMSTypedData;
 import org.bouncycastle.cms.SignerInformation;
 import org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoVerifierBuilder;
 import org.bouncycastle.jce.provider.BouncyCastleProvider;
 import org.bouncycastle.openssl.PEMParser;
 import org.bouncycastle.operator.OperatorCreationException;
+import org.openecomp.sdc.be.csar.storage.ArtifactInfo;
+import org.openecomp.sdc.common.errors.SdcRuntimeException;
 import org.openecomp.sdc.logging.api.Logger;
 import org.openecomp.sdc.logging.api.LoggerFactory;
+import org.openecomp.sdc.vendorsoftwareproduct.types.OnboardSignedPackage;
 
 /**
  * This is temporary solution. When AAF provides functionality for verifying trustedCertificates, this class should be reviewed Class is responsible
@@ -71,13 +80,12 @@ import org.openecomp.sdc.logging.api.LoggerFactory;
  */
 public class SecurityManager {
 
+    public static final Set<String> ALLOWED_SIGNATURE_EXTENSIONS = Set.of("cms");
+    public static final Set<String> ALLOWED_CERTIFICATE_EXTENSIONS = Set.of("cert", "crt");
     private static final String CERTIFICATE_DEFAULT_LOCATION = "cert";
-    public static final Set<String> ALLOWED_SIGNATURE_EXTENSIONS = ImmutableSet.of("cms");
-    public static final Set<String> ALLOWED_CERTIFICATE_EXTENSIONS = ImmutableSet.of("cert", "crt");
-    private Logger logger = LoggerFactory.getLogger(SecurityManager.class);
-    private Set<X509Certificate> trustedCertificates = new HashSet<>();
-    private Set<X509Certificate> trustedCertificatesFromPackage = new HashSet<>();
-    private File certificateDirectory;
+    private static final Logger logger = LoggerFactory.getLogger(SecurityManager.class);
+    private static final String UNEXPECTED_ERROR_OCCURRED_DURING_SIGNATURE_VALIDATION = "Unexpected error occurred during signature validation!";
+    private static final String COULD_NOT_VERIFY_SIGNATURE = "Could not verify signature!";
 
     static {
         if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
@@ -85,6 +93,10 @@ public class SecurityManager {
         }
     }
 
+    private Set<X509Certificate> trustedCertificates = new HashSet<>();
+    private Set<X509Certificate> trustedCertificatesFromPackage = new HashSet<>();
+    private File certificateDirectory;
+
     private SecurityManager() {
         certificateDirectory = this.getcertDirectory(System.getenv("SDC_CERT_DIR"));
     }
@@ -98,21 +110,13 @@ public class SecurityManager {
         return SecurityManagerInstanceHolder.instance;
     }
 
-    /**
-     * Initialization on demand class / synchronized singleton pattern.
-     */
-    private static class SecurityManagerInstanceHolder {
-
-        private static final SecurityManager instance = new SecurityManager();
-    }
-
     /**
      * Checks the configured location for available trustedCertificates
      *
      * @return set of trustedCertificates
      * @throws SecurityManagerException
      */
-    public Set<X509Certificate> getTrustedCertificates() throws SecurityManagerException, FileNotFoundException {
+    public Set<X509Certificate> getTrustedCertificates() throws SecurityManagerException {
         //if file number in certificate directory changed reload certs
         String[] certFiles = certificateDirectory.list();
         if (certFiles == null) {
@@ -145,43 +149,121 @@ public class SecurityManager {
      * @return true if signature verified
      * @throws SecurityManagerException
      */
-    public boolean verifySignedData(final byte[] messageSyntaxSignature, final byte[] packageCert, final byte[] innerPackageFile)
-        throws SecurityManagerException {
-        try (ByteArrayInputStream signatureStream = new ByteArrayInputStream(messageSyntaxSignature); final PEMParser pemParser = new PEMParser(
-            new InputStreamReader(signatureStream))) {
+    public boolean verifySignedData(final byte[] messageSyntaxSignature,
+                                    final byte[] packageCert,
+                                    final byte[] innerPackageFile) throws SecurityManagerException {
+        try (final ByteArrayInputStream signatureStream = new ByteArrayInputStream(messageSyntaxSignature);
+            final PEMParser pemParser = new PEMParser(new InputStreamReader(signatureStream))) {
             final Object parsedObject = pemParser.readObject();
             if (!(parsedObject instanceof ContentInfo)) {
                 throw new SecurityManagerException("Signature is not recognized");
             }
-            final ContentInfo signature = ContentInfo.getInstance(parsedObject);
-            final CMSTypedData signedContent = new CMSProcessableByteArray(innerPackageFile);
-            final CMSSignedData signedData = new CMSSignedData(signedContent, signature);
-            final Collection<SignerInformation> signers = signedData.getSignerInfos().getSigners();
-            final SignerInformation firstSigner = signers.iterator().next();
-            final X509Certificate cert;
-            Collection<X509CertificateHolder> certs;
-            if (packageCert == null) {
-                certs = signedData.getCertificates().getMatches(null);
-                cert = readSignCert(certs, firstSigner)
-                    .orElseThrow(() -> new SecurityManagerException("No certificate found in cms signature that should contain one!"));
-            } else {
-                certs = parseCertsFromPem(packageCert);
-                cert = readSignCert(certs, firstSigner)
-                    .orElseThrow(() -> new SecurityManagerException("No matching certificate found in certificate file that should contain one!"));
+            return verify(packageCert, new CMSSignedData(new CMSProcessableByteArray(innerPackageFile), ContentInfo.getInstance(parsedObject)));
+        } catch (final IOException | CMSException e) {
+            logger.error(e.getMessage(), e);
+            throw new SecurityManagerException(UNEXPECTED_ERROR_OCCURRED_DURING_SIGNATURE_VALIDATION, e);
+        }
+    }
+
+    public boolean verifyPackageSignedData(final OnboardSignedPackage signedPackage, final ArtifactInfo artifactInfo)
+        throws SecurityManagerException {
+        boolean fail = false;
+        final var fileContentHandler = signedPackage.getFileContentHandler();
+        byte[] packageCert = null;
+        final Optional<String> certificateFilePath = signedPackage.getCertificateFilePath();
+        if (certificateFilePath.isPresent()) {
+            packageCert = fileContentHandler.getFileContent(certificateFilePath.get());
+        }
+        final var path = artifactInfo.getPath();
+        final var target = Path.of(path.toString() + "." + UUID.randomUUID());
+
+        try (final var signatureStream = new ByteArrayInputStream(fileContentHandler.getFileContent(signedPackage.getSignatureFilePath()));
+            final var pemParser = new PEMParser(new InputStreamReader(signatureStream))) {
+            final var parsedObject = pemParser.readObject();
+            if (!(parsedObject instanceof ContentInfo)) {
+                fail = true;
+                throw new SecurityManagerException("Signature is not recognized");
             }
-            trustedCertificatesFromPackage = readTrustedCerts(certs, firstSigner);
-            if (verifyCertificate(cert, getTrustedCertificates()) == null) {
+
+            if (!findCSARandExtract(path, target)) {
+                fail = true;
                 return false;
             }
-            return firstSigner.verify(new JcaSimpleSignerInfoVerifierBuilder().build(cert));
-        } catch (OperatorCreationException | IOException | CMSException e) {
+            final var verify = verify(packageCert, new CMSSignedData(new CMSProcessableFile(target.toFile()), ContentInfo.getInstance(parsedObject)));
+            fail = !verify;
+            return verify;
+        } catch (final IOException e) {
+            fail = true;
             logger.error(e.getMessage(), e);
-            throw new SecurityManagerException("Unexpected error occurred during signature validation!", e);
-        } catch (GeneralSecurityException e) {
-            throw new SecurityManagerException("Could not verify signature!", e);
+            throw new SecurityManagerException(UNEXPECTED_ERROR_OCCURRED_DURING_SIGNATURE_VALIDATION, e);
+        } catch (final CMSException e) {
+            fail = true;
+            throw new SecurityManagerException(COULD_NOT_VERIFY_SIGNATURE, e);
+        } catch (final SecurityManagerException e) {
+            fail = true;
+            throw e;
+        } finally {
+            deleteFile(target);
+            if (fail) {
+                deleteFile(path);
+            }
+        }
+    }
+
+    private void deleteFile(final Path filePath) {
+        try {
+            Files.delete(filePath);
+        } catch (final IOException e) {
+            logger.warn("Failed to delete '{}' after verifying package signed data", filePath, e);
         }
     }
 
+    private boolean verify(final byte[] packageCert, final CMSSignedData signedData) throws SecurityManagerException {
+        final SignerInformation firstSigner = signedData.getSignerInfos().getSigners().iterator().next();
+        final X509Certificate cert;
+        Collection<X509CertificateHolder> certs;
+        if (packageCert == null) {
+            certs = signedData.getCertificates().getMatches(null);
+            cert = readSignCert(certs, firstSigner)
+                .orElseThrow(() -> new SecurityManagerException("No certificate found in cms signature that should contain one!"));
+        } else {
+            try {
+                certs = parseCertsFromPem(packageCert);
+            } catch (final IOException e) {
+                throw new SecurityManagerException("Failed to parse certificate from PEM", e);
+            }
+            cert = readSignCert(certs, firstSigner)
+                .orElseThrow(() -> new SecurityManagerException("No matching certificate found in certificate file that should contain one!"));
+        }
+        trustedCertificatesFromPackage = readTrustedCerts(certs, firstSigner);
+        if (verifyCertificate(cert, getTrustedCertificates()) == null) {
+            return false;
+        }
+        try {
+            return firstSigner.verify(new JcaSimpleSignerInfoVerifierBuilder().build(cert));
+        } catch (CMSException | OperatorCreationException e) {
+            throw new SecurityManagerException("Failed to verify package signed data", e);
+        }
+    }
+
+    private boolean findCSARandExtract(final Path path, final Path target) throws IOException {
+        final AtomicBoolean found = new AtomicBoolean(false);
+        try (final var zf = new ZipFile(path.toString())) {
+            zf.entries().asIterator().forEachRemaining(entry -> {
+                final var entryName = entry.getName();
+                if (!entry.isDirectory() && entryName.toLowerCase().endsWith(".csar")) {
+                    try {
+                        Files.copy(zf.getInputStream(entry), target, REPLACE_EXISTING);
+                    } catch (final IOException e) {
+                        throw new SdcRuntimeException(UNEXPECTED_ERROR_OCCURRED_DURING_SIGNATURE_VALIDATION, e);
+                    }
+                    found.set(true);
+                }
+            });
+        }
+        return found.get();
+    }
+
     private Optional<X509Certificate> readSignCert(final Collection<X509CertificateHolder> certs, final SignerInformation firstSigner) {
         return certs.stream().filter(crt -> firstSigner.getSID().match(crt)).findAny().map(this::loadCertificate);
     }
@@ -205,7 +287,7 @@ public class SecurityManager {
         return allCerts;
     }
 
-    private void processCertificateDir() throws SecurityManagerException, FileNotFoundException {
+    private void processCertificateDir() throws SecurityManagerException {
         if (!certificateDirectory.exists() || !certificateDirectory.isDirectory()) {
             logger.error("Issue with certificate directory, check if exists!");
             return;
@@ -253,8 +335,8 @@ public class SecurityManager {
         }
     }
 
-    private PKIXCertPathBuilderResult verifyCertificate(X509Certificate cert, Set<X509Certificate> additionalCerts)
-        throws GeneralSecurityException, SecurityManagerException {
+    private PKIXCertPathBuilderResult verifyCertificate(final X509Certificate cert,
+                                                        final Set<X509Certificate> additionalCerts) throws SecurityManagerException {
         if (null == cert) {
             throw new SecurityManagerException("The certificate is empty!");
         }
@@ -273,7 +355,11 @@ public class SecurityManager {
                 intermediateCerts.add(additionalCert);
             }
         }
-        return verifyCertificate(cert, trustedRootCerts, intermediateCerts);
+        try {
+            return verifyCertificate(cert, trustedRootCerts, intermediateCerts);
+        } catch (final GeneralSecurityException e) {
+            throw new SecurityManagerException("Failed to verify certificate", e);
+        }
     }
 
     private PKIXCertPathBuilderResult verifyCertificate(X509Certificate cert, Set<X509Certificate> allTrustedRootCerts,
@@ -325,4 +411,12 @@ public class SecurityManager {
     private boolean isSelfSigned(X509Certificate cert) {
         return cert.getIssuerDN().equals(cert.getSubjectDN());
     }
+
+    /**
+     * Initialization on demand class / synchronized singleton pattern.
+     */
+    private static class SecurityManagerInstanceHolder {
+
+        private static final SecurityManager instance = new SecurityManager();
+    }
 }
index 5f5f9eb..96d11eb 100644 (file)
@@ -19,6 +19,7 @@
 
 package org.openecomp.sdc.vendorsoftwareproduct.impl.orchestration.csar.validation;
 
+import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
 import static org.hamcrest.core.Is.is;
 import static org.junit.Assert.assertThat;
 import static org.junit.Assert.fail;
@@ -27,12 +28,21 @@ import static org.mockito.Mockito.when;
 import static org.mockito.MockitoAnnotations.initMocks;
 
 import java.io.IOException;
+import java.net.URI;
 import java.net.URISyntaxException;
 import java.nio.file.Files;
+import java.nio.file.Path;
 import java.nio.file.Paths;
-import org.junit.Before;
-import org.junit.Test;
+import java.util.List;
+import java.util.UUID;
+import java.util.stream.Collectors;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
 import org.mockito.Mock;
+import org.openecomp.sdc.be.csar.storage.ArtifactInfo;
+import org.openecomp.sdc.be.csar.storage.PersistentStorageArtifactInfo;
 import org.openecomp.sdc.vendorsoftwareproduct.impl.onboarding.OnboardingPackageProcessor;
 import org.openecomp.sdc.vendorsoftwareproduct.impl.onboarding.validation.CnfPackageValidator;
 import org.openecomp.sdc.vendorsoftwareproduct.security.SecurityManager;
@@ -40,37 +50,88 @@ import org.openecomp.sdc.vendorsoftwareproduct.security.SecurityManagerException
 import org.openecomp.sdc.vendorsoftwareproduct.types.OnboardPackageInfo;
 import org.openecomp.sdc.vendorsoftwareproduct.types.OnboardSignedPackage;
 
-public class CsarSecurityValidatorTest {
+class CsarSecurityValidatorTest {
 
-    private static final String BASE_DIR = "/vspmanager.csar/";
+    private static final String BASE_DIR = "/vspmanager.csar/signing/";
+    private static final String DELIMITER = "---";
     private CsarSecurityValidator csarSecurityValidator;
     @Mock
-    SecurityManager securityManager;
+    private SecurityManager securityManager;
 
-    @Before
-    public void setUp() {
+    @AfterEach
+    void tearDown() throws Exception {
+        restore();
+    }
+
+    private void restore() throws Exception {
+        final URI uri = CsarSecurityValidatorTest.class.getResource(BASE_DIR).toURI();
+        final List<Path> list = Files.list(Path.of(uri.getPath())).filter(path -> path.toString().contains(DELIMITER)).collect(Collectors.toList());
+        for (final Path path : list) {
+            final String[] split = path.toString().split(DELIMITER);
+            Files.move(path, Path.of(split[0]), REPLACE_EXISTING);
+        }
+    }
+
+    @BeforeEach
+    public void setUp() throws Exception {
         initMocks(this);
         csarSecurityValidator = new CsarSecurityValidator(securityManager);
+        backup();
+    }
+
+    private void backup() throws Exception {
+        final URI uri = CsarSecurityValidatorTest.class.getResource(BASE_DIR).toURI();
+        final List<Path> list = Files.list(Path.of(uri.getPath())).collect(Collectors.toList());
+        for (final Path path : list) {
+            Files.copy(path, Path.of(path.toString() + DELIMITER + UUID.randomUUID()), REPLACE_EXISTING);
+        }
     }
 
     @Test
-    public void isSignatureValidTestCorrectStructureAndValidSignatureExists() throws SecurityManagerException {
-        final byte[] packageBytes = getFileBytesOrFail("signing/signed-package.zip");
-        final OnboardSignedPackage onboardSignedPackage = loadSignedPackage("signed-package.zip",
+    void isSignatureValidTestCorrectStructureAndValidSignatureExists() throws SecurityManagerException, IOException {
+        final byte[] packageBytes = getFileBytesOrFail("signed-package.zip");
+        final OnboardPackageInfo onboardPackageInfo = loadSignedPackageWithArtifactInfo("signed-package.zip", packageBytes, null);
+        when(securityManager.verifyPackageSignedData(any(OnboardSignedPackage.class), any(ArtifactInfo.class))).thenReturn(true);
+        final boolean isSignatureValid = csarSecurityValidator
+            .verifyPackageSignature((OnboardSignedPackage) onboardPackageInfo.getOriginalOnboardPackage(), onboardPackageInfo.getArtifactInfo());
+        assertThat("Signature should be valid", isSignatureValid, is(true));
+    }
+
+    @Test
+    void isSignatureValidTestCorrectStructureAndNotValidSignatureExists() throws SecurityManagerException {
+        final byte[] packageBytes = getFileBytesOrFail("signed-package-tampered-data.zip");
+        final OnboardPackageInfo onboardPackageInfo = loadSignedPackageWithArtifactInfo("signed-package-tampered-data.zip", packageBytes, null);
+        //no mocked securityManager
+        csarSecurityValidator = new CsarSecurityValidator();
+        Assertions.assertThrows(SecurityManagerException.class, () -> {
+            csarSecurityValidator
+                .verifyPackageSignature((OnboardSignedPackage) onboardPackageInfo.getOriginalOnboardPackage(), onboardPackageInfo.getArtifactInfo());
+        });
+    }
+
+    @Test
+    void isSignatureValidTestCorrectStructureAndValidSignatureExistsArtifactStorageManagerIsEnabled() throws SecurityManagerException {
+        final byte[] packageBytes = getFileBytesOrFail("signed-package.zip");
+        final OnboardPackageInfo onboardPackageInfo = loadSignedPackageWithoutArtifactInfo("signed-package.zip",
             packageBytes, null);
         when(securityManager.verifySignedData(any(), any(), any())).thenReturn(true);
-        final boolean isSignatureValid = csarSecurityValidator.verifyPackageSignature(onboardSignedPackage);
+        final boolean isSignatureValid = csarSecurityValidator
+            .verifyPackageSignature((OnboardSignedPackage) onboardPackageInfo.getOriginalOnboardPackage(), onboardPackageInfo.getArtifactInfo());
+
         assertThat("Signature should be valid", isSignatureValid, is(true));
     }
 
-    @Test(expected = SecurityManagerException.class)
-    public void isSignatureValidTestCorrectStructureAndNotValidSignatureExists() throws SecurityManagerException {
-        final byte[] packageBytes = getFileBytesOrFail("signing/signed-package-tampered-data.zip");
-        final OnboardSignedPackage onboardSignedPackage = loadSignedPackage("signed-package-tampered-data.zip",
+    @Test
+    void isSignatureValidTestCorrectStructureAndNotValidSignatureExistsArtifactStorageManagerIsEnabled() throws SecurityManagerException {
+        final byte[] packageBytes = getFileBytesOrFail("signed-package-tampered-data.zip");
+        final OnboardPackageInfo onboardPackageInfo = loadSignedPackageWithoutArtifactInfo("signed-package-tampered-data.zip",
             packageBytes, null);
         //no mocked securityManager
         csarSecurityValidator = new CsarSecurityValidator();
-        csarSecurityValidator.verifyPackageSignature(onboardSignedPackage);
+        Assertions.assertThrows(SecurityManagerException.class, () -> {
+            csarSecurityValidator
+                .verifyPackageSignature((OnboardSignedPackage) onboardPackageInfo.getOriginalOnboardPackage(), onboardPackageInfo.getArtifactInfo());
+        });
     }
 
     private byte[] getFileBytesOrFail(final String path) {
@@ -87,8 +148,21 @@ public class CsarSecurityValidatorTest {
             CsarSecurityValidatorTest.class.getResource(BASE_DIR + path).toURI()));
     }
 
-    private OnboardSignedPackage loadSignedPackage(final String packageName, final byte[] packageBytes,
-        CnfPackageValidator cnfPackageValidator) {
+    private OnboardPackageInfo loadSignedPackageWithArtifactInfo(final String packageName, final byte[] packageBytes,
+                                                                 final CnfPackageValidator cnfPackageValidator) {
+        final OnboardingPackageProcessor onboardingPackageProcessor =
+            new OnboardingPackageProcessor(packageName, packageBytes, cnfPackageValidator,
+                new PersistentStorageArtifactInfo(Path.of("src/test/resources/vspmanager.csar/signing/signed-package.zip")));
+        final OnboardPackageInfo onboardPackageInfo = onboardingPackageProcessor.getOnboardPackageInfo().orElse(null);
+        if (onboardPackageInfo == null) {
+            fail("Unexpected error. Could not load original package");
+        }
+
+        return onboardPackageInfo;
+    }
+
+    private OnboardPackageInfo loadSignedPackageWithoutArtifactInfo(final String packageName, final byte[] packageBytes,
+                                                                    final CnfPackageValidator cnfPackageValidator) {
         final OnboardingPackageProcessor onboardingPackageProcessor =
             new OnboardingPackageProcessor(packageName, packageBytes, cnfPackageValidator, null);
         final OnboardPackageInfo onboardPackageInfo = onboardingPackageProcessor.getOnboardPackageInfo().orElse(null);
@@ -96,6 +170,6 @@ public class CsarSecurityValidatorTest {
             fail("Unexpected error. Could not load original package");
         }
 
-        return (OnboardSignedPackage) onboardPackageInfo.getOriginalOnboardPackage();
+        return onboardPackageInfo;
     }
 }
index b5479e0..6dc5517 100644 (file)
@@ -27,14 +27,20 @@ import java.io.File;
 import java.io.IOException;
 import java.net.URISyntaxException;
 import java.nio.file.Files;
+import java.nio.file.Path;
 import java.nio.file.Paths;
 import org.apache.commons.io.FileUtils;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
+import org.openecomp.sdc.be.csar.storage.PersistentStorageArtifactInfo;
+import org.openecomp.sdc.vendorsoftwareproduct.impl.onboarding.OnboardingPackageProcessor;
+import org.openecomp.sdc.vendorsoftwareproduct.impl.onboarding.validation.CnfPackageValidator;
+import org.openecomp.sdc.vendorsoftwareproduct.types.OnboardPackageInfo;
+import org.openecomp.sdc.vendorsoftwareproduct.types.OnboardSignedPackage;
 
-public class SecurityManagerTest {
+class SecurityManagerTest {
 
     private File certDir;
     private String cerDirPath = "/tmp/cert/";
@@ -71,7 +77,7 @@ public class SecurityManagerTest {
     }
 
     @Test
-    public void testGetCertificates() throws IOException, SecurityManagerException, URISyntaxException {
+    void testGetCertificates() throws IOException, SecurityManagerException, URISyntaxException {
         File newFile = prepareCertFiles("/cert/root-certificate.pem", cerDirPath + "/root-certificate.pem");
         assertEquals(1, securityManager.getTrustedCertificates().size());
         newFile.delete();
@@ -79,13 +85,13 @@ public class SecurityManagerTest {
     }
 
     @Test
-    public void testGetCertificatesNoDirectory() throws IOException, SecurityManagerException {
+    void testGetCertificatesNoDirectory() throws IOException, SecurityManagerException {
         certDir.delete();
         assertEquals(0, securityManager.getTrustedCertificates().size());
     }
 
     @Test
-    public void testGetCertificatesException() throws IOException, SecurityManagerException {
+    void testGetCertificatesException() throws IOException, SecurityManagerException {
         File newFile = new File(cerDirPath + "root-certificate.pem");
         newFile.createNewFile();
         Assertions.assertThrows(SecurityManagerException.class, () -> {
@@ -97,9 +103,9 @@ public class SecurityManagerTest {
     }
 
     @Test
-    public void testGetCertificatesUpdated() throws IOException, SecurityManagerException, URISyntaxException {
+    void testGetCertificatesUpdated() throws IOException, SecurityManagerException, URISyntaxException {
         File newFile = prepareCertFiles("/cert/root-certificate.pem", cerDirPath + "root-certificate.pem");
-        assertTrue(securityManager.getTrustedCertificates().size() == 1);
+        assertEquals(1, securityManager.getTrustedCertificates().size());
         File otherNewFile = prepareCertFiles("/cert/package-certificate.pem", cerDirPath + "package-certificate.pem");
         assertEquals(2, securityManager.getTrustedCertificates().size());
         otherNewFile.delete();
@@ -109,7 +115,7 @@ public class SecurityManagerTest {
     }
 
     @Test
-    public void verifySignedDataTestCertIncludedIntoSignature() throws IOException, URISyntaxException, SecurityManagerException {
+    void verifySignedDataTestCertIncludedIntoSignature() throws IOException, URISyntaxException, SecurityManagerException {
         prepareCertFiles("/cert/rootCA.cert", cerDirPath + "root.cert");
         byte[] signature = readAllBytes("/cert/2-file-signed-package/dummyPnfv4.cms");
         byte[] archive = readAllBytes("/cert/2-file-signed-package/dummyPnfv4.csar");
@@ -117,7 +123,22 @@ public class SecurityManagerTest {
     }
 
     @Test
-    public void verifySignedDataTestCertNotIncludedIntoSignatureButExpected() throws IOException, URISyntaxException, SecurityManagerException {
+    void verifySignedDataTestCertIncludedIntoSignatureArtifactStorageManagerIsEnabled()
+        throws IOException, URISyntaxException, SecurityManagerException {
+        prepareCertFiles("/cert/rootCA.cert", cerDirPath + "root.cert");
+        byte[] fileToUploadBytes = readAllBytes("/cert/2-file-signed-package/2-file-signed-package.zip");
+
+        final var onboardingPackageProcessor = new OnboardingPackageProcessor("2-file-signed-package.zip", fileToUploadBytes,
+            new CnfPackageValidator(),
+            new PersistentStorageArtifactInfo(Path.of("src/test/resources/cert/2-file-signed-package/2-file-signed-package.zip")));
+        final OnboardPackageInfo onboardPackageInfo = onboardingPackageProcessor.getOnboardPackageInfo().orElse(null);
+
+        assertTrue(securityManager
+            .verifyPackageSignedData((OnboardSignedPackage) onboardPackageInfo.getOriginalOnboardPackage(), onboardPackageInfo.getArtifactInfo()));
+    }
+
+    @Test
+    void verifySignedDataTestCertNotIncludedIntoSignatureButExpected() throws IOException, URISyntaxException, SecurityManagerException {
         Assertions.assertThrows(SecurityManagerException.class, () -> {
             prepareCertFiles("/cert/root.cert", cerDirPath + "root.cert");
             byte[] signature = readAllBytes("/cert/3-file-signed-package/dummyPnfv4.cms");
@@ -128,7 +149,7 @@ public class SecurityManagerTest {
     }
 
     @Test
-    public void verifySignedDataTestCertNotIncludedIntoSignature() throws IOException, URISyntaxException, SecurityManagerException {
+    void verifySignedDataTestCertNotIncludedIntoSignature() throws IOException, URISyntaxException, SecurityManagerException {
         prepareCertFiles("/cert/rootCA.cert", cerDirPath + "root.cert");
         byte[] signature = readAllBytes("/cert/3-file-signed-package/dummyPnfv4.cms");
         byte[] archive = readAllBytes("/cert/3-file-signed-package/dummyPnfv4.csar");
@@ -137,7 +158,22 @@ public class SecurityManagerTest {
     }
 
     @Test
-    public void verifySignedDataTestCertIntermediateNotIncludedIntoSignature() throws IOException, URISyntaxException, SecurityManagerException {
+    void verifySignedDataTestCertNotIncludedIntoSignatureArtifactStorageManagerIsEnabled()
+        throws IOException, URISyntaxException, SecurityManagerException {
+        prepareCertFiles("/cert/rootCA.cert", cerDirPath + "root.cert");
+        byte[] fileToUploadBytes = readAllBytes("/cert/3-file-signed-package/3-file-signed-package.zip");
+
+        final var onboardingPackageProcessor = new OnboardingPackageProcessor("3-file-signed-package.zip", fileToUploadBytes,
+            new CnfPackageValidator(),
+            new PersistentStorageArtifactInfo(Path.of("src/test/resources/cert/3-file-signed-package/3-file-signed-package.zip")));
+        final OnboardPackageInfo onboardPackageInfo = onboardingPackageProcessor.getOnboardPackageInfo().orElse(null);
+
+        assertTrue(securityManager
+            .verifyPackageSignedData((OnboardSignedPackage) onboardPackageInfo.getOriginalOnboardPackage(), onboardPackageInfo.getArtifactInfo()));
+    }
+
+    @Test
+    void verifySignedDataTestCertIntermediateNotIncludedIntoSignature() throws IOException, URISyntaxException, SecurityManagerException {
         prepareCertFiles("/cert/rootCA.cert", cerDirPath + "root.cert");
         prepareCertFiles("/cert/package2.cert", cerDirPath + "signing-ca2.crt");
         byte[] signature = readAllBytes("/cert/3-file-signed-package/dummyPnfv4.cms");
@@ -147,7 +183,7 @@ public class SecurityManagerTest {
     }
 
     @Test
-    public void verifySignedDataTestCertWrongIntermediate() throws IOException, URISyntaxException, SecurityManagerException {
+    void verifySignedDataTestCertWrongIntermediate() throws IOException, URISyntaxException, SecurityManagerException {
         Assertions.assertThrows(SecurityManagerException.class, () -> {
             prepareCertFiles("/cert/root.cert", cerDirPath + "root.cert");
             prepareCertFiles("/cert/signing-ca1.crt", cerDirPath + "signing-ca1.crt");
@@ -160,7 +196,7 @@ public class SecurityManagerTest {
     }
 
     @Test
-    public void verifySignedDataTestCertIncludedIntoSignatureWithWrongIntermediateInDirectory()
+    void verifySignedDataTestCertIncludedIntoSignatureWithWrongIntermediateInDirectory()
         throws IOException, URISyntaxException, SecurityManagerException {
         prepareCertFiles("/cert/rootCA.cert", cerDirPath + "root.cert");
         prepareCertFiles("/cert/signing-ca1.crt", cerDirPath + "signing-ca1.crt");
@@ -170,7 +206,7 @@ public class SecurityManagerTest {
     }
 
     @Test
-    public void verifySignedDataTestCertWrongIntermediateInDirectory() throws IOException, URISyntaxException, SecurityManagerException {
+    void verifySignedDataTestCertWrongIntermediateInDirectory() throws IOException, URISyntaxException, SecurityManagerException {
         prepareCertFiles("/cert/rootCA.cert", cerDirPath + "root.cert");
         prepareCertFiles("/cert/signing-ca1.crt", cerDirPath + "signing-ca1.crt");
         byte[] signature = readAllBytes("/cert/3-file-signed-package/dummyPnfv4.cms");
@@ -180,7 +216,7 @@ public class SecurityManagerTest {
     }
 
     @Test
-    public void verifySignedDataTestWrongCertificate() throws IOException, URISyntaxException, SecurityManagerException {
+    void verifySignedDataTestWrongCertificate() throws IOException, URISyntaxException, SecurityManagerException {
         Assertions.assertThrows(SecurityManagerException.class, () -> {
             prepareCertFiles("/cert/root-certificate.pem", cerDirPath + "root-certificate.cert");
             byte[] signature = readAllBytes("/cert/3-file-signed-package/dummyPnfv4.cms");
@@ -192,7 +228,7 @@ public class SecurityManagerTest {
     }
 
     @Test
-    public void verifySignedDataTestChangedArchive() throws IOException, URISyntaxException, SecurityManagerException {
+    void verifySignedDataTestChangedArchive() throws IOException, URISyntaxException, SecurityManagerException {
         Assertions.assertThrows(SecurityManagerException.class, () -> {
             prepareCertFiles("/cert/root.cert", cerDirPath + "root.cert");
             byte[] signature = readAllBytes("/cert/tampered-signed-package/dummyPnfv4.cms");
diff --git a/openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/test/resources/cert/2-file-signed-package/2-file-signed-package.zip b/openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/test/resources/cert/2-file-signed-package/2-file-signed-package.zip
new file mode 100644 (file)
index 0000000..be48e8a
Binary files /dev/null and b/openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/test/resources/cert/2-file-signed-package/2-file-signed-package.zip differ
diff --git a/openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/test/resources/cert/3-file-signed-package/3-file-signed-package.zip b/openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/test/resources/cert/3-file-signed-package/3-file-signed-package.zip
new file mode 100644 (file)
index 0000000..7f2eacb
Binary files /dev/null and b/openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/test/resources/cert/3-file-signed-package/3-file-signed-package.zip differ