This is an automated email from the ASF dual-hosted git repository.

joao pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/cloudstack.git


The following commit(s) were added to refs/heads/main by this push:
     new ede39d8edc4 Configuration to disable URL validation when registering 
templates/ISOs (#8751)
ede39d8edc4 is described below

commit ede39d8edc44ca05d4d2604fb27e996314c3db60
Author: Fabricio Duarte <[email protected]>
AuthorDate: Tue Aug 27 16:12:31 2024 -0300

    Configuration to disable URL validation when registering templates/ISOs 
(#8751)
---
 .../java/com/cloud/template/TemplateManager.java   |  9 +++++
 .../cloud/template/HypervisorTemplateAdapter.java  |  4 +-
 .../com/cloud/template/TemplateManagerImpl.java    |  2 +-
 utils/src/main/java/com/cloud/utils/UriUtils.java  | 45 ++++++++++++++++------
 4 files changed, 45 insertions(+), 15 deletions(-)

diff --git 
a/engine/components-api/src/main/java/com/cloud/template/TemplateManager.java 
b/engine/components-api/src/main/java/com/cloud/template/TemplateManager.java
index 3b3537d5488..997ae3985f1 100644
--- 
a/engine/components-api/src/main/java/com/cloud/template/TemplateManager.java
+++ 
b/engine/components-api/src/main/java/com/cloud/template/TemplateManager.java
@@ -51,6 +51,11 @@ public interface TemplateManager {
     static final ConfigKey<Integer> TemplatePreloaderPoolSize = new 
ConfigKey<Integer>("Advanced", Integer.class, TemplatePreloaderPoolSizeCK, "8",
             "Size of the TemplateManager threadpool", false, 
ConfigKey.Scope.Global);
 
+    ConfigKey<Boolean> ValidateUrlIsResolvableBeforeRegisteringTemplate = new 
ConfigKey<>("Advanced", Boolean.class,
+            "validate.url.is.resolvable.before.registering.template", "true", 
"Indicates whether CloudStack "
+            + "will validate if the provided URL is resolvable during the 
register of templates/ISOs before persisting them in the database.",
+            true);
+
     static final String VMWARE_TOOLS_ISO = "vmware-tools.iso";
     static final String XS_TOOLS_ISO = "xs-tools.iso";
 
@@ -139,4 +144,8 @@ public interface TemplateManager {
     TemplateType validateTemplateType(BaseCmd cmd, boolean isAdmin, boolean 
isCrossZones);
 
     List<DatadiskTO> getTemplateDisksOnImageStore(Long templateId, 
DataStoreRole role, String configurationId);
+
+    static Boolean getValidateUrlIsResolvableBeforeRegisteringTemplateValue() {
+        return ValidateUrlIsResolvableBeforeRegisteringTemplate.value();
+    }
 }
diff --git 
a/server/src/main/java/com/cloud/template/HypervisorTemplateAdapter.java 
b/server/src/main/java/com/cloud/template/HypervisorTemplateAdapter.java
index b7a511aad36..026a9350f33 100644
--- a/server/src/main/java/com/cloud/template/HypervisorTemplateAdapter.java
+++ b/server/src/main/java/com/cloud/template/HypervisorTemplateAdapter.java
@@ -204,7 +204,7 @@ public class HypervisorTemplateAdapter extends 
TemplateAdapterBase {
     public TemplateProfile prepare(RegisterIsoCmd cmd) throws 
ResourceAllocationException {
         TemplateProfile profile = super.prepare(cmd);
         String url = profile.getUrl();
-        UriUtils.validateUrl(ImageFormat.ISO.getFileExtension(), url);
+        UriUtils.validateUrl(ImageFormat.ISO.getFileExtension(), url, 
!TemplateManager.getValidateUrlIsResolvableBeforeRegisteringTemplateValue(), 
false);
         boolean followRedirects = 
StorageManager.DataStoreDownloadFollowRedirects.value();
         if (cmd.isDirectDownload()) {
             DigestHelper.validateChecksumString(cmd.getChecksum());
@@ -238,7 +238,7 @@ public class HypervisorTemplateAdapter extends 
TemplateAdapterBase {
     public TemplateProfile prepare(RegisterTemplateCmd cmd) throws 
ResourceAllocationException {
         TemplateProfile profile = super.prepare(cmd);
         String url = profile.getUrl();
-        UriUtils.validateUrl(cmd.getFormat(), url, cmd.isDirectDownload());
+        UriUtils.validateUrl(cmd.getFormat(), url, 
!TemplateManager.getValidateUrlIsResolvableBeforeRegisteringTemplateValue(), 
cmd.isDirectDownload());
         Hypervisor.HypervisorType hypervisor = 
Hypervisor.HypervisorType.getType(cmd.getHypervisor());
         boolean followRedirects = 
StorageManager.DataStoreDownloadFollowRedirects.value();
         if (cmd.isDirectDownload()) {
diff --git a/server/src/main/java/com/cloud/template/TemplateManagerImpl.java 
b/server/src/main/java/com/cloud/template/TemplateManagerImpl.java
index 4d095d09cc6..af558304981 100755
--- a/server/src/main/java/com/cloud/template/TemplateManagerImpl.java
+++ b/server/src/main/java/com/cloud/template/TemplateManagerImpl.java
@@ -2349,7 +2349,7 @@ public class TemplateManagerImpl extends ManagerBase 
implements TemplateManager,
 
     @Override
     public ConfigKey<?>[] getConfigKeys() {
-        return new ConfigKey<?>[] {AllowPublicUserTemplates, 
TemplatePreloaderPoolSize};
+        return new ConfigKey<?>[] {AllowPublicUserTemplates, 
TemplatePreloaderPoolSize, ValidateUrlIsResolvableBeforeRegisteringTemplate};
     }
 
     public List<TemplateAdapter> getTemplateAdapters() {
diff --git a/utils/src/main/java/com/cloud/utils/UriUtils.java 
b/utils/src/main/java/com/cloud/utils/UriUtils.java
index e1766e691c2..4964215020d 100644
--- a/utils/src/main/java/com/cloud/utils/UriUtils.java
+++ b/utils/src/main/java/com/cloud/utils/UriUtils.java
@@ -263,10 +263,17 @@ public class UriUtils {
     }
 
     public static Pair<String, Integer> validateUrl(String format, String url) 
throws IllegalArgumentException {
-        return validateUrl(format, url, false);
+        return validateUrl(format, url, false, false);
     }
 
-    public static Pair<String, Integer> validateUrl(String format, String url, 
boolean skipIpv6Check) throws IllegalArgumentException {
+    /**
+     * Verifies whether the provided URL is valid.
+     * @param skipHostCheck if false, this function will verify whether the 
provided URL is resolvable, if it is a legal address and if it does not use 
IPv6 (configured by `skipIpv6Check`). If any of these conditions are false, an 
exception will be thrown.
+     * @param skipIpv6Check if false, this function will verify whether the 
host uses IPv6 and, if it does, an exception will be thrown. This check is also 
skipped if `skipHostCheck` is true.
+     * @return a pair containing the host and the corresponding port.
+     * @throws IllegalArgumentException if the provided URL is invalid.
+     */
+    public static Pair<String, Integer> validateUrl(String format, String url, 
boolean skipHostCheck, boolean skipIpv6Check) throws IllegalArgumentException {
         try {
             URI uri = new URI(url);
             if ((uri.getScheme() == null) ||
@@ -282,16 +289,8 @@ public class UriUtils {
             }
 
             String host = uri.getHost();
-            try {
-                InetAddress hostAddr = InetAddress.getByName(host);
-                if (hostAddr.isAnyLocalAddress() || 
hostAddr.isLinkLocalAddress() || hostAddr.isLoopbackAddress() || 
hostAddr.isMulticastAddress()) {
-                    throw new IllegalArgumentException("Illegal host specified 
in url");
-                }
-                if (!skipIpv6Check && hostAddr instanceof Inet6Address) {
-                    throw new IllegalArgumentException("IPV6 addresses not 
supported (" + hostAddr.getHostAddress() + ")");
-                }
-            } catch (UnknownHostException uhe) {
-                throw new IllegalArgumentException("Unable to resolve " + 
host);
+            if (!skipHostCheck) {
+                checkHost(host, skipIpv6Check);
             }
 
             // verify format
@@ -305,6 +304,28 @@ public class UriUtils {
         }
     }
 
+    /**
+     * Verifies whether the provided host is valid. Throws an 
`IllegalArgumentException` if:
+     * <ul>
+     *     <li>The host is not resolvable;</li>
+     *     <li>The host address is illegal (any local, link local, loopback or 
multicast address);</li>
+     *     <li>The host uses IPv6. This check is skipped if `skipIv6Check` is 
set to true.</li>
+     * </ul>
+     */
+    private static void checkHost(String host, boolean skipIpv6Check) {
+        try {
+            InetAddress hostAddr = InetAddress.getByName(host);
+            if (hostAddr.isAnyLocalAddress() || hostAddr.isLinkLocalAddress() 
|| hostAddr.isLoopbackAddress() || hostAddr.isMulticastAddress()) {
+                throw new IllegalArgumentException("Illegal host specified in 
URL.");
+            }
+            if (!skipIpv6Check && hostAddr instanceof Inet6Address) {
+                throw new IllegalArgumentException(String.format("IPv6 
addresses are not supported (%s).", hostAddr.getHostAddress()));
+            }
+        } catch (UnknownHostException uhe) {
+            throw new IllegalArgumentException(String.format("Unable to 
resolve %s.", host));
+        }
+    }
+
     /**
      * Add element to priority list examining node attributes: priority (for 
urls) and type (for checksums)
      */

Reply via email to