Skip to content

Instantly share code, notes, and snippets.

@jakzal
Created July 23, 2021 12:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jakzal/4a8e06b9ff795d619487eabe1019651b to your computer and use it in GitHub Desktop.
Save jakzal/4a8e06b9ff795d619487eabe1019651b to your computer and use it in GitHub Desktop.
JUnit extension to generate certificates
package com.kaffeinelabs.test.extension;
import org.junit.jupiter.api.extension.AfterAllCallback;
import org.junit.jupiter.api.extension.BeforeAllCallback;
import org.junit.jupiter.api.extension.ExtensionContext;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class CertificateExtension implements BeforeAllCallback, AfterAllCallback {
private static final String SCRIPT_GENERATE_CERT = "/certs/generate-cert.sh";
private final List<String> paths;
private CertificateExtension(List<String> paths) {
this.paths = paths;
}
public static CertificateExtension forCertificates(List<String> paths) {
return new CertificateExtension(paths);
}
@Override
public void beforeAll(ExtensionContext extensionContext) {
paths.forEach(this::generateCertificate);
}
@Override
public void afterAll(ExtensionContext extensionContext) {
paths.forEach(this::deleteCertificate);
}
private void generateCertificate(String path) {
String type = extractCertificateTypeFromResourcePath(path);
switch (type) {
case "pem":
generatePem(path);
break;
default:
throw new RuntimeException(String.format("Certificate type `%s` not supported.", type));
}
}
private void deleteCertificate(String path) {
new File(getClass().getResource(path).getPath()).delete();
}
private void generatePem(String path) {
try {
String name = extractNameFromResourcePath(path);
final String scriptPath = getClass().getResource(SCRIPT_GENERATE_CERT).getPath();
final String certsPath = getClass().getResource(extractDirectoryFromResourcePath(path)).getPath();
executeScript(scriptPath, name, certsPath);
} catch (Exception e) {
throw new RuntimeException(String.format("Failed to generate the `%s` certificate.", path), e);
}
}
private void executeScript(String scriptPath, String... arguments) throws IOException, InterruptedException {
ProcessBuilder builder = new ProcessBuilder();
builder.command("sh", "-c", scriptPath + " " + Stream.of(arguments).collect(Collectors.joining(" ")));
builder.redirectErrorStream(true);
builder.redirectOutput(ProcessBuilder.Redirect.INHERIT);
Process process = builder.start();
int exitCode = process.waitFor();
if (exitCode != 0) {
throw new RuntimeException(String.format("Script exited with a non-zero status code: `%d`.", exitCode));
}
}
private String extractNameFromResourcePath(String path) {
if (!path.contains(".")) {
throw new RuntimeException(String.format("Certificate extension not found in `%s`.", path));
}
return path.substring(path.lastIndexOf('/') + 1, path.lastIndexOf('.'));
}
private String extractCertificateTypeFromResourcePath(String path) {
if (!path.contains(".")) {
throw new RuntimeException(String.format("Certificate extension not found in `%s`.", path));
}
return path.substring(path.lastIndexOf('.') + 1);
}
private String extractDirectoryFromResourcePath(String path) {
return path.substring(0, path.lastIndexOf('/') + 1);
}
}
package com.kaffeinelabs.cert;
import com.kaffeinelabs.test.extension.CertificateExtension;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.Date;
public class CertTest {
@RegisterExtension
static CertificateExtension certificateExtension = CertificateExtension.forCertificates(Arrays.asList(
"/certificates/test-certificate.pem"
));
@Test
public void itLoadsCerts() throws IOException, CertificateException {
final CertificateFactory cf = CertificateFactory.getInstance("X.509");
final InputStream certFile = getClass().getResource("/certificates/test-certificate.pem").openStream();
final X509Certificate cert = (X509Certificate) cf.generateCertificate(certFile);
final Date expiry = cert.getNotAfter();
// ...
}
}
#!/bin/sh
NAME=${1:-"test"}
LOCATION=${2:-"."}
(
pushd $LOCATION > /dev/null
openssl req -new -newkey rsa:4096 -nodes -days 1 -subj "/C=UK/ST=London/L=London/O=KaffeineLabs/CN=kaffeinelabs.com" -keyout $NAME.key -out $NAME.csr
openssl x509 -req -sha256 -days 1 -in $NAME.csr -signkey $NAME.key -out $NAME.pem
rm $NAME.key $NAME.csr
popd > /dev/null
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment