Skip to content

Commit

Permalink
Merge pull request #1123 from michalvavrik/feature/main-fix-pem-cert-…
Browse files Browse the repository at this point in the history
…mounting

Fix PEM certificate generation and mounting in OpenShift
  • Loading branch information
mjurc authored May 10, 2024
2 parents f230a22 + 12b08e4 commit 4001100
Show file tree
Hide file tree
Showing 7 changed files with 64 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,11 @@ private ServiceContext registerWithSanitizedServiceName(ScenarioContext context,
} else {
this.configuration = Configuration.load(serviceName, originalServiceName);
}

this.context = new ServiceContext(this, context);
onPreStart(s -> properties.putAll(this.context.getConfigPropertiesWithTestScope()));
onPreStop(s -> this.context.getConfigPropertiesWithTestScope().forEach((k, v) -> properties.remove(k)));

onPreStart(s -> futureProperties.forEach(Runnable::run));
context.getTestStore().put(serviceName, this);
return this.context;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,17 @@ public final class ServiceContext {
private final Path serviceFolder;
private final Map<String, Object> store = new HashMap<>();

/**
* Whatever we put into {@link Service#withProperty(String, String)} is stored inside static field instance.
* Like 'static RestService app = new RestService()'.
* If a couple of test classes has same superclass and the 'app' field is in that superclass, properties are shared.
* That is if during the execution of the first test class you put there dynamically property "a",
* the "a" property will be there when the next test class is executed.
*
* This field stores properties that has only a test class scope.
*/
private final Map<String, String> configPropertiesWithTestScope = new HashMap<>();

ServiceContext(Service owner, ScenarioContext scenarioContext) {
this.owner = owner;
this.scenarioContext = scenarioContext;
Expand Down Expand Up @@ -54,6 +65,15 @@ public <T> T get(String key) {
return (T) store.get(key);
}

public ServiceContext withTestScopeConfigProperty(String key, String value) {
configPropertiesWithTestScope.put(key, value);
return this;
}

Map<String, String> getConfigPropertiesWithTestScope() {
return configPropertiesWithTestScope;
}

private String getArtifactIdFromGav(String gav) {
String artifactId = gav;
int firstPos = gav.indexOf(":");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@

public interface Certificate {

String prefix();

String format();

String password();
Expand All @@ -50,16 +52,27 @@ public interface Certificate {

Collection<ClientCertificate> clientCertificates();

interface PemCertificate extends Certificate {

String keyPath();

String certPath();

}

static Certificate of(String prefix, io.quarkus.test.services.Certificate.Format format, String password) {
return of(prefix, format, password, false, false, false, new io.quarkus.test.services.Certificate.ClientCertificate[0]);
}

static Certificate of(String prefix, io.quarkus.test.services.Certificate.Format format, String password,
boolean keystoreProps, boolean truststoreProps, boolean keystoreManagementInterfaceProps,
io.quarkus.test.services.Certificate.ClientCertificate[] clientCertificates) {
Map<String, String> props = new HashMap<>();
CertificateGenerator generator = new CertificateGenerator(createCertsTempDir(prefix), false);
String serverTrustStoreLocation = null;
String serverKeyStoreLocation = null;
String keyLocation = null;
String certLocation = null;
List<ClientCertificate> generatedClientCerts = new ArrayList<>();
String[] cnAttrs = collectCommonNames(clientCertificates);
var unknownClientCn = getUnknownClientCnAttr(clientCertificates, cnAttrs);
Expand All @@ -81,7 +94,21 @@ static Certificate of(String prefix, io.quarkus.test.services.Certificate.Format
serverTrustStoreLocation = getPathOrNull(pkcs12CertFile.trustStoreFile());
}
} else if (certFile instanceof PemCertificateFiles pemCertsFile) {
serverTrustStoreLocation = getPathOrNull(pemCertsFile.serverTrustFile());
keyLocation = getPathOrNull(pemCertsFile.keyFile());
certLocation = getPathOrNull(pemCertsFile.certFile());
if (isOpenshiftPlatform() || isKubernetesPlatform()) {
if (certLocation != null) {
certLocation = makeFileMountPathUnique(prefix, certLocation);
// mount certificate to the pod
props.put(getRandomPropKey("crt"), toSecretProperty(certLocation));
}

if (keyLocation != null) {
keyLocation = makeFileMountPathUnique(prefix, keyLocation);
// mount private key to the pod
props.put(getRandomPropKey("key"), toSecretProperty(keyLocation));
}
}
} else if (certFile instanceof JksCertificateFiles jksCertFile) {
serverKeyStoreLocation = getPathOrNull(jksCertFile.keyStoreFile());
if (withClientCerts) {
Expand Down Expand Up @@ -122,7 +149,6 @@ static Certificate of(String prefix, io.quarkus.test.services.Certificate.Format
}

// 3. PREPARE QUARKUS APPLICATION CONFIGURATION PROPERTIES
Map<String, String> props = new HashMap<>();
if (serverTrustStoreLocation != null) {
if (isOpenshiftPlatform() || isKubernetesPlatform()) {
// mount truststore to the pod
Expand Down Expand Up @@ -153,7 +179,7 @@ static Certificate of(String prefix, io.quarkus.test.services.Certificate.Format
}

return new CertificateImpl(serverKeyStoreLocation, serverTrustStoreLocation, Map.copyOf(props),
List.copyOf(generatedClientCerts), password, format.toString());
List.copyOf(generatedClientCerts), password, format.toString(), keyLocation, certLocation, prefix);
}

private static String getUnknownClientCnAttr(io.quarkus.test.services.Certificate.ClientCertificate[] clientCertificates,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ public interface CertificateBuilder {

List<Certificate> certificates();

Certificate findCertificateByPrefix(String prefix);

static CertificateBuilder of(io.quarkus.test.services.Certificate[] certificates) {
if (certificates == null || certificates.length == 0) {
return null;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
package io.quarkus.test.security.certificate;

import java.util.List;
import java.util.Objects;

record CertificateBuilderImp(List<Certificate> certificates) implements CertificateBuilder {
@Override
public Certificate findCertificateByPrefix(String prefix) {
Objects.requireNonNull(prefix);
return certificates.stream().filter(c -> prefix.equals(c.prefix())).findFirst().orElse(null);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
import java.util.Objects;

record CertificateImpl(String keystorePath, String truststorePath, Map<String, String> configProperties,
Collection<ClientCertificate> clientCertificates, String password, String format) implements Certificate {
Collection<ClientCertificate> clientCertificates, String password, String format, String keyPath, String certPath,
String prefix) implements Certificate.PemCertificate {

@Override
public ClientCertificate getClientCertificateByCn(String cn) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ protected void configureCertificates() {
.certificates()
.forEach(certificate -> certificate
.configProperties()
.forEach((k, v) -> context.getOwner().withProperty(k, v)));
.forEach((k, v) -> getContext().withTestScopeConfigProperty(k, v)));
}
}

Expand Down

0 comments on commit 4001100

Please sign in to comment.