From 414f4542684b0f25abe9e4f0b5792945c70e26e3 Mon Sep 17 00:00:00 2001 From: lubomirw Date: Thu, 21 Nov 2024 15:13:02 +0100 Subject: [PATCH 1/2] Add validation to prevent issuing certificate with disabled RA profile --- .../core/service/v2/impl/ClientOperationServiceImpl.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/main/java/com/czertainly/core/service/v2/impl/ClientOperationServiceImpl.java b/src/main/java/com/czertainly/core/service/v2/impl/ClientOperationServiceImpl.java index f18ff070..9c04a15a 100644 --- a/src/main/java/com/czertainly/core/service/v2/impl/ClientOperationServiceImpl.java +++ b/src/main/java/com/czertainly/core/service/v2/impl/ClientOperationServiceImpl.java @@ -194,6 +194,14 @@ public CertificateDetailDto submitCertificateRequest(ClientCertificateRequestDto @Transactional(Transactional.TxType.NOT_SUPPORTED) @ExternalAuthorization(resource = Resource.RA_PROFILE, action = ResourceAction.DETAIL, parentResource = Resource.AUTHORITY, parentAction = ResourceAction.DETAIL) public ClientCertificateDataResponseDto issueCertificate(final SecuredParentUUID authorityUuid, final SecuredUUID raProfileUuid, final ClientCertificateSignRequestDto request, final CertificateProtocolInfo protocolInfo) throws NotFoundException, CertificateException, NoSuchAlgorithmException, CertificateOperationException, CertificateRequestException { + // validate RA profile + RaProfile raProfile = raProfileRepository.findByUuidAndEnabledIsTrue(raProfileUuid.getValue()) + .orElseThrow(() -> new NotFoundException(RaProfile.class, raProfileUuid)); + + if (Boolean.FALSE.equals(raProfile.getEnabled())) { + throw new ValidationException(String.format("Cannot issue certificate with disabled RA profile. Ra Profile: %s", raProfile.getName())); + } + ClientCertificateRequestDto certificateRequestDto = new ClientCertificateRequestDto(); certificateRequestDto.setRaProfileUuid(raProfileUuid.getValue()); certificateRequestDto.setCsrAttributes(request.getCsrAttributes()); From 1290595e098de063204b6ccbf43c2cabb6e97b35 Mon Sep 17 00:00:00 2001 From: lubomirw Date: Thu, 21 Nov 2024 16:49:04 +0100 Subject: [PATCH 2/2] Add and enable certificate issuing tests --- .../v2/impl/ClientOperationServiceImpl.java | 2 +- .../service/ClientOperationServiceV2Test.java | 62 +++++++++++++++---- 2 files changed, 50 insertions(+), 14 deletions(-) diff --git a/src/main/java/com/czertainly/core/service/v2/impl/ClientOperationServiceImpl.java b/src/main/java/com/czertainly/core/service/v2/impl/ClientOperationServiceImpl.java index 9c04a15a..0ba699fe 100644 --- a/src/main/java/com/czertainly/core/service/v2/impl/ClientOperationServiceImpl.java +++ b/src/main/java/com/czertainly/core/service/v2/impl/ClientOperationServiceImpl.java @@ -195,7 +195,7 @@ public CertificateDetailDto submitCertificateRequest(ClientCertificateRequestDto @ExternalAuthorization(resource = Resource.RA_PROFILE, action = ResourceAction.DETAIL, parentResource = Resource.AUTHORITY, parentAction = ResourceAction.DETAIL) public ClientCertificateDataResponseDto issueCertificate(final SecuredParentUUID authorityUuid, final SecuredUUID raProfileUuid, final ClientCertificateSignRequestDto request, final CertificateProtocolInfo protocolInfo) throws NotFoundException, CertificateException, NoSuchAlgorithmException, CertificateOperationException, CertificateRequestException { // validate RA profile - RaProfile raProfile = raProfileRepository.findByUuidAndEnabledIsTrue(raProfileUuid.getValue()) + RaProfile raProfile = raProfileRepository.findByUuid(raProfileUuid.getValue()) .orElseThrow(() -> new NotFoundException(RaProfile.class, raProfileUuid)); if (Boolean.FALSE.equals(raProfile.getEnabled())) { diff --git a/src/test/java/com/czertainly/core/service/ClientOperationServiceV2Test.java b/src/test/java/com/czertainly/core/service/ClientOperationServiceV2Test.java index 3f9f6e5c..f804387d 100644 --- a/src/test/java/com/czertainly/core/service/ClientOperationServiceV2Test.java +++ b/src/test/java/com/czertainly/core/service/ClientOperationServiceV2Test.java @@ -19,8 +19,6 @@ import com.czertainly.core.dao.entity.*; import com.czertainly.core.dao.entity.Certificate; import com.czertainly.core.dao.repository.*; -import com.czertainly.core.model.request.CertificateRequest; -import com.czertainly.core.model.request.CrmfCertificateRequest; import com.czertainly.core.security.authz.SecuredParentUUID; import com.czertainly.core.security.authz.SecuredUUID; import com.czertainly.core.service.v2.ClientOperationService; @@ -28,17 +26,15 @@ import com.czertainly.core.util.BaseSpringBootTest; import com.github.tomakehurst.wiremock.WireMockServer; import com.github.tomakehurst.wiremock.client.WireMock; -import org.bouncycastle.asn1.crmf.CertReqMsg; -import org.bouncycastle.asn1.crmf.CertRequest; import org.bouncycastle.asn1.x500.X500Name; import org.bouncycastle.cert.crmf.CRMFException; -import org.bouncycastle.cert.crmf.CertificateRequestMessage; import org.bouncycastle.cert.crmf.jcajce.JcaCertificateRequestMessageBuilder; import org.bouncycastle.operator.OperatorCreationException; import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; import org.junit.jupiter.api.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.transaction.TestTransaction; import java.io.IOException; import java.io.InputStream; @@ -85,6 +81,8 @@ public class ClientOperationServiceV2Test extends BaseSpringBootTest { @Autowired private CertificateRepository certificateRepository; @Autowired + private CertificateEventHistoryRepository certificateEventHistoryRepository; + @Autowired private CertificateContentRepository certificateContentRepository; private RaProfile raProfile; @@ -206,7 +204,10 @@ public void testValidateIssueCertificateAttributes_validationFail() { @Test - public void testIssueCertificate() throws ConnectorException, CertificateException, AlreadyExistException, NoSuchAlgorithmException, CertificateOperationException, IOException, InvalidKeyException { + public void testIssueCertificate() throws ConnectorException, CertificateException, AlreadyExistException, NoSuchAlgorithmException, CertificateOperationException, IOException, InvalidKeyException, CertificateRequestException { + TestTransaction.flagForCommit(); + TestTransaction.end(); + String certificateData = Base64.getEncoder().encodeToString(x509Cert.getEncoded()); mockServer.stubFor(WireMock .post(WireMock.urlPathMatching("/v2/authorityProvider/authorities/[^/]+/certificates/issue")) @@ -221,13 +222,21 @@ public void testIssueCertificate() throws ConnectorException, CertificateExcepti ClientCertificateSignRequestDto request = new ClientCertificateSignRequestDto(); request.setRequest(SAMPLE_PKCS10); request.setAttributes(List.of()); -// clientOperationService.issueCertificate(authorityInstanceReference.getSecuredParentUuid(), raProfile.getSecuredUuid(), request); + clientOperationService.issueCertificate(authorityInstanceReference.getSecuredParentUuid(), raProfile.getSecuredUuid(), request, null); + + setUpCommitedCleanup(); } - @Disabled @Test - public void testIssueCertificate_validationFail() { - Assertions.assertThrows(NotFoundException.class, () -> clientOperationService.issueCertificate(SecuredParentUUID.fromUUID(raProfile.getAuthorityInstanceReferenceUuid()), SecuredUUID.fromString("abfbc322-29e1-11ed-a261-0242ac120002"), null, null)); + public void testIssueCertificate_validationFail_disabledRaProfile() { + TestTransaction.flagForCommit(); + TestTransaction.end(); + + raProfile.setEnabled(false); + raProfile = raProfileRepository.save(raProfile); + Assertions.assertThrows(ValidationException.class, () -> clientOperationService.issueCertificate(SecuredParentUUID.fromUUID(raProfile.getAuthorityInstanceReferenceUuid()),raProfile.getSecuredUuid(), null, null)); + + setUpCommitedCleanup(); } @Test @@ -243,10 +252,22 @@ public void testRenewCertificate() throws ConnectorException, CertificateExcepti // Assertions.assertThrows(ValidationException.class, () -> clientOperationService.renewCertificateAction(SecuredParentUUID.fromUUID(raProfile.getAuthorityInstanceReferenceUuid()), raProfile.getSecuredUuid(), certificate.getUuid().toString(), request)); } - @Disabled @Test - public void testRenewCertificate_validationFail() { - Assertions.assertThrows(NotFoundException.class, () -> clientOperationService.renewCertificate(SecuredParentUUID.fromUUID(raProfile.getAuthorityInstanceReferenceUuid()), SecuredUUID.fromString("abfbc322-29e1-11ed-a261-0242ac120002"), null, null)); + public void testRenewCertificate_validationFail_differentRaProfile() { + RaProfile raProfile2 = new RaProfile(); + raProfile2.setName("testraprofile2"); + raProfile2.setAuthorityInstanceReference(authorityInstanceReference); + raProfile2.setAuthorityInstanceReferenceUuid(authorityInstanceReference.getUuid()); + raProfile2.setEnabled(true); + raProfileRepository.save(raProfile2); + + TestTransaction.flagForCommit(); + TestTransaction.end(); + + Assertions.assertThrows(ValidationException.class, () -> clientOperationService.renewCertificate(SecuredParentUUID.fromUUID(raProfile2.getAuthorityInstanceReferenceUuid()), raProfile2.getSecuredUuid(), certificate.getUuid().toString(), null)); + + raProfileRepository.delete(raProfile2); + setUpCommitedCleanup(); } @Test @@ -302,6 +323,21 @@ public void testRevokeCertificate_validationFail() { Assertions.assertThrows(NotFoundException.class, () -> clientOperationService.revokeCertificateAction(UUID.randomUUID(), null, true)); } + private void setUpCommitedCleanup() { + TestTransaction.start(); + + attributeEngine.deleteConnectorAttributeDefinitionsContent(connector.getUuid()); + + certificateEventHistoryRepository.deleteAll(); + certificateRepository.deleteAll(); + raProfileRepository.delete(raProfile); + authorityInstanceReferenceRepository.delete(authorityInstanceReference); + connectorRepository.delete(connector); + + TestTransaction.flagForCommit(); + TestTransaction.end(); + } + private static byte[] generateRequestWithPOPSig( BigInteger certReqID, KeyPair kp, String sigAlg) throws OperatorCreationException, CRMFException, IOException { X500Name subject = new X500Name("CN=Example");