chore: Refactor packages/classes a little to update the PoC architecture a bit #18

Merged
MarkL4YG merged 4 commits from chore/archRefactor into main 2024-11-23 21:10:20 +00:00
15 changed files with 179 additions and 117 deletions

View file

@ -20,6 +20,18 @@ jobs:
with: with:
distribution: 'temurin' distribution: 'temurin'
java-version: 21 java-version: 21
- name: Update environment variables based on PR labels
id: pr-env
uses: actions/github-script@v7
with:
script: |
const labels = context.payload.pull_request.labels.map(label => label.name);
console.log('PR labels:', labels);
const springDebug = labels.includes('pr-debug');
return { SPRING_DEBUG: '' + springDebug };
result-encoding: json
- uses: gradle/actions/setup-gradle@v4 - uses: gradle/actions/setup-gradle@v4
- name: Build gradle project - name: Build gradle project
run: ./gradlew build run: ./gradlew build
env:
ORG_GRADLE_PROJECT_SPRING_DEBUG: ${{ fromJSON(steps.pr-env.outputs.result).SPRING_DEBUG }}

View file

@ -7,6 +7,7 @@ plugins {
group = "io.github.markl4yg.hca" group = "io.github.markl4yg.hca"
version = "0.0.1-SNAPSHOT" version = "0.0.1-SNAPSHOT"
val springDebugLogging = providers.gradleProperty("SPRING_DEBUG").orNull == "true"
apply( apply(
from = file("./gradle/spotless.gradle") from = file("./gradle/spotless.gradle")
@ -57,6 +58,13 @@ dependencies {
tasks.withType<Test> { tasks.withType<Test> {
useJUnitPlatform() useJUnitPlatform()
if (springDebugLogging) {
// Additional Hibernate logging
jvmArgs("-Dlogging.level.org.sqlite=DEBUG")
jvmArgs("-Dlogging.level.org.hibernate=DEBUG")
jvmArgs("-Dhibernate.show_sql=true")
jvmArgs("-Dhibernate.format_sql=true")
}
systemProperty("spring.profiles.active", "test") systemProperty("spring.profiles.active", "test")
jvmArgs("-XX:+EnableDynamicAgentLoading") // DynamicAgentLoading for byteBuddy within Mockito jvmArgs("-XX:+EnableDynamicAgentLoading") // DynamicAgentLoading for byteBuddy within Mockito

View file

@ -0,0 +1,26 @@
package de.mlessmann.certassist.keystore;
import de.mlessmann.certassist.openssl.CertificatePasswordProvider;
import de.mlessmann.certassist.openssl.OpenSSLService;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AutoBootKeyStoreManagement {
@Bean
@ConditionalOnMissingBean(KeyStoreManager.class)
public KeyStoreManager keystoreProvider(
OpenSSLService certificateCreator,
CertificatePasswordProvider passwordProvider
) {
return new KeyStoreManager(certificateCreator, passwordProvider);
}
@Bean
@ConditionalOnMissingBean(TruststoreManager.class)
public TruststoreManager truststoreProvider() {
return new TruststoreManager();
}
}

View file

@ -3,7 +3,7 @@ package de.mlessmann.certassist.keystore;
import de.mlessmann.certassist.except.JavaSecurityException; import de.mlessmann.certassist.except.JavaSecurityException;
import de.mlessmann.certassist.openssl.CertificatePasswordProvider; import de.mlessmann.certassist.openssl.CertificatePasswordProvider;
import de.mlessmann.certassist.openssl.CertificateUsage; import de.mlessmann.certassist.openssl.CertificateUsage;
import de.mlessmann.certassist.openssl.OpenSSLCertificateCreator; import de.mlessmann.certassist.openssl.OpenSSLService;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.OpenOption; import java.nio.file.OpenOption;
@ -27,7 +27,7 @@ public class KeyStoreManager {
StandardOpenOption.CREATE, StandardOpenOption.CREATE,
StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.TRUNCATE_EXISTING,
}; };
private final OpenSSLCertificateCreator certificateCreator; private final OpenSSLService certificateCreator;
private final CertificatePasswordProvider passwordProvider; private final CertificatePasswordProvider passwordProvider;
public KeystoreUsage createKeyStore(String keyStorePassphrase, CertificateUsage... serverCerts) public KeystoreUsage createKeyStore(String keyStorePassphrase, CertificateUsage... serverCerts)

View file

@ -1,11 +1,11 @@
package de.mlessmann.certassist.openssl; package de.mlessmann.certassist.models;
import lombok.Builder; import lombok.Builder;
import lombok.Data; import lombok.Data;
@Data @Data
@Builder @Builder
public class CertificateRequest { public class CertificateInfo {
private RequestType type; private RequestType type;
private String trustingAuthority; private String trustingAuthority;
@ -16,9 +16,9 @@ public class CertificateRequest {
@Builder.Default @Builder.Default
private int requestedValidityDays = 365; private int requestedValidityDays = 365;
private CertificateSubject subject; private CertificateInfoSubject subject;
private CertificateSubject issuer; private CertificateInfoSubject issuer;
private CertificateRequestExtension extension; private CertificateInfoExtension extension;
public enum RequestType { public enum RequestType {
ROOT_AUTHORITY, ROOT_AUTHORITY,
@ -26,21 +26,19 @@ public class CertificateRequest {
NORMAL_CERTIFICATE, NORMAL_CERTIFICATE,
} }
public static class CertificateRequestBuilder { public static class CertificateInfoBuilder {
public CertificateRequestBuilder subject(CertificateSubject.CertificateSubjectBuilder builder) { public CertificateInfoBuilder subject(CertificateInfoSubject.CertificateInfoSubjectBuilder builder) {
this.subject = builder.build(); this.subject = builder.build();
return this; return this;
} }
public CertificateRequestBuilder issuer(CertificateSubject.CertificateSubjectBuilder builder) { public CertificateInfoBuilder issuer(CertificateInfoSubject.CertificateInfoSubjectBuilder builder) {
this.issuer = builder.build(); this.issuer = builder.build();
return this; return this;
} }
public CertificateRequestBuilder extension( public CertificateInfoBuilder extension(CertificateInfoExtension.CertificateInfoExtensionBuilder builder) {
CertificateRequestExtension.CertificateRequestExtensionBuilder builder
) {
this.extension = builder.build(); this.extension = builder.build();
return this; return this;
} }

View file

@ -1,4 +1,4 @@
package de.mlessmann.certassist.openssl; package de.mlessmann.certassist.models;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
@ -8,15 +8,15 @@ import lombok.Getter;
@Getter @Getter
@Builder @Builder
public class CertificateRequestExtension { public class CertificateInfoExtension {
private List<String> alternativeNames; private List<String> alternativeDnsNames;
public static class CertificateRequestExtensionBuilder { public static class CertificateInfoExtensionBuilder {
public CertificateRequestExtensionBuilder alternativeNames(String... altNames) { public CertificateInfoExtensionBuilder alternativeDnsNames(String... altNames) {
Objects.requireNonNull(altNames, "Alternative names must not be null (but can be empty)"); Objects.requireNonNull(altNames, "Alternative names must not be null (but can be empty)");
this.alternativeNames = this.alternativeDnsNames =
Stream Stream
.of(altNames) .of(altNames)
.filter(Objects::nonNull) .filter(Objects::nonNull)

View file

@ -1,11 +1,11 @@
package de.mlessmann.certassist.openssl; package de.mlessmann.certassist.models;
import lombok.Builder; import lombok.Builder;
import lombok.Getter; import lombok.Getter;
@Getter @Getter
@Builder @Builder
public class CertificateSubject { public class CertificateInfoSubject {
private String commonName; private String commonName;
private String emailAddress; private String emailAddress;
@ -15,5 +15,7 @@ public class CertificateSubject {
private String state; private String state;
private String locality; private String locality;
public static class CertificateSubjectBuilder {} public static class CertificateInfoSubjectBuilder {
// Class only exists to allow the builder to be statically imported.
}
} }

View file

@ -0,0 +1,26 @@
package de.mlessmann.certassist.openssl;
import de.mlessmann.certassist.service.ExecutableResolver;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AutoBootOpenSSL {
@Bean
@ConditionalOnMissingBean(CertificatePasswordProvider.class)
public CertificatePasswordProvider usageProvider() {
return new InMemoryCertificatePasswordProvider();
}
@Bean
@ConditionalOnMissingBean(CertificatePasswordProvider.class)
public OpenSSLService openSSLProvider(
ExecutableResolver executableResolver,
CertificatePasswordProvider passwordProvider,
CertificateProvider usageProvider
) {
return new OpenSSLService(executableResolver, passwordProvider, usageProvider);
}
}

View file

@ -1,15 +1,13 @@
package de.mlessmann.certassist.service; package de.mlessmann.certassist.openssl;
import de.mlessmann.certassist.openssl.CertificatePasswordProvider; import de.mlessmann.certassist.service.PassphraseService;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@Service @Slf4j
@ConditionalOnMissingBean(CertificatePasswordProvider.class)
public class InMemoryCertificatePasswordProvider implements CertificatePasswordProvider { public class InMemoryCertificatePasswordProvider implements CertificatePasswordProvider {
private final Map<String, String> passwords = new ConcurrentHashMap<>(); private final Map<String, String> passwords = new ConcurrentHashMap<>();
@ -22,11 +20,13 @@ public class InMemoryCertificatePasswordProvider implements CertificatePasswordP
@Override @Override
public String getPasswordFor(String certificateFingerprint) { public String getPasswordFor(String certificateFingerprint) {
log.trace("Getting password for certificate fingerprint: {}", certificateFingerprint);
return Optional.ofNullable(passwords.get(certificateFingerprint)).orElseThrow(); return Optional.ofNullable(passwords.get(certificateFingerprint)).orElseThrow();
} }
@Override @Override
public void setPasswordFor(String certificateFingerprint, String password) { public void setPasswordFor(String certificateFingerprint, String password) {
log.trace("Setting password for certificate fingerprint: {}", certificateFingerprint);
Objects.requireNonNull(certificateFingerprint); Objects.requireNonNull(certificateFingerprint);
Objects.requireNonNull(password); Objects.requireNonNull(password);
passwords.put(certificateFingerprint, password); passwords.put(certificateFingerprint, password);

View file

@ -5,11 +5,14 @@ import static java.util.concurrent.TimeUnit.*;
import static org.slf4j.LoggerFactory.getLogger; import static org.slf4j.LoggerFactory.getLogger;
import de.mlessmann.certassist.DeleteRecursiveFileVisitor; import de.mlessmann.certassist.DeleteRecursiveFileVisitor;
import de.mlessmann.certassist.ExecutableResolver;
import de.mlessmann.certassist.except.CommandLineOperationException; import de.mlessmann.certassist.except.CommandLineOperationException;
import de.mlessmann.certassist.except.UnresolvableCLIDependency; import de.mlessmann.certassist.except.UnresolvableCLIDependency;
import de.mlessmann.certassist.openssl.CertificateRequest.RequestType; import de.mlessmann.certassist.models.CertificateInfo;
import de.mlessmann.certassist.openssl.CertificateSubject.CertificateSubjectBuilder; import de.mlessmann.certassist.models.CertificateInfo.RequestType;
import de.mlessmann.certassist.models.CertificateInfoExtension;
import de.mlessmann.certassist.models.CertificateInfoSubject;
import de.mlessmann.certassist.models.CertificateInfoSubject.CertificateInfoSubjectBuilder;
import de.mlessmann.certassist.service.ExecutableResolver;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.nio.file.Files; import java.nio.file.Files;
@ -40,7 +43,7 @@ import org.zeroturnaround.exec.stream.slf4j.Slf4jStream;
@Service @Service
@RequiredArgsConstructor @RequiredArgsConstructor
@Slf4j @Slf4j
public class OpenSSLCertificateCreator { public class OpenSSLService {
private static final Logger openSSLLogger = getLogger("OpenSSL-Logger"); private static final Logger openSSLLogger = getLogger("OpenSSL-Logger");
public static final String OPENSSL_CERT_SUBJECT_TEMPLATE = public static final String OPENSSL_CERT_SUBJECT_TEMPLATE =
@ -65,7 +68,7 @@ public class OpenSSLCertificateCreator {
private final CertificatePasswordProvider passwordProvider; private final CertificatePasswordProvider passwordProvider;
private final CertificateProvider certificateProvider; private final CertificateProvider certificateProvider;
private static String buildSubjectArg(CertificateRequest request) { private static String buildSubjectArg(CertificateInfo request) {
String certSubject = OPENSSL_CERT_SUBJECT_TEMPLATE String certSubject = OPENSSL_CERT_SUBJECT_TEMPLATE
.replace("ISO-COUNTRY", request.getSubject().getCountry()) .replace("ISO-COUNTRY", request.getSubject().getCountry())
.replace("STATE", request.getSubject().getState()) .replace("STATE", request.getSubject().getState())
@ -103,7 +106,7 @@ public class OpenSSLCertificateCreator {
} }
@NonNull @NonNull
public OpenSSLCertificateResult createCertificate(CertificateRequest request) throws CommandLineOperationException { public OpenSSLCertificateResult createCertificate(CertificateInfo request) throws CommandLineOperationException {
Path tmpDir; Path tmpDir;
try { try {
tmpDir = Files.createTempDirectory(CERTASSIST_TMP_PREFIX); tmpDir = Files.createTempDirectory(CERTASSIST_TMP_PREFIX);
@ -150,7 +153,7 @@ public class OpenSSLCertificateCreator {
} }
} }
private Path createKeyfile(CertificateRequest request, Path outFile, String filePassword) private Path createKeyfile(CertificateInfo request, Path outFile, String filePassword)
throws CommandLineOperationException { throws CommandLineOperationException {
Path keyFile = outFile.toAbsolutePath(); Path keyFile = outFile.toAbsolutePath();
log.debug("Writing new certificate key to {}", keyFile); log.debug("Writing new certificate key to {}", keyFile);
@ -182,7 +185,7 @@ public class OpenSSLCertificateCreator {
return keyFile; return keyFile;
} }
private Path createCertificate(CertificateRequest request, Path keyFile, Path outFile, String keyPassphrase) private Path createCertificate(CertificateInfo request, Path keyFile, Path outFile, String keyPassphrase)
throws CommandLineOperationException { throws CommandLineOperationException {
log.debug("Writing new certificate file {}", outFile); log.debug("Writing new certificate file {}", outFile);
@ -222,7 +225,7 @@ public class OpenSSLCertificateCreator {
return outFile; return outFile;
} }
private Path createSigningRequest(CertificateRequest request, Path keyFile, Path outFile, String certPassword) private Path createSigningRequest(CertificateInfo request, Path keyFile, Path outFile, String certPassword)
throws CommandLineOperationException { throws CommandLineOperationException {
log.atDebug().log("Writing new certificate signing request file {}", outFile); log.atDebug().log("Writing new certificate signing request file {}", outFile);
@ -363,7 +366,7 @@ public class OpenSSLCertificateCreator {
} }
private Path signCertificate( private Path signCertificate(
CertificateRequest request, CertificateInfo request,
Path caCert, Path caCert,
Path caKey, Path caKey,
String caKeyPassphrase, String caKeyPassphrase,
@ -377,7 +380,7 @@ public class OpenSSLCertificateCreator {
String extContent = CSR_EXT_TEMPLATE; String extContent = CSR_EXT_TEMPLATE;
List<String> altNames = Optional List<String> altNames = Optional
.ofNullable(request.getExtension()) .ofNullable(request.getExtension())
.map(CertificateRequestExtension::getAlternativeNames) .map(CertificateInfoExtension::getAlternativeDnsNames)
.orElse(List.of()); .orElse(List.of());
if (!altNames.isEmpty()) { if (!altNames.isEmpty()) {
AtomicInteger counter = new AtomicInteger(1); AtomicInteger counter = new AtomicInteger(1);
@ -489,7 +492,7 @@ public class OpenSSLCertificateCreator {
} }
} }
public CertificateRequest getCertificateInfo(Path path) throws CommandLineOperationException { public CertificateInfo getCertificateInfo(Path path) throws CommandLineOperationException {
StartedProcess infoProc = null; StartedProcess infoProc = null;
try { try {
infoProc = infoProc =
@ -563,14 +566,14 @@ public class OpenSSLCertificateCreator {
} }
} }
private CertificateRequest getCertificateInfo(String[] lines) { private CertificateInfo getCertificateInfo(String[] lines) {
var builder = CertificateRequest.builder(); var builder = CertificateInfo.builder();
boolean hasIssuer = false; boolean hasIssuer = false;
for (int i = 0; i < lines.length; i++) { for (int i = 0; i < lines.length; i++) {
String line = lines[i]; String line = lines[i];
if (line.startsWith("subject=")) { if (line.startsWith("subject=")) {
CertificateSubjectBuilder subjectBuilder = CertificateSubject.builder(); var subjectBuilder = CertificateInfoSubject.builder();
line = lines[++i]; line = lines[++i];
while (line.startsWith(" ")) { while (line.startsWith(" ")) {
@ -580,7 +583,7 @@ public class OpenSSLCertificateCreator {
builder = builder.subject(subjectBuilder); builder = builder.subject(subjectBuilder);
} else if (line.startsWith("issuer=")) { } else if (line.startsWith("issuer=")) {
hasIssuer = true; hasIssuer = true;
CertificateSubjectBuilder issuerBuilder = CertificateSubject.builder(); var issuerBuilder = CertificateInfoSubject.builder();
line = lines[++i]; line = lines[++i];
while (line.startsWith(" ")) { while (line.startsWith(" ")) {
@ -591,7 +594,7 @@ public class OpenSSLCertificateCreator {
builder = builder.issuer(issuerBuilder); builder = builder.issuer(issuerBuilder);
} else if (line.startsWith("X509v3 Subject Alternative Name")) { } else if (line.startsWith("X509v3 Subject Alternative Name")) {
String[] altNames = lines[++i].split(","); String[] altNames = lines[++i].split(",");
builder = builder.extension(CertificateRequestExtension.builder().alternativeNames(altNames)); builder = builder.extension(CertificateInfoExtension.builder().alternativeDnsNames(altNames));
} }
} }
@ -599,7 +602,7 @@ public class OpenSSLCertificateCreator {
return builder.build(); return builder.build();
} }
private CertificateSubjectBuilder readSubjectInfo(String line, CertificateSubjectBuilder builder) { private CertificateInfoSubjectBuilder readSubjectInfo(String line, CertificateInfoSubjectBuilder builder) {
String[] parts = line.split("=", 2); String[] parts = line.split("=", 2);
if (parts.length != 2) { if (parts.length != 2) {
return builder; return builder;

View file

@ -1,9 +1,7 @@
package de.mlessmann.certassist.service; package de.mlessmann.certassist.service;
import de.mlessmann.certassist.except.CommandLineOperationException; import de.mlessmann.certassist.except.CommandLineOperationException;
import de.mlessmann.certassist.models.Certificate; import de.mlessmann.certassist.models.*;
import de.mlessmann.certassist.models.CertificateExtension;
import de.mlessmann.certassist.models.CertificateType;
import de.mlessmann.certassist.openssl.*; import de.mlessmann.certassist.openssl.*;
import de.mlessmann.certassist.repositories.CertificateRepository; import de.mlessmann.certassist.repositories.CertificateRepository;
import java.io.IOException; import java.io.IOException;
@ -19,17 +17,13 @@ import org.springframework.stereotype.Service;
public class CertificateCreationService { public class CertificateCreationService {
private final CertificateRepository certificateRepository; private final CertificateRepository certificateRepository;
private final OpenSSLCertificateCreator openSSLCertificateCreator; private final OpenSSLService openSSLService;
private final PassphraseService passphraseService; private final PassphraseService passphraseService;
public Certificate createCertificate(final CertificateRequest certificateRequest) { public Certificate createCertificate(final CertificateInfo certificateInfo) {
final Certificate certificate = createEntityFromRequest(certificateRequest); final Certificate certificate = createEntityFromRequest(certificateInfo);
try ( try (OpenSSLCertificateResult certificateCreatorResult = openSSLService.createCertificate(certificateInfo);) {
OpenSSLCertificateResult certificateCreatorResult = openSSLCertificateCreator.createCertificate(
certificateRequest
);
) {
certificate.setPrivateKey(Files.readAllBytes(certificateCreatorResult.certificateKeyPath())); certificate.setPrivateKey(Files.readAllBytes(certificateCreatorResult.certificateKeyPath()));
certificate.setCert(Files.readAllBytes(certificateCreatorResult.certificatePath())); certificate.setCert(Files.readAllBytes(certificateCreatorResult.certificatePath()));
} catch (CommandLineOperationException | IOException e) { } catch (CommandLineOperationException | IOException e) {
@ -40,26 +34,26 @@ public class CertificateCreationService {
return certificate; return certificate;
} }
private Certificate createEntityFromRequest(CertificateRequest certificateRequest) { private Certificate createEntityFromRequest(CertificateInfo certificateInfo) {
final Certificate certificate = new Certificate(); final Certificate certificate = new Certificate();
certificate.setType(mapCertificateRequestType(certificateRequest.getType())); certificate.setType(mapCertificateRequestType(certificateInfo.getType()));
certificate.setSubjectCommonName(certificateRequest.getSubject().getCommonName()); certificate.setSubjectCommonName(certificateInfo.getSubject().getCommonName());
certificate.setTrustingAuthority(certificateRequest.getTrustingAuthority()); certificate.setTrustingAuthority(certificateInfo.getTrustingAuthority());
certificate.setRequestedKeyLength(certificateRequest.getRequestedKeyLength()); certificate.setRequestedKeyLength(certificateInfo.getRequestedKeyLength());
certificate.setRequestedValidityDays(certificateRequest.getRequestedValidityDays()); certificate.setRequestedValidityDays(certificateInfo.getRequestedValidityDays());
final CertificateSubject certificateSubject = certificateRequest.getSubject(); final CertificateInfoSubject subjectInfo = certificateInfo.getSubject();
certificate.setSubjectEmailAddress(certificateSubject.getEmailAddress()); certificate.setSubjectEmailAddress(subjectInfo.getEmailAddress());
certificate.setSubjectOrganization(certificateSubject.getOrganization()); certificate.setSubjectOrganization(subjectInfo.getOrganization());
certificate.setSubjectOrganizationalUnit(certificateSubject.getOrganizationalUnit()); certificate.setSubjectOrganizationalUnit(subjectInfo.getOrganizationalUnit());
certificate.setSubjectCountry(certificateSubject.getCountry()); certificate.setSubjectCountry(subjectInfo.getCountry());
certificate.setSubjectState(certificateSubject.getState()); certificate.setSubjectState(subjectInfo.getState());
certificate.setSubjectLocality(certificateSubject.getLocality()); certificate.setSubjectLocality(subjectInfo.getLocality());
final CertificateRequestExtension extension = certificateRequest.getExtension(); final CertificateInfoExtension extension = certificateInfo.getExtension();
if (extension != null) { if (extension != null) {
final CertificateExtension certificateExtension = new CertificateExtension(); final CertificateExtension certificateExtension = new CertificateExtension();
certificateExtension.setIdentifier("alternativeNames"); certificateExtension.setIdentifier("alternativeNames");
certificateExtension.setValue(String.join(",", extension.getAlternativeNames())); certificateExtension.setValue(String.join(",", extension.getAlternativeDnsNames()));
certificate.setCertificateExtension(List.of(certificateExtension)); certificate.setCertificateExtension(List.of(certificateExtension));
} }
return certificate; return certificate;
@ -67,8 +61,8 @@ public class CertificateCreationService {
public Certificate importCertificate(Path certificate, Path keyFile, String passphrase) { public Certificate importCertificate(Path certificate, Path keyFile, String passphrase) {
try { try {
String fingerprint = openSSLCertificateCreator.getCertificateFingerprint(certificate); String fingerprint = openSSLService.getCertificateFingerprint(certificate);
var generatedRequest = openSSLCertificateCreator.getCertificateInfo(certificate); var generatedRequest = openSSLService.getCertificateInfo(certificate);
Certificate entity = createEntityFromRequest(generatedRequest); Certificate entity = createEntityFromRequest(generatedRequest);
entity.setCert(Files.readAllBytes(certificate)); entity.setCert(Files.readAllBytes(certificate));
entity.setPrivateKey(Files.readAllBytes(keyFile)); entity.setPrivateKey(Files.readAllBytes(keyFile));
@ -81,7 +75,7 @@ public class CertificateCreationService {
} }
} }
private CertificateType mapCertificateRequestType(CertificateRequest.RequestType requestType) { private CertificateType mapCertificateRequestType(CertificateInfo.RequestType requestType) {
return switch (requestType) { return switch (requestType) {
case ROOT_AUTHORITY -> CertificateType.ROOT_CA; case ROOT_AUTHORITY -> CertificateType.ROOT_CA;
case STANDALONE_CERTIFICATE -> CertificateType.STANDALONE_CERT; case STANDALONE_CERTIFICATE -> CertificateType.STANDALONE_CERT;

View file

@ -1,4 +1,4 @@
package de.mlessmann.certassist; package de.mlessmann.certassist.service;
import de.mlessmann.certassist.except.UnresolvableCLIDependency; import de.mlessmann.certassist.except.UnresolvableCLIDependency;
import java.io.File; import java.io.File;

View file

@ -2,9 +2,9 @@ package de.mlessmann.certassist;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import de.mlessmann.certassist.openssl.CertificateRequest; import de.mlessmann.certassist.models.CertificateInfo;
import de.mlessmann.certassist.openssl.CertificateRequestExtension; import de.mlessmann.certassist.models.CertificateInfoExtension;
import de.mlessmann.certassist.openssl.CertificateSubject; import de.mlessmann.certassist.models.CertificateInfoSubject;
import de.mlessmann.certassist.service.CertificateCreationService; import de.mlessmann.certassist.service.CertificateCreationService;
import java.nio.file.Path; import java.nio.file.Path;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@ -19,11 +19,11 @@ public class CertificateServiceTest {
@Test @Test
void testCanCreateCertificate() { void testCanCreateCertificate() {
var request = CertificateRequest var request = CertificateInfo
.builder() .builder()
.type(CertificateRequest.RequestType.STANDALONE_CERTIFICATE) .type(CertificateInfo.RequestType.STANDALONE_CERTIFICATE)
.subject( .subject(
CertificateSubject CertificateInfoSubject
.builder() .builder()
.commonName("cert.creation") .commonName("cert.creation")
.country("DE") .country("DE")
@ -31,7 +31,7 @@ public class CertificateServiceTest {
.locality("HH") .locality("HH")
.organization("Crazy-Cats") .organization("Crazy-Cats")
) )
.extension(CertificateRequestExtension.builder().alternativeNames("test2.home", "test3.home")) .extension(CertificateInfoExtension.builder().alternativeDnsNames("test2.home", "test3.home"))
.build(); .build();
var cert = certificateService.createCertificate(request); var cert = certificateService.createCertificate(request);
assertThat(cert).isNotNull(); assertThat(cert).isNotNull();
@ -40,11 +40,11 @@ public class CertificateServiceTest {
@Test @Test
void testCanImportCertificate() { void testCanImportCertificate() {
Path certDir = TestOpenSSLCertificateCreator.TEST_CERT_PATH; Path certDir = TestOpenSSLService.TEST_CERT_PATH;
var importedCert = certificateService.importCertificate( var importedCert = certificateService.importCertificate(
certDir.resolve("x509forImport.pem"), certDir.resolve("x509forImport.pem"),
certDir.resolve("x509forImport.key.pem"), certDir.resolve("x509forImport.key.pem"),
TestOpenSSLCertificateCreator.TEST_CERT_PASSPHRASE TestOpenSSLService.TEST_CERT_PASSPHRASE
); );
assertThat(importedCert).isNotNull(); assertThat(importedCert).isNotNull();
assertThat(importedCert.getId()).isGreaterThan("0"); assertThat(importedCert.getId()).isGreaterThan("0");

View file

@ -6,8 +6,9 @@ import de.mlessmann.certassist.keystore.KeyStoreManager;
import de.mlessmann.certassist.keystore.TruststoreManager; import de.mlessmann.certassist.keystore.TruststoreManager;
import de.mlessmann.certassist.openssl.CertificateProvider; import de.mlessmann.certassist.openssl.CertificateProvider;
import de.mlessmann.certassist.openssl.CertificateUsage; import de.mlessmann.certassist.openssl.CertificateUsage;
import de.mlessmann.certassist.openssl.OpenSSLCertificateCreator; import de.mlessmann.certassist.openssl.InMemoryCertificatePasswordProvider;
import de.mlessmann.certassist.service.InMemoryCertificatePasswordProvider; import de.mlessmann.certassist.openssl.OpenSSLService;
import de.mlessmann.certassist.service.ExecutableResolver;
import java.io.IOException; import java.io.IOException;
import java.net.ServerSocket; import java.net.ServerSocket;
import java.nio.file.Path; import java.nio.file.Path;
@ -26,36 +27,32 @@ public class TestKeystoreCreation {
private final CertificateUsage dummyCert = new CertificateUsage() { private final CertificateUsage dummyCert = new CertificateUsage() {
@Override @Override
public String fingerprint() { public String fingerprint() {
return TestOpenSSLCertificateCreator.TEST_CERT_FINGERPRINT; return TestOpenSSLService.TEST_CERT_FINGERPRINT;
} }
@Override @Override
public Path certificatePath() { public Path certificatePath() {
return TestOpenSSLCertificateCreator.TEST_CERT_PATH.resolve("x509forImport.pem"); return TestOpenSSLService.TEST_CERT_PATH.resolve("x509forImport.pem");
} }
@Override @Override
public Path certificateKeyPath() { public Path certificateKeyPath() {
return TestOpenSSLCertificateCreator.TEST_CERT_PATH.resolve("x509forImport.key.pem"); return TestOpenSSLService.TEST_CERT_PATH.resolve("x509forImport.key.pem");
} }
@Override @Override
public Path fullchainPath() { public Path fullchainPath() {
return TestOpenSSLCertificateCreator.TEST_CERT_PATH.resolve("x509forImport.fullchain.pem"); return TestOpenSSLService.TEST_CERT_PATH.resolve("x509forImport.fullchain.pem");
} }
}; };
@Test @Test
void testTruststore() throws Exception { void testTruststore() throws Exception {
var passwordProvider = new InMemoryCertificatePasswordProvider(); var passwordProvider = new InMemoryCertificatePasswordProvider();
passwordProvider.setPasswordFor(dummyCert.fingerprint(), TestOpenSSLCertificateCreator.TEST_CERT_PASSPHRASE); passwordProvider.setPasswordFor(dummyCert.fingerprint(), TestOpenSSLService.TEST_CERT_PASSPHRASE);
var certificateProvider = Mockito.mock(CertificateProvider.class); var certificateProvider = Mockito.mock(CertificateProvider.class);
var opensslCertCreator = new OpenSSLCertificateCreator( var opensslCertCreator = new OpenSSLService(new ExecutableResolver(), passwordProvider, certificateProvider);
new ExecutableResolver(),
passwordProvider,
certificateProvider
);
var truststoreManager = new TruststoreManager(); var truststoreManager = new TruststoreManager();
var keyStoreManager = new KeyStoreManager(opensslCertCreator, passwordProvider); var keyStoreManager = new KeyStoreManager(opensslCertCreator, passwordProvider);
AtomicBoolean serverAccepted = new AtomicBoolean(false); AtomicBoolean serverAccepted = new AtomicBoolean(false);

View file

@ -3,8 +3,12 @@ package de.mlessmann.certassist;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.*; import static org.mockito.Mockito.*;
import de.mlessmann.certassist.models.CertificateInfo;
import de.mlessmann.certassist.models.CertificateInfo.RequestType;
import de.mlessmann.certassist.models.CertificateInfoExtension;
import de.mlessmann.certassist.models.CertificateInfoSubject;
import de.mlessmann.certassist.openssl.*; import de.mlessmann.certassist.openssl.*;
import de.mlessmann.certassist.openssl.CertificateRequest.RequestType; import de.mlessmann.certassist.service.ExecutableResolver;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.Objects; import java.util.Objects;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
@ -13,7 +17,7 @@ import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.boot.test.mock.mockito.MockBean;
@SpringBootTest @SpringBootTest
class TestOpenSSLCertificateCreator { class TestOpenSSLService {
public static final String TEST_CERT_PASSPHRASE = "ABC-123"; public static final String TEST_CERT_PASSPHRASE = "ABC-123";
public static final Path TEST_CERT_PATH = Path.of("src/test/resources/openssl"); public static final Path TEST_CERT_PATH = Path.of("src/test/resources/openssl");
@ -35,17 +39,13 @@ class TestOpenSSLCertificateCreator {
void testCertificateCreation() throws Exception { void testCertificateCreation() throws Exception {
CertificateProvider certificateProvider = mock(CertificateProvider.class); CertificateProvider certificateProvider = mock(CertificateProvider.class);
ExecutableResolver executableResolver = new ExecutableResolver(); ExecutableResolver executableResolver = new ExecutableResolver();
var certificateCreator = new OpenSSLCertificateCreator( var certificateCreator = new OpenSSLService(executableResolver, passwordProvider, certificateProvider);
executableResolver,
passwordProvider,
certificateProvider
);
CertificateRequest certRequest = CertificateRequest CertificateInfo certRequest = CertificateInfo
.builder() .builder()
.type(RequestType.STANDALONE_CERTIFICATE) .type(RequestType.STANDALONE_CERTIFICATE)
.subject( .subject(
CertificateSubject CertificateInfoSubject
.builder() .builder()
.commonName("test.home") .commonName("test.home")
.country("DE") .country("DE")
@ -53,7 +53,7 @@ class TestOpenSSLCertificateCreator {
.locality("HH") .locality("HH")
.organization("Crazy-Cats") .organization("Crazy-Cats")
) )
.extension(CertificateRequestExtension.builder().alternativeNames("test2.home", "test3.home")) .extension(CertificateInfoExtension.builder().alternativeDnsNames("test2.home", "test3.home"))
.build(); .build();
try (var cert = certificateCreator.createCertificate(certRequest)) { try (var cert = certificateCreator.createCertificate(certRequest)) {
@ -64,12 +64,12 @@ class TestOpenSSLCertificateCreator {
.withFailMessage(ERR_NOT_ENCRYPTED) .withFailMessage(ERR_NOT_ENCRYPTED)
.isTrue(); .isTrue();
CertificateRequest childRequest = CertificateRequest CertificateInfo childRequest = CertificateInfo
.builder() .builder()
.type(RequestType.NORMAL_CERTIFICATE) .type(RequestType.NORMAL_CERTIFICATE)
.trustingAuthority(cert.fingerprint()) .trustingAuthority(cert.fingerprint())
.subject( .subject(
CertificateSubject CertificateInfoSubject
.builder() .builder()
.commonName("test.local") .commonName("test.local")
.country("DE") .country("DE")
@ -77,7 +77,7 @@ class TestOpenSSLCertificateCreator {
.locality("HH") .locality("HH")
.organization("Crazy-Cats") .organization("Crazy-Cats")
) )
.extension(CertificateRequestExtension.builder().alternativeNames("test2.local", "test3.local")) .extension(CertificateInfoExtension.builder().alternativeDnsNames("test2.local", "test3.local"))
.build(); .build();
var spiedCert = spy(cert); var spiedCert = spy(cert);
@ -101,11 +101,7 @@ class TestOpenSSLCertificateCreator {
void testCertificateImport() throws Exception { void testCertificateImport() throws Exception {
CertificateProvider certificateProvider = mock(CertificateProvider.class); CertificateProvider certificateProvider = mock(CertificateProvider.class);
ExecutableResolver executableResolver = new ExecutableResolver(); ExecutableResolver executableResolver = new ExecutableResolver();
var certificateCreator = new OpenSSLCertificateCreator( var certificateCreator = new OpenSSLService(executableResolver, passwordProvider, certificateProvider);
executableResolver,
passwordProvider,
certificateProvider
);
var request = certificateCreator.getCertificateInfo(TEST_CERT_PATH.resolve("x509forImportCA.pem")); var request = certificateCreator.getCertificateInfo(TEST_CERT_PATH.resolve("x509forImportCA.pem"));
assertThat(request).isNotNull(); assertThat(request).isNotNull();
@ -123,6 +119,6 @@ class TestOpenSSLCertificateCreator {
assertThat(request.getSubject().getState()).isEqualTo("SH"); assertThat(request.getSubject().getState()).isEqualTo("SH");
assertThat(request.getSubject().getLocality()).isEqualTo("HH"); assertThat(request.getSubject().getLocality()).isEqualTo("HH");
assertThat(request.getSubject().getOrganization()).isEqualTo("Crazy-Cats"); assertThat(request.getSubject().getOrganization()).isEqualTo("Crazy-Cats");
assertThat(request.getExtension().getAlternativeNames()).containsExactly("test2.local", "test3.local"); assertThat(request.getExtension().getAlternativeDnsNames()).containsExactly("test2.local", "test3.local");
} }
} }