diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 1d4ad42cd..6bb8cce4b 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -58,4 +58,4 @@ jobs:
- name: Build
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any
- run: mvn -B verify
+ run: mvn -B -U verify
diff --git a/pom.xml b/pom.xml
index 4166b7fca..64405fb69 100644
--- a/pom.xml
+++ b/pom.xml
@@ -10,7 +10,7 @@
core
- 2.13.0
+ 2.13.1
CZERTAINLY-Core
@@ -31,14 +31,14 @@
io.opentelemetry
opentelemetry-bom
- 1.41.0
+ 1.42.1
pom
import
io.opentelemetry.instrumentation
opentelemetry-instrumentation-bom
- 2.7.0
+ 2.8.0
pom
import
@@ -49,7 +49,7 @@
com.czertainly
interfaces
- 2.13.0
+ 2.13.1
diff --git a/prebuild_image_script b/prebuild_image_script
index 588526c56..c0762d3ea 100755
--- a/prebuild_image_script
+++ b/prebuild_image_script
@@ -16,9 +16,9 @@ docker build -f Dockerfile-pre -t prebuild .
echo "MVN Build"
if [[ "$OSTYPE" == "darwin"* ]]; then
echo "MacOS detected, using TESTCONTAINERS_HOST_OVERRIDE"
- docker run -e TESTCONTAINERS_HOST_OVERRIDE=docker.for.mac.host.internal -v /var/run/docker.sock:/var/run/docker.sock --name czertainlycont -i prebuild mvn -f /home/app/pom.xml clean package
+ docker run -e TESTCONTAINERS_HOST_OVERRIDE=docker.for.mac.host.internal -v /var/run/docker.sock:/var/run/docker.sock --name czertainlycont -i prebuild mvn -f /home/app/pom.xml -U clean package
else
- docker run -v /var/run/docker.sock:/var/run/docker.sock --name czertainlycont -i prebuild mvn -f /home/app/pom.xml clean package
+ docker run -v /var/run/docker.sock:/var/run/docker.sock --name czertainlycont -i prebuild mvn -f /home/app/pom.xml -U clean package
fi
echo "Starting czertainlycont"
diff --git a/src/main/java/com/czertainly/core/api/ExceptionHandlingAdvice.java b/src/main/java/com/czertainly/core/api/ExceptionHandlingAdvice.java
index b8463b107..352722777 100644
--- a/src/main/java/com/czertainly/core/api/ExceptionHandlingAdvice.java
+++ b/src/main/java/com/czertainly/core/api/ExceptionHandlingAdvice.java
@@ -458,6 +458,17 @@ public ErrorMessageDto handleCertificateRequestException(CertificateRequestExcep
return ErrorMessageDto.getInstance(ex.getMessage() + cause);
}
+ /**
+ * Handler for {@link NotSupportedException}.
+ *
+ * @return {@link ErrorMessageDto}
+ */
+ @ExceptionHandler(NotSupportedException.class)
+ @ResponseStatus(HttpStatus.NOT_IMPLEMENTED)
+ public ErrorMessageDto handleTokenInstanceException(NotSupportedException ex) {
+ LOG.debug("HTTP 501: {}", ex.getMessage());
+ return ErrorMessageDto.getInstance(ex.getMessage());
+ }
/**
* Handler for {@link Exception}.
diff --git a/src/main/java/com/czertainly/core/api/web/CertificateControllerImpl.java b/src/main/java/com/czertainly/core/api/web/CertificateControllerImpl.java
index c243a72ff..82a35a993 100644
--- a/src/main/java/com/czertainly/core/api/web/CertificateControllerImpl.java
+++ b/src/main/java/com/czertainly/core/api/web/CertificateControllerImpl.java
@@ -81,8 +81,11 @@ public void updateCertificateObjects(String uuid, CertificateUpdateObjectsDto re
}
@Override
- public void bulkUpdateCertificateObjects(MultipleCertificateObjectUpdateDto request) throws NotFoundException {
- certificateService.bulkUpdateCertificateObjects(SecurityFilter.create(), request);
+ public void bulkUpdateCertificateObjects(MultipleCertificateObjectUpdateDto request) throws NotFoundException, NotSupportedException {
+ if (request.getFilters() != null && !request.getFilters().isEmpty() && (request.getCertificateUuids() == null || request.getCertificateUuids().isEmpty())) {
+ throw new NotSupportedException("Bulk updating of certificates by filters is not supported.");
+ }
+ certificateService.bulkUpdateCertificatesObjects(SecurityFilter.create(), request);
}
@Override
@@ -100,9 +103,12 @@ public ResponseEntity upload(@RequestBody UploadCertificateRequestDto r
}
@Override
- public BulkOperationResponse bulkDeleteCertificate(@RequestBody RemoveCertificateDto request) throws NotFoundException {
- certificateService.bulkDeleteCertificate(SecurityFilter.create(), request);
+ public BulkOperationResponse bulkDeleteCertificate(@RequestBody RemoveCertificateDto request) throws NotFoundException, NotSupportedException {
BulkOperationResponse response = new BulkOperationResponse();
+ if (request.getFilters() != null && !request.getFilters().isEmpty() && (request.getUuids() == null || request.getUuids().isEmpty())) {
+ throw new NotSupportedException("Bulk delete of certificates by filters is not supported.");
+ }
+ certificateService.bulkDeleteCertificate(SecurityFilter.create(), request);
response.setMessage("Initiated bulk delete Certificates. Please refresh after some time");
response.setStatus(BulkOperationStatus.SUCCESS);
return response;
diff --git a/src/main/java/com/czertainly/core/api/web/DiscoveryControllerImpl.java b/src/main/java/com/czertainly/core/api/web/DiscoveryControllerImpl.java
index 081393127..150d53a1e 100644
--- a/src/main/java/com/czertainly/core/api/web/DiscoveryControllerImpl.java
+++ b/src/main/java/com/czertainly/core/api/web/DiscoveryControllerImpl.java
@@ -9,12 +9,12 @@
import com.czertainly.api.model.client.discovery.DiscoveryHistoryDetailDto;
import com.czertainly.api.model.common.UuidDto;
import com.czertainly.api.model.core.scheduler.ScheduleDiscoveryDto;
+import com.czertainly.api.model.core.scheduler.ScheduledJobDetailDto;
import com.czertainly.api.model.core.search.SearchFieldDataByGroupDto;
-import com.czertainly.core.dao.entity.ScheduledJob;
-import com.czertainly.core.dao.repository.ScheduledJobsRepository;
import com.czertainly.core.security.authz.SecuredUUID;
import com.czertainly.core.security.authz.SecurityFilter;
import com.czertainly.core.service.DiscoveryService;
+import com.czertainly.core.service.SchedulerService;
import com.czertainly.core.tasks.DiscoveryCertificateTask;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -36,9 +36,17 @@ public class DiscoveryControllerImpl implements DiscoveryController {
private DiscoveryService discoveryService;
- private ScheduledJobsRepository scheduledJobsRepository;
+ private SchedulerService schedulerService;
- private DiscoveryCertificateTask discoveryCertificateTask;
+ @Autowired
+ public void setSchedulerService(SchedulerService schedulerService) {
+ this.schedulerService = schedulerService;
+ }
+
+ @Autowired
+ public void setDiscoveryService(DiscoveryService discoveryService) {
+ this.discoveryService = discoveryService;
+ }
@Override
public DiscoveryResponseDto listDiscoveries(final SearchRequestDto request) {
@@ -91,7 +99,7 @@ public ResponseEntity> scheduleDiscovery(final ScheduleDiscoveryDto scheduleDi
jobName = scheduleDiscoveryDto.getJobName();
}
- ScheduledJob scheduledJob = discoveryCertificateTask.registerScheduler(jobName, scheduleDiscoveryDto.getCronExpression(), scheduleDiscoveryDto.isOneTime(), scheduleDiscoveryDto.getRequest());
+ ScheduledJobDetailDto scheduledJob = schedulerService.registerScheduledJob(DiscoveryCertificateTask.class, jobName, scheduleDiscoveryDto.getCronExpression(), scheduleDiscoveryDto.isOneTime(), scheduleDiscoveryDto.getRequest());
logger.info("Job {} was registered.", jobName);
// TODO: construct location URI differently without hardcoded path
@@ -120,20 +128,4 @@ public List getSearchableFieldInformation() {
return discoveryService.getSearchableFieldInformationByGroup();
}
- // SETTERs
-
- @Autowired
- public void setDiscoveryService(DiscoveryService discoveryService) {
- this.discoveryService = discoveryService;
- }
-
- @Autowired
- public void setScheduledJobsRepository(ScheduledJobsRepository scheduledJobsRepository) {
- this.scheduledJobsRepository = scheduledJobsRepository;
- }
-
- @Autowired
- public void setDiscoveryCertificateTask(DiscoveryCertificateTask discoveryCertificateTask) {
- this.discoveryCertificateTask = discoveryCertificateTask;
- }
}
diff --git a/src/main/java/com/czertainly/core/attribute/engine/AttributeEngine.java b/src/main/java/com/czertainly/core/attribute/engine/AttributeEngine.java
index 252d7278e..ff61ac582 100644
--- a/src/main/java/com/czertainly/core/attribute/engine/AttributeEngine.java
+++ b/src/main/java/com/czertainly/core/attribute/engine/AttributeEngine.java
@@ -478,6 +478,20 @@ public List getDefinitionObjectAttributeContent(AttributeType att
return mapping.values().stream().toList();
}
+ public void registerAttributeContentItems(UUID attributeDefinitionUuid, Collection attributeContentItems) {
+ for (BaseAttributeContent> attributeContentItem : attributeContentItems) {
+ AttributeContentItem contentItemEntity = attributeContentItemRepository.findByJsonAndAttributeDefinitionUuid(attributeContentItem, attributeDefinitionUuid);
+
+ // check if content item for this attribute definition exists to don't create duplicate items
+ if (contentItemEntity == null) {
+ contentItemEntity = new AttributeContentItem();
+ contentItemEntity.setJson(attributeContentItem);
+ contentItemEntity.setAttributeDefinitionUuid(attributeDefinitionUuid);
+ attributeContentItemRepository.save(contentItemEntity);
+ }
+ }
+ }
+
public List getObjectCustomAttributesContent(Resource objectType, UUID objectUuid) {
logger.debug("Getting the custom attributes for {} with UUID: {}", objectType.getLabel(), objectUuid);
SecurityResourceFilter securityResourceFilter = loadCustomAttributesSecurityResourceFilter();
@@ -839,14 +853,11 @@ private void createObjectAttributeContent(AttributeDefinition attributeDefinitio
validateAttributeContent(attributeDefinition, attributeContentItems);
for (int i = 0; i < attributeContentItems.size(); i++) {
- AttributeContentItem contentItemEntity;
BaseAttributeContent> attributeContentItem = attributeContentItems.get(i);
- Optional contentItemEntityResponse = attributeContentItemRepository.findByJsonAndAttributeDefinitionUuid(attributeContentItem, attributeDefinition.getUuid());
+ AttributeContentItem contentItemEntity = attributeContentItemRepository.findByJsonAndAttributeDefinitionUuid(attributeContentItem, attributeDefinition.getUuid());
// check if content item for this attribute definition exists to don't create duplicate items
- if (contentItemEntityResponse.isPresent()) {
- contentItemEntity = contentItemEntityResponse.get();
-
+ if (contentItemEntity != null) {
// check if that content item is not already assigned to same object for meta attribute
// TODO: do we need to allow duplicate content items for one attribute definition? Maybe if attribute is list or do this check just for META attributes?
var aco = attributeContent2ObjectRepository.getByConnectorUuidAndAttributeContentItemUuidAndObjectTypeAndObjectUuidAndSourceObjectTypeAndSourceObjectUuid(objectAttributeContentInfo.connectorUuid(), contentItemEntity.getUuid(), objectAttributeContentInfo.objectType(), objectAttributeContentInfo.objectUuid(), objectAttributeContentInfo.sourceObjectType(), objectAttributeContentInfo.sourceObjectUuid());
diff --git a/src/main/java/com/czertainly/core/dao/entity/Certificate.java b/src/main/java/com/czertainly/core/dao/entity/Certificate.java
index b2f98ac4a..43449c4d4 100644
--- a/src/main/java/com/czertainly/core/dao/entity/Certificate.java
+++ b/src/main/java/com/czertainly/core/dao/entity/Certificate.java
@@ -90,8 +90,9 @@ public class Certificate extends UniquelyIdentifiedAndAudited implements Seriali
@Column(name = "key_usage")
private String keyUsage;
- @Column(name = "basic_constraints")
- private String basicConstraints;
+ @Column(name = "subject_type", nullable = false)
+ @Enumerated(EnumType.STRING)
+ private CertificateSubjectType subjectType = CertificateSubjectType.END_ENTITY;
@Column(name = "state")
@Enumerated(EnumType.STRING)
@@ -211,7 +212,7 @@ public CertificateDetailDto mapToDto() {
dto.setIssuerDn(issuerDn);
dto.setNotBefore(notBefore);
dto.setNotAfter(notAfter);
- dto.setBasicConstraints(basicConstraints);
+ dto.setSubjectType(subjectType);
dto.setExtendedKeyUsage(MetaDefinitions.deserializeArrayString(extendedKeyUsage));
dto.setKeyUsage(MetaDefinitions.deserializeArrayString(keyUsage));
dto.setFingerprint(fingerprint);
diff --git a/src/main/java/com/czertainly/core/dao/entity/ScheduledJob.java b/src/main/java/com/czertainly/core/dao/entity/ScheduledJob.java
index 77c79def5..b84e88b93 100644
--- a/src/main/java/com/czertainly/core/dao/entity/ScheduledJob.java
+++ b/src/main/java/com/czertainly/core/dao/entity/ScheduledJob.java
@@ -21,7 +21,7 @@
@RequiredArgsConstructor
@Entity
@Table(name = "scheduled_job")
-public class ScheduledJob extends UniquelyIdentified{
+public class ScheduledJob extends UniquelyIdentified {
@Column(name = "job_name")
private String jobName;
@@ -61,7 +61,7 @@ public ScheduledJobDetailDto mapToDetailDto(ScheduledJobHistory latestHistory) {
dto.setEnabled(this.enabled);
dto.setSystem(this.system);
dto.setOneTime(this.oneTime);
- if(latestHistory != null) dto.setLastExecutionStatus(latestHistory.getSchedulerExecutionStatus());
+ if (latestHistory != null) dto.setLastExecutionStatus(latestHistory.getSchedulerExecutionStatus());
return dto;
}
@@ -75,7 +75,7 @@ public ScheduledJobDto mapToDto(ScheduledJobHistory latestHistory) {
dto.setEnabled(this.enabled);
dto.setOneTime(this.oneTime);
dto.setSystem(this.system);
- if(latestHistory != null) dto.setLastExecutionStatus(latestHistory.getSchedulerExecutionStatus());
+ if (latestHistory != null) dto.setLastExecutionStatus(latestHistory.getSchedulerExecutionStatus());
return dto;
}
diff --git a/src/main/java/com/czertainly/core/dao/repository/AttributeContentItemRepository.java b/src/main/java/com/czertainly/core/dao/repository/AttributeContentItemRepository.java
index d57e0ec0b..e7c116367 100644
--- a/src/main/java/com/czertainly/core/dao/repository/AttributeContentItemRepository.java
+++ b/src/main/java/com/czertainly/core/dao/repository/AttributeContentItemRepository.java
@@ -12,7 +12,7 @@
@Repository
public interface AttributeContentItemRepository extends JpaRepository {
- Optional findByJsonAndAttributeDefinitionUuid(BaseAttributeContent> attributeContent, UUID definitionUuid);
+ AttributeContentItem findByJsonAndAttributeDefinitionUuid(BaseAttributeContent> attributeContent, UUID definitionUuid);
long deleteByAttributeDefinitionUuid(UUID definitionUuid);
long deleteByAttributeDefinitionTypeAndAttributeDefinitionConnectorUuid(AttributeType attributeType, UUID connectorUuid);
diff --git a/src/main/java/com/czertainly/core/dao/repository/ScheduledJobsRepository.java b/src/main/java/com/czertainly/core/dao/repository/ScheduledJobsRepository.java
index b239e27a1..00dccc6e8 100644
--- a/src/main/java/com/czertainly/core/dao/repository/ScheduledJobsRepository.java
+++ b/src/main/java/com/czertainly/core/dao/repository/ScheduledJobsRepository.java
@@ -3,9 +3,10 @@
import com.czertainly.core.dao.entity.ScheduledJob;
import org.springframework.stereotype.Repository;
+import java.util.Optional;
import java.util.UUID;
@Repository
public interface ScheduledJobsRepository extends SecurityFilterRepository {
- ScheduledJob findByJobName(String jobName);
+ Optional findByJobName(String jobName);
}
diff --git a/src/main/java/com/czertainly/core/dao/repository/SecurityFilterRepositoryImpl.java b/src/main/java/com/czertainly/core/dao/repository/SecurityFilterRepositoryImpl.java
index 1b350c838..c76c7cc14 100644
--- a/src/main/java/com/czertainly/core/dao/repository/SecurityFilterRepositoryImpl.java
+++ b/src/main/java/com/czertainly/core/dao/repository/SecurityFilterRepositoryImpl.java
@@ -3,14 +3,14 @@
import com.czertainly.api.exception.ValidationError;
import com.czertainly.api.exception.ValidationException;
import com.czertainly.api.model.common.NameAndUuidDto;
-import com.czertainly.core.dao.entity.*;
import com.czertainly.core.dao.AggregateResultDto;
+import com.czertainly.core.dao.entity.CryptographicKeyItem;
import com.czertainly.core.model.auth.ResourceAction;
import com.czertainly.core.security.authz.SecuredUUID;
import com.czertainly.core.security.authz.SecurityFilter;
import com.czertainly.core.security.authz.SecurityResourceFilter;
import com.czertainly.core.util.AuthHelper;
-import com.czertainly.core.util.converter.Sql2PredicateConverter;
+import com.czertainly.core.util.FilterPredicatesBuilder;
import jakarta.persistence.EntityManager;
import jakarta.persistence.NoResultException;
import jakarta.persistence.criteria.*;
@@ -241,8 +241,8 @@ private List getPredicates(SecurityFilter filter, TriFunction
try {
NameAndUuidDto userInformation = AuthHelper.getUserIdentification();
String ownerAttributePath = root.getJavaType().equals(CryptographicKeyItem.class) ? "cryptographicKey.owner" : "owner";
- Join fromOwner = Sql2PredicateConverter.prepareJoin(root, ownerAttributePath);
- combinedObjectAccessPredicates.add(cb.equal(Sql2PredicateConverter.prepareExpression(fromOwner, "ownerUsername"), userInformation.getName()));
+ Join fromOwner = FilterPredicatesBuilder.prepareJoin(root, ownerAttributePath);
+ combinedObjectAccessPredicates.add(cb.equal(FilterPredicatesBuilder.prepareExpression(fromOwner, "ownerUsername"), userInformation.getName()));
} catch (ValidationException e) {
// cannot apply filter predicate for anonymous user
}
@@ -266,14 +266,14 @@ private Predicate getPredicateBySecurityResourceFilter(Root root, SecurityRes
if (resourceFilter != null) {
From from = root;
if (attributeName.contains(".")) {
- from = Sql2PredicateConverter.prepareJoin(root, attributeName.substring(0, attributeName.lastIndexOf(".")));
+ from = FilterPredicatesBuilder.prepareJoin(root, attributeName.substring(0, attributeName.lastIndexOf(".")));
attributeName = attributeName.substring(attributeName.lastIndexOf(".") + 1);
}
if (resourceFilter.areOnlySpecificObjectsAllowed()) {
- predicate = Sql2PredicateConverter.prepareExpression(from, attributeName).in(resourceFilter.getAllowedObjects());
+ predicate = FilterPredicatesBuilder.prepareExpression(from, attributeName).in(resourceFilter.getAllowedObjects());
} else {
if (!resourceFilter.getForbiddenObjects().isEmpty()) {
- predicate = Sql2PredicateConverter.prepareExpression(from, attributeName).in(resourceFilter.getForbiddenObjects()).not();
+ predicate = FilterPredicatesBuilder.prepareExpression(from, attributeName).in(resourceFilter.getForbiddenObjects()).not();
}
}
}
diff --git a/src/main/java/com/czertainly/core/enums/FilterField.java b/src/main/java/com/czertainly/core/enums/FilterField.java
index f26ecc73e..6a22f74b2 100644
--- a/src/main/java/com/czertainly/core/enums/FilterField.java
+++ b/src/main/java/com/czertainly/core/enums/FilterField.java
@@ -6,6 +6,7 @@
import com.czertainly.api.model.common.enums.cryptography.KeyType;
import com.czertainly.api.model.core.auth.Resource;
import com.czertainly.api.model.core.certificate.CertificateState;
+import com.czertainly.api.model.core.certificate.CertificateSubjectType;
import com.czertainly.api.model.core.certificate.CertificateValidationStatus;
import com.czertainly.api.model.core.compliance.ComplianceStatus;
import com.czertainly.api.model.core.cryptography.key.KeyState;
@@ -37,7 +38,7 @@ public enum FilterField {
PUBLIC_KEY_ALGORITHM(Resource.CERTIFICATE, null, null, Certificate_.publicKeyAlgorithm, "Public Key Algorithm", SearchFieldTypeEnum.LIST),
KEY_SIZE(Resource.CERTIFICATE, null, null, Certificate_.keySize, "Key Size", SearchFieldTypeEnum.LIST),
KEY_USAGE(Resource.CERTIFICATE, null, null, Certificate_.keyUsage, "Key Usage", SearchFieldTypeEnum.LIST),
- BASIC_CONSTRAINTS(Resource.CERTIFICATE, null, null, Certificate_.basicConstraints, "Basic Constraints", SearchFieldTypeEnum.LIST),
+ SUBJECT_TYPE(Resource.CERTIFICATE, null, null, Certificate_.subjectType, "Subject Type", SearchFieldTypeEnum.LIST, CertificateSubjectType.class),
SUBJECT_ALTERNATIVE_NAMES(Resource.CERTIFICATE, null, null, Certificate_.subjectAlternativeNames, "Subject Alternative Name", SearchFieldTypeEnum.STRING),
SUBJECTDN(Resource.CERTIFICATE, null, null, Certificate_.subjectDn, "Subject DN", SearchFieldTypeEnum.STRING),
ISSUERDN(Resource.CERTIFICATE, null, null, Certificate_.issuerDn, "Issuer DN", SearchFieldTypeEnum.STRING),
diff --git a/src/main/java/com/czertainly/core/enums/SearchFieldNameEnum.java b/src/main/java/com/czertainly/core/enums/SearchFieldNameEnum.java
deleted file mode 100644
index c75a00d74..000000000
--- a/src/main/java/com/czertainly/core/enums/SearchFieldNameEnum.java
+++ /dev/null
@@ -1,128 +0,0 @@
-package com.czertainly.core.enums;
-
-import com.czertainly.api.model.core.auth.Resource;
-import com.czertainly.api.model.core.search.SearchableFields;
-
-import java.util.Arrays;
-import java.util.List;
-
-public enum SearchFieldNameEnum {
-
- // Certificate
- COMMON_NAME(SearchableFields.COMMON_NAME, "Common Name", SearchFieldTypeEnum.STRING, false, Resource.CERTIFICATE, null),
- SERIAL_NUMBER_LABEL(SearchableFields.SERIAL_NUMBER, "Serial Number", SearchFieldTypeEnum.STRING, false, Resource.CERTIFICATE, null),
- RA_PROFILE(SearchableFields.RA_PROFILE_NAME, "RA Profile", SearchFieldTypeEnum.LIST, true, Resource.CERTIFICATE, Resource.RA_PROFILE),
- CERTIFICATE_STATE(SearchableFields.CERTIFICATE_STATE, "State", SearchFieldTypeEnum.LIST, false, Resource.CERTIFICATE, null),
- CERTIFICATE_VALIDATION_STATUS(SearchableFields.CERTIFICATE_VALIDATION_STATUS, "Validation status", SearchFieldTypeEnum.LIST, false, Resource.CERTIFICATE, null),
- GROUP(SearchableFields.GROUP_NAME, "Groups", SearchFieldTypeEnum.LIST, true, Resource.CERTIFICATE, Resource.GROUP),
- CERT_LOCATION_NAME(SearchableFields.CERT_LOCATION_NAME, "Locations", SearchFieldTypeEnum.LIST, false, Resource.CERTIFICATE, Resource.LOCATION),
- OWNER(SearchableFields.OWNER, "Owner", SearchFieldTypeEnum.LIST, true, Resource.CERTIFICATE, Resource.USER),
- ISSUER_COMMON_NAME(SearchableFields.ISSUER_COMMON_NAME, "Issuer Common Name", SearchFieldTypeEnum.STRING, false, Resource.CERTIFICATE, null),
- SIGNATURE_ALGORITHM(SearchableFields.SIGNATURE_ALGORITHM, "Signature Algorithm", SearchFieldTypeEnum.LIST, false, Resource.CERTIFICATE, null),
- FINGERPRINT(SearchableFields.FINGERPRINT, "Fingerprint", SearchFieldTypeEnum.STRING, false, Resource.CERTIFICATE, null),
- EXPIRES(SearchableFields.NOT_AFTER, "Expires At", SearchFieldTypeEnum.DATE, false, Resource.CERTIFICATE, null),
- NOT_BEFORE(SearchableFields.NOT_BEFORE, "Valid From", SearchFieldTypeEnum.DATE, false, Resource.CERTIFICATE, null),
- PUBLIC_KEY_ALGORITHM(SearchableFields.PUBLIC_KEY_ALGORITHM, "Public Key Algorithm", SearchFieldTypeEnum.LIST, false, Resource.CERTIFICATE, null),
- KEY_SIZE(SearchableFields.KEY_SIZE, "Key Size", SearchFieldTypeEnum.LIST, false, Resource.CERTIFICATE, null),
- KEY_USAGE(SearchableFields.KEY_USAGE, "Key Usage", SearchFieldTypeEnum.LIST, false, Resource.CERTIFICATE, null),
- BASIC_CONSTRAINTS(SearchableFields.BASIC_CONSTRAINTS, "Basic Constraints", SearchFieldTypeEnum.LIST, false, Resource.CERTIFICATE, null),
- SUBJECT_ALTERNATIVE(SearchableFields.SUBJECT_ALTERNATIVE_NAMES, "Subject Alternative Name", SearchFieldTypeEnum.STRING, false, Resource.CERTIFICATE, null),
- SUBJECT_DN(SearchableFields.SUBJECTDN, "Subject DN", SearchFieldTypeEnum.STRING, false, Resource.CERTIFICATE, null),
- ISSUER_DN(SearchableFields.ISSUERDN, "Issuer DN", SearchFieldTypeEnum.STRING, false, Resource.CERTIFICATE, null),
- ISSUER_SERIAL_NUMBER(SearchableFields.ISSUER_SERIAL_NUMBER, "Issuer Serial Number", SearchFieldTypeEnum.STRING, false, Resource.CERTIFICATE, null),
- OCSP_VALIDATION(SearchableFields.OCSP_VALIDATION, "OCSP Validation", SearchFieldTypeEnum.LIST, false, Resource.CERTIFICATE, null),
- CRL_VALIDATION(SearchableFields.CRL_VALIDATION, "CRL Validation", SearchFieldTypeEnum.LIST, false, Resource.CERTIFICATE, null),
- SIGNATURE_VALIDATION(SearchableFields.SIGNATURE_VALIDATION, "Signature Validation", SearchFieldTypeEnum.LIST, false, Resource.CERTIFICATE, null),
- COMPLIANCE_STATUS(SearchableFields.COMPLIANCE_STATUS, "Compliance Status", SearchFieldTypeEnum.LIST, false, Resource.CERTIFICATE, null),
- PRIVATE_KEY(SearchableFields.PRIVATE_KEY, "Has private key", SearchFieldTypeEnum.BOOLEAN, false, Resource.CERTIFICATE, null),
- TRUSTED_CA(SearchableFields.TRUSTED_CA, "Trusted CA", SearchFieldTypeEnum.BOOLEAN, false, Resource.CERTIFICATE, null),
-
- // Cryptographic Key
- CKI_NAME(SearchableFields.CKI_NAME, "Name", SearchFieldTypeEnum.STRING, false, Resource.CRYPTOGRAPHIC_KEY, null),
- KEY_TYPE(SearchableFields.CKI_TYPE, "Key type", SearchFieldTypeEnum.LIST, false, Resource.CRYPTOGRAPHIC_KEY, null),
- KEY_FORMAT(SearchableFields.CKI_FORMAT, "Key format", SearchFieldTypeEnum.LIST, false, Resource.CRYPTOGRAPHIC_KEY, null),
- KEY_STATE(SearchableFields.CKI_STATE, "State", SearchFieldTypeEnum.LIST, true, Resource.CRYPTOGRAPHIC_KEY, null),
- KEY_CRYPTOGRAPHIC_ALGORITHM(SearchableFields.CKI_CRYPTOGRAPHIC_ALGORITHM, "Cryptographic algorithm", SearchFieldTypeEnum.LIST, false, Resource.CRYPTOGRAPHIC_KEY, null),
- KEY_TOKEN_PROFILE(SearchableFields.CK_TOKEN_PROFILE, "Token profile", SearchFieldTypeEnum.LIST, false, Resource.CRYPTOGRAPHIC_KEY, Resource.TOKEN_PROFILE),
- KEY_TOKEN_INSTANCE_LABEL(SearchableFields.CK_TOKEN_INSTANCE, "Token instance", SearchFieldTypeEnum.LIST, true, Resource.CRYPTOGRAPHIC_KEY, Resource.TOKEN),
- KEY_LENGTH(SearchableFields.CKI_LENGTH, "Key Size", SearchFieldTypeEnum.NUMBER, false, Resource.CRYPTOGRAPHIC_KEY, null),
- CK_GROUP(SearchableFields.CK_GROUP, "Groups", SearchFieldTypeEnum.LIST, true, Resource.CRYPTOGRAPHIC_KEY, Resource.GROUP),
- CK_OWNER(SearchableFields.CK_OWNER, "Owner", SearchFieldTypeEnum.LIST, true, Resource.CRYPTOGRAPHIC_KEY, Resource.USER),
- CK_KEY_USAGE(SearchableFields.CKI_USAGE, "Key Usage", SearchFieldTypeEnum.LIST, true, Resource.CRYPTOGRAPHIC_KEY, null),
-
- // Discovery
- DISCOVERY_NAME(SearchableFields.DISCOVERY_NAME, "Name", SearchFieldTypeEnum.DATETIME, false, Resource.DISCOVERY, null),
- DISCOVERY_START_TIME(SearchableFields.DISCOVERY_START_TIME, "Start time", SearchFieldTypeEnum.DATETIME, false, Resource.DISCOVERY, null),
- DISCOVERY_END_TIME(SearchableFields.DISCOVERY_END_TIME, "End time", SearchFieldTypeEnum.DATETIME, false, Resource.DISCOVERY, null),
- DISCOVERY_TOTAL_CERT_DISCOVERED(SearchableFields.DISCOVERY_TOTAL_CERT_DISCOVERED, "Total certificate discovered", SearchFieldTypeEnum.NUMBER, false, Resource.DISCOVERY, null),
- DISCOVERY_CONNECTOR_NAME(SearchableFields.DISCOVERY_CONNECTOR_NAME, "Discovery provider",SearchFieldTypeEnum.LIST, false, Resource.DISCOVERY, null),
- DISCOVERY_KIND(SearchableFields.DISCOVERY_KIND, "Kind",SearchFieldTypeEnum.STRING, false, Resource.DISCOVERY, null),
- DISCOVERY_STATUS(SearchableFields.DISCOVERY_STATUS, "Status", SearchFieldTypeEnum.LIST, false, Resource.DISCOVERY, null),
-
- // Entity
- ENTITY_NAME(SearchableFields.ENTITY_NAME, "Name", SearchFieldTypeEnum.STRING, false, Resource.ENTITY, null),
- ENTITY_CONNECTOR_NAME(SearchableFields.ENTITY_CONNECTOR_NAME, "Entity provider", SearchFieldTypeEnum.LIST, false, Resource.ENTITY, null),
- ENTITY_KIND(SearchableFields.ENTITY_KIND, "Kind", SearchFieldTypeEnum.LIST, false, Resource.ENTITY, null),
-
- // Location
- LOCATION_NAME(SearchableFields.LOCATION_NAME, "Name", SearchFieldTypeEnum.STRING, false, Resource.LOCATION, null),
- LOCATION_ENTITY_INSTANCE(SearchableFields.LOCATION_ENTITY_INSTANCE, "Entity instance", SearchFieldTypeEnum.LIST, false, Resource.LOCATION, Resource.ENTITY),
- LOCATION_ENABLED(SearchableFields.LOCATION_ENABLED, "Enabled", SearchFieldTypeEnum.BOOLEAN, true, Resource.LOCATION, null),
- LOCATION_SUPPORT_MULTIPLE_ENTRIES(SearchableFields.LOCATION_SUPPORT_MULTIPLE_ENTRIES, "Support multiple entries", SearchFieldTypeEnum.BOOLEAN, false, Resource.LOCATION, null),
- LOCATION_SUPPORT_KEY_MANAGEMENT(SearchableFields.LOCATION_SUPPORT_KEY_MANAGEMENT, "Support key management", SearchFieldTypeEnum.BOOLEAN, false, Resource.LOCATION, null),
- ;
-
- private final SearchableFields fieldProperty;
-
- private final String fieldLabel;
-
- private final SearchFieldTypeEnum fieldTypeEnum;
-
- private final boolean settable;
-
- private final Resource resource;
-
- private final Resource fieldResource;
-
- SearchFieldNameEnum(final SearchableFields fieldProperty, final String fieldLabel, final SearchFieldTypeEnum fieldTypeEnum, final boolean settable, final Resource resource, final Resource fieldResource) {
- this.fieldProperty = fieldProperty;
- this.fieldLabel = fieldLabel;
- this.fieldTypeEnum = fieldTypeEnum;
- this.settable = settable;
- this.resource = resource;
- this.fieldResource = fieldResource;
- }
-
- public SearchableFields getFieldProperty() {
- return fieldProperty;
- }
-
- public String getFieldLabel() {
- return fieldLabel;
- }
-
- public SearchFieldTypeEnum getFieldTypeEnum() {
- return fieldTypeEnum;
- }
-
- public boolean isSettable() {
- return settable;
- }
-
- public Resource getResource() { return this.resource; }
-
- public Resource getFieldResource() {return this.fieldResource;}
-
- public static SearchFieldNameEnum getEnumBySearchableFields(final SearchableFields searchableFields) {
- for (SearchFieldNameEnum searchFieldNameEnum : SearchFieldNameEnum.values()) {
- if (searchFieldNameEnum.getFieldProperty().equals(searchableFields)) {
- return searchFieldNameEnum;
- }
- }
- return null;
- }
-
- public static List getEnumsForResource(Resource resource) {
- return Arrays.stream(SearchFieldNameEnum.values()).filter(searchFieldNameEnum -> searchFieldNameEnum.resource == resource).toList();
- }
-}
diff --git a/src/main/java/com/czertainly/core/evaluator/CertificateRuleEvaluator.java b/src/main/java/com/czertainly/core/evaluator/CertificateRuleEvaluator.java
index 7d934c835..89721e492 100644
--- a/src/main/java/com/czertainly/core/evaluator/CertificateRuleEvaluator.java
+++ b/src/main/java/com/czertainly/core/evaluator/CertificateRuleEvaluator.java
@@ -6,9 +6,9 @@
import com.czertainly.api.exception.RuleException;
import com.czertainly.api.model.core.auth.Resource;
import com.czertainly.api.model.core.search.FilterFieldSource;
-import com.czertainly.api.model.core.search.SearchableFields;
import com.czertainly.core.dao.entity.Certificate;
import com.czertainly.core.dao.entity.workflows.ExecutionItem;
+import com.czertainly.core.enums.FilterField;
import com.czertainly.core.security.authz.SecuredUUID;
import com.czertainly.core.service.CertificateService;
import org.springframework.beans.factory.annotation.Autowired;
@@ -37,9 +37,9 @@ public void performAction(ExecutionItem executionItem, Certificate object, Resou
SecuredUUID certificateUuid = object.getSecuredUuid();
- SearchableFields searchableField;
+ FilterField searchableField;
try {
- searchableField = Enum.valueOf(SearchableFields.class, executionItem.getFieldIdentifier());
+ searchableField = Enum.valueOf(FilterField.class, executionItem.getFieldIdentifier());
} catch (IllegalArgumentException e) {
throw new RuleException("Field identifier '" + executionItem.getFieldIdentifier() + "' is not supported.");
}
diff --git a/src/main/java/com/czertainly/core/evaluator/RuleEvaluator.java b/src/main/java/com/czertainly/core/evaluator/RuleEvaluator.java
index bcb64a811..9a8dd3c4c 100644
--- a/src/main/java/com/czertainly/core/evaluator/RuleEvaluator.java
+++ b/src/main/java/com/czertainly/core/evaluator/RuleEvaluator.java
@@ -13,14 +13,15 @@
import com.czertainly.api.model.core.search.FilterConditionOperator;
import com.czertainly.api.model.core.search.FilterFieldSource;
import com.czertainly.api.model.core.search.FilterFieldType;
-import com.czertainly.api.model.core.search.SearchableFields;
import com.czertainly.core.attribute.engine.AttributeEngine;
import com.czertainly.core.attribute.engine.records.ObjectAttributeContentInfo;
import com.czertainly.core.dao.entity.workflows.*;
+import com.czertainly.core.enums.FilterField;
import com.czertainly.core.enums.ResourceToClass;
-import com.czertainly.core.enums.SearchFieldNameEnum;
import com.czertainly.core.service.TriggerService;
import com.czertainly.core.util.AttributeDefinitionUtils;
+import com.czertainly.core.util.FilterPredicatesBuilder;
+import jakarta.persistence.metamodel.Attribute;
import org.apache.commons.beanutils.PropertyUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -116,37 +117,27 @@ public Boolean evaluateConditionItem(ConditionItem conditionItem, T object, Reso
// First, check where from to get object value based on Field Source
if (fieldSource == FilterFieldSource.PROPERTY) {
Object objectValue;
- SearchableFields field;
+ FilterField field;
try {
- field = Enum.valueOf(SearchableFields.class, fieldIdentifier);
+ field = Enum.valueOf(FilterField.class, fieldIdentifier);
} catch (IllegalArgumentException e) {
throw new RuleException("Field identifier '" + fieldIdentifier + "' is not supported.");
}
// Get value of property from the object
try {
- objectValue = getPropertyValue(object, field.getCode(), false);
+ objectValue = getPropertyValue(object, field, false);
} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
throw new RuleException("Cannot get property " + fieldIdentifier + " from resource " + resource + ".");
}
- // Determine field type from field identifier using Searchable field enum
- SearchFieldNameEnum propertyEnum;
- try {
- propertyEnum = SearchFieldNameEnum.getEnumBySearchableFields(field);
- } catch (Exception e) {
- throw new RuleException("Field identifier '" + fieldIdentifier + "' is not supported.");
- }
- if (propertyEnum == null) {
- throw new RuleException("Unknown property field identifier: " + fieldIdentifier);
- }
- FilterFieldType fieldType = propertyEnum.getFieldTypeEnum().getFieldType();
+ FilterFieldType fieldType = field.getType().getFieldType();
// Apply comparing function on value in object and value in condition, based on operator and field type, return whether the condition is satisfied
try {
if (!(objectValue instanceof Collection> objectValues)) {
return fieldTypeToOperatorActionMap.get(fieldType).get(operator).apply(objectValue, conditionValue);
}
for (Object item : objectValues) {
- Object o = getPropertyValue(item, field.getCode(), true);
+ Object o = getPropertyValue(item, field, true);
if (!fieldTypeToOperatorActionMap.get(fieldType).get(operator).apply(o, conditionValue)) {
return false;
}
@@ -238,14 +229,14 @@ public void performAction(ExecutionItem executionItem, T object, Resource resour
// Set a property of the object using setter, the property must be set as settable
if (fieldSource == FilterFieldSource.PROPERTY) {
- SearchFieldNameEnum propertyEnum = SearchFieldNameEnum.getEnumBySearchableFields(SearchableFields.fromCode(fieldIdentifier));
+ FilterField propertyEnum = Enum.valueOf(FilterField.class, fieldIdentifier);
if (propertyEnum == null) {
throw new RuleException("Field identifier '" + fieldIdentifier + "' is not supported.");
}
if (!propertyEnum.isSettable())
throw new RuleException("Setting property '" + fieldIdentifier + "' is not supported.");
try {
- PropertyUtils.setProperty(object, propertyEnum.getFieldProperty().getCode(), actionData);
+ PropertyUtils.setProperty(object, propertyEnum.getFieldAttribute().getName(), actionData);
} catch (IllegalArgumentException | IllegalAccessException | InvocationTargetException |
NoSuchMethodException e) {
throw new RuleException(e.getMessage());
@@ -268,29 +259,32 @@ public void performAction(ExecutionItem executionItem, T object, Resource resour
}
}
- private Object getPropertyValue(Object object, String fieldIdentifier, boolean alreadyNested) throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
- final int indexOfDot = fieldIdentifier.lastIndexOf(".");
- boolean isNested = indexOfDot != -1;
+ private Object getPropertyValue(Object object, FilterField filterField, boolean alreadyNested) throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
+ boolean isNested = filterField.getJoinAttributes() != null;
+ String pathToProperty = FilterPredicatesBuilder.buildPathToProperty(filterField, alreadyNested);
+
try {
if (alreadyNested) {
- return PropertyUtils.getProperty(object, fieldIdentifier.substring(indexOfDot + 1));
+ return PropertyUtils.getProperty(object, pathToProperty);
}
- return PropertyUtils.getProperty(object, fieldIdentifier);
+ return PropertyUtils.getProperty(object, pathToProperty);
} catch (NoSuchMethodException e) {
if (!isNested || alreadyNested) {
throw e;
}
- final String parentPropertyIdentifier = fieldIdentifier.substring(0, indexOfDot);
- Object tmpValue = PropertyUtils.getProperty(object, parentPropertyIdentifier);
+ Object tmpValue = PropertyUtils.getProperty(object, filterField.getJoinAttributes().getFirst().getName());
if (tmpValue instanceof Collection>) {
return tmpValue;
}
throw e;
+
}
+
}
+
private boolean getConditionEvaluationResult(ConditionItem conditionItem, T object, TriggerHistory triggerHistory, Rule rule) {
try {
if (!evaluateConditionItem(conditionItem, object, rule.getResource())) {
diff --git a/src/main/java/com/czertainly/core/event/transaction/DiscoveryFinishedEvent.java b/src/main/java/com/czertainly/core/event/transaction/DiscoveryFinishedEvent.java
index 17a91c10b..3956bea21 100644
--- a/src/main/java/com/czertainly/core/event/transaction/DiscoveryFinishedEvent.java
+++ b/src/main/java/com/czertainly/core/event/transaction/DiscoveryFinishedEvent.java
@@ -1,6 +1,8 @@
package com.czertainly.core.event.transaction;
+import com.czertainly.core.tasks.ScheduledJobInfo;
+
import java.util.UUID;
-public record DiscoveryFinishedEvent(UUID discoveryUuid, UUID loggedUserUuid) {
+public record DiscoveryFinishedEvent(UUID discoveryUuid, UUID loggedUserUuid, ScheduledJobInfo scheduledJobInfo) {
}
diff --git a/src/main/java/com/czertainly/core/event/transaction/ScheduledJobFinishedEvent.java b/src/main/java/com/czertainly/core/event/transaction/ScheduledJobFinishedEvent.java
new file mode 100644
index 000000000..bbc8db0e7
--- /dev/null
+++ b/src/main/java/com/czertainly/core/event/transaction/ScheduledJobFinishedEvent.java
@@ -0,0 +1,7 @@
+package com.czertainly.core.event.transaction;
+
+import com.czertainly.core.model.ScheduledTaskResult;
+import com.czertainly.core.tasks.ScheduledJobInfo;
+
+public record ScheduledJobFinishedEvent(ScheduledJobInfo scheduledJobInfo, ScheduledTaskResult result) {
+}
diff --git a/src/main/java/com/czertainly/core/messaging/listeners/EventListener.java b/src/main/java/com/czertainly/core/messaging/listeners/EventListener.java
index 6dae9ea8b..b2816f4dc 100644
--- a/src/main/java/com/czertainly/core/messaging/listeners/EventListener.java
+++ b/src/main/java/com/czertainly/core/messaging/listeners/EventListener.java
@@ -10,7 +10,9 @@
import com.czertainly.core.messaging.model.EventMessage;
import com.czertainly.core.service.CertificateEventHistoryService;
import com.czertainly.core.service.DiscoveryService;
+import com.czertainly.core.tasks.ScheduledJobInfo;
import com.czertainly.core.util.AuthHelper;
+import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
@@ -31,13 +33,15 @@ public class EventListener {
private CertificateEventHistoryService certificateEventHistoryService;
private DiscoveryService discoveryService;
private AuthHelper authHelper;
+ private final ObjectMapper mapper = new ObjectMapper();
@Autowired
public void setAuthHelper(AuthHelper authHelper) {
this.authHelper = authHelper;
}
+
@Autowired
- public void setDiscoveryService(DiscoveryService discoveryService){
+ public void setDiscoveryService(DiscoveryService discoveryService) {
this.discoveryService = discoveryService;
}
@@ -49,11 +53,13 @@ public void setCertificateEventHistoryService(CertificateEventHistoryService cer
@RabbitListener(queues = RabbitMQConstants.QUEUE_EVENTS_NAME, messageConverter = "jsonMessageConverter", concurrency = "3")
public void processMessage(EventMessage eventMessage) throws NotFoundException, CertificateException, NoSuchAlgorithmException, RuleException, AttributeException {
switch (eventMessage.getResource()) {
- case CERTIFICATE -> certificateEventHistoryService.addEventHistory(eventMessage.getResourceUUID(), CertificateEvent.findByCode(eventMessage.getEventName()), CertificateEventStatus.valueOf(eventMessage.getEventStatus()), eventMessage.getEventMessage(), eventMessage.getEventDetail());
- case DISCOVERY ->
- {
+ case CERTIFICATE ->
+ certificateEventHistoryService.addEventHistory(eventMessage.getResourceUUID(), CertificateEvent.findByCode(eventMessage.getEventName()), CertificateEventStatus.valueOf(eventMessage.getEventStatus()), eventMessage.getEventMessage(), eventMessage.getEventDetail());
+ case DISCOVERY -> {
authHelper.authenticateAsUser(eventMessage.getUserUuid());
- if (Objects.equals(eventMessage.getEventName(), ResourceEvent.DISCOVERY_FINISHED.getCode())) discoveryService.evaluateDiscoveryTriggers(eventMessage.getResourceUUID(), eventMessage.getUserUuid());
+ if (Objects.equals(eventMessage.getEventName(), ResourceEvent.DISCOVERY_FINISHED.getCode())) {
+ discoveryService.evaluateDiscoveryTriggers(eventMessage.getResourceUUID(), eventMessage.getUserUuid(), mapper.convertValue(eventMessage.getEventData(), ScheduledJobInfo.class));
+ }
}
default -> logger.warn("Event handling is supported only for certificates for now");
}
diff --git a/src/main/java/com/czertainly/core/messaging/listeners/SchedulerListener.java b/src/main/java/com/czertainly/core/messaging/listeners/SchedulerListener.java
index 1da33ac52..652b63069 100644
--- a/src/main/java/com/czertainly/core/messaging/listeners/SchedulerListener.java
+++ b/src/main/java/com/czertainly/core/messaging/listeners/SchedulerListener.java
@@ -1,81 +1,37 @@
package com.czertainly.core.messaging.listeners;
-import com.czertainly.api.exception.ConnectorException;
+import com.czertainly.api.exception.NotFoundException;
import com.czertainly.api.exception.SchedulerException;
import com.czertainly.api.model.scheduler.SchedulerJobExecutionMessage;
-import com.czertainly.api.model.scheduler.SchedulerJobExecutionStatus;
-import com.czertainly.core.dao.entity.ScheduledJob;
-import com.czertainly.core.dao.entity.ScheduledJobHistory;
-import com.czertainly.core.dao.repository.ScheduledJobHistoryRepository;
-import com.czertainly.core.dao.repository.ScheduledJobsRepository;
import com.czertainly.core.messaging.configuration.RabbitMQConstants;
-import com.czertainly.core.tasks.SchedulerJobProcessor;
+import com.czertainly.core.service.SchedulerService;
import jakarta.transaction.Transactional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
-import java.util.Date;
-
@Component
@Transactional
public class SchedulerListener {
- private ApplicationContext applicationContext;
-
- private ScheduledJobHistoryRepository scheduledJobHistoryRepository;
+ private static final Logger logger = LoggerFactory.getLogger(SchedulerListener.class);
- private ScheduledJobsRepository scheduledJobsRepository;
+ private SchedulerService schedulerService;
- private static final Logger logger = LoggerFactory.getLogger(SchedulerListener.class);
+ @Autowired
+ public void setSchedulerService(SchedulerService schedulerService) {
+ this.schedulerService = schedulerService;
+ }
@RabbitListener(queues = RabbitMQConstants.QUEUE_SCHEDULER_NAME, messageConverter = "jsonMessageConverter", concurrency = "10")
public void processMessage(SchedulerJobExecutionMessage schedulerMessage) {
- logger.info("Received scheduler message: {}", schedulerMessage);
-
+ logger.debug("Received scheduler message: {}", schedulerMessage);
try {
- final Class> clazz = Class.forName(schedulerMessage.getClassToBeExecuted());
- final Object clazzObject = applicationContext.getBean(clazz);
- if (clazzObject != null && clazzObject instanceof SchedulerJobProcessor processor) {
- logger.info("Job {} is executed.", schedulerMessage.getJobName());
- final SchedulerJobProcessor schedulerJobProcessor = processor;
- schedulerJobProcessor.processTask(schedulerMessage.getJobName());
- logger.info("Job {} was processed.", schedulerMessage.getJobName());
- }
-
- } catch (SchedulerException | ConnectorException | ClassNotFoundException e) {
- logger.error("Unable to process the job {}", schedulerMessage.getJobName());
-
- final ScheduledJob scheduledJob = scheduledJobsRepository.findByJobName(schedulerMessage.getJobName());
- if (scheduledJob != null) {
- final ScheduledJobHistory scheduledJobHistory = new ScheduledJobHistory();
- scheduledJobHistory.setScheduledJobUuid(scheduledJob.getUuid());
- scheduledJobHistory.setJobExecution(new Date());
- scheduledJobHistory.setSchedulerExecutionStatus(SchedulerJobExecutionStatus.FAILED);
- scheduledJobHistoryRepository.save(scheduledJobHistory);
- } else {
- logger.error("There is no such job {} registered.", schedulerMessage.getJobName());
- }
+ schedulerService.runScheduledJob(schedulerMessage.getJobName());
+ } catch (SchedulerException | NotFoundException e) {
+ logger.error("Unable to process the job {}. Error: {}", schedulerMessage.getJobName(), e.getMessage(), e);
}
}
-
- // SETTERs
-
- @Autowired
- public void setApplicationContext(ApplicationContext applicationContext) {
- this.applicationContext = applicationContext;
- }
-
- @Autowired
- public void setScheduledJobHistoryRepository(ScheduledJobHistoryRepository scheduledJobHistoryRepository) {
- this.scheduledJobHistoryRepository = scheduledJobHistoryRepository;
- }
-
- @Autowired
- public void setScheduledJobsRepository(ScheduledJobsRepository scheduledJobsRepository) {
- this.scheduledJobsRepository = scheduledJobsRepository;
- }
}
diff --git a/src/main/java/com/czertainly/core/messaging/model/EventMessage.java b/src/main/java/com/czertainly/core/messaging/model/EventMessage.java
index 4fcdf40c4..a24b59aed 100644
--- a/src/main/java/com/czertainly/core/messaging/model/EventMessage.java
+++ b/src/main/java/com/czertainly/core/messaging/model/EventMessage.java
@@ -1,7 +1,6 @@
package com.czertainly.core.messaging.model;
import com.czertainly.api.model.core.auth.Resource;
-import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.*;
import java.util.UUID;
@@ -26,4 +25,6 @@ public class EventMessage {
private UUID userUuid;
+ private Object eventData;
+
}
diff --git a/src/main/java/com/czertainly/core/messaging/producers/EventProducer.java b/src/main/java/com/czertainly/core/messaging/producers/EventProducer.java
index 54386ad04..42ca68cdd 100644
--- a/src/main/java/com/czertainly/core/messaging/producers/EventProducer.java
+++ b/src/main/java/com/czertainly/core/messaging/producers/EventProducer.java
@@ -7,6 +7,7 @@
import com.czertainly.api.model.core.other.ResourceEvent;
import com.czertainly.core.messaging.configuration.RabbitMQConstants;
import com.czertainly.core.messaging.model.EventMessage;
+import com.czertainly.core.tasks.ScheduledJobInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
@@ -32,20 +33,20 @@ public void produceMessage(final EventMessage eventMessage) {
public void produceCertificateEventMessage(final UUID certificateUUID, final String eventName, final String eventStatus, final String message, final String detail) {
logger.debug("Sending Certificate {} event message: {}", certificateUUID, message);
- final EventMessage eventMessage = new EventMessage(Resource.CERTIFICATE, certificateUUID, eventName, eventStatus, message, detail, null);
+ final EventMessage eventMessage = new EventMessage(Resource.CERTIFICATE, certificateUUID, eventName, eventStatus, message, detail, null, null);
produceMessage(eventMessage);
}
public void produceCertificateStatusChangeEventMessage(final UUID certificateUUID, final CertificateEvent certificateEvent, final CertificateEventStatus eventStatus, IPlatformEnum oldStatus, IPlatformEnum newStatus) {
String message = String.format("Certificate %s changed from %s to %s.", certificateEvent == CertificateEvent.UPDATE_STATE ? "state" : "validation status", oldStatus.getLabel(), newStatus.getLabel());
logger.debug("Sending Certificate {} event message: {}", certificateUUID, message);
- final EventMessage eventMessage = new EventMessage(Resource.CERTIFICATE, certificateUUID, certificateEvent.getCode(), eventStatus.toString(), message, null, null);
+ final EventMessage eventMessage = new EventMessage(Resource.CERTIFICATE, certificateUUID, certificateEvent.getCode(), eventStatus.toString(), message, null, null, null);
produceMessage(eventMessage);
}
- public void produceDiscoveryFinishedEventMessage(final UUID discoveryUuid, final UUID userUuid, final ResourceEvent event) {
+ public void produceDiscoveryFinishedEventMessage(final UUID discoveryUuid, final UUID userUuid, final ResourceEvent event, final ScheduledJobInfo scheduledJobInfo) {
- final EventMessage eventMessage = new EventMessage(Resource.DISCOVERY, discoveryUuid, event.getCode(), null, null, null, userUuid);
+ final EventMessage eventMessage = new EventMessage(Resource.DISCOVERY, discoveryUuid, event.getCode(), null, null, null, userUuid, scheduledJobInfo);
produceMessage(eventMessage);
}
diff --git a/src/main/java/com/czertainly/core/service/CertificateEventHistoryService.java b/src/main/java/com/czertainly/core/service/CertificateEventHistoryService.java
index 4b26b2ad1..17e33fa21 100644
--- a/src/main/java/com/czertainly/core/service/CertificateEventHistoryService.java
+++ b/src/main/java/com/czertainly/core/service/CertificateEventHistoryService.java
@@ -1,11 +1,9 @@
package com.czertainly.core.service;
import com.czertainly.api.exception.NotFoundException;
-import com.czertainly.api.model.client.certificate.SearchFilterRequestDto;
import com.czertainly.api.model.core.certificate.CertificateEvent;
import com.czertainly.api.model.core.certificate.CertificateEventHistoryDto;
import com.czertainly.api.model.core.certificate.CertificateEventStatus;
-import com.czertainly.api.model.core.search.SearchFieldDataDto;
import com.czertainly.core.dao.entity.Certificate;
import com.czertainly.core.dao.entity.CertificateEventHistory;
@@ -31,5 +29,4 @@ public interface CertificateEventHistoryService {
void addEventHistory(UUID certificateUuid, CertificateEvent event, CertificateEventStatus status, String message, String additionalInformation);
- void addEventHistoryForRequest(List filters, String entity, List originalJson, CertificateEvent event, CertificateEventStatus status, String message);
}
diff --git a/src/main/java/com/czertainly/core/service/CertificateService.java b/src/main/java/com/czertainly/core/service/CertificateService.java
index f49ae01dc..8ed07085a 100644
--- a/src/main/java/com/czertainly/core/service/CertificateService.java
+++ b/src/main/java/com/czertainly/core/service/CertificateService.java
@@ -42,7 +42,7 @@ public interface CertificateService extends ResourceExtensionService {
Certificate getCertificateEntityByIssuerDnNormalizedAndSerialNumber(String issuerDn, String serialNumber) throws NotFoundException;
- Boolean checkCertificateExistsByFingerprint(String fingerprint);
+ boolean checkCertificateExistsByFingerprint(String fingerprint);
void deleteCertificate(SecuredUUID uuid) throws NotFoundException;
@@ -85,7 +85,7 @@ public interface CertificateService extends ResourceExtensionService {
List getSearchableFieldInformationByGroup();
- void bulkDeleteCertificate(SecurityFilter filter, RemoveCertificateDto request) throws NotFoundException;
+ void bulkDeleteCertificate(SecurityFilter filter, RemoveCertificateDto request) throws NotFoundException, NotSupportedException;
/**
* List all locations associated with the certificate
@@ -164,7 +164,7 @@ public interface CertificateService extends ResourceExtensionService {
*
* @param request Request to update multiple objects
*/
- void bulkUpdateCertificateObjects(SecurityFilter filter, MultipleCertificateObjectUpdateDto request) throws NotFoundException;
+ void bulkUpdateCertificatesObjects(SecurityFilter filter, MultipleCertificateObjectUpdateDto request) throws NotFoundException, NotSupportedException;
/**
* Function to update status of certificates by scheduled event
diff --git a/src/main/java/com/czertainly/core/service/DiscoveryService.java b/src/main/java/com/czertainly/core/service/DiscoveryService.java
index f75100649..3638d2f40 100644
--- a/src/main/java/com/czertainly/core/service/DiscoveryService.java
+++ b/src/main/java/com/czertainly/core/service/DiscoveryService.java
@@ -9,6 +9,7 @@
import com.czertainly.api.model.core.search.SearchFieldDataByGroupDto;
import com.czertainly.core.security.authz.SecuredUUID;
import com.czertainly.core.security.authz.SecurityFilter;
+import com.czertainly.core.tasks.ScheduledJobInfo;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
@@ -34,7 +35,7 @@ public interface DiscoveryService extends ResourceExtensionService {
DiscoveryCertificateResponseDto getDiscoveryCertificates(SecuredUUID uuid, Boolean newlyDiscovered, int itemsPerPage, int pageNumber) throws NotFoundException;
DiscoveryHistoryDetailDto createDiscovery(DiscoveryDto request, boolean saveEntity) throws AlreadyExistException, ConnectorException, AttributeException;
- DiscoveryHistoryDetailDto runDiscovery(UUID discoveryUuid);
+ DiscoveryHistoryDetailDto runDiscovery(UUID discoveryUuid, ScheduledJobInfo scheduledJobInfo);
void runDiscoveryAsync(UUID discoveryUuid);
void deleteDiscovery(SecuredUUID uuid) throws NotFoundException;
@@ -50,6 +51,6 @@ public interface DiscoveryService extends ResourceExtensionService {
List getSearchableFieldInformationByGroup();
- void evaluateDiscoveryTriggers(UUID discoveryUuid, UUID userUuid) throws NotFoundException, RuleException, CertificateException, NoSuchAlgorithmException, AttributeException;
+ void evaluateDiscoveryTriggers(UUID discoveryUuid, UUID userUuid, ScheduledJobInfo scheduledJobInfo) throws NotFoundException, RuleException, CertificateException, NoSuchAlgorithmException, AttributeException;
}
\ No newline at end of file
diff --git a/src/main/java/com/czertainly/core/service/SchedulerService.java b/src/main/java/com/czertainly/core/service/SchedulerService.java
index ca1a85a81..691d54f76 100644
--- a/src/main/java/com/czertainly/core/service/SchedulerService.java
+++ b/src/main/java/com/czertainly/core/service/SchedulerService.java
@@ -8,6 +8,7 @@
import com.czertainly.api.model.core.scheduler.ScheduledJobDetailDto;
import com.czertainly.api.model.scheduler.UpdateScheduledJob;
import com.czertainly.core.security.authz.SecurityFilter;
+import com.czertainly.core.tasks.ScheduledJobTask;
public interface SchedulerService {
@@ -25,4 +26,9 @@ public interface SchedulerService {
ScheduledJobDetailDto updateScheduledJob(String uuid, UpdateScheduledJob request) throws NotFoundException, SchedulerException;
+ ScheduledJobDetailDto registerScheduledJob(Class extends ScheduledJobTask> scheduledJobTaskClass) throws SchedulerException;
+
+ ScheduledJobDetailDto registerScheduledJob(Class extends ScheduledJobTask> scheduledJobTaskClass, String jobName, String cronExpression, boolean oneTime, Object taskData) throws SchedulerException;
+
+ void runScheduledJob(String jobName) throws SchedulerException, NotFoundException;
}
diff --git a/src/main/java/com/czertainly/core/service/SearchService.java b/src/main/java/com/czertainly/core/service/SearchService.java
deleted file mode 100644
index 13bd05989..000000000
--- a/src/main/java/com/czertainly/core/service/SearchService.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package com.czertainly.core.service;
-
-import com.czertainly.api.exception.ValidationException;
-import com.czertainly.api.model.client.certificate.SearchFilterRequestDto;
-import com.czertainly.api.model.client.certificate.SearchRequestDto;
-import com.czertainly.api.model.core.search.DynamicSearchInternalResponse;
-import com.czertainly.api.model.core.search.SearchFieldDataDto;
-import com.czertainly.core.security.authz.SecurityFilter;
-
-import java.util.List;
-
-public interface SearchService {
- Object completeSearchQueryExecutor(List filters, String entity, List originalJson);
- DynamicSearchInternalResponse dynamicSearchQueryExecutor(SearchRequestDto searchRequestDto, String entity, List originalJson, String additionalWhereClause);
-
- Object customQueryExecutor(String sqlQuery);
-
- String getCompleteSearchQuery(List filters, String entity, String joinQuery, List originalJson, Boolean conditionOnly, Boolean nativeCode);
-
- String getQueryDynamicBasedOnFilter(List conditions, String entity, List originalJson, String joinQuery, Boolean conditionOnly, Boolean nativeCode, String additionalWhereClause) throws ValidationException;
-
- String createCriteriaBuilderString(SecurityFilter filter, Boolean addFinisher);
-}
diff --git a/src/main/java/com/czertainly/core/service/acme/impl/AcmeServiceImpl.java b/src/main/java/com/czertainly/core/service/acme/impl/AcmeServiceImpl.java
index 6b27f6fe6..936cf6bac 100644
--- a/src/main/java/com/czertainly/core/service/acme/impl/AcmeServiceImpl.java
+++ b/src/main/java/com/czertainly/core/service/acme/impl/AcmeServiceImpl.java
@@ -214,8 +214,25 @@ public ResponseEntity newAccount(String acmeProfileName, String request
validateRequest(jwsRequest, acmeProfileName, requestUri, isRaProfileBased);
NewAccountRequest accountRequest = AcmeJsonProcessor.getPayloadAsRequestObject(jwsRequest.getJwsObject(), NewAccountRequest.class);
- logger.debug("New Account requested: {}", accountRequest.toString());
- AcmeAccount account = addNewAccount(acmeProfileName, AcmePublicKeyProcessor.publicKeyPemStringFromObject(jwsRequest.getPublicKey()), accountRequest, isRaProfileBased);
+ logger.debug("New Account request: {}", accountRequest.toString());
+
+ // Check if the Account already exists
+ AcmeAccount account = acmeAccountRepository.findByPublicKey(AcmePublicKeyProcessor.publicKeyPemStringFromObject(jwsRequest.getPublicKey()));
+
+ if (accountRequest.isOnlyReturnExisting()) {
+ logger.debug("Request to only return existing Account");
+ if (account == null) {
+ logger.error("Requested Account does not exists");
+ throw new AcmeProblemDocumentException(HttpStatus.BAD_REQUEST, Problem.ACCOUNT_DOES_NOT_EXIST);
+ }
+ } else {
+ // Create a new Account if it does not exist
+ if (account == null) {
+ logger.debug("Request to create a new Account");
+ account = addNewAccount(acmeProfileName, AcmePublicKeyProcessor.publicKeyPemStringFromObject(jwsRequest.getPublicKey()), accountRequest, isRaProfileBased);
+ }
+ }
+
Account accountDto = account.mapToDto();
String baseUri = getAcmeBaseUri();
diff --git a/src/main/java/com/czertainly/core/service/handler/CertificateHandler.java b/src/main/java/com/czertainly/core/service/handler/CertificateHandler.java
index 3e617cc4b..9af007e9f 100644
--- a/src/main/java/com/czertainly/core/service/handler/CertificateHandler.java
+++ b/src/main/java/com/czertainly/core/service/handler/CertificateHandler.java
@@ -5,12 +5,14 @@
import com.czertainly.api.exception.NotFoundException;
import com.czertainly.api.exception.RuleException;
import com.czertainly.api.model.common.attribute.v2.MetadataAttribute;
+import com.czertainly.api.model.common.attribute.v2.content.BaseAttributeContent;
import com.czertainly.api.model.connector.discovery.DiscoveryProviderCertificateDataDto;
import com.czertainly.api.model.core.auth.Resource;
import com.czertainly.api.model.core.certificate.CertificateEvent;
import com.czertainly.api.model.core.certificate.CertificateEventStatus;
import com.czertainly.core.attribute.engine.AttributeEngine;
import com.czertainly.core.attribute.engine.records.ObjectAttributeContentInfo;
+import com.czertainly.core.dao.entity.AttributeDefinition;
import com.czertainly.core.dao.entity.Certificate;
import com.czertainly.core.dao.entity.DiscoveryCertificate;
import com.czertainly.core.dao.entity.DiscoveryHistory;
@@ -135,11 +137,12 @@ public void validate(Certificate certificate) {
}
@Transactional(propagation = Propagation.REQUIRES_NEW, isolation = Isolation.DEFAULT)
- public void updateMetadataDefinition(List metadataAttributes, UUID connectorUuid, String connectorName) {
+ public void updateMetadataDefinition(List metadataAttributes, Map> metadataContentsMapping, UUID connectorUuid, String connectorName) {
logger.debug("Updating {} discovery certificate metadata definitions for connector {}", metadataAttributes.size(), connectorName);
for (MetadataAttribute metadataAttribute : metadataAttributes) {
try {
- attributeEngine.updateMetadataAttributeDefinition(metadataAttribute, connectorUuid);
+ AttributeDefinition attributeDefinition = attributeEngine.updateMetadataAttributeDefinition(metadataAttribute, connectorUuid);
+ attributeEngine.registerAttributeContentItems(attributeDefinition.getUuid(), metadataContentsMapping.get(metadataAttribute.getUuid()));
} catch (AttributeException e) {
logger.error("Unable to update discovery certificate metadata definition with UUID {} and name {} for discovery connector {}. Message: {}", metadataAttribute.getUuid(), metadataAttribute.getName(), connectorName, e.getMessage(), e);
}
diff --git a/src/main/java/com/czertainly/core/service/impl/AuditLogServiceImpl.java b/src/main/java/com/czertainly/core/service/impl/AuditLogServiceImpl.java
index c100acaea..33307ffa7 100644
--- a/src/main/java/com/czertainly/core/service/impl/AuditLogServiceImpl.java
+++ b/src/main/java/com/czertainly/core/service/impl/AuditLogServiceImpl.java
@@ -9,7 +9,7 @@
import com.czertainly.core.model.auth.ResourceAction;
import com.czertainly.core.security.authz.ExternalAuthorization;
import com.czertainly.core.service.AuditLogService;
-import com.czertainly.core.util.converter.Sql2PredicateConverter;
+import com.czertainly.core.util.FilterPredicatesBuilder;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
@@ -166,7 +166,7 @@ public ExportResultDto exportAuditLogs(AuditLogFilter filter, Sort sort) {
@AuditLogged(originator = ObjectType.FE, affected = ObjectType.AUDIT_LOG, operation = OperationType.DELETE)
@ExternalAuthorization(resource = Resource.AUDIT_LOG, action = ResourceAction.DELETE)
public void purgeAuditLogs(AuditLogFilter filter, Sort sort) {
- CriteriaDelete criteriaQueryDataObject = Sql2PredicateConverter.prepareQueryForAuditLog(filter, entityManager.getCriteriaBuilder());
+ CriteriaDelete criteriaQueryDataObject = FilterPredicatesBuilder.prepareQueryForAuditLog(filter, entityManager.getCriteriaBuilder());
entityManager.createQuery(criteriaQueryDataObject).executeUpdate();
}
diff --git a/src/main/java/com/czertainly/core/service/impl/CertificateEventHistoryServiceImpl.java b/src/main/java/com/czertainly/core/service/impl/CertificateEventHistoryServiceImpl.java
index 60f4dd7f9..1ed2461ad 100644
--- a/src/main/java/com/czertainly/core/service/impl/CertificateEventHistoryServiceImpl.java
+++ b/src/main/java/com/czertainly/core/service/impl/CertificateEventHistoryServiceImpl.java
@@ -1,17 +1,14 @@
package com.czertainly.core.service.impl;
import com.czertainly.api.exception.NotFoundException;
-import com.czertainly.api.model.client.certificate.SearchFilterRequestDto;
import com.czertainly.api.model.core.certificate.CertificateEvent;
import com.czertainly.api.model.core.certificate.CertificateEventHistoryDto;
import com.czertainly.api.model.core.certificate.CertificateEventStatus;
-import com.czertainly.api.model.core.search.SearchFieldDataDto;
import com.czertainly.core.dao.entity.Certificate;
import com.czertainly.core.dao.entity.CertificateEventHistory;
import com.czertainly.core.dao.repository.CertificateEventHistoryRepository;
import com.czertainly.core.dao.repository.CertificateRepository;
import com.czertainly.core.service.CertificateEventHistoryService;
-import com.czertainly.core.service.SearchService;
import com.czertainly.core.util.MetaDefinitions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -20,7 +17,6 @@
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
-import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.UUID;
@@ -36,8 +32,6 @@ public class CertificateEventHistoryServiceImpl implements CertificateEventHisto
private CertificateRepository certificateRepository;
@Autowired
private CertificateEventHistoryRepository certificateEventHistoryRepository;
- @Autowired
- private SearchService searchService;
@Override
public void addEventHistory(UUID certificateUuid, CertificateEvent event, CertificateEventStatus status, String message, HashMap additionalInformation) {
@@ -79,14 +73,5 @@ public void asyncSaveAllInBatch(List certificateEventHi
logger.info("Inserted {} record into the database", certificateEventHistories.size());
}
- @Override
- @Async
- public void addEventHistoryForRequest(List filters, String entity, List originalJson, CertificateEvent event, CertificateEventStatus status, String message) {
- List batchHistoryOperationList = new ArrayList<>();
- for (Certificate certificate : (List) searchService.completeSearchQueryExecutor(filters, "Certificate", originalJson)) {
- batchHistoryOperationList.add(getEventHistory(event, status, message, "", certificate));
- }
- asyncSaveAllInBatch(batchHistoryOperationList);
- }
}
diff --git a/src/main/java/com/czertainly/core/service/impl/CertificateServiceImpl.java b/src/main/java/com/czertainly/core/service/impl/CertificateServiceImpl.java
index 189d3a485..4fec88b8c 100644
--- a/src/main/java/com/czertainly/core/service/impl/CertificateServiceImpl.java
+++ b/src/main/java/com/czertainly/core/service/impl/CertificateServiceImpl.java
@@ -33,7 +33,7 @@
import com.czertainly.core.comparator.SearchFieldDataComparator;
import com.czertainly.core.dao.entity.*;
import com.czertainly.core.dao.repository.*;
-import com.czertainly.core.enums.SearchFieldNameEnum;
+import com.czertainly.core.enums.FilterField;
import com.czertainly.core.event.transaction.CertificateValidationEvent;
import com.czertainly.core.messaging.model.NotificationRecipient;
import com.czertainly.core.messaging.producers.EventProducer;
@@ -49,7 +49,6 @@
import com.czertainly.core.service.*;
import com.czertainly.core.service.v2.ExtendedAttributeService;
import com.czertainly.core.util.*;
-import com.czertainly.core.util.converter.Sql2PredicateConverter;
import com.czertainly.core.validation.certificate.ICertificateValidator;
import jakarta.persistence.criteria.*;
import org.apache.commons.lang3.function.TriFunction;
@@ -91,7 +90,9 @@
import java.time.Instant;
import java.time.LocalDateTime;
import java.util.*;
-import java.util.concurrent.*;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
import java.util.function.BiFunction;
import java.util.stream.Collectors;
@@ -99,12 +100,6 @@
@Transactional
public class CertificateServiceImpl implements CertificateService {
- // Default page size for the certificate search API when page size is not provided
- public static final Integer DEFAULT_PAGE_SIZE = 10;
- // Maximum page size for search API operation
- public static final Integer MAX_PAGE_SIZE = 1000;
- // Default batch size to perform bulk delete operation on Certificates
- public static final Integer DELETE_BATCH_SIZE = 1000;
private static final String UNDEFINED_CERTIFICATE_OBJECT_NAME = "undefined";
private static final Logger logger = LoggerFactory.getLogger(CertificateServiceImpl.class);
@@ -142,9 +137,6 @@ public class CertificateServiceImpl implements CertificateService {
@Autowired
private CertificateEventHistoryService certificateEventHistoryService;
- @Autowired
- private SearchService searchService;
-
@Lazy
@Autowired
private LocationService locationService;
@@ -303,7 +295,7 @@ public Certificate getCertificateEntityByIssuerDnNormalizedAndSerialNumber(Strin
}
@Override
- public Boolean checkCertificateExistsByFingerprint(String fingerprint) {
+ public boolean checkCertificateExistsByFingerprint(String fingerprint) {
try {
return certificateRepository.findByFingerprint(fingerprint).isPresent();
} catch (Exception e) {
@@ -374,26 +366,57 @@ private void updateTrustedCaMark(SecuredUUID uuid, Boolean trustedCa) throws Not
@Override
@AuditLogged(originator = ObjectType.FE, affected = ObjectType.CERTIFICATE, operation = OperationType.CHANGE)
@ExternalAuthorization(resource = Resource.CERTIFICATE, action = ResourceAction.UPDATE, parentResource = Resource.RA_PROFILE, parentAction = ResourceAction.DETAIL)
- public void bulkUpdateCertificateObjects(SecurityFilter filter, MultipleCertificateObjectUpdateDto request) throws NotFoundException {
+ @Transactional(propagation = Propagation.NOT_SUPPORTED)
+ public void bulkUpdateCertificatesObjects(SecurityFilter filter, MultipleCertificateObjectUpdateDto request) throws NotFoundException, NotSupportedException {
logger.info("Bulk updating certificate objects: RA {} groups {} owner {}", request.getRaProfileUuid(), request.getGroupUuids(), request.getOwnerUuid());
setupSecurityFilter(filter);
- if (request.getRaProfileUuid() != null) {
- bulkUpdateRaProfile(filter, request);
+ Set groupUuids = null;
+ if (request.getGroupUuids() != null)
+ groupUuids = request.getGroupUuids().stream().map(UUID::fromString).collect(Collectors.toSet());
+ String ownerUuid = null;
+ if (request.getOwnerUuid() != null && !request.getOwnerUuid().isEmpty()) {
+ ownerUuid = request.getOwnerUuid();
}
- if (request.getGroupUuids() != null) {
- bulkUpdateCertificateGroup(filter, request);
+
+ boolean removeRaProfile = false;
+ if (request.getRaProfileUuid() != null) removeRaProfile = request.getRaProfileUuid().isEmpty();
+
+ if (request.getFilters() != null && !request.getFilters().isEmpty() && (request.getCertificateUuids() == null || request.getCertificateUuids().isEmpty())) {
+ throw new NotSupportedException("Bulk updating of certificates by filters is not supported.");
}
- if (request.getOwnerUuid() != null) {
- bulkUpdateOwner(filter, request);
+
+ UUID loggedUserUuid = null;
+ for (String certificateUuidString : request.getCertificateUuids()) {
+ SecuredUUID certificateUuid = SecuredUUID.fromString(certificateUuidString);
+ TransactionStatus status = transactionManager.getTransaction(new DefaultTransactionDefinition());
+ try {
+ bulkUpdateCertificateObjects(request, certificateUuid, groupUuids, ownerUuid, removeRaProfile);
+ transactionManager.commit(status);
+ } catch (Exception e) {
+ transactionManager.rollback(status);
+ logger.error("Error occurred when updating certificate with UUID {}: {}", certificateUuidString, e.getMessage());
+ if (loggedUserUuid == null) {
+ loggedUserUuid = UUID.fromString(AuthHelper.getUserIdentification().getUuid());
+ }
+ notificationProducer.produceNotificationText(Resource.CERTIFICATE, certificateUuid.getValue(), NotificationRecipient.buildUserNotificationRecipient(loggedUserUuid), "Unable to update properties of the certificate " + certificateUuid, e.getMessage());
+ }
}
}
+ private void bulkUpdateCertificateObjects(MultipleCertificateObjectUpdateDto request, SecuredUUID certificateUuid, Set groupUuids, String ownerUuid, boolean removeRaProfile) throws NotFoundException, CertificateOperationException, AttributeException {
+ permissionEvaluator.certificate(certificateUuid);
+ if (groupUuids != null) updateCertificateGroups(certificateUuid, groupUuids);
+ if (request.getOwnerUuid() != null) updateOwner(certificateUuid, ownerUuid);
+ if (request.getRaProfileUuid() != null)
+ switchRaProfile(certificateUuid, removeRaProfile ? null : SecuredUUID.fromString(request.getRaProfileUuid()));
+ }
+
@Override
@AuditLogged(originator = ObjectType.FE, affected = ObjectType.CERTIFICATE, operation = OperationType.DELETE)
@Async
@ExternalAuthorization(resource = Resource.CERTIFICATE, action = ResourceAction.DELETE, parentResource = Resource.RA_PROFILE, parentAction = ResourceAction.DETAIL)
@Transactional(propagation = Propagation.NOT_SUPPORTED)
- public void bulkDeleteCertificate(SecurityFilter filter, RemoveCertificateDto request) throws NotFoundException {
+ public void bulkDeleteCertificate(SecurityFilter filter, RemoveCertificateDto request) throws NotFoundException, NotSupportedException {
setupSecurityFilter(filter);
UUID loggedUserUuid = null;
@@ -414,61 +437,43 @@ public void bulkDeleteCertificate(SecurityFilter filter, RemoveCertificateDto re
}
logger.debug("Bulk deleted {} of {} certificates.", deletedCount, request.getUuids().size());
} else {
- String joins = "WHERE c.userUuid IS NULL";
- String data = searchService.createCriteriaBuilderString(filter, true);
- if (!data.isEmpty()) {
- joins = joins + " AND " + data;
- }
-
- String customQuery = searchService.getQueryDynamicBasedOnFilter(request.getFilters(), "Certificate", getSearchableFieldInformation(), joins, false, false, "");
-
- List certListDyn = (List) searchService.customQueryExecutor(customQuery);
-
- for (List certificates : partitionList(certListDyn)) {
- certificateRepository.deleteAll(certificates);
- }
- for (List certificateContents : partitionContents(certificateContentRepository.findCertificateContentNotUsed())) {
- certificateContentRepository.deleteAll(certificateContents);
- }
+ throw new NotSupportedException("Bulk delete of certificates by filters is not supported.");
}
}
- @Deprecated
- public List getSearchableFieldInformation() {
- return getSearchableFieldsMap();
- }
@Override
public List getSearchableFieldInformationByGroup() {
final List searchFieldDataByGroupDtos = attributeEngine.getResourceSearchableFields(Resource.CERTIFICATE, false);
List fields = List.of(
- SearchHelper.prepareSearch(SearchFieldNameEnum.COMMON_NAME),
- SearchHelper.prepareSearch(SearchFieldNameEnum.SERIAL_NUMBER_LABEL),
- SearchHelper.prepareSearch(SearchFieldNameEnum.ISSUER_SERIAL_NUMBER),
- SearchHelper.prepareSearch(SearchFieldNameEnum.RA_PROFILE, raProfileRepository.findAll().stream().map(RaProfile::getName).toList()),
- SearchHelper.prepareSearch(SearchFieldNameEnum.GROUP, groupRepository.findAll().stream().map(Group::getName).toList()),
- SearchHelper.prepareSearch(SearchFieldNameEnum.CERT_LOCATION_NAME, locationRepository.findAll().stream().map(Location::getName).toList()),
- SearchHelper.prepareSearch(SearchFieldNameEnum.OWNER, userManagementApiClient.getUsers().getData().stream().map(UserDto::getUsername).toList()),
- SearchHelper.prepareSearch(SearchFieldNameEnum.CERTIFICATE_STATE, Arrays.stream(CertificateState.values()).map(CertificateState::getCode).toList()),
- SearchHelper.prepareSearch(SearchFieldNameEnum.CERTIFICATE_VALIDATION_STATUS, Arrays.stream(CertificateValidationStatus.values()).map(CertificateValidationStatus::getCode).toList()),
- SearchHelper.prepareSearch(SearchFieldNameEnum.COMPLIANCE_STATUS, Arrays.stream(ComplianceStatus.values()).map(ComplianceStatus::getCode).toList()),
- SearchHelper.prepareSearch(SearchFieldNameEnum.ISSUER_COMMON_NAME),
- SearchHelper.prepareSearch(SearchFieldNameEnum.FINGERPRINT),
- SearchHelper.prepareSearch(SearchFieldNameEnum.SIGNATURE_ALGORITHM, new ArrayList<>(certificateRepository.findDistinctSignatureAlgorithm())),
- SearchHelper.prepareSearch(SearchFieldNameEnum.EXPIRES),
- SearchHelper.prepareSearch(SearchFieldNameEnum.NOT_BEFORE),
- SearchHelper.prepareSearch(SearchFieldNameEnum.SUBJECT_DN),
- SearchHelper.prepareSearch(SearchFieldNameEnum.ISSUER_DN),
- SearchHelper.prepareSearch(SearchFieldNameEnum.SUBJECT_ALTERNATIVE),
- SearchHelper.prepareSearch(SearchFieldNameEnum.OCSP_VALIDATION, Arrays.stream((CertificateValidationStatus.values())).map(CertificateValidationStatus::getCode).toList()),
- SearchHelper.prepareSearch(SearchFieldNameEnum.CRL_VALIDATION, Arrays.stream((CertificateValidationStatus.values())).map(CertificateValidationStatus::getCode).toList()),
- SearchHelper.prepareSearch(SearchFieldNameEnum.SIGNATURE_VALIDATION, Arrays.stream((CertificateValidationStatus.values())).map(CertificateValidationStatus::getCode).toList()),
- SearchHelper.prepareSearch(SearchFieldNameEnum.PUBLIC_KEY_ALGORITHM, new ArrayList<>(certificateRepository.findDistinctPublicKeyAlgorithm())),
- SearchHelper.prepareSearch(SearchFieldNameEnum.KEY_SIZE, new ArrayList<>(certificateRepository.findDistinctKeySize())),
- SearchHelper.prepareSearch(SearchFieldNameEnum.KEY_USAGE, serializedListOfStringToListOfObject(certificateRepository.findDistinctKeyUsage())),
- SearchHelper.prepareSearch(SearchFieldNameEnum.PRIVATE_KEY),
- SearchHelper.prepareSearch(SearchFieldNameEnum.TRUSTED_CA)
+ SearchHelper.prepareSearch(FilterField.COMMON_NAME),
+ SearchHelper.prepareSearch(FilterField.SERIAL_NUMBER),
+ SearchHelper.prepareSearch(FilterField.ISSUER_SERIAL_NUMBER),
+ SearchHelper.prepareSearch(FilterField.RA_PROFILE_NAME, raProfileRepository.findAll().stream().map(RaProfile::getName).toList()),
+ SearchHelper.prepareSearch(FilterField.GROUP_NAME, groupRepository.findAll().stream().map(Group::getName).toList()),
+ SearchHelper.prepareSearch(FilterField.CERT_LOCATION_NAME, locationRepository.findAll().stream().map(Location::getName).toList()),
+ SearchHelper.prepareSearch(FilterField.OWNER, userManagementApiClient.getUsers().getData().stream().map(UserDto::getUsername).toList()),
+ SearchHelper.prepareSearch(FilterField.CERTIFICATE_STATE, Arrays.stream(CertificateState.values()).map(CertificateState::getCode).toList()),
+ SearchHelper.prepareSearch(FilterField.CERTIFICATE_VALIDATION_STATUS, Arrays.stream(CertificateValidationStatus.values()).map(CertificateValidationStatus::getCode).toList()),
+ SearchHelper.prepareSearch(FilterField.COMPLIANCE_STATUS, Arrays.stream(ComplianceStatus.values()).map(ComplianceStatus::getCode).toList()),
+ SearchHelper.prepareSearch(FilterField.ISSUER_COMMON_NAME),
+ SearchHelper.prepareSearch(FilterField.FINGERPRINT),
+ SearchHelper.prepareSearch(FilterField.SIGNATURE_ALGORITHM, new ArrayList<>(certificateRepository.findDistinctSignatureAlgorithm())),
+ SearchHelper.prepareSearch(FilterField.NOT_AFTER),
+ SearchHelper.prepareSearch(FilterField.NOT_BEFORE),
+ SearchHelper.prepareSearch(FilterField.SUBJECTDN),
+ SearchHelper.prepareSearch(FilterField.ISSUERDN),
+ SearchHelper.prepareSearch(FilterField.SUBJECT_ALTERNATIVE_NAMES),
+ SearchHelper.prepareSearch(FilterField.OCSP_VALIDATION, Arrays.stream((CertificateValidationStatus.values())).map(CertificateValidationStatus::getCode).toList()),
+ SearchHelper.prepareSearch(FilterField.CRL_VALIDATION, Arrays.stream((CertificateValidationStatus.values())).map(CertificateValidationStatus::getCode).toList()),
+ SearchHelper.prepareSearch(FilterField.SIGNATURE_VALIDATION, Arrays.stream((CertificateValidationStatus.values())).map(CertificateValidationStatus::getCode).toList()),
+ SearchHelper.prepareSearch(FilterField.PUBLIC_KEY_ALGORITHM, new ArrayList<>(certificateRepository.findDistinctPublicKeyAlgorithm())),
+ SearchHelper.prepareSearch(FilterField.KEY_SIZE, new ArrayList<>(certificateRepository.findDistinctKeySize())),
+ SearchHelper.prepareSearch(FilterField.KEY_USAGE, serializedListOfStringToListOfObject(certificateRepository.findDistinctKeyUsage())),
+ SearchHelper.prepareSearch(FilterField.PRIVATE_KEY),
+ SearchHelper.prepareSearch(FilterField.SUBJECT_TYPE, Arrays.stream(CertificateSubjectType.values()).map(CertificateSubjectType::getCode).toList()),
+ SearchHelper.prepareSearch(FilterField.TRUSTED_CA)
);
fields = new ArrayList<>(fields);
@@ -1082,7 +1087,7 @@ public StatisticsDto addCertificateStatistics(SecurityFilter filter, StatisticsD
return null;
},
() -> {
- dto.setCertificateStatByBasicConstraints(certificateRepository.countGroupedUsingSecurityFilter(filter, null, Certificate_.basicConstraints, null));
+ dto.setCertificateStatBySubjectType(certificateRepository.countGroupedUsingSecurityFilter(filter, null, Certificate_.subjectType, null));
return null;
},
() -> {
@@ -1387,34 +1392,6 @@ public List listCmpSigningCertificates(SecurityFilter filter) {
.map(Certificate::mapToListDto).toList();
}
- private String getExpiryTime(Date now, Date expiry) {
- long diffInMilliseconds = expiry.getTime() - now.getTime();
- long difference = TimeUnit.DAYS.convert(diffInMilliseconds, TimeUnit.MILLISECONDS);
- if (diffInMilliseconds <= 0) {
- return "expired";
- } else if (difference < 10) {
- return "10";
- } else if (difference < 20) {
- return "20";
- } else if (difference < 30) {
- return "30";
- } else if (difference < 60) {
- return "60";
- } else if (difference < 90) {
- return "90";
- }
- return "More";
- }
-
-
- @Deprecated
- private List getSearchableFieldsMap() {
-
- final List fields = List.of(SearchHelper.prepareSearch(SearchFieldNameEnum.COMMON_NAME), SearchHelper.prepareSearch(SearchFieldNameEnum.SERIAL_NUMBER_LABEL), SearchHelper.prepareSearch(SearchFieldNameEnum.ISSUER_SERIAL_NUMBER), SearchHelper.prepareSearch(SearchFieldNameEnum.RA_PROFILE, raProfileRepository.findAll().stream().map(RaProfile::getName).toList()), SearchHelper.prepareSearch(SearchFieldNameEnum.GROUP, groupRepository.findAll().stream().map(Group::getName).toList()), SearchHelper.prepareSearch(SearchFieldNameEnum.OWNER), SearchHelper.prepareSearch(SearchFieldNameEnum.CERTIFICATE_STATE, Arrays.stream(CertificateState.values()).map(CertificateState::getCode).toList()), SearchHelper.prepareSearch(SearchFieldNameEnum.CERTIFICATE_VALIDATION_STATUS, Arrays.stream(CertificateValidationStatus.values()).map(CertificateValidationStatus::getCode).toList()), SearchHelper.prepareSearch(SearchFieldNameEnum.COMPLIANCE_STATUS, Arrays.stream(ComplianceStatus.values()).map(ComplianceStatus::getCode).toList()), SearchHelper.prepareSearch(SearchFieldNameEnum.ISSUER_COMMON_NAME), SearchHelper.prepareSearch(SearchFieldNameEnum.FINGERPRINT), SearchHelper.prepareSearch(SearchFieldNameEnum.SIGNATURE_ALGORITHM, new ArrayList<>(certificateRepository.findDistinctSignatureAlgorithm())), SearchHelper.prepareSearch(SearchFieldNameEnum.EXPIRES), SearchHelper.prepareSearch(SearchFieldNameEnum.NOT_BEFORE), SearchHelper.prepareSearch(SearchFieldNameEnum.SUBJECT_DN), SearchHelper.prepareSearch(SearchFieldNameEnum.ISSUER_DN), SearchHelper.prepareSearch(SearchFieldNameEnum.SUBJECT_ALTERNATIVE), SearchHelper.prepareSearch(SearchFieldNameEnum.OCSP_VALIDATION, Arrays.stream((CertificateValidationStatus.values())).map(CertificateValidationStatus::getCode).toList()), SearchHelper.prepareSearch(SearchFieldNameEnum.CRL_VALIDATION, Arrays.stream((CertificateValidationStatus.values())).map(CertificateValidationStatus::getCode).toList()), SearchHelper.prepareSearch(SearchFieldNameEnum.SIGNATURE_VALIDATION, Arrays.stream((CertificateValidationStatus.values())).map(CertificateValidationStatus::getCode).toList()), SearchHelper.prepareSearch(SearchFieldNameEnum.PUBLIC_KEY_ALGORITHM, new ArrayList<>(certificateRepository.findDistinctPublicKeyAlgorithm())), SearchHelper.prepareSearch(SearchFieldNameEnum.KEY_SIZE, new ArrayList<>(certificateRepository.findDistinctKeySize())), SearchHelper.prepareSearch(SearchFieldNameEnum.KEY_USAGE, serializedListOfStringToListOfObject(certificateRepository.findDistinctKeyUsage())));
-
- logger.debug("Searchable Fields: {}", fields);
- return fields;
- }
private List