95 lines
3.4 KiB
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);
|
|
}
|
|
}
|
|
}
|
|
}
|