Skip to content

Commit

Permalink
Limit repository URLs to file, http, https schemas
Browse files Browse the repository at this point in the history
  • Loading branch information
TomasHofman committed Jul 26, 2024
1 parent fd6c1ac commit 01128f0
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,14 @@ default ArgumentParsingException nonExistingFilePath(Path nonExistingPath) {
return new ArgumentParsingException(format(bundle.getString("prospero.general.validation.file_path.not_exists"), nonExistingPath));
}

default ArgumentParsingException unsupportedRemoteScheme(String url) {
return new ArgumentParsingException(format(bundle.getString("prospero.general.validation.url.unsupported_remote_scheme"), url));
}

default ArgumentParsingException unsupportedScheme(String url) {
return new ArgumentParsingException(format(bundle.getString("prospero.general.validation.url.unsupported_scheme"), url));
}

default IllegalArgumentException updateCandidateStateNotMatched(Path targetDir, Path updateDir) {
return new IllegalArgumentException(format(bundle.getString("prospero.updates.apply.validation.candidate.outdated"), targetDir, updateDir));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,13 @@
import java.nio.file.InvalidPathException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class RepositoryDefinition {

private static final List<String> ALLOWED_SCHEMAS = Arrays.asList("file", "http", "https");

public static List<Repository> from(List<String> repos) throws ArgumentParsingException {
final ArrayList<Repository> repositories = new ArrayList<>(repos.size());
for (int i = 0; i < repos.size(); i++) {
Expand Down Expand Up @@ -62,8 +65,12 @@ static String parseRepositoryLocation(String location, boolean checkLocalPathExi
URI uri;
try {
uri = new URI(location);
if (("file".equals(uri.getScheme()) || StringUtils.isBlank(uri.getScheme()))
&& StringUtils.isBlank(uri.getHost())) {

if ("file".equals(uri.getScheme()) || StringUtils.isBlank(uri.getScheme())) {
if (StringUtils.isNotBlank(uri.getHost())) {
throw CliMessages.MESSAGES.unsupportedRemoteScheme(location);
}

// A "file:" URI with an empty host is assumed to be a local filesystem URL. An empty scheme would mean
// a URI that is just a path without any "proto:" part, which is still assumed a local path.
// A "file:" URI with a non-empty host would signify a remote URL, in which case we don't process it
Expand All @@ -83,6 +90,11 @@ static String parseRepositoryLocation(String location, boolean checkLocalPathExi
// Resulting URI must be convertible to URL.
//noinspection ResultOfMethodCallIgnored
uri.toURL();

// Check it is supported scheme.
if (StringUtils.isNotBlank(uri.getScheme()) && !ALLOWED_SCHEMAS.contains(uri.getScheme())) {
throw CliMessages.MESSAGES.unsupportedScheme(location);
}
} catch (URISyntaxException | MalformedURLException e) {
try {
// If the location is not a valid URI / URL, try to handle it as a path.
Expand Down
2 changes: 2 additions & 0 deletions prospero-cli/src/main/resources/UsageMessages.properties
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,8 @@ prospero.general.validation.local_repo.not_directory=Repository path `%s` is a f
prospero.general.validation.repo_format=Repository definition [%s] is invalid. The definition format should be [id::url] or [url].
prospero.general.validation.file_path.not_exists=The provided path [%s] doesn't exist or is not accessible. The local repository has to an existing, readable folder.
prospero.general.validation.file_path.invalid=The given file path [%s] is invalid.
prospero.general.validation.url.unsupported_remote_scheme=Invalid URL, only the "http" and "https" schemas are supported for remote URLs: [%s]
prospero.general.validation.url.unsupported_scheme=Invalid URL, only the "file", "http" and "https" schemas are supported: [%s]

prospero.general.error.missing_file=Required file at `%s` cannot be opened.
prospero.general.error.galleon.parse=Failed to parse provisioning configuration: %s
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import java.util.stream.Collectors;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.junit.Assert.*;
import static org.wildfly.prospero.cli.RepositoryDefinition.from;

Expand Down Expand Up @@ -191,26 +192,34 @@ public void testNormalization() throws Exception {
assertThat(RepositoryDefinition.parseRepositoryLocation("file:" + cwdPath, true)) // file:/home/...
.isEqualTo("file:" + cwdPath);

assertThat(RepositoryDefinition.parseRepositoryLocation("file://host/some/path", true))
.isEqualTo("file://host/some/path");
assertThatExceptionOfType(ArgumentParsingException.class)
.isThrownBy(() -> {
RepositoryDefinition.parseRepositoryLocation("file://host/some/path", true);
});

assertThat(RepositoryDefinition.parseRepositoryLocation("file:../prospero-cli", true))
.isEqualTo("file:" + cwdPath);

try {
RepositoryDefinition.parseRepositoryLocation("file://../prospero-cli", true); // This is interpreted as local absolute path "/../path".
fail("This path should fail because it doesn't exist.");
} catch (ArgumentParsingException e) {
// pass
}
assertThatExceptionOfType(ArgumentParsingException.class)
.isThrownBy(() -> {
RepositoryDefinition.parseRepositoryLocation("file://../prospero-cli", true); // This is interpreted as local absolute path "/../path". });
});

// On Linux following is interpreted as relative path, on Windows it's an absolute path
if (SystemUtils.IS_OS_WINDOWS) {
assertThat(RepositoryDefinition.parseRepositoryLocation("a:foo/bar", false)) // interpreted as local relative path
.isEqualTo("file:/A:/foo/bar");
assertThatExceptionOfType(ArgumentParsingException.class)
.isThrownBy(() -> {
RepositoryDefinition.parseRepositoryLocation("a:foo/bar", true); // This is interpreted as local absolute path "/../path". });
});
} else {
assertThat(RepositoryDefinition.parseRepositoryLocation("a:foo/bar", false)) // interpreted as local relative path
.isEqualTo("file:" + cwdPath + "a:foo/bar");
assertThatExceptionOfType(ArgumentParsingException.class)
.isThrownBy(() -> {
RepositoryDefinition.parseRepositoryLocation("a:foo/bar", true); // This is interpreted as local absolute path "/../path". });
});
}
}

Expand All @@ -224,8 +233,10 @@ public void testNormalizationWindowsPaths() throws Exception {
assertThat(RepositoryDefinition.parseRepositoryLocation("file:///c:/some/path", false))
.isEqualTo("file:/c:/some/path");

assertThat(RepositoryDefinition.parseRepositoryLocation("file://host/c:/some/path", false))
.isEqualTo("file://host/c:/some/path");
assertThatExceptionOfType(ArgumentParsingException.class)
.isThrownBy(() -> {
RepositoryDefinition.parseRepositoryLocation("file://host/c:/some/path", false);
});

// On Linux following is interpreted as relative path, on Windows it's an absolute path
if (SystemUtils.IS_OS_WINDOWS) {
Expand Down

0 comments on commit 01128f0

Please sign in to comment.