-
Notifications
You must be signed in to change notification settings - Fork 28
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Support certs generation when SSL enabled to fix FIPS scenarios
- Loading branch information
1 parent
d4ebef6
commit 7cf11c2
Showing
19 changed files
with
289 additions
and
54 deletions.
There are no files selected for viewing
Binary file removed
BIN
-2.35 KB
examples/https/src/main/resources/META-INF/resources/server.keystore
Binary file not shown.
Binary file removed
BIN
-2.35 KB
examples/https/src/main/resources/META-INF/resources/server.truststore
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,2 @@ | ||
# HTTPS | ||
quarkus.http.ssl.certificate.key-store-file=META-INF/resources/server.keystore | ||
quarkus.http.ssl.certificate.key-store-file-type=JKS | ||
quarkus.http.ssl.certificate.key-store-password=password | ||
quarkus.ssl.native=true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 0 additions & 2 deletions
2
examples/https/src/test/resources/windows.application.properties
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
162 changes: 162 additions & 0 deletions
162
quarkus-test-core/src/main/java/io/quarkus/test/security/certificate/CertificateBuilder.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
package io.quarkus.test.security.certificate; | ||
|
||
import static io.quarkus.test.utils.PropertiesUtils.DESTINATION_TO_FILENAME_SEPARATOR; | ||
import static io.quarkus.test.utils.PropertiesUtils.SECRET_WITH_DESTINATION_PREFIX; | ||
import static io.quarkus.test.utils.TestExecutionProperties.isKubernetesPlatform; | ||
import static io.quarkus.test.utils.TestExecutionProperties.isOpenshiftPlatform; | ||
|
||
import java.io.File; | ||
import java.io.IOException; | ||
import java.nio.file.Files; | ||
import java.nio.file.Path; | ||
import java.time.Duration; | ||
import java.util.HashMap; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.Random; | ||
|
||
import io.quarkus.test.services.Certificate.Format; | ||
import io.quarkus.test.utils.FileUtils; | ||
import me.escoffier.certs.CertificateGenerator; | ||
import me.escoffier.certs.CertificateRequest; | ||
import me.escoffier.certs.JksCertificateFiles; | ||
import me.escoffier.certs.PemCertificateFiles; | ||
import me.escoffier.certs.Pkcs12CertificateFiles; | ||
|
||
public interface CertificateBuilder { | ||
|
||
/** | ||
* Test context instance key. | ||
*/ | ||
String INSTANCE_KEY = "io.quarkus.test.security.certificate#INSTANCE"; | ||
|
||
List<Certificate> certificates(); | ||
|
||
interface Certificate { | ||
|
||
String keystorePath(); | ||
|
||
String truststorePath(); | ||
|
||
Map<String, String> configProperties(); | ||
|
||
} | ||
|
||
static CertificateBuilder of(io.quarkus.test.services.Certificate[] certificates) { | ||
if (certificates == null || certificates.length == 0) { | ||
return null; | ||
} | ||
return createBuilder(certificates); | ||
} | ||
|
||
static Certificate of(String prefix, Format format, String password) { | ||
return of(prefix, format, password, false, false); | ||
} | ||
|
||
private static Certificate of(String prefix, Format format, String password, boolean keystoreProps, | ||
boolean truststoreProps) { | ||
Path certsDir = createCertsTempDir(prefix); | ||
CertificateGenerator generator = new CertificateGenerator(certsDir, true); | ||
CertificateRequest request = (new CertificateRequest()).withName(prefix) | ||
.withClientCertificate(false) | ||
.withFormat(me.escoffier.certs.Format.valueOf(format.toString())) | ||
.withCN("localhost") | ||
.withPassword(password) | ||
.withDuration(Duration.ofDays(2)); | ||
String trustStoreLocation = null; | ||
String keyStoreLocation = null; | ||
try { | ||
var certFile = generator.generate(request).get(0); | ||
if (certFile instanceof Pkcs12CertificateFiles pkcs12CertFile) { | ||
if (pkcs12CertFile.trustStoreFile() != null) { | ||
trustStoreLocation = pkcs12CertFile.trustStoreFile().toAbsolutePath().toString(); | ||
} | ||
if (pkcs12CertFile.keyStoreFile() != null) { | ||
keyStoreLocation = pkcs12CertFile.keyStoreFile().toAbsolutePath().toString(); | ||
} | ||
} else if (certFile instanceof PemCertificateFiles pemCertsFile) { | ||
if (pemCertsFile.serverTrustFile() != null) { | ||
trustStoreLocation = pemCertsFile.serverTrustFile().toAbsolutePath().toString(); | ||
} | ||
} else if (certFile instanceof JksCertificateFiles jksCertFile) { | ||
if (jksCertFile.trustStoreFile() != null) { | ||
trustStoreLocation = jksCertFile.trustStoreFile().toAbsolutePath().toString(); | ||
} | ||
if (jksCertFile.keyStoreFile() != null) { | ||
keyStoreLocation = jksCertFile.keyStoreFile().toAbsolutePath().toString(); | ||
} | ||
} | ||
} catch (Exception e) { | ||
throw new RuntimeException("Failed to generate certificate", e); | ||
} | ||
Map<String, String> props = new HashMap<>(); | ||
if (trustStoreLocation != null) { | ||
if (isOpenshiftPlatform() || isKubernetesPlatform()) { | ||
// mount truststore to the pod | ||
props.put(getRandomPropKey("truststore"), toSecretProperty(trustStoreLocation)); | ||
} | ||
if (truststoreProps) { | ||
props.put("quarkus.http.ssl.certificate.trust-store-file", trustStoreLocation); | ||
props.put("quarkus.http.ssl.certificate.trust-store-file-type", format.toString()); | ||
props.put("quarkus.http.ssl.certificate.trust-store-password", password); | ||
} | ||
} | ||
if (keyStoreLocation != null) { | ||
if (isOpenshiftPlatform() || isKubernetesPlatform()) { | ||
keyStoreLocation = makeFileMountPathUnique(prefix, keyStoreLocation); | ||
// mount keystore to the pod | ||
props.put(getRandomPropKey("keystore"), toSecretProperty(keyStoreLocation)); | ||
} | ||
if (keystoreProps) { | ||
props.put("quarkus.http.ssl.certificate.key-store-file", keyStoreLocation); | ||
props.put("quarkus.http.ssl.certificate.key-store-file-type", format.toString()); | ||
props.put("quarkus.http.ssl.certificate.key-store-password", password); | ||
} | ||
} | ||
return new CertificateImpl(keyStoreLocation, trustStoreLocation, Map.copyOf(props)); | ||
} | ||
|
||
private static String makeFileMountPathUnique(String prefix, String storeLocation) { | ||
var newTempCertDir = createCertsTempDir(prefix); | ||
var storeFile = Path.of(storeLocation).toFile(); | ||
FileUtils.copyFileTo(storeFile, newTempCertDir); | ||
return newTempCertDir.resolve(storeFile.getName()).toAbsolutePath().toString(); | ||
} | ||
|
||
private static Path createCertsTempDir(String prefix) { | ||
Path certsDir; | ||
try { | ||
certsDir = Files.createTempDirectory(prefix + "-certs"); | ||
} catch (IOException e) { | ||
throw new RuntimeException(e); | ||
} | ||
return certsDir; | ||
} | ||
|
||
private static CertificateBuilder createBuilder(io.quarkus.test.services.Certificate[] certificates) { | ||
Certificate[] generatedCerts = new Certificate[certificates.length]; | ||
for (int i = 0; i < certificates.length; i++) { | ||
generatedCerts[i] = of(certificates[i].prefix(), certificates[i].format(), certificates[i].password(), | ||
certificates[i].configureKeystore(), certificates[i].configureTruststore()); | ||
} | ||
return new CertificateBuilderImp(List.of(generatedCerts)); | ||
} | ||
|
||
private static String getRandomPropKey(String store) { | ||
return store + "-" + new Random().nextInt(); | ||
} | ||
|
||
private static String toSecretProperty(String path) { | ||
int fileNameSeparatorIdx = path.lastIndexOf(File.separator); | ||
String fileName = path.substring(fileNameSeparatorIdx + 1); | ||
String pathToFile = path.substring(0, fileNameSeparatorIdx); | ||
return SECRET_WITH_DESTINATION_PREFIX + pathToFile + DESTINATION_TO_FILENAME_SEPARATOR + fileName; | ||
} | ||
|
||
record CertificateBuilderImp(List<Certificate> certificates) implements CertificateBuilder { | ||
} | ||
|
||
record CertificateImpl(String keystorePath, String truststorePath, | ||
Map<String, String> configProperties) implements Certificate { | ||
} | ||
} |
52 changes: 52 additions & 0 deletions
52
quarkus-test-core/src/main/java/io/quarkus/test/services/Certificate.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
package io.quarkus.test.services; | ||
|
||
/** | ||
* Defines certificate request for which this framework will generate a keystore and truststore. | ||
*/ | ||
public @interface Certificate { | ||
|
||
enum Format { | ||
PEM, | ||
JKS, | ||
PKCS12 | ||
} | ||
|
||
/** | ||
* Prefix keystore and truststore name with this attribute. | ||
*/ | ||
String prefix() default "quarkus-qe"; | ||
|
||
/** | ||
* Secure file format. | ||
*/ | ||
Format format() default Format.PKCS12; | ||
|
||
/** | ||
* Keystore and truststore password. | ||
*/ | ||
String password() default "password"; | ||
|
||
/** | ||
* Whether following configuration properties should be set for you: | ||
* | ||
* - `quarkus.http.ssl.certificate.key-store-file` | ||
* - `quarkus.http.ssl.certificate.key-store-file-type` | ||
* - `quarkus.http.ssl.certificate.key-store-password` | ||
* | ||
* You still can set and/or override these properties | ||
* with {@link io.quarkus.test.bootstrap.BaseService#withProperty(String, String)} service method. | ||
*/ | ||
boolean configureKeystore() default false; | ||
|
||
/** | ||
* Whether following configuration properties should be set for you: | ||
* | ||
* - `quarkus.http.ssl.certificate.trust-store-file` | ||
* - `quarkus.http.ssl.certificate.trust-store-file-type` | ||
* - `quarkus.http.ssl.certificate.trust-store-password` | ||
* | ||
* You still can set and/or override these properties | ||
* with {@link io.quarkus.test.bootstrap.BaseService#withProperty(String, String)} service method. | ||
*/ | ||
boolean configureTruststore() default false; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.