Add changes for device deletion.

Changes data structures to facilitate deletion of devices
from the DB and all other entries with foreign key relationships.
This commit is contained in:
apldev2 2018-11-20 10:21:11 -05:00 committed by apldev3
parent 3c5a657c17
commit 02cb30ad6d
8 changed files with 241 additions and 5 deletions

View File

@ -1,6 +1,12 @@
package hirs.data.persist;
import com.google.common.base.Preconditions;
import hirs.persist.CrudManager;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.hibernate.criterion.Conjunction;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Restrictions;
import javax.persistence.CascadeType;
import javax.persistence.Column;
@ -11,10 +17,14 @@ import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
/**
* A container class to group multiple related {@link SupplyChainValidation} instances
@ -26,6 +36,8 @@ public class SupplyChainValidationSummary extends ArchivableEntity {
@JoinColumn(name = "device_id")
private final Device device;
private static final String DEVICE_ID_FIELD = "device.id";
@Column
@Enumerated(EnumType.STRING)
private final AppraisalStatus.Status overallValidationResult;
@ -43,6 +55,113 @@ public class SupplyChainValidationSummary extends ArchivableEntity {
validations = Collections.emptySet();
}
/**
* This class enables the retrieval of SupplyChainValidationSummaries by their attributes.
*/
public static class Selector {
private final CrudManager<SupplyChainValidationSummary>
supplyChainValidationSummaryCrudManager;
private final Map<String, Object> fieldValueSelections;
/**
* Construct a new Selector that will use the given {@link CrudManager} to
* retrieve SupplyChainValidationSummaries.
*
* @param supplyChainValidationSummaryCrudManager the summary manager to be used to retrieve
* supply chain validation summaries
*/
public Selector(
final CrudManager<SupplyChainValidationSummary>
supplyChainValidationSummaryCrudManager) {
Preconditions.checkArgument(
supplyChainValidationSummaryCrudManager != null,
"supply chain validation summary manager cannot be null"
);
this.supplyChainValidationSummaryCrudManager = supplyChainValidationSummaryCrudManager;
this.fieldValueSelections = new HashMap<>();
}
/**
* Construct the criterion that can be used to query for supply chain validation summaries
* matching the configuration of this Selector.
*
* @return a Criterion that can be used to query for supply chain validation summaries
* matching the configuration of this instance
*/
public Criterion getCriterion() {
Conjunction conj = new Conjunction();
for (Map.Entry<String, Object> fieldValueEntry : fieldValueSelections.entrySet()) {
conj.add(Restrictions.eq(fieldValueEntry.getKey(), fieldValueEntry.getValue()));
}
return conj;
}
/**
* Set a field name and value to match.
*
* @param name the field name to query
* @param value the value to query
*/
protected void setFieldValue(final String name, final Object value) {
Object valueToAssign = value;
Preconditions.checkArgument(
value != null,
"field value cannot be null."
);
if (value instanceof String) {
Preconditions.checkArgument(
StringUtils.isNotEmpty((String) value),
"field value cannot be empty."
);
}
if (value instanceof byte[]) {
byte[] valueBytes = (byte[]) value;
Preconditions.checkArgument(
ArrayUtils.isNotEmpty(valueBytes),
"field value cannot be empty."
);
valueToAssign = Arrays.copyOf(valueBytes, valueBytes.length);
}
fieldValueSelections.put(name, valueToAssign);
}
/**
* Specify a device id that supply chain validation summaries must have to be considered
* as matching.
*
* @param device the device id to query
* @return this instance (for chaining further calls)
*/
public Selector byDeviceId(final UUID device) {
setFieldValue(DEVICE_ID_FIELD, device);
return this;
}
}
/**
* Get a Selector for use in retrieving SupplyChainValidationSummary.
*
* @param certMan the CrudManager to be used to retrieve persisted supply chain validation
* summaries
* @return a SupplyChainValidationSummary.Selector instance to use for retrieving certificates
*/
public static SupplyChainValidationSummary.Selector select(
final CrudManager<SupplyChainValidationSummary> certMan) {
return new SupplyChainValidationSummary.Selector(certMan);
}
/**
* Construct a new SupplyChainValidationSummary.
*

View File

@ -21,6 +21,12 @@ public abstract class DeviceAssociatedCertificate extends Certificate {
@JoinColumn(name = "device_id")
private Device device;
/**
* Holds the name of the entity 'DEVICE_ID' field.
*/
protected static final String DEVICE_ID_FIELD = "device.id";
/**
* Default Constructor.
*/

