home-cert-assistant/src/main/java/de/mlessmann/certassist/service/CertificateProviderImpl.java

95 lines
3.4 KiB
Java

package de.mlessmann.certassist.service;
import static java.util.Objects.requireNonNull;
import de.mlessmann.certassist.Constants;
import de.mlessmann.certassist.DeleteRecursiveFileVisitor;
import de.mlessmann.certassist.models.Certificate;
import de.mlessmann.certassist.models.CertificateType;
import de.mlessmann.certassist.openssl.CertificateProvider;
import de.mlessmann.certassist.openssl.CertificateUsage;
import de.mlessmann.certassist.repositories.CertificateRepository;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.OpenOption;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@Service
@Slf4j
@RequiredArgsConstructor
public class CertificateProviderImpl implements CertificateProvider {
private static final OpenOption[] CREATE_TRUNCATE = new OpenOption[] {
StandardOpenOption.CREATE,
StandardOpenOption.TRUNCATE_EXISTING,
};
private final CertificateRepository certificateRepository;
@Override
public CertificateUsage requestCertificateUsage(String fingerprint) {
requireNonNull(fingerprint, "Fingerprint must be provided.");
Certificate certFromDB;
try {
certFromDB = certificateRepository.findByFingerprintIs(fingerprint);
} catch (RuntimeException e) {
log.error("Failed to retrieve certificate from database by fingerprint: {}", fingerprint);
throw e;
}
if (certFromDB == null) {
throw new IllegalArgumentException("Unknown fingerprint");
}
boolean selfSigned =
certFromDB.getType() == CertificateType.ROOT_CA || certFromDB.getType() == CertificateType.STANDALONE_CERT;
try {
Path tempDirectory = Files.createTempDirectory(Constants.CERTASSIST_TMP_PREFIX);
Files.write(tempDirectory.resolve("key.pem"), certFromDB.getPrivateKey(), CREATE_TRUNCATE);
Files.write(tempDirectory.resolve("cert.pem"), certFromDB.getCert(), CREATE_TRUNCATE);
if (!selfSigned) {
Files.write(tempDirectory.resolve("fullchain.pem"), certFromDB.getFullchain(), CREATE_TRUNCATE);
}
return new ExtractedCert(tempDirectory, certFromDB.getFingerprint());
} catch (IOException e) {
// TODO: Better exception definitions
throw new RuntimeException("Unable to temporarily store certificate for use.", e);
}
}
@Slf4j
private record ExtractedCert(Path tempDir, String fingerprint) implements CertificateUsage {
@Override
public Path certificateKeyPath() {
return this.tempDir.resolve("key.pem");
}
@Override
public Path certificatePath() {
return this.tempDir.resolve("cert.pem");
}
@Override
public Path fullchainPath() {
Path fcFile = this.tempDir.resolve("fullchain.pem");
if (Files.exists(fcFile)) {
return fcFile;
}
return null;
}
@Override
public void close() {
try {
Files.walkFileTree(this.tempDir, new DeleteRecursiveFileVisitor());
Files.deleteIfExists(this.tempDir);
} catch (IOException e) {
log.error("Unable to clean up temporary directory: {}", this.tempDir, e);
}
}
}
}