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 8883d6a79..b984d260c 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,18 +1,23 @@ package hirs.attestationca.portal.page.controllers; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import hirs.FilteredRecordsList; import hirs.attestationca.portal.datatables.DataTableInput; import hirs.attestationca.portal.datatables.DataTableResponse; import hirs.attestationca.portal.datatables.OrderedListQueryDataTableAdapter; import hirs.attestationca.portal.page.PageController; import hirs.attestationca.portal.page.params.NoPageParams; +import hirs.data.persist.SupplyChainValidationSummary; import hirs.data.persist.certificate.Certificate; import hirs.data.persist.certificate.PlatformCredential; import hirs.data.persist.certificate.attributes.ComponentIdentifier; import hirs.data.persist.certificate.attributes.V2.ComponentIdentifierV2; import hirs.persist.CertificateManager; +import hirs.persist.CriteriaModifier; +import hirs.persist.CrudManager; import hirs.persist.DeviceManager; import org.apache.logging.log4j.Logger; -import static org.apache.logging.log4j.LogManager.getLogger; import org.hibernate.Criteria; import org.hibernate.criterion.Restrictions; import org.springframework.beans.factory.annotation.Autowired; @@ -24,12 +29,6 @@ import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.servlet.ModelAndView; -import static hirs.attestationca.portal.page.Page.VALIDATION_REPORTS; -import hirs.FilteredRecordsList; -import hirs.data.persist.SupplyChainValidationSummary; -import hirs.persist.CriteriaModifier; -import hirs.persist.CrudManager; - import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.BufferedWriter; @@ -47,6 +46,9 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; +import static hirs.attestationca.portal.page.Page.VALIDATION_REPORTS; +import static org.apache.logging.log4j.LogManager.getLogger; + /** * Controller for the Validation Reports page. */ @@ -141,7 +143,7 @@ public void modify(final Criteria criteria) { * @param response object * @throws IOException thrown by BufferedWriter object */ - @SuppressWarnings("checkstyle:magicnumber") + @SuppressWarnings({"checkstyle:magicnumber", "checkstyle:methodlength" }) @RequestMapping(value = "download", method = RequestMethod.POST) public void download(final HttpServletRequest request, final HttpServletResponse response) throws IOException { @@ -161,6 +163,7 @@ public void download(final HttpServletRequest request, boolean componentOnly = false; String filterManufacturer = ""; String filterSerial = ""; + boolean jsonVersion = false; Enumeration parameters = request.getParameterNames(); while (parameters.hasMoreElements()) { @@ -236,23 +239,23 @@ public void download(final HttpServletRequest request, filterSerial = parameterValue; } break; - + case "json": + response.setHeader("Content-Type", "application/json"); + jsonVersion = true; + break; default: } } - response.setHeader("Content-Type", "text/csv"); - response.setHeader("Content-Disposition", - "attachment;filename=validation_report.csv"); + 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(); - bufferedWriter.append("Company: " + company + "\n"); - bufferedWriter.append("Contract number: " + contractNumber + "\n"); - if (systemOnly && componentOnly) { - systemOnly = false; - componentOnly = false; - } + 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) @@ -260,38 +263,99 @@ public void download(final HttpServletRequest request, UUID deviceId = deviceManager.getDevice(deviceNames[i]).getId(); PlatformCredential pc = PlatformCredential.select(certificateManager) .byDeviceId(deviceId).getCertificate(); - 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().toString() + "," - + pc.getDevice().getSupplyChainStatus() + ","); + 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) { - ArrayList> parsedComponents = parseComponents(pc); - for (ArrayList component : parsedComponents) { - for (String data : component) { - reportData.append(data + ","); + 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().toString() + "," + + pc.getDevice().getSupplyChainStatus() + ","); + } + if (!systemOnly) { + ArrayList> parsedComponents = parseComponents(pc); + for (ArrayList component : parsedComponents) { + for (String data : component) { + reportData.append(data + ","); + } + reportData.deleteCharAt(reportData.length() - 1); + reportData.append("\n"); + if (!componentOnly) { + reportData.append(",,,,,"); + } } - reportData.deleteCharAt(reportData.length() - 1); - reportData.append("\n,,,,,"); } } + reportData.append("\n"); } } } - if (columnHeaders.isEmpty()) { - columnHeaders = systemColumnHeaders + componentColumnHeaders; + if (!jsonVersion) { + if (columnHeaders.isEmpty()) { + columnHeaders = systemColumnHeaders + componentColumnHeaders; + } + bufferedWriter.append(columnHeaders + "\n"); + bufferedWriter.append(reportData.toString()); + } else { + bufferedWriter.append(jsonReportData.toString()); } - bufferedWriter.append(columnHeaders + "\n"); - bufferedWriter.append(reportData.toString() + "\n"); 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. + */ + @SuppressWarnings({"checkstyle:magicnumber" }) + private JsonObject assembleJsonContent(final PlatformCredential pc, + final ArrayList> parsedComponents, + final String company, + final String contractNumber) { + JsonObject systemData = new JsonObject(); + + 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", pc.getDevice().getSupplyChainStatus().toString()); + + JsonArray components = new JsonArray(); + 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(3)); + component.addProperty("Issuer", componentData.get(4)); + component.addProperty("Component status", componentData.get(5)); + components.add(component); + } + systemData.add("Components", components); + + return systemData; + } + /** * This method parses the following ComponentIdentifier fields into an ArrayList of ArrayLists. * - ComponentClass diff --git a/scripts/download_validation_reports.sh b/scripts/download_validation_reports.sh index 95fc752e2..06d74774b 100644 --- a/scripts/download_validation_reports.sh +++ b/scripts/download_validation_reports.sh @@ -15,8 +15,8 @@ else fi #set parameter names and call getopts on inputsi, then parse/assign arguments -SHORTOPTS=m:s:h -LONGOPTS=start-date:,end-date:,ip:,system-only,component-only,manufacturer:,serial:,help +SHORTOPTS=d:e:i:ypm:s:jh +LONGOPTS=start-date:,end-date:,ip:,system-only,component-only,manufacturer:,serial:,json,help PARSED=$(getopt --options=$SHORTOPTS --longoptions=$LONGOPTS --name "$0" -- "$@") if [[ ${PIPESTATUS[0]} -ne 0 ]] then @@ -30,35 +30,37 @@ system= component= manufacturer= serial= +json= -helpText="\n\n\nHELP MENU\n\nThe following options are available:\n--start-date\t\t\tDefault: 1970-01-01\tThe earliest date to return validation reports from.\n" -helpText+="--end-date\t\t\tDefault: current time\tThe latest date to return validation reports from.\n" -helpText+="--ip\t\t\t\tDefault: localhost\tThe IP address where the ACA is located.\n" -helpText+="--system-only\t\t\t\t\t\t\tReturn only system information from validation reports.\n" -helpText+="--component-only\t\t\t\t\t\tReturn only component information from validation reports.\n" +helpText="\n\n\nHELP MENU\n\nThe following options are available:\n-d|--start-date\t\t\tDefault: 1970-01-01\tThe earliest date to return validation reports from.\n" +helpText+="-e|--end-date\t\t\tDefault: current time\tThe latest date to return validation reports from.\n" +helpText+="-i|--ip\t\t\t\tDefault: localhost\tThe IP address where the ACA is located.\n" +helpText+="-y|--system-only\t\t\t\t\t\tReturn only system information from validation reports.\n" +helpText+="-p|--component-only\t\t\t\t\t\tReturn only component information from validation reports.\n" helpText+="-m|--manufacturer\t\t\t\tReturn only the validation report of the device from this manufacturer.\n" helpText+="-s|--serial\t\t\t\t\t\tReturn only the validation report of the device with this serial number.\n" +helpText+="-j|--json\t\t\t\t\t\t\tReturn output in JSON format. Only --start-date, --end-date,\n\t\t\t\t\t\t\t\tand --ip parameters are read with this option, all others are ignored.\n" while true do case "$1" in - --start-date) + -d|--start-date) startDate="$2" shift 2 ;; - --end-date) + -e|--end-date) endDate="$2" shift 2 ;; - --ip) + -i|--ip) ip="$2" shift 2 ;; - --system-only) + -y|--system-only) system=true shift ;; - --component-only) + -p|--component-only) component=true shift ;; @@ -70,6 +72,10 @@ do serial="$2" shift 2 ;; + -j|--json) + json=true + shift + ;; -h|--help) printf "$helpText" exit 0 @@ -85,8 +91,6 @@ do esac done -#echo "start date: $startDate, end date: $endDate, ip: $ip, system: $system, component: $component, manufacturer: $manufacturer, serial: $serial" - #call ACA for validation report endpoint="https://$ip:8443/HIRS_AttestationCAPortal/portal/validation-reports" echo "$endpoint" @@ -103,4 +107,11 @@ deviceNames=$(jq -r '.data | map(.device.name) | join(",")' <<< "$content") echo "Create times: $createTimes" echo "Device names: $deviceNames" -curl --data "dateStart=$startDate&dateEnd=$endDate&createTimes=$createTimes&deviceNames=$deviceNames&system=$system&component=$component&manufacturer=$manufacturer&serial=$serial" --insecure $endpoint/download +curlData="dateStart=$startDate&dateEnd=$endDate&createTimes=$createTimes&deviceNames=$deviceNames" +if [[ "$json" = true ]] +then + curlData+="&json=true" +else + curlData+="&system=$system&component=$component&manufacturer=$manufacturer&serial=$serial" +fi +curl --data "$curlData" --insecure $endpoint/download