View File

@ -7,6 +7,7 @@ import java.io.IOException;
import java.nio.file.Path;
import java.util.Collections;
import java.util.Set;
import java.util.UUID;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
@ -40,6 +41,18 @@ public class IssuedAttestationCertificate extends DeviceAssociatedCertificate {
public Selector(final CertificateManager certificateManager) {
super(certificateManager, IssuedAttestationCertificate.class);
}
/**
* Specify a device id that certificates must have to be considered
* as matching.
*
* @param device the device id to query
* @return this instance (for chaining further calls)
*/
public Selector byDeviceId(final UUID device) {
setFieldValue(DEVICE_ID_FIELD, device);
return this;
}
}
/**

View File

@ -274,4 +274,26 @@ public class DBDeviceManager extends DBManager<Device> implements
return devices;
}
/**
* Deletes the <code>Device</code> from the database. This removes all
* of the database entries that stored information with regards to the
* <code>Device</code> with a foreign key relationship.
*
* @param name of the device to be deleted
* @return true if successfully found and deleted, false if otherwise
* @throws DeviceGroupManagerException
* if unable to find the device group or delete it from the
* database
*/
@Override
public final boolean deleteDevice(final String name)
throws DeviceManagerException {
LOGGER.debug("deleting device: {}", name);
try {
return super.delete(name);
} catch (DBManagerException e) {
throw new DeviceManagerException(e);
}
}
}

View File

@ -115,7 +115,7 @@ public class DBManager<T> extends AbstractDbManager<T> {
* @throws DBManagerException if an error is encountered while performing the query or creating
* the result objects
*/
protected final List<T> getWithCriteria(final Collection<Criterion> criteriaCollection)
public final List<T> getWithCriteria(final Collection<Criterion> criteriaCollection)
throws DBManagerException {
return retryTemplate.execute(
new RetryCallback<List<T>, DBManagerException>() {

View File

@ -118,4 +118,15 @@ public interface DeviceManager extends OrderedListQuerier<Device> {
*/
List<Device> getDefaultDevices() throws DeviceManagerException;
/**
* Delete the <code>Device</code> identified by <code>name</code>. If
* the deletion is successful, true is returned. Otherwise, false is
* returned.
*
* @param name of the <code>Device</code> to delete
* @return boolean indicating outcome of the deletion
* @throws DeviceManagerException if unable to delete the device group
*/
boolean deleteDevice(String name) throws DeviceManagerException;
}

View File

@ -1,12 +1,17 @@
package hirs.persist;
import hirs.data.persist.Device;
import hirs.data.persist.DeviceGroup;
import hirs.data.persist.SpringPersistenceTest;
import hirs.data.persist.certificate.Certificate;
import hirs.data.persist.certificate.CertificateAuthorityCredential;
import hirs.data.persist.certificate.CertificateTest;
import hirs.data.persist.certificate.ConformanceCredential;
import hirs.data.persist.certificate.DeviceAssociatedCertificate;
import hirs.data.persist.certificate.EndorsementCredential;
import hirs.data.persist.certificate.IssuedAttestationCertificate;
import hirs.data.persist.certificate.PlatformCredential;
import hirs.data.persist.certificate.PlatformCredentialTest;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@ -17,8 +22,6 @@ import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import hirs.data.persist.certificate.CertificateTest;
import hirs.data.persist.certificate.PlatformCredentialTest;
import java.io.IOException;
import java.math.BigInteger;
@ -34,6 +37,8 @@ import java.util.Map;
import java.util.Set;
import java.util.UUID;
import static hirs.data.persist.certificate.CertificateTest.ISSUED_CLIENT_CERT;
/**
* This class tests the storage, retrieval, and deletion of {@link Certificate}s.
*/
@ -75,7 +80,7 @@ public class DBCertificateManagerTest extends SpringPersistenceTest {
*/
@BeforeMethod
public void setupTestObjects() throws IOException {
// create indivdual test certificates
// create individual test certificates
rootCert = CertificateTest.getTestCertificate(CertificateTest.FAKE_ROOT_CA_FILE);
intelIntermediateCert = CertificateTest.getTestCertificate(
CertificateTest.FAKE_INTEL_INT_CA_FILE
@ -91,6 +96,9 @@ public class DBCertificateManagerTest extends SpringPersistenceTest {
CertificateTest.ANOTHER_SELF_SIGNED_FILE
);
hirsClientCert = CertificateTest.getTestCertificate(IssuedAttestationCertificate.class,
ISSUED_CLIENT_CERT);
stmEkCert = CertificateTest.getTestCertificate(EndorsementCredential.class,
CertificateTest.STM_NUC1_EC);
@ -137,7 +145,7 @@ public class DBCertificateManagerTest extends SpringPersistenceTest {
IssuedAttestationCertificate issuedCert =
(IssuedAttestationCertificate)
CertificateTest.getTestCertificate(IssuedAttestationCertificate.class,
CertificateTest.ISSUED_CLIENT_CERT, endorsementCredential, platformCredentials);
ISSUED_CLIENT_CERT, endorsementCredential, platformCredentials);
testCertificates.put(IssuedAttestationCertificate.class, issuedCert);
}
@ -381,6 +389,34 @@ public class DBCertificateManagerTest extends SpringPersistenceTest {
);
}
/**
* Tests that a Certificate can be retrieved by its deviceId.
* @throws IOException if there is a problem creating the certificate
* @throws CertificateException if there is a problem deserializing the original X509Certificate
*/
@Test
public void testGetByDeviceId() throws IOException, CertificateException {
CertificateManager certMan = new DBCertificateManager(sessionFactory);
DeviceManager deviceManager = new DBDeviceManager(sessionFactory);
DeviceGroupManager deviceGroupManager = new DBDeviceGroupManager(sessionFactory);
Device device = new Device("test_device");
DeviceGroup dg = new DeviceGroup("Default");
DeviceGroup savedDg = deviceGroupManager.saveDeviceGroup(dg);
device.setDeviceGroup(savedDg);
Device savedDevice = deviceManager.saveDevice(device);
((DeviceAssociatedCertificate) hirsClientCert).setDevice(savedDevice);
Certificate savedCert = certMan.save(hirsClientCert);
Set<IssuedAttestationCertificate> retrievedCerts =
IssuedAttestationCertificate.select(certMan).byDeviceId(savedDevice.getId()).
getCertificates();
Assert.assertEquals(retrievedCerts.size(), 1);
for (IssuedAttestationCertificate cert: retrievedCerts) {
Assert.assertEquals(savedCert.getId(), cert.getId());
}
}
/**
* Tests that a single Certificate can be retrieved amongst many stored Certificates according
* to its type and subject.

View File

@ -149,6 +149,35 @@ public final class DBDeviceManagerTest extends SpringPersistenceTest {
Assert.fail("save did not fail");
}
/**
* Tests that when a <code>Device</code> is deleted, the
* <code>Device</code> is removed from the DB.
*
* @throws Exception if error occurs while creating test device
*/
@Test
public void testDeleteDevice() throws Exception {
LOGGER.debug("testDeleteDevice");
Assert.assertEquals(DBUtility.getCount(sessionFactory, Device.class), 0);
final Device device = new Device(deviceName);
final DeviceManager mgr = new DBDeviceManager(sessionFactory);
final DeviceGroup group = createGroup(DeviceGroup.DEFAULT_GROUP);
device.setDeviceGroup(group);
final Device savedDevice = mgr.saveDevice(device);
Assert.assertEquals(DBUtility.getCount(sessionFactory, Device.class), 1);
Assert.assertTrue(DBUtility.isInDatabase(sessionFactory, Device.class, deviceName));
final UUID deviceID = savedDevice.getId();
Assert.assertNotNull(deviceID);
boolean deleteSuccessful = mgr.deleteDevice(deviceName);
Assert.assertTrue(deleteSuccessful);
Assert.assertFalse(
DBUtility.isInDatabase(sessionFactory, DeviceGroup.class, deviceName)
);
}
/**
* Tests that the <code>DBDeviceManager</code> can update a
* <code>Device</code>.