Fix Security Vulnerabilities 64/118964/12
authoraribeiro <anderson.ribeiro@est.tech>
Mon, 15 Feb 2021 17:24:11 +0000 (17:24 +0000)
committerChristophe Closset <christophe.closset@intl.att.com>
Tue, 16 Mar 2021 13:27:37 +0000 (13:27 +0000)
Issue-ID: SDC-3500
Signed-off-by: aribeiro <anderson.ribeiro@est.tech>
Change-Id: I3fa2ed2bc3a170d8256fbc91c98bbfbaf5c0a403

catalog-be/src/main/java/org/openecomp/sdc/be/servlets/LifecycleServlet.java
catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ResourcesServlet.java
catalog-ui/src/app/models/components/component.ts
catalog-ui/src/app/services/components/component-service.ts
catalog-ui/src/app/utils/validation-utils.ts
common-app-api/src/main/java/org/openecomp/sdc/common/util/ValidationUtils.java
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/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/test/resources/files/sample-not-signed.csar [new file with mode: 0644]
openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/test/resources/files/sample-signed.zip [new file with mode: 0644]

index f13621f..87c890d 100644 (file)
@@ -33,6 +33,18 @@ import io.swagger.v3.oas.annotations.servers.Server;
 import io.swagger.v3.oas.annotations.servers.Servers;
 import io.swagger.v3.oas.annotations.tags.Tag;
 import io.swagger.v3.oas.annotations.tags.Tags;
+import java.io.IOException;
+import javax.inject.Inject;
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.HeaderParam;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
 import org.openecomp.sdc.be.components.impl.aaf.AafPermission;
 import org.openecomp.sdc.be.components.impl.aaf.PermissionAllowed;
 import org.openecomp.sdc.be.components.lifecycle.LifecycleBusinessLogic;
@@ -54,22 +66,10 @@ import org.openecomp.sdc.common.log.elements.LoggerSupportability;
 import org.openecomp.sdc.common.log.enums.LoggerSupportabilityActions;
 import org.openecomp.sdc.common.log.enums.StatusCode;
 import org.openecomp.sdc.common.log.wrappers.Logger;
+import org.openecomp.sdc.common.util.ValidationUtils;
 import org.openecomp.sdc.exception.ResponseFormat;
 import org.springframework.stereotype.Controller;
 
-import javax.inject.Inject;
-import javax.servlet.http.HttpServletRequest;
-import javax.ws.rs.Consumes;
-import javax.ws.rs.HeaderParam;
-import javax.ws.rs.POST;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.Context;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-import java.io.IOException;
-
 @Loggable(prepend = true, value = Loggable.DEBUG, trim = false)
 @Path("/v1/catalog")
 @Tags({@Tag(name = "SDC Internal APIs")})
