Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding test coverage to support encrypted PEM Keys #1508

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package io.quarkus.qe;

import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.cert.CertificateParsingException;
import java.security.cert.X509Certificate;

import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;

import io.quarkus.tls.TlsConfiguration;
import io.quarkus.tls.TlsConfigurationRegistry;

@Path("/tls-registry")
public class TlsRegistryResource {

private static final String CERT_EXAMPLE = "dummy-entry-0";

@Inject
TlsConfigurationRegistry tlsConfigurationRegistry;

@GET
@Produces(MediaType.TEXT_PLAIN)
public String tlsRegistryInspection() throws KeyStoreException, CertificateParsingException {
TlsConfiguration tlsConfiguration = tlsConfigurationRegistry.getDefault().orElseThrow();

KeyStore keyStore = tlsConfiguration.getKeyStore();
if (keyStore == null) {
return "No KeyStore found in default TLS configuration.";
}
X509Certificate x509Certificate = (X509Certificate) keyStore.getCertificate(CERT_EXAMPLE);
if (x509Certificate == null) {
return "No certificate found with alias " + CERT_EXAMPLE;
}
return "Subject X500 : " + x509Certificate.getSubjectX500Principal().getName()
+ "\nSubject Alternative names (SANs) : " + x509Certificate.getSubjectAlternativeNames();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package io.quarkus.qe;

import static io.quarkus.qe.HttpsTlsRegistryNamedConfigIT.CLIENT_CN_1;
import static org.junit.jupiter.api.Assertions.assertEquals;

import org.apache.http.HttpStatus;
import org.junit.jupiter.api.Test;

import io.quarkus.test.bootstrap.RestService;
import io.quarkus.test.scenarios.QuarkusScenario;
import io.quarkus.test.security.certificate.CertificateBuilder;
import io.quarkus.test.security.certificate.ClientCertificateRequest;
import io.quarkus.test.services.Certificate;
import io.quarkus.test.services.QuarkusApplication;
import io.quarkus.test.utils.AwaitilityUtils;

@QuarkusScenario
public class HttpsEncryptedPEMCertificateReloadingIT {

private static final String NEW_CLIENT_CN = "my-new-client";
private static final String CERT_PREFIX = "reload-cert";

@QuarkusApplication(ssl = true, certificates = @Certificate(clientCertificates = {
@Certificate.ClientCertificate(cnAttribute = CLIENT_CN_1)
}, configureTruststore = true, configureHttpServer = true, configureKeystore = true, prefix = CERT_PREFIX, format = Certificate.Format.ENCRYPTED_PEM))
static final RestService app = new RestService()
.withProperty("quarkus.http.ssl.client-auth", "request")
.withProperty("quarkus.http.insecure-requests", "DISABLED")
.withProperty("quarkus.tls.reload-period", "2s");

@Test
public void encryptedPEMCertificateReloadingTest() {
var path = "/greeting/mutual-tls";
var response = app.mutinyHttps(CLIENT_CN_1).get(path).sendAndAwait();
assertEquals(HttpStatus.SC_OK, response.statusCode());
assertEquals("Hello CN=%s!".formatted(CLIENT_CN_1), response.bodyAsString());

var clientReq = new ClientCertificateRequest(NEW_CLIENT_CN, false);
app
.<CertificateBuilder> getPropertyFromContext(CertificateBuilder.INSTANCE_KEY)
.regenerateCertificate(CERT_PREFIX, certReq -> certReq.withClientRequests(clientReq));

AwaitilityUtils.untilAsserted(() -> {
var response1 = app.mutinyHttps(NEW_CLIENT_CN).get(path).sendAndAwait();
assertEquals(HttpStatus.SC_OK, response1.statusCode());
assertEquals("Hello CN=%s!".formatted(NEW_CLIENT_CN), response1.bodyAsString());
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package io.quarkus.qe;

import static org.junit.jupiter.api.Assertions.assertEquals;

import org.apache.http.HttpStatus;
import org.junit.jupiter.api.Test;

import io.quarkus.test.bootstrap.RestService;
import io.quarkus.test.scenarios.QuarkusScenario;
import io.quarkus.test.services.Certificate;
import io.quarkus.test.services.QuarkusApplication;

@QuarkusScenario
public class HttpsEncryptedPemIT {

private static final String DUMMY_CLIENT_CN_1 = "my-dummy--1";
@QuarkusApplication(ssl = true, certificates = @Certificate(format = Certificate.Format.ENCRYPTED_PEM, configureHttpServer = true, clientCertificates = {
@Certificate.ClientCertificate(cnAttribute = DUMMY_CLIENT_CN_1)
}))
static final RestService app = new RestService()
.withProperty("quarkus.http.insecure-requests", "disabled")
.withProperty("quarkus.http.ssl.client-auth", "none");

@Test
public void testSimpleHttpsCommunication() {
var response = app.mutinyHttps(DUMMY_CLIENT_CN_1).get("/greeting").sendAndAwait();
assertEquals(HttpStatus.SC_OK, response.statusCode());
assertEquals("Hello World!", response.bodyAsString(),
"Response is not the expected on that endpoint");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package io.quarkus.qe;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

import org.apache.http.HttpStatus;
import org.junit.jupiter.api.Test;

import io.quarkus.test.bootstrap.RestService;
import io.quarkus.test.scenarios.QuarkusScenario;
import io.quarkus.test.services.Certificate;
import io.quarkus.test.services.QuarkusApplication;

@QuarkusScenario
public class TlsRegistryDecryptedKeyIT {
private static final String CERT_EXAMPLE = "dummy-entry-0";

@QuarkusApplication(ssl = true, certificates = @Certificate(format = Certificate.Format.ENCRYPTED_PEM, configureHttpServer = true, clientCertificates = @Certificate.ClientCertificate(cnAttribute = CERT_EXAMPLE)))
static final RestService app = new RestService()
.withProperty("quarkus.http.insecure-requests", "disabled")
.withProperty("quarkus.http.ssl.client-auth", "none");

@Test
public void testInspectDecryptedKey() {
var response = app.mutinyHttps(CERT_EXAMPLE).get("/tls-registry").sendAndAwait();
assertEquals(HttpStatus.SC_OK, response.statusCode(), "Expected 200 but got: "
+ response.statusCode());

String body = response.bodyAsString();
assertTrue(body.contains("Subject X500 : CN=dummy-entry-0"),
"Response from /tls-inspection does not contain subject info: " + body);
assertTrue(body.contains("localhost") || body.contains(" [[2, localhost], [2, 0.0.0.0]]"),
"Response from /tls-inspection does not mention Subject Alternative names (SANs) : localhost or [[2, localhost], [2, 0.0.0.0]]");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,9 @@ private static Certificate.PemCertificate of(CertificateOptions o) {
boolean withClientCerts = cnAttrs.length > 0;
String cn = withClientCerts ? cnAttrs[0] : "localhost";
final CertificateRequest request = createCertificateRequest(o.prefix(), o.format(), o.password(), withClientCerts, cn);
if (o.format() == ENCRYPTED_PEM && !withClientCerts) {
throw new RuntimeException("You configured ENCRYPTED_PEM but didn't provide any client certificates. ");
}
try {
var certFile = generator.generate(request).get(0);
if (certFile instanceof Pkcs12CertificateFiles pkcs12CertFile) {
Expand Down
Loading