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);
boolean acceptExpiredCerts = policy.isExpiredCertificateValidationEnabled();
PlatformCredential baseCredential = null;
String componentFailures = "";
List<SupplyChainValidation> validations = new LinkedList<>();
Map<PlatformCredential, SupplyChainValidation> deltaMapping = new HashMap<>();
SupplyChainValidation platformScv = null;
@ -199,15 +198,22 @@ public class SupplyChainValidationServiceImpl implements SupplyChainValidationSe
Iterator<PlatformCredential> it = pcs.iterator();
while (it.hasNext()) {
PlatformCredential pc = it.next();
SupplyChainValidation attributeScv;
SupplyChainValidation attributeScv = null;
if (pc != null) {
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.
attributeScv = validateDeltaPlatformCredentialAttributes(
pc, device.getDeviceInfo(),
baseCredential, deltaMapping);
try {
attributeScv = validateDeltaPlatformCredentialAttributes(
pc, device.getDeviceInfo(),
baseCredential, deltaMapping);
} catch (Exception ex) {
for (StackTraceElement element : ex.getStackTrace()) {
LOGGER.error(element.toString());
}
LOGGER.error(ex.getMessage());
}
} else {
attributeScv = validatePlatformCredentialAttributes(
pc, device.getDeviceInfo(), ec);
@ -239,8 +245,6 @@ public class SupplyChainValidationServiceImpl implements SupplyChainValidationSe
String.format("%s%n%s", platformScv.getMessage(),
attributeScv.getMessage())));
}
componentFailures = updateUnmatchedComponents(
attributeScv.getMessage());
}
pc.setDevice(device);
@ -259,10 +263,6 @@ public class SupplyChainValidationServiceImpl implements SupplyChainValidationSe
// Generate validation summary, save it, and return it.
SupplyChainValidationSummary summary
= new SupplyChainValidationSummary(device, validations);
if (baseCredential != null) {
baseCredential.setComponentFailures(componentFailures);
this.certificateManager.update(baseCredential);
}
try {
supplyChainValidatorSummaryManager.save(summary);
} catch (DBManagerException ex) {
@ -272,29 +272,6 @@ public class SupplyChainValidationServiceImpl implements SupplyChainValidationSe
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
* 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,
result.getMessage(), delta, Level.INFO);
case FAIL:
if (!result.getAdditionalInfo().isEmpty()) {
LOGGER.error(result.getAdditionalInfo());
base.setComponentFailures(result.getAdditionalInfo());
this.certificateManager.update(base);
}
return buildValidationRecord(validationType, AppraisalStatus.Status.FAIL,
result.getMessage(), delta, Level.WARN);
case ERROR:

View File

@ -153,17 +153,6 @@ public class CertificateRequestPageController extends PageController<NoPageParam
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

View File

