From 6fe7d30e2c00af1bbde0c60bca5fbfc584d188cd Mon Sep 17 00:00:00 2001 From: RPKI Team at RIPE NCC Date: Mon, 5 Feb 2024 09:54:37 +0000 Subject: [PATCH] RIPE NCC has merged fb9346a * Remove rsync repository write check from health check [2def4f13] * Allow config path to be overridden [6767cef0] * Naming [c887eeb8] * Review items [6dc56937] * Code smells [5b21fbe5] * Typos [771db045] * Comment [6a23e493] * Fix broken tests [b23ba13e] * Straighten ACA request-response workflow [82ab2814] * Wrap singleton list in ArrayList to avoid XStream permission issue [25c30724] * Fix the filename of the `.jsonl` logs [9c705391] * Remove DB migration [b4608b00] * Add some DB check constraints corresponding to @NotNull in Java code [73fab508] * Add more validation checks [04a111f5] * Revert erroneous change [aa026edb] * Cleanup [c579d4f3] * Do not use hibernate-validation, it fails to load persistence provider [23a00e87] * Remove functionality that forced a single nCipher.sworld key to exist [2ab0cfed] --- src/main/dist/rpki-ripe-ncc.sh | 2 +- .../impl/CertificationProviderConfig.java | 14 +--- ...ertificationProviderConfigurationData.java | 39 +---------- .../rpki/domain/HardwareKeyPairFactory.java | 11 ---- .../domain/IncomingResourceCertificate.java | 11 +++- .../net/ripe/rpki/domain/KeyPairEntity.java | 3 +- .../net/ripe/rpki/domain/KeyPairService.java | 2 - .../domain/OutgoingResourceCertificate.java | 7 +- .../ProductionCertificateAuthority.java | 5 -- .../ripe/rpki/domain/ResourceCertificate.java | 22 +++++-- .../core/domain/support/EntitySupport.java | 12 ---- ...tificateRepositoryUpToDateHealthCheck.java | 44 ------------- .../services/impl/KeyPairServiceBean.java | 13 ---- ...yManagementInitiateRollCommandHandler.java | 8 ++- .../ripe/rpki/web/UpstreamCaController.java | 64 +++++++++++++------ .../WEB-INF/templates/admin/upstream-ca.html | 2 +- .../resources/application-prepdev.properties | 5 -- .../resources/logback/logback-production.xml | 2 +- .../ui/daemon/health/HealthChecksTest.java | 4 +- .../rpki/web/UpstreamCaControllerTest.java | 4 +- 20 files changed, 94 insertions(+), 180 deletions(-) delete mode 100644 src/main/java/net/ripe/rpki/ripencc/ui/daemon/health/checks/CertificateRepositoryUpToDateHealthCheck.java diff --git a/src/main/dist/rpki-ripe-ncc.sh b/src/main/dist/rpki-ripe-ncc.sh index 8089263..5e64213 100755 --- a/src/main/dist/rpki-ripe-ncc.sh +++ b/src/main/dist/rpki-ripe-ncc.sh @@ -17,7 +17,7 @@ CORE_JAR=${CORE_JAR:-"./rpki-ripe-ncc.jar"} CORE_OPTS=( "--spring.profiles.active=$APPLICATION_ENVIRONMENT" - "--spring.config.additional-location=file:/cert/shared/rpki-config-credentials.properties" + "--spring.config.additional-location=${SPRING_CONFIG_ADDITIONAL_LOCATION:-file:/cert/shared/rpki-config-credentials.properties}" ) case "$APPLICATION_ENVIRONMENT" in diff --git a/src/main/java/net/ripe/rpki/application/impl/CertificationProviderConfig.java b/src/main/java/net/ripe/rpki/application/impl/CertificationProviderConfig.java index 3423deb..7d7c672 100644 --- a/src/main/java/net/ripe/rpki/application/impl/CertificationProviderConfig.java +++ b/src/main/java/net/ripe/rpki/application/impl/CertificationProviderConfig.java @@ -12,18 +12,10 @@ public CertificationProviderConfigurationData certificationProviderConfiguration @Value("${keystore.provider}") String keyStoreProvider, @Value("${keypair.generator.provider}") String keyPairGeneratorProvider, @Value("${signature.provider}") String signatureProvider, - @Value("${keystore.type}") String keyStoreType, - @Value("${fs.keystore.provider:${keystore.provider}}") - String fsKeyStoreProvider, - @Value("${fs.keypair.generator.provider:${keypair.generator.provider}}") - String fsKeyPairGeneratorProvider, - @Value("${fs.signature.provider:${signature.provider}}") - String fsSignatureProvider, - @Value("${fs.keystore.type:${keystore.type}}") - String fsKeyStoreType + @Value("${keystore.type}") String keyStoreType ) { return new CertificationProviderConfigurationData( - keyStoreProvider, keyPairGeneratorProvider, signatureProvider, keyStoreType, - fsKeyStoreProvider, fsKeyPairGeneratorProvider, fsSignatureProvider, fsKeyStoreType); + keyStoreProvider, keyPairGeneratorProvider, signatureProvider, keyStoreType + ); } } diff --git a/src/main/java/net/ripe/rpki/domain/CertificationProviderConfigurationData.java b/src/main/java/net/ripe/rpki/domain/CertificationProviderConfigurationData.java index bda54d9..733f008 100644 --- a/src/main/java/net/ripe/rpki/domain/CertificationProviderConfigurationData.java +++ b/src/main/java/net/ripe/rpki/domain/CertificationProviderConfigurationData.java @@ -1,44 +1,11 @@ package net.ripe.rpki.domain; -import lombok.Getter; -import net.ripe.rpki.server.api.support.objects.ValueObjectSupport; - -@Getter -public class CertificationProviderConfigurationData extends ValueObjectSupport { +import lombok.Data; +@Data +public class CertificationProviderConfigurationData { private final String keyStoreProvider; private final String keyPairGeneratorProvider; private final String signatureProvider; private final String keyStoreType; - - private final String fsKeyStoreProvider; - private final String fsKeyPairGeneratorProvider; - private final String fsSignatureProvider; - private final String fsKeyStoreType; - - public CertificationProviderConfigurationData(String keyStoreProvider, - String keyPairGeneratorProvider, - String signatureProvider, - String keyStoreType, - String fsKeyStoreProvider, - String fsKeyPairGeneratorProvider, - String fsSignatureProvider, - String fsKeyStoreType) { - this.keyStoreProvider = keyStoreProvider; - this.keyPairGeneratorProvider = keyPairGeneratorProvider; - this.signatureProvider = signatureProvider; - this.keyStoreType = keyStoreType; - this.fsKeyStoreProvider = fsKeyStoreProvider; - this.fsKeyPairGeneratorProvider = fsKeyPairGeneratorProvider; - this.fsSignatureProvider = fsSignatureProvider; - this.fsKeyStoreType = fsKeyStoreType; - } - - public boolean hasDifferentProviders() { - return !keyStoreProvider.equals(fsKeyStoreProvider) || - !keyPairGeneratorProvider.equals(fsKeyPairGeneratorProvider) || - !signatureProvider.equals(fsSignatureProvider) || - !keyStoreType.equals(fsKeyStoreType); - } - } diff --git a/src/main/java/net/ripe/rpki/domain/HardwareKeyPairFactory.java b/src/main/java/net/ripe/rpki/domain/HardwareKeyPairFactory.java index d066f30..1fc1b68 100644 --- a/src/main/java/net/ripe/rpki/domain/HardwareKeyPairFactory.java +++ b/src/main/java/net/ripe/rpki/domain/HardwareKeyPairFactory.java @@ -12,21 +12,14 @@ */ public class HardwareKeyPairFactory implements Supplier { private final KeyPairFactory keyPairFactory; - private final KeyPairFactory fsKeyPairFactory; private final CertificationProviderConfigurationData providerConfigurationData; public HardwareKeyPairFactory(CertificationProviderConfigurationData providerConfigurationData) { this.keyPairFactory = new KeyPairFactory(providerConfigurationData.getKeyPairGeneratorProvider()); - this.fsKeyPairFactory = providerConfigurationData.hasDifferentProviders() ? - new KeyPairFactory(providerConfigurationData.getFsKeyPairGeneratorProvider()) : - this.keyPairFactory; this.providerConfigurationData = providerConfigurationData; } public HardwareKeyPairFactory(CertificationProviderConfigurationData providerConfigurationData, KeyPairFactory keyPairFactory) { this.keyPairFactory = keyPairFactory.withProvider(providerConfigurationData.getSignatureProvider()); - this.fsKeyPairFactory = providerConfigurationData.hasDifferentProviders() ? - new KeyPairFactory(providerConfigurationData.getFsSignatureProvider()) : - this.keyPairFactory; this.providerConfigurationData = providerConfigurationData; } @@ -35,10 +28,6 @@ public KeyPair get() { return keyPairFactory.generate(); } - public KeyPair getFsKey() { - return fsKeyPairFactory.generate(); - } - public String keyPairGeneratorProvider() { return providerConfigurationData.getKeyPairGeneratorProvider(); } diff --git a/src/main/java/net/ripe/rpki/domain/IncomingResourceCertificate.java b/src/main/java/net/ripe/rpki/domain/IncomingResourceCertificate.java index 1fbf403..85d5313 100644 --- a/src/main/java/net/ripe/rpki/domain/IncomingResourceCertificate.java +++ b/src/main/java/net/ripe/rpki/domain/IncomingResourceCertificate.java @@ -4,6 +4,7 @@ import lombok.NonNull; import net.ripe.ipresource.ImmutableResourceSet; import net.ripe.rpki.domain.interca.CertificateIssuanceResponse; +import org.apache.commons.lang3.Validate; import javax.persistence.*; import javax.validation.constraints.NotNull; @@ -34,10 +35,11 @@ protected IncomingResourceCertificate() { public IncomingResourceCertificate(@NonNull CertificateIssuanceResponse issuanceResponse, @NonNull KeyPairEntity subjectKeyPair) { super(issuanceResponse.getCertificate()); + Validate.notNull(issuanceResponse); setPublicationUri(issuanceResponse.getPublicationUri()); this.inheritedResources = issuanceResponse.getInheritedResources(); this.subjectKeyPair = subjectKeyPair; - assertValid(); + revalidate(); } public boolean update(CertificateIssuanceResponse issuanceResponse) { @@ -50,10 +52,17 @@ public boolean update(CertificateIssuanceResponse issuanceResponse) { updateCertificate(issuanceResponse.getCertificate()); setPublicationUri(issuanceResponse.getPublicationUri()); this.inheritedResources = issuanceResponse.getInheritedResources(); + revalidate(); return true; } public ImmutableResourceSet getCertifiedResources() { return inheritedResources.union(super.getResources()); } + + protected void revalidate() { + Validate.notNull(subjectKeyPair); + Validate.notNull(inheritedResources); + revalidateCertificate(); + } } diff --git a/src/main/java/net/ripe/rpki/domain/KeyPairEntity.java b/src/main/java/net/ripe/rpki/domain/KeyPairEntity.java index 40c785a..57d10c5 100644 --- a/src/main/java/net/ripe/rpki/domain/KeyPairEntity.java +++ b/src/main/java/net/ripe/rpki/domain/KeyPairEntity.java @@ -89,11 +89,12 @@ public KeyPairEntity(KeyPair keyPair, String crlFilename, String manifestFilename) { this(); + Validate.notNull(manifestFilename); + Validate.notNull(crlFilename); this.size = ((RSAPublicKey) keyPair.getPublic()).getModulus().bitLength(); this.persistedKeyPair = new PersistedKeyPair(keyPair, signInfo); this.crlFilename = crlFilename; this.manifestFilename = manifestFilename; - assertValid(); } @Override diff --git a/src/main/java/net/ripe/rpki/domain/KeyPairService.java b/src/main/java/net/ripe/rpki/domain/KeyPairService.java index b84c6ab..7df84f6 100644 --- a/src/main/java/net/ripe/rpki/domain/KeyPairService.java +++ b/src/main/java/net/ripe/rpki/domain/KeyPairService.java @@ -7,7 +7,5 @@ public interface KeyPairService { KeyPairEntity createKeyPairEntity(); - KeyPairEntity createSpecialFsKeyPairEntity(); - DownStreamProvisioningCommunicator createMyIdentityMaterial(ManagedCertificateAuthority ca); } diff --git a/src/main/java/net/ripe/rpki/domain/OutgoingResourceCertificate.java b/src/main/java/net/ripe/rpki/domain/OutgoingResourceCertificate.java index e6cb34b..b201f89 100644 --- a/src/main/java/net/ripe/rpki/domain/OutgoingResourceCertificate.java +++ b/src/main/java/net/ripe/rpki/domain/OutgoingResourceCertificate.java @@ -21,6 +21,8 @@ import javax.validation.constraints.NotNull; import java.net.URI; +import static java.util.Objects.requireNonNull; + @Entity @DiscriminatorValue(value = "OUTGOING") public class OutgoingResourceCertificate extends ResourceCertificate { @@ -65,6 +67,7 @@ protected OutgoingResourceCertificate() { super(certificate); Validate.isTrue(embedded || filename != null, "embedded or filename must be set"); Validate.isTrue(embedded || parentPublicationDirectory != null, "embedded or parentPublicationDirectory must be set"); + Validate.notNull(signingKeyPair); this.signingKeyPair = signingKeyPair; this.embedded = embedded; this.status = OutgoingResourceCertificateStatus.CURRENT; @@ -72,7 +75,7 @@ protected OutgoingResourceCertificate() { publishedObject = new PublishedObject(signingKeyPair, filename, getDerEncoded(), true, parentPublicationDirectory, getValidityPeriod()); setPublicationUri(publishedObject.getUri()); } - assertValid(); + revalidateCertificate(); } public KeyPairEntity getSigningKeyPair() { @@ -81,7 +84,7 @@ public KeyPairEntity getSigningKeyPair() { public void setRequestingCertificateAuthority(@NonNull ChildCertificateAuthority requestingCertificateAuthority) { Validate.isTrue(isCurrent(), "only CURRENT certificate can have requesting child certificate authority"); - this.requestingCertificateAuthority = requestingCertificateAuthority; + this.requestingCertificateAuthority = requireNonNull(requestingCertificateAuthority); } public boolean isCurrent() { diff --git a/src/main/java/net/ripe/rpki/domain/ProductionCertificateAuthority.java b/src/main/java/net/ripe/rpki/domain/ProductionCertificateAuthority.java index 72c08d6..3ed1ee8 100644 --- a/src/main/java/net/ripe/rpki/domain/ProductionCertificateAuthority.java +++ b/src/main/java/net/ripe/rpki/domain/ProductionCertificateAuthority.java @@ -51,9 +51,4 @@ public Optional lookupCertifiableIpResources(ResourceLookupSe public ProvisioningIdentityCertificate getProvisioningIdentityCertificate() { return myDownStreamProvisioningCommunicator.getProvisioningIdentityCertificate(); } - - @Override - protected KeyPairEntity generateNewKeyPair(KeyPairService keyPairService) { - return keyPairService.createSpecialFsKeyPairEntity(); - } } diff --git a/src/main/java/net/ripe/rpki/domain/ResourceCertificate.java b/src/main/java/net/ripe/rpki/domain/ResourceCertificate.java index 2539e68..3b02c43 100644 --- a/src/main/java/net/ripe/rpki/domain/ResourceCertificate.java +++ b/src/main/java/net/ripe/rpki/domain/ResourceCertificate.java @@ -37,6 +37,7 @@ public abstract class ResourceCertificate extends EntitySupport { @Id @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seq_resourcecertificate") + @Getter private Long id; @NotNull @@ -102,19 +103,26 @@ protected void updateCertificate(X509ResourceCertificate certificate) { this.encodedSubjectPublicKey = certificate.getPublicKey().getEncoded(); this.validityPeriod = new EmbeddedValidityPeriod(certificate.getValidityPeriod()); this.encoded = certificate.getEncoded(); + revalidateCertificate(); } - @Override - public Long getId() { - return id; + protected void revalidateCertificate() { + Validate.notNull(serial); + Validate.notNull(subject); + Validate.notNull(issuer); + Validate.notNull(resourceExtension); + Validate.notNull(subjectPublicKey); + Validate.notNull(encodedSubjectPublicKey); + Validate.notNull(validityPeriod); + Validate.notNull(encoded); } - public @NonNull ImmutableResourceSet getResources() { - return resourceExtension.getResources(); + public ImmutableResourceSet getResources() { + return requireNonNull(resourceExtension.getResources()); } - public @NonNull ResourceExtension getResourceExtension() { - return resourceExtension.getResourceExtension(); + public ResourceExtension getResourceExtension() { + return requireNonNull(resourceExtension.getResourceExtension()); } public ValidityPeriod getValidityPeriod() { diff --git a/src/main/java/net/ripe/rpki/ncc/core/domain/support/EntitySupport.java b/src/main/java/net/ripe/rpki/ncc/core/domain/support/EntitySupport.java index 400c7d2..f131d5e 100755 --- a/src/main/java/net/ripe/rpki/ncc/core/domain/support/EntitySupport.java +++ b/src/main/java/net/ripe/rpki/ncc/core/domain/support/EntitySupport.java @@ -46,16 +46,4 @@ public String toString() { return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE); } - /** - * @throws IllegalStateException - * the entity validation failed. - */ - public void assertValid() { - ValidatorFactory factory = Validation.buildDefaultValidatorFactory(); - Validator validator = factory.getValidator(); - Set> result = validator.validate(this); - if (!result.isEmpty()) { - throw new IllegalStateException(result.toString()); - } - } } diff --git a/src/main/java/net/ripe/rpki/ripencc/ui/daemon/health/checks/CertificateRepositoryUpToDateHealthCheck.java b/src/main/java/net/ripe/rpki/ripencc/ui/daemon/health/checks/CertificateRepositoryUpToDateHealthCheck.java deleted file mode 100644 index 7392801..0000000 --- a/src/main/java/net/ripe/rpki/ripencc/ui/daemon/health/checks/CertificateRepositoryUpToDateHealthCheck.java +++ /dev/null @@ -1,44 +0,0 @@ -package net.ripe.rpki.ripencc.ui.daemon.health.checks; - -import net.ripe.rpki.ripencc.ui.daemon.health.Health; -import net.ripe.rpki.server.api.configuration.RepositoryConfiguration; -import org.joda.time.DateTime; -import org.joda.time.Duration; -import org.joda.time.Period; -import org.joda.time.format.PeriodFormat; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -import java.io.File; - -@Component -public class CertificateRepositoryUpToDateHealthCheck extends Health.Check { - // if there is no user activity, repository only updates every 8 hours - public static final Duration MAXIMUM_TIME_FOR_REPO_UPDATES = - Duration.standardHours(8).plus(Duration.standardMinutes(5)); - - private final RepositoryConfiguration configuration; - - @Autowired - public CertificateRepositoryUpToDateHealthCheck(RepositoryConfiguration configuration) { - super("certificate-repository-uptodate"); - this.configuration = configuration; - } - - @Override - public Health.Status check() { - final File localRepositoryDirectory = configuration.getLocalRepositoryDirectory(); - final File publishedDir = new File(localRepositoryDirectory.getAbsolutePath() + "/published"); - final DateTime lastModified = new DateTime(publishedDir.lastModified()); - if (lastModified.plus(MAXIMUM_TIME_FOR_REPO_UPDATES).isAfterNow()) { - return Health.ok(humanFriendly(lastModified)); - } - return Health.error(humanFriendly(lastModified)); - } - - private String humanFriendly(DateTime lastUpdateTime) { - return String.format("last updated %s ago (at %s)", - new Period(lastUpdateTime, new DateTime()).withMillis(0).toString(PeriodFormat.getDefault()), - lastUpdateTime); - } -} diff --git a/src/main/java/net/ripe/rpki/services/impl/KeyPairServiceBean.java b/src/main/java/net/ripe/rpki/services/impl/KeyPairServiceBean.java index 0bdb402..1ff6b95 100644 --- a/src/main/java/net/ripe/rpki/services/impl/KeyPairServiceBean.java +++ b/src/main/java/net/ripe/rpki/services/impl/KeyPairServiceBean.java @@ -36,11 +36,6 @@ public KeyPairEntity createKeyPairEntity() { return getKeyPairEntity(hardwareKeyPairFactory.get(), createSignInfo()); } - @Override - public KeyPairEntity createSpecialFsKeyPairEntity() { - return getKeyPairEntity(hardwareKeyPairFactory.getFsKey(), createFsSignInfo()); - } - private KeyPairEntity getKeyPairEntity(KeyPair keyPair, KeyPairEntitySignInfo signInfo) { String crlFilename = namingStrategy.crlFileName(keyPair); String manifestFilename = namingStrategy.manifestFileName(keyPair); @@ -60,12 +55,4 @@ private KeyPairEntitySignInfo createSignInfo() { providerConfiguration.getSignatureProvider(), providerConfiguration.getKeyStoreType()); } - - private KeyPairEntitySignInfo createFsSignInfo() { - return new KeyPairEntitySignInfo( - providerConfiguration.getFsKeyStoreProvider(), - providerConfiguration.getFsSignatureProvider(), - providerConfiguration.getFsKeyStoreType()); - } - } diff --git a/src/main/java/net/ripe/rpki/services/impl/handlers/KeyManagementInitiateRollCommandHandler.java b/src/main/java/net/ripe/rpki/services/impl/handlers/KeyManagementInitiateRollCommandHandler.java index eea8986..713a8b4 100644 --- a/src/main/java/net/ripe/rpki/services/impl/handlers/KeyManagementInitiateRollCommandHandler.java +++ b/src/main/java/net/ripe/rpki/services/impl/handlers/KeyManagementInitiateRollCommandHandler.java @@ -16,7 +16,9 @@ import net.ripe.rpki.server.api.services.command.CommandWithoutEffectException; import javax.inject.Inject; +import java.util.ArrayList; import java.util.Collections; +import java.util.List; import static net.ripe.rpki.domain.Resources.DEFAULT_RESOURCE_CLASS; @@ -80,9 +82,9 @@ public void handle(KeyManagementInitiateRollCommand command, CommandStatus comma } private void handleForAllResourcesCa(AllResourcesCertificateAuthority ca, CertificateIssuanceRequest request) { - ca.setUpStreamCARequestEntity(new UpStreamCARequestEntity(ca, certificationRequestCreationService.createTrustAnchorRequest( - Collections.singletonList(toTaRequests(request)) - ))); + List signingRequests = new ArrayList<>(Collections.singletonList(toTaRequests(request))); + ca.setUpStreamCARequestEntity(new UpStreamCARequestEntity(ca, + certificationRequestCreationService.createTrustAnchorRequest(signingRequests))); } private void handleForManagedCertificateAuthority(ManagedCertificateAuthority ca, CertificateIssuanceRequest request) { diff --git a/src/main/java/net/ripe/rpki/web/UpstreamCaController.java b/src/main/java/net/ripe/rpki/web/UpstreamCaController.java index 2718abe..867e181 100644 --- a/src/main/java/net/ripe/rpki/web/UpstreamCaController.java +++ b/src/main/java/net/ripe/rpki/web/UpstreamCaController.java @@ -38,10 +38,11 @@ public class UpstreamCaController extends BaseController { public static final String UPSTREAM_CA = "upstream-ca"; - public static final String PAGE_TYPE = "pageType"; + public static final String REQUEST_HANDLING = "requestHandling"; public static final String ACA_KEY_STATUS = "acaKeyStatus"; public static final String ADMIN_INDEX_PAGE = "admin/index"; public static final String ACTIVE_NODE_FORM = "activeNodeForm"; + public static final String ERROR = "error"; private final CertificateAuthorityViewService certificateAuthorityViewService; private final CommandService commandService; @@ -75,12 +76,17 @@ public ModelAndView upstreamCa() { var overallStatus = overallKeyPairLifeCyclePhase(allResourcesCa); model.put(ACA_KEY_STATUS, overallStatus.map(x -> x.name().toLowerCase(Locale.ROOT)).orElse("new")); if (allResourcesCa.getTrustAnchorRequest() == null) { - model.put(PAGE_TYPE, "create-request"); + // Only show "generate request" when there are no key pair in PENDING or OLD state, + // trying to generate yet another one will mess things up + if (!hasKeyWithStatus(allResourcesCa, KeyPairStatus.PENDING) && + !hasKeyWithStatus(allResourcesCa, KeyPairStatus.OLD)) { + model.put(REQUEST_HANDLING, "create-request"); + } } else { // Do not show any extra key life-cycle buttons to avoid // clicking wrong button when uploading TA response. model.put(ACA_KEY_STATUS, "none"); - model.put(PAGE_TYPE, "download-request"); + model.put(REQUEST_HANDLING, "download-request"); model.put("requestFileName", getRequestFileName(allResourcesCa.getTrustAnchorRequest())); } return new ModelAndView("admin/upstream-ca", model); @@ -101,8 +107,8 @@ public Object downloadSignRequest() { if (allResourcesCa == null || allResourcesCa.getTrustAnchorRequest() == null) { final ActiveNodeForm node = new ActiveNodeForm(activeNodeService.getActiveNodeName()); return new ModelAndView(ADMIN_INDEX_PAGE, HttpStatus.NOT_FOUND) - .addObject("error", "All Resources CA or signing request do not exist.") - .addObject("activeNodeForm", node); + .addObject(ERROR, "All Resources CA or signing request do not exist.") + .addObject(ACTIVE_NODE_FORM, node); } final TrustAnchorRequest taRequest = allResourcesCa.getTrustAnchorRequest(); @@ -132,16 +138,16 @@ public Object uploadSignResponse(@RequestParam("response") MultipartFile file, R } catch (Exception e) { log.error("Could not upload response", e); final ActiveNodeForm node = new ActiveNodeForm(activeNodeService.getActiveNodeName()); - return new ModelAndView("admin/index", HttpStatus.NOT_FOUND) - .addObject("error", "Could not upload/process response, " + e.getMessage()) - .addObject("activeNodeForm", node); + return new ModelAndView(ADMIN_INDEX_PAGE, HttpStatus.NOT_FOUND) + .addObject(ERROR, "Could not upload/process response, " + e.getMessage()) + .addObject(ACTIVE_NODE_FORM, node); } } @PostMapping({"/revoke-old-aca-key"}) public Object revokeOldAcaKey() { return withAllResourcesCa(allResourcesCa -> - ifNoTaRequest(allResourcesCa, () -> { + requireACAState(allResourcesCa, KeyPairStatus.OLD, () -> { commandService.execute(new KeyManagementRevokeOldKeysCommand(allResourcesCa.getVersionedId())); return new RedirectView(UPSTREAM_CA, true); })); @@ -150,7 +156,7 @@ public Object revokeOldAcaKey() { @PostMapping({"/activate-pending-aca-key"}) public Object activateAcaPendingKey() { return withAllResourcesCa(allResourcesCa -> - ifNoTaRequest(allResourcesCa, () -> { + requireACAState(allResourcesCa, KeyPairStatus.PENDING, () -> { commandService.execute(KeyManagementActivatePendingKeysCommand.manualActivationCommand(allResourcesCa.getVersionedId())); allCaCertificateUpdateServiceBean.execute(Collections.emptyMap()); return new RedirectView(UPSTREAM_CA, true); @@ -160,7 +166,7 @@ public Object activateAcaPendingKey() { @PostMapping({"/initiate-rolling-aca-key"}) public Object initiateRollingAcaKey() { return withAllResourcesCa(allResourcesCa -> - ifNoTaRequest(allResourcesCa, () -> { + requireACAState(allResourcesCa, KeyPairStatus.CURRENT, () -> { commandService.execute(new KeyManagementInitiateRollCommand(allResourcesCa.getVersionedId(), 0)); return new RedirectView(UPSTREAM_CA, true); })); @@ -170,25 +176,39 @@ private Object withAllResourcesCa(Function f) { + private Object requireACAState(CertificateAuthorityData allResourcesCa, KeyPairStatus requiredStatus, Supplier f) { if (allResourcesCa.getTrustAnchorRequest() != null) { final ActiveNodeForm node = new ActiveNodeForm(activeNodeService.getActiveNodeName()); - return new ModelAndView("admin/index", HttpStatus.BAD_REQUEST) - .addObject("error", "All resources CA already has a TA request, it must be processed first.") - .addObject("activeNodeForm", node); + return new ModelAndView(ADMIN_INDEX_PAGE, HttpStatus.BAD_REQUEST) + .addObject(ERROR, "All resources CA already has a TA request, it must be processed first.") + .addObject(ACTIVE_NODE_FORM, node); + } else { + var overallStatus = overallKeyPairLifeCyclePhase((ManagedCertificateAuthorityData) allResourcesCa); + if (overallStatus.isEmpty()) { + return f.get(); + } + if (overallStatus.get() != requiredStatus) { + // The status of the ACA keypair cannot be processed here + final ActiveNodeForm node = new ActiveNodeForm(activeNodeService.getActiveNodeName()); + var errorMessage = String.format("All resources CA keypair having status %s is present, " + + "but expected status is %s.", overallStatus.get(), requiredStatus); + return new ModelAndView(ADMIN_INDEX_PAGE, HttpStatus.BAD_REQUEST) + .addObject(ERROR, errorMessage) + .addObject(ACTIVE_NODE_FORM, node); + } } return f.get(); } @@ -209,6 +229,10 @@ private Optional overallKeyPairLifeCyclePhase(ManagedCertificateA .or(() -> keyWithStatus(keys, KeyPairStatus.CURRENT)); } + private boolean hasKeyWithStatus(ManagedCertificateAuthorityData allResourcesCa, KeyPairStatus expectedStatus) { + return keyWithStatus(allResourcesCa.getKeys(), expectedStatus).isPresent(); + } + private Optional keyWithStatus(Collection keys, KeyPairStatus expectedStatus) { return keys.stream() .map(KeyPairData::getStatus) diff --git a/src/main/resources/WEB-INF/templates/admin/upstream-ca.html b/src/main/resources/WEB-INF/templates/admin/upstream-ca.html index 8657882..e3e05e9 100644 --- a/src/main/resources/WEB-INF/templates/admin/upstream-ca.html +++ b/src/main/resources/WEB-INF/templates/admin/upstream-ca.html @@ -16,7 +16,7 @@ error messages -
+
diff --git a/src/main/resources/application-prepdev.properties b/src/main/resources/application-prepdev.properties index 32f65bb..67dd362 100644 --- a/src/main/resources/application-prepdev.properties +++ b/src/main/resources/application-prepdev.properties @@ -37,11 +37,6 @@ keypair.generator.provider=DBProvider signature.provider=DBProvider keystore.type=nCipher.database -fs.keystore.provider=nCipherKM -fs.keypair.generator.provider=nCipherKM -fs.signature.provider=nCipherKM -fs.keystore.type=ncipher.sworld - # Remote Services # Internet Resource Backend diff --git a/src/main/resources/logback/logback-production.xml b/src/main/resources/logback/logback-production.xml index a9ac03d..3c68981 100644 --- a/src/main/resources/logback/logback-production.xml +++ b/src/main/resources/logback/logback-production.xml @@ -17,7 +17,7 @@ - ../logs/certification-jsonl + ../logs/certification.jsonl ../logs/certification.jsonl.%d{yyyy-MM-dd} diff --git a/src/test/java/net/ripe/rpki/ripencc/ui/daemon/health/HealthChecksTest.java b/src/test/java/net/ripe/rpki/ripencc/ui/daemon/health/HealthChecksTest.java index 7529aa1..7ce4e7b 100644 --- a/src/test/java/net/ripe/rpki/ripencc/ui/daemon/health/HealthChecksTest.java +++ b/src/test/java/net/ripe/rpki/ripencc/ui/daemon/health/HealthChecksTest.java @@ -21,6 +21,6 @@ public class HealthChecksTest { @Test public void checkRegistered() { - assertThat(subject.getChecks().size()).isEqualTo(6); + assertThat(subject.getChecks().size()).isEqualTo(5); } -} \ No newline at end of file +} diff --git a/src/test/java/net/ripe/rpki/web/UpstreamCaControllerTest.java b/src/test/java/net/ripe/rpki/web/UpstreamCaControllerTest.java index f4a90d8..51a3a08 100644 --- a/src/test/java/net/ripe/rpki/web/UpstreamCaControllerTest.java +++ b/src/test/java/net/ripe/rpki/web/UpstreamCaControllerTest.java @@ -96,7 +96,7 @@ public void should_show_upstream_no_sign_request() throws Exception { assertThat(result.getResponse().getStatus()).isEqualTo(HttpStatus.OK.value()); assertThat(result.getModelAndView()).isNotNull(); Map model = result.getModelAndView().getModel(); - assertThat(model).extractingByKey("pageType").isEqualTo("create-request"); + assertThat(model).extractingByKey("requestHandling").isEqualTo("create-request"); assertThat(result.getResponse().getContentAsString()).contains(""); } @@ -112,7 +112,7 @@ public void should_show_upstream_sign_request_exists() throws Exception { assertThat(result.getResponse().getStatus()).isEqualTo(HttpStatus.OK.value()); assertThat(result.getModelAndView()).isNotNull(); Map model = result.getModelAndView().getModel(); - assertThat(model).extractingByKey("pageType").isEqualTo("download-request"); + assertThat(model).extractingByKey("requestHandling").isEqualTo("download-request"); assertThat(model).extractingByKey("requestFileName").isEqualTo("request-19700101-000000.xml"); assertThat(result.getResponse().getContentAsString()).contains("
Generate signing requestGenerate signing requestDownload signing request");