🚧 Create disposable generator result & include cli output in Logging

This commit is contained in:
Magnus Leßmann (@MarkL4YG) 2024-11-10 21:10:24 +01:00
parent 1671fe29ca
commit 637d94e846
Signed by: Mark.TwoFive
GPG key ID: 5B5EBCBE331F1E6F
6 changed files with 97 additions and 29 deletions

View file

@ -29,7 +29,8 @@ repositories {
}
dependencies {
implementation("org.apache.commons:commons-lang3:3.17.0")
implementation("org.zeroturnaround:zt-exec:1.12")
implementation("org.apache.commons:commons-lang3:3.17.0")
implementation("org.springframework.boot:spring-boot-autoconfigure")
implementation("org.springframework.boot:spring-boot-starter-jdbc")
@ -54,4 +55,5 @@ dependencies {
tasks.withType<Test> {
useJUnitPlatform()
testLogging.showStandardStreams = true
}

View file

@ -0,0 +1,16 @@
package de.mlessmann.certassist.except;
public class CommandLineOperationException extends Exception {
public CommandLineOperationException(String message) {
super(message);
}
public CommandLineOperationException(String message, Throwable cause) {
super(message, cause);
}
public CommandLineOperationException(Throwable cause) {
super(cause);
}
}

View file

@ -1,14 +1,20 @@
package de.mlessmann.certassist.openssl;
import de.mlessmann.certassist.ExecutableResolver;
import de.mlessmann.certassist.except.CommandLineOperationException;
import de.mlessmann.certassist.except.UnresolvableCLIDependency;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Service;
import org.zeroturnaround.exec.ProcessExecutor;
import org.zeroturnaround.exec.StartedProcess;
import org.zeroturnaround.exec.stream.slf4j.Slf4jStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.concurrent.ExecutionException;
import static org.slf4j.LoggerFactory.getLogger;
@ -24,39 +30,51 @@ public class OpenSSLCertificateCreator {
this.executableResolver = executableResolver;
}
public void createCertificate(CertificateRequest request) {
@Nullable
public OpenSSLCertificateResult createCertificate(CertificateRequest request) throws CommandLineOperationException, InterruptedException {
Path tmpDir;
try {
tmpDir = Files.createTempDirectory("certassist");
} catch (IOException e) {
LOGGER.atError()
.log("Could not create temp directory for openssl generator!", e);
return;
throw new CommandLineOperationException("Could not create temporary directory for certificate creation", e);
}
createKeyfile(request, tmpDir);
return new OpenSSLCertificateResult(tmpDir);
}
private Path createKeyfile(CertificateRequest request, Path tmpDir) throws CommandLineOperationException, InterruptedException {
Path keyFile = tmpDir.resolve("root.key")
.toAbsolutePath();
LOGGER.atDebug()
.log("Writing new certificate key to {}", keyFile);
try {
createKeyfile(request, tmpDir);
} catch (IOException | InterruptedException e) {
LOGGER.atError()
.log(e.getMessage());
} catch (UnresolvableCLIDependency e) {
LOGGER.atError()
.log(e.getMessage());
StartedProcess keygenProc = new ProcessExecutor().command(resolveOpenSSL(), "genrsa", "-out",
keyFile.toString(),
"-passout", "env:KEY_PASS",
Integer.toString(request.getRequestedKeyLength()))
.environment("KEY_PASS", request.getOid())
.redirectOutput(Slf4jStream.ofCaller()
.asDebug())
.redirectError(Slf4jStream.ofCaller()
.asError())
.start();
keygenProc.getFuture()
.get();
} catch (IOException e) {
throw new CommandLineOperationException("Failure running OpenSSL keygen command.", e);
} catch (ExecutionException e) {
throw new RuntimeException(e);
}
}
private Path createKeyfile(CertificateRequest request, Path tmpDir) throws UnresolvableCLIDependency, IOException, InterruptedException {
Path keyFile = tmpDir.resolve("root.key").toAbsolutePath();
LOGGER.atDebug().log("Creating root certificate key at: {}", keyFile);
String openSSLPath = executableResolver.getOpenSSLPath();
Process createRootKeyProc = new ProcessBuilder()
.command(openSSLPath, "req", "genrsa", "-des3", "-out", keyFile.toString(),
Integer.toString(request.getRequestedKeyLength()))
.inheritIO()
.start();
createRootKeyProc.waitFor();
return keyFile;
}
private String resolveOpenSSL() throws CommandLineOperationException {
try {
return executableResolver.getOpenSSLPath();
} catch (UnresolvableCLIDependency e) {
throw new CommandLineOperationException(e);
}
}
}

View file

@ -0,0 +1,26 @@
package de.mlessmann.certassist.openssl;
import org.slf4j.Logger;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import static org.slf4j.LoggerFactory.getLogger;
public class OpenSSLCertificateResult implements AutoCloseable {
private static final Logger LOGGER = getLogger(OpenSSLCertificateResult.class);
private final Path tmpDir;
OpenSSLCertificateResult(Path tmpDir) {
this.tmpDir = tmpDir;
}
@Override
public void close() throws IOException {
LOGGER.info("Cleaning up temporary output directory {}", tmpDir);
Files.deleteIfExists(tmpDir);
}
}

View file

@ -8,4 +8,8 @@ password=admin
spring.jpa.database-platform=org.hibernate.community.dialect.SQLiteDialect
#TODO: Use flyway for db setup
hibernate.hbm2ddl.auto=create-drop
hibernate.show_sql=true
hibernate.show_sql=true
# Logging
logging.level.root=INFO
logging.level.de.mlessmann.certassist=DEBUG

View file

@ -17,12 +17,14 @@ public class TestOpenSSLCertificateCreator {
}
@Test
void testCertificateCreation() {
void testCertificateCreation() throws Exception {
CertificateRequest certRequest = CertificateRequest.builder()
.commonName("test.home")
.type(RequestType.STANDALONE_CERTIFICATE)
.build();
openSSLCertificateCreator.createCertificate(certRequest);
try (var cert = openSSLCertificateCreator.createCertificate(certRequest)) {
System.out.println("Certificate created: " + cert);
}
}
}