Continued refactoring to update the failed components part of the attribute validation. The delta mapping needs to be reworked to not use serials.

This commit is contained in:
Cyrus
2020-11-23 14:46:29 -05:00
parent d99bb1039c
commit fbdcf83840
7 changed files with 253 additions and 68 deletions

View File

@ -132,7 +132,6 @@ public class SupplyChainValidationServiceImpl implements SupplyChainValidationSe
supplyChainAppraiser); supplyChainAppraiser);
boolean acceptExpiredCerts = policy.isExpiredCertificateValidationEnabled(); boolean acceptExpiredCerts = policy.isExpiredCertificateValidationEnabled();
PlatformCredential baseCredential = null; PlatformCredential baseCredential = null;
String componentFailures = "";
List<SupplyChainValidation> validations = new LinkedList<>(); List<SupplyChainValidation> validations = new LinkedList<>();
Map<PlatformCredential, SupplyChainValidation> deltaMapping = new HashMap<>(); Map<PlatformCredential, SupplyChainValidation> deltaMapping = new HashMap<>();
SupplyChainValidation platformScv = null; SupplyChainValidation platformScv = null;
@ -199,15 +198,22 @@ public class SupplyChainValidationServiceImpl implements SupplyChainValidationSe
Iterator<PlatformCredential> it = pcs.iterator(); Iterator<PlatformCredential> it = pcs.iterator();
while (it.hasNext()) { while (it.hasNext()) {
PlatformCredential pc = it.next(); PlatformCredential pc = it.next();
SupplyChainValidation attributeScv; SupplyChainValidation attributeScv = null;
if (pc != null) { if (pc != null) {
if (pc.isDeltaChain()) { if (pc.isDeltaChain()) {
// this check validates the delta changes and recompares // this check validates the delta changes and re-compares
// the modified list to the original. // the modified list to the original.
attributeScv = validateDeltaPlatformCredentialAttributes( try {
pc, device.getDeviceInfo(), attributeScv = validateDeltaPlatformCredentialAttributes(
baseCredential, deltaMapping); pc, device.getDeviceInfo(),
baseCredential, deltaMapping);
} catch (Exception ex) {
for (StackTraceElement element : ex.getStackTrace()) {
LOGGER.error(element.toString());
}
LOGGER.error(ex.getMessage());
}
} else { } else {
attributeScv = validatePlatformCredentialAttributes( attributeScv = validatePlatformCredentialAttributes(
pc, device.getDeviceInfo(), ec); pc, device.getDeviceInfo(), ec);
@ -239,8 +245,6 @@ public class SupplyChainValidationServiceImpl implements SupplyChainValidationSe
String.format("%s%n%s", platformScv.getMessage(), String.format("%s%n%s", platformScv.getMessage(),
attributeScv.getMessage()))); attributeScv.getMessage())));
} }
componentFailures = updateUnmatchedComponents(
attributeScv.getMessage());
} }
pc.setDevice(device); pc.setDevice(device);
@ -259,10 +263,6 @@ public class SupplyChainValidationServiceImpl implements SupplyChainValidationSe
// Generate validation summary, save it, and return it. // Generate validation summary, save it, and return it.
SupplyChainValidationSummary summary SupplyChainValidationSummary summary
= new SupplyChainValidationSummary(device, validations); = new SupplyChainValidationSummary(device, validations);
if (baseCredential != null) {
baseCredential.setComponentFailures(componentFailures);
this.certificateManager.update(baseCredential);
}
try { try {
supplyChainValidatorSummaryManager.save(summary); supplyChainValidatorSummaryManager.save(summary);
} catch (DBManagerException ex) { } catch (DBManagerException ex) {
@ -272,29 +272,6 @@ public class SupplyChainValidationServiceImpl implements SupplyChainValidationSe
return summary; return summary;
} }
private String updateUnmatchedComponents(final String unmatchedString) {
StringBuilder updatedFailures = new StringBuilder();
String manufacturer = "";
String model = "";
for (String rows : unmatchedString.split(";")) {
for (String str : rows.split(",")) {
String[] manufacturerSplit;
String[] modelSplit;
if (str.contains("Manufacturer")) {
manufacturerSplit = str.split("=");
manufacturer = manufacturerSplit[VALUE_INDEX];
}
if (str.contains("Model")) {
modelSplit = str.split("=");
model = modelSplit[VALUE_INDEX];
}
}
updatedFailures.append(String.format("%s%s;", manufacturer, model));
}
return updatedFailures.toString();
}
/** /**
* This method is a sub set of the validate supply chain method and focuses * This method is a sub set of the validate supply chain method and focuses
* on the specific multibase validation check for a delta chain. This method * on the specific multibase validation check for a delta chain. This method
@ -724,6 +701,11 @@ public class SupplyChainValidationServiceImpl implements SupplyChainValidationSe
return buildValidationRecord(validationType, PASS, return buildValidationRecord(validationType, PASS,
result.getMessage(), delta, Level.INFO); result.getMessage(), delta, Level.INFO);
case FAIL: case FAIL:
if (!result.getAdditionalInfo().isEmpty()) {
LOGGER.error(result.getAdditionalInfo());
base.setComponentFailures(result.getAdditionalInfo());
this.certificateManager.update(base);
}
return buildValidationRecord(validationType, AppraisalStatus.Status.FAIL, return buildValidationRecord(validationType, AppraisalStatus.Status.FAIL,
result.getMessage(), delta, Level.WARN); result.getMessage(), delta, Level.WARN);
case ERROR: case ERROR:

View File

@ -153,17 +153,6 @@ public class CertificateRequestPageController extends PageController<NoPageParam
return mav; return mav;
} }
/**
* TODO
* 1. add flag for rim validation dependent on pc attribute flag DONE
* 2. create tpmbaseline on upload of rimel file (DONE?)
* a. add device id? though one won't exist yet
* 3. validation
* a. looks for baseline
* b. if it doesn't find one, looks for rim
* a. creates baseline if it exists
* c. validates after reading rimel, if it finds one.
*/
/** /**
* Queries for the list of Certificates and returns a data table response * Queries for the list of Certificates and returns a data table response

View File

@ -340,7 +340,11 @@ public final class CertificateStringMapBuilder {
//CPSuri //CPSuri
data.put("CPSuri", certificate.getCPSuri()); data.put("CPSuri", certificate.getCPSuri());
//component failure //component failure
data.put("failures", certificate.getComponentFailures()); if (certificate.getComponentFailures().isEmpty()) {
data.put("failures", certificate.getComponentFailures());
} else {
LOGGER.error(certificate.getComponentFailures());
}
//Get platform Configuration values and set map with it //Get platform Configuration values and set map with it
PlatformConfiguration platformConfiguration = certificate.getPlatformConfiguration(); PlatformConfiguration platformConfiguration = certificate.getPlatformConfiguration();

View File

@ -32,6 +32,7 @@ public class AppraisalStatus {
private Status appStatus; private Status appStatus;
private String message; private String message;
private String additionalInfo;
/** /**
* Default constructor. Set appraisal status and description. * Default constructor. Set appraisal status and description.
@ -43,6 +44,20 @@ public class AppraisalStatus {
this.message = message; this.message = message;
} }
/**
* Default constructor. Set appraisal status and description.
* @param appStatus status of appraisal
* @param message description of result
* @param additionalInfo any additional information needed to
* be passed on
*/
public AppraisalStatus(final Status appStatus, final String message,
final String additionalInfo) {
this.appStatus = appStatus;
this.message = message;
this.additionalInfo = additionalInfo;
}
/** /**
* Get appraisal status. * Get appraisal status.
* @return appraisal status * @return appraisal status
@ -74,4 +89,20 @@ public class AppraisalStatus {
public void setMessage(final String message) { public void setMessage(final String message) {
this.message = message; this.message = message;
} }
/**
* Getter for additional information during validation.
* @return string of additional information
*/
public String getAdditionalInfo() {
return additionalInfo;
}
/**
* Setter for any additional information.
* @param additionalInfo the string of additional information
*/
public void setAdditionalInfo(final String additionalInfo) {
this.additionalInfo = additionalInfo;
}
} }

