mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
volume upload: added validation for file formats
merged TemplateUtils and ImageStoreUtil to a singe ImageStoreUtil also added a unittest for ImageStoreUtil
This commit is contained in:
parent
d5dffb5dc9
commit
018023c1ef
@ -28,6 +28,7 @@ import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.util.Date;
|
||||
|
||||
import org.apache.cloudstack.utils.imagestore.ImageStoreUtil;
|
||||
import org.apache.commons.httpclient.Credentials;
|
||||
import org.apache.commons.httpclient.Header;
|
||||
import org.apache.commons.httpclient.HttpClient;
|
||||
@ -45,7 +46,6 @@ import org.apache.log4j.Logger;
|
||||
|
||||
import org.apache.cloudstack.managed.context.ManagedContextRunnable;
|
||||
import org.apache.cloudstack.storage.command.DownloadCommand.ResourceType;
|
||||
import org.apache.cloudstack.utils.template.TemplateUtils;
|
||||
|
||||
import com.cloud.agent.api.storage.Proxy;
|
||||
import com.cloud.storage.StorageLayer;
|
||||
@ -259,7 +259,7 @@ public class HttpTemplateDownloader extends ManagedContextRunnable implements Te
|
||||
} catch (URISyntaxException e) {
|
||||
s_logger.warn("Invalid download url: " + getDownloadUrl() + ", This should not happen since we have validated the url before!!");
|
||||
}
|
||||
String unsupportedFormat = TemplateUtils.checkTemplateFormat(file.getAbsolutePath(), uripath);
|
||||
String unsupportedFormat = ImageStoreUtil.checkTemplateFormat(file.getAbsolutePath(), uripath);
|
||||
if (unsupportedFormat == null || !unsupportedFormat.isEmpty()) {
|
||||
try {
|
||||
request.abort();
|
||||
|
||||
@ -29,7 +29,6 @@ import java.util.concurrent.ExecutionException;
|
||||
import javax.inject.Inject;
|
||||
|
||||
import com.cloud.utils.EncryptionUtil;
|
||||
import com.cloud.utils.ImageStoreUtil;
|
||||
import com.cloud.utils.db.TransactionCallbackWithException;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
@ -39,6 +38,7 @@ import org.apache.cloudstack.api.response.GetUploadParamsResponse;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.DataObject;
|
||||
import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint;
|
||||
import org.apache.cloudstack.storage.command.TemplateOrVolumePostUploadCommand;
|
||||
import org.apache.cloudstack.utils.imagestore.ImageStoreUtil;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.apache.cloudstack.api.command.user.volume.AttachVolumeCmd;
|
||||
import org.apache.cloudstack.api.command.user.volume.CreateVolumeCmd;
|
||||
|
||||
@ -35,13 +35,13 @@ import javax.naming.ConfigurationException;
|
||||
|
||||
import com.cloud.storage.ImageStoreUploadMonitorImpl;
|
||||
import com.cloud.utils.EncryptionUtil;
|
||||
import com.cloud.utils.ImageStoreUtil;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
|
||||
import org.apache.cloudstack.api.command.user.template.GetUploadParamsForTemplateCmd;
|
||||
import org.apache.cloudstack.api.response.GetUploadParamsResponse;
|
||||
import org.apache.cloudstack.storage.command.TemplateOrVolumePostUploadCommand;
|
||||
import org.apache.cloudstack.utils.imagestore.ImageStoreUtil;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.apache.cloudstack.acl.SecurityChecker.AccessType;
|
||||
|
||||
@ -28,6 +28,8 @@ import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.apache.cloudstack.storage.template.UploadEntity;
|
||||
import org.apache.cloudstack.utils.imagestore.ImageStoreUtil;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import com.cloud.exception.InvalidParameterValueException;
|
||||
@ -228,6 +230,14 @@ public class HttpUploadServerHandler extends SimpleChannelInboundHandler<HttpObj
|
||||
FileUpload fileUpload = (FileUpload) data;
|
||||
if (fileUpload.isCompleted()) {
|
||||
fileReceived = true;
|
||||
String format = ImageStoreUtil.checkTemplateFormat(fileUpload.getFile().getAbsolutePath(), fileUpload.getFilename());
|
||||
if(StringUtils.isNotBlank(format)) {
|
||||
String errorString = "File type mismatch between the sent file and the actual content. Received: " + format;
|
||||
logger.error(errorString);
|
||||
responseContent.append(errorString);
|
||||
storageResource.updateStateMapWithError(uuid, errorString);
|
||||
return HttpResponseStatus.BAD_REQUEST;
|
||||
}
|
||||
String status = storageResource.postUpload(uuid, fileUpload.getFile().getName());
|
||||
if (status != null) {
|
||||
responseContent.append(status);
|
||||
|
||||
@ -66,8 +66,10 @@ import io.netty.handler.logging.LogLevel;
|
||||
import io.netty.handler.logging.LoggingHandler;
|
||||
import org.apache.cloudstack.storage.command.TemplateOrVolumePostUploadCommand;
|
||||
import org.apache.cloudstack.storage.template.UploadEntity;
|
||||
import org.apache.cloudstack.utils.imagestore.ImageStoreUtil;
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.HttpResponse;
|
||||
@ -2663,6 +2665,18 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements S
|
||||
|
||||
String fileSavedTempLocation = uploadEntity.getInstallPathPrefix() + "/" + filename;
|
||||
|
||||
String uploadedFileExtension = FilenameUtils.getExtension(filename);
|
||||
String userSelectedFormat= "vhd";
|
||||
if(uploadedFileExtension.equals("zip") || uploadedFileExtension.equals("bz2") || uploadedFileExtension.equals("gz")) {
|
||||
userSelectedFormat += "." + uploadedFileExtension;
|
||||
}
|
||||
String formatError = ImageStoreUtil.checkTemplateFormat(fileSavedTempLocation, userSelectedFormat);
|
||||
if(StringUtils.isNotBlank(formatError)) {
|
||||
String errorString = "File type mismatch between uploaded file and selected format. Selected file format: " + uploadEntity.getFormat() + ". Received: " + formatError;
|
||||
s_logger.error(errorString);
|
||||
return errorString;
|
||||
}
|
||||
|
||||
int imgSizeGigs = getSizeInGB(_storage.getSize(fileSavedTempLocation));
|
||||
int maxSize = uploadEntity.getMaxSizeInGB();
|
||||
if(imgSizeGigs > maxSize) {
|
||||
|
||||
@ -1,39 +0,0 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package com.cloud.utils;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
public class ImageStoreUtil {
|
||||
public static final Logger s_logger = Logger.getLogger(ImageStoreUtil.class.getName());
|
||||
|
||||
public static String generatePostUploadUrl(String ssvmUrlDomain, String ipAddress, String uuid) {
|
||||
String hostname = ipAddress;
|
||||
|
||||
//if ssvm url domain is present, use it to construct hostname in the format 1-2-3-4.domain
|
||||
// if the domain name is not present, ssl validation fails and has to be ignored
|
||||
if(StringUtils.isNotBlank(ssvmUrlDomain)) {
|
||||
hostname = ipAddress.replace(".", "-");
|
||||
hostname = hostname + ssvmUrlDomain.substring(1);
|
||||
}
|
||||
|
||||
//only https works with postupload and url format is fixed
|
||||
return "https://" + hostname + "/upload/" + uuid;
|
||||
}
|
||||
}
|
||||
@ -1,30 +1,43 @@
|
||||
//
|
||||
// Licensed to the Apache Software Foundation (ASF) under one
|
||||
// or more contributor license agreements. See the NOTICE file
|
||||
// distributed with this work for additional information
|
||||
// regarding copyright ownership. The ASF licenses this file
|
||||
// to you under the Apache License, Version 2.0 (the
|
||||
// "License"); you may not use this file except in compliance
|
||||
// with the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing,
|
||||
// software distributed under the License is distributed on an
|
||||
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
// KIND, either express or implied. See the License for the
|
||||
// specific language governing permissions and limitations
|
||||
// under the License.
|
||||
//
|
||||
|
||||
package org.apache.cloudstack.utils.template;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.cloudstack.utils.imagestore;
|
||||
|
||||
import com.cloud.utils.script.Script;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
public class TemplateUtils {
|
||||
public static final Logger s_logger = Logger.getLogger(TemplateUtils.class.getName());
|
||||
public class ImageStoreUtil {
|
||||
public static final Logger s_logger = Logger.getLogger(ImageStoreUtil.class.getName());
|
||||
|
||||
public static String generatePostUploadUrl(String ssvmUrlDomain, String ipAddress, String uuid) {
|
||||
String hostname = ipAddress;
|
||||
|
||||
//if ssvm url domain is present, use it to construct hostname in the format 1-2-3-4.domain
|
||||
// if the domain name is not present, ssl validation fails and has to be ignored
|
||||
if(StringUtils.isNotBlank(ssvmUrlDomain)) {
|
||||
hostname = ipAddress.replace(".", "-");
|
||||
hostname = hostname + ssvmUrlDomain.substring(1);
|
||||
}
|
||||
|
||||
//only https works with postupload and url format is fixed
|
||||
return "https://" + hostname + "/upload/" + uuid;
|
||||
}
|
||||
|
||||
// given a path, returns empty if path is supported image, and the file type if unsupported
|
||||
// this is meant to catch things like accidental upload of ASCII text .vmdk descriptor
|
||||
@ -75,7 +88,7 @@ public class TemplateUtils {
|
||||
return output;
|
||||
}
|
||||
|
||||
public static boolean isCorrectExtension(String path, String ext) {
|
||||
private static boolean isCorrectExtension(String path, String ext) {
|
||||
if (path.toLowerCase().endsWith(ext)
|
||||
|| path.toLowerCase().endsWith(ext + ".gz")
|
||||
|| path.toLowerCase().endsWith(ext + ".bz2")
|
||||
@ -85,7 +98,7 @@ public class TemplateUtils {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isCompressedExtension(String path) {
|
||||
private static boolean isCompressedExtension(String path) {
|
||||
if (path.toLowerCase().endsWith(".gz")
|
||||
|| path.toLowerCase().endsWith(".bz2")
|
||||
|| path.toLowerCase().endsWith(".zip")) {
|
||||
@ -0,0 +1,38 @@
|
||||
package org.apache.cloudstack.utils.imagestore;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class ImageStoreUtilTest {
|
||||
|
||||
@Test
|
||||
public void testgeneratePostUploadUrl() throws MalformedURLException {
|
||||
String ssvmdomain = "*.realhostip.com";
|
||||
String ipAddress = "10.147.28.14";
|
||||
String uuid = UUID.randomUUID().toString();
|
||||
|
||||
//ssvm domain is not set
|
||||
String url = ImageStoreUtil.generatePostUploadUrl(null, ipAddress, uuid);
|
||||
assertPostUploadUrl(url, ipAddress, uuid);
|
||||
|
||||
//ssvm domain is set to empty value
|
||||
url = ImageStoreUtil.generatePostUploadUrl("", ipAddress, uuid);
|
||||
assertPostUploadUrl(url, ipAddress, uuid);
|
||||
|
||||
//ssvm domain is set to a valid value
|
||||
url = ImageStoreUtil.generatePostUploadUrl(ssvmdomain, ipAddress, uuid);
|
||||
assertPostUploadUrl(url, ipAddress.replace(".", "-") + ssvmdomain.substring(1), uuid);
|
||||
}
|
||||
|
||||
private void assertPostUploadUrl(String urlStr, String domain, String uuid) throws MalformedURLException {
|
||||
URL url = new URL(urlStr);
|
||||
Assert.assertNotNull(url);
|
||||
Assert.assertEquals(url.getHost(), domain);
|
||||
Assert.assertEquals(url.getPath(), "/upload/" + uuid);
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user