Fix zip slip security flaw
[sdc.git] / catalog-be / src / main / java / org / openecomp / sdc / be / servlets / AbstractValidationsServlet.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * SDC
4  * ================================================================================
5  * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  * 
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  * 
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END=========================================================
19  * Modifications copyright (c) 2019 Nokia
20  * ================================================================================
21  */
22
23 package org.openecomp.sdc.be.servlets;
24
25 import com.fasterxml.jackson.databind.ObjectMapper;
26 import com.google.gson.Gson;
27 import com.google.gson.JsonSyntaxException;
28 import fj.data.Either;
29 import java.io.File;
30 import java.io.FileInputStream;
31 import java.io.FileNotFoundException;
32 import java.io.IOException;
33 import java.io.InputStream;
34 import java.lang.reflect.Type;
35 import java.nio.charset.StandardCharsets;
36 import java.util.Arrays;
37 import java.util.HashMap;
38 import java.util.List;
39 import java.util.Map;
40 import java.util.function.Supplier;
41 import javax.servlet.ServletContext;
42 import javax.servlet.http.HttpServletRequest;
43 import javax.ws.rs.core.Response;
44 import org.apache.commons.codec.binary.Base64;
45 import org.apache.commons.collections4.MapUtils;
46 import org.apache.commons.io.IOUtils;
47 import org.apache.commons.lang3.StringUtils;
48 import org.apache.commons.lang3.tuple.ImmutablePair;
49 import org.openecomp.sdc.be.components.impl.ComponentInstanceBusinessLogic;
50 import org.openecomp.sdc.be.components.impl.CsarValidationUtils;
51 import org.openecomp.sdc.be.components.impl.ImportUtils;
52 import org.openecomp.sdc.be.components.impl.ImportUtils.ResultStatusEnum;
53 import org.openecomp.sdc.be.components.impl.ImportUtils.ToscaElementTypeEnum;
54 import org.openecomp.sdc.be.components.impl.ResourceImportManager;
55 import org.openecomp.sdc.be.components.impl.exceptions.ByResponseFormatComponentException;
56 import org.openecomp.sdc.be.config.BeEcompErrorManager;
57 import org.openecomp.sdc.be.dao.api.ActionStatus;
58 import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
59 import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum;
60 import org.openecomp.sdc.be.impl.ComponentsUtils;
61 import org.openecomp.sdc.be.impl.ServletUtils;
62 import org.openecomp.sdc.be.model.ArtifactDefinition;
63 import org.openecomp.sdc.be.model.Resource;
64 import org.openecomp.sdc.be.model.UploadResourceInfo;
65 import org.openecomp.sdc.be.model.User;
66 import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum;
67 import org.openecomp.sdc.be.servlets.ResourceUploadServlet.ResourceAuthorityTypeEnum;
68 import org.openecomp.sdc.be.user.IUserBusinessLogic;
69 import org.openecomp.sdc.be.user.Role;
70 import org.openecomp.sdc.be.user.UserBusinessLogic;
71 import org.openecomp.sdc.be.utils.TypeUtils;
72 import org.openecomp.sdc.common.api.Constants;
73 import org.openecomp.sdc.common.api.UploadArtifactInfo;
74 import org.openecomp.sdc.common.datastructure.Wrapper;
75 import org.openecomp.sdc.common.log.wrappers.Logger;
76 import org.openecomp.sdc.common.util.GeneralUtility;
77 import org.openecomp.sdc.common.util.YamlToObjectConverter;
78 import org.openecomp.sdc.common.zip.ZipUtils;
79 import org.openecomp.sdc.common.zip.exception.ZipException;
80 import org.openecomp.sdc.exception.ResponseFormat;
81 import org.yaml.snakeyaml.Yaml;
82
83 public abstract class AbstractValidationsServlet extends BeGenericServlet {
84
85     private static final Logger log = Logger.getLogger(AbstractValidationsServlet.class);
86     private static final String TOSCA_SIMPLE_YAML_PREFIX = "tosca_simple_yaml_";
87     private static final List<String> TOSCA_DEFINITION_VERSIONS = Arrays.asList(TOSCA_SIMPLE_YAML_PREFIX + "1_0_0", TOSCA_SIMPLE_YAML_PREFIX + "1_1_0", "tosca_simple_profile_for_nfv_1_0_0", TOSCA_SIMPLE_YAML_PREFIX + "1_0", TOSCA_SIMPLE_YAML_PREFIX + "1_1");
88     private static final List<String> TOSCA_YML_CSAR_VALID_SUFFIX = Arrays.asList(".yml", ".yaml", ".csar");
89
90     protected ServletUtils servletUtils;
91     protected ResourceImportManager resourceImportManager;
92     protected final ComponentInstanceBusinessLogic componentInstanceBusinessLogic;
93
94
95     public AbstractValidationsServlet(UserBusinessLogic userBusinessLogic,
96         ComponentInstanceBusinessLogic componentInstanceBL, ComponentsUtils componentsUtils,
97         ServletUtils servletUtils, ResourceImportManager resourceImportManager) {
98         super(userBusinessLogic, componentsUtils);
99         this.servletUtils = servletUtils;
100         this.resourceImportManager = resourceImportManager;
101         this.componentInstanceBusinessLogic = componentInstanceBL;
102     }
103
104     protected void init() {
105     }
106
107     protected void validateResourceDoesNotExist(Wrapper<Response> responseWrapper, User user, String resourceName) {
108         if (resourceImportManager.isResourceExist(resourceName)) {
109             ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.RESOURCE_ALREADY_EXISTS);
110             Response errorResponse = buildErrorResponse(responseFormat);
111             getComponentsUtils().auditResource(responseFormat, user, resourceName, AuditingActionEnum.IMPORT_RESOURCE);
112             responseWrapper.setInnerElement(errorResponse);
113         }
114     }
115
116     protected void validateUserExist(Wrapper<Response> responseWrapper, Wrapper<User> userWrapper, String userUserId) {
117         log.debug("get user {} from DB", userUserId);
118         // get user details
119         if (userUserId == null) {
120             log.info("user userId is null");
121             Response response = returnMissingInformation(new User());
122             responseWrapper.setInnerElement(response);
123         }
124
125         else {
126             IUserBusinessLogic userAdmin = getServletUtils().getUserAdmin();
127             Either<User, ActionStatus> eitherCreator = userAdmin.getUser(userUserId, false);
128             if (eitherCreator.isRight()) {
129                 log.info("user is not listed. userId={}", userUserId);
130                 User user = new User();
131                 user.setUserId(userUserId);
132                 Response response = returnMissingInformation(user);
133                 responseWrapper.setInnerElement(response);
134             } else {
135                 userWrapper.setInnerElement(eitherCreator.left().value());
136             }
137         }
138     }
139
140     protected Response returnMissingInformation(User user) {
141         ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.MISSING_INFORMATION);
142         getComponentsUtils().auditResource(responseFormat, user, "", AuditingActionEnum.IMPORT_RESOURCE);
143         return buildErrorResponse(responseFormat);
144     }
145
146     protected void validateDataNotNull(Wrapper<Response> responseWrapper, Object... dataParams) {
147         for (Object dataElement : dataParams) {
148             if (dataElement == null) {
149                 log.info("Invalid body was received.");
150                 Response response = buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT));
151                 responseWrapper.setInnerElement(response);
152                 break;
153             }
154         }
155
156     }
157
158     protected void validateUserRole(Wrapper<Response> errorResponseWrapper, User user) {
159         log.debug("validate user role");
160         if (!user.getRole().equals(Role.ADMIN.name()) && !user.getRole().equals(Role.DESIGNER.name())) {
161             log.info("user is not in appropriate role to perform action");
162             ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.RESTRICTED_OPERATION);
163             log.debug("audit before sending response");
164             getComponentsUtils().auditResource(responseFormat, user, "", AuditingActionEnum.IMPORT_RESOURCE);
165
166             Response response = buildErrorResponse(responseFormat);
167             errorResponseWrapper.setInnerElement(response);
168         }
169
170     }
171
172     protected void validateZip(final Wrapper<Response> responseWrapper, final File zipFile, final String payloadName) {
173         if (StringUtils.isEmpty(payloadName)) {
174             log.info("Invalid JSON was received. Payload name is empty");
175             final Response errorResponse =
176                 buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT));
177             responseWrapper.setInnerElement(errorResponse);
178             return;
179         }
180         final Map<String, byte[]> unzippedFolder;
181         try {
182             unzippedFolder = ZipUtils.readZip(zipFile, false);
183         } catch (final ZipException e) {
184             log.error("Could not read ZIP file '{}' for validation", zipFile.getName(), e);
185             final Response errorResponse =
186                 buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT));
187             responseWrapper.setInnerElement(errorResponse);
188             return;
189         }
190         if (!unzippedFolder.containsKey(payloadName)) {
191             log.info("Could no find payload '{}' in ZIP file '{}'", payloadName, zipFile.getName());
192             final Response errorResponse =
193                 buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT));
194             responseWrapper.setInnerElement(errorResponse);
195         }
196
197
198     }
199
200     protected void validateCsar(final Wrapper<Response> responseWrapper, final File csarFile, final String payloadName) {
201         if (StringUtils.isEmpty(payloadName)) {
202             log.info("Invalid JSON was received. Payload name is empty");
203             Response errorResponse = buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT));
204             responseWrapper.setInnerElement(errorResponse);
205             return;
206         }
207         final Map<String, byte[]> unzippedFolder;
208         try {
209             unzippedFolder = ZipUtils.readZip(csarFile, false);
210         } catch (final ZipException e) {
211             log.error("Could not read CSAR file '{}' for validation", csarFile.getName(), e);
212             final Response errorResponse =
213                 buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT));
214             responseWrapper.setInnerElement(errorResponse);
215             return;
216         }
217         if (unzippedFolder.isEmpty()) {
218             log.info("The CSAR file is empty");
219             Response errorResponse = buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT));
220             responseWrapper.setInnerElement(errorResponse);
221         }
222
223     }
224
225     protected void fillZipContents(Wrapper<String> yamlStringWrapper, File file) throws ZipException {
226         extractZipContents(yamlStringWrapper, file);
227     }
228
229     public static void extractZipContents(Wrapper<String> yamlStringWrapper, File file) throws ZipException {
230         final Map<String, byte[]> unzippedFolder = ZipUtils.readZip(file, false);
231         String ymlName = unzippedFolder.keySet().iterator().next();
232         fillToscaTemplateFromZip(yamlStringWrapper, ymlName, file);
233     }
234
235     private static void fillToscaTemplateFromZip(Wrapper<String> yamlStringWrapper, String payloadName, File file) {
236         Map<String, byte[]> unzippedFolder = null;
237         try {
238             unzippedFolder = ZipUtils.readZip(file, false);
239         } catch (final ZipException e) {
240             log.info("Failed to unzip file", e);
241         }
242         byte[] yamlFileInBytes = unzippedFolder.get(payloadName);
243         String yamlAsString = new String(yamlFileInBytes, StandardCharsets.UTF_8);
244         log.debug("received yaml: {}", yamlAsString);
245         yamlStringWrapper.setInnerElement(yamlAsString);
246     }
247
248     protected void fillPayloadDataFromFile(Wrapper<Response> responseWrapper, UploadResourceInfo uploadResourceInfoWrapper, File file)  {
249         try(InputStream fileInputStream = new FileInputStream(file)){
250
251             byte [] data = new byte[(int)file.length()];
252             if( fileInputStream.read(data) == -1){
253                 log.info("Invalid json was received.");
254                 ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT);
255
256                 Response errorResp = buildErrorResponse(responseFormat);
257                 responseWrapper.setInnerElement(errorResp);
258             }
259             String payloadData =  Base64.encodeBase64String(data);
260             uploadResourceInfoWrapper.setPayloadData(payloadData);
261
262
263
264         } catch (IOException e) {
265             log.info("Invalid json was received or Error while closing input Stream.");
266             log.debug("Invalid json was received or Error while closing input Stream. {}", e.getMessage(), e);
267             ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT);
268
269             Response errorResp = buildErrorResponse(responseFormat);
270             responseWrapper.setInnerElement(errorResp);
271
272         }
273     }
274
275     protected void validateUserRole(Wrapper<Response> errorResponseWrapper, User user, ResourceAuthorityTypeEnum resourceAuthority) {
276         log.debug("validate user role");
277         if (resourceAuthority == ResourceAuthorityTypeEnum.NORMATIVE_TYPE_BE) {
278             if (!user.getRole().equals(Role.ADMIN.name())) {
279                 log.info("user is not in appropriate role to perform action");
280                 ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.RESTRICTED_OPERATION);
281                 log.debug("audit before sending response");
282                 getComponentsUtils().auditResource(responseFormat, user, "", AuditingActionEnum.IMPORT_RESOURCE);
283
284                 Response response = buildErrorResponse(responseFormat);
285                 errorResponseWrapper.setInnerElement(response);
286             }
287         } else {
288             validateUserRole(errorResponseWrapper, user);
289         }
290
291     }
292
293     protected void validateAndFillResourceJson(Wrapper<Response> responseWrapper, Wrapper<UploadResourceInfo> uploadResourceInfoWrapper, User user, ResourceAuthorityTypeEnum resourceAuthorityEnum, String resourceInfo) {
294         boolean isValid;
295         try {
296             log.debug("The received json is {}", resourceInfo);
297             UploadResourceInfo resourceInfoObject = gson.fromJson(resourceInfo, UploadResourceInfo.class);
298             if (resourceInfoObject == null) {
299                 isValid = false;
300             } else {
301                 if (!resourceAuthorityEnum.isBackEndImport()) {
302                     isValid = resourceInfoObject.getPayloadName() != null && !resourceInfoObject.getPayloadName().isEmpty();
303                     //only resource name is checked
304                 } else {
305                     isValid = true;
306                 }
307                 uploadResourceInfoWrapper.setInnerElement(resourceInfoObject);
308             }
309
310         } catch (JsonSyntaxException e) {
311             log.debug("Invalid json was received. {}", e.getMessage(), e);
312             isValid = false;
313
314         }
315         if (!isValid) {
316             log.info("Invalid json was received.");
317             ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT);
318             getComponentsUtils().auditResource(responseFormat, user, "", AuditingActionEnum.IMPORT_RESOURCE);
319             Response errorResp = buildErrorResponse(responseFormat);
320             responseWrapper.setInnerElement(errorResp);
321         }
322     }
323
324     protected void validateAuthorityType(Wrapper<Response> responseWrapper, String authorityType) {
325         log.debug("The received authority type is {}", authorityType);
326         ResourceAuthorityTypeEnum authorityTypeEnum = ResourceAuthorityTypeEnum.findByUrlPath(authorityType);
327         if (authorityTypeEnum == null) {
328             log.info("Invalid authority type was received.");
329             Response errorResp = buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT));
330             responseWrapper.setInnerElement(errorResp);
331         }
332     }
333
334     public ServletUtils getServletUtils() {
335         return servletUtils;
336     }
337
338     public Gson getGson() {
339         return getServletUtils().getGson();
340     }
341
342     public ComponentsUtils getComponentsUtils() {
343         return getServletUtils().getComponentsUtils();
344     }
345
346     protected void validatePayloadIsTosca(Wrapper<Response> responseWrapper, UploadResourceInfo uploadResourceInfo, User user, String toscaPayload) {
347         log.debug("checking payload is valid tosca");
348         boolean isValid;
349         Map<String, Object> mappedToscaTemplate = (Map<String, Object>) new Yaml().load(toscaPayload);
350         Either<String, ResultStatusEnum> findFirstToscaStringElement = ImportUtils.findFirstToscaStringElement(mappedToscaTemplate, TypeUtils.ToscaTagNamesEnum.TOSCA_VERSION);
351
352         if (findFirstToscaStringElement.isRight()) {
353             isValid = false;
354         } else {
355             String defenitionVersionFound = findFirstToscaStringElement.left().value();
356             if (defenitionVersionFound == null || defenitionVersionFound.isEmpty()) {
357                 isValid = false;
358             } else {
359                 isValid = TOSCA_DEFINITION_VERSIONS.contains(defenitionVersionFound);
360             }
361         }
362
363         if (!isValid) {
364             ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.INVALID_TOSCA_TEMPLATE);
365             Response errorResponse = buildErrorResponse(responseFormat);
366              getComponentsUtils().auditResource(responseFormat, user, uploadResourceInfo.getName(), AuditingActionEnum.IMPORT_RESOURCE);
367             responseWrapper.setInnerElement(errorResponse);
368         }
369
370     }
371
372     protected void validatePayloadIsYml(Wrapper<Response> responseWrapper, User user, UploadResourceInfo uploadResourceInfo, String toscaTamplatePayload) {
373         log.debug("checking tosca template is valid yml");
374         YamlToObjectConverter yamlConvertor = new YamlToObjectConverter();
375         boolean isYamlValid = yamlConvertor.isValidYaml(toscaTamplatePayload.getBytes());
376         if (!isYamlValid) {
377             ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.INVALID_YAML_FILE);
378             Response errorResponse = buildErrorResponse(responseFormat);
379              getComponentsUtils().auditResource(responseFormat, user, uploadResourceInfo.getName(), AuditingActionEnum.IMPORT_RESOURCE);
380             responseWrapper.setInnerElement(errorResponse);
381         }
382     }
383
384     protected void validatePayloadNameSpace(Wrapper<Response> responseWrapper, UploadResourceInfo resourceInfo, User user, String toscaPayload) {
385         boolean isValid;
386         String nameSpace = "";
387         Map<String, Object> mappedToscaTemplate = (Map<String, Object>) new Yaml().load(toscaPayload);
388         Either<Map<String, Object>, ResultStatusEnum> toscaElement = ImportUtils.findFirstToscaMapElement(mappedToscaTemplate, TypeUtils.ToscaTagNamesEnum.NODE_TYPES);
389         if (toscaElement.isRight() || toscaElement.left().value().size() != 1) {
390             isValid = false;
391         } else {
392             nameSpace = toscaElement.left().value().keySet().iterator().next();
393             isValid = nameSpace.startsWith(Constants.USER_DEFINED_RESOURCE_NAMESPACE_PREFIX);
394         }
395         if (!isValid) {
396             ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.INVALID_RESOURCE_NAMESPACE);
397             Response errorResponse = buildErrorResponse(responseFormat);
398              getComponentsUtils().auditResource(responseFormat, user, resourceInfo.getName(), AuditingActionEnum.IMPORT_RESOURCE);
399             responseWrapper.setInnerElement(errorResponse);
400         } else {
401             String str1 = nameSpace.substring(Constants.USER_DEFINED_RESOURCE_NAMESPACE_PREFIX.length());
402             String[] findTypes = str1.split("\\.");
403             if (ResourceTypeEnum.containsName(findTypes[0].toUpperCase())) {
404                 String type = findTypes[0].toUpperCase();
405                 resourceInfo.setResourceType(type);
406             } else {
407                 resourceInfo.setResourceType(ResourceTypeEnum.VFC.name());
408             }
409         }
410
411     }
412
413     protected void validatePayloadIsSingleResource(Wrapper<Response> responseWrapper, UploadResourceInfo uploadResourceInfo, User user, String toscaPayload) {
414         log.debug("checking payload contains single resource");
415         boolean isValid;
416         Map<String, Object> mappedToscaTemplate = (Map<String, Object>) new Yaml().load(toscaPayload);
417         Either<Map<String, Object>, ResultStatusEnum> toscaElement = ImportUtils.findFirstToscaMapElement(mappedToscaTemplate, TypeUtils.ToscaTagNamesEnum.NODE_TYPES);
418         if (toscaElement.isRight()) {
419             isValid = false;
420         } else {
421             isValid = toscaElement.left().value().size() == 1;
422         }
423
424         if (!isValid) {
425             ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.NOT_SINGLE_RESOURCE);
426             Response errorResponse = buildErrorResponse(responseFormat);
427              getComponentsUtils().auditResource(responseFormat, user, uploadResourceInfo.getName(), AuditingActionEnum.IMPORT_RESOURCE);
428             responseWrapper.setInnerElement(errorResponse);
429         }
430
431     }
432
433     protected void validatePayloadIsNotService(Wrapper<Response> responseWrapper, User user, UploadResourceInfo uploadResourceInfo, String toscaPayload) {
434         log.debug("checking payload is not a tosca service");
435         Map<String, Object> mappedToscaTemplate = (Map<String, Object>) new Yaml().load(toscaPayload);
436         Either<Object, ResultStatusEnum> toscaElement = ImportUtils.findToscaElement(mappedToscaTemplate, TypeUtils.ToscaTagNamesEnum.TOPOLOGY_TEMPLATE, ToscaElementTypeEnum.ALL);
437
438         if (toscaElement.isLeft()) {
439             ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.NOT_RESOURCE_TOSCA_TEMPLATE);
440             Response errorResponse = buildErrorResponse(responseFormat);
441             getComponentsUtils().auditResource(responseFormat, user, uploadResourceInfo.getName(), AuditingActionEnum.IMPORT_RESOURCE);
442             responseWrapper.setInnerElement(errorResponse);
443         }
444
445     }
446
447     protected void validateToscaTemplatePayloadName(Wrapper<Response> responseWrapper, UploadResourceInfo uploadResourceInfo, User user) {
448         String toscaTemplatePayloadName = uploadResourceInfo.getPayloadName();
449         boolean isValidSuffix = false;
450         if (toscaTemplatePayloadName != null && !toscaTemplatePayloadName.isEmpty()) {
451             for (String validSuffix : TOSCA_YML_CSAR_VALID_SUFFIX) {
452                 isValidSuffix = isValidSuffix || toscaTemplatePayloadName.toLowerCase().endsWith(validSuffix);
453             }
454         }
455         if (!isValidSuffix) {
456             ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.INVALID_TOSCA_FILE_EXTENSION);
457             Response errorResponse = buildErrorResponse(responseFormat);
458             getComponentsUtils().auditResource(responseFormat, user, uploadResourceInfo.getName(), AuditingActionEnum.IMPORT_RESOURCE);
459             responseWrapper.setInnerElement(errorResponse);
460         }
461
462     }
463
464     protected void validateMD5(Wrapper<Response> responseWrapper, User user, UploadResourceInfo resourceInfo, HttpServletRequest request, String resourceInfoJsonString) {
465         boolean isValid;
466         String recievedMD5 = request.getHeader(Constants.MD5_HEADER);
467         if (recievedMD5 == null) {
468             isValid = false;
469         } else {
470             String calculateMD5 = GeneralUtility.calculateMD5Base64EncodedByString(resourceInfoJsonString);
471             isValid = calculateMD5.equals(recievedMD5);
472         }
473         if (!isValid) {
474             ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.INVALID_RESOURCE_CHECKSUM);
475             Response errorResponse = buildErrorResponse(responseFormat);
476             getComponentsUtils().auditResource(responseFormat, user, resourceInfo.getName(), AuditingActionEnum.IMPORT_RESOURCE);
477             responseWrapper.setInnerElement(errorResponse);
478         }
479     }
480
481     protected void validateComponentType(Wrapper<Response> responseWrapper, Wrapper<ComponentTypeEnum> componentTypeWrapper, String componentType) {
482         boolean isValid;
483         if (componentType == null) {
484             isValid = false;
485         } else {
486             if (ComponentTypeEnum.RESOURCE_PARAM_NAME.equalsIgnoreCase(componentType)) {
487                 isValid = true;
488                 componentTypeWrapper.setInnerElement(ComponentTypeEnum.RESOURCE);
489             } else if (ComponentTypeEnum.SERVICE_PARAM_NAME.equalsIgnoreCase(componentType)) {
490                 isValid = true;
491                 componentTypeWrapper.setInnerElement(ComponentTypeEnum.SERVICE);
492             } else {
493                 isValid = false;
494             }
495         }
496         if (!isValid) {
497             log.debug("Invalid componentType:{}", componentType);
498             responseWrapper.setInnerElement(buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.UNSUPPORTED_ERROR, componentType)));
499         }
500     }
501
502     protected Either<ComponentTypeEnum, ResponseFormat> convertToComponentType(String componentType) {
503         Wrapper<Response> errorWrapper = new Wrapper<>();
504         Wrapper<ComponentTypeEnum> componentWrapper = new Wrapper<>();
505         validateComponentType(errorWrapper, componentWrapper, componentType);
506         return errorWrapper.isEmpty() ? Either.left(componentWrapper.getInnerElement()) : Either.right(getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT));
507     }
508
509     protected void fillToscaTemplateFromJson(Wrapper<Response> responseWrapper, Wrapper<String> yamlStringWrapper, User user, UploadResourceInfo resourceInfo) {
510         if (resourceInfo.getPayloadData() == null || resourceInfo.getPayloadData().isEmpty()) {
511             ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.INVALID_RESOURCE_PAYLOAD);
512             Response errorResponse = buildErrorResponse(responseFormat);
513             getComponentsUtils().auditResource(responseFormat, user, resourceInfo.getName(), AuditingActionEnum.IMPORT_RESOURCE);
514             responseWrapper.setInnerElement(errorResponse);
515         } else {
516             String toscaPayload = resourceInfo.getPayloadData();
517             String decodedPayload = new String(Base64.decodeBase64(toscaPayload));
518             yamlStringWrapper.setInnerElement(decodedPayload);
519         }
520
521     }
522
523     protected void fillPayload(Wrapper<Response> responseWrapper, Wrapper<UploadResourceInfo> uploadResourceInfoWrapper, Wrapper<String> yamlStringWrapper, User user, String resourceInfoJsonString, ResourceAuthorityTypeEnum resourceAuthorityEnum,
524             File file) throws FileNotFoundException {
525
526         if (responseWrapper.isEmpty()) {
527             if (resourceAuthorityEnum.isBackEndImport()) {
528                 // PrePayload Validations
529                 if (responseWrapper.isEmpty()) {
530                     validateDataNotNull(responseWrapper, file, resourceInfoJsonString);
531                 }
532                 if(!resourceAuthorityEnum.equals(ResourceAuthorityTypeEnum.CSAR_TYPE_BE)){
533                     if (responseWrapper.isEmpty()) {
534                         validateZip(responseWrapper, file, uploadResourceInfoWrapper.getInnerElement().getPayloadName());
535                     }
536
537                     // Fill PayLoad From File
538                     if (responseWrapper.isEmpty()) {
539                         fillToscaTemplateFromZip(yamlStringWrapper, uploadResourceInfoWrapper.getInnerElement().getPayloadName(), file);
540                     }
541                 }else{
542
543                     if (responseWrapper.isEmpty()) {
544                         validateCsar(responseWrapper, file, uploadResourceInfoWrapper.getInnerElement().getPayloadName());
545                     }
546
547                     // Fill PayLoad From File
548                     if (responseWrapper.isEmpty()) {
549                         fillPayloadDataFromFile(responseWrapper, uploadResourceInfoWrapper.getInnerElement(), file);
550                     }
551
552                 }
553
554             } else {
555                 // Fill PayLoad From JSON
556                 if (responseWrapper.isEmpty()) {
557                     fillToscaTemplateFromJson(responseWrapper, yamlStringWrapper, user, uploadResourceInfoWrapper.getInnerElement());
558                 }
559             }
560
561         }
562
563     }
564
565     protected void specificResourceAuthorityValidations(Wrapper<Response> responseWrapper, Wrapper<UploadResourceInfo> uploadResourceInfoWrapper, Wrapper<String> yamlStringWrapper, User user, HttpServletRequest request, String resourceInfoJsonString,
566             ResourceAuthorityTypeEnum resourceAuthorityEnum) throws FileNotFoundException {
567
568         if (responseWrapper.isEmpty()) {
569             // UI Only Validation
570             if (!resourceAuthorityEnum.isBackEndImport()) {
571                 importUIValidations(responseWrapper, uploadResourceInfoWrapper.getInnerElement(), user, request, resourceInfoJsonString);
572             }
573
574             // User Defined Type Resources
575             if (resourceAuthorityEnum.isUserTypeResource() && !CsarValidationUtils.isCsarPayloadName(uploadResourceInfoWrapper.getInnerElement().getPayloadName())) {
576                 if (responseWrapper.isEmpty()) {
577                     validatePayloadNameSpace(responseWrapper, uploadResourceInfoWrapper.getInnerElement(), user, yamlStringWrapper.getInnerElement());
578                 }
579
580             }
581         }
582     }
583
584     protected void commonGeneralValidations(Wrapper<Response> responseWrapper, Wrapper<User> userWrapper, Wrapper<UploadResourceInfo> uploadResourceInfoWrapper, ResourceAuthorityTypeEnum resourceAuthorityEnum, String userUserId,
585             String resourceInfoJsonString) {
586
587         if (responseWrapper.isEmpty()) {
588             validateUserExist(responseWrapper, userWrapper, userUserId);
589         }
590
591         if (responseWrapper.isEmpty()) {
592             validateUserRole(responseWrapper, userWrapper.getInnerElement(), resourceAuthorityEnum);
593         }
594
595         if (responseWrapper.isEmpty()) {
596             validateAndFillResourceJson(responseWrapper, uploadResourceInfoWrapper, userWrapper.getInnerElement(), resourceAuthorityEnum, resourceInfoJsonString);
597         }
598
599         if (responseWrapper.isEmpty()) {
600             validateToscaTemplatePayloadName(responseWrapper, uploadResourceInfoWrapper.getInnerElement(), userWrapper.getInnerElement());
601         }
602         if (responseWrapper.isEmpty()) {
603             validateResourceType(responseWrapper, uploadResourceInfoWrapper.getInnerElement(), userWrapper.getInnerElement());
604         }
605
606     }
607
608     private void validateResourceType(Wrapper<Response> responseWrapper, UploadResourceInfo uploadResourceInfo, User user) {
609         String resourceType = uploadResourceInfo.getResourceType();
610         if (resourceType == null || !ResourceTypeEnum.containsName(resourceType)) {
611             ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT);
612             Response errorResponse = buildErrorResponse(responseFormat);
613             getComponentsUtils().auditResource(responseFormat, user, uploadResourceInfo.getName(), AuditingActionEnum.IMPORT_RESOURCE);
614             responseWrapper.setInnerElement(errorResponse);
615         }
616     }
617
618     protected void importUIValidations(Wrapper<Response> responseWrapper, UploadResourceInfo resourceInfo, User user, HttpServletRequest request, String resourceInfoJsonString) {
619         if (responseWrapper.isEmpty()) {
620             validateMD5(responseWrapper, user, resourceInfo, request, resourceInfoJsonString);
621         }
622         if (responseWrapper.isEmpty() && request != null && request.getMethod() != null && request.getMethod().equals("POST")) {
623             validateResourceDoesNotExist(responseWrapper, user, resourceInfo.getName());
624         }
625     }
626
627     protected void commonPayloadValidations(Wrapper<Response> responseWrapper, Wrapper<String> yamlStringWrapper, User user, UploadResourceInfo uploadResourceInfo) {
628
629         if (responseWrapper.isEmpty()) {
630             validatePayloadIsYml(responseWrapper, user, uploadResourceInfo, yamlStringWrapper.getInnerElement());
631         }
632         if (responseWrapper.isEmpty()) {
633             validatePayloadIsTosca(responseWrapper, uploadResourceInfo, user, yamlStringWrapper.getInnerElement());
634         }
635         if (responseWrapper.isEmpty()) {
636             validatePayloadIsNotService(responseWrapper, user, uploadResourceInfo, yamlStringWrapper.getInnerElement());
637         }
638         if (responseWrapper.isEmpty()) {
639             validatePayloadIsSingleResource(responseWrapper, uploadResourceInfo, user, yamlStringWrapper.getInnerElement());
640         }
641     }
642
643
644     protected void handleImport(Wrapper<Response> responseWrapper, User user, UploadResourceInfo resourceInfoObject, String yamlAsString, ResourceAuthorityTypeEnum authority, boolean createNewVersion, String resourceUniqueId) {
645         Either<ImmutablePair<Resource, ActionStatus>, ResponseFormat> createOrUpdateResponse = null;
646         Response response = null;
647         Object representation = null;
648         ImmutablePair<Resource, ActionStatus> importedResourceStatus = null;
649         if (CsarValidationUtils.isCsarPayloadName(resourceInfoObject.getPayloadName())) {
650             log.debug("import resource from csar");
651             importedResourceStatus = importResourceFromUICsar(resourceInfoObject, user, resourceUniqueId);
652         } else if (!authority.isUserTypeResource()) {
653             log.debug("import normative type resource");
654             createOrUpdateResponse = resourceImportManager.importNormativeResource(yamlAsString, resourceInfoObject, user, createNewVersion, true);
655         } else {
656             log.debug("import user resource (not normative type)");
657             createOrUpdateResponse = resourceImportManager.importUserDefinedResource(yamlAsString, resourceInfoObject, user,  false);
658         }
659         if (createOrUpdateResponse!= null){
660             if(createOrUpdateResponse.isRight()){
661                 response = buildErrorResponse(createOrUpdateResponse.right().value());
662             }else {
663                 importedResourceStatus = createOrUpdateResponse.left().value();
664             }
665         }
666         if(importedResourceStatus != null){
667             try {
668                 representation = RepresentationUtils.toRepresentation(importedResourceStatus.left);
669             } catch (IOException e) {
670                 log.debug("Error while building resource representation : {}", e.getMessage(), e);
671             }
672             response = buildOkResponse(getComponentsUtils().getResponseFormat(importedResourceStatus.right), representation);
673         }
674         responseWrapper.setInnerElement(response);
675     }
676
677     private ImmutablePair<Resource, ActionStatus> importResourceFromUICsar(UploadResourceInfo resourceInfoObject, User user, String resourceUniqueId) {
678
679         Resource newResource;
680         ImmutablePair<Resource, ActionStatus> result = null;
681         ActionStatus actionStatus;
682         Resource resource = new Resource();
683         String payloadName = resourceInfoObject.getPayloadName();
684         fillResourceFromResourceInfoObject(resource, resourceInfoObject);
685
686         Either<Map<String, byte[]>, ResponseFormat> csarUIPayloadRes = getCsarFromPayload(resourceInfoObject);
687         if (csarUIPayloadRes.isRight()) {
688             throw new ByResponseFormatComponentException(csarUIPayloadRes.right().value());
689         }
690         Map<String, byte[]> csarUIPayload = csarUIPayloadRes.left().value();
691
692         getAndValidateCsarYaml(csarUIPayload, resource, user, payloadName);
693
694         if (resourceUniqueId == null || resourceUniqueId.isEmpty()) {
695             newResource = resourceImportManager.getResourceBusinessLogic().createResource(resource, AuditingActionEnum.CREATE_RESOURCE, user, csarUIPayload, payloadName);
696             actionStatus = ActionStatus.CREATED;
697         } else {
698             newResource = resourceImportManager.getResourceBusinessLogic().validateAndUpdateResourceFromCsar(resource, user, csarUIPayload, payloadName, resourceUniqueId);
699             actionStatus = ActionStatus.OK;
700         }
701         return new ImmutablePair<>(newResource, actionStatus);
702     }
703
704     private Resource throwComponentException(ResponseFormat responseFormat) {
705         throw new ByResponseFormatComponentException(responseFormat);
706     }
707
708     private void getAndValidateCsarYaml(Map<String, byte[]> csarUIPayload, Resource resource, User user, String csarUUID) {
709
710         Either<ImmutablePair<String, String>, ResponseFormat> getToscaYamlRes = CsarValidationUtils.getToscaYaml(csarUIPayload, csarUUID, getComponentsUtils());
711
712         if (getToscaYamlRes.isRight()) {
713             ResponseFormat responseFormat = getToscaYamlRes.right().value();
714             log.debug("Error when try to get csar toscayamlFile with csar ID {}, error: {}", csarUUID, responseFormat);
715             BeEcompErrorManager.getInstance().logBeDaoSystemError("Creating resource from CSAR: fetching CSAR with id " + csarUUID + " failed");
716             getComponentsUtils().auditResource(responseFormat, user, resource, AuditingActionEnum.CREATE_RESOURCE);
717             throwComponentException(responseFormat);
718         }
719         String toscaYaml = getToscaYamlRes.left().value().getValue();
720
721         log.debug("checking tosca template is valid yml");
722         YamlToObjectConverter yamlConvertor = new YamlToObjectConverter();
723         boolean isValid = yamlConvertor.isValidYaml(toscaYaml.getBytes());
724         if (!isValid) {
725             ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.INVALID_YAML_FILE);
726             getComponentsUtils().auditResource(responseFormat, user, resource, AuditingActionEnum.IMPORT_RESOURCE);
727             throwComponentException(responseFormat);
728         }
729
730         log.debug("checking payload is valid tosca");
731         Map<String, Object> mappedToscaTemplate = (Map<String, Object>) new Yaml().load(toscaYaml);
732         Either<String, ResultStatusEnum> findFirstToscaStringElement = ImportUtils.findFirstToscaStringElement(mappedToscaTemplate, TypeUtils.ToscaTagNamesEnum.TOSCA_VERSION);
733
734         if (findFirstToscaStringElement.isRight()) {
735             isValid = false;
736         } else {
737             String defenitionVersionFound = findFirstToscaStringElement.left().value();
738             if (defenitionVersionFound == null || defenitionVersionFound.isEmpty()) {
739                 isValid = false;
740             } else {
741                 isValid = TOSCA_DEFINITION_VERSIONS.contains(defenitionVersionFound);
742             }
743         }
744
745         if (!isValid) {
746             ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.INVALID_TOSCA_TEMPLATE);
747             getComponentsUtils().auditResource(responseFormat, user, resource, AuditingActionEnum.IMPORT_RESOURCE);
748             throwComponentException(responseFormat);
749         }
750     }
751
752     private void fillResourceFromResourceInfoObject(Resource resource, UploadResourceInfo resourceInfoObject) {
753         resourceImportManager.populateResourceMetadata(resourceInfoObject, resource);
754         fillArtifacts(resource, resourceInfoObject);
755
756     }
757
758     private void fillArtifacts(Resource resource, UploadResourceInfo resourceInfoObject) {
759         if (resource != null && resourceInfoObject != null) {
760             List<UploadArtifactInfo> artifactList = resourceInfoObject.getArtifactList();
761             if (artifactList != null) {
762                 Map<String, ArtifactDefinition> artifactsHM = new HashMap<>();
763                 for (UploadArtifactInfo artifact : artifactList) {
764                     ArtifactDefinition artifactDef = new ArtifactDefinition();
765                     artifactDef.setArtifactName(artifact.getArtifactName());
766                     artifactDef.setArtifactType(artifact.getArtifactType().getType());
767                     artifactDef.setDescription(artifact.getArtifactDescription());
768                     artifactDef.setPayloadData(artifact.getArtifactData());
769                     artifactDef.setArtifactRef(artifact.getArtifactPath());
770                     artifactsHM.put(artifactDef.getArtifactName(), artifactDef);
771                 }
772                 resource.setArtifacts(artifactsHM);
773             }
774         }
775     }
776
777     private Either<Map<String, byte[]>, ResponseFormat> getCsarFromPayload(UploadResourceInfo innerElement) {
778         String csarUUID = innerElement.getPayloadName();
779         String payloadData = innerElement.getPayloadData();
780         if (payloadData == null) {
781             log.info("Failed to decode received csar {}", csarUUID);
782             return Either.right(componentsUtils.getResponseFormat(ActionStatus.CSAR_NOT_FOUND, csarUUID));
783         }
784
785         byte[] decodedPayload = Base64.decodeBase64(payloadData.getBytes(StandardCharsets.UTF_8));
786         if (decodedPayload == null) {
787             log.info("Failed to decode received csar {}", csarUUID);
788             return Either.right(componentsUtils.getResponseFormat(ActionStatus.CSAR_NOT_FOUND, csarUUID));
789         }
790
791         Map<String, byte[]> csar = null;
792         try {
793             csar = ZipUtils.readZip(decodedPayload, false);
794         } catch (final ZipException e) {
795             log.info("Failed to unzip received csar {}", csarUUID, e);
796         }
797         if (MapUtils.isEmpty(csar)) {
798             return Either.right(componentsUtils.getResponseFormat(ActionStatus.CSAR_INVALID, csarUUID));
799         }
800         return Either.left(csar);
801     }
802
803     protected void validateInputStream(final HttpServletRequest request, Wrapper<String> dataWrapper, Wrapper<ResponseFormat> errorWrapper) throws IOException {
804         InputStream inputStream = request.getInputStream();
805         byte[] bytes = IOUtils.toByteArray(inputStream);
806         if (bytes == null || bytes.length == 0) {
807             log.info("Empty body was sent.");
808             errorWrapper.setInnerElement(getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT));
809         } else {
810             dataWrapper.setInnerElement(new String(bytes, StandardCharsets.UTF_8));
811         }
812
813     }
814
815     protected <T> void validateClassParse(String data, Wrapper<T> parsedClassWrapper, Supplier<Class<T>> classGen, Wrapper<ResponseFormat> errorWrapper) {
816         try {
817             T parsedClass = gson.fromJson(data, classGen.get());
818             if (parsedClass == null) {
819                 errorWrapper.setInnerElement(getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT));
820             } else {
821                 parsedClassWrapper.setInnerElement(parsedClass);
822             }
823         } catch (JsonSyntaxException e) {
824             log.debug("Failed to decode received {} {} to object.", classGen.get().getName(), data, e);
825             errorWrapper.setInnerElement(getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT));
826         }
827     }
828
829     protected void validateComponentInstanceBusinessLogic(HttpServletRequest request, String containerComponentType, Wrapper<ComponentInstanceBusinessLogic> blWrapper, Wrapper<ResponseFormat> errorWrapper) {
830         ServletContext context = request.getSession().getServletContext();
831         if (componentInstanceBusinessLogic == null) {
832             log.debug("Unsupported component type {}", containerComponentType);
833             errorWrapper.setInnerElement(getComponentsUtils().getResponseFormat(ActionStatus.UNSUPPORTED_ERROR, containerComponentType));
834         } else {
835             blWrapper.setInnerElement(componentInstanceBusinessLogic);
836         }
837     }
838
839     protected <T> Response buildResponseFromElement(Wrapper<ResponseFormat> errorWrapper, Wrapper<T> attributeWrapper) throws IOException {
840         Response response;
841         if (errorWrapper.isEmpty()) {
842             ObjectMapper mapper = new ObjectMapper();
843             String result = mapper.writeValueAsString(attributeWrapper.getInnerElement());
844             response = buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), result);
845         } else {
846             response = buildErrorResponse(errorWrapper.getInnerElement());
847         }
848         return response;
849     }
850
851     protected void validateXECOMPInstanceIDHeader(String instanceIdHeader, Wrapper<ResponseFormat> responseWrapper) {
852         ResponseFormat responseFormat;
853         if(StringUtils.isEmpty(instanceIdHeader) ){
854             log.debug("Missing X-ECOMP-InstanceID header");
855             responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.MISSING_X_ECOMP_INSTANCE_ID);
856             responseWrapper.setInnerElement(responseFormat);
857         }
858     }
859
860     protected void validateHttpCspUserIdHeader(String header, Wrapper<ResponseFormat> responseWrapper) {
861         ResponseFormat responseFormat;
862         if( StringUtils.isEmpty(header)){
863             log.debug("MissingUSER_ID");
864             responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.MISSING_USER_ID);
865             responseWrapper.setInnerElement(responseFormat);
866         }
867     }
868
869     /**
870      * Convert json to Object object
871      * @param <T>
872      * @param classSupplier
873      * @param json
874      * @return
875      */
876     public <T> Either<T, ResponseFormat> parseToObject(String json, Supplier<Class<T>> classSupplier) {
877
878         try {
879             T object = RepresentationUtils.fromRepresentation(json, classSupplier.get());
880             return Either.left(object);
881         } catch (Exception e) {
882             log.debug("Failed to parse json to {} object", classSupplier.get().getName(), e);
883             ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT);
884             return Either.right(responseFormat);
885         }
886     }
887
888     /**
889      * Convert json to Object object
890      * @param <T>
891      * @param json
892      * @param type
893      * @return
894      */
895     public <T> Either<List<T>, ResponseFormat> parseListOfObjects(String json, Type type) {
896         try {
897             List<T> listOfObjects = gson.fromJson(json, type);
898             return Either.left(listOfObjects);
899         } catch (Exception e) {
900             log.debug("Failed to parse json to {} object", type.getClass().getName(), e);
901             ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT);
902             return Either.right(responseFormat);
903         }
904     }
905 }