Skip to content

Commit ede39d8

Browse files
authored
Configuration to disable URL validation when registering templates/ISOs (#8751)
1 parent d32ace6 commit ede39d8

4 files changed

Lines changed: 45 additions & 15 deletions

File tree

engine/components-api/src/main/java/com/cloud/template/TemplateManager.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,11 @@ public interface TemplateManager {
5151
static final ConfigKey<Integer> TemplatePreloaderPoolSize = new ConfigKey<Integer>("Advanced", Integer.class, TemplatePreloaderPoolSizeCK, "8",
5252
"Size of the TemplateManager threadpool", false, ConfigKey.Scope.Global);
5353

54+
ConfigKey<Boolean> ValidateUrlIsResolvableBeforeRegisteringTemplate = new ConfigKey<>("Advanced", Boolean.class,
55+
"validate.url.is.resolvable.before.registering.template", "true", "Indicates whether CloudStack "
56+
+ "will validate if the provided URL is resolvable during the register of templates/ISOs before persisting them in the database.",
57+
true);
58+
5459
static final String VMWARE_TOOLS_ISO = "vmware-tools.iso";
5560
static final String XS_TOOLS_ISO = "xs-tools.iso";
5661

@@ -139,4 +144,8 @@ public interface TemplateManager {
139144
TemplateType validateTemplateType(BaseCmd cmd, boolean isAdmin, boolean isCrossZones);
140145

141146
List<DatadiskTO> getTemplateDisksOnImageStore(Long templateId, DataStoreRole role, String configurationId);
147+
148+
static Boolean getValidateUrlIsResolvableBeforeRegisteringTemplateValue() {
149+
return ValidateUrlIsResolvableBeforeRegisteringTemplate.value();
150+
}
142151
}

server/src/main/java/com/cloud/template/HypervisorTemplateAdapter.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ protected void checkZoneImageStores(final VMTemplateVO template, final List<Long
204204
public TemplateProfile prepare(RegisterIsoCmd cmd) throws ResourceAllocationException {
205205
TemplateProfile profile = super.prepare(cmd);
206206
String url = profile.getUrl();
207-
UriUtils.validateUrl(ImageFormat.ISO.getFileExtension(), url);
207+
UriUtils.validateUrl(ImageFormat.ISO.getFileExtension(), url, !TemplateManager.getValidateUrlIsResolvableBeforeRegisteringTemplateValue(), false);
208208
boolean followRedirects = StorageManager.DataStoreDownloadFollowRedirects.value();
209209
if (cmd.isDirectDownload()) {
210210
DigestHelper.validateChecksumString(cmd.getChecksum());
@@ -238,7 +238,7 @@ public TemplateProfile prepare(GetUploadParamsForIsoCmd cmd) throws ResourceAllo
238238
public TemplateProfile prepare(RegisterTemplateCmd cmd) throws ResourceAllocationException {
239239
TemplateProfile profile = super.prepare(cmd);
240240
String url = profile.getUrl();
241-
UriUtils.validateUrl(cmd.getFormat(), url, cmd.isDirectDownload());
241+
UriUtils.validateUrl(cmd.getFormat(), url, !TemplateManager.getValidateUrlIsResolvableBeforeRegisteringTemplateValue(), cmd.isDirectDownload());
242242
Hypervisor.HypervisorType hypervisor = Hypervisor.HypervisorType.getType(cmd.getHypervisor());
243243
boolean followRedirects = StorageManager.DataStoreDownloadFollowRedirects.value();
244244
if (cmd.isDirectDownload()) {

server/src/main/java/com/cloud/template/TemplateManagerImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2349,7 +2349,7 @@ public String getConfigComponentName() {
23492349

23502350
@Override
23512351
public ConfigKey<?>[] getConfigKeys() {
2352-
return new ConfigKey<?>[] {AllowPublicUserTemplates, TemplatePreloaderPoolSize};
2352+
return new ConfigKey<?>[] {AllowPublicUserTemplates, TemplatePreloaderPoolSize, ValidateUrlIsResolvableBeforeRegisteringTemplate};
23532353
}
23542354

23552355
public List<TemplateAdapter> getTemplateAdapters() {

utils/src/main/java/com/cloud/utils/UriUtils.java

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -263,10 +263,17 @@ public static Pair<String, Integer> validateUrl(String url) throws IllegalArgume
263263
}
264264

265265
public static Pair<String, Integer> validateUrl(String format, String url) throws IllegalArgumentException {
266-
return validateUrl(format, url, false);
266+
return validateUrl(format, url, false, false);
267267
}
268268

269-
public static Pair<String, Integer> validateUrl(String format, String url, boolean skipIpv6Check) throws IllegalArgumentException {
269+
/**
270+
* Verifies whether the provided URL is valid.
271+
* @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.
272+
* @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.
273+
* @return a pair containing the host and the corresponding port.
274+
* @throws IllegalArgumentException if the provided URL is invalid.
275+
*/
276+
public static Pair<String, Integer> validateUrl(String format, String url, boolean skipHostCheck, boolean skipIpv6Check) throws IllegalArgumentException {
270277
try {
271278
URI uri = new URI(url);
272279
if ((uri.getScheme() == null) ||
@@ -282,16 +289,8 @@ public static Pair<String, Integer> validateUrl(String format, String url, boole
282289
}
283290

284291
String host = uri.getHost();
285-
try {
286-
InetAddress hostAddr = InetAddress.getByName(host);
287-
if (hostAddr.isAnyLocalAddress() || hostAddr.isLinkLocalAddress() || hostAddr.isLoopbackAddress() || hostAddr.isMulticastAddress()) {
288-
throw new IllegalArgumentException("Illegal host specified in url");
289-
}
290-
if (!skipIpv6Check && hostAddr instanceof Inet6Address) {
291-
throw new IllegalArgumentException("IPV6 addresses not supported (" + hostAddr.getHostAddress() + ")");
292-
}
293-
} catch (UnknownHostException uhe) {
294-
throw new IllegalArgumentException("Unable to resolve " + host);
292+
if (!skipHostCheck) {
293+
checkHost(host, skipIpv6Check);
295294
}
296295

297296
// verify format
@@ -305,6 +304,28 @@ public static Pair<String, Integer> validateUrl(String format, String url, boole
305304
}
306305
}
307306

307+
/**
308+
* Verifies whether the provided host is valid. Throws an `IllegalArgumentException` if:
309+
* <ul>
310+
* <li>The host is not resolvable;</li>
311+
* <li>The host address is illegal (any local, link local, loopback or multicast address);</li>
312+
* <li>The host uses IPv6. This check is skipped if `skipIv6Check` is set to true.</li>
313+
* </ul>
314+
*/
315+
private static void checkHost(String host, boolean skipIpv6Check) {
316+
try {
317+
InetAddress hostAddr = InetAddress.getByName(host);
318+
if (hostAddr.isAnyLocalAddress() || hostAddr.isLinkLocalAddress() || hostAddr.isLoopbackAddress() || hostAddr.isMulticastAddress()) {
319+
throw new IllegalArgumentException("Illegal host specified in URL.");
320+
}
321+
if (!skipIpv6Check && hostAddr instanceof Inet6Address) {
322+
throw new IllegalArgumentException(String.format("IPv6 addresses are not supported (%s).", hostAddr.getHostAddress()));
323+
}
324+
} catch (UnknownHostException uhe) {
325+
throw new IllegalArgumentException(String.format("Unable to resolve %s.", host));
326+
}
327+
}
328+
308329
/**
309330
* Add element to priority list examining node attributes: priority (for urls) and type (for checksums)
310331
*/

0 commit comments

Comments
 (0)