Created
July 23, 2021 12:32
-
-
Save jakzal/4a8e06b9ff795d619487eabe1019651b to your computer and use it in GitHub Desktop.
JUnit extension to generate certificates
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
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); | |
} | |
} |
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
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(); | |
// ... | |
} | |
} |
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
#!/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