View File

@ -47,6 +47,7 @@ public class ComponentClass {
private String category; private String category;
private String component; private String component;
private int componentIdentifier; private int componentIdentifier;
private String classValueString;
/** /**
* Default class constructor. * Default class constructor.
@ -83,6 +84,7 @@ public class ComponentClass {
*/ */
public ComponentClass(final Path componentClassPath, final String componentIdentifier) { public ComponentClass(final Path componentClassPath, final String componentIdentifier) {
this(componentClassPath, getComponentIntValue(componentIdentifier)); this(componentClassPath, getComponentIntValue(componentIdentifier));
this.classValueString = componentIdentifier;
} }
/** /**
@ -142,6 +144,14 @@ public class ComponentClass {
return componentIdentifier; return componentIdentifier;
} }
/**
* Getter for the Component Class Value as a string.
* @return String representation of the class.
*/
public final String getClassValueString() {
return classValueString;
}
/** /**
* This is the main way this class will be referenced and how it * This is the main way this class will be referenced and how it
* will be displayed on the portal. * will be displayed on the portal.

View File

@ -46,6 +46,10 @@ public class ComponentInfo implements Serializable {
@Column @Column
private String componentRevision; private String componentRevision;
@XmlElement
@Column
private String componentClass;
/** /**
* Get the Component's Manufacturer. * Get the Component's Manufacturer.
* @return the Component's Manufacturer * @return the Component's Manufacturer
@ -78,6 +82,14 @@ public class ComponentInfo implements Serializable {
return componentRevision; return componentRevision;
} }
/**
* Get the Component's Class Registry.
* @return the Component's Class
*/
public String getComponentClass() {
return componentClass;
}
/** /**
* Default constructor required by Hibernate. * Default constructor required by Hibernate.
*/ */
@ -115,6 +127,45 @@ public class ComponentInfo implements Serializable {
} }
} }
/**
* Constructor.
* @param componentManufacturer Component Manufacturer (must not be null)
* @param componentModel Component Model (must not be null)
* @param componentSerial Component Serial Number (can be null)
* @param componentRevision Component Revision or Version (can be null)
* @param componentClass Component Class (can be null)
*/
public ComponentInfo(final String componentManufacturer,
final String componentModel,
final String componentSerial,
final String componentRevision,
final String componentClass) {
Assert.state(isComplete(
componentManufacturer,
componentModel,
componentSerial,
componentRevision
));
this.componentManufacturer = componentManufacturer.trim();
this.componentModel = componentModel.trim();
if (componentSerial != null) {
this.componentSerial = componentSerial.trim();
} else {
this.componentSerial = StringUtils.EMPTY;
}
if (componentRevision != null) {
this.componentRevision = componentRevision.trim();
} else {
this.componentRevision = StringUtils.EMPTY;
}
if (componentClass != null) {
this.componentClass = componentClass;
} else {
this.componentClass = StringUtils.EMPTY;
}
}
/** /**
* Determines whether the given properties represent a * Determines whether the given properties represent a
* ComponentInfo that will be useful in validation. * ComponentInfo that will be useful in validation.
@ -131,9 +182,8 @@ public class ComponentInfo implements Serializable {
final String componentModel, final String componentModel,
final String componentSerial, final String componentSerial,
final String componentRevision) { final String componentRevision) {
return !( return !(StringUtils.isEmpty(componentManufacturer)
StringUtils.isEmpty(componentManufacturer) || StringUtils.isEmpty(componentModel) || StringUtils.isEmpty(componentModel));
);
} }
@Override @Override
@ -149,22 +199,26 @@ public class ComponentInfo implements Serializable {
&& Objects.equals(componentManufacturer, that.componentManufacturer) && Objects.equals(componentManufacturer, that.componentManufacturer)
&& Objects.equals(componentModel, that.componentModel) && Objects.equals(componentModel, that.componentModel)
&& Objects.equals(componentSerial, that.componentSerial) && Objects.equals(componentSerial, that.componentSerial)
&& Objects.equals(componentRevision, that.componentRevision); && Objects.equals(componentRevision, that.componentRevision)
&& Objects.equals(componentClass, that.componentClass);
} }
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hash(id, componentManufacturer, componentModel, return Objects.hash(id, componentManufacturer, componentModel,
componentSerial, componentRevision); componentSerial, componentRevision, componentClass);
} }
@Override @Override
public String toString() { public String toString() {
return "ComponentInfo{" return String.format("ComponentInfo{"
+ "componentManufacturer='" + componentManufacturer + '\'' + "componentManufacturer='%s'"
+ ", componentModel='" + componentModel + '\'' + ", componentModel='%s'"
+ ", componentSerial='" + componentSerial + '\'' + ", componentSerial='%s'"
+ ", componentRevision='" + componentRevision + '\'' + ", componentRevision='%s'"
+ '}'; + ", componentClass='%s'}",
componentManufacturer,
componentModel, componentSerial,
componentRevision, componentClass);
} }
} }

View File

@ -140,6 +140,43 @@ public final class SupplyChainCredentialValidator implements CredentialValidator
return componentInfoList; return componentInfoList;
} }
/**
* Parses the output from PACCOR's allcomponents.sh script into ComponentInfo objects.
* @param paccorOutput the output from PACCOR's allcomoponents.sh
* @return a list of ComponentInfo objects built from paccorOutput
* @throws IOException if something goes wrong parsing the JSON
*/
public static List<ComponentInfo> getV2PaccorOutput(
final String paccorOutput) throws IOException {
List<ComponentInfo> ciList = new LinkedList<>();
String manufacturer, model, serial, revision;
String componentClass = Strings.EMPTY;
if (StringUtils.isNotEmpty(paccorOutput)) {
ObjectMapper objectMapper = new ObjectMapper(new JsonFactory());
JsonNode rootNode = objectMapper.readTree(paccorOutput);
Iterator<JsonNode> jsonComponentNodes
= rootNode.findValue("COMPONENTS").elements();
while (jsonComponentNodes.hasNext()) {
JsonNode next = jsonComponentNodes.next();
manufacturer = getJSONNodeValueAsText(next, "MANUFACTURER");
model = getJSONNodeValueAsText(next, "MODEL");
serial = getJSONNodeValueAsText(next, "SERIAL");
revision = getJSONNodeValueAsText(next, "REVISION");
List<JsonNode> compClassNodes = next.findValues("COMPONENTCLASS");
for (JsonNode subNode : compClassNodes) {
componentClass = getJSONNodeValueAsText(subNode,
"COMPONENTCLASSVALUE");
}
ciList.add(new ComponentInfo(manufacturer, model,
serial, revision, componentClass));
}
}
return ciList;
}
private static String getJSONNodeValueAsText(final JsonNode node, final String fieldName) { private static String getJSONNodeValueAsText(final JsonNode node, final String fieldName) {
if (node.hasNonNull(fieldName)) { if (node.hasNonNull(fieldName)) {
return node.findValue(fieldName).asText(); return node.findValue(fieldName).asText();
@ -555,6 +592,7 @@ public final class SupplyChainCredentialValidator implements CredentialValidator
* base cert for this specific chain * base cert for this specific chain
* @return Appraisal Status of delta being validated. * @return Appraisal Status of delta being validated.
*/ */
@SuppressWarnings("methodlength")
static AppraisalStatus validateDeltaAttributesChainV2p0( static AppraisalStatus validateDeltaAttributesChainV2p0(
final DeviceInfoReport deviceInfoReport, final DeviceInfoReport deviceInfoReport,
final Map<PlatformCredential, SupplyChainValidation> deltaMapping, final Map<PlatformCredential, SupplyChainValidation> deltaMapping,
@ -602,7 +640,10 @@ public final class SupplyChainCredentialValidator implements CredentialValidator
StringBuilder failureMsg = new StringBuilder(); StringBuilder failureMsg = new StringBuilder();
certificateList = new ArrayList<>(); certificateList = new ArrayList<>();
certificateList.add(delta); certificateList.add(delta);
/**
* This chainnn maipping may have to change because
* the serial number isn't required
*/
for (ComponentIdentifier ci : delta.getComponentIdentifiers()) { for (ComponentIdentifier ci : delta.getComponentIdentifiers()) {
if (ci.isVersion2()) { if (ci.isVersion2()) {
ciSerial = ci.getComponentSerial().toString(); ciSerial = ci.getComponentSerial().toString();
@ -681,10 +722,18 @@ public final class SupplyChainCredentialValidator implements CredentialValidator
String paccorOutputString = deviceInfoReport.getPaccorOutputString(); String paccorOutputString = deviceInfoReport.getPaccorOutputString();
String unmatchedComponents; String unmatchedComponents;
try { try {
List<ComponentInfo> componentInfoList // List<ComponentInfo> componentInfoList
= getComponentInfoFromPaccorOutput(paccorOutputString); // = getComponentInfoFromPaccorOutput(paccorOutputString);
unmatchedComponents = validateV2p0PlatformCredentialComponentsExpectingExactMatch( // compare based on component class
new LinkedList<>(chainCiMapping.values()), componentInfoList); List<ComponentInfo> componentInfoList = getV2PaccorOutput(paccorOutputString);
// testComponentMatching(compMapping, chainCiMapping.values());
// this is what I want to rewrite
// unmatchedComponents = validateV2p0PlatformCredentialComponentsExpectingExactMatch(
// new LinkedList<>(chainCiMapping.values()),
// compMapping.keySet().stream().collect(Collectors.toList()));
unmatchedComponents = validateV2PlatformCredentialAttributes(
new LinkedList<>(chainCiMapping.values()),
componentInfoList);
fieldValidation &= unmatchedComponents.isEmpty(); fieldValidation &= unmatchedComponents.isEmpty();
} catch (IOException e) { } catch (IOException e) {
final String baseErrorMessage = "Error parsing JSON output from PACCOR: "; final String baseErrorMessage = "Error parsing JSON output from PACCOR: ";
@ -692,16 +741,82 @@ public final class SupplyChainCredentialValidator implements CredentialValidator
LOGGER.error("PACCOR output string:\n" + paccorOutputString); LOGGER.error("PACCOR output string:\n" + paccorOutputString);
return new AppraisalStatus(ERROR, baseErrorMessage + e.getMessage()); return new AppraisalStatus(ERROR, baseErrorMessage + e.getMessage());
} }
if (!fieldValidation) { if (!fieldValidation) {
// instead of listing all unmatched, just print the #. The failure
// will link to the platform certificate that'll display them.
LOGGER.error(unmatchedComponents);
String failureResults = unmatchedComponents.substring(0,
unmatchedComponents.length() - 1);
String size = unmatchedComponents.substring(unmatchedComponents.length() - 1);
resultMessage = new StringBuilder(); resultMessage = new StringBuilder();
resultMessage.append("There are unmatched components:\n"); resultMessage.append(String.format("There are %s unmatched components",
resultMessage.append(unmatchedComponents); size));
return new AppraisalStatus(FAIL, resultMessage.toString(), failureResults);
}
return new AppraisalStatus(PASS, PLATFORM_ATTRIBUTES_VALID);
}
return new AppraisalStatus(FAIL, resultMessage.toString()); private static String validateV2PlatformCredentialAttributes(
final List<ComponentIdentifier> fullDeltaChainComponents,
final List<ComponentInfo> allDeviceInfoComponents) {
ComponentIdentifierV2 ciV2;
StringBuilder invalidDeviceInfo = new StringBuilder();
StringBuilder invalidPcIds = new StringBuilder();
List<ComponentIdentifier> subCompIdList = fullDeltaChainComponents
.stream().collect(Collectors.toList());
List<ComponentInfo> subCompInfoList = allDeviceInfoComponents
.stream().collect(Collectors.toList());
LOGGER.error(String.format("fullDeltaChainComponents - %d", fullDeltaChainComponents.size()));
LOGGER.error(String.format("subCompIdList - %d", subCompIdList.size()));
LOGGER.error(String.format("allDeviceInfoComponents - %d", allDeviceInfoComponents.size()));
LOGGER.error(String.format("subCompInfoList - %d", subCompInfoList.size()));
// Delta is the baseline
for (ComponentInfo cInfo : allDeviceInfoComponents) {
for (ComponentIdentifier cId : fullDeltaChainComponents) {
ciV2 = (ComponentIdentifierV2) cId;
if (cInfo.getComponentClass().equals(
ciV2.getComponentClass().getClassValueString())) {
LOGGER.error(String.format("Testing %s -> %s%n%n", cInfo, ciV2));
if (!isMatch(cId, cInfo)) {
invalidDeviceInfo.append(String.format("%s:%s;",
cInfo.getComponentClass(), cInfo.toString()));
invalidPcIds.append(String.format("%s:%s;",
ciV2.getComponentClass().getClassValueString(),
ciV2.toString()));
} else {
LOGGER.error("TDM - Removed items");
subCompIdList.remove(cId);
subCompInfoList.remove(cInfo);
}
}
}
} }
return new AppraisalStatus(PASS, PLATFORM_ATTRIBUTES_VALID); if (subCompIdList.isEmpty() && subCompInfoList.isEmpty()) {
return Strings.EMPTY;
}
// now we return everything that was unmatched
// what is in the component info/device reported components
// is to be displayed as the failure
if (!subCompIdList.isEmpty()) {
for (ComponentIdentifier ci : subCompIdList) {
ciV2 = (ComponentIdentifierV2) ci;
invalidPcIds.append(String.format("%s:%s;",
ciV2.getComponentClass().getClassValueString(),
ciV2.getComponentModel()));
}
}
if (!subCompInfoList.isEmpty()) {
for (ComponentInfo ci : subCompInfoList) {
invalidDeviceInfo.append(String.format("%s:%s;",
ci.getComponentClass(), ci.getComponentModel()));
}
}
return String.format("DEVICEINFO=%s?COMPID=%s%d",
invalidDeviceInfo.toString(), invalidPcIds.toString(), subCompInfoList.size());
} }
/** /**