From f7ee7d3d887ba8d6e114f0b9728d0ad899f8013c Mon Sep 17 00:00:00 2001 From: ThatSilentCoder <184309164+ThatSilentCoder@users.noreply.github.com> Date: Fri, 11 Apr 2025 14:12:14 -0400 Subject: [PATCH] v3_issue_811: Can now do global search on all certificates and devices. WOrking on doing the same for the RIMs and RIM DB. Validation summary ug found and created an issue for said bug. Create the pipeline for doing a global search for validation summaires - will now need to figure out how to fix the issues for that page to get it to work 80% done. --- HIRS_AttestationCA/build.gradle | 1 + .../persist/service/CertificateService.java | 5 +- .../persist/service/DeviceService.java | 256 ++++++++++++ .../service/ReferenceManifestService.java | 77 ++++ .../ValidationSummaryReportsService.java | 376 +++++++++++++++++- .../CertificateDetailsPageController.java | 13 +- .../controllers/DevicePageController.java | 195 ++------- .../EndorsementCredentialPageController.java | 4 +- .../IDevIdCertificatePageController.java | 2 +- .../IssuedCertificatePageController.java | 2 +- .../PlatformCredentialPageController.java | 2 +- .../ReferenceManifestPageController.java | 34 +- .../ValidationReportsPageController.java | 349 +--------------- .../src/main/webapp/WEB-INF/jsp/devices.jsp | 2 + 14 files changed, 785 insertions(+), 533 deletions(-) create mode 100644 HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/service/DeviceService.java create mode 100644 HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/service/ReferenceManifestService.java diff --git a/HIRS_AttestationCA/build.gradle b/HIRS_AttestationCA/build.gradle index 88f24280..f07a8941 100644 --- a/HIRS_AttestationCA/build.gradle +++ b/HIRS_AttestationCA/build.gradle @@ -20,6 +20,7 @@ dependencies { implementation libs.commons.codec implementation libs.commons.io implementation libs.commons.lang3 + implementation libs.gson implementation libs.guava implementation libs.jackson.core implementation libs.jackson.databind 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 f2897d30..91d20722 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 @@ -93,7 +93,10 @@ public class CertificateService { // Dynamically loop through columns and create LIKE conditions for each searchable column for (String columnName : searchableColumns) { - // todo + // 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(".")) { } 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 new file mode 100644 index 00000000..ec2f0d09 --- /dev/null +++ b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/service/DeviceService.java @@ -0,0 +1,256 @@ +package hirs.attestationca.persist.service; + +import hirs.attestationca.persist.FilteredRecordsList; +import hirs.attestationca.persist.entity.manager.DeviceRepository; +import hirs.attestationca.persist.entity.manager.EndorsementCredentialRepository; +import hirs.attestationca.persist.entity.manager.IssuedCertificateRepository; +import hirs.attestationca.persist.entity.manager.PlatformCertificateRepository; +import hirs.attestationca.persist.entity.userdefined.Device; +import hirs.attestationca.persist.entity.userdefined.certificate.EndorsementCredential; +import hirs.attestationca.persist.entity.userdefined.certificate.IssuedAttestationCertificate; +import hirs.attestationca.persist.entity.userdefined.certificate.PlatformCredential; +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.beans.factory.annotation.Autowired; +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.Collections; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.UUID; + +/** + * Service layer class that handles the storage and retrieval of devices. + */ +@Service +@Log4j2 +public class DeviceService { + + private final DeviceRepository deviceRepository; + private final PlatformCertificateRepository platformCertificateRepository; + private final EndorsementCredentialRepository endorsementCredentialRepository; + private final IssuedCertificateRepository issuedCertificateRepository; + private final EntityManager entityManager; + + /** + * Constructor for Device Service. + * + * @param deviceRepository device repository + * @param platformCertificateRepository platform certificate repository + * @param endorsementCredentialRepository endorsement credential repository + * @param issuedCertificateRepository issued certificate repository + * @param entityManager entity manager + */ + @Autowired + public DeviceService(final DeviceRepository deviceRepository, + final PlatformCertificateRepository platformCertificateRepository, + final EndorsementCredentialRepository endorsementCredentialRepository, + final IssuedCertificateRepository issuedCertificateRepository, + final EntityManager entityManager) { + this.deviceRepository = deviceRepository; + this.platformCertificateRepository = platformCertificateRepository; + this.endorsementCredentialRepository = endorsementCredentialRepository; + this.issuedCertificateRepository = issuedCertificateRepository; + this.entityManager = entityManager; + } + + /** + * Takes the provided column names, the search term that the user entered and attempts to find + * devices 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 devices + */ + public Page findAllDevicesBySearchableColumns( + final List searchableColumns, + final String searchText, + final Pageable pageable) { + CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); + CriteriaQuery query = + criteriaBuilder.createQuery(Device.class); + Root deviceRoot = + query.from(Device.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(deviceRoot.get(columnName)), + "%" + 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); + } + + /** + * Retrieves all devices from the database. + * + * @param pageable pageable + * @return page of devices + */ + public Page findAllDevices(final Pageable pageable) { + return deviceRepository.findAll(pageable); + } + + /** + * Retrieves the total number of records in the device repository. + * + * @return total number of records in the device repository. + */ + public long findDeviceRepositoryCount() { + return this.deviceRepository.count(); + } + + /** + * Returns the list of devices combined with the certificates. + * + * @param deviceList list containing the devices + * @return a record list after the device and certificate was mapped together. + */ + public FilteredRecordsList> retrieveDevicesAndAssociatedCertificates( + final FilteredRecordsList deviceList) { + FilteredRecordsList> records = new FilteredRecordsList<>(); + // hashmap containing the device-certificate relationship + HashMap deviceCertMap = new HashMap<>(); + List deviceIdList = getDevicesId(deviceList); + List platformCredentialList = new ArrayList<>(); + List endorsementCredentialList = new ArrayList<>(); + List issuedCertificateList = new ArrayList<>(); + List certificateListFromMap = new LinkedList<>(); + + // parse if there is a Device + if (!deviceList.isEmpty()) { + // get a list of Certificates that contains the device IDs from the list + for (UUID id : deviceIdList) { + platformCredentialList.addAll(platformCertificateRepository.findByDeviceId(id)); + endorsementCredentialList.addAll(endorsementCredentialRepository.findByDeviceId(id)); + issuedCertificateList.addAll(issuedCertificateRepository.findByDeviceId(id)); + } + + HashMap> certificatePropertyMap; + // loop all the devices + for (Device device : deviceList) { + // hashmap containing the list of certificates based on the certificate type + certificatePropertyMap = new HashMap<>(); + + deviceCertMap.put("device", device); + String deviceName; + + // loop all the certificates and combined the ones that match the ID + for (PlatformCredential pc : platformCredentialList) { + deviceName = deviceRepository.findById(pc.getDeviceId()).get().getName(); + + // set the certificate if it's the same ID + if (device.getName().equals(deviceName)) { + String certificateId = PlatformCredential.class.getSimpleName(); + // create a new list for the certificate type if does not exist + // else add it to the current certificate type list + certificateListFromMap + = certificatePropertyMap.get(certificateId); + if (certificateListFromMap != null) { + certificateListFromMap.add(pc); + } else { + certificatePropertyMap.put(certificateId, + new ArrayList<>(Collections.singletonList(pc))); + } + } + } + + for (EndorsementCredential ec : endorsementCredentialList) { + deviceName = deviceRepository.findById(ec.getDeviceId()).get().getName(); + + // set the certificate if it's the same ID + if (device.getName().equals(deviceName)) { + String certificateId = EndorsementCredential.class.getSimpleName(); + // create a new list for the certificate type if does not exist + // else add it to the current certificate type list + certificateListFromMap + = certificatePropertyMap.get(certificateId); + if (certificateListFromMap != null) { + certificateListFromMap.add(ec); + } else { + certificatePropertyMap.put(certificateId, + new ArrayList<>(Collections.singletonList(ec))); + } + } + } + + for (IssuedAttestationCertificate ic : issuedCertificateList) { + deviceName = ic.getDeviceName(); + // set the certificate if it's the same ID + if (device.getName().equals(deviceName)) { + String certificateId = IssuedAttestationCertificate.class.getSimpleName(); + // create a new list for the certificate type if does not exist + // else add it to the current certificate type list + certificateListFromMap + = certificatePropertyMap.get(certificateId); + if (certificateListFromMap != null) { + certificateListFromMap.add(ic); + } else { + certificatePropertyMap.put(certificateId, + new ArrayList<>(Collections.singletonList(ic))); + } + } + } + + // add the device-certificate map to the record + deviceCertMap.putAll(certificatePropertyMap); + records.add(new HashMap<>(deviceCertMap)); + deviceCertMap.clear(); + } + } + // set pagination values + records.setRecordsTotal(deviceList.getRecordsTotal()); + records.setRecordsFiltered(deviceList.getRecordsFiltered()); + return records; + } + + /** + * Returns the list of devices IDs. + * + * @param deviceList list containing the devices + * @return a list of the devices IDs + */ + private List getDevicesId(final FilteredRecordsList deviceList) { + return deviceList.stream().map(Device::getId).toList(); + } +} 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 new file mode 100644 index 00000000..6915fb3f --- /dev/null +++ b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/service/ReferenceManifestService.java @@ -0,0 +1,77 @@ +package hirs.attestationca.persist.service; + +import hirs.attestationca.persist.entity.userdefined.ReferenceManifest; +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 java.util.ArrayList; +import java.util.List; + +/** + * + */ +@Service +@Log4j2 +public class ReferenceManifestService { + + private final EntityManager entityManager; + + + public ReferenceManifestService(EntityManager entityManager) { + this.entityManager = entityManager; + } + + public Page findRIMBySearchableColumns(final List searchableColumns, + final String searchText, + 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); + } + } + + 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/ValidationSummaryReportsService.java b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/service/ValidationSummaryReportsService.java index 29c2280a..33988a27 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 @@ -1,13 +1,24 @@ package hirs.attestationca.persist.service; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import hirs.attestationca.persist.entity.manager.CertificateRepository; +import hirs.attestationca.persist.entity.manager.DeviceRepository; +import hirs.attestationca.persist.entity.manager.PlatformCertificateRepository; +import hirs.attestationca.persist.entity.userdefined.Device; import hirs.attestationca.persist.entity.userdefined.SupplyChainValidationSummary; +import hirs.attestationca.persist.entity.userdefined.certificate.PlatformCredential; +import hirs.attestationca.persist.entity.userdefined.certificate.attributes.ComponentIdentifier; +import hirs.attestationca.persist.entity.userdefined.certificate.attributes.V2.ComponentIdentifierV2; import jakarta.persistence.EntityManager; import jakarta.persistence.TypedQuery; import jakarta.persistence.criteria.CriteriaBuilder; import jakarta.persistence.criteria.CriteriaQuery; -import jakarta.persistence.criteria.Path; import jakarta.persistence.criteria.Predicate; import jakarta.persistence.criteria.Root; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import lombok.extern.log4j.Log4j2; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; @@ -16,8 +27,19 @@ import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; +import java.io.BufferedWriter; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.nio.charset.StandardCharsets; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; import java.util.ArrayList; +import java.util.Enumeration; import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; /** * Service layer class that handles the storage and retrieval of validation reports. @@ -26,19 +48,29 @@ import java.util.List; @Log4j2 public class ValidationSummaryReportsService { + private static final String DEFAULT_COMPANY = "AllDevices"; + private static final String UNDEFINED = "undefined"; + private static final String TRUE = "true"; + private static final String SYSTEM_COLUMN_HEADERS = "Verified Manufacturer," + + "Model,SN,Verification Date,Device Status"; + private static final String COMPONENT_COLUMN_HEADERS = "Component name,Component manufacturer," + + "Component model,Component SN,Issuer,Component status"; + + private final PlatformCertificateRepository platformCertificateRepository; private final EntityManager entityManager; + private final CertificateRepository certificateRepository; + private final DeviceRepository deviceRepository; @Autowired - public ValidationSummaryReportsService(EntityManager entityManager) { + public ValidationSummaryReportsService(final PlatformCertificateRepository platformCertificateRepository, + final CertificateRepository certificateRepository, + final DeviceRepository deviceRepository, + final EntityManager entityManager) { + this.platformCertificateRepository = platformCertificateRepository; + this.certificateRepository = certificateRepository; + this.deviceRepository = deviceRepository; this.entityManager = entityManager; - } - public static Path getNestedPath(Root root, CriteriaBuilder cb, String... fieldNames) { - Path path = root; - for (String fieldName : fieldNames) { - path = path.get(fieldName); - } - return path; } /** @@ -69,6 +101,10 @@ public class ValidationSummaryReportsService { // 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(".")) { @@ -98,4 +134,326 @@ public class ValidationSummaryReportsService { List resultList = typedQuery.getResultList(); return new PageImpl<>(resultList, pageable, totalRows); } + + /** + * Downloads the validation summary reports based on the provided request parameters. + * + * @param request http request + * @param response http response + * @throws IOException if there are any issues while trying to download the summary reports + */ + public void downloadValidationReports(final HttpServletRequest request, + final HttpServletResponse response) throws IOException { + String company = ""; + String contractNumber = ""; + Pattern pattern = Pattern.compile("^\\w*$"); + DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("uuuu-MM-dd"); + DateTimeFormatter dateTimeFormat = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss"); + LocalDate startDate = null; + LocalDate endDate = null; + ArrayList createTimes = new ArrayList<>(); + String[] deviceNames = new String[] {}; + StringBuilder columnHeaders = new StringBuilder(); + boolean systemOnly = false; + boolean componentOnly = false; + String filterManufacturer = ""; + String filterSerial = ""; + boolean jsonVersion = false; + + final Enumeration parameters = request.getParameterNames(); + + while (parameters.hasMoreElements()) { + String parameter = parameters.nextElement(); + String parameterValue = request.getParameter(parameter); + log.info("{}: {}", parameter, parameterValue); + switch (parameter) { + case "company": + Matcher companyMatcher = pattern.matcher(parameterValue); + if (companyMatcher.matches()) { + company = parameterValue; + } else { + company = DEFAULT_COMPANY; + } + break; + case "contract": + Matcher contractMatcher = pattern.matcher(parameterValue); + if (contractMatcher.matches()) { + contractNumber = parameterValue; + } else { + contractNumber = "none"; + } + break; + case "dateStart": + if (parameterValue != null && !parameterValue.isEmpty()) { + startDate = LocalDate.parse(parameterValue, dateFormat); + } else { + startDate = LocalDate.ofEpochDay(0); + } + break; + case "dateEnd": + if (parameterValue != null && !parameterValue.isEmpty()) { + endDate = LocalDate.parse(parameterValue, dateFormat); + } else { + endDate = LocalDate.now(ZoneId.of("America/New_York")); + } + break; + case "createTimes": + //todo issue #922 + if (!parameterValue.equals(UNDEFINED) + && !parameterValue.isEmpty()) { + String[] timestamps = parameterValue.split(","); + for (String timestamp : timestamps) { + createTimes.add(LocalDateTime.parse(timestamp, + dateTimeFormat).toLocalDate()); + } + } + break; + case "deviceNames": + if (!parameterValue.equals(UNDEFINED) + && !parameterValue.isEmpty()) { + deviceNames = parameterValue.split(","); + } + break; + case "system": + if (parameterValue.equals(TRUE)) { + systemOnly = true; + if (!columnHeaders.isEmpty()) { + columnHeaders.insert(0, ","); + } + columnHeaders.insert(0, SYSTEM_COLUMN_HEADERS); + } + break; + case "component": + if (parameterValue.equals(TRUE)) { + componentOnly = true; + if (!columnHeaders.isEmpty()) { + columnHeaders.append(","); + } + columnHeaders.append(COMPONENT_COLUMN_HEADERS); + } + break; + case "manufacturer": + if (parameterValue != null && !parameterValue.isEmpty()) { + filterManufacturer = parameterValue; + } + break; + case "serial": + if (parameterValue != null && !parameterValue.isEmpty()) { + filterSerial = parameterValue; + } + break; + case "json": + response.setHeader("Content-Type", "application/json"); + jsonVersion = true; + break; + default: + } + } + + if (!jsonVersion) { + response.setHeader("Content-Type", "text/csv"); + response.setHeader("Content-Disposition", + "attachment;filename=validation_report.csv"); + } + + BufferedWriter bufferedWriter = new BufferedWriter( + new OutputStreamWriter(response.getOutputStream(), StandardCharsets.UTF_8)); + + StringBuilder reportData = new StringBuilder(); + JsonArray jsonReportData = new JsonArray(); + for (int i = 0; i < deviceNames.length; i++) { + if ((createTimes.get(i).isAfter(startDate) || createTimes.get(i).isEqual(startDate)) + && (createTimes.get(i).isBefore(endDate) + || createTimes.get(i).isEqual(endDate))) { + Device device = deviceRepository.findByName(deviceNames[i]); + PlatformCredential pc = platformCertificateRepository.findByDeviceId(device.getId()).get(0); + if (jsonVersion) { + jsonReportData.add(assembleJsonContent(pc, parseComponents(pc), + company, contractNumber)); + } else { + if (i == 0) { + bufferedWriter.append("Company: ").append(company).append("\n"); + bufferedWriter.append("Contract number: ").append(contractNumber).append("\n"); + } + + if (systemOnly && componentOnly) { + systemOnly = false; + componentOnly = false; + } + + if ((filterManufacturer.isEmpty() || filterManufacturer.equals( + pc.getManufacturer())) + && (filterSerial.isEmpty() || filterSerial.equals( + pc.getPlatformSerial()))) { + if (!componentOnly) { + reportData.append(pc.getManufacturer()) + .append(",") + .append(pc.getModel()) + .append(",") + .append(pc.getPlatformSerial()) + .append(",") + .append(LocalDateTime.now()) + .append(",") + .append(device.getSupplyChainValidationStatus()) + .append(","); + } + + if (!systemOnly) { + ArrayList> parsedComponents = parseComponents(pc); + for (ArrayList component : parsedComponents) { + for (String data : component) { + reportData.append(data).append(","); + } + reportData.deleteCharAt(reportData.length() - 1); + reportData.append(System.lineSeparator()); + if (!componentOnly) { + reportData.append(",,,,,"); + } + } + reportData = reportData.delete( + reportData.lastIndexOf(System.lineSeparator()) + 1, + reportData.length()); + } + } + } + } + } + + if (!jsonVersion) { + if (columnHeaders.isEmpty()) { + columnHeaders = new StringBuilder(SYSTEM_COLUMN_HEADERS + "," + COMPONENT_COLUMN_HEADERS); + } + bufferedWriter.append(columnHeaders.toString()).append(System.lineSeparator()); + bufferedWriter.append(reportData.toString()); + } else { + bufferedWriter.append(jsonReportData.toString()); + } + bufferedWriter.flush(); + } + + + /** + * This method builds a JSON object from the system and component data in a + * validation report. + * + * @param pc the platform credential used to validate. + * @param parsedComponents component data parsed from the platform credential. + * @param company company name. + * @param contractNumber contract number. + * @return the JSON object in String format. + */ + private JsonObject assembleJsonContent(final PlatformCredential pc, + final ArrayList> parsedComponents, + final String company, + final String contractNumber) { + JsonObject systemData = new JsonObject(); + String deviceName = deviceRepository.findById((pc) + .getDeviceId()).get().getName(); + + systemData.addProperty("Company", company); + systemData.addProperty("Contract number", contractNumber); + systemData.addProperty("Verified Manufacturer", pc.getManufacturer()); + systemData.addProperty("Model", pc.getModel()); + systemData.addProperty("SN", pc.getPlatformSerial()); + systemData.addProperty("Verification Date", LocalDateTime.now().toString()); + systemData.addProperty("Device Status", deviceRepository.findByName(deviceName) + .getSupplyChainValidationStatus().toString()); + + JsonArray components = new JsonArray(); + final int componentDataPosition4 = 3; + final int componentDataPosition5 = 4; + final int componentDataPosition6 = 5; + for (ArrayList componentData : parsedComponents) { + JsonObject component = new JsonObject(); + component.addProperty("Component name", componentData.get(0)); + component.addProperty("Component manufacturer", componentData.get(1)); + component.addProperty("Component model", componentData.get(2)); + component.addProperty("Component SN", componentData.get(componentDataPosition4)); + component.addProperty("Issuer", componentData.get(componentDataPosition5)); + component.addProperty("Component status", componentData.get(componentDataPosition6)); + components.add(component); + } + systemData.add("Components", components); + + return systemData; + } + + /** + * This method parses the following ComponentIdentifier fields into an ArrayList of ArrayLists. + * - ComponentClass + * - Manufacturer + * - Model + * - Serial number + * - Pass/fail status (based on componentFailures string) + * + * @param pc the platform credential. + * @return the ArrayList of ArrayLists containing the parsed component data. + */ + private ArrayList> parseComponents(final PlatformCredential pc) { + ArrayList> parsedComponents = new ArrayList<>(); + ArrayList> chainComponents = new ArrayList<>(); + + StringBuilder componentFailureString = new StringBuilder(); + if (pc.getComponentIdentifiers() != null + && !pc.getComponentIdentifiers().isEmpty()) { + componentFailureString.append(pc.getComponentFailures()); + // get all the certificates associated with the platform serial + List chainCertificates = + certificateRepository.byBoardSerialNumber(pc.getPlatformSerial()); + // combine all components in each certificate + for (ComponentIdentifier ci : pc.getComponentIdentifiers()) { + ArrayList issuerAndComponent = new ArrayList<>(); + issuerAndComponent.add(pc.getHolderIssuer()); + issuerAndComponent.add(ci); + chainComponents.add(issuerAndComponent); + } + + for (PlatformCredential cert : chainCertificates) { + componentFailureString.append(cert.getComponentFailures()); + if (!cert.isPlatformBase()) { + for (ComponentIdentifier ci : cert.getComponentIdentifiers()) { + ArrayList issuerAndComponent = new ArrayList<>(); + issuerAndComponent.add(cert.getHolderIssuer()); + issuerAndComponent.add(ci); + chainComponents.add(issuerAndComponent); + } + } + } + log.info("Component failures: {}", componentFailureString); + for (ArrayList issuerAndComponent : chainComponents) { + ArrayList componentData = new ArrayList<>(); + String issuer = (String) issuerAndComponent.get(0); + issuer = issuer.replaceAll(",", " "); + ComponentIdentifier ci = (ComponentIdentifier) issuerAndComponent.get(1); + if (ci instanceof ComponentIdentifierV2) { + String componentClass = + ((ComponentIdentifierV2) ci).getComponentClass().toString(); + String[] splitStrings = componentClass.split("\r\n|\n|\r"); + StringBuilder sb = new StringBuilder(); + for (String s : splitStrings) { + sb.append(s); + sb.append(" "); + } + sb = sb.deleteCharAt(sb.length() - 1); + componentData.add(sb.toString()); + } else { + componentData.add("Platform Component"); + } + componentData.add(ci.getComponentManufacturer().getString()); + componentData.add(ci.getComponentModel().getString()); + componentData.add(ci.getComponentSerial().getString()); + componentData.add(issuer); + //Failing components are identified by hashcode + if (componentFailureString.toString().contains(String.valueOf(ci.hashCode()))) { + componentData.add("Fail"); + } else { + componentData.add("Pass"); + } + parsedComponents.add(componentData); + log.info(String.join(",", componentData)); + } + } + + return parsedComponents; + } } diff --git a/HIRS_AttestationCAPortal/src/main/java/hirs/attestationca/portal/page/controllers/CertificateDetailsPageController.java b/HIRS_AttestationCAPortal/src/main/java/hirs/attestationca/portal/page/controllers/CertificateDetailsPageController.java index 7e29388d..4cbe6952 100644 --- a/HIRS_AttestationCAPortal/src/main/java/hirs/attestationca/portal/page/controllers/CertificateDetailsPageController.java +++ b/HIRS_AttestationCAPortal/src/main/java/hirs/attestationca/portal/page/controllers/CertificateDetailsPageController.java @@ -3,7 +3,6 @@ package hirs.attestationca.portal.page.controllers; import hirs.attestationca.persist.entity.manager.CACredentialRepository; import hirs.attestationca.persist.entity.manager.CertificateRepository; import hirs.attestationca.persist.entity.manager.ComponentResultRepository; -import hirs.attestationca.persist.entity.manager.IDevIDCertificateRepository; import hirs.attestationca.portal.page.Page; import hirs.attestationca.portal.page.PageController; import hirs.attestationca.portal.page.PageMessages; @@ -35,26 +34,22 @@ public class CertificateDetailsPageController extends PageController { - private final DeviceRepository deviceRepository; - private final CertificateRepository certificateRepository; - private final PlatformCertificateRepository platformCertificateRepository; - private final EndorsementCredentialRepository endorsementCredentialRepository; - private final IssuedCertificateRepository issuedCertificateRepository; + private final DeviceService deviceService; /** * Device Page Controller constructor. - * - * @param deviceRepository device repository. - * @param certificateRepository certificate repository. - * @param platformCertificateRepository platform certificate repository. - * @param endorsementCredentialRepository endorsement credential repository. - * @param issuedCertificateRepository issued certificate repository. */ @Autowired - public DevicePageController(final DeviceRepository deviceRepository, - final CertificateRepository certificateRepository, - final PlatformCertificateRepository platformCertificateRepository, - final EndorsementCredentialRepository endorsementCredentialRepository, - final IssuedCertificateRepository issuedCertificateRepository) { + public DevicePageController( + DeviceService deviceService) { super(Page.DEVICES); - this.deviceRepository = deviceRepository; - this.certificateRepository = certificateRepository; - this.platformCertificateRepository = platformCertificateRepository; - this.endorsementCredentialRepository = endorsementCredentialRepository; - this.issuedCertificateRepository = issuedCertificateRepository; + this.deviceService = deviceService; } /** @@ -87,7 +62,8 @@ public class DevicePageController extends PageController { } /** - * GET request that retrieves table data using the provided data table input. + * Processes request to retrieve the collection of devices and device related + * information that will be displayed on the devices page. * * @param input data table input. * @return a data table response @@ -95,18 +71,31 @@ public class DevicePageController extends PageController { @ResponseBody @GetMapping(value = "/list", produces = MediaType.APPLICATION_JSON_VALUE) - public DataTableResponse> getTableData( + public DataTableResponse> getDevicesTableData( final DataTableInput input) { - log.debug("Received request to for device list"); + log.info("Received request to display list of devices"); + log.debug("Request received a datatable input object for the device page: {}", + input); + String orderColumnName = input.getOrderColumnName(); log.debug("Ordering on column: {}", orderColumnName); + final String searchText = input.getSearch().getValue(); + final List searchableColumns = findSearchableColumnsNames(input.getColumns()); + // get all the devices FilteredRecordsList deviceList = new FilteredRecordsList<>(); int currentPage = input.getStart() / input.getLength(); - Pageable paging = PageRequest.of(currentPage, input.getLength(), Sort.by(orderColumnName)); - org.springframework.data.domain.Page pagedResult = deviceRepository.findAll(paging); + Pageable pageable = PageRequest.of(currentPage, input.getLength(), Sort.by(orderColumnName)); + org.springframework.data.domain.Page pagedResult; + + if (StringUtils.isBlank(searchText)) { + pagedResult = this.deviceService.findAllDevices(pageable); + } else { + pagedResult = this.deviceService.findAllDevicesBySearchableColumns(searchableColumns, searchText, + pageable); + } if (pagedResult.hasContent()) { deviceList.addAll(pagedResult.getContent()); @@ -114,134 +103,24 @@ public class DevicePageController extends PageController { } else { deviceList.setRecordsTotal(input.getLength()); } - deviceList.setRecordsFiltered(deviceRepository.count()); + + deviceList.setRecordsFiltered(this.deviceService.findDeviceRepositoryCount()); FilteredRecordsList> records - = retrieveDevicesAndAssociatedCertificates(deviceList); + = this.deviceService.retrieveDevicesAndAssociatedCertificates(deviceList); return new DataTableResponse<>(records, input); } /** - * Returns the list of devices combined with the certificates. + * Helper method that returns a list of column names that are searchable. * - * @param deviceList list containing the devices - * @return a record list after the device and certificate was mapped together. + * @param columns columns + * @return searchable column names */ - private FilteredRecordsList> retrieveDevicesAndAssociatedCertificates( - final FilteredRecordsList deviceList) { - FilteredRecordsList> records = new FilteredRecordsList<>(); - // hashmap containing the device-certificate relationship - HashMap deviceCertMap = new HashMap<>(); - PlatformCredential certificate; - List deviceIdList = getDevicesId(deviceList); - List platformCredentialList = new ArrayList<>(); - List endorsementCredentialList = new ArrayList<>(); - List issuedCertificateList = new ArrayList<>(); - List certificateListFromMap = new LinkedList<>(); - - // parse if there is a Device - if (!deviceList.isEmpty()) { - // get a list of Certificates that contains the device IDs from the list - for (UUID id : deviceIdList) { - platformCredentialList.addAll(platformCertificateRepository.findByDeviceId(id)); - endorsementCredentialList.addAll(endorsementCredentialRepository.findByDeviceId(id)); - issuedCertificateList.addAll(issuedCertificateRepository.findByDeviceId(id)); - } - - HashMap> certificatePropertyMap; - // loop all the devices - for (Device device : deviceList) { - // hashmap containing the list of certificates based on the certificate type - certificatePropertyMap = new HashMap<>(); - - deviceCertMap.put("device", device); - String deviceName; - - // loop all the certificates and combined the ones that match the ID - for (PlatformCredential pc : platformCredentialList) { - deviceName = deviceRepository.findById(pc.getDeviceId()).get().getName(); - - // set the certificate if it's the same ID - if (device.getName().equals(deviceName)) { - String certificateId = PlatformCredential.class.getSimpleName(); - // create a new list for the certificate type if does not exist - // else add it to the current certificate type list - certificateListFromMap - = certificatePropertyMap.get(certificateId); - if (certificateListFromMap != null) { - certificateListFromMap.add(pc); - } else { - certificatePropertyMap.put(certificateId, - new ArrayList<>(Collections.singletonList(pc))); - } - } - } - - for (EndorsementCredential ec : endorsementCredentialList) { - deviceName = deviceRepository.findById(ec.getDeviceId()).get().getName(); - - // set the certificate if it's the same ID - if (device.getName().equals(deviceName)) { - String certificateId = EndorsementCredential.class.getSimpleName(); - // create a new list for the certificate type if does not exist - // else add it to the current certificate type list - certificateListFromMap - = certificatePropertyMap.get(certificateId); - if (certificateListFromMap != null) { - certificateListFromMap.add(ec); - } else { - certificatePropertyMap.put(certificateId, - new ArrayList<>(Collections.singletonList(ec))); - } - } - } - - for (IssuedAttestationCertificate ic : issuedCertificateList) { - deviceName = ic.getDeviceName(); - // set the certificate if it's the same ID - if (device.getName().equals(deviceName)) { - String certificateId = IssuedAttestationCertificate.class.getSimpleName(); - // create a new list for the certificate type if does not exist - // else add it to the current certificate type list - certificateListFromMap - = certificatePropertyMap.get(certificateId); - if (certificateListFromMap != null) { - certificateListFromMap.add(ic); - } else { - certificatePropertyMap.put(certificateId, - new ArrayList<>(Collections.singletonList(ic))); - } - } - } - - // add the device-certificate map to the record - deviceCertMap.putAll(certificatePropertyMap); - records.add(new HashMap<>(deviceCertMap)); - deviceCertMap.clear(); - } - } - // set pagination values - records.setRecordsTotal(deviceList.getRecordsTotal()); - records.setRecordsFiltered(deviceList.getRecordsFiltered()); - return records; + private List findSearchableColumnsNames(final List columns) { + // Retrieve all searchable columns and collect their names into a list of strings. + return columns.stream().filter(Column::isSearchable).map(Column::getName) + .collect(Collectors.toList()); } - - /** - * Returns the list of devices IDs. - * - * @param deviceList list containing the devices - * @return a list of the devices IDs - */ - private List getDevicesId(final FilteredRecordsList deviceList) { - List deviceIds = new ArrayList<>(); - - // loop all the devices - for (Device device : deviceList) { - deviceIds.add(device.getId()); - } - - return deviceIds; - } - } 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 ade27368..53d153d2 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 @@ -67,7 +67,7 @@ public class EndorsementCredentialPageController extends PageController findSearchableColumnsNames(final List columns) { - // Retrieve all searchable columns and collect their names into a list of strings. return columns.stream().filter(Column::isSearchable).map(Column::getName) .collect(Collectors.toList()); } - /** * Attempts to parse the provided file in order to create an Endorsement Credential. * diff --git a/HIRS_AttestationCAPortal/src/main/java/hirs/attestationca/portal/page/controllers/IDevIdCertificatePageController.java b/HIRS_AttestationCAPortal/src/main/java/hirs/attestationca/portal/page/controllers/IDevIdCertificatePageController.java index 26a20a0b..ee8b2167 100644 --- a/HIRS_AttestationCAPortal/src/main/java/hirs/attestationca/portal/page/controllers/IDevIdCertificatePageController.java +++ b/HIRS_AttestationCAPortal/src/main/java/hirs/attestationca/portal/page/controllers/IDevIdCertificatePageController.java @@ -66,7 +66,7 @@ public class IDevIdCertificatePageController extends PageController getTableData( @Valid final DataTableInput input) { - log.debug("Handling request for summary list: {}", input); + log.info("Received request to display list of reference manifests"); + log.debug("Request received a datatable input object for the reference manifest page " + + " page: {}", input); String orderColumnName = input.getOrderColumnName(); - log.info("Ordering on column: {}", orderColumnName); - log.info("Querying with the following dataTableInput: {}", input); + log.debug("Ordering on column: {}", orderColumnName); + + final String searchText = input.getSearch().getValue(); + final List searchableColumns = findSearchableColumnsNames(input.getColumns()); FilteredRecordsList records = new FilteredRecordsList<>(); int currentPage = input.getStart() / input.getLength(); @@ -436,6 +443,19 @@ public class ReferenceManifestPageController extends PageController findSearchableColumnsNames(final List columns) { + // Retrieve all searchable columns and collect their names into a list of strings. + return columns.stream().filter(Column::isSearchable).map(Column::getName) + .collect(Collectors.toList()); + } + + private Map updateSupportRimInfo( final List dbSupportRims) { SupportReferenceManifest supportRim; diff --git a/HIRS_AttestationCAPortal/src/main/java/hirs/attestationca/portal/page/controllers/ValidationReportsPageController.java b/HIRS_AttestationCAPortal/src/main/java/hirs/attestationca/portal/page/controllers/ValidationReportsPageController.java index 238e213c..2aa5cf3a 100644 --- a/HIRS_AttestationCAPortal/src/main/java/hirs/attestationca/portal/page/controllers/ValidationReportsPageController.java +++ b/HIRS_AttestationCAPortal/src/main/java/hirs/attestationca/portal/page/controllers/ValidationReportsPageController.java @@ -1,17 +1,8 @@ package hirs.attestationca.portal.page.controllers; -import com.google.gson.JsonArray; -import com.google.gson.JsonObject; import hirs.attestationca.persist.FilteredRecordsList; -import hirs.attestationca.persist.entity.manager.CertificateRepository; -import hirs.attestationca.persist.entity.manager.DeviceRepository; -import hirs.attestationca.persist.entity.manager.PlatformCertificateRepository; import hirs.attestationca.persist.entity.manager.SupplyChainValidationSummaryRepository; -import hirs.attestationca.persist.entity.userdefined.Device; import hirs.attestationca.persist.entity.userdefined.SupplyChainValidationSummary; -import hirs.attestationca.persist.entity.userdefined.certificate.PlatformCredential; -import hirs.attestationca.persist.entity.userdefined.certificate.attributes.ComponentIdentifier; -import hirs.attestationca.persist.entity.userdefined.certificate.attributes.V2.ComponentIdentifierV2; import hirs.attestationca.persist.service.ValidationSummaryReportsService; import hirs.attestationca.portal.datatables.Column; import hirs.attestationca.portal.datatables.DataTableInput; @@ -36,19 +27,8 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.servlet.ModelAndView; -import java.io.BufferedWriter; import java.io.IOException; -import java.io.OutputStreamWriter; -import java.nio.charset.StandardCharsets; -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.ZoneId; -import java.time.format.DateTimeFormatter; -import java.util.ArrayList; -import java.util.Enumeration; import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; import java.util.stream.Collectors; /** @@ -59,41 +39,21 @@ import java.util.stream.Collectors; @RequestMapping("/HIRS_AttestationCAPortal/portal/validation-reports") public class ValidationReportsPageController extends PageController { - private static final String DEFAULT_COMPANY = "AllDevices"; - private static final String UNDEFINED = "undefined"; - private static final String TRUE = "true"; - private static final String SYSTEM_COLUMN_HEADERS = "Verified Manufacturer," - + "Model,SN,Verification Date,Device Status"; - private static final String COMPONENT_COLUMN_HEADERS = "Component name,Component manufacturer," - + "Component model,Component SN,Issuer,Component status"; - private final SupplyChainValidationSummaryRepository supplyChainValidatorSummaryRepository; - private final CertificateRepository certificateRepository; - private final DeviceRepository deviceRepository; - private final PlatformCertificateRepository platformCertificateRepository; private final ValidationSummaryReportsService validationSummaryReportsService; /** * Constructor providing the Page's display and routing specification. * * @param supplyChainValidatorSummaryRepository the manager - * @param certificateRepository the certificate manager - * @param deviceRepository the device manager - * @param platformCertificateRepository the platform certificate manager * @param validationSummaryReportsService the validation summary reports service */ @Autowired public ValidationReportsPageController( final SupplyChainValidationSummaryRepository supplyChainValidatorSummaryRepository, - final CertificateRepository certificateRepository, - final DeviceRepository deviceRepository, - final PlatformCertificateRepository platformCertificateRepository, final ValidationSummaryReportsService validationSummaryReportsService) { super(Page.VALIDATION_REPORTS); this.supplyChainValidatorSummaryRepository = supplyChainValidatorSummaryRepository; - this.certificateRepository = certificateRepository; - this.deviceRepository = deviceRepository; - this.platformCertificateRepository = platformCertificateRepository; this.validationSummaryReportsService = validationSummaryReportsService; } @@ -166,189 +126,17 @@ public class ValidationReportsPageController extends PageController createTimes = new ArrayList<>(); - String[] deviceNames = new String[] {}; - String columnHeaders = ""; - boolean systemOnly = false; - boolean componentOnly = false; - String filterManufacturer = ""; - String filterSerial = ""; - boolean jsonVersion = false; - Enumeration parameters = request.getParameterNames(); - while (parameters.hasMoreElements()) { - String parameter = (String) parameters.nextElement(); - String parameterValue = request.getParameter(parameter); - log.info("{}: {}", parameter, parameterValue); - switch (parameter) { - case "company": - Matcher companyMatcher = pattern.matcher(parameterValue); - if (companyMatcher.matches()) { - company = parameterValue; - } else { - company = DEFAULT_COMPANY; - } - break; - case "contract": - Matcher contractMatcher = pattern.matcher(parameterValue); - if (contractMatcher.matches()) { - contractNumber = parameterValue; - } else { - contractNumber = "none"; - } - break; - case "dateStart": - if (parameterValue != null && !parameterValue.isEmpty()) { - startDate = LocalDate.parse(parameterValue, dateFormat); - } else { - startDate = LocalDate.ofEpochDay(0); - } - break; - case "dateEnd": - if (parameterValue != null && !parameterValue.isEmpty()) { - endDate = LocalDate.parse(parameterValue, dateFormat); - } else { - endDate = LocalDate.now(ZoneId.of("America/New_York")); - } - break; - case "createTimes": - if (!parameterValue.equals(UNDEFINED) - && !parameterValue.isEmpty()) { - String[] timestamps = parameterValue.split(","); - for (String timestamp : timestamps) { - createTimes.add(LocalDateTime.parse(timestamp, - dateTimeFormat).toLocalDate()); - } - } - break; - case "deviceNames": - if (!parameterValue.equals(UNDEFINED) - && !parameterValue.isEmpty()) { - deviceNames = parameterValue.split(","); - } - break; - case "system": - if (parameterValue.equals(TRUE)) { - systemOnly = true; - if (!columnHeaders.isEmpty()) { - columnHeaders = "," + columnHeaders; - } - columnHeaders = SYSTEM_COLUMN_HEADERS + columnHeaders; - } - break; - case "component": - if (parameterValue.equals(TRUE)) { - componentOnly = true; - if (!columnHeaders.isEmpty()) { - columnHeaders += ","; - } - columnHeaders += COMPONENT_COLUMN_HEADERS; - } - break; - case "manufacturer": - if (parameterValue != null && !parameterValue.isEmpty()) { - filterManufacturer = parameterValue; - } - break; - case "serial": - if (parameterValue != null && !parameterValue.isEmpty()) { - filterSerial = parameterValue; - } - break; - case "json": - response.setHeader("Content-Type", "application/json"); - jsonVersion = true; - break; - default: - } - } - - if (!jsonVersion) { - response.setHeader("Content-Type", "text/csv"); - response.setHeader("Content-Disposition", - "attachment;filename=validation_report.csv"); - } - BufferedWriter bufferedWriter = new BufferedWriter( - new OutputStreamWriter(response.getOutputStream(), StandardCharsets.UTF_8)); - StringBuilder reportData = new StringBuilder(); - JsonArray jsonReportData = new JsonArray(); - for (int i = 0; i < deviceNames.length; i++) { - if ((createTimes.get(i).isAfter(startDate) || createTimes.get(i).isEqual(startDate)) - && (createTimes.get(i).isBefore(endDate) - || createTimes.get(i).isEqual(endDate))) { - Device device = deviceRepository.findByName(deviceNames[i]); - PlatformCredential pc = platformCertificateRepository.findByDeviceId(device.getId()).get(0); - if (jsonVersion) { - jsonReportData.add(assembleJsonContent(pc, parseComponents(pc), - company, contractNumber)); - } else { - if (i == 0) { - bufferedWriter.append("Company: " + company + "\n"); - bufferedWriter.append("Contract number: " + contractNumber + "\n"); - } - if (systemOnly && componentOnly) { - systemOnly = false; - componentOnly = false; - } - if ((filterManufacturer.isEmpty() || filterManufacturer.equals( - pc.getManufacturer())) - && (filterSerial.isEmpty() || filterSerial.equals( - pc.getPlatformSerial()))) { - if (!componentOnly) { - reportData.append(pc.getManufacturer() + "," - + pc.getModel() + "," - + pc.getPlatformSerial() + "," - + LocalDateTime.now() + "," - + device.getSupplyChainValidationStatus() + ","); - } - if (!systemOnly) { - ArrayList> parsedComponents = parseComponents(pc); - for (ArrayList component : parsedComponents) { - for (String data : component) { - reportData.append(data + ","); - } - reportData.deleteCharAt(reportData.length() - 1); - reportData.append(System.lineSeparator()); - if (!componentOnly) { - reportData.append(",,,,,"); - } - } - reportData = reportData.delete( - reportData.lastIndexOf(System.lineSeparator()) + 1, - reportData.length()); - } - } - } - } - } - if (!jsonVersion) { - if (columnHeaders.isEmpty()) { - columnHeaders = SYSTEM_COLUMN_HEADERS + "," + COMPONENT_COLUMN_HEADERS; - } - bufferedWriter.append(columnHeaders + System.lineSeparator()); - bufferedWriter.append(reportData.toString()); - } else { - bufferedWriter.append(jsonReportData.toString()); - } - bufferedWriter.flush(); + this.validationSummaryReportsService.downloadValidationReports(request, response); } /** @@ -362,129 +150,4 @@ public class ValidationReportsPageController extends PageController> parsedComponents, - final String company, - final String contractNumber) { - JsonObject systemData = new JsonObject(); - String deviceName = deviceRepository.findById((pc) - .getDeviceId()).get().getName(); - - systemData.addProperty("Company", company); - systemData.addProperty("Contract number", contractNumber); - systemData.addProperty("Verified Manufacturer", pc.getManufacturer()); - systemData.addProperty("Model", pc.getModel()); - systemData.addProperty("SN", pc.getPlatformSerial()); - systemData.addProperty("Verification Date", LocalDateTime.now().toString()); - systemData.addProperty("Device Status", deviceRepository.findByName(deviceName) - .getSupplyChainValidationStatus().toString()); - - JsonArray components = new JsonArray(); - final int componentDataPosition4 = 3; - final int componentDataPosition5 = 4; - final int componentDataPosition6 = 5; - for (ArrayList componentData : parsedComponents) { - JsonObject component = new JsonObject(); - component.addProperty("Component name", componentData.get(0)); - component.addProperty("Component manufacturer", componentData.get(1)); - component.addProperty("Component model", componentData.get(2)); - component.addProperty("Component SN", componentData.get(componentDataPosition4)); - component.addProperty("Issuer", componentData.get(componentDataPosition5)); - component.addProperty("Component status", componentData.get(componentDataPosition6)); - components.add(component); - } - systemData.add("Components", components); - - return systemData; - } - - /** - * This method parses the following ComponentIdentifier fields into an ArrayList of ArrayLists. - * - ComponentClass - * - Manufacturer - * - Model - * - Serial number - * - Pass/fail status (based on componentFailures string) - * - * @param pc the platform credential. - * @return the ArrayList of ArrayLists containing the parsed component data. - */ - private ArrayList> parseComponents(final PlatformCredential pc) { - ArrayList> parsedComponents = new ArrayList<>(); - ArrayList> chainComponents = new ArrayList<>(); - - StringBuilder componentFailureString = new StringBuilder(); - if (pc.getComponentIdentifiers() != null - && !pc.getComponentIdentifiers().isEmpty()) { - componentFailureString.append(pc.getComponentFailures()); - // get all the certificates associated with the platform serial - List chainCertificates = - certificateRepository.byBoardSerialNumber(pc.getPlatformSerial()); - // combine all components in each certificate - for (ComponentIdentifier ci : pc.getComponentIdentifiers()) { - ArrayList issuerAndComponent = new ArrayList<>(); - issuerAndComponent.add(pc.getHolderIssuer()); - issuerAndComponent.add(ci); - chainComponents.add(issuerAndComponent); - } - - for (PlatformCredential cert : chainCertificates) { - componentFailureString.append(cert.getComponentFailures()); - if (!cert.isPlatformBase()) { - for (ComponentIdentifier ci : cert.getComponentIdentifiers()) { - ArrayList issuerAndComponent = new ArrayList<>(); - issuerAndComponent.add(cert.getHolderIssuer()); - issuerAndComponent.add(ci); - chainComponents.add(issuerAndComponent); - } - } - } - log.info("Component failures: {}", componentFailureString); - for (ArrayList issuerAndComponent : chainComponents) { - ArrayList componentData = new ArrayList<>(); - String issuer = (String) issuerAndComponent.get(0); - issuer = issuer.replaceAll(",", " "); - ComponentIdentifier ci = (ComponentIdentifier) issuerAndComponent.get(1); - if (ci instanceof ComponentIdentifierV2) { - String componentClass = - ((ComponentIdentifierV2) ci).getComponentClass().toString(); - String[] splitStrings = componentClass.split("\r\n|\n|\r"); - StringBuilder sb = new StringBuilder(); - for (String s : splitStrings) { - sb.append(s); - sb.append(" "); - } - sb = sb.deleteCharAt(sb.length() - 1); - componentData.add(sb.toString()); - } else { - componentData.add("Platform Component"); - } - componentData.add(ci.getComponentManufacturer().getString()); - componentData.add(ci.getComponentModel().getString()); - componentData.add(ci.getComponentSerial().getString()); - componentData.add(issuer); - //Failing components are identified by hashcode - if (componentFailureString.toString().contains(String.valueOf(ci.hashCode()))) { - componentData.add("Fail"); - } else { - componentData.add("Pass"); - } - parsedComponents.add(componentData); - log.info(String.join(",", componentData)); - } - } - - return parsedComponents; - } } diff --git a/HIRS_AttestationCAPortal/src/main/webapp/WEB-INF/jsp/devices.jsp b/HIRS_AttestationCAPortal/src/main/webapp/WEB-INF/jsp/devices.jsp index 4e6206b0..4a58bc0c 100644 --- a/HIRS_AttestationCAPortal/src/main/webapp/WEB-INF/jsp/devices.jsp +++ b/HIRS_AttestationCAPortal/src/main/webapp/WEB-INF/jsp/devices.jsp @@ -78,6 +78,8 @@ { name: "name", data: "name", + searchable: true, + orderable: true, render: function (data, type, full, meta) { return full.device.name; },