Implement improved MinIo client
[sdc.git] / openecomp-be / backend / openecomp-sdc-vendor-software-product-manager / src / test / java / org / openecomp / sdc / vendorsoftwareproduct / impl / orchestration / csar / validation / CsarSecurityValidatorTest.java
1 /*
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
8  *
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.
15  *
16  *  SPDX-License-Identifier: Apache-2.0
17  *  ============LICENSE_END=========================================================
18  */
19
20 package org.openecomp.sdc.vendorsoftwareproduct.impl.orchestration.csar.validation;
21
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;
34
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;
41 import java.net.URI;
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;
48 import java.util.Map;
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;
70
71 @ExtendWith(MockitoExtension.class)
72 class CsarSecurityValidatorTest {
73
74     private static final String BASE_DIR = "/vspmanager.csar/signing/";
75     private static final String DELIMITER = "---";
76     private CsarSecurityValidator csarSecurityValidator;
77     @Mock
78     private SecurityManager securityManager;
79     @Mock
80     private CommonConfigurationManager commonConfigurationManager;
81     @Mock
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;
87     @Mock
88     private GetObjectArgs getObjectArgs;
89
90     @AfterEach
91     void tearDown() throws Exception {
92         restore();
93     }
94
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);
101         }
102     }
103
104     @BeforeEach
105     public void setUp() throws Exception {
106         openMocks(this);
107         csarSecurityValidator = new CsarSecurityValidator(securityManager);
108         backup();
109     }
110
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);
116         }
117     }
118
119     @Test
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));
127     }
128
129     @Test
130     void isSignatureValidTestCorrectStructureAndNotValidSignatureExists() throws Exception {
131
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");
138
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);
143                 when(builderMinio
144                     .endpoint(anyString(), anyInt(), anyBoolean())
145                     .credentials(anyString(), anyString())
146                     .build()
147                 ).thenReturn(minioClient);
148
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);
154
155                 final byte[] packageBytes = getFileBytesOrFail("signed-package-tampered-data.zip");
156
157                 when(getObjectArgsBuilder
158                     .bucket(anyString())
159                     .object(anyString())
160                     .build()
161                 ).thenReturn(getObjectArgs);
162
163                 when(minioClient.getObject(any(GetObjectArgs.class)))
164                     .thenReturn(new GetObjectResponse(null, "bucket", "", "objectName",
165                         new BufferedInputStream(new ByteArrayInputStream(packageBytes))));
166
167                 final OnboardPackageInfo onboardPackageInfo = loadSignedPackageWithArtifactInfoS3Store("signed-package-tampered-data.zip",
168                     packageBytes,
169                     null);
170                 //no mocked securityManager
171                 csarSecurityValidator = new CsarSecurityValidator();
172                 Assertions.assertThrows(SecurityManagerException.class, () -> {
173                     csarSecurityValidator.verifyPackageSignature((OnboardSignedPackage) onboardPackageInfo.getOriginalOnboardPackage(),
174                         onboardPackageInfo.getArtifactInfo());
175                 });
176             }
177         }
178     }
179
180     @Test
181     void isSignatureValidTestCorrectStructureAndValidSignatureExistsArtifactStorageManagerIsEnabled() throws SecurityManagerException {
182         final byte[] packageBytes = getFileBytesOrFail("signed-package.zip");
183         final OnboardPackageInfo onboardPackageInfo = loadSignedPackageWithoutArtifactInfo("signed-package.zip",
184             packageBytes, null);
185         when(securityManager.verifySignedData(any(), any(), any())).thenReturn(true);
186         final boolean isSignatureValid = csarSecurityValidator
187             .verifyPackageSignature((OnboardSignedPackage) onboardPackageInfo.getOriginalOnboardPackage(), onboardPackageInfo.getArtifactInfo());
188
189         assertThat("Signature should be valid", isSignatureValid, is(true));
190     }
191
192     @Test
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",
196             packageBytes, null);
197         //no mocked securityManager
198         csarSecurityValidator = new CsarSecurityValidator();
199         Assertions.assertThrows(SecurityManagerException.class, () -> {
200             csarSecurityValidator
201                 .verifyPackageSignature((OnboardSignedPackage) onboardPackageInfo.getOriginalOnboardPackage(), onboardPackageInfo.getArtifactInfo());
202         });
203     }
204
205     private byte[] getFileBytesOrFail(final String path) {
206         try {
207             return getFileBytes(path);
208         } catch (final URISyntaxException | IOException e) {
209             fail("Could not load file " + path);
210             return null;
211         }
212     }
213
214     private byte[] getFileBytes(final String path) throws URISyntaxException, IOException {
215         return Files.readAllBytes(Paths.get(
216             CsarSecurityValidatorTest.class.getResource(BASE_DIR + path).toURI()));
217     }
218
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");
226         }
227
228         return onboardPackageInfo;
229     }
230
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");
238         }
239
240         return onboardPackageInfo;
241     }
242 }