From 3d35eafa51b4fccce67f04eb74338c2ba8145408 Mon Sep 17 00:00:00 2001 From: ThatSilentCoder <184309164+ThatSilentCoder@users.noreply.github.com> Date: Wed, 16 Apr 2025 18:06:00 -0400 Subject: [PATCH] v3_issue_811: Created an enum that represents the certificate type, deleted the two new services because didnt want the PR to be outside of the scope of the issue (created a new issue that addresses the separation of responsibility), fixing up checkstyle issues, and currently fixing up comments left behind in previous commits. Almost PR ready. --- .../persist/service/CertificateService.java | 56 +++--- .../persist/service/CertificateType.java | 41 ++++ .../persist/service/DeviceService.java | 34 ++-- .../service/ReferenceDigestValueService.java | 95 --------- .../service/ReferenceManifestService.java | 183 ------------------ .../ValidationSummaryReportsService.java | 43 +++- .../EndorsementCredentialPageController.java | 11 +- .../IDevIdCertificatePageController.java | 11 +- .../IssuedCertificatePageController.java | 9 +- .../PlatformCredentialPageController.java | 11 +- .../ReferenceManifestPageController.java | 164 ++++++++++++++-- .../RimDatabasePageController.java | 90 ++++++++- .../TrustChainCertificatePageController.java | 15 +- 13 files changed, 385 insertions(+), 378 deletions(-) create mode 100644 HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/service/CertificateType.java delete mode 100644 HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/service/ReferenceDigestValueService.java delete mode 100644 HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/service/ReferenceManifestService.java diff --git a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/service/CertificateService.java b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/service/CertificateService.java index 3fa23a20..a3c0d6a2 100644 --- a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/service/CertificateService.java +++ b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/service/CertificateService.java @@ -13,6 +13,8 @@ import jakarta.persistence.EntityNotFoundException; import jakarta.persistence.TypedQuery; import jakarta.persistence.criteria.CriteriaBuilder; import jakarta.persistence.criteria.CriteriaQuery; +import jakarta.persistence.criteria.Expression; +import jakarta.persistence.criteria.Path; import jakarta.persistence.criteria.Predicate; import jakarta.persistence.criteria.Root; import lombok.extern.log4j.Log4j2; @@ -37,13 +39,6 @@ import java.util.zip.ZipOutputStream; @Log4j2 @Service public class CertificateService { - - private static final String TRUST_CHAIN = "trust-chain"; - private static final String PLATFORM_CREDENTIALS = "platform-credentials"; - private static final String IDEVID_CERTIFICATES = "idevid-certificates"; - private static final String ENDORSEMENT_CREDENTIALS = "endorsement-key-credentials"; - private static final String ISSUED_CERTIFICATES = "issued-certificates"; - private final CertificateRepository certificateRepository; private final ComponentResultRepository componentResultRepository; private final EntityManager entityManager; @@ -93,18 +88,28 @@ public class CertificateService { // Dynamically loop through columns and create LIKE conditions for each searchable column for (String columnName : searchableColumns) { - // there is a possibility that one of the column names - // that matches one of the class fields is nested (e.g. device.name) , - // and we will need to do further work to extract the - // field name - if (columnName.contains(".")) { + // Get the attribute type from entity root + Path fieldPath = rootCertificate.get(columnName); + // if the field is a string type + if (String.class.equals(fieldPath.getJavaType())) { + Predicate predicate = + criteriaBuilder.like(criteriaBuilder.lower(rootCertificate.get(columnName)), + "%" + searchText.toLowerCase() + "%"); + predicates.add(predicate); } + // if the field is a non-string type + else { + // convert the field to a string + Expression fieldAsString = criteriaBuilder + .literal(fieldPath).as(String.class); - Predicate predicate = - criteriaBuilder.like(criteriaBuilder.lower(rootCertificate.get(columnName)), - "%" + searchText.toLowerCase() + "%"); - predicates.add(predicate); + Predicate predicate = criteriaBuilder.like( + criteriaBuilder.lower(fieldAsString), + "%" + searchText.toLowerCase() + "%" + ); + predicates.add(predicate); + } } } @@ -146,7 +151,7 @@ public class CertificateService { * @param certificate the certificate to store */ public void storeCertificate( - final String certificateType, + final CertificateType certificateType, final String fileName, final List successMessages, final List errorMessages, @@ -170,7 +175,7 @@ public class CertificateService { try { // save the new certificate if no match is found if (existingCertificate == null) { - if (certificateType.equals(PLATFORM_CREDENTIALS)) { + if (certificateType.equals(CertificateType.PLATFORM_CREDENTIALS)) { PlatformCredential platformCertificate = (PlatformCredential) certificate; if (platformCertificate.isPlatformBase()) { List sharedCertificates = getPlatformCertificateByBoardSN( @@ -262,7 +267,7 @@ public class CertificateService { * @param errorMessages contains any error messages that will be displayed on the page */ public void deleteCertificate(final UUID uuid, - final String certificateType, + final CertificateType certificateType, final List successMessages, final List errorMessages) { @@ -275,7 +280,7 @@ public class CertificateService { log.warn(notFoundMessage); throw new EntityNotFoundException(notFoundMessage); } else { - if (certificateType.equals(PLATFORM_CREDENTIALS)) { + if (certificateType.equals(CertificateType.PLATFORM_CREDENTIALS)) { PlatformCredential platformCertificate = (PlatformCredential) certificate; if (platformCertificate.isPlatformBase()) { // only do this if the base is being deleted. @@ -305,12 +310,13 @@ public class CertificateService { /** * Packages a collection of certificates into a zip file. * - * @param zipOut zip outputs streams - * @param singleFileName zip file name + * @param zipOut zip outputs streams + * @param singleFileName zip file name + * @param certificateType certificate type * @throws IOException if there are any issues packaging or downloading the zip file */ public void bulkDownloadCertificates(final ZipOutputStream zipOut, - final String certificateType, + final CertificateType certificateType, final String singleFileName) throws IOException { String zipFileName; final List certificates = findCertificatesByType(certificateType); @@ -337,7 +343,7 @@ public class CertificateService { * @param certificateType certificate type * @return list of certificates */ - private List findCertificatesByType(String certificateType) { + private List findCertificatesByType(final CertificateType certificateType) { return switch (certificateType) { case PLATFORM_CREDENTIALS -> this.certificateRepository .findByType( @@ -367,7 +373,7 @@ public class CertificateService { * @return the certificate or null if none is found */ private Certificate getCertificateByHash( - final String certificateType, + final CertificateType certificateType, final int certificateHash) { return switch (certificateType) { case PLATFORM_CREDENTIALS -> this.certificateRepository diff --git a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/service/CertificateType.java b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/service/CertificateType.java new file mode 100644 index 00000000..28bd6676 --- /dev/null +++ b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/service/CertificateType.java @@ -0,0 +1,41 @@ +package hirs.attestationca.persist.service; + +import lombok.Getter; + +/** + * Contains a set of request mapping paths associated with the endpoints for the Certificate Pages. + * Each entry in this enum corresponds to a specific URL pattern handled by the controller for managing certificate-related requests. + */ +@Getter +public enum CertificateType { + /** + * Represents the request mapping path for the endpoints inside the Platform Credentials Page controller. + */ + PLATFORM_CREDENTIALS("platform-credentials"), + + /** + * Represents the request mapping path for the endpoints inside the Endorsement Key Credentials Page controller. + */ + ENDORSEMENT_CREDENTIALS("endorsement-key-credentials"), + + /** + * Represents the request mapping path for the endpoints inside the IdevId Page controller. + */ + IDEVID_CERTIFICATES("idevid-certificates"), + + /** + * Represents the request mapping path for the endpoints inside the Issued Certificates Page controller. + */ + ISSUED_CERTIFICATES("issued-certificates"), + + /** + * Represents the request mapping path for the endpoints inside the Trust Chains Page controller. + */ + TRUST_CHAIN("trust-chain"); + + private final String certificateTypePath; + + CertificateType(final String certificateTypePath) { + this.certificateTypePath = certificateTypePath; + } +} diff --git a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/service/DeviceService.java b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/service/DeviceService.java index ec2f0d09..3582924c 100644 --- a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/service/DeviceService.java +++ b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/service/DeviceService.java @@ -13,6 +13,8 @@ import jakarta.persistence.EntityManager; import jakarta.persistence.TypedQuery; import jakarta.persistence.criteria.CriteriaBuilder; import jakarta.persistence.criteria.CriteriaQuery; +import jakarta.persistence.criteria.Expression; +import jakarta.persistence.criteria.Path; import jakarta.persistence.criteria.Predicate; import jakarta.persistence.criteria.Root; import lombok.extern.log4j.Log4j2; @@ -90,21 +92,29 @@ public class DeviceService { if (!StringUtils.isBlank(searchText)) { // Dynamically loop through columns and create LIKE conditions for each searchable column for (String columnName : searchableColumns) { + // Get the attribute type from entity root + Path fieldPath = deviceRoot.get(columnName); - // there is a possibility that one of the column names - // that matches one of the class fields is nested (e.g. device.name) , - // and we will need to do further work to extract the - // field name - // todo - if (columnName.contains(".")) { - + // if the field is a string type + if (String.class.equals(fieldPath.getJavaType())) { + Predicate predicate = + criteriaBuilder.like( + criteriaBuilder.lower(deviceRoot.get(columnName)), + "%" + searchText.toLowerCase() + "%"); + predicates.add(predicate); } + // if the field is a non-string type + else { + // convert the field to a string + Expression fieldAsString = criteriaBuilder + .literal(fieldPath).as(String.class); - Predicate predicate = - criteriaBuilder.like( - criteriaBuilder.lower(deviceRoot.get(columnName)), - "%" + searchText.toLowerCase() + "%"); - predicates.add(predicate); + Predicate predicate = criteriaBuilder.like( + criteriaBuilder.lower(fieldAsString), + "%" + searchText.toLowerCase() + "%" + ); + predicates.add(predicate); + } } } diff --git a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/service/ReferenceDigestValueService.java b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/service/ReferenceDigestValueService.java deleted file mode 100644 index e796adec..00000000 --- a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/service/ReferenceDigestValueService.java +++ /dev/null @@ -1,95 +0,0 @@ -package hirs.attestationca.persist.service; - -import hirs.attestationca.persist.entity.userdefined.rim.ReferenceDigestValue; -import jakarta.persistence.EntityManager; -import jakarta.persistence.TypedQuery; -import jakarta.persistence.criteria.CriteriaBuilder; -import jakarta.persistence.criteria.CriteriaQuery; -import jakarta.persistence.criteria.Expression; -import jakarta.persistence.criteria.Path; -import jakarta.persistence.criteria.Predicate; -import jakarta.persistence.criteria.Root; -import lombok.extern.log4j.Log4j2; -import org.apache.commons.lang3.StringUtils; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.PageImpl; -import org.springframework.data.domain.Pageable; -import org.springframework.stereotype.Service; - -import java.util.ArrayList; -import java.util.List; - -/** - * - */ -@Service -@Log4j2 -public class ReferenceDigestValueService { - - private final EntityManager entityManager; - - public ReferenceDigestValueService(EntityManager entityManager) { - this.entityManager = entityManager; - } - - /** - * @param searchableColumns list of the searchable column name - * @param searchText text that was input in the search textbox - * @param pageable pageable - * @return page full of reference digest values - */ - public Page findReferenceDigestValuesBySearchableColumns( - final List searchableColumns, - final String searchText, - final Pageable pageable) { - CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); - CriteriaQuery query = - criteriaBuilder.createQuery(ReferenceDigestValue.class); - Root referenceDigestValueRoot = - query.from(ReferenceDigestValue.class); - - List predicates = new ArrayList<>(); - - // Dynamically add search conditions for each field that should be searchable - if (!StringUtils.isBlank(searchText)) { - // Dynamically loop through columns and create LIKE conditions for each searchable column - for (String columnName : searchableColumns) { - // Get the attribute type from entity root - Path fieldPath = referenceDigestValueRoot.get(columnName); - - // if the field is a string type - if (String.class.equals(fieldPath.getJavaType())) { - Predicate predicate = - criteriaBuilder.like( - criteriaBuilder.lower(referenceDigestValueRoot.get(columnName)), - "%" + searchText.toLowerCase() + "%"); - predicates.add(predicate); - } - // if the field is a non-string type - else { - Expression fieldAsString = criteriaBuilder - .literal(fieldPath).as(String.class); - - Predicate predicate = criteriaBuilder.like( - criteriaBuilder.lower(fieldAsString), - "%" + searchText.toLowerCase() + "%" - ); - - predicates.add(predicate); - } - } - } - - query.where(criteriaBuilder.or(predicates.toArray(new Predicate[0]))); - - // Apply pagination - TypedQuery typedQuery = entityManager.createQuery(query); - int totalRows = typedQuery.getResultList().size(); // Get the total count for pagination - typedQuery.setFirstResult((int) pageable.getOffset()); - typedQuery.setMaxResults(pageable.getPageSize()); - - // Wrap the result in a Page object to return pagination info - List resultList = typedQuery.getResultList(); - return new PageImpl<>(resultList, pageable, totalRows); - } -} diff --git a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/service/ReferenceManifestService.java b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/service/ReferenceManifestService.java deleted file mode 100644 index 4064ab4f..00000000 --- a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/service/ReferenceManifestService.java +++ /dev/null @@ -1,183 +0,0 @@ -package hirs.attestationca.persist.service; - -import hirs.attestationca.persist.entity.manager.ReferenceDigestValueRepository; -import hirs.attestationca.persist.entity.manager.ReferenceManifestRepository; -import hirs.attestationca.persist.entity.userdefined.ReferenceManifest; -import hirs.attestationca.persist.entity.userdefined.rim.BaseReferenceManifest; -import hirs.attestationca.persist.entity.userdefined.rim.SupportReferenceManifest; -import jakarta.persistence.EntityManager; -import jakarta.persistence.TypedQuery; -import jakarta.persistence.criteria.CriteriaBuilder; -import jakarta.persistence.criteria.CriteriaQuery; -import jakarta.persistence.criteria.Predicate; -import jakarta.persistence.criteria.Root; -import lombok.extern.log4j.Log4j2; -import org.apache.commons.lang3.StringUtils; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.PageImpl; -import org.springframework.data.domain.Pageable; -import org.springframework.stereotype.Service; -import org.springframework.util.StreamUtils; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; -import java.util.zip.ZipEntry; -import java.util.zip.ZipOutputStream; - -/** - * - */ -@Service -@Log4j2 -public class ReferenceManifestService { - - private final EntityManager entityManager; - private final ReferenceManifestRepository referenceManifestRepository; - private final ReferenceDigestValueRepository referenceDigestValueRepository; - - - public ReferenceManifestService(EntityManager entityManager, - ReferenceManifestRepository referenceManifestRepository, - ReferenceDigestValueRepository referenceDigestValueRepository) { - this.entityManager = entityManager; - this.referenceManifestRepository = referenceManifestRepository; - this.referenceDigestValueRepository = referenceDigestValueRepository; - } - - /** - * Takes the provided column names, the search term that the user entered and attempts to find - * RIMS whose field values matches the provided search term. - * - * @param searchableColumns list of the searchable column names - * @param searchText text that was input in the search textbox - * @param archiveFlag archive flag - * @param pageable pageable - * @return page full of reference manifests - */ - public Page findRIMSBySearchableColumnsAndArchiveFlag( - final List searchableColumns, - final String searchText, - final boolean archiveFlag, - final Pageable pageable) { - CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); - CriteriaQuery query = criteriaBuilder.createQuery(ReferenceManifest.class); - Root rimRoot = query.from(ReferenceManifest.class); - - List predicates = new ArrayList<>(); - - // Dynamically add search conditions for each field that should be searchable - if (!StringUtils.isBlank(searchText)) { - // Dynamically loop through columns and create LIKE conditions for each searchable column - for (String columnName : searchableColumns) { - - // there is a possibility that one of the column names - // that matches one of the class fields is nested (e.g. device.name) , - // and we will need to do further work to extract the - // field name - // todo - if (columnName.contains(".")) { - - } - - Predicate predicate = - criteriaBuilder.like( - criteriaBuilder.lower(rimRoot.get(columnName)), - "%" + searchText.toLowerCase() + "%"); - predicates.add(predicate); - } - } - - Predicate likeConditions = criteriaBuilder.or(predicates.toArray(new Predicate[0])); - - // Add archiveFlag condition if specified - query.where(criteriaBuilder.and(likeConditions, - criteriaBuilder.equal(rimRoot.get("archiveFlag"), archiveFlag))); - - // Apply pagination - TypedQuery typedQuery = entityManager.createQuery(query); - int totalRows = typedQuery.getResultList().size(); // Get the total count for pagination - typedQuery.setFirstResult((int) pageable.getOffset()); - typedQuery.setMaxResults(pageable.getPageSize()); - - // Wrap the result in a Page object to return pagination info - List resultList = typedQuery.getResultList(); - return new PageImpl<>(resultList, pageable, totalRows); - } - - /** - * Retrieves all RIMs from the database based on the provided archive flag. - * - * @param archiveFlag archive flag - * @param pageable pageable - * @return page of RIMs - */ - public Page findAllRIMsByArchiveFlag(final boolean archiveFlag, - final Pageable pageable) { - return referenceManifestRepository.findByArchiveFlag(archiveFlag, pageable); - } - - /** - * This method takes the parameter and looks for this information in the - * Database. - * - * @param uuid RIM uuid - * @return the associated RIM from the DB - */ - public ReferenceManifest findSpecifiedRIM(final UUID uuid) { - if (referenceManifestRepository.existsById(uuid)) { - return referenceManifestRepository.getReferenceById(uuid); - } - return null; - } - - /** - * Packages a collection of RIMs into a zip file. - * - * @param zipOut zip outputs streams - * @throws IOException if there are any issues packaging or downloading the zip file - */ - public void bulkDownloadRIMS(ZipOutputStream zipOut) throws IOException { - List allRIMs = this.referenceManifestRepository.findAll(); - - List referenceManifestList = new ArrayList<>(); - - for (ReferenceManifest rim : allRIMs) { - if ((rim instanceof BaseReferenceManifest) - || (rim instanceof SupportReferenceManifest)) { - referenceManifestList.add(rim); - } - } - - String zipFileName; - - // get all files - for (ReferenceManifest rim : referenceManifestList) { - if (rim.getFileName().isEmpty()) { - zipFileName = ""; - } else { - // configure the zip entry, the properties of the 'file' - zipFileName = rim.getFileName(); - } - ZipEntry zipEntry = new ZipEntry(zipFileName); - zipEntry.setSize((long) rim.getRimBytes().length * Byte.SIZE); - zipEntry.setTime(System.currentTimeMillis()); - zipOut.putNextEntry(zipEntry); - // the content of the resource - StreamUtils.copy(rim.getRimBytes(), zipOut); - zipOut.closeEntry(); - } - zipOut.finish(); - } - - - /** - * Deletes the specified reference manifest. - * - * @param referencedManifest - */ - public void deleteSpecifiedRIM(ReferenceManifest referencedManifest) { - referenceManifestRepository.delete(referencedManifest); - } -} diff --git a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/service/ValidationSummaryReportsService.java b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/service/ValidationSummaryReportsService.java index 33988a27..53a3c24f 100644 --- a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/service/ValidationSummaryReportsService.java +++ b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/service/ValidationSummaryReportsService.java @@ -15,6 +15,8 @@ import jakarta.persistence.EntityManager; import jakarta.persistence.TypedQuery; import jakarta.persistence.criteria.CriteriaBuilder; import jakarta.persistence.criteria.CriteriaQuery; +import jakarta.persistence.criteria.Expression; +import jakarta.persistence.criteria.Path; import jakarta.persistence.criteria.Predicate; import jakarta.persistence.criteria.Root; import jakarta.servlet.http.HttpServletRequest; @@ -61,6 +63,12 @@ public class ValidationSummaryReportsService { private final CertificateRepository certificateRepository; private final DeviceRepository deviceRepository; + /** + * @param platformCertificateRepository platform certificate repository + * @param certificateRepository certificate repository + * @param deviceRepository device repository + * @param entityManager entity manager + */ @Autowired public ValidationSummaryReportsService(final PlatformCertificateRepository platformCertificateRepository, final CertificateRepository certificateRepository, @@ -86,8 +94,8 @@ public class ValidationSummaryReportsService { public Page findValidationReportsBySearchableColumnsAndArchiveFlag( final List searchableColumns, final String searchText, - Boolean archiveFlag, - Pageable pageable) { + final boolean archiveFlag, + final Pageable pageable) { CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); CriteriaQuery query = criteriaBuilder.createQuery(SupplyChainValidationSummary.class); @@ -108,13 +116,34 @@ public class ValidationSummaryReportsService { // todo if (columnName.contains(".")) { + continue; } - Predicate predicate = - criteriaBuilder.like( - criteriaBuilder.lower(supplyChainValidationSummaryRoot.get(columnName)), - "%" + searchText.toLowerCase() + "%"); - predicates.add(predicate); + // assuming the column name is not a nested entity field + // Get the attribute type from entity root + Path fieldPath = supplyChainValidationSummaryRoot.get(columnName); + + // if the field is a string type + if (String.class.equals(fieldPath.getJavaType())) { + + Predicate predicate = + criteriaBuilder.like( + criteriaBuilder.lower(supplyChainValidationSummaryRoot.get(columnName)), + "%" + searchText.toLowerCase() + "%"); + predicates.add(predicate); + } + // if the field is a non-string type + else { + // convert the field to a string + Expression fieldAsString = criteriaBuilder + .literal(fieldPath).as(String.class); + + Predicate predicate = criteriaBuilder.like( + criteriaBuilder.lower(fieldAsString), + "%" + searchText.toLowerCase() + "%" + ); + predicates.add(predicate); + } } } diff --git a/HIRS_AttestationCAPortal/src/main/java/hirs/attestationca/portal/page/controllers/EndorsementCredentialPageController.java b/HIRS_AttestationCAPortal/src/main/java/hirs/attestationca/portal/page/controllers/EndorsementCredentialPageController.java index 53d153d2..f3021c17 100644 --- a/HIRS_AttestationCAPortal/src/main/java/hirs/attestationca/portal/page/controllers/EndorsementCredentialPageController.java +++ b/HIRS_AttestationCAPortal/src/main/java/hirs/attestationca/portal/page/controllers/EndorsementCredentialPageController.java @@ -5,6 +5,7 @@ import hirs.attestationca.persist.entity.manager.EndorsementCredentialRepository import hirs.attestationca.persist.entity.userdefined.Certificate; import hirs.attestationca.persist.entity.userdefined.certificate.EndorsementCredential; import hirs.attestationca.persist.service.CertificateService; +import hirs.attestationca.persist.service.CertificateType; import hirs.attestationca.portal.datatables.Column; import hirs.attestationca.portal.datatables.DataTableInput; import hirs.attestationca.portal.datatables.DataTableResponse; @@ -51,9 +52,6 @@ import java.util.zip.ZipOutputStream; @Controller @RequestMapping("/HIRS_AttestationCAPortal/portal/certificate-request/endorsement-key-credentials") public class EndorsementCredentialPageController extends PageController { - - private static final String ENDORSEMENT_CREDENTIALS = "endorsement-key-credentials"; - private final EndorsementCredentialRepository endorsementCredentialRepository; private final CertificateService certificateService; @@ -219,7 +217,8 @@ public class EndorsementCredentialPageController extends PageController { - - private static final String IDEVID_CERTIFICATE = "idevid-certificates"; - private final IDevIDCertificateRepository iDevIDCertificateRepository; private final CertificateService certificateService; @@ -216,7 +214,8 @@ public class IDevIdCertificatePageController extends PageController { - - private static final String ISSUED_CERTIFICATES = "issued-certificates"; - private final IssuedCertificateRepository issuedCertificateRepository; private final CertificateService certificateService; @@ -219,7 +217,8 @@ public class IssuedCertificatePageController extends PageController { - - private static final String PLATFORM_CREDENTIALS = "platform-credentials"; - private final PlatformCertificateRepository platformCertificateRepository; private final EndorsementCredentialRepository endorsementCredentialRepository; private final CertificateService certificateService; @@ -243,7 +241,8 @@ public class PlatformCredentialPageController extends PageController pagedResult; if (StringUtils.isBlank(searchText)) { - pagedResult = this.referenceManifestService.findAllRIMsByArchiveFlag(false, pageable); + pagedResult = this.referenceManifestRepository.findByArchiveFlag(false, pageable); } else { - pagedResult = - this.referenceManifestService.findRIMSBySearchableColumnsAndArchiveFlag(searchableColumns - , searchText, - false, - pageable); + pagedResult = findRIMSBySearchableColumnsAndArchiveFlag(searchableColumns + , searchText, + false, + pageable); } int rimCount = 0; @@ -247,7 +256,7 @@ public class ReferenceManifestPageController extends PageController findRIMSBySearchableColumnsAndArchiveFlag( + final List searchableColumns, + final String searchText, + final boolean archiveFlag, + final Pageable pageable) { + CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); + CriteriaQuery query = criteriaBuilder.createQuery(ReferenceManifest.class); + Root rimRoot = query.from(ReferenceManifest.class); + + List predicates = new ArrayList<>(); + + // Dynamically add search conditions for each field that should be searchable + if (!StringUtils.isBlank(searchText)) { + // Dynamically loop through columns and create LIKE conditions for each searchable column + for (String columnName : searchableColumns) { + // Get the attribute type from entity root + Path fieldPath = rimRoot.get(columnName); + + // if the field is a string type + if (String.class.equals(fieldPath.getJavaType())) { + Predicate predicate = + criteriaBuilder.like( + criteriaBuilder.lower(rimRoot.get(columnName)), + "%" + searchText.toLowerCase() + "%"); + predicates.add(predicate); + } + // if the field is a non-string type + else { + // convert the field to a string + Expression fieldAsString = criteriaBuilder + .literal(fieldPath).as(String.class); + + Predicate predicate = criteriaBuilder.like( + criteriaBuilder.lower(fieldAsString), + "%" + searchText.toLowerCase() + "%" + ); + predicates.add(predicate); + } + } + } + + Predicate likeConditions = criteriaBuilder.or(predicates.toArray(new Predicate[0])); + + // Add archiveFlag condition if specified + query.where(criteriaBuilder.and(likeConditions, + criteriaBuilder.equal(rimRoot.get("archiveFlag"), archiveFlag))); + + // Apply pagination + TypedQuery typedQuery = entityManager.createQuery(query); + int totalRows = typedQuery.getResultList().size(); // Get the total count for pagination + typedQuery.setFirstResult((int) pageable.getOffset()); + typedQuery.setMaxResults(pageable.getPageSize()); + + // Wrap the result in a Page object to return pagination info + List resultList = typedQuery.getResultList(); + return new PageImpl<>(resultList, pageable, totalRows); + } + + /** + * This method takes the parameter and looks for this information in the + * Database. + * + * @param uuid RIM uuid + * @return the associated RIM from the DB + */ + private ReferenceManifest findSpecifiedRIM(final UUID uuid) { + if (referenceManifestRepository.existsById(uuid)) { + return referenceManifestRepository.getReferenceById(uuid); + } + return null; + } + + /** + * Packages a collection of RIMs into a zip file. + * + * @param zipOut zip outputs streams + * @throws IOException if there are any issues packaging or downloading the zip file + */ + private void bulkDownloadRIMS(final ZipOutputStream zipOut) throws IOException { + List allRIMs = this.referenceManifestRepository.findAll(); + + List referenceManifestList = new ArrayList<>(); + + for (ReferenceManifest rim : allRIMs) { + if ((rim instanceof BaseReferenceManifest) + || (rim instanceof SupportReferenceManifest)) { + referenceManifestList.add(rim); + } + } + + String zipFileName; + + // get all files + for (ReferenceManifest rim : referenceManifestList) { + if (rim.getFileName().isEmpty()) { + zipFileName = ""; + } else { + // configure the zip entry, the properties of the 'file' + zipFileName = rim.getFileName(); + } + ZipEntry zipEntry = new ZipEntry(zipFileName); + zipEntry.setSize((long) rim.getRimBytes().length * Byte.SIZE); + zipEntry.setTime(System.currentTimeMillis()); + zipOut.putNextEntry(zipEntry); + // the content of the resource + StreamUtils.copy(rim.getRimBytes(), zipOut); + zipOut.closeEntry(); + } + zipOut.finish(); + } /** * Takes the rim files provided and returns a {@link ReferenceManifest} diff --git a/HIRS_AttestationCAPortal/src/main/java/hirs/attestationca/portal/page/controllers/RimDatabasePageController.java b/HIRS_AttestationCAPortal/src/main/java/hirs/attestationca/portal/page/controllers/RimDatabasePageController.java index a02a666f..955cf9b1 100644 --- a/HIRS_AttestationCAPortal/src/main/java/hirs/attestationca/portal/page/controllers/RimDatabasePageController.java +++ b/HIRS_AttestationCAPortal/src/main/java/hirs/attestationca/portal/page/controllers/RimDatabasePageController.java @@ -6,17 +6,25 @@ import hirs.attestationca.persist.entity.manager.ReferenceDigestValueRepository; import hirs.attestationca.persist.entity.manager.ReferenceManifestRepository; import hirs.attestationca.persist.entity.userdefined.rim.ReferenceDigestValue; import hirs.attestationca.persist.entity.userdefined.rim.SupportReferenceManifest; -import hirs.attestationca.persist.service.ReferenceDigestValueService; import hirs.attestationca.portal.datatables.Column; import hirs.attestationca.portal.datatables.DataTableInput; import hirs.attestationca.portal.datatables.DataTableResponse; import hirs.attestationca.portal.page.Page; import hirs.attestationca.portal.page.PageController; import hirs.attestationca.portal.page.params.NoPageParams; +import jakarta.persistence.EntityManager; +import jakarta.persistence.TypedQuery; +import jakarta.persistence.criteria.CriteriaBuilder; +import jakarta.persistence.criteria.CriteriaQuery; +import jakarta.persistence.criteria.Expression; +import jakarta.persistence.criteria.Path; +import jakarta.persistence.criteria.Predicate; +import jakarta.persistence.criteria.Root; import jakarta.validation.Valid; import lombok.extern.log4j.Log4j2; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; @@ -28,6 +36,7 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.servlet.ModelAndView; +import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; @@ -41,26 +50,27 @@ public class RimDatabasePageController extends PageController { private final ReferenceDigestValueRepository referenceDigestValueRepository; private final ReferenceManifestRepository referenceManifestRepository; - private final ReferenceDigestValueService referenceDigestValueService; + private final EntityManager entityManager; /** * Constructor providing the Page's display and routing specification. * * @param referenceDigestValueRepository the referenceDigestValueRepository object * @param referenceManifestRepository the reference manifest manager object + * @param entityManager entity manager */ @Autowired public RimDatabasePageController(final ReferenceDigestValueRepository referenceDigestValueRepository, final ReferenceManifestRepository referenceManifestRepository, - ReferenceDigestValueService referenceDigestValueService) { + final EntityManager entityManager) { super(Page.RIM_DATABASE); this.referenceDigestValueRepository = referenceDigestValueRepository; this.referenceManifestRepository = referenceManifestRepository; - this.referenceDigestValueService = referenceDigestValueService; + this.entityManager = entityManager; } /** - * Returns the filePath for the view and the data model for the page. + * Returns the filePath for the view and the data model for the RimDatabase page. * * @param params The object to map url parameters into. * @param model The data model for the request. Can contain data from @@ -84,7 +94,7 @@ public class RimDatabasePageController extends PageController { @ResponseBody @GetMapping(value = "/list", produces = MediaType.APPLICATION_JSON_VALUE) - public DataTableResponse getTableData( + public DataTableResponse getRDVTableData( @Valid final DataTableInput input) { log.info("Received request to display list of TPM events"); log.debug("Request received a datatable input object for the RIM database page: {}", input); @@ -106,7 +116,7 @@ public class RimDatabasePageController extends PageController { this.referenceDigestValueRepository.findAll(pageable); } else { pagedResult = - this.referenceDigestValueService.findReferenceDigestValuesBySearchableColumns( + findReferenceDigestValuesBySearchableColumns( searchableColumns, searchText, pageable); } @@ -152,4 +162,70 @@ public class RimDatabasePageController extends PageController { return columns.stream().filter(Column::isSearchable).map(Column::getName) .collect(Collectors.toList()); } + + + /** + * Takes the provided column names, the search term that the user entered and attempts to find + * reference digest values whose field values matches the provided search term. + * + * @param searchableColumns list of the searchable column name + * @param searchText text that was input in the search textbox + * @param pageable pageable + * @return page full of reference digest values + */ + private org.springframework.data.domain.Page + findReferenceDigestValuesBySearchableColumns( + final List searchableColumns, + final String searchText, + final Pageable pageable) { + CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); + CriteriaQuery query = + criteriaBuilder.createQuery(ReferenceDigestValue.class); + Root referenceDigestValueRoot = + query.from(ReferenceDigestValue.class); + + List predicates = new ArrayList<>(); + + // Dynamically add search conditions for each field that should be searchable + if (!StringUtils.isBlank(searchText)) { + // Dynamically loop through columns and create LIKE conditions for each searchable column + for (String columnName : searchableColumns) { + // Get the attribute type from entity root + Path fieldPath = referenceDigestValueRoot.get(columnName); + + // if the field is a string type + if (String.class.equals(fieldPath.getJavaType())) { + Predicate predicate = + criteriaBuilder.like( + criteriaBuilder.lower(referenceDigestValueRoot.get(columnName)), + "%" + searchText.toLowerCase() + "%"); + predicates.add(predicate); + } + // if the field is a non-string type + else { + // convert the field to a string + Expression fieldAsString = criteriaBuilder + .literal(fieldPath).as(String.class); + + Predicate predicate = criteriaBuilder.like( + criteriaBuilder.lower(fieldAsString), + "%" + searchText.toLowerCase() + "%" + ); + predicates.add(predicate); + } + } + } + + query.where(criteriaBuilder.or(predicates.toArray(new Predicate[0]))); + + // Apply pagination + TypedQuery typedQuery = entityManager.createQuery(query); + int totalRows = typedQuery.getResultList().size(); // Get the total count for pagination + typedQuery.setFirstResult((int) pageable.getOffset()); + typedQuery.setMaxResults(pageable.getPageSize()); + + // Wrap the result in a Page object to return pagination info + List resultList = typedQuery.getResultList(); + return new PageImpl<>(resultList, pageable, totalRows); + } } diff --git a/HIRS_AttestationCAPortal/src/main/java/hirs/attestationca/portal/page/controllers/TrustChainCertificatePageController.java b/HIRS_AttestationCAPortal/src/main/java/hirs/attestationca/portal/page/controllers/TrustChainCertificatePageController.java index f04a085c..d4707ff5 100644 --- a/HIRS_AttestationCAPortal/src/main/java/hirs/attestationca/portal/page/controllers/TrustChainCertificatePageController.java +++ b/HIRS_AttestationCAPortal/src/main/java/hirs/attestationca/portal/page/controllers/TrustChainCertificatePageController.java @@ -6,6 +6,7 @@ import hirs.attestationca.persist.entity.manager.CertificateRepository; import hirs.attestationca.persist.entity.userdefined.Certificate; import hirs.attestationca.persist.entity.userdefined.certificate.CertificateAuthorityCredential; import hirs.attestationca.persist.service.CertificateService; +import hirs.attestationca.persist.service.CertificateType; import hirs.attestationca.persist.util.CredentialHelper; import hirs.attestationca.portal.datatables.Column; import hirs.attestationca.portal.datatables.DataTableInput; @@ -61,14 +62,11 @@ import java.util.zip.ZipOutputStream; @Controller @RequestMapping("/HIRS_AttestationCAPortal/portal/certificate-request/trust-chain") public class TrustChainCertificatePageController extends PageController { - /** * Model attribute name used by initPage for the aca cert info. */ static final String ACA_CERT_DATA = "acaCertData"; - private static final String TRUST_CHAIN = "trust-chain"; - private final CertificateRepository certificateRepository; private final CACredentialRepository caCredentialRepository; private final CertificateService certificateService; @@ -182,7 +180,7 @@ public class TrustChainCertificatePageController extends PageController errorMessages = new ArrayList<>(); this.certificateService.storeCertificate( - TRUST_CHAIN, + CertificateType.TRUST_CHAIN, file.getOriginalFilename(), successMessages, errorMessages,