@@ -101,9 +101,8 @@ public class LifecycleServlet extends BeGenericServlet {
             @ApiResponse(responseCode = "409", description = "Resource already exist")})
     @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE)
     public Response changeResourceState(
-            @Parameter(
-                    description = "LifecycleChangeInfo - relevant for checkin, failCertification, cancelCertification",
-                    required = false) String jsonChangeInfo,
+            @Parameter(description = "LifecycleChangeInfo - relevant for checkin, failCertification, cancelCertification")
+                String jsonChangeInfo,
             @Parameter(description = "validValues: resources / services / products",
                     schema = @Schema(allowableValues = {ComponentTypeEnum.RESOURCE_PARAM_NAME,
                             ComponentTypeEnum.SERVICE_PARAM_NAME, ComponentTypeEnum.PRODUCT_PARAM_NAME})) @PathParam(
@@ -116,7 +115,6 @@ public class LifecycleServlet extends BeGenericServlet {
             @Context final HttpServletRequest request,
             @Parameter(description = "id of user initiating the operation") @HeaderParam(
                     value = Constants.USER_ID_HEADER) String userId) throws IOException {
-
         String url = request.getMethod() + " " + request.getRequestURI();
         log.debug("Start handle request of {}", url);
         loggerSupportability.log(LoggerSupportabilityActions.CHANGELIFECYCLESTATE, StatusCode.STARTED,"Starting to change lifecycle state to " + lifecycleTransition + " by user " + userId);
@@ -143,7 +141,9 @@ public class LifecycleServlet extends BeGenericServlet {
         try {
             if (jsonChangeInfo != null && !jsonChangeInfo.isEmpty()) {
                 ObjectMapper mapper = new ObjectMapper();
-                changeInfo = new LifecycleChangeInfoWithAction(mapper.readValue(jsonChangeInfo, LifecycleChangeInfoBase.class).getUserRemarks());
+                changeInfo = new LifecycleChangeInfoWithAction(mapper
+                    .readValue(ValidationUtils.sanitizeInputString(jsonChangeInfo), LifecycleChangeInfoBase.class)
+                    .getUserRemarks());
             }
         }
 
index 168a70a..43fa378 100644 (file)
@@ -33,6 +33,25 @@ import io.swagger.v3.oas.annotations.servers.Servers;
 import io.swagger.v3.oas.annotations.tags.Tag;
 import io.swagger.v3.oas.annotations.tags.Tags;
 import java.io.File;
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+import javax.inject.Inject;
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.HeaderParam;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
 import org.apache.http.HttpStatus;
 import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
 import org.glassfish.jersey.media.multipart.FormDataParam;
@@ -40,7 +59,6 @@ import org.json.JSONException;
 import org.json.JSONObject;
 import org.openecomp.sdc.be.components.impl.ComponentInstanceBusinessLogic;
 import org.openecomp.sdc.be.components.impl.CsarValidationUtils;
-import org.openecomp.sdc.be.components.impl.ElementBusinessLogic;
 import org.openecomp.sdc.be.components.impl.ImportUtils;
 import org.openecomp.sdc.be.components.impl.ResourceBusinessLogic;
 import org.openecomp.sdc.be.components.impl.ResourceImportManager;
@@ -67,30 +85,11 @@ import org.openecomp.sdc.common.log.elements.LoggerSupportability;
 import org.openecomp.sdc.common.log.enums.LoggerSupportabilityActions;
 import org.openecomp.sdc.common.log.enums.StatusCode;
 import org.openecomp.sdc.common.log.wrappers.Logger;
+import org.openecomp.sdc.common.util.ValidationUtils;
 import org.openecomp.sdc.common.zip.exception.ZipException;
 import org.openecomp.sdc.exception.ResponseFormat;
 import org.springframework.stereotype.Controller;
 
-import javax.inject.Inject;
-import javax.servlet.ServletContext;
-import javax.servlet.http.HttpServletRequest;
-import javax.ws.rs.Consumes;
-import javax.ws.rs.DELETE;
-import javax.ws.rs.GET;
-import javax.ws.rs.HeaderParam;
-import javax.ws.rs.POST;
-import javax.ws.rs.PUT;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-import javax.ws.rs.Produces;
-import javax.ws.rs.QueryParam;
-import javax.ws.rs.core.Context;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-import java.io.IOException;
-import java.util.List;
-import java.util.Map;
-
 @Loggable(prepend = true, value = Loggable.DEBUG, trim = false)
 @Path("/v1/catalog")
 @Tags({@Tag(name = "SDC Internal APIs")})
@@ -582,12 +581,12 @@ public class ResourcesServlet extends AbstractValidationsServlet {
         try {
 
             Either<Resource, ResponseFormat> eitherResource =
-                    resourceBusinessLogic.getLatestResourceFromCsarUuid(csarUUID, user);
+                    resourceBusinessLogic.getLatestResourceFromCsarUuid(ValidationUtils.sanitizeInputString(csarUUID), user);
 
             // validate response
             if (eitherResource.isRight()) {
                 log.debug("failed to get resource from csarUuid : {}", csarUUID);
-                response = buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), eitherResource.right().value());
+                response = buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT), eitherResource.right().value());
             } else {
                 Object representation = RepresentationUtils.toRepresentation(eitherResource.left().value());
                 response = buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), representation);
index 1d48151..f787142 100644 (file)
@@ -247,7 +247,7 @@ export abstract class Component implements IComponent {
         let onError = (error:any):void => {
             deferred.reject(error);
         };
-        this.componentService.changeLifecycleState(this, state, JSON.stringify(commentObj)).then(onSuccess, onError);
+        this.componentService.changeLifecycleState(this, state, commentObj).then(onSuccess, onError);
         return deferred.promise;
     };
 
index f22562f..47eec26 100644 (file)
  */
 'use strict';
 import * as _ from "lodash";
-import {ArtifactModel, IFileDownload, InstancesInputsPropertiesMap, InputModel, IValidate, RelationshipModel, PropertyModel, Component, ComponentInstance,
-    AttributeModel, IAppConfigurtaion, Resource, Module, DisplayModule, ArtifactGroupModel, InputsAndProperties} from "app/models";
+import {
+    ArtifactModel,
+    IFileDownload,
+    InstancesInputsPropertiesMap,
+    InputModel,
+    IValidate,
+    RelationshipModel,
+    PropertyModel,
+    Component,
+    ComponentInstance,
+    AttributeModel,
+    IAppConfigurtaion,
+    Resource,
+    Module,
+    DisplayModule,
+    ArtifactGroupModel,
+    InputsAndProperties,
+    AsdcComment
+} from "app/models";
 import {ComponentInstanceFactory, CommonUtils} from "app/utils";
 import {SharingService} from "app/services-ng2";
 import {ComponentMetadata} from "../../models/component-metadata";
@@ -29,7 +46,7 @@ export interface IComponentService {
 
     getComponent(id:string);
     updateComponent(component:Component):ng.IPromise<Component>;
-    changeLifecycleState(component:Component, state:string, userRemarks:any):ng.IPromise<ComponentMetadata> ;
+    changeLifecycleState(component:Component, state:string, userRemarks:AsdcComment):ng.IPromise<ComponentMetadata> ;
     validateName(newName:string, subtype?:string):ng.IPromise<IValidate>;
     createComponent(component:Component):ng.IPromise<Component>;
     //importComponent
@@ -233,15 +250,28 @@ export class ComponentService implements IComponentService {
         return deferred.promise;
     };
 
-    public changeLifecycleState = (component:Component, state:string, userRemarks:any):ng.IPromise<ComponentMetadata> => {
+    public changeLifecycleState = (component:Component, state:string, commentObj:AsdcComment):ng.IPromise<ComponentMetadata> => {
         let deferred = this.$q.defer<ComponentMetadata>();
-        this.restangular.one(component.uniqueId).one(state).customPOST(userRemarks).then((response:ComponentMetadata) => {
-            this.sharingService.addUuidValue(response.uniqueId, response.uuid);
-            let component:ComponentMetadata = new ComponentMetadata().deserialize(response);
-            deferred.resolve(component);
-        }, (err)=> {
-            deferred.reject(err);
-        });
+        let headerObj = {};
+        if (commentObj.userRemarks) {
+            headerObj = this.getHeaderMd5(commentObj);
+            this.restangular.one(component.uniqueId).one(state).customPOST(JSON.stringify(commentObj), '', {}, headerObj)
+            .then((response:ComponentMetadata) => {
+                this.sharingService.addUuidValue(response.uniqueId, response.uuid);
+                let component:ComponentMetadata = new ComponentMetadata().deserialize(response);
+                deferred.resolve(component);
+            }, (err)=> {
+                deferred.reject(err);
+            });
+        } else {
+            this.restangular.one(component.uniqueId).one(state).customPOST().then((response:ComponentMetadata) => {
+                this.sharingService.addUuidValue(response.uniqueId, response.uuid);
+                let component:ComponentMetadata = new ComponentMetadata().deserialize(response);
+                deferred.resolve(component);
+            }, (err)=> {
+                deferred.reject(err);
+            });
+        }
         return deferred.promise;
     };
 
index b7e43f7..bcb49d8 100644 (file)
@@ -64,7 +64,10 @@ export class ValidationUtils {
         if (!text) {
             return null;
         }
-        return text.replace(/\s+/g, ' ').replace(/%[A-Fa-f0-9]{2}/g, '').trim();
+        return text.replace(/\s+/g, ' ').replace(/%[A-Fa-f0-9]{2}/g, '')
+        .replace(/&/g, "&amp;").replace(/>/g, "&gt;")
+        .replace(/</g, "&lt;").replace(/"/g, "&quot;")
+        .replace(/'/g, "&apos;").trim();
     }
 
     public getValidationPattern = (validationType:string, parameterType?:string):RegExp => {
index 375f041..1a9cb26 100644 (file)
@@ -585,4 +585,15 @@ public class ValidationUtils {
        public static boolean validateForwardingPathNamePattern(String forwardingPathName) {
                return FORWARDING_PATH_NAME_PATTERN.matcher(forwardingPathName).matches();
        }
+
+       public static String sanitizeInputString(String input) {
+               if (StringUtils.isNotEmpty(input)) {
+                       input = ValidationUtils.removeNoneUtf8Chars(input);
+                       input = ValidationUtils.removeHtmlTags(input);
+                       input = ValidationUtils.normaliseWhitespace(input);
+                       input = ValidationUtils.stripOctets(input);
+               }
+               return input;
+       }
+
 }
index 073400f..b393153 100644 (file)
@@ -1,6 +1,7 @@
 /*
  * Copyright © 2016-2018 European Support Limited
  * Copyright © 2021 Nokia
+ * Copyright © 2021 Nordix Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -32,6 +33,7 @@ import java.util.Optional;
 import javax.activation.DataHandler;
 import javax.inject.Named;
 import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
 import org.apache.commons.lang3.tuple.Pair;
 import org.apache.cxf.jaxrs.ext.multipart.Attachment;
 import org.openecomp.sdc.activitylog.ActivityLogManager;
@@ -39,6 +41,7 @@ import org.openecomp.sdc.activitylog.ActivityLogManagerFactory;
 import org.openecomp.sdc.activitylog.dao.type.ActivityLogEntity;
 import org.openecomp.sdc.activitylog.dao.type.ActivityType;
 import org.openecomp.sdc.common.errors.Messages;
+import org.openecomp.sdc.common.util.ValidationUtils;
 import org.openecomp.sdc.common.utils.SdcCommon;
 import org.openecomp.sdc.datatypes.error.ErrorLevel;
 import org.openecomp.sdc.datatypes.error.ErrorMessage;
@@ -100,13 +103,13 @@ public class OrchestrationTemplateCandidateImpl implements OrchestrationTemplate
                          final Attachment fileToUpload, final String user) {
     final byte[] fileToUploadBytes = fileToUpload.getObject(byte[].class);
     final DataHandler dataHandler = fileToUpload.getDataHandler();
-    final String filename = dataHandler.getName();
+    final String filename = ValidationUtils.sanitizeInputString(dataHandler.getName());
 
     final OnboardingPackageProcessor onboardingPackageProcessor = new OnboardingPackageProcessor(filename, fileToUploadBytes);
     if (onboardingPackageProcessor.hasErrors()) {
       final UploadFileResponseDto uploadFileResponseDto =
           buildUploadResponseWithError(onboardingPackageProcessor.getErrorMessages().toArray(new ErrorMessage[0]));
-      return Response.ok(uploadFileResponseDto).build();
+      return Response.status(Status.NOT_ACCEPTABLE).entity(uploadFileResponseDto).build();
     }
 
     final OnboardPackageInfo onboardPackageInfo = onboardingPackageProcessor.getOnboardPackageInfo().orElse(null);
@@ -117,7 +120,8 @@ public class OrchestrationTemplateCandidateImpl implements OrchestrationTemplate
       return Response.ok(uploadFileResponseDto).build();
     }
 
-    final VspDetails vspDetails = new VspDetails(vspId, new Version(versionId));
+    final VspDetails vspDetails = new VspDetails(ValidationUtils.sanitizeInputString(vspId),
+        new Version(ValidationUtils.sanitizeInputString(versionId)));
     return processOnboardPackage(onboardPackageInfo, vspDetails);
   }
 
index dec6342..41891de 100644 (file)
@@ -22,16 +22,21 @@ package org.openecomp.sdcrests.vsp.rest.services;
 
 import static junit.framework.TestCase.assertEquals;
 import static junit.framework.TestCase.assertFalse;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.MockitoAnnotations.initMocks;
 import static org.mockito.Mockito.when;
 
 import java.io.IOException;
+import java.net.URL;
 import java.util.Arrays;
+import java.util.Objects;
 import java.util.Optional;
 import java.util.UUID;
 import javax.activation.DataHandler;
 import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import org.apache.commons.io.IOUtils;
 import org.apache.commons.lang3.tuple.Pair;
 import org.apache.cxf.jaxrs.ext.multipart.Attachment;
 import org.apache.cxf.jaxrs.ext.multipart.ContentDisposition;
@@ -135,32 +140,46 @@ public class OrchestrationTemplateCandidateImplTest {
 
     @Test
     public void uploadSignedTest() {
-        Response response = orchestrationTemplateCandidate.upload("1", "1", mockAttachment("filename.zip"), "1");
-        assertEquals(Response.Status.OK.getStatusCode(), response.getStatus());
+        Response response = orchestrationTemplateCandidate
+            .upload("1", "1", mockAttachment("filename.zip", this.getClass().getResource("/files/sample-signed.zip")),
+                "1");
+        assertEquals(Status.OK.getStatusCode(), response.getStatus());
+        assertTrue(((UploadFileResponseDto) response.getEntity()).getErrors().isEmpty());
     }
 
     @Test
-    public void uploadNotSignedTest(){
-        Response response = orchestrationTemplateCandidate.upload("1", "1", mockAttachment("filename.csar"), "1");
-        assertEquals(Response.Status.OK.getStatusCode(), response.getStatus());
+    public void uploadNotSignedTest() {
+        Response response = orchestrationTemplateCandidate.upload("1", "1",
+            mockAttachment("filename.csar", this.getClass().getResource("/files/sample-not-signed.csar")), "1");
+        assertEquals(Status.OK.getStatusCode(), response.getStatus());
+        assertTrue(((UploadFileResponseDto) response.getEntity()).getErrors().isEmpty());
     }
 
-    private Attachment mockAttachment(final String fileName) {
+    private Attachment mockAttachment(final String fileName, final URL fileToUpload) {
         final Attachment attachment = Mockito.mock(Attachment.class);
         when(attachment.getContentDisposition()).thenReturn(new ContentDisposition("test"));
         final DataHandler dataHandler = Mockito.mock(DataHandler.class);
         when(dataHandler.getName()).thenReturn(fileName);
         when(attachment.getDataHandler()).thenReturn(dataHandler);
-        final byte[] bytes = "upload package Test".getBytes();
+        byte[] bytes = "upload package Test".getBytes();
+        if (Objects.nonNull(fileToUpload)) {
+            try {
+                bytes = IOUtils.toByteArray(fileToUpload);
+            } catch (final IOException e) {
+                logger.error("unexpected exception", e);
+                Assert.fail("Not able to convert file to byte array");
+            }
+        }
         when(attachment.getObject(ArgumentMatchers.any())).thenReturn(bytes);
         return attachment;
     }
 
     @Test
     public void uploadSignNotValidTest() {
-        Response response = orchestrationTemplateCandidate.upload("1", "1", mockAttachment("filename.zip"), "1");
-        assertEquals(Response.Status.OK.getStatusCode(), response.getStatus());
-        assertFalse(((UploadFileResponseDto)response.getEntity()).getErrors().isEmpty());
+        Response response = orchestrationTemplateCandidate
+            .upload("1", "1", mockAttachment("filename.zip", null), "1");
+        assertEquals(Status.NOT_ACCEPTABLE.getStatusCode(), response.getStatus());
+        assertFalse(((UploadFileResponseDto) response.getEntity()).getErrors().isEmpty());
     }
 
     @Test
diff --git a/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/test/resources/files/sample-not-signed.csar b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/test/resources/files/sample-not-signed.csar
new file mode 100644 (file)
index 0000000..e4e60b2
Binary files /dev/null and b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/test/resources/files/sample-not-signed.csar differ
diff --git a/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/test/resources/files/sample-signed.zip b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/test/resources/files/sample-signed.zip
new file mode 100644 (file)
index 0000000..fecb45a
Binary files /dev/null and b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/test/resources/files/sample-signed.zip differ