Skip to content

Commit

Permalink
Configuration to disable URL validation when registering templates/IS…
Browse files Browse the repository at this point in the history
…Os (#8751)
  • Loading branch information
winterhazel committed Aug 27, 2024
1 parent d32ace6 commit ede39d8
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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";

Expand Down Expand Up @@ -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();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ protected void checkZoneImageStores(final VMTemplateVO template, final List<Long
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());
Expand Down Expand Up @@ -238,7 +238,7 @@ public TemplateProfile prepare(GetUploadParamsForIsoCmd cmd) throws ResourceAllo
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()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2349,7 +2349,7 @@ public String getConfigComponentName() {

@Override
public ConfigKey<?>[] getConfigKeys() {
return new ConfigKey<?>[] {AllowPublicUserTemplates, TemplatePreloaderPoolSize};
return new ConfigKey<?>[] {AllowPublicUserTemplates, TemplatePreloaderPoolSize, ValidateUrlIsResolvableBeforeRegisteringTemplate};
}

public List<TemplateAdapter> getTemplateAdapters() {
Expand Down
45 changes: 33 additions & 12 deletions utils/src/main/java/com/cloud/utils/UriUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -263,10 +263,17 @@ public static Pair<String, Integer> validateUrl(String url) throws IllegalArgume
}

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) ||
Expand All @@ -282,16 +289,8 @@ public static Pair<String, Integer> validateUrl(String format, String url, boole
}

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
Expand All @@ -305,6 +304,28 @@ public static Pair<String, Integer> validateUrl(String format, String url, boole
}
}

/**
* 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)
*/
Expand Down

0 comments on commit ede39d8

Please sign in to comment.