2 * ============LICENSE_START=======================================================
3 * Copyright (C) 2019 Nordix Foundation
4 * ================================================================================
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 * SPDX-License-Identifier: Apache-2.0
17 * ============LICENSE_END=========================================================
20 package org.openecomp.sdc.vendorsoftwareproduct.impl.orchestration.csar.validation;
22 import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
23 import static org.hamcrest.core.Is.is;
24 import static org.junit.Assert.assertThat;
25 import static org.junit.Assert.fail;
26 import static org.mockito.ArgumentMatchers.any;
27 import static org.mockito.ArgumentMatchers.anyBoolean;
28 import static org.mockito.ArgumentMatchers.anyInt;
29 import static org.mockito.ArgumentMatchers.anyString;
30 import static org.mockito.ArgumentMatchers.eq;
31 import static org.mockito.Mockito.when;
32 import static org.mockito.MockitoAnnotations.openMocks;
33 import static org.openecomp.sdc.be.csar.storage.StorageFactory.StorageType.MINIO;
35 import io.minio.GetObjectArgs;
36 import io.minio.GetObjectResponse;
37 import io.minio.MinioClient;
38 import java.io.BufferedInputStream;
39 import java.io.ByteArrayInputStream;
40 import java.io.IOException;
42 import java.net.URISyntaxException;
43 import java.nio.file.Files;
44 import java.nio.file.Path;
45 import java.nio.file.Paths;
46 import java.util.HashMap;
47 import java.util.List;
49 import java.util.UUID;
50 import java.util.stream.Collectors;
51 import org.junit.jupiter.api.AfterEach;
52 import org.junit.jupiter.api.Assertions;
53 import org.junit.jupiter.api.BeforeEach;
54 import org.junit.jupiter.api.Test;
55 import org.junit.jupiter.api.extension.ExtendWith;
56 import org.mockito.Answers;
57 import org.mockito.Mock;
58 import org.mockito.MockedStatic;
59 import org.mockito.Mockito;
60 import org.mockito.junit.jupiter.MockitoExtension;
61 import org.openecomp.sdc.be.csar.storage.ArtifactInfo;
62 import org.openecomp.sdc.be.csar.storage.MinIoArtifactInfo;
63 import org.openecomp.sdc.common.CommonConfigurationManager;
64 import org.openecomp.sdc.vendorsoftwareproduct.impl.onboarding.OnboardingPackageProcessor;
65 import org.openecomp.sdc.vendorsoftwareproduct.impl.onboarding.validation.CnfPackageValidator;
66 import org.openecomp.sdc.vendorsoftwareproduct.security.SecurityManager;
67 import org.openecomp.sdc.vendorsoftwareproduct.security.SecurityManagerException;
68 import org.openecomp.sdc.vendorsoftwareproduct.types.OnboardPackageInfo;
69 import org.openecomp.sdc.vendorsoftwareproduct.types.OnboardSignedPackage;
71 @ExtendWith(MockitoExtension.class)
72 class CsarSecurityValidatorTest {
74 private static final String BASE_DIR = "/vspmanager.csar/signing/";
75 private static final String DELIMITER = "---";
76 private CsarSecurityValidator csarSecurityValidator;
78 private SecurityManager securityManager;
80 private CommonConfigurationManager commonConfigurationManager;
82 private MinioClient minioClient;
83 @Mock(answer = Answers.RETURNS_DEEP_STUBS)
84 private MinioClient.Builder builderMinio;
85 @Mock(answer = Answers.RETURNS_DEEP_STUBS)
86 private GetObjectArgs.Builder getObjectArgsBuilder;
88 private GetObjectArgs getObjectArgs;
91 void tearDown() throws Exception {
95 private void restore() throws Exception {
96 final URI uri = CsarSecurityValidatorTest.class.getResource(BASE_DIR).toURI();
97 final List<Path> list = Files.list(Path.of(uri.getPath())).filter(path -> path.toString().contains(DELIMITER)).collect(Collectors.toList());
98 for (final Path path : list) {
99 final String[] split = path.toString().split(DELIMITER);
100 Files.move(path, Path.of(split[0]), REPLACE_EXISTING);
105 public void setUp() throws Exception {
107 csarSecurityValidator = new CsarSecurityValidator(securityManager);
111 private void backup() throws Exception {
112 final URI uri = CsarSecurityValidatorTest.class.getResource(BASE_DIR).toURI();
113 final List<Path> list = Files.list(Path.of(uri.getPath())).collect(Collectors.toList());
114 for (final Path path : list) {
115 Files.copy(path, Path.of(path.toString() + DELIMITER + UUID.randomUUID()), REPLACE_EXISTING);
120 void isSignatureValidTestCorrectStructureAndValidSignatureExists() throws SecurityManagerException {
121 final byte[] packageBytes = getFileBytesOrFail("signed-package.zip");
122 final OnboardPackageInfo onboardPackageInfo = loadSignedPackageWithArtifactInfoS3Store("signed-package.zip", packageBytes, null);
123 when(securityManager.verifyPackageSignedData(any(OnboardSignedPackage.class), any(ArtifactInfo.class))).thenReturn(true);
124 final boolean isSignatureValid = csarSecurityValidator
125 .verifyPackageSignature((OnboardSignedPackage) onboardPackageInfo.getOriginalOnboardPackage(), onboardPackageInfo.getArtifactInfo());
126 assertThat("Signature should be valid", isSignatureValid, is(true));
130 void isSignatureValidTestCorrectStructureAndNotValidSignatureExists() throws Exception {
132 final Map<String, Object> endpoint = new HashMap<>();
133 endpoint.put("host", "localhost");
134 endpoint.put("port", 9000);
135 final Map<String, Object> credentials = new HashMap<>();
136 credentials.put("accessKey", "login");
137 credentials.put("secretKey", "password");
139 try (MockedStatic<CommonConfigurationManager> utilities = Mockito.mockStatic(CommonConfigurationManager.class)) {
140 utilities.when(CommonConfigurationManager::getInstance).thenReturn(commonConfigurationManager);
141 try (MockedStatic<MinioClient> minioUtilities = Mockito.mockStatic(MinioClient.class)) {
142 minioUtilities.when(MinioClient::builder).thenReturn(builderMinio);
144 .endpoint(anyString(), anyInt(), anyBoolean())
145 .credentials(anyString(), anyString())
147 ).thenReturn(minioClient);
149 when(commonConfigurationManager.getConfigValue("externalCsarStore", "endpoint", null)).thenReturn(endpoint);
150 when(commonConfigurationManager.getConfigValue("externalCsarStore", "credentials", null)).thenReturn(credentials);
151 when(commonConfigurationManager.getConfigValue("externalCsarStore", "tempPath", null)).thenReturn("cert/2-file-signed-package");
152 when(commonConfigurationManager.getConfigValue(eq("externalCsarStore"), eq("storageType"), any())).thenReturn(MINIO.name());
153 when(commonConfigurationManager.getConfigValue(eq("externalCsarStore"), eq("uploadPartSize"), any())).thenReturn(50_000_000);
155 final byte[] packageBytes = getFileBytesOrFail("signed-package-tampered-data.zip");
157 when(getObjectArgsBuilder
161 ).thenReturn(getObjectArgs);
163 when(minioClient.getObject(any(GetObjectArgs.class)))
164 .thenReturn(new GetObjectResponse(null, "bucket", "", "objectName",
165 new BufferedInputStream(new ByteArrayInputStream(packageBytes))));
167 final OnboardPackageInfo onboardPackageInfo = loadSignedPackageWithArtifactInfoS3Store("signed-package-tampered-data.zip",
170 //no mocked securityManager
171 csarSecurityValidator = new CsarSecurityValidator();
172 Assertions.assertThrows(SecurityManagerException.class, () -> {
173 csarSecurityValidator.verifyPackageSignature((OnboardSignedPackage) onboardPackageInfo.getOriginalOnboardPackage(),
174 onboardPackageInfo.getArtifactInfo());
181 void isSignatureValidTestCorrectStructureAndValidSignatureExistsArtifactStorageManagerIsEnabled() throws SecurityManagerException {
182 final byte[] packageBytes = getFileBytesOrFail("signed-package.zip");
183 final OnboardPackageInfo onboardPackageInfo = loadSignedPackageWithoutArtifactInfo("signed-package.zip",
185 when(securityManager.verifySignedData(any(), any(), any())).thenReturn(true);
186 final boolean isSignatureValid = csarSecurityValidator
187 .verifyPackageSignature((OnboardSignedPackage) onboardPackageInfo.getOriginalOnboardPackage(), onboardPackageInfo.getArtifactInfo());
189 assertThat("Signature should be valid", isSignatureValid, is(true));
193 void isSignatureValidTestCorrectStructureAndNotValidSignatureExistsArtifactStorageManagerIsEnabled() throws SecurityManagerException {
194 final byte[] packageBytes = getFileBytesOrFail("signed-package-tampered-data.zip");
195 final OnboardPackageInfo onboardPackageInfo = loadSignedPackageWithoutArtifactInfo("signed-package-tampered-data.zip",
197 //no mocked securityManager
198 csarSecurityValidator = new CsarSecurityValidator();
199 Assertions.assertThrows(SecurityManagerException.class, () -> {
200 csarSecurityValidator
201 .verifyPackageSignature((OnboardSignedPackage) onboardPackageInfo.getOriginalOnboardPackage(), onboardPackageInfo.getArtifactInfo());
205 private byte[] getFileBytesOrFail(final String path) {
207 return getFileBytes(path);
208 } catch (final URISyntaxException | IOException e) {
209 fail("Could not load file " + path);
214 private byte[] getFileBytes(final String path) throws URISyntaxException, IOException {
215 return Files.readAllBytes(Paths.get(
216 CsarSecurityValidatorTest.class.getResource(BASE_DIR + path).toURI()));
219 private OnboardPackageInfo loadSignedPackageWithArtifactInfoS3Store(final String packageName, final byte[] packageBytes,
220 final CnfPackageValidator cnfPackageValidator) {
221 final OnboardingPackageProcessor onboardingPackageProcessor =
222 new OnboardingPackageProcessor(packageName, packageBytes, cnfPackageValidator, new MinIoArtifactInfo("bucket", "object"));
223 final OnboardPackageInfo onboardPackageInfo = onboardingPackageProcessor.getOnboardPackageInfo().orElse(null);
224 if (onboardPackageInfo == null) {
225 fail("Unexpected error. Could not load original package");
228 return onboardPackageInfo;
231 private OnboardPackageInfo loadSignedPackageWithoutArtifactInfo(final String packageName, final byte[] packageBytes,
232 final CnfPackageValidator cnfPackageValidator) {
233 final OnboardingPackageProcessor onboardingPackageProcessor =
234 new OnboardingPackageProcessor(packageName, packageBytes, cnfPackageValidator, null);
235 final OnboardPackageInfo onboardPackageInfo = onboardingPackageProcessor.getOnboardPackageInfo().orElse(null);
236 if (onboardPackageInfo == null) {
237 fail("Unexpected error. Could not load original package");
240 return onboardPackageInfo;