@ -340,7 +340,11 @@ public final class CertificateStringMapBuilder {
//CPSuri
data.put("CPSuri", certificate.getCPSuri());
//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
PlatformConfiguration platformConfiguration = certificate.getPlatformConfiguration();

View File

@ -32,6 +32,7 @@ public class AppraisalStatus {
private Status appStatus;
private String message;
private String additionalInfo;
/**
* Default constructor. Set appraisal status and description.
@ -43,6 +44,20 @@ public class AppraisalStatus {
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.
* @return appraisal status
@ -74,4 +89,20 @@ public class AppraisalStatus {
public void setMessage(final String 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 component;
private int componentIdentifier;
private String classValueString;
/**
* Default class constructor.
@ -83,6 +84,7 @@ public class ComponentClass {
*/
public ComponentClass(final Path componentClassPath, final String componentIdentifier) {
this(componentClassPath, getComponentIntValue(componentIdentifier));
this.classValueString = componentIdentifier;
}
/**
@ -142,6 +144,14 @@ public class ComponentClass {
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
* will be displayed on the portal.

View File

@ -46,6 +46,10 @@ public class ComponentInfo implements Serializable {
@Column
private String componentRevision;
@XmlElement
@Column
private String componentClass;
/**
* Get the Component's Manufacturer.
* @return the Component's Manufacturer
@ -78,6 +82,14 @@ public class ComponentInfo implements Serializable {
return componentRevision;
}
/**
* Get the Component's Class Registry.
* @return the Component's Class
*/
public String getComponentClass() {
return componentClass;
}
/**
* 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
* ComponentInfo that will be useful in validation.
@ -131,9 +182,8 @@ public class ComponentInfo implements Serializable {
final String componentModel,
final String componentSerial,
final String componentRevision) {
return !(
StringUtils.isEmpty(componentManufacturer) || StringUtils.isEmpty(componentModel)
);
return !(StringUtils.isEmpty(componentManufacturer)
|| StringUtils.isEmpty(componentModel));
}
@Override
@ -149,22 +199,26 @@ public class ComponentInfo implements Serializable {
&& Objects.equals(componentManufacturer, that.componentManufacturer)
&& Objects.equals(componentModel, that.componentModel)
&& Objects.equals(componentSerial, that.componentSerial)
&& Objects.equals(componentRevision, that.componentRevision);
&& Objects.equals(componentRevision, that.componentRevision)
&& Objects.equals(componentClass, that.componentClass);
}
@Override
public int hashCode() {
return Objects.hash(id, componentManufacturer, componentModel,
componentSerial, componentRevision);
componentSerial, componentRevision, componentClass);
}
@Override
public String toString() {
return "ComponentInfo{"
+ "componentManufacturer='" + componentManufacturer + '\''
+ ", componentModel='" + componentModel + '\''
+ ", componentSerial='" + componentSerial + '\''
+ ", componentRevision='" + componentRevision + '\''
+ '}';
return String.format("ComponentInfo{"
+ "componentManufacturer='%s'"
+ ", componentModel='%s'"
+ ", componentSerial='%s'"
+ ", componentRevision='%s'"
+ ", componentClass='%s'}",
componentManufacturer,
componentModel, componentSerial,
componentRevision, componentClass);
}
}

View File

@ -140,6 +140,43 @@ public final class SupplyChainCredentialValidator implements CredentialValidator
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) {
if (node.hasNonNull(fieldName)) {
return node.findValue(fieldName).asText();
@ -555,6 +592,7 @@ public final class SupplyChainCredentialValidator implements CredentialValidator
* base cert for this specific chain
* @return Appraisal Status of delta being validated.
*/
@SuppressWarnings("methodlength")
static AppraisalStatus validateDeltaAttributesChainV2p0(
final DeviceInfoReport deviceInfoReport,
final Map<PlatformCredential, SupplyChainValidation> deltaMapping,
@ -602,7 +640,10 @@ public final class SupplyChainCredentialValidator implements CredentialValidator
StringBuilder failureMsg = new StringBuilder();
certificateList = new ArrayList<>();
certificateList.add(delta);
/**
* This chainnn maipping may have to change because
* the serial number isn't required
*/
for (ComponentIdentifier ci : delta.getComponentIdentifiers()) {
if (ci.isVersion2()) {
ciSerial = ci.getComponentSerial().toString();
@ -681,10 +722,18 @@ public final class SupplyChainCredentialValidator implements CredentialValidator
String paccorOutputString = deviceInfoReport.getPaccorOutputString();
String unmatchedComponents;
try {
List<ComponentInfo> componentInfoList
= getComponentInfoFromPaccorOutput(paccorOutputString);
unmatchedComponents = validateV2p0PlatformCredentialComponentsExpectingExactMatch(
new LinkedList<>(chainCiMapping.values()), componentInfoList);
// List<ComponentInfo> componentInfoList
// = getComponentInfoFromPaccorOutput(paccorOutputString);
// compare based on component class
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();
} catch (IOException e) {
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);
return new AppraisalStatus(ERROR, baseErrorMessage + e.getMessage());
}
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.append("There are unmatched components:\n");
resultMessage.append(unmatchedComponents);
resultMessage.append(String.format("There are %s unmatched components",
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());
}
/**