20d8e26cb0c11c39e6b6255c997adb878321b88c
[sdc.git] /
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.onboarding;
21
22 import static org.openecomp.sdc.common.errors.Messages.PACKAGE_EMPTY_ERROR;
23 import static org.openecomp.sdc.common.errors.Messages.PACKAGE_INVALID_ERROR;
24 import static org.openecomp.sdc.common.errors.Messages.PACKAGE_INVALID_EXTENSION;
25 import static org.openecomp.sdc.common.errors.Messages.PACKAGE_MISSING_INTERNAL_PACKAGE;
26 import static org.openecomp.sdc.common.errors.Messages.PACKAGE_PROCESS_ERROR;
27 import static org.openecomp.sdc.common.errors.Messages.PACKAGE_PROCESS_INTERNAL_PACKAGE_ERROR;
28 import static org.openecomp.sdc.vendorsoftwareproduct.security.SecurityManager.ALLOWED_CERTIFICATE_EXTENSIONS;
29 import static org.openecomp.sdc.vendorsoftwareproduct.security.SecurityManager.ALLOWED_SIGNATURE_EXTENSIONS;
30
31 import java.nio.ByteBuffer;
32 import java.util.HashSet;
33 import java.util.Map;
34 import java.util.Optional;
35 import java.util.Set;
36 import org.apache.commons.collections4.CollectionUtils;
37 import org.apache.commons.collections4.MapUtils;
38 import org.apache.commons.io.FilenameUtils;
39 import org.openecomp.core.utilities.file.FileContentHandler;
40 import org.openecomp.core.utilities.orchestration.OnboardingTypesEnum;
41 import org.openecomp.sdc.common.zip.exception.ZipException;
42 import org.openecomp.sdc.common.utils.CommonUtil;
43 import org.openecomp.sdc.datatypes.error.ErrorLevel;
44 import org.openecomp.sdc.datatypes.error.ErrorMessage;
45 import org.openecomp.sdc.logging.api.Logger;
46 import org.openecomp.sdc.logging.api.LoggerFactory;
47 import org.openecomp.sdc.vendorsoftwareproduct.types.OnboardPackage;
48 import org.openecomp.sdc.vendorsoftwareproduct.types.OnboardPackageInfo;
49 import org.openecomp.sdc.vendorsoftwareproduct.types.OnboardSignedPackage;
50
51 public class OnboardingPackageProcessor {
52     private static final Logger LOGGER = LoggerFactory.getLogger(OnboardingPackageProcessor.class);
53     private static final String CSAR_EXTENSION = "csar";
54     private static final String ZIP_EXTENSION = "zip";
55
56     private final String packageFileName;
57     private final byte[] packageFileContent;
58     private FileContentHandler onboardPackageContentHandler;
59     private Set<ErrorMessage> errorMessageSet = new HashSet<>();
60     private OnboardPackageInfo onboardPackageInfo;
61
62     public OnboardingPackageProcessor(final String packageFileName, final byte[] packageFileContent) {
63         this.packageFileName = packageFileName;
64         this.packageFileContent = packageFileContent;
65         onboardPackageInfo = processPackage();
66     }
67
68     private OnboardPackageInfo processPackage() {
69         if (!hasValidExtension()) {
70             final String message = PACKAGE_INVALID_EXTENSION.formatMessage(packageFileName, String.join(", ", CSAR_EXTENSION, ZIP_EXTENSION));
71             reportError(ErrorLevel.ERROR, message);
72             return null;
73         }
74         try {
75             onboardPackageContentHandler = CommonUtil.getZipContent(packageFileContent);
76         } catch (final ZipException e) {
77             final String message = PACKAGE_PROCESS_ERROR.formatMessage(packageFileName);
78             LOGGER.error(message, e);
79             reportError(ErrorLevel.ERROR, message);
80             return null;
81         }
82         if (isPackageEmpty()) {
83             final String message = PACKAGE_EMPTY_ERROR.formatMessage(packageFileName);
84             reportError(ErrorLevel.ERROR, message);
85             return null;
86         }
87
88         final String packageName = FilenameUtils.getBaseName(packageFileName);
89         final String packageExtension = FilenameUtils.getExtension(packageFileName);
90
91         if (hasSignedPackageStructure()) {
92             return processSignedPackage(packageName, packageExtension);
93         } else {
94             if (packageExtension.equalsIgnoreCase(CSAR_EXTENSION)) {
95                 final OnboardPackage onboardPackage = new OnboardPackage(packageName, packageExtension,
96                     ByteBuffer.wrap(packageFileContent), new OnboardingPackageContentHandler(onboardPackageContentHandler));
97                 return new OnboardPackageInfo(onboardPackage, OnboardingTypesEnum.CSAR);
98             } else if (packageExtension.equalsIgnoreCase(ZIP_EXTENSION)) {
99                 final OnboardPackage onboardPackage = new OnboardPackage(packageName, packageExtension,
100                     ByteBuffer.wrap(packageFileContent), onboardPackageContentHandler);
101                 return new OnboardPackageInfo(onboardPackage, OnboardingTypesEnum.ZIP);
102             }
103         }
104
105         reportError(ErrorLevel.ERROR, PACKAGE_INVALID_ERROR.formatMessage(packageFileName));
106         return null;
107     }
108
109     private boolean hasValidExtension() {
110         final String packageExtension = FilenameUtils.getExtension(packageFileName);
111         return packageExtension.equalsIgnoreCase(CSAR_EXTENSION) || packageExtension.equalsIgnoreCase(ZIP_EXTENSION);
112     }
113
114     private OnboardPackageInfo processSignedPackage(final String packageName, final String packageExtension) {
115         final String internalPackagePath = findInternalPackagePath().orElse(null);
116         if (internalPackagePath == null) {
117             reportError(ErrorLevel.ERROR, PACKAGE_MISSING_INTERNAL_PACKAGE.getErrorMessage());
118             return null;
119         }
120         final String signatureFilePath = findSignatureFilePath().orElse(null);
121         final String certificateFilePath = findCertificateFilePath().orElse(null);
122         final OnboardSignedPackage onboardSignedPackage =
123             new OnboardSignedPackage(packageName, packageExtension, ByteBuffer.wrap(packageFileContent),
124                 onboardPackageContentHandler, signatureFilePath, internalPackagePath, certificateFilePath);
125
126         final String internalPackageName = FilenameUtils.getName(internalPackagePath);
127         final String internalPackageBaseName = FilenameUtils.getBaseName(internalPackagePath);
128         final String internalPackageExtension = FilenameUtils.getExtension(internalPackagePath);
129         final byte[] internalPackageContent = onboardPackageContentHandler.getFileContent(internalPackagePath);
130         final OnboardPackage onboardPackage;
131         try {
132             final OnboardingPackageContentHandler fileContentHandler =
133                 new OnboardingPackageContentHandler(CommonUtil.getZipContent(internalPackageContent));
134             onboardPackage = new OnboardPackage(internalPackageBaseName, internalPackageExtension,
135                 internalPackageContent, fileContentHandler);
136         } catch (final ZipException e) {
137             final String message = PACKAGE_PROCESS_INTERNAL_PACKAGE_ERROR.formatMessage(internalPackageName);
138             LOGGER.error(message, e);
139             reportError(ErrorLevel.ERROR, message);
140             return null;
141         }
142
143         return new OnboardPackageInfo(onboardSignedPackage, onboardPackage, OnboardingTypesEnum.SIGNED_CSAR);
144     }
145
146     private void reportError(final ErrorLevel errorLevel, final String message) {
147         errorMessageSet.add(new ErrorMessage(errorLevel, message));
148     }
149
150     public boolean hasErrors() {
151         return !errorMessageSet.isEmpty();
152     }
153
154     public Set<ErrorMessage> getErrorMessageSet() {
155         return errorMessageSet;
156     }
157
158     private Optional<String> findInternalPackagePath() {
159         return onboardPackageContentHandler.getFileList().stream()
160             .filter(filePath -> {
161                     final String extension = FilenameUtils.getExtension(filePath);
162                     return CSAR_EXTENSION.equalsIgnoreCase(extension) || ZIP_EXTENSION.equalsIgnoreCase(extension);
163                 }
164             )
165             .findFirst();
166     }
167
168     private boolean isPackageEmpty() {
169         return MapUtils.isEmpty(onboardPackageContentHandler.getFiles());
170     }
171
172     private boolean hasSignedPackageStructure() {
173         if (MapUtils.isEmpty(onboardPackageContentHandler.getFiles()) || !CollectionUtils.isEmpty(
174             onboardPackageContentHandler.getFolderList())) {
175             return false;
176         }
177         final int numberOfFiles = onboardPackageContentHandler.getFileList().size();
178         if (numberOfFiles == 2) {
179             return hasOneInternalPackageFile(onboardPackageContentHandler) &&
180                 hasOneSignatureFile(onboardPackageContentHandler);
181         }
182
183         if (numberOfFiles == 3) {
184             return hasOneInternalPackageFile(onboardPackageContentHandler) &&
185                 hasOneSignatureFile(onboardPackageContentHandler) &&
186                 hasOneCertificateFile(onboardPackageContentHandler);
187         }
188
189         return false;
190     }
191
192     private boolean hasOneInternalPackageFile(final FileContentHandler fileContentHandler) {
193         return fileContentHandler.getFileList().parallelStream()
194             .map(FilenameUtils::getExtension)
195             .map(String::toLowerCase)
196             .filter(file -> file.endsWith(CSAR_EXTENSION)).count() == 1;
197     }
198
199     private boolean hasOneSignatureFile(final FileContentHandler fileContentHandler) {
200         return fileContentHandler.getFileList().parallelStream()
201             .map(FilenameUtils::getExtension)
202             .map(String::toLowerCase)
203             .filter(ALLOWED_SIGNATURE_EXTENSIONS::contains).count() == 1;
204     }
205
206     private boolean hasOneCertificateFile(final FileContentHandler fileContentHandler) {
207         return fileContentHandler.getFileList().parallelStream()
208             .map(FilenameUtils::getExtension)
209             .map(String::toLowerCase)
210             .filter(ALLOWED_CERTIFICATE_EXTENSIONS::contains).count() == 1;
211     }
212
213     private Optional<String> findSignatureFilePath() {
214         final Map<String, byte[]> files = onboardPackageContentHandler.getFiles();
215         return files.keySet().stream()
216             .filter(fileName -> ALLOWED_SIGNATURE_EXTENSIONS.contains(FilenameUtils.getExtension(fileName).toLowerCase()))
217             .findFirst();
218     }
219
220     private Optional<String> findCertificateFilePath() {
221         final Map<String, byte[]> files = onboardPackageContentHandler.getFiles();
222         return files.keySet().stream()
223             .filter(fileName -> ALLOWED_CERTIFICATE_EXTENSIONS.contains(FilenameUtils.getExtension(fileName).toLowerCase()))
224             .findFirst();
225     }
226
227     public Optional<OnboardPackageInfo> getOnboardPackageInfo() {
228         return Optional.ofNullable(onboardPackageInfo);
229     }
230 }