NoSuchFileException with ${kc.home.dir} on Windows (#24080)
* NoSuchFileException with ${kc.home.dir} on Windows * added a path validation for https cert and key files in HttpPropertyMappers Closes #23217 Signed-off-by: Peter Zaoral <pzaoral@redhat.com> * NoSuchFileException with ${kc.home.dir} on Windows * added a path validation for https cert and key files in HttpPropertyMappers Closes #23217 Signed-off-by: Peter Zaoral <pzaoral@redhat.com> * NoSuchFileException with ${kc.home.dir} on Windows * added a path validation for https cert and key files in HttpPropertyMappers Closes #23217 Signed-off-by: Peter Zaoral <pzaoral@redhat.com> --------- Signed-off-by: Peter Zaoral <pzaoral@redhat.com>
This commit is contained in:
parent
d79e414199
commit
386e4ea8d4
3 changed files with 55 additions and 11 deletions
|
@ -59,12 +59,12 @@ public class HttpOptions {
|
|||
.defaultValue("TLSv1.3,TLSv1.2")
|
||||
.build();
|
||||
|
||||
public static final Option HTTPS_CERTIFICATE_FILE = new OptionBuilder<>("https-certificate-file", File.class)
|
||||
public static final Option<File> HTTPS_CERTIFICATE_FILE = new OptionBuilder<>("https-certificate-file", File.class)
|
||||
.category(OptionCategory.HTTP)
|
||||
.description("The file path to a server certificate or certificate chain in PEM format.")
|
||||
.build();
|
||||
|
||||
public static final Option HTTPS_CERTIFICATE_KEY_FILE = new OptionBuilder<>("https-certificate-key-file", File.class)
|
||||
public static final Option<File> HTTPS_CERTIFICATE_KEY_FILE = new OptionBuilder<>("https-certificate-key-file", File.class)
|
||||
.category(OptionCategory.HTTP)
|
||||
.description("The file path to a private key in PEM format.")
|
||||
.build();
|
||||
|
|
|
@ -13,6 +13,7 @@ import org.keycloak.quarkus.runtime.configuration.MicroProfileConfigProvider;
|
|||
import java.io.File;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Optional;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
import static java.util.Optional.empty;
|
||||
import static java.util.Optional.of;
|
||||
|
@ -21,6 +22,8 @@ import static org.keycloak.quarkus.runtime.configuration.mappers.PropertyMappers
|
|||
import static org.keycloak.quarkus.runtime.integration.QuarkusPlatform.addInitializationException;
|
||||
|
||||
final class HttpPropertyMappers {
|
||||
private static final String QUARKUS_HTTPS_CERT_FILES = "quarkus.http.ssl.certificate.files";
|
||||
private static final String QUARKUS_HTTPS_CERT_KEY_FILES = "quarkus.http.ssl.certificate.key-files";
|
||||
|
||||
private HttpPropertyMappers(){}
|
||||
|
||||
|
@ -64,15 +67,17 @@ final class HttpPropertyMappers {
|
|||
.paramLabel("protocols")
|
||||
.build(),
|
||||
fromOption(HttpOptions.HTTPS_CERTIFICATE_FILE)
|
||||
.to("quarkus.http.ssl.certificate.files")
|
||||
.to(QUARKUS_HTTPS_CERT_FILES)
|
||||
.transformer(HttpPropertyMappers.validatePath(QUARKUS_HTTPS_CERT_FILES))
|
||||
.paramLabel("file")
|
||||
.build(),
|
||||
fromOption(HttpOptions.HTTPS_CERTIFICATE_KEY_FILE)
|
||||
.to("quarkus.http.ssl.certificate.key-files")
|
||||
.to(QUARKUS_HTTPS_CERT_KEY_FILES)
|
||||
.transformer(HttpPropertyMappers.validatePath(QUARKUS_HTTPS_CERT_KEY_FILES))
|
||||
.paramLabel("file")
|
||||
.build(),
|
||||
fromOption(HttpOptions.HTTPS_KEY_STORE_FILE
|
||||
.withRuntimeSpecificDefault(getDefaultKeystorePathValue()))
|
||||
.withRuntimeSpecificDefault(getDefaultKeystorePathValue()))
|
||||
.to("quarkus.http.ssl.certificate.key-store-file")
|
||||
.paramLabel("file")
|
||||
.build(),
|
||||
|
@ -109,6 +114,10 @@ final class HttpPropertyMappers {
|
|||
};
|
||||
}
|
||||
|
||||
private static BiFunction<Optional<String>, ConfigSourceInterceptorContext, Optional<String>> validatePath(String key) {
|
||||
return (value, context) -> Environment.isWindows() ? value.filter(v -> v.equals(context.proceed(key).getValue())).map(p -> p.replace("\\", "/")) : value;
|
||||
}
|
||||
|
||||
private static Optional<String> getHttpEnabledTransformer(Optional<String> value, ConfigSourceInterceptorContext context) {
|
||||
boolean enabled = Boolean.parseBoolean(value.get());
|
||||
ConfigValue proxy = context.proceed(MicroProfileConfigProvider.NS_KEYCLOAK_PREFIX + "proxy");
|
||||
|
|
|
@ -28,6 +28,8 @@ import org.junit.jupiter.api.MethodOrderer.OrderAnnotation;
|
|||
import org.junit.jupiter.api.Order;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.TestMethodOrder;
|
||||
import org.junit.jupiter.api.condition.DisabledOnOs;
|
||||
import org.junit.jupiter.api.condition.OS;
|
||||
import org.keycloak.it.junit5.extension.BeforeStartDistribution;
|
||||
import org.keycloak.it.junit5.extension.CLIResult;
|
||||
import org.keycloak.it.junit5.extension.DistributionTest;
|
||||
|
@ -105,7 +107,7 @@ public class QuarkusPropertiesDistTest {
|
|||
@Test
|
||||
@BeforeStartDistribution(UpdateHibernateMetricsFromQuarkusProps.class)
|
||||
@Launch({ "build", "--metrics-enabled=true" })
|
||||
@Order(8)
|
||||
@Order(7)
|
||||
void buildFirstWithUnknownQuarkusBuildProperty(LaunchResult result) {
|
||||
CLIResult cliResult = (CLIResult) result;
|
||||
cliResult.assertBuild();
|
||||
|
@ -114,7 +116,7 @@ public class QuarkusPropertiesDistTest {
|
|||
@Test
|
||||
@KeepServerAlive
|
||||
@Launch({ "start", "--http-enabled=true", "--hostname-strict=false", OPTIMIZED_BUILD_OPTION_LONG})
|
||||
@Order(9)
|
||||
@Order(8)
|
||||
void testUnknownQuarkusBuildTimePropertyApplied(LaunchResult result) {
|
||||
CLIResult cliResult = (CLIResult) result;
|
||||
cliResult.assertNoBuild();
|
||||
|
@ -124,7 +126,7 @@ public class QuarkusPropertiesDistTest {
|
|||
|
||||
@Test
|
||||
@Launch({ "start", "--http-enabled=true", "--hostname-strict=false", "--config-keystore=../../../../src/test/resources/keystore" })
|
||||
@Order(10)
|
||||
@Order(9)
|
||||
void testMissingSmallRyeKeyStorePasswordProperty(LaunchResult result) {
|
||||
CLIResult cliResult = (CLIResult) result;
|
||||
cliResult.assertError("config-keystore-password must be specified");
|
||||
|
@ -133,7 +135,7 @@ public class QuarkusPropertiesDistTest {
|
|||
|
||||
@Test
|
||||
@Launch({ "start", "--http-enabled=true", "--hostname-strict=false", "--config-keystore-password=secret" })
|
||||
@Order(11)
|
||||
@Order(10)
|
||||
void testMissingSmallRyeKeyStorePathProperty(LaunchResult result) {
|
||||
CLIResult cliResult = (CLIResult) result;
|
||||
cliResult.assertError("config-keystore must be specified");
|
||||
|
@ -143,7 +145,7 @@ public class QuarkusPropertiesDistTest {
|
|||
@Test
|
||||
@Launch({ "start", "--http-enabled=true", "--hostname-strict=false", "--config-keystore=/invalid/path",
|
||||
"--config-keystore-password=secret" })
|
||||
@Order(12)
|
||||
@Order(11)
|
||||
void testInvalidSmallRyeKeyStorePathProperty(LaunchResult result) {
|
||||
CLIResult cliResult = (CLIResult) result;
|
||||
cliResult.assertError("java.lang.IllegalArgumentException: config-keystore path does not exist: /invalid/path");
|
||||
|
@ -153,7 +155,7 @@ public class QuarkusPropertiesDistTest {
|
|||
@Test
|
||||
@Launch({ "start", "--http-enabled=true", "--hostname-strict=false",
|
||||
"--config-keystore=../../../../src/test/resources/keystore", "--config-keystore-password=secret" })
|
||||
@Order(13)
|
||||
@Order(12)
|
||||
void testSmallRyeKeyStoreConfigSource(LaunchResult result) {
|
||||
// keytool -importpass -alias kc.log-level -keystore keystore -storepass secret -storetype PKCS12 -v (with "debug" as the stored password)
|
||||
CLIResult cliResult = (CLIResult) result;
|
||||
|
@ -161,6 +163,30 @@ public class QuarkusPropertiesDistTest {
|
|||
cliResult.assertBuild();
|
||||
}
|
||||
|
||||
@Test
|
||||
@BeforeStartDistribution(ForceRebuild.class)
|
||||
@DisabledOnOs(value = { OS.WINDOWS }, disabledReason = "Windows uses a different path separator.")
|
||||
@Launch({ "start", "--http-enabled=true", "--hostname-strict=false",
|
||||
"--https-certificate-file=/tmp/kc/bin/../conf/server.crt.pem",
|
||||
"--https-certificate-key-file=/tmp/kc/bin/../conf/server.key.pem" })
|
||||
@Order(13)
|
||||
void testHttpCertsPathTransformer(LaunchResult result) {
|
||||
CLIResult cliResult = (CLIResult) result;
|
||||
assertTrue(cliResult.getOutput().contains("ERROR: /tmp/kc/bin/../conf/server.crt.pem"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@BeforeStartDistribution(ForceRebuild.class)
|
||||
@DisabledOnOs(value = { OS.LINUX, OS.MAC }, disabledReason = "Windows uses a different path separator.")
|
||||
@Launch({ "start", "--http-enabled=true", "--hostname-strict=false",
|
||||
"--https-certificate-file=C:\\tmp\\kc\\bin\\..\\conf/server.crt.pem",
|
||||
"--https-certificate-key-file=C:\\tmp\\kc\\bin\\..\\conf/server.key.pem" })
|
||||
@Order(14)
|
||||
void testHttpCertsPathTransformerOnWindows(LaunchResult result) {
|
||||
CLIResult cliResult = (CLIResult) result;
|
||||
assertTrue(cliResult.getOutput().contains("ERROR: C:/tmp/kc/bin/../conf/server.crt.pem"));
|
||||
}
|
||||
|
||||
public static class UpdateConsoleLogLevelToWarnFromQuarkusProps implements Consumer<KeycloakDistribution> {
|
||||
@Override
|
||||
public void accept(KeycloakDistribution distribution) {
|
||||
|
@ -194,4 +220,13 @@ public class QuarkusPropertiesDistTest {
|
|||
distribution.setQuarkusProperty(QUARKUS_BUILDTIME_HIBERNATE_METRICS_KEY, "true");
|
||||
}
|
||||
}
|
||||
|
||||
public static class ForceRebuild implements Consumer<KeycloakDistribution> {
|
||||
|
||||
@Override
|
||||
public void accept(KeycloakDistribution distribution) {
|
||||
CLIResult buildResult = distribution.run("build");
|
||||
buildResult.assertBuild();
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue