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.
Some checks failed
Dotnet Provisioner Unit Tests / Restore and Run Unit Tests (ubuntu-latest) (push) Has been cancelled
Dotnet Provisioner Unit Tests / Restore and Run Unit Tests (windows-2022) (push) Has been cancelled
HIRS Build and Unit Test / ACA_Provisioner_Unit_Tests (push) Has been cancelled
HIRS System Tests / DockerTests (push) Has been cancelled
Dotnet Provisioner Unit Tests / Evaluate Tests (push) Has been cancelled

This commit is contained in:
ThatSilentCoder 2025-04-11 14:12:14 -04:00
parent e1ee5a0ce3
commit f7ee7d3d88
14 changed files with 785 additions and 533 deletions

View File

@ -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

View File

@ -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(".")) {
}

View File

@ -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<Device> findAllDevicesBySearchableColumns(
final List<String> searchableColumns,
final String searchText,
final Pageable pageable) {
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<Device> query =
criteriaBuilder.createQuery(Device.class);
Root<Device> deviceRoot =
query.from(Device.class);
List<Predicate> 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<Device> 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<Device> resultList = typedQuery.getResultList();
return new PageImpl<>(resultList, pageable, totalRows);
}
/**
* Retrieves all devices from the database.
*
* @param pageable pageable
* @return page of devices
*/
public Page<Device> 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<HashMap<String, Object>> retrieveDevicesAndAssociatedCertificates(
final FilteredRecordsList<Device> deviceList) {
FilteredRecordsList<HashMap<String, Object>> records = new FilteredRecordsList<>();
// hashmap containing the device-certificate relationship
HashMap<String, Object> deviceCertMap = new HashMap<>();
List<UUID> deviceIdList = getDevicesId(deviceList);
List<PlatformCredential> platformCredentialList = new ArrayList<>();
List<EndorsementCredential> endorsementCredentialList = new ArrayList<>();
List<IssuedAttestationCertificate> issuedCertificateList = new ArrayList<>();
List<Object> 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<String, List<Object>> 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<UUID> getDevicesId(final FilteredRecordsList<Device> deviceList) {
return deviceList.stream().map(Device::getId).toList();
}
}

View File

@ -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<ReferenceManifest> findRIMBySearchableColumns(final List<String> searchableColumns,
final String searchText,
final Pageable pageable) {
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<ReferenceManifest> query = criteriaBuilder.createQuery(ReferenceManifest.class);
Root<ReferenceManifest> rimRoot = query.from(ReferenceManifest.class);
List<Predicate> 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<ReferenceManifest> 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<ReferenceManifest> resultList = typedQuery.getResultList();
return new PageImpl<>(resultList, pageable, totalRows);
}
}

View File

@ -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<SupplyChainValidationSummary> 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<LocalDate> 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<String> 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<ArrayList<String>> parsedComponents = parseComponents(pc);
for (ArrayList<String> 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<ArrayList<String>> 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<String> 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<ArrayList<String>> parseComponents(final PlatformCredential pc) {
ArrayList<ArrayList<String>> parsedComponents = new ArrayList<>();
ArrayList<ArrayList<Object>> 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<PlatformCredential> chainCertificates =
certificateRepository.byBoardSerialNumber(pc.getPlatformSerial());
// combine all components in each certificate
for (ComponentIdentifier ci : pc.getComponentIdentifiers()) {
ArrayList<Object> 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<Object> issuerAndComponent = new ArrayList<>();
issuerAndComponent.add(cert.getHolderIssuer());
issuerAndComponent.add(ci);
chainComponents.add(issuerAndComponent);
}
}
}
log.info("Component failures: {}", componentFailureString);
for (ArrayList<Object> issuerAndComponent : chainComponents) {
ArrayList<String> 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;
}
}

View File

@ -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<Certificate
private final CertificateRepository certificateRepository;
private final CACredentialRepository caCredentialRepository;
private final ComponentResultRepository componentResultRepository;
private final IDevIDCertificateRepository iDevIDCertificateRepository;
/**
* Constructor providing the Page's display and routing specification.
*
* @param certificateRepository the certificate repository
* @param componentResultRepository the component result repository
* @param caCredentialRepository the ca credential manager
* @param iDevIDCertificateRepository the idevid certificate repository
* @param certificateRepository the certificate repository
* @param componentResultRepository the component result repository
* @param caCredentialRepository the ca credential manager
*/
@Autowired
public CertificateDetailsPageController(final CertificateRepository certificateRepository,
final ComponentResultRepository componentResultRepository,
final CACredentialRepository caCredentialRepository,
final IDevIDCertificateRepository iDevIDCertificateRepository) {
final CACredentialRepository caCredentialRepository) {
super(Page.CERTIFICATE_DETAILS);
this.certificateRepository = certificateRepository;
this.componentResultRepository = componentResultRepository;
this.caCredentialRepository = caCredentialRepository;
this.iDevIDCertificateRepository = iDevIDCertificateRepository;
}
/**

View File

@ -1,21 +1,16 @@
package hirs.attestationca.portal.page.controllers;
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.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 hirs.attestationca.persist.service.DeviceService;
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 lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
@ -28,12 +23,9 @@ 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.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
/**
* Controller for the Device page.
@ -43,33 +35,16 @@ import java.util.UUID;
@RequestMapping("/HIRS_AttestationCAPortal/portal/devices")
public class DevicePageController extends PageController<NoPageParams> {
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<NoPageParams> {
}
/**
* 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<NoPageParams> {
@ResponseBody
@GetMapping(value = "/list",
produces = MediaType.APPLICATION_JSON_VALUE)
public DataTableResponse<HashMap<String, Object>> getTableData(
public DataTableResponse<HashMap<String, Object>> 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<String> searchableColumns = findSearchableColumnsNames(input.getColumns());
// get all the devices
FilteredRecordsList<Device> deviceList = new FilteredRecordsList<>();
int currentPage = input.getStart() / input.getLength();
Pageable paging = PageRequest.of(currentPage, input.getLength(), Sort.by(orderColumnName));
org.springframework.data.domain.Page<Device> pagedResult = deviceRepository.findAll(paging);
Pageable pageable = PageRequest.of(currentPage, input.getLength(), Sort.by(orderColumnName));
org.springframework.data.domain.Page<Device> 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<NoPageParams> {
} else {
deviceList.setRecordsTotal(input.getLength());
}
deviceList.setRecordsFiltered(deviceRepository.count());
deviceList.setRecordsFiltered(this.deviceService.findDeviceRepositoryCount());
FilteredRecordsList<HashMap<String, Object>> 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<HashMap<String, Object>> retrieveDevicesAndAssociatedCertificates(
final FilteredRecordsList<Device> deviceList) {
FilteredRecordsList<HashMap<String, Object>> records = new FilteredRecordsList<>();
// hashmap containing the device-certificate relationship
HashMap<String, Object> deviceCertMap = new HashMap<>();
PlatformCredential certificate;
List<UUID> deviceIdList = getDevicesId(deviceList);
List<PlatformCredential> platformCredentialList = new ArrayList<>();
List<EndorsementCredential> endorsementCredentialList = new ArrayList<>();
List<IssuedAttestationCertificate> issuedCertificateList = new ArrayList<>();
List<Object> 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<String, List<Object>> 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<String> findSearchableColumnsNames(final List<Column> 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<UUID> getDevicesId(final FilteredRecordsList<Device> deviceList) {
List<UUID> deviceIds = new ArrayList<>();
// loop all the devices
for (Device device : deviceList) {
deviceIds.add(device.getId());
}
return deviceIds;
}
}

View File

@ -67,7 +67,7 @@ public class EndorsementCredentialPageController extends PageController<NoPagePa
public EndorsementCredentialPageController(
final EndorsementCredentialRepository endorsementCredentialRepository,
final CertificateService certificateService) {
super(Page.TRUST_CHAIN);
super(Page.ENDORSEMENT_KEY_CREDENTIALS);
this.endorsementCredentialRepository = endorsementCredentialRepository;
this.certificateService = certificateService;
}
@ -319,13 +319,11 @@ public class EndorsementCredentialPageController extends PageController<NoPagePa
* @return searchable column names
*/
private List<String> findSearchableColumnsNames(final List<Column> 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.
*

View File

@ -66,7 +66,7 @@ public class IDevIdCertificatePageController extends PageController<NoPageParams
@Autowired
public IDevIdCertificatePageController(final IDevIDCertificateRepository iDevIDCertificateRepository,
final CertificateService certificateService) {
super(Page.TRUST_CHAIN);
super(Page.IDEVID_CERTIFICATES);
this.iDevIDCertificateRepository = iDevIDCertificateRepository;
this.certificateService = certificateService;
}

View File

@ -65,7 +65,7 @@ public class IssuedCertificatePageController extends PageController<NoPageParams
public IssuedCertificatePageController(
final IssuedCertificateRepository issuedCertificateRepository,
final CertificateService certificateService) {
super(Page.TRUST_CHAIN);
super(Page.ISSUED_CERTIFICATES);
this.issuedCertificateRepository = issuedCertificateRepository;
this.certificateService = certificateService;
}

View File

@ -72,7 +72,7 @@ public class PlatformCredentialPageController extends PageController<NoPageParam
final PlatformCertificateRepository platformCertificateRepository,
final EndorsementCredentialRepository endorsementCredentialRepository,
final CertificateService certificateService) {
super(Page.TRUST_CHAIN);
super(Page.PLATFORM_CREDENTIALS);
this.platformCertificateRepository = platformCertificateRepository;
this.endorsementCredentialRepository = endorsementCredentialRepository;
this.certificateService = certificateService;

View File

@ -8,6 +8,8 @@ import hirs.attestationca.persist.entity.userdefined.ReferenceManifest;
import hirs.attestationca.persist.entity.userdefined.rim.BaseReferenceManifest;
import hirs.attestationca.persist.entity.userdefined.rim.ReferenceDigestValue;
import hirs.attestationca.persist.entity.userdefined.rim.SupportReferenceManifest;
import hirs.attestationca.persist.service.ReferenceManifestService;
import hirs.attestationca.portal.datatables.Column;
import hirs.attestationca.portal.datatables.DataTableInput;
import hirs.attestationca.portal.datatables.DataTableResponse;
import hirs.attestationca.portal.page.Page;
@ -16,7 +18,6 @@ import hirs.attestationca.portal.page.PageMessages;
import hirs.attestationca.portal.page.params.NoPageParams;
import hirs.utils.tpm.eventlog.TCGEventLog;
import hirs.utils.tpm.eventlog.TpmPcrEvent;
import jakarta.persistence.EntityManager;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import jakarta.xml.bind.UnmarshalException;
@ -52,6 +53,7 @@ import java.util.Map;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
@ -67,8 +69,7 @@ public class ReferenceManifestPageController extends PageController<NoPageParams
private static final String SUPPORT_RIM_FILE_PATTERN = "([^\\s]+(\\.(?i)(rimpcr|rimel|bin|log))$)";
private final ReferenceManifestRepository referenceManifestRepository;
private final ReferenceDigestValueRepository referenceDigestValueRepository;
@Autowired(required = false)
private EntityManager entityManager;
private final ReferenceManifestService referenceManifestService;
/**
* Constructor providing the Page's display and routing specification.
@ -79,10 +80,12 @@ public class ReferenceManifestPageController extends PageController<NoPageParams
@Autowired
public ReferenceManifestPageController(
final ReferenceManifestRepository referenceManifestRepository,
final ReferenceDigestValueRepository referenceDigestValueRepository) {
final ReferenceDigestValueRepository referenceDigestValueRepository,
ReferenceManifestService referenceManifestService) {
super(Page.REFERENCE_MANIFESTS);
this.referenceManifestRepository = referenceManifestRepository;
this.referenceDigestValueRepository = referenceDigestValueRepository;
this.referenceManifestService = referenceManifestService;
}
/**
@ -112,11 +115,15 @@ public class ReferenceManifestPageController extends PageController<NoPageParams
produces = MediaType.APPLICATION_JSON_VALUE)
public DataTableResponse<ReferenceManifest> 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<String> searchableColumns = findSearchableColumnsNames(input.getColumns());
FilteredRecordsList<ReferenceManifest> records = new FilteredRecordsList<>();
int currentPage = input.getStart() / input.getLength();
@ -436,6 +443,19 @@ public class ReferenceManifestPageController extends PageController<NoPageParams
}
}
/**
* Helper method that returns a list of column names that are searchable.
*
* @param columns columns
* @return searchable column names
*/
private List<String> findSearchableColumnsNames(final List<Column> 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<String, SupportReferenceManifest> updateSupportRimInfo(
final List<SupportReferenceManifest> dbSupportRims) {
SupportReferenceManifest supportRim;

View File

@ -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<NoPageParams> {
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<NoPageParams
}
/**
* This method handles downloading a validation report.
* Processes request to download the validation summary report.
*
* @param request object
* @param response object
* @throws IOException thrown by BufferedWriter object
* @param request http request
* @param response http response
*/
@PostMapping("/download")
public void download(final HttpServletRequest request,
final HttpServletResponse response) throws IOException {
public void downloadValidationReports(final HttpServletRequest request,
final HttpServletResponse response) throws IOException {
log.info("Received request to download validation report");
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<LocalDate> 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<ArrayList<String>> parsedComponents = parseComponents(pc);
for (ArrayList<String> 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<NoPageParams
return columns.stream().filter(Column::isSearchable).map(Column::getName)
.collect(Collectors.toList());
}
/**
* 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<ArrayList<String>> 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<String> 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<ArrayList<String>> parseComponents(final PlatformCredential pc) {
ArrayList<ArrayList<String>> parsedComponents = new ArrayList<>();
ArrayList<ArrayList<Object>> 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<PlatformCredential> chainCertificates =
certificateRepository.byBoardSerialNumber(pc.getPlatformSerial());
// combine all components in each certificate
for (ComponentIdentifier ci : pc.getComponentIdentifiers()) {
ArrayList<Object> 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<Object> issuerAndComponent = new ArrayList<>();
issuerAndComponent.add(cert.getHolderIssuer());
issuerAndComponent.add(ci);
chainComponents.add(issuerAndComponent);
}
}
}
log.info("Component failures: {}", componentFailureString);
for (ArrayList<Object> issuerAndComponent : chainComponents) {
ArrayList<String> 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;
}
}

View File

@ -78,6 +78,8 @@
{
name: "name",
data: "name",
searchable: true,
orderable: true,
render: function (data, type, full, meta) {
return full.device.name;
},