Removed a lot of files

This commit is contained in:
Cyrus 2022-05-04 14:19:18 -04:00
parent cbf1b0aaa8
commit dabd88719f
121 changed files with 173 additions and 12850 deletions

View File

@ -34,7 +34,6 @@ import hirs.persist.DeviceManager;
import hirs.persist.ReferenceDigestManager;
import hirs.persist.ReferenceEventManager;
import hirs.persist.ReferenceManifestManager;
import hirs.persist.TPM2ProvisionerState;
import hirs.structs.converters.SimpleStructBuilder;
import hirs.structs.converters.StructConverter;
import hirs.structs.elements.aca.IdentityRequestEnvelope;

View File

@ -7,6 +7,11 @@ import hirs.persist.AppraiserManager;
import hirs.persist.DeviceGroupManager;
import hirs.persist.PolicyManager;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import static hirs.attestationca.AbstractAttestationCertificateAuthority.LOG;
/**
@ -66,4 +71,19 @@ public final class AcaDbInit {
LOG.info("ACA database initialization complete.");
}
public static void main(String[] args) throws IOException {
File file = new File("/home/tdmatth/Downloads/HP_CND12774J0_pxe.1.swidtag");
FileInputStream fis = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(fis);
byte[] buffer = new byte[1024];
int length = 0;
String output = "";
while ((length = bis.read(buffer)) != -1) {
output += new String(buffer, 0, length);
}
System.out.println(output);
}
}

View File

@ -9,7 +9,6 @@ import hirs.persist.DeviceManager;
import hirs.persist.ReferenceDigestManager;
import hirs.persist.ReferenceEventManager;
import hirs.persist.ReferenceManifestManager;
import hirs.persist.TPM2ProvisionerState;
import hirs.structs.converters.StructConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;

View File

@ -1,151 +0,0 @@
package hirs.alert;
import hirs.alert.resolve.AddToIMABaselineAlertResolver;
import hirs.alert.resolve.AddToTPMBaselineAlertResolver;
import hirs.alert.resolve.AlertResolver;
import hirs.alert.resolve.IgnoreAlertResolver;
import hirs.alert.resolve.RemoveFromIMABaselineAlertResolver;
import hirs.alert.resolve.RemoveFromTPMBaselineAlertResolver;
import hirs.alert.resolve.RequestNewReportAlertResolver;
import hirs.data.persist.baseline.Baseline;
import hirs.data.persist.baseline.SimpleImaBaseline;
import hirs.data.persist.baseline.TpmWhiteListBaseline;
/**
* Specifies actions that can be taken to resolve an Alert.
*/
public enum AlertResolutionAction {
/**
* Take no action.
*/
NONE("No action taken"),
/**
* Ignore the given alert or alerts.
*/
IGNORE("Ignored Once", IgnoreAlertResolver.class),
/**
* Add the referenced IMA record to a baseline.
*/
ADD_TO_IMA_BASELINE("Added to IMA Baseline", AddToIMABaselineAlertResolver.class,
SimpleImaBaseline.class),
/**
* Remove the referenced IMA record from any baselines it can be found in.
*/
REMOVE_FROM_IMA_BASELINE("Removed from IMA Baseline", RemoveFromIMABaselineAlertResolver.class,
SimpleImaBaseline.class),
/**
* Add the referenced TPM record to a baseline.
*/
ADD_TO_TPM_BASELINE("Added to TPM baseline", AddToTPMBaselineAlertResolver.class,
TpmWhiteListBaseline.class),
/**
* Remove the referenced TPM record from any baselines it can be found in.
*/
REMOVE_FROM_TPM_BASELINE("Removed from TPM Baseline", RemoveFromTPMBaselineAlertResolver.class,
TpmWhiteListBaseline.class),
/**
* Request a new report.
*/
REQUEST_NEW_REPORT("Requested new report.", RequestNewReportAlertResolver.class);
private final String defaultReason;
private final Class<? extends AlertResolver> alertResolver;
private final Class<? extends Baseline> baselineType;
/**
* Construct a new AlertResolutionAction with a reason the alert has been resolved, the class
* that can perform the resolution, and the class of baseline operated on by this resolution.
*
* @param defaultReason the reason an alert can be considered resolved as a result of this
* action
* @param alertResolver the class that will perform the resolution action
* @param baselineType the type of baseline operated on by this resolution action
*/
AlertResolutionAction(final String defaultReason,
final Class<? extends AlertResolver> alertResolver,
final Class<? extends Baseline> baselineType) {
this.defaultReason = defaultReason;
this.alertResolver = alertResolver;
this.baselineType = baselineType;
}
/**
* Construct a new AlertResolutionAction with a reason the alert has been resolved and the class
* that can perform the resolution.
*
* @param defaultReason the reason an alert can be considered resolved as a result of this
* action
* @param alertResolver the class that will perform the resolution action
*/
AlertResolutionAction(final String defaultReason,
final Class<? extends AlertResolver> alertResolver) {
this.defaultReason = defaultReason;
this.baselineType = null;
this.alertResolver = alertResolver;
}
/**
* Construct a new AlertResolutionAction with a reason the alert has been resolved.
*
* @param defaultReason the reason an alert can be considered resolved as a result of this
* action
*/
AlertResolutionAction(final String defaultReason) {
this.defaultReason = defaultReason;
this.baselineType = null;
this.alertResolver = null;
}
/**
* Returns a string containing a generic reason for the resolution if not provided by the user.
*
* @return string containing a generic reason for the resolution
*/
public String getDefaultReason() {
return defaultReason;
}
/**
* Returns the AlertResolver class for the action.
*
* @return the AlertResolver class for the action
*/
public Class<? extends AlertResolver> getAlertResolver() {
return alertResolver;
}
/**
* Returns the appropriate {@link Baseline} class for the action or null if the action does not
* involve a baseline.
*
* @return the appropriate {@link Baseline} class for the action
*/
public Class<? extends Baseline> getBaselineType() {
return baselineType;
}
/**
* Returns true if the resolution modifies a Baseline.
*
* @return true if the resolution modifies a Baseline
*/
public boolean isBaselineResolution() {
return baselineType != null;
}
/**
* Returns true if the resolution can resolve the specified Baseline.
*
* @param baseline the Baseline to test
* @return true if the resolution can resolve the specified Baseline.
*/
public boolean canResolve(final Baseline baseline) {
if (baseline == null || baselineType == null) {
return false;
} else {
return baselineType.isAssignableFrom(baseline.getClass());
}
}
}

View File

@ -1,84 +0,0 @@
package hirs.alert;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.util.List;
/**
* A serializable response for a possible alert resolution option.
*/
@SuppressFBWarnings("URF_UNREAD_FIELD")
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY)
public class AlertResolutionOption {
// the operation that will be attempted if this option is executed
private final AlertResolutionAction action;
// why the chosen option is provided
private final String reason;
// the names of the baselines that can be affected by this option
private List<String> whitelistNames;
private List<String> requiredSetNames;
private List<String> ignoreSetNames;
private List<String> tpmBaselineNames;
/**
* Create a new <code>AlertResolutionOption</code>.
*
* @param action to take if this option is chosen
* @param reason why the chosen option is provided
*/
public AlertResolutionOption(final AlertResolutionAction action, final String reason) {
this.action = action;
this.reason = reason;
}
/**
* Set the names of whitelists that can be edited by choosing this option.
*
* @param whitelistNames that can be edited
*/
public void setWhitelistNames(final List<String> whitelistNames) {
this.whitelistNames = whitelistNames;
}
/**
* Set the names of required sets that can be edited by choosing this option.
*
* @param requiredSetNames that can be edited
*/
public void setRequiredSetNames(final List<String> requiredSetNames) {
this.requiredSetNames = requiredSetNames;
}
/**
* Set the names of ignore sets that can be edited by choosing this option.
*
* @param ignoreSetNames that can be edited
*/
public void setIgnoreSetNames(final List<String> ignoreSetNames) {
this.ignoreSetNames = ignoreSetNames;
}
/**
* Set the names of TPM baselines that can be edited by choosing this option.
*
* @param tpmBaselineNames that can be edited
*/
public void setTpmBaselineNames(final List<String> tpmBaselineNames) {
this.tpmBaselineNames = tpmBaselineNames;
}
/**
* Checks if the specified action matches this option's action.
*
* @param action the action to check
* @return true if the specified action matches this option's action
*/
public boolean hasAction(final AlertResolutionAction action) {
return action == this.action;
}
}

View File

@ -1,65 +0,0 @@
package hirs.alert;
import hirs.data.persist.Alert;
import java.util.Collections;
import java.util.List;
/**
* Describes a resolution for an alert as specified by a user.
*/
public class AlertResolutionRequest {
private final List<Alert> alerts;
private final AlertResolutionAction action;
private final String baselineName;
private final String reason;
/**
* Constructor for AlertResolutionRequest.
* @param alerts the alerts being resolved
* @param action the action to take for resolving the alerts
* @param baselineName the baseline
* @param reason the reason for taking the action
*/
public AlertResolutionRequest(final List<Alert> alerts, final AlertResolutionAction action,
final String baselineName, final String reason) {
this.alerts = alerts;
this.action = action;
this.baselineName = baselineName;
this.reason = reason;
}
/**
* Gets an unmodifiable List of the alerts.
* @return an unmodifiable List of the alerts
*/
public List<Alert> getAlerts() {
return Collections.unmodifiableList(alerts);
}
/**
* Gets the action being taken for the alerts.
* @return the action being taken for the alerts
*/
public AlertResolutionAction getAction() {
return action;
}
/**
* Gets the name of the baseline.
* @return the name of the baseline
*/
public String getBaselineName() {
return baselineName;
}
/**
* Gets the reason for taking the action.
* @return the reason for taking the action
*/
public String getReason() {
return reason;
}
}

View File

@ -1,368 +0,0 @@
package hirs.alert;
import hirs.alert.resolve.AlertResolver;
import hirs.appraiser.Appraiser;
import hirs.appraiser.IMAAppraiser;
import hirs.appraiser.TPMAppraiser;
import hirs.data.persist.Alert;
import hirs.alert.resolve.AlertResolverFactory;
import hirs.data.persist.Device;
import hirs.data.persist.DeviceGroup;
import hirs.data.persist.IMAPolicy;
import hirs.data.persist.baseline.ImaAcceptableRecordBaseline;
import hirs.data.persist.baseline.ImaBaseline;
import hirs.data.persist.baseline.ImaIgnoreSetBaseline;
import hirs.data.persist.baseline.TPMBaseline;
import hirs.data.persist.TPMPolicy;
import hirs.data.persist.baseline.TpmWhiteListBaseline;
import hirs.data.persist.enums.AlertSource;
import hirs.data.persist.enums.AlertType;
import hirs.persist.AppraiserManager;
import hirs.persist.DeviceManager;
import hirs.persist.PolicyManager;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
import hirs.persist.AlertManager;
import hirs.persist.BaselineManager;
import hirs.persist.DeviceHealthManager;
import hirs.persist.ImaBaselineRecordManager;
/**
* A service to resolve {@link Alert}s that are no longer problematic. Determines the possible
* actions that can be taken given a specific set of alerts and takes those actions.
*/
@Service
public class AlertResolutionService {
private static final Logger LOGGER = LogManager.getLogger(AlertResolutionService.class);
@Autowired
private DeviceManager deviceManager;
@Autowired
private AppraiserManager appraiserManager;
@Autowired
private PolicyManager policyManager;
@Autowired
private AlertManager alertManager;
@Autowired
private DeviceHealthManager deviceHealthManager;
@Autowired
private BaselineManager baselineManager;
@Autowired
private ImaBaselineRecordManager imaBaselineRecordManager;
@Autowired
private AlertResolverFactory alertResolverFactory;
/**
* This method will evaluate alerts and provide potentially useful
* <code>AlertResolutionOption</code>s for resolution.
*
* @param alerts alerts to be evaluated for resolution
* @return
* Returns a list of <code>AlertResolutionOption</code>s based on the source,
* type, and associated policy of the given alerts
*/
public List<AlertResolutionOption> getResolutionOptions(final List<Alert> alerts) {
// find cases where ignoring is the only option, such as nonexistent devices or groups,
// multiple alert sources, or multiple device groups
List<AlertResolutionOption> options = getIgnoreOnlyOptions(alerts);
if (!options.isEmpty()) {
return options;
}
// now the alert sources and the device groups of the referenced devices should all be
// the same, so take them from the first alert
DeviceGroup deviceGroup = deviceManager.getDevice(alerts.get(0).getDeviceName())
.getDeviceGroup();
AlertSource source = alerts.get(0).getSource();
// build a list of resolution options specific to the alert source
LOGGER.debug(String.format("source of alerts is %s", source.toString()));
switch (source) {
case IMA_APPRAISER:
return getImaResolutionOptions(alerts, deviceGroup);
case TPM_APPRAISER:
return getTpmResolutionOptions(alerts, deviceGroup);
// only the default options are supported for all other alerts
default:
return getDefaultOptions(alerts);
}
}
/**
* Determine if the given alerts support any actions besides ignoring. This will be the case if
* one of the following is true:
* <ul>
* <li>Any of the alerts has a null device or nonexistent device name</li>
* <li>Any of the alerts references a device with a null group</li>
* <li>Any two alerts have different sources</li>
* <li>Any two alerts have different device groups (and thus different policies)</li>
* </ul>
*
* @param alerts the list of alerts to check
* @return a list with an ignore option or an empty list if there might be more options
*/
private List<AlertResolutionOption> getIgnoreOnlyOptions(final List<Alert> alerts) {
List<AlertResolutionOption> options = new ArrayList<>();
Device device = null;
AlertSource sharedSource = null;
AlertSource currentSource = null;
DeviceGroup sharedDeviceGroup = null;
DeviceGroup currentDeviceGroup = null;
for (Alert alert : alerts) {
// the device might be null if the report was malformed
device = deviceManager.getDevice(alert.getDeviceName());
if (device == null) {
options.add(new AlertResolutionOption(
AlertResolutionAction.IGNORE,
"One or more alerts reference a nonexistent device."));
return options;
}
// the device group shouldn't be null, but we should check it
currentDeviceGroup = device.getDeviceGroup();
if (currentDeviceGroup == null) {
options.add(new AlertResolutionOption(
AlertResolutionAction.IGNORE,
"One or more alerts reference a device with a nonexistent group."));
return options;
}
currentSource = alert.getSource();
if (currentSource == null) {
options.add(new AlertResolutionOption(
AlertResolutionAction.IGNORE,
"One or more alerts is missing an alert source."));
return options;
}
// if this is the first alert in the list
if (sharedSource == null && sharedDeviceGroup == null) {
sharedSource = currentSource;
sharedDeviceGroup = currentDeviceGroup;
} else {
if (!currentSource.equals(sharedSource)) {
options.add(new AlertResolutionOption(
AlertResolutionAction.IGNORE,
"Multiple alerts reference different alert sources."));
return options;
}
if (!currentDeviceGroup.equals(sharedDeviceGroup)) {
options.add(new AlertResolutionOption(
AlertResolutionAction.IGNORE,
"One or more alerts reference devices in different device groups."));
return options;
}
}
}
// an empty options list means the alert list may be actionable
return options;
}
/**
* Determine resolution options for alerts with IMA Appraiser as the alert source.
* @param alertList - list of alerts that share a source and device group
* @return a list of <code>AlertResolutionOption</code>s
*/
private List<AlertResolutionOption> getImaResolutionOptions(
final List<Alert> alertList, final DeviceGroup deviceGroup) {
boolean canAddToBaseline = true;
AlertType alertType;
for (Alert alert : alertList) {
alertType = alert.getType();
// addToBaseline only helps if each alert would be fixed by adding a record
if (!alertType.equals(AlertType.WHITELIST_MISMATCH)
&& !alertType.equals(AlertType.REQUIRED_SET_MISMATCH)
&& !alertType.equals(AlertType.UNKNOWN_FILE)) {
LOGGER.debug("cannot add ima record to baseline to resolve alert because alert is"
+ " type {}", alertType);
canAddToBaseline = false;
break;
}
}
List<AlertResolutionOption> options = getDefaultOptions(alertList);
if (canAddToBaseline) {
options.add(getAddToImaBaselineOption(deviceGroup));
}
return options;
}
/**
* Create an <code>AlertResolutionOption</code> to add to the IMA baselines associated with the
* given device group.
*
* @param deviceGroup to get IMA baselines from
* @return option including the possible baselines to add to
*/
private AlertResolutionOption getAddToImaBaselineOption(final DeviceGroup deviceGroup) {
AlertResolutionOption option = new AlertResolutionOption(
AlertResolutionAction.ADD_TO_IMA_BASELINE,
"One or more alerts could be resolved by adding a record to an IMA baseline.");
Appraiser appraiser = appraiserManager.getAppraiser(IMAAppraiser.NAME);
IMAPolicy imaPolicy = (IMAPolicy) policyManager.getPolicy(appraiser, deviceGroup);
List<ImaAcceptableRecordBaseline> whitelists = new ArrayList<>(imaPolicy.getWhitelists());
List<ImaAcceptableRecordBaseline> requiredSets =
new ArrayList<>(imaPolicy.getRequiredSets());
List<ImaIgnoreSetBaseline> ignoreSets = new ArrayList<>(imaPolicy.getIgnoreSets());
List<String> whitelistNames = new ArrayList<>();
for (ImaBaseline whitelist : whitelists) {
whitelistNames.add(whitelist.getName());
}
option.setWhitelistNames(whitelistNames);
List<String> requiredSetNames = new ArrayList<>();
for (ImaBaseline requiredSet : requiredSets) {
requiredSetNames.add(requiredSet.getName());
}
option.setRequiredSetNames(requiredSetNames);
List<String> ignoreSetNames = new ArrayList<>();
for (ImaIgnoreSetBaseline ignoreSet : ignoreSets) {
ignoreSetNames.add(ignoreSet.getName());
}
option.setIgnoreSetNames(ignoreSetNames);
return option;
}
/**
* Determine resolution options for alerts with TPM Appraiser as the alert source.
* @param alertList - list of alerts that share a source and device group
* @return a list of <code>AlertResolutionOption</code>s
*/
private List<AlertResolutionOption> getTpmResolutionOptions(
final List<Alert> alertList, final DeviceGroup deviceGroup) {
boolean canEditBaseline = true;
// should only attempt to add to the baseline if all the alerts are of
// the type WHITE_LIST_PCR_MISMATCH
for (Alert alert : alertList) {
if (!alert.getType().equals(AlertType.WHITE_LIST_PCR_MISMATCH)) {
canEditBaseline = false;
break;
}
}
List<AlertResolutionOption> options = getDefaultOptions(alertList);
if (canEditBaseline) {
options.add(getAddToTpmBaselineOption(deviceGroup));
options.add(new AlertResolutionOption(
AlertResolutionAction.REMOVE_FROM_TPM_BASELINE,
"One or more alerts could be resolved by removing a record from a TPM "
+ "baseline."));
}
return options;
}
/**
* Create an <code>AlertResolutionOption</code> to add to the TPM baselines associated with the
* given device group.
*
* @param deviceGroup to get TPM baselines from
* @return option including the possible baselines to add to
*/
private AlertResolutionOption getAddToTpmBaselineOption(final DeviceGroup deviceGroup) {
AlertResolutionOption option = new AlertResolutionOption(
AlertResolutionAction.ADD_TO_TPM_BASELINE,
"One or more alerts could be resolved by adding a record to a TPM baseline.");
Appraiser appraiser = appraiserManager.getAppraiser(TPMAppraiser.NAME);
TPMPolicy tpmPolicy = (TPMPolicy) policyManager.getPolicy(appraiser, deviceGroup);
List<TpmWhiteListBaseline> tpmBaselines
= new ArrayList<>(tpmPolicy.getTpmWhiteListBaselines());
List<String> tpmBaselineNames = new ArrayList<>();
for (TPMBaseline baseline : tpmBaselines) {
tpmBaselineNames.add(baseline.getName());
}
option.setTpmBaselineNames(tpmBaselineNames);
return option;
}
/**
* Build the list of default options.
* @return a list of the options available for all alerts
*/
private List<AlertResolutionOption> getDefaultOptions(final List<Alert> alertList) {
List<AlertResolutionOption> options = new ArrayList<>();
LOGGER.debug("adding default alert resolution options for alert source {}",
alertList.get(0).getSource());
// ignoring the alert and requesting a new report are always options
options.add(new AlertResolutionOption(
AlertResolutionAction.IGNORE,
"Default alert resolution option"));
options.add(new AlertResolutionOption(
AlertResolutionAction.REQUEST_NEW_REPORT,
"Default alert resolution option"));
return options;
}
/**
* Checks AlertResolutionRequest parameters, then creates and invokes the appropriate
* AlertResolver.
*
* @param request the AlertResolution request defining the action to be taken
* @return AlertResolutionResults containing the resolved alerts and errors
*/
@SuppressWarnings("checkstyle:avoidinlineconditionals")
public AlertResolver resolve(final AlertResolutionRequest request) {
// check alerts
final List<Alert> alerts = request.getAlerts();
if (alerts == null || alerts.isEmpty()) {
return alertResolverFactory.getAnonymous("No alerts were provided.");
}
// check if valid resolution
final AlertResolutionAction action = request.getAction();
List<AlertResolutionOption> options = getResolutionOptions(request.getAlerts());
for (AlertResolutionOption option : options) {
if (option.hasAction(action)) {
LOGGER.info("Resolving " + alerts.size() + " alert(s) by " + action + "...");
return alertResolverFactory.get(request).resolve();
}
}
// return error
String msg = action + " is not a valid resolution for the specified alert";
msg += request.getAlerts().size() == 1 ? "." : "s.";
return alertResolverFactory.getAnonymous(msg);
}
}

View File

@ -1,21 +0,0 @@
package hirs.alert;
import hirs.data.persist.Alert;
/**
* Alert service for sending out alerts. This class is an interface for
* components to use to send out <code>Alert</code>s. <code>Appraiser</code>
* should use this interface when sending out <code>Alert</code>s when
* an appraisal fail.
*/
public interface AlertService {
/**
* Send out an <code>Alert</code>. This will notify all interested parties
* of a new alert.
*
* @param alert alert
*/
void alert(Alert alert);
}

View File

@ -1,75 +0,0 @@
package hirs.alert;
import hirs.data.persist.Alert;
import hirs.data.persist.ReportSummary;
import hirs.persist.AlertManager;
import hirs.persist.AlertServiceConfigManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.apache.logging.log4j.Logger;
import static org.apache.logging.log4j.LogManager.getLogger;
import java.util.List;
/**
* The <code> CompositeAlertService</code> enables the forwarding of alerts. Supports alert
* forwarding to multiple alert monitoring applications. The CompositeAlertService interacts with
* the <code>AlertMonitorManager</code> to support Portal based management of the HIRS alert service
* and subscribers (alert Monitors) of the service. Supports managed and 1 unmanaged alert services.
* Currently the <code>HibernateAlertService</code> (the database) is the only unmanaged alert
* service.
*/
@Service
public class CompositeAlertService implements AlertService {
private static final Logger LOGGER = getLogger(CompositeAlertService.class);
@Autowired
private AlertServiceConfigManager alertServiceManager;
@Autowired
private List<ManagedAlertService> alertServices;
@Autowired
private AlertManager alertManager;
/**
* Forwarding service for alerts. Forwards the alert to all enabled Alert Service (Managed and
* unmanaged).
*
* @param alert alert to forward
*/
public final void alert(final Alert alert) {
LOGGER.debug("Sending alerts to all Managed Alert Services");
// persist the alert, must be done prior to using monitors.
alertManager.saveAlert(alert);
// iterate through the managed alert services and alert on each that is enabled
for (ManagedAlertService currentService : alertServices) {
if (currentService.isEnabled()) {
currentService.alert(alert);
}
}
}
/**
* Sends out an <code>Alert</code> when at least one alert is found after report processing is
* completed. The alert service configuration will determine if the service will send
* notification on every alert. This will notify all interested parties of a new alert. This is
* intended to be called at the end of the Integrity Report Processing when at least one or more
* alerts have been encountered
*
* @param summary the Summary created for the report
*/
public final void alertSummary(final ReportSummary summary) {
LOGGER.debug("Sending alert summaries to all Managed Alert Services");
for (ManagedAlertService currentService : alertServices) {
if (currentService.isEnabled()) {
currentService.alertSummary(summary);
}
}
}
}

View File

@ -1,216 +0,0 @@
package hirs.alert;
import static org.apache.logging.log4j.LogManager.getLogger;
import hirs.data.persist.Alert;
import hirs.data.persist.ReportSummary;
import hirs.data.persist.alert.AlertMonitor;
import hirs.data.persist.alert.AlertServiceConfig;
import hirs.data.persist.alert.JsonAlertMonitor;
import hirs.persist.AlertServiceConfigManager;
import hirs.persist.BaselineManager;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import hirs.persist.PolicyManager;
import hirs.persist.PortalInfoManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.fasterxml.jackson.databind.ObjectMapper;
import hirs.data.persist.enums.AlertSeverity;
import java.util.Optional;
import java.util.UUID;
/**
* Implementation of a JavaScript Object Notation (JSON) Alert Service.
* Upon receiving an Alert, the JSON service will wrap the alert data into a JSON object
* and forward the object to all JSON alert monitors configured for the service.
*/
@Service
public class JsonAlertService extends ManagedAlertService {
/**
* Name of the JSON alert service.
*/
public static final String NAME = "JSON";
private static final Logger LOGGER = getLogger(JsonAlertService.class);
/**
* DB Manager for Portal information.
*/
@Autowired
private PortalInfoManager portalInfoManager;
/**
* DB Manager for policy information.
*/
@Autowired
private PolicyManager policyManager;
/**
* DB Manager for baseline information.
*/
@Autowired
private BaselineManager baselineManager;
/**
* Creates a new <code>JsonAlertService</code> for testing. The optional config
* parameter is a file path to a Hibernate configuration file.
*/
public JsonAlertService() {
super(NAME);
}
/**
* Send a test alert to the configured JSON Alert Monitor.
* Used to ensure the target can receive forwarded alerts.
* @param jsonMonitor configured JSON Alert Monitor
* @return True if the test alert was sent. Otherwise false.
* @throws IOException If there was a problem.
*/
public boolean sendTest(final JsonAlertMonitor jsonMonitor) throws IOException {
HashMap<String, String> items = new HashMap<>();
String url = portalInfoManager.getPortalUrlBase() + "jsp/alertmonitors.jsp";
items.put("url", url);
Date datetime = new Date();
items.put("timestamp", formatDate(datetime));
items.put("hostname", InetAddress.getLocalHost().getHostName());
items.put("source", "PORTAL");
items.put("type", "Test JSON");
items.put("severity", AlertSeverity.INFO.toString());
items.put("details", "This is a test alert sent by the HIRS portal.");
return send(jsonMonitor, buildJson(items));
}
@Override
public void persist(final AlertServiceConfigManager alertServiceConfigManager) {
alertServiceConfigManager.saveAlertServiceConfig(new AlertServiceConfig(NAME));
}
/**
* Sends a JSON alert.
*
* @param monitor an alert monitor configuration.
* @param alert the individual alert to send to the remote monitor
*/
@Override
protected final void sendAlert(final AlertMonitor monitor, final Alert alert) {
if (isEnabled()) {
try {
if (!send((JsonAlertMonitor) monitor, convertAlert(alert))) {
LOGGER.error("Alert was not sent to JSON monitor '" + monitor.getName() + ".");
}
} catch (IOException ioe) {
LOGGER.error("Could not use properties file: " + ioe.getMessage());
}
}
}
/**
* Sends a JSON summary.
*
* @param monitor an alert monitor configuration.
* @param summary a summary of the report with the alert
*/
@Override
protected void sendAlertSummary(final AlertMonitor monitor, final ReportSummary summary) {
throw new UnsupportedOperationException("Alert summary functionality not yet implemented.");
}
/**
* Wraps the alert data into a JSON object.
* @param alert Alert to wrap into JSON.
* @return String of JSON data.
* @throws IOException If there is a problem.
*/
private String convertAlert(final Alert alert) throws IOException {
LOGGER.info("Sending JSON Alert Type = " + alert.getType().toString());
HashMap<String, String> items = new HashMap<>();
Optional<UUID> firstUUID = alert.getBaselineIds().stream().findFirst();
// Retrieve the url to the main page of the Portal
String url = portalInfoManager.getPortalUrlBase()
+ "jsp/alertdetails.jsp?alertID=" + alert.getId();
items.put("url", url);
items.put("id", alert.getId().toString());
items.put("timestamp", formatDate(alert.getCreateTime()));
items.put("hostname", alert.getDeviceName());
if (alert.getPolicyId() != null) {
items.put("policy", policyManager.getPolicy(alert.getPolicyId()).getName());
}
if (firstUUID.isPresent()) {
items.put("baseline",
baselineManager.getBaseline(firstUUID.get()).getName());
}
items.put("source", alert.getSource().toString());
items.put("type", alert.getType().toString());
items.put("severity", alert.getSeverity().toString());
items.put("details", alert.getDetails());
return buildJson(items);
}
/**
* Makes a String of JSON data from the elements provided.
* @param items Map<String,String> of elements to convert into a string of JSON data.
* The keys of the map will be used as field names, and the values will be the field values.
* @return String of JSON data.
*/
private String buildJson(final Map<String, String> items) throws IOException {
return new ObjectMapper().writeValueAsString(items);
}
/**
* Performs the transmission of data.
* @param jsonMonitor configured JSON Alert Monitor.
* @param json String of JSON data.
* @return True if the data was sent. Otherwise false.
* @throws IOException If there is a problem.
*/
private boolean send(final JsonAlertMonitor jsonMonitor, final String json) throws IOException {
// Open the appropriate socket type
// Each protocol has a different delivery process
if (jsonMonitor.isTCP()) {
try (Socket tcp = new Socket(jsonMonitor.getIpAddress(), jsonMonitor.getPort())) {
DataOutputStream out = new DataOutputStream(tcp.getOutputStream());
out.writeBytes(json);
out.flush();
return true;
}
} else if (jsonMonitor.isUDP()) {
try (DatagramSocket udp = new DatagramSocket()) {
DatagramPacket packet = new DatagramPacket(
json.getBytes(StandardCharsets.UTF_8), json.length(),
jsonMonitor.getIpAddress(), jsonMonitor.getPort());
udp.send(packet);
return true;
}
}
return false;
}
/**
* Convert a Date object into a String using the format used on the Portal.
* @param datetime Date object
* @return date formatted String
*/
private String formatDate(final Date datetime) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z");
return sdf.format(datetime);
}
}

View File

@ -1,257 +0,0 @@
package hirs.alert;
import com.google.common.base.Preconditions;
import hirs.data.persist.Alert;
import hirs.data.persist.ReportSummary;
import hirs.data.persist.alert.AlertMonitor;
import hirs.data.persist.alert.AlertServiceConfig;
import hirs.persist.AlertMonitorManager;
import hirs.persist.AlertServiceConfigManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import static org.apache.logging.log4j.LogManager.getLogger;
/**
* The ManagedAlertService is an abstract class that enables optional HIRS alert notifications. The
* <code>CompositeAlertService</code> will receive the alert notification from a HIRS component
* (e.g. IMAAppraiser)and forward the alert to all enabled alert services. Managed Alert Services
* enable portal configuration settings to create,delete, and configure settings for remote
* consumers of HIRS alerts.
*/
public abstract class ManagedAlertService implements AlertService {
private static final Logger LOGGER = getLogger(ManagedAlertService.class);
/**
* DB Manager for Alert Monitors.
*/
@Autowired
private AlertMonitorManager alertMonitorManager;
/**
* DB Manager for Alert Service Configs.
*/
@Autowired
private AlertServiceConfigManager alertServiceManager;
/**
* Alert Service Configuration for this Alert Service.
*/
private AlertServiceConfig config;
/**
* Alert Monitor List for this Alert Service.
*/
private List<AlertMonitor> monitors = new ArrayList<>();
private String name;
/**
* Construct a new ManagedAlertService.
*
* @param name the name of the alert service
*/
public ManagedAlertService(final String name) {
Preconditions.checkNotNull(name, "Name argument cannot be null.");
this.name = name;
}
/**
* Saves a new alert service manager.
*
* @param alertServiceConfigManager the manager to use to persist objects
*/
public abstract void persist(AlertServiceConfigManager alertServiceConfigManager);
/**
* Returns the type of the Managed Alert Service. type is used by DBManager to retrieve an
* object. name should be set by the class that extends ManagedAlertService within its
* constructor.
*
* @return Type of the Managed Alert Service
*/
public String getName() {
return name;
}
/**
* Returns a single configuration for the alert service.
*
* @return AlertServiceConfig object
*/
public AlertServiceConfig getConfig() {
return config;
}
/**
* Sets the configuration of a Managed Alert Service.
*
* @param newConfig Alert Service Configuration
*/
public final void updateConfig(final AlertServiceConfig newConfig) {
LOGGER.info("Updating Configuration for Alert Service of type {}", newConfig.getType());
alertServiceManager.updateAlertServiceConfig(newConfig);
}
/**
* Returns a list of alert monitors for this AlertService. Only monitors with the
* AlertServiceName matching this service will be returned.
*
* @return A list of ManagedAlertMonitors
*/
public final List<AlertMonitor> getMonitors() {
return Collections.unmodifiableList(monitors);
}
/**
* Finds and returns an Alert monitor.
*
* @param monitorName name of the Alert Monitor
* @return a AlertMonitor or null if not found
*/
public final AlertMonitor getMonitor(final String monitorName) {
LOGGER.debug("Getting Alert Monitor named {}", monitorName);
return alertMonitorManager.getAlertMonitor(monitorName);
}
/**
* Adds a monitor to the service monitor list. Inserts the name of this alert service to the
* monitor object
*
* @param newMonitor add a monitor to the Alert Services monitor list
*/
public final void addMonitor(final AlertMonitor newMonitor) {
LOGGER.info("Adding Alert Monitor named {}", newMonitor.getName());
newMonitor.setAlertServiceType(name);
alertMonitorManager.saveAlertMonitor(newMonitor);
}
/**
* Deletes the specified monitor from the alert services monitor list.
*
* @param monitorToDelete Alert Monitor to remove
*/
public final void deleteMonitor(final AlertMonitor monitorToDelete) {
LOGGER.info("Deleting Alert Monitor named {}", monitorToDelete.getName());
alertMonitorManager.deleteAlertMonitor(monitorToDelete.getName());
}
/**
* Forwards an alert to a managed alert service.
*
* @param alert alert to forward
*/
@Override
public void alert(final Alert alert) {
//check if portal updated properties since last time
reloadProperties();
// Only process alert if this alert service is enabled.
if (isEnabled()) {
for (AlertMonitor currentMonitor : monitors) {
if (currentMonitor.isMonitorEnabled()
&& currentMonitor.isIndividualAlertEnabled()) {
sendAlert(currentMonitor, alert);
}
}
}
}
/**
* Returns true if the configuration is not null and is enabled; false otherwise.
*
* @return true if the configuration is not null and is enabled; false otherwise
*/
public boolean isEnabled() {
return config != null && config.isEnabled();
}
/**
* Sends out an <code>Alert</code> when at least one alert is found after report processing is
* completed. The alert service configuration will determine if the service will send
* notification on every alert. This will notify all interested parties of a new alert.
*
* @param summary summary ReportSummary
*/
public void alertSummary(final ReportSummary summary) {
List<AlertMonitor> monitorList = alertMonitorManager
.getAlertMonitorList(AlertMonitor.class);
for (AlertMonitor currentMonitor : monitorList) {
if (currentMonitor.isMonitorEnabled()
&& currentMonitor.isAlertOnSummaryEnabled()) {
sendAlertSummary(currentMonitor, summary);
}
}
}
/**
* Sends an alert to a single alert monitor.
*
* @param monitor an individual alert monitor to send the alert to
* @param alert the individual alert to send to the remote monitor
*/
protected abstract void sendAlert(AlertMonitor monitor, Alert alert);
/**
* Sends an alert summary to a single alert monitor.
*
* @param monitor an individual alert monitor to send the alert to
* @param summary a summary for for the report
*/
protected abstract void sendAlertSummary(AlertMonitor monitor, ReportSummary summary);
/**
* Reloads <code>AlertService</code> configuration properties. This is intended to be called
* after the HIRS Portal updates a configuration file. This will force the service to update its
* properties.
*/
@PostConstruct
public final void reloadProperties() {
config = loadConfig();
monitors = loadMonitors();
}
/**
* Returns a list of alert monitors for this AlertService. Only monitors with the
* AlertServiceName matching this service will be returned.
*
* @return A list of ManagedAlertMonitors
*/
private List<AlertMonitor> loadMonitors() {
LOGGER.debug("Getting Alert Monitor list");
List<AlertMonitor> alertMonitors =
alertMonitorManager.getAlertMonitorList(AlertMonitor.class);
List<AlertMonitor> filteredMonitors = new ArrayList<>();
// screen all monitors and make sure they were intended for this alert service
for (AlertMonitor monitor : alertMonitors) {
if (monitor.getAlertServiceType().equals(getName())) {
filteredMonitors.add(monitor);
}
}
return filteredMonitors;
}
/**
* Returns a single configuration for the alert service.
*
* @return AlertServiceConfig object
*/
private AlertServiceConfig loadConfig() {
List<AlertServiceConfig> configurations =
alertServiceManager.getAlertServiceConfigList(AlertServiceConfig.class);
AlertServiceConfig configuration = null;
for (AlertServiceConfig conf : configurations) {
if (conf.getType().equals(getName())) {
configuration = conf;
}
}
return configuration;
}
}

View File

@ -1,4 +0,0 @@
/**
* Classes for the alert service.
*/
package hirs.alert;

View File

@ -1,25 +0,0 @@
package hirs.alert.resolve;
import hirs.data.persist.Alert;
import hirs.data.persist.baseline.IMABaselineRecord;
import org.springframework.stereotype.Component;
/**
* Resolves alerts by adding a record to an IMA Baseline.
*/
@Component
public class AddToIMABaselineAlertResolver extends IMABaselineAlertResolver {
@Override
public boolean resolve(final Alert alert) {
IMABaselineRecord record = parseImaRecord(alert, alert.getReceived());
if (record == null) {
return false;
} else {
record.setBaselineForRecordManager(imaBaseline);
imaBaselineRecordManager.saveRecord(record);
return true;
}
}
}

View File

@ -1,27 +0,0 @@
package hirs.alert.resolve;
import hirs.data.persist.Alert;
import hirs.data.persist.TPMMeasurementRecord;
import java.util.Set;
import org.springframework.stereotype.Component;
/**
* Resolves alerts by adding a record to a TPM Baseline.
*/
@Component
public class AddToTPMBaselineAlertResolver extends TPMBaselineAlertResolver {
@Override
public boolean resolve(final Alert alert) {
Set<TPMMeasurementRecord> records = parseTpmRecords(alert, alert.getReceived());
if (records == null) {
return false;
} else {
for (TPMMeasurementRecord record : records) {
tpmBaseline.addToBaseline(record);
}
return true;
}
}
}

View File

@ -1,261 +0,0 @@
package hirs.alert.resolve;
import hirs.alert.AlertResolutionAction;
import hirs.alert.AlertResolutionRequest;
import hirs.data.persist.Alert;
import hirs.persist.AlertManager;
import hirs.persist.DeviceHealthManager;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
/**
* Abstract class providing common functionality for resolving alerts including parameter checking,
* retrieving Alerts, Alert iteration, recording lists of resolved Alerts and error messages
* encountered during the Alert resolution process, and ultimately marking Alerts as being
* successfully resolved.
*/
public abstract class AlertResolver {
private static final Logger LOGGER = LogManager.getLogger(BaselineAlertResolver.class);
/**
* Returns an exception's message or its class name if message is null.
*
* @param ex the exception from which to get the message
* @return the exception's message or its class name if message is null
*/
protected static String getMessage(final Exception ex) {
if (StringUtils.isBlank(ex.getMessage())) {
return ex.getClass().getSimpleName();
} else {
return ex.getMessage();
}
}
@Autowired
private AlertManager alertManager;
@Autowired
private DeviceHealthManager deviceHealthManager;
private AlertResolutionRequest request;
private boolean hasExecuted = false;
private final List<Alert> resolved = new ArrayList<>();
private final List<String> errors = new ArrayList<>();
/**
* The default or user-specified explanation for the action taken.
*/
@SuppressWarnings("checkstyle:visibilitymodifier")
protected String reason;
/**
* Initializes the resolver by setting the resolution request and resetting results, errors, and
* state.
*
* @param request the request specifying the alerts to be resolved and action to be taken.
* @return this resolver
*/
final AlertResolver init(final AlertResolutionRequest request) {
this.request = request;
hasExecuted = false;
resolved.clear();
errors.clear();
reason = null;
return this;
}
/**
* Returns this resolver's alert resolution request.
*
* @return this resolver's alert resolution request.
*/
protected AlertResolutionRequest getRequest() {
return request;
}
/**
* Adds the specified alert to the list of resolved alerts.
*
* @param alert the alert that has been resolved successfully
* @return this resolver
*/
protected final AlertResolver addResolved(final Alert alert) {
resolved.add(alert);
return this;
}
/**
* Returns the list of resolved alerts.
*
* @return the list of resolved alerts.
*/
public final List<Alert> getResolved() {
return Collections.unmodifiableList(resolved);
}
/**
* Adds the message to the list of error messages.
*
* @param error the message to add
* @return this resolver
*/
public final AlertResolver addError(final String error) {
errors.add(error);
return this;
}
/**
* Adds the exception's message to the list of error messages.
*
* @param ex the exception to add
* @return this resolver
*/
public final AlertResolver addError(final Exception ex) {
errors.add(getMessage(ex));
return this;
}
/**
* Adds the error messages in the collection to the list of error messages.
*
* @param errors the error messages to add
* @return this resolver
*/
public final AlertResolver addErrors(final Collection<String> errors) {
this.errors.addAll(errors);
return this;
}
/**
* Returns true if error messages have been recorded.
*
* @return true if error messages have been recorded.
*/
public final boolean hasErrors() {
return !errors.isEmpty();
}
/**
* Returns the list of error messages.
*
* @return the list of error messages.
*/
public final List<String> getErrors() {
return Collections.unmodifiableList(errors);
}
/**
* Returns true if this resolver can perform the specified action.
*
* @param action the action to check
* @return true if this resolver can perform the specified action.
*/
public final boolean canResolve(final AlertResolutionAction action) {
if (action == null || action.getAlertResolver() == null) {
return false;
} else {
return action.getAlertResolver().isAssignableFrom(getClass());
}
}
/**
* Performs the resolution for the specified alerts. Checks if the resolver's current state is
* valid, does nothing if errors have already been encountered, sets the default reason if not
* specified by the user, iterates over the specified alerts calling the subclass's
* resolve(Alert) method, records the successfully resolved alerts, and updates the health
* status for associated devices
*
* @return this resolver
*/
public final AlertResolver resolve() {
// don't execute if errors have already been recorded.
if (!hasErrors()) {
// only run if initialized
if (request == null) {
throw new IllegalStateException("Resolver has not been initialized.");
}
// only allow to run once
if (hasExecuted) {
throw new IllegalStateException("Resolver has already been executed.");
}
hasExecuted = true;
final AlertResolutionAction action = request.getAction();
// get reason
reason = StringUtils.defaultIfBlank(request.getReason(), action.getDefaultReason());
// catch unexpected errors
try {
// allow subclasses to execute code before loop
if (beforeLoop()) {
// process each alert
if (action != AlertResolutionAction.NONE) {
for (final Alert alert : request.getAlerts()) {
if (resolve(alert)) {
addResolved(alert);
}
}
}
// allow subclasses to execute code after loop
if (afterLoop()) {
// mark the alerts as resolved
alertManager.resolveAlerts(getResolved(), reason);
deviceHealthManager.updateHealth(getResolved());
}
}
} catch (Exception ex) {
LOGGER.error("Error resolving alerts:", ex);
addError(ex);
}
}
return this;
}
/**
* Called for each alert by resolve. Must be implemented by subclasses.
*
* @param alert the alert to resolve
* @return true if the resolution was successful
*/
public abstract boolean resolve(Alert alert);
/**
* Optional hook to allow subclasses to execute code before the alerts are iterated.
*
* @return true if successful
*/
protected boolean beforeLoop() {
return true;
}
/**
* Optional hook to allow subclasses to execute code after the alerts are iterated.
*
* @return true if successful
*/
protected boolean afterLoop() {
return true;
}
}

View File

@ -1,59 +0,0 @@
package hirs.alert.resolve;
import hirs.alert.AlertResolutionAction;
import hirs.alert.AlertResolutionRequest;
import hirs.data.persist.Alert;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
/**
* Creates the appropriate AlertResolver bean for the specified AlertResolutionRequest.
*/
@Component
public class AlertResolverFactory {
@Autowired
private ApplicationContext ac;
/**
* Returns an anonymous AlertResolver that can be used to record and return error messages in
* cases where a specific AlertResolver cannot or has not been created.
*
* @param error the initial error message to record
* @return an anonymous AlertResolver
*/
public final AlertResolver getAnonymous(final String error) {
AlertResolver resolver = new AlertResolver() {
@Override
public boolean resolve(final Alert alert) {
throw new UnsupportedOperationException(
"This class is used only to report errors.");
}
};
return resolver.addError(error);
}
/**
* Creates the appropriate AlertResolver bean for the specified AlertResolutionRequest.
*
* @param request the user-specified AlertResolutionRequest
* @return the appropriate AlertResolver bean
*/
public final AlertResolver get(final AlertResolutionRequest request) {
final AlertResolutionAction action = request.getAction();
if (action == null) {
return getAnonymous("No action was provided.");
} else {
Class<? extends AlertResolver> resolverClass = action.getAlertResolver();
if (resolverClass == null) {
return getAnonymous("Action " + action + " does not resolve alerts.");
} else {
final AlertResolver resolver = ac.getBean(resolverClass);
return resolver.init(request);
}
}
}
}

View File

@ -1,91 +0,0 @@
package hirs.alert.resolve;
import hirs.alert.AlertResolutionAction;
import hirs.data.persist.baseline.Baseline;
import hirs.persist.BaselineManager;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
/**
* Abstract class for resolutions that involve the modification of baselines.
*/
public abstract class BaselineAlertResolver extends AlertResolver {
private static final Logger LOGGER = LogManager.getLogger(AlertResolver.class);
/**
* The baseline manager used to load and save baselines.
*/
@Autowired
@SuppressWarnings("checkstyle:visibilitymodifier")
protected BaselineManager baselineManager;
/**
* The baseline to be modified by this resolver.
*/
@SuppressWarnings("checkstyle:visibilitymodifier")
protected Baseline baseline;
/**
* Checks the baseline name and loads and checks the baseline or creates a new baseline.
*
* @return true if successful
*/
@Override
protected boolean beforeLoop() {
final AlertResolutionAction action = getRequest().getAction();
// get baseline name
final String name = getRequest().getBaselineName();
if (StringUtils.isBlank(name)) {
addError("No baseline name was specified.");
return false;
}
// add baseline name to default reason
if (reason != null && reason.equals(action.getDefaultReason())) {
reason += " '" + name + "'";
}
// get baseline type
final Class<? extends Baseline> type = action.getBaselineType();
// get or create baseline
baseline = baselineManager.getBaseline(name);
if (baseline != null) {
// check type
if (!action.canResolve(baseline)) {
addError("Baseline '" + name + "' is a "
+ baseline.getClass().getSimpleName() + ", but was expected to be a "
+ type.getSimpleName() + ".");
return false;
}
} else if (action.name().startsWith("ADD_TO")) {
// create new baseline
try {
baseline = type.newInstance();
} catch (InstantiationException | IllegalAccessException ex) {
String msg = "Error creating new baseline named '" + name + "'.";
LOGGER.error(msg, ex);
addError(msg);
return false;
}
baseline.setName(name);
baselineManager.saveBaseline(baseline);
} else {
addError("Could not find baseline named '" + name + "'.");
}
return true;
}
}

View File

@ -1,60 +0,0 @@
package hirs.alert.resolve;
import hirs.data.persist.Alert;
import hirs.data.persist.baseline.IMABaselineRecord;
import hirs.data.persist.baseline.SimpleImaBaseline;
import hirs.persist.ImaBaselineRecordManager;
import org.springframework.beans.factory.annotation.Autowired;
/**
* Abstract class providing common functionality for IMA Baseline alert resolvers.
*/
public abstract class IMABaselineAlertResolver extends BaselineAlertResolver {
/**
* The IMA baseline record manager used to load and save IMA baseline records.
*/
@Autowired
@SuppressWarnings("checkstyle:visibilitymodifier")
protected ImaBaselineRecordManager imaBaselineRecordManager;
/**
* The IMA baseline to be modified by this resolver.
*/
@SuppressWarnings("checkstyle:visibilitymodifier")
protected SimpleImaBaseline imaBaseline = null;
/**
* Casts BaselineAlertResolver's baseline to a SimpleImaBaseline.
*
* @return true to indicate success
*/
@Override
protected boolean beforeLoop() {
if (super.beforeLoop()) {
imaBaseline = (SimpleImaBaseline) baseline;
return true;
} else {
return false;
}
}
/**
* Parses the received/expected value of an {@link Alert} into an {@link IMABaselineRecord}.
*
* @param alert the Alert the record is from
* @param record - received/expected record from Alert
* @return IMABaselineRecord created from parsing the record String
*/
protected IMABaselineRecord parseImaRecord(final Alert alert, final String record) {
try {
return IMABaselineRecord.fromString(record);
} catch (Exception ex) {
String error = "Error parsing IMA record '" + record + "' for alert ["
+ alert.getId() + "]: " + getMessage(ex);
addError(error);
return null;
}
}
}

View File

@ -1,23 +0,0 @@
package hirs.alert.resolve;
import hirs.data.persist.Alert;
import org.springframework.stereotype.Component;
/**
* Ignores alerts by always indicating them as successfully resolved.
*/
@Component
public class IgnoreAlertResolver extends AlertResolver {
/**
* Returns true to indicate that AlertResolver should mark the alert as resolved.
*
* @param alert the alert to ignore
* @return true
*/
@Override
public boolean resolve(final Alert alert) {
return true;
}
}

View File

@ -1,42 +0,0 @@
package hirs.alert.resolve;
import hirs.data.persist.Alert;
import hirs.data.persist.baseline.IMABaselineRecord;
import org.springframework.stereotype.Component;
/**
* Resolves alerts by adding a record to an IMA baseline.
*/
@Component
public class RemoveFromIMABaselineAlertResolver extends IMABaselineAlertResolver {
/**
* Resolves alerts by adding a record to an IMA baseline.
*
* @param alert the alert to resolve
* @return true if the alert is successfully resolved
*/
@Override
public boolean resolve(final Alert alert) {
IMABaselineRecord find = parseImaRecord(alert, alert.getExpected());
find.setBaselineForRecordManager(imaBaseline);
IMABaselineRecord found = imaBaselineRecordManager.getRecord(
find.getPath(), find.getHash(), imaBaseline);
if (found == null) {
addError("Could not find IMA Baseline Record for alert " + "[" + alert.getId() + "].");
return false;
}
if (!imaBaselineRecordManager.deleteRecord(found)) {
addError("Could not delete IMA Baseline Record for alert "
+ "[" + alert.getId() + "].");
return false;
}
return true;
}
}

View File

@ -1,32 +0,0 @@
package hirs.alert.resolve;
import hirs.data.persist.Alert;
import hirs.data.persist.TPMMeasurementRecord;
import java.util.Set;
import org.springframework.stereotype.Component;
/**
* Resolves alerts by removing a record from a TPM Baseline.
*/
@Component
public class RemoveFromTPMBaselineAlertResolver extends TPMBaselineAlertResolver {
/**
* Resolves alerts by removing a record from a TPM Baseline.
* @param alert the alert to resolve
* @return true if the alert was successfully resolved
*/
@Override
public boolean resolve(final Alert alert) {
Set<TPMMeasurementRecord> records = parseTpmRecords(alert, alert.getExpected());
if (records == null) {
return false;
} else {
for (TPMMeasurementRecord record : records) {
tpmBaseline.removeFromBaseline(record);
}
return true;
}
}
}

View File

@ -1,66 +0,0 @@
package hirs.alert.resolve;
import hirs.data.persist.Alert;
import hirs.data.persist.Device;
import hirs.data.persist.IntegrityReport;
import hirs.persist.DeviceManager;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* Aggregates and deduplicates the devices associated with alerts so that new reports can be
* requested for them.
*/
@Component
public class RequestNewReportAlertResolver extends AlertResolver {
private final Map<String, Device> devices = new HashMap<>();
@Autowired
private DeviceManager deviceManager;
/**
* Aggregates the devices associated with alerts so that new reports can be requested for them.
*
* @param alert the alert to be resolved
* @return true if the device was successfully loaded
*/
@Override
public boolean resolve(final Alert alert) {
String name = alert.getDeviceName();
if (StringUtils.isBlank(name)) {
name = ((IntegrityReport) alert.getReport()).getDeviceName();
}
if (StringUtils.isEmpty(name)) {
addError("Could not get device name for alert [" + alert.getId() + "]");
return false;
} else if (!devices.containsKey(name)) {
Device device = deviceManager.getDevice(name);
if (device == null) {
addError("Device '" + name + "' for alert id [" + alert.getId()
+ "] was not found");
return false;
}
devices.put(name, device);
}
return true;
}
/**
* Returns a map of the loaded devices indexed by name.
*
* @return a map of the loaded devices indexed by name.
*/
public Map<String, Device> getDevices() {
return Collections.unmodifiableMap(devices);
}
}

View File

@ -1,127 +0,0 @@
package hirs.alert.resolve;
import hirs.data.persist.Alert;
import hirs.data.persist.Digest;
import hirs.data.persist.enums.DigestAlgorithm;
import hirs.data.persist.baseline.TPMBaseline;
import hirs.data.persist.TPMMeasurementRecord;
import java.util.HashSet;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
/**
* Abstract class providing common functionality for TPM Baseline alert resolvers.
*/
public abstract class TPMBaselineAlertResolver extends BaselineAlertResolver {
private static final Logger LOGGER = LogManager.getLogger(TPMBaselineAlertResolver.class);
/**
* The TPM baseline to be modified by this resolver.
*/
@SuppressWarnings("checkstyle:visibilitymodifier")
protected TPMBaseline tpmBaseline = null;
/**
* Casts BaselineAlertResolver's baseline to a TPMBaseline.
*
* @return true to indicate success
*/
@Override
protected boolean beforeLoop() {
if (super.beforeLoop()) {
tpmBaseline = (TPMBaseline) baseline;
return true;
} else {
return false;
}
}
/**
* Updates the baseline.
*
* @return true if successful
*/
@Override
protected boolean afterLoop() {
if (super.afterLoop()) {
baselineManager.updateBaseline(baseline);
return true;
} else {
return false;
}
}
// Regex patterns used to parse expected/received Strings in Alerts into records
private static final Pattern TPM_PCR_PATTERN = Pattern.compile(".*#([0-9]{1,2})");
private static final Pattern TPM_DIGEST_PATTERN = Pattern.compile("(.*:|or).(([a-f]|[0-9])*)");
/**
* Parses the record of an Alert into a TPMMeasurementRecord.
*
* @param alert - Alert to be resolved
* @param record - record chosen to be parsed
* @return TPMMeasurementRecord based on the TPM record and alert information
*/
protected Set<TPMMeasurementRecord> parseTpmRecords(final Alert alert, final String record) {
// parse the PCR values out of the Alert details String
Integer pcr = null;
final Matcher pcrMatcher = TPM_PCR_PATTERN.matcher(alert.getDetails());
if (pcrMatcher.find()) {
pcr = Integer.parseInt(pcrMatcher.group(1));
}
// creates digest from String
Set<Digest> digests = new HashSet<>();
final Matcher digestMatcher = TPM_DIGEST_PATTERN.matcher(record);
boolean digestError = false;
while (digestMatcher.find()) {
final String match = digestMatcher.group(2);
if (StringUtils.isBlank(match)) {
addError("Invalid syntax or digest value in record '" + record + "' for alert ["
+ alert.getId() + "].");
digestError = true;
} else {
try {
final byte[] digestBytes = Hex.decodeHex(match.toCharArray());
final Digest digest = new Digest(DigestAlgorithm.SHA1, digestBytes);
digests.add(digest);
} catch (DecoderException ex) {
final String msg = "Error decoding TPM record digest '" + match + "' in alert ["
+ alert.getId() + "]: " + getMessage(ex);
addError(msg);
digestError = true;
}
}
}
// check for errors
if (pcr == null || digests.isEmpty()) {
if (pcr == null) {
addError("Could not parse PCR from details '" + alert.getDetails() + "' in alert ["
+ alert.getId() + "].");
}
if (digests.isEmpty() && !digestError) {
addError("Could not parse digest from record '" + record + "' in alert ["
+ alert.getId() + "].");
}
return null;
}
// create records
final Set<TPMMeasurementRecord> measurementRecords = new HashSet<>();
for (Digest digest : digests) {
measurementRecords.add(new TPMMeasurementRecord(pcr, digest));
}
return measurementRecords;
}
}

View File

@ -1,4 +0,0 @@
/**
* Classes for alert resolvers.
*/
package hirs.alert.resolve;

View File

@ -1,489 +0,0 @@
package hirs.data.persist;
import hirs.data.persist.baseline.ImaIgnoreSetBaseline;
import hirs.data.persist.baseline.ImaBlacklistBaseline;
import hirs.data.persist.baseline.ImaBaseline;
import hirs.data.persist.baseline.ImaAcceptableRecordBaseline;
import hirs.data.persist.baseline.HasBaselines;
import hirs.data.persist.baseline.Baseline;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.OrderColumn;
import javax.persistence.Transient;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
/**
* Represents the criteria by which an <code>IMAAppraiser</code> appraises a
* <code>Report</code>. This includes the following:
* <p>&nbsp;
* <ul>
* <li>A list of <code>ImaBlacklistBaseline</code>s to use a blacklists</li>
* <li>A list of <code>ImaIgnoreSetBaseline</code>'s to use as ignore sets</li>
* <li>A list of <code>ImaAcceptableRecordBaseline</code>s to use as whitelists</li>
* <li>A list of <code>ImaAcceptableRecordBaseline</code>s to use as required sets</li>
* <li>A flag to determine determine whether appraisal should fail on unknowns </li>
* <li>A flag to determine whether PCR 10 should be used to validate the hash of
* the <code>IMAReport</code></li>
* <li>A flag to determine whether delta reports should be requested</li>
* <li>A flag to determine whether partial path appraisal should be supported</li>
* </ul>
*/
@Entity
public class IMAPolicy extends Policy implements HasBaselines {
private static final Logger LOGGER = LogManager.getLogger(IMAPolicy.class);
private static final boolean DEFAULT_UNKNOWN_POLICY = false;
private static final boolean DEFAULT_PCR_VALIDATION = false;
private static final boolean DEFAULT_DELTA_REPORT_POLICY = true;
private static final boolean DEFAULT_PARTIAL_PATH_POLICY = true;
@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(name = "Whitelists",
joinColumns = {@JoinColumn(
name = "PolicyID", nullable = false) })
@OrderColumn(name = "WhitelistsIndex")
private final List<ImaAcceptableRecordBaseline> whitelists = new LinkedList<>();
@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(name = "RequiredSets",
joinColumns = {@JoinColumn(
name = "PolicyID", nullable = false) })
@OrderColumn(name = "RequiredSetsIndex")
private final List<ImaAcceptableRecordBaseline> requiredSets = new LinkedList<>();
@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(name = "IgnoreSets",
joinColumns = {@JoinColumn(
name = "PolicyID", nullable = false) })
@OrderColumn(name = "IgnoreSetsIndex")
private final List<ImaIgnoreSetBaseline> ignoreSets = new LinkedList<>();
@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(name = "ImaBlacklists",
joinColumns = {@JoinColumn(
name = "PolicyID", nullable = false) })
@OrderColumn(name = "ImaBlacklistsIndex")
private final List<ImaBlacklistBaseline> blacklists = new LinkedList<>();
@Column(nullable = false)
private boolean failOnUnknowns = DEFAULT_UNKNOWN_POLICY;
@Column(nullable = false)
private boolean validatePcr = DEFAULT_PCR_VALIDATION;
@Column(nullable = false)
private boolean deltaReportEnable = DEFAULT_DELTA_REPORT_POLICY;
@Column(nullable = false)
private boolean partialPathEnable = DEFAULT_PARTIAL_PATH_POLICY;
@Transient
private Multimap<String, String> pathEquivalences = null;
/**
* Constructor used to initialize IMAPolicy object.
*
* @param name a name used to uniquely identify and reference the IMA policy
*/
public IMAPolicy(final String name) {
super(name);
}
/**
* Constructor used to initialize IMAPolicy object.
*
* @param name a name used to uniquely identify and reference the IMA policy
* @param description optional description that may be provided by the user
*/
public IMAPolicy(final String name, final String description) {
super(name, description);
}
/**
* Default constructor necessary for Hibernate.
*/
protected IMAPolicy() {
super();
}
/**
* Deprecated method to remove all whitelists currently contained in
* <code>this.whitelists</code> and add the given whitelist. Replaced by
* <code>setWhitelists</code>.
*
* @param imaBaseline baseline that represents the new white list, can be NULL
*/
public final void setWhitelist(final ImaAcceptableRecordBaseline imaBaseline) {
LOGGER.debug("adding ImaBaseline {} as {} policy whitelist",
imaBaseline, getName());
if (imaBaseline == null) {
this.whitelists.clear();
} else {
this.whitelists.clear();
this.whitelists.add(imaBaseline);
}
}
/**
* Replace the current <code>List</code> of whitelists with a new
* <code>List</code>. Can be empty but cannot be null. The order of the
* <code>List</code> will be the order used for appraisal by the
* <code>TPMAppraiser</code>.
*
* @param newWhitelists list of <code>ImaBaseline</code>s to use as whitelists, can be
* empty but not null
*/
public final void setWhitelists(
final List<? extends ImaAcceptableRecordBaseline> newWhitelists
) {
if (newWhitelists == null) {
throw new PolicyException("cannot set whitelists to null");
}
LOGGER.debug("setting new whitelists for {}", getName());
whitelists.clear();
whitelists.addAll(newWhitelists);
}
/**
* Deprecated method to return the first whitelist in
* <code>this.whitelists</code>. Replaced by <code>getWhitelists</code>.
*
* @return the baseline representing the first whitelist, can be NULL
*/
public final ImaAcceptableRecordBaseline getWhitelist() {
if (this.whitelists == null || this.whitelists.isEmpty()) {
return null;
}
return this.whitelists.get(0);
}
/**
* Return the current list of whitelists.
*
* @return the unmodifiable list of whitelists, cannot be null
*/
public final List<ImaAcceptableRecordBaseline> getWhitelists() {
return Collections.unmodifiableList(this.whitelists);
}
/**
* Deprecated method to remove all required sets currently contained in
* <code>this.requiredSets</code> and add the given required set. Replaced
* by <code>setRequiredSets</code>.
*
* @param imaBaseline baseline that represents the new required set, can be NULL
*/
public final void setRequiredSet(final ImaAcceptableRecordBaseline imaBaseline) {
LOGGER.debug("adding ImaBaseline {} as {} policy required set",
imaBaseline, getName());
if (imaBaseline == null) {
this.requiredSets.clear();
} else {
this.requiredSets.clear();
this.requiredSets.add(imaBaseline);
}
}
/**
* Replace the current <code>List</code> of required sets with a new
* <code>List</code>. Can be empty but cannot be null. The order of the
* <code>List</code> will be the order used for appraisal by the
* <code>TPMAppraiser</code>.
*
* @param newRequiredSets list of <code>ImaBaseline</code>s to use as required sets, can
* be empty but not null
*/
public final void setRequiredSets(
final List<? extends ImaAcceptableRecordBaseline> newRequiredSets
) {
if (newRequiredSets == null) {
throw new PolicyException("cannot set required sets to null");
}
LOGGER.debug("setting new required sets for {}", getName());
this.requiredSets.clear();
for (ImaAcceptableRecordBaseline baseline : newRequiredSets) {
this.requiredSets.add(baseline);
}
}
/**
* Deprecated method to return the first required set in
* <code>this.requiredSets</code>. Replaced by <code>getrequiredSets</code>.
*
* @return the baseline representing the first required set, can be NULL
*/
public final ImaBaseline getRequiredSet() {
if (this.requiredSets == null || this.requiredSets.isEmpty()) {
return null;
}
return this.requiredSets.get(0);
}
/**
* Return the current list of required sets.
*
* @return the unmodifiable list of required sets, cannot be null
*/
public final List<ImaAcceptableRecordBaseline> getRequiredSets() {
return Collections.unmodifiableList(this.requiredSets);
}
/**
* Deprecated method to remove all ignore sets currently contained in
* <code>this.ignoreSets</code> and add the given ignore set. Replaced
* by <code>setIgnoreSets</code>.
*
* @param imaIgnoreSetBaseline set of optional records that represents the new ignore set,
* can be NULL
*/
public final void setImaIgnoreSetBaseline(final ImaIgnoreSetBaseline
imaIgnoreSetBaseline) {
LOGGER.debug("adding optionalSetPolicy {} as {} policy ignore set",
imaIgnoreSetBaseline, getName());
if (imaIgnoreSetBaseline == null) {
this.ignoreSets.clear();
} else {
this.ignoreSets.clear();
this.ignoreSets.add(imaIgnoreSetBaseline);
}
}
/**
* Replace the current <code>List</code> of ignore sets with a new
* <code>List</code>. Can be empty but cannot be null. The order of the
* <code>List</code> will be the order used for appraisal by the
* <code>TPMAppraiser</code>.
*
* @param newIgnoreSets list of <code>OptionalSetPolicy</code>'s to use as required
* sets, can be empty but not null
*/
public final void setIgnoreSets(final List<? extends ImaIgnoreSetBaseline> newIgnoreSets) {
if (newIgnoreSets == null) {
throw new PolicyException("cannot set ignore sets to null");
}
LOGGER.debug("setting new ignore sets for {}", getName());
this.ignoreSets.clear();
for (ImaIgnoreSetBaseline oSet : newIgnoreSets) {
this.ignoreSets.add(oSet);
}
}
/**
* Deprecated method to return the first ignore set in
* <code>this.ignoreSets</code>. Replaced by <code>getIgnoreSets</code>.
*
* @return the optional set policy representing the first ignore set, can be
* NULL
*/
public final ImaIgnoreSetBaseline getImaIgnoreSetBaseline() {
if (this.ignoreSets == null || this.ignoreSets.isEmpty()) {
return null;
}
return this.ignoreSets.get(0);
}
/**
* Return the current list of ignore sets.
*
* @return the unmodifiable list of ignore sets, which cannot be null
*/
public final List<ImaIgnoreSetBaseline> getIgnoreSets() {
return Collections.unmodifiableList(this.ignoreSets);
}
/**
* Set the IMA blacklists for this IMA policy.
*
* @param newBlacklists the blacklists to assign to this policy
*/
public final void setBlacklists(final List<ImaBlacklistBaseline> newBlacklists) {
if (newBlacklists == null) {
throw new PolicyException("Cannot set blacklists to null");
}
LOGGER.debug("setting new blacklists for {}: {}", getName(), newBlacklists);
blacklists.clear();
blacklists.addAll(newBlacklists);
}
/**
* Retrieve this policy's IMA blacklists.
*
* @return this policy's blacklists
*/
public final List<ImaBlacklistBaseline> getBlacklists() {
return Collections.unmodifiableList(this.blacklists);
}
/**
* Returns the policy on whether appraisal should fail if any unknown files
* are found. During the IMA appraisal process unknown files may be
* encountered. This boolean indicates if an appraisal should fail for any
* unknown files that are found.
*
* @return appraisal failure policy if any unknowns found
*/
public final boolean isFailOnUnknowns() {
return failOnUnknowns;
}
/**
* Set the policy on whether appraisal should fail if any unknown files
* are found. See {@link #isFailOnUnknowns()} for more details.
*
* @param failOnUnknowns appraisal failure policy if any unknowns found
*/
public final void setFailOnUnknowns(final boolean failOnUnknowns) {
LOGGER.debug("setting fail on unknowns policy to {}", failOnUnknowns);
this.failOnUnknowns = failOnUnknowns;
}
/**
* Returns a boolean as to whether or not the PCR hash should be validated.
* An IMA report that has a TPM enabled has a running hash stored in a TPM,
* typically PCR 10. If this is set to true then the running hash of the IMA
* report is regenerated during the appraisal process and compared to the
* PCR.
* <p>
* If this is enabled a <code>TPMReport</code> must be in the
* <code>IntegrityReport</code>.
*
* @return the validatePcr
*/
public final boolean isValidatePcr() {
return validatePcr;
}
/**
* Enable the validation of PCR hash. See {@link #isValidatePcr()} for a
* complete description of this property.
*
* @param validatePcr the validatePcr to set
*/
public final void setValidatePcr(final boolean validatePcr) {
LOGGER.debug("setting validate pcr policy to {}", validatePcr);
this.validatePcr = validatePcr;
}
/**
* Returns a boolean as to whether IMA reports are enabled for
* delta reports.
*
* @return deltaReportEnable
*/
public final boolean isDeltaReportEnable() {
return deltaReportEnable;
}
/**
* Set the indicator that determines if delta reports are enabled
* within a <code>IntegrityReport</code>.
*
* @param deltaReportEnable the flag for delta reports
*/
public final void setDeltaReportEnable(final boolean deltaReportEnable) {
LOGGER.debug("setting deltaReportEnable to {}", deltaReportEnable);
this.deltaReportEnable = deltaReportEnable;
}
@Override
public final List<Baseline> getBaselines() {
List<Baseline> baselines = new LinkedList<>();
baselines.addAll(getRequiredSets());
baselines.addAll(getWhitelists());
baselines.addAll(getBlacklists());
baselines.addAll(getIgnoreSets());
return baselines;
}
/**
* Checks whether partial path support is enabled or not for the whitelists,
* required sets, and ignore sets contained in this <code>Policy</code>.
* When partial path support is enabled the full file path for records and
* baselines is not used when calling
* <code>ImaBaseline#contains(IMAMeasurementRecord)</code>.
* Instead only the file name is used. For example, if a record has the file
* path "gradle" then its path will match against baseline records with the
* file paths "/usr/bin/gradle" and "/home/foo/bin/gradle."
* <p>
* This feature should be enabled when comparing against IMA reports from
* kernels that do not have the latest IMA code. The earlier IMA code did
* not always report the absolute file path for each record. This is true
* for CentOS versions prior to CentOS 7.
*
* @return partialPathEnable
*/
public final boolean isPartialPathEnable() {
return partialPathEnable;
}
/**
* Sets whether partial path support is enabled or not for the whitelists.
* See {@link #isPartialPathEnable()} for more details about the flag.
*
* @param partialPathEnable boolean determining whether partial paths are used
*/
public final void setPartialPathEnable(final boolean partialPathEnable) {
LOGGER.debug("setting partialPathEnable to {}", partialPathEnable);
this.partialPathEnable = partialPathEnable;
}
/**
* Returns a Multimap representing that paths that should be considered
* 'equivalent' while evaluating an IMA baseline contained by this policy.
* Equivalent paths are those which could potentially hold the same files, or links
* to those same files. For instance, on CentOS 7, /bin is symlinked to /usr/bin, so the
* IMA log may report equivalent entries at both /bin/file and /usr/bin/file.
* Creating a mapping between /bin/ and /usr/bin/ allows IMA appraisal to equate the
* two paths.
* <p>
* The map returned will have directories as keys, and those directories' equivalent
* directories as its collection of values. These relationships are bidirectional; that is,
* if a is equivalent to b and c, b is equivalent to a, and c is also equivalent to a.
*
* @return a Multimap relating equivalent directories as described above
*/
public final synchronized Multimap<String, String> getPathEquivalences() {
// if we've already set pathEquivalences, return it
if (pathEquivalences != null) {
return pathEquivalences;
}
Multimap<String, String> equivalentPaths = HashMultimap.create();
// define equivalences
equivalentPaths.put("/bin/", "/usr/bin/");
equivalentPaths.put("/lib/", "/usr/lib/");
equivalentPaths.put("/lib64/", "/usr/lib64/");
equivalentPaths.put("/usr/bin/", "/usr/sbin/");
equivalentPaths.put("/sbin/", "/usr/sbin/");
// populate inverse relationships
Multimap<String, String> bidirectionalEquivalences = HashMultimap.create();
for (Map.Entry<String, Collection<String>> equivalentPathPair
: equivalentPaths.asMap().entrySet()) {
String dir = equivalentPathPair.getKey();
Collection<String> equivalentDirs = equivalentPathPair.getValue();
bidirectionalEquivalences.putAll(dir, equivalentDirs);
for (String equivalentDir : equivalentDirs) {
bidirectionalEquivalences.put(equivalentDir, dir);
}
}
this.pathEquivalences = bidirectionalEquivalences;
return this.pathEquivalences;
}
}

View File

@ -1,306 +0,0 @@
package hirs.data.persist.alert;
/**
* The Alert Monitor holds configuration information about an individual remote monitor (a remote
* "Alert Manager") that is subscribing (monitoring) the HIRS alert service.
*/
import javax.persistence.Access;
import javax.persistence.AccessType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.Table;
import java.net.InetAddress;
import java.net.UnknownHostException;
/**
* Database Object representing the configuration of a remote Alert Monitor. The Alert Monitor
* configuration holds information about an individual remote monitor (a remote "Alert Manager")
* that is subscribing (monitoring) the HIRS alert service. The configuration allows for one alert
* to be sent for every event or one alert per report processed that encountered at least one event.
*/
@Entity
@Table(name = "AlertMonitor")
@Inheritance(strategy = InheritanceType.JOINED)
@Access(AccessType.FIELD)
public abstract class AlertMonitor {
/**
* ID assigned to the configuration.
*/
@Id
@Column
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column(unique = true, nullable = false)
private String name;
@Column
private InetAddress ipAddress;
@Column
private int port = 0;
@Column(name = "alertOnSummary")
private boolean alertOnSummaryEnabled = false;
@Column(name = "alertOnEvent")
private boolean individualAlertEnabled = false;
@Column
private String alertServiceType;
@Column
private boolean monitorEnabled;
/**
* Default constructor. Needed for Hibernate unit tests.
*/
protected AlertMonitor() {
// Do nothing
}
/**
* Creates an Alert Monitor.
*
* @param monitorName name assigned to this monitor.
*/
public AlertMonitor(final String monitorName) {
if (monitorName == null) {
throw new NullPointerException("AlertMonitor name not set");
}
name = monitorName;
}
/**
* Returns the persisted ID of the monitor.
*
* @return persistence ID of the monitor
*/
public final Long getId() {
return id;
}
/**
* Sets the FQDN of of the Alert Monitor.
*
* @param type Type of the AlertService
*/
public void setAlertServiceType(final String type) {
if (type == null) {
throw new NullPointerException("AlertMonitor type not set");
}
alertServiceType = type;
}
/**
* Returns the Type of the AlertService associated with the monitor.
*
* @return Type of the AlertService this monitor is associated with
*/
public final String getAlertServiceType() {
return alertServiceType;
}
/**
* Sets the name of the remote Manager.
*
* @param newName Name of the remote manager
*/
public final void setName(final String newName) {
if (newName == null) {
throw new NullPointerException("AlertMonitor name cannot be null");
}
name = newName;
}
/**
* Gets the name assigned to the remote alert manager.
*
* @return Name of the remote alert manager
*/
public final String getName() {
return name;
}
/**
* Sets the address of the remote alert manager.
*
* @param newip address assigned to the remote manager
*/
public final void setIpAddress(final InetAddress newip) {
ipAddress = newip;
}
/**
* Resolves, then sets the address of the remote alert manager.
*
* @param host address assigned to the remote manager
* @throws UnknownHostException For problems resolving or storing the host.
*/
public final void setIpAddress(final String host) throws UnknownHostException {
ipAddress = InetAddress.getByName(host);
}
/**
* Gets the IP assigned to the remote manager.
*
* @return IP of the remote manager
*/
public final InetAddress getIpAddress() {
return ipAddress;
}
/**
* Assign port of the remote alert manager.
*
* @param newport port assigned to the remote manager
*/
public final void setPort(final int newport) {
final int upperBound = 65535;
if (0 < newport && newport <= upperBound) {
port = newport;
} else {
throw new IllegalArgumentException("Failed to set monitor port. Provided number was"
+ " outside of valid range (1 - 65535)");
}
}
/**
* Gets port assigned to the remote manager.
*
* @return the port used by the remote manager
*/
public final int getPort() {
return port;
}
/**
* Returns the summary Alert enable setting.
* If true the Alert Manager will send one summary message per message that incurred an alert.
*
* @return true if Alert Monitor will send an alert upon an Alert Summary
*/
public final boolean isAlertOnSummaryEnabled() {
return this.alertOnSummaryEnabled;
}
/**
* Enables the Remote Alert Manager to send a summary of alerts per report.
* This does not effect the enableIndividualAlert method.
*/
public final void enableAlertOnSummary() {
alertOnSummaryEnabled = true;
}
/**
* Disables the Remote Alert Manager to send a summary of alerts per report.
* This does not effect the disableIndividualAlert method.
*/
public final void disableAlertOnSummary() {
alertOnSummaryEnabled = false;
}
/**
* Returns the individual Alert enable setting.
* If true the Alert Manager will send the remote alert manager one message per alert.
*
* @return Enable setting for the Remote Alert monitor
*/
public final boolean isIndividualAlertEnabled() {
return individualAlertEnabled;
}
/**
* Enables the Remote Alert Manager to send individual alerts.
* This could lead to hundreds of alerts per issued per report.
*/
public final void enableIndividualAlert() {
individualAlertEnabled = true;
}
/**
* Disables the Remote Alert Manager to send individual alerts.
*/
public final void disableIndividualAlert() {
individualAlertEnabled = false;
}
/**
* Enables AlertMonitor. This needs to be called in order for an Alert to be sent to the
* provided monitor.
*/
public final void enable() {
monitorEnabled = true;
}
/**
* Disables AlertMonitor. This will prevent Alerts from being forwarded to the supplied
* monitor.
*/
public final void disable() {
monitorEnabled = false;
}
/**
* Returns the enabled/disabled status of the monitor.
*
* @return the status of the monitor. True if enabled, false if disabled.
*/
public final boolean isMonitorEnabled() {
return monitorEnabled;
}
/**
* Returns a boolean if other is equal to this. <code>AlertMonitor</code>s are identified
* by their name, so this returns true if <code>other</code> is an instance of
* <code>AlertMonitor</code> and its name is the same as this <code>AlertMonitor</code>.
* Otherwise this returns false.
*
* @param other other object to test for equals
* @return true if other is <code>AlertMonitor</code> and has same name
*/
@Override
public final boolean equals(final Object other) {
if (this == other) {
return true;
}
if (!(other instanceof AlertMonitor)) {
return false;
}
final AlertMonitor config = (AlertMonitor) other;
return this.getName().equals(config.getName());
}
/**
* Returns a hash code for this <code>AlertMonitor</code>. <code>AlertMonitor</code>
* are identified by their name, so the returned hash is the hash of the name.
*
* @return hash
*/
@Override
public final int hashCode() {
return name.hashCode();
}
/**
* Returns a <code>String</code> representation of this class. This returns the
* <code>AlertMonitor</code> name.
*
* @return <code>AlertMonitor</code> name
*/
@Override
public final String toString() {
return this.name;
}
}

View File

@ -1,151 +0,0 @@
package hirs.data.persist.alert;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
/**
* The AlertServiceConfig holds persistent configuration data for the
* ManagedAlertService.
*/
@Entity
@Table(name = "AlertServiceConfig")
public class AlertServiceConfig {
@Id
@Column(name = "id", unique = true)
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column(name = "enabled")
private boolean enabled = false;
@Column
private String serviceIdentifier;
@Column(unique = true, nullable = false)
private String type;
/**
* Default constructor.
* Needed for Hibernate unit tests.
*/
protected AlertServiceConfig() {
// Do Nothing
}
/**
* Creates a new <code>AlertServiceConfig</code> that uses the default
* database. The default database is used to store all of the objects.
*
* @param serviceType type assigned to this alert service.
*/
public AlertServiceConfig(final String serviceType) {
if (serviceType == null) {
throw new NullPointerException("AlertServiceConfig name not set");
}
type = serviceType;
}
/**
* Enables the alert service.
*/
public final void enable() {
enabled = true;
}
/**
* Disables the alert service.
*/
public final void disable() {
enabled = false;
}
/**
* Gets enabled status (Alert Service state).
*
* @return True if the service is enabled, false if disabled
*/
public boolean isEnabled() {
return enabled;
}
/**
* Gets the type of the AlertService.
*
* @return Type of the service
*/
public final String getType() {
return type;
}
/**
* Gets the ID of the Alert Service.
*
* @return ID of the service
*/
public final String getServiceIdentifier() {
return serviceIdentifier;
}
/**
* Set the Identifier of the service.
*
* @param id
* Identifier to assign
*/
public final void setServiceIdentifier(final String id) {
serviceIdentifier = id;
}
/**
* Returns a hash code for this <code>Device</code>. The hash code is
* determined from the name of the <code>Device</code>.
*
* @return hash code
*/
@Override
public final int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + type.hashCode();
return result;
}
/**
* Tests whether <code>this</code> is equal to <code>obj</code>. This
* returns true if and only if the class of obj is equal to this class and
* the names are equal.
*
* @param obj other object to compare against
* @return equality
*/
@Override
public final boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof AlertServiceConfig)) {
return false;
}
AlertServiceConfig other = (AlertServiceConfig) obj;
return this.type.equals(other.type);
}
/**
* Returns a <code>String</code> representation of this class. This returns
* the <code>AlertMonitor</code> name.
*
* @return <code>Policy</code> name
*/
@Override
public final String toString() {
return type.toString();
}
}

View File

@ -1,94 +0,0 @@
package hirs.data.persist.alert;
import hirs.alert.JsonAlertService;
import javax.persistence.Access;
import javax.persistence.AccessType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.Table;
/**
* This configuration extends the generic AlertMonitor for JSON.
*/
@Entity
@Table(name = "JsonAlertMonitor")
@Access(AccessType.FIELD)
public class JsonAlertMonitor extends AlertMonitor {
/**
* The protocol used to send the JSON Alerts.
*/
public enum JsonAlertMode {
/**
* via TCP.
*/
TCP,
/**
* via UDP.
*/
UDP;
}
@Column
private JsonAlertMode mode;
/**
* Constructor.
*/
public JsonAlertMonitor() {
super();
}
/**
* Constructor.
*
* @param name - name of the monitor
*/
public JsonAlertMonitor(final String name) {
super(name);
setAlertServiceType(JsonAlertService.NAME);
setTCP();
disable();
}
/**
* Returns the <code>JsonAlertMode</code> of this <code>JsonAlertMonitor</code>.
* @return JsonAlertMode
*/
@Enumerated(EnumType.ORDINAL)
public JsonAlertMode getJsonAlertMode() {
return this.mode;
}
/**
* Returns true if this <code>JsonAlertMonitor</code> is configured to forward alerts via TCP.
* @return boolean
*/
public boolean isTCP() {
return this.mode == JsonAlertMode.TCP;
}
/**
* Set the mode to TCP.
*/
public void setTCP() {
this.mode = JsonAlertMode.TCP;
}
/**
* Returns true if this <code>JsonAlertMonitor</code> is configured to forward alerts via UDP.
* @return boolean
*/
public boolean isUDP() {
return this.mode == JsonAlertMode.UDP;
}
/**
* Set the mode to UDP.
*/
public void setUDP() {
this.mode = JsonAlertMode.UDP;
}
}

View File

@ -1,4 +0,0 @@
/**
* This package contains a set of classes for accessing alert service data.
*/
package hirs.data.persist.alert;

View File

@ -1,200 +0,0 @@
package hirs.data.persist.baseline;
import hirs.data.persist.Digest;
import hirs.data.persist.enums.DigestAlgorithm;
import hirs.data.persist.OptionalDigest;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import javax.persistence.Column;
import javax.persistence.Embedded;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
import javax.persistence.Transient;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Objects;
/**
* An <code>AbstractImaBaselineRecord</code> represents an entry in a baseline used
* during appraisal of a machine's IMA log. These records indicate paths
* and/or hashes that may be acceptable, ignored, or blacklisted, according
* to their uses.
* <p>
* Known extending classes include:
* - {@link IMABaselineRecord}
* - {@link ImaIgnoreSetRecord}
* - {@link ImaBlacklistRecord}
*/
@MappedSuperclass
public abstract class AbstractImaBaselineRecord {
private static final Logger LOGGER = LogManager.getLogger(AbstractImaBaselineRecord.class);
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.AUTO)
private final Long id;
/**
* Holds the name of the 'path' field.
*/
public static final String PATH_FIELD = "path";
@SuppressWarnings("checkstyle:magicnumber")
@Column(name = PATH_FIELD, nullable = true, length = 2048)
private final String path;
/**
* Holds the name of the 'hash' field.
*/
public static final String HASH_FIELD = "hash";
@Embedded
private final OptionalDigest hash;
@SuppressWarnings("checkstyle:magicnumber")
@Column(nullable = true, length = 255)
private final String description;
/**
* Creates a new <code>ImaBaseRecord</code>. Creates a new record and
* specifies all of the properties. All of the properties may be null
* except for path and hash.
*
* @param path
* file path
* @param hash
* file SHA-1 hash
* @param description
* a description for this baseline entry
* @throws IllegalArgumentException
* if digest algorithm is not SHA-1
*/
public AbstractImaBaselineRecord(final String path, final Digest hash, final String description)
throws IllegalArgumentException {
if (hash != null && hash.getAlgorithm() != DigestAlgorithm.SHA1) {
throw new IllegalArgumentException("Hash algorithm is not SHA-1");
}
this.id = null;
this.path = path;
if (path != null && StringUtils.isBlank(path)) {
throw new IllegalArgumentException("Path is blank");
}
if (hash != null) {
this.hash = hash.asOptionalDigest();
} else {
this.hash = null;
}
this.description = description;
}
/**
* Default constructor necessary for Hibernate.
*/
protected AbstractImaBaselineRecord() {
this.id = null;
this.path = null;
this.hash = null;
this.description = null;
}
/**
* Returns the database ID associated with this record. If this record has
* not been persisted in the database then this method will return null.
*
* @return ID of this record
*/
public final Long getId() {
return id;
}
/**
* Returns the path (including file name) of the IMA baseline record.
*
* @return file path of baseline record
*/
public String getPath() {
return path;
}
/**
* Returns the SHA1 hash of the file associated with IMA baseline record.
*
* @return hash of file associated with baseline record
*/
@Transient
public Digest getHash() {
if (hash != null) {
return hash.asDigest();
} else {
return null;
}
}
/**
* Get the partial path associated with this baseline record; may be null.
*
* @return the partial path associated with this baseline record; may be null.
*/
public String getPartialPath() {
if (path == null) {
return null;
}
return getPartialPath(path);
}
/**
* Returns the partial path (file name) of the given Path, represented by a string.
*
* @param path the path for which to generate a partial path
* @return file name
*/
public static String getPartialPath(final String path) {
if (path == null) {
throw new IllegalArgumentException("Cannot get partial path for null value");
}
Path filename = Paths.get(path).getFileName();
//should only be triggered if path is '/' directory
if (filename == null) {
LOGGER.error("Invalid filename from path: " + path);
return "";
}
return filename.toString();
}
/**
* Returns the description of the file associated with IMA ignore baseline record.
*
* @return hash of file associated with baseline record
*/
public final String getDescription() {
return this.description;
}
@Override
public final boolean equals(final Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
AbstractImaBaselineRecord that = (AbstractImaBaselineRecord) o;
return Objects.equals(path, that.path)
&& Objects.equals(hash, that.hash);
}
@Override
public final int hashCode() {
return Objects.hash(path, hash);
}
@Override
public final String toString() {
return String.format("(%s, %s)", path, hash);
}
}

View File

@ -1,83 +0,0 @@
package hirs.data.persist.baseline;
import hirs.data.persist.UserDefinedEntity;
import hirs.data.persist.enums.AlertSeverity;
import javax.persistence.Access;
import javax.persistence.AccessType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.Table;
/**
* A baseline (a.k.a. whitelist) contains a set of expected values for a
* measurement comparison. In the case of a TPM a baseline for that would
* contain the PCR IDs along with the expected hash values. This is similar for
* IMA.
* <p>
* The <code>Baseline</code> class represents a baseline. This is an abstract
* class for referencing <code>Baseline</code>s. A <code>Baseline</code> is
* identified by its name, so the name for a <code>Baseline</code> must be
* unique.
*/
@Entity
@Table(name = "Baseline")
@Inheritance(strategy = InheritanceType.JOINED)
@Access(AccessType.FIELD)
public abstract class Baseline extends UserDefinedEntity {
@Column(nullable = false, name = "severity")
@Enumerated(EnumType.STRING)
private AlertSeverity severity = AlertSeverity.UNSPECIFIED;
@Column(nullable = false)
private String type;
/**
* Creates a new <code>Baseline</code> with the specified name.
*
* @param name name
*/
public Baseline(final String name) {
super(name);
type = getClass().getSimpleName();
}
/**
* Default empty constructor is required for Hibernate. It is protected to
* prevent code from calling it directly.
*/
protected Baseline() {
super();
type = getClass().getSimpleName();
}
/**
* When baselines are serialized to be sent to the browser, this can be used
* to determine the type of baseline.
*
* @return The class name for the baseline
*/
public String getType() {
return this.type;
}
/**
* Gets the baseline severity.
* @return the severity
*/
public AlertSeverity getSeverity() {
return severity;
}
/**
* Sets the severity of alerts raised by this baseline.
* @param severity The desired severity of alerts raised by this baseline
*/
public void setSeverity(final AlertSeverity severity) {
this.severity = severity;
}
}

View File

@ -1,178 +0,0 @@
package hirs.data.persist.baseline;
import hirs.persist.RepositoryManager;
import hirs.repository.Repository;
import hirs.repository.RepoPackage;
import org.hibernate.Criteria;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.Access;
import javax.persistence.AccessType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.ManyToMany;
import javax.persistence.Transient;
/**
* An IMA baseline that references a set of <code>Repository</code> instances. Appraisals are done
* by using every package in each of the repositories as a baseline. An update() will synchronize
* the local packages to the measured contents of the repositories.
*
*/
@Entity
@Access(AccessType.FIELD)
public class BroadRepoImaBaseline extends QueryableRecordImaBaseline
implements UpdatableImaBaseline {
/**
* The repositories used for an appraisal against this baseline.
*/
@ManyToMany(fetch = FetchType.EAGER)
private Set<Repository<?>> repositories;
/**
* Name of the repoPackages field.
*/
public static final String REPO_PACKAGES_FIELD = "repoPackages";
/**
* The packages that have been extracted from this baseline's repositories.
*/
@ManyToMany(fetch = FetchType.EAGER)
private Set<RepoPackage> repoPackages;
@Transient
private final Set<IMABaselineRecord> cachedBaselineRecords = new HashSet<>();
@Transient
private boolean shouldUpdateCache = true;
/**
* Constructor used to initialize a <code>BroadRepoImaBaseline</code> with the given name and
* an empty <code>Set</code> of <code>Repository</code> instances and <code>RepoPackage</code>s.
*
* @param name the name of the new baseline
*/
public BroadRepoImaBaseline(final String name) {
super(name);
repositories = new HashSet<>();
repoPackages = new HashSet<>();
}
/** Default constructor necessary for Hibernate. Makes an empty <code>Set</code> of
* <code>Repository</code> instances and <code>RepoPackage</code>s.
*/
protected BroadRepoImaBaseline() {
super();
repositories = new HashSet<>();
repoPackages = new HashSet<>();
}
/**
* Update this baseline to match repositories that may have been updated. First clear the
* current <code>Set</code> of <code>RepoPackage</code>s, then iterate through the
* <code>Repository</code> objects referenced in this baseline and use all of the measured
* packages found within each of them to populate this baseline's <code>Set</code> of
* <code>RepoPackage</code>s.
*
* @param repositoryManager a repository manager to use to gather data about repositories, or
* null if object already contains all info (no lazy-loaded data)
*/
@Override
public final void update(final RepositoryManager repositoryManager) {
repoPackages.clear();
for (Repository<?> repository : repositories) {
Repository<?> repoWithPackages;
if (repositoryManager != null) {
repoWithPackages = repositoryManager.getRepository(repository.getId());
} else {
repoWithPackages = repository;
}
repoPackages.addAll(repoWithPackages.getPackages());
}
synchronized (cachedBaselineRecords) {
this.shouldUpdateCache = true;
}
}
@Override
public final Set<IMABaselineRecord> getBaselineRecords() {
synchronized (cachedBaselineRecords) {
if (!shouldUpdateCache) {
return Collections.unmodifiableSet(cachedBaselineRecords);
}
cachedBaselineRecords.clear();
for (RepoPackage repoPackage : repoPackages) {
cachedBaselineRecords.addAll(repoPackage.getPackageRecords());
}
shouldUpdateCache = false;
return Collections.unmodifiableSet(cachedBaselineRecords);
}
}
@Override
public void configureCriteriaForBaselineRecords(final Criteria criteria, final int bucket) {
criteria.add(Restrictions.eq("id", getId()))
.setProjection(Projections.projectionList()
.add(Projections.property(
String.format("%s.%s",
RepoPackage.PACKAGE_RECORDS_FIELD,
IMABaselineRecord.PATH_FIELD)
), IMABaselineRecord.PATH_FIELD)
.add(Projections.property(
String.format("%s.%s",
RepoPackage.PACKAGE_RECORDS_FIELD,
IMABaselineRecord.HASH_FIELD)
), IMABaselineRecord.HASH_FIELD)
);
criteria.add(Restrictions.eq(
String.format("%s.%s",
RepoPackage.PACKAGE_RECORDS_FIELD,
IMABaselineRecord.BUCKET_FIELD),
bucket)
);
criteria.createAlias(REPO_PACKAGES_FIELD, REPO_PACKAGES_FIELD);
criteria.createAlias(
String.format("%s.%s", REPO_PACKAGES_FIELD, RepoPackage.PACKAGE_RECORDS_FIELD),
RepoPackage.PACKAGE_RECORDS_FIELD
);
}
/**
* Get the <code>Set</code> of <code>RepoPackage</code>s associated with this baseline.
*
* @return the RepoPackages associated with this baseline
*/
public final Set<RepoPackage> getRepositoryPackages() {
return Collections.unmodifiableSet(repoPackages);
}
/**
* Get the <code>Set</code> of <code>Repository</code> instances associated with this baseline.
*
* @return the Repositories tracked by this baseline
*/
public final Set<Repository<?>> getRepositories() {
return Collections.unmodifiableSet(repositories);
}
/**
* Set the <code>Set</code> of <code>Repository</code> instances associated with this baseline.
* Note that the map update needed flags do not change here. They will only change during an
* update() because that is where the <code>RepoPackage</code>s change.
*
* @param newRepositories the new repositories to be tracked by this baseline
*/
public final void setRepositories(final Set<Repository<?>> newRepositories) {
repositories.clear();
repositories.addAll(newRepositories);
}
}

View File

@ -1,14 +0,0 @@
package hirs.data.persist.baseline;
import java.util.List;
/**
*
*/
public interface HasBaselines {
/**
* Convenience method for accessing related Baselines.
* @return Baselines related to this object
*/
List<Baseline> getBaselines();
}

View File

@ -1,176 +0,0 @@
package hirs.data.persist.baseline;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Index;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.persistence.Transient;
import com.google.common.base.Preconditions;
import hirs.data.persist.Digest;
/**
* An <code>IMABaselineRecord</code> represents a single entry in an
* {@link ImaAcceptableRecordBaseline}. These contain paths and hashes of expected
* entries in a machine's IMA log, and are used in the contexts of whitelists and required
* sets via ImaAcceptableRecordBaselines.
*/
@Entity
@Table(indexes = { @Index(columnList = "bucket") })
public class IMABaselineRecord extends AbstractImaBaselineRecord {
/**
* IMABaselineRecords are randomly assigned buckets based on a hash of their path. These
* bucket values are used to artificially segment the baseline into equal divisions for
* simultaneous multithreaded retrieval. This defines the number of distinct bucket values that
* will be used in this process.
*/
public static final int FILENAME_HASH_BUCKET_COUNT = 4;
/**
* Holds the name of the 'bucket' field.
*/
public static final String BUCKET_FIELD = "bucket";
@Column(name = BUCKET_FIELD, nullable = false)
private final int bucket;
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "ima_baseline_id")
private SimpleImaBaseline baseline;
@Transient
private static final Pattern RECORD_PATTERN = Pattern.compile("\\((.*), (.*)\\)");
/**
* Creates a new <code>IMABaselineRecord</code>.
* @param path
* file path of the record
* @param hash
* hash of the record
*/
public IMABaselineRecord(final String path, final Digest hash) {
super(path, hash, null);
Preconditions.checkNotNull(path, "Path cannot be null.");
Preconditions.checkNotNull(hash, "Hash cannot be null.");
this.bucket = getBucket(path);
}
/**
* Creates a new <code>IMABaselineRecord</code>. Creates a new record and
* specifies all of the properties. All of the properties may be null
* except for path and hash.
*
* @param path
* file path
* @param hash
* file SHA-1 hash
* @param baseline
* baseline assigned to the record (nullable)
* @throws IllegalArgumentException
* if digest algorithm is not SHA-1
*/
public IMABaselineRecord(final String path, final Digest hash, final SimpleImaBaseline baseline)
throws IllegalArgumentException {
this(path, hash);
setBaselineForRecordManager(baseline);
}
/**
* Returns the 'bucket' of the given path (based on its hash).
*
* @param path the path to hash
* @return the hash of the path
*/
private static int getBucket(final String path) {
if (path == null) {
throw new IllegalArgumentException("Cannot get bucket for null value");
}
return Math.abs(getPartialPath(path).hashCode()) % FILENAME_HASH_BUCKET_COUNT;
}
/**
* Default constructor necessary for Hibernate.
*/
protected IMABaselineRecord() {
super();
this.bucket = 0;
}
/**
* This gets the baseline.
*
* @return Baseline
*/
public final ImaBaseline getBaseline() {
return baseline;
}
/**
* Sets the given baseline.
*
* @param baseline baseline that matches the given baseline
*/
public final void setBaseline(final SimpleImaBaseline baseline) {
setOnlyBaseline(baseline);
if (baseline != null) {
baseline.addOnlyToBaseline(this);
}
}
/**
* Sets the baseline for this record.
*
* @param baseline
* baseline or null
*/
final void setOnlyBaseline(final SimpleImaBaseline baseline) {
if (this.baseline != null && baseline != null) {
this.baseline.removeOnlyBaseline(this);
}
this.baseline = baseline;
}
/**
* This method is to be used strictly for when the record is being added or modified by the
* <code>ImaBaselineRecordManager</code>. The methods
* {@link #setBaseline(hirs.data.persist.SimpleImaBaseline)} and {@link
* #setOnlyBaseline(hirs.data.persist.SimpleImaBaseline)} will still need to exist for
* use with the <code>BaselineManager</code>
*
* @param baseline
* SimpleImaBaseline that will be set and persisted by the
* <code>ImaBaselineRecordManager</code>
*/
public final void setBaselineForRecordManager(final SimpleImaBaseline baseline) {
this.baseline = baseline;
}
/**
* Reverses the toString operation. Throws an IllegalArgumentException if an invalid String is
* passed in
*
* @param record
* String representation of the IMABaselineRecord
* @return IMABaselineRecord
*/
public static IMABaselineRecord fromString(final String record) {
Matcher m = RECORD_PATTERN.matcher(record);
m.matches();
if (m.groupCount() != 2) {
String msg = String.format("Unexpected number of groups found with pattern \"%s\" "
+ "on string \"%s\"", RECORD_PATTERN.toString(), record);
throw new IllegalArgumentException(msg);
}
String path = m.group(1);
String digestString = m.group(2);
Digest digest = Digest.fromString(digestString);
return new IMABaselineRecord(path, digest);
}
}

View File

@ -1,90 +0,0 @@
package hirs.data.persist.baseline;
import com.fasterxml.jackson.annotation.JsonIgnore;
import hirs.data.persist.IMAMeasurementRecord;
import hirs.data.persist.IMAPolicy;
import hirs.ima.matching.BatchImaMatchStatus;
import hirs.persist.ImaBaselineRecordManager;
import javax.persistence.Entity;
import java.util.Collection;
import java.util.Set;
/**
* Base class for all {@link ImaBaseline}s which contain data representing 'acceptable'
* IMA baseline entries in the form of {@link IMABaselineRecord}s. Used in the roles
* of whitelists and required sets in {@link IMAPolicy}.
*/
@Entity
public abstract class ImaAcceptableRecordBaseline extends ImaBaseline<IMABaselineRecord> {
/**
* Creates a new ImaAcceptableRecordBaseline with the given name.
*
* @param name a name used to uniquely identify and reference the IMA baseline
*/
public ImaAcceptableRecordBaseline(final String name) {
super(name);
}
/**
* Default constructor necessary for Hibernate.
*/
protected ImaAcceptableRecordBaseline() {
}
/**
* Similar to contains, but only considers the hash value and does not consider
* the path as relevant to matching at all.
*
* Each type of baseline specifies its own
* 'contains' algorithm for deciding whether the given measurements are
* considered as matches, mismatches, or unknowns to the baseline. The 'contains' method
* of ImaAcceptableRecordBaselines that is normally used to judge measurement records
* against baseline records considers both paths and hashes; this method offers an
* additional mechanism for finding matching baseline records solely based
* on matching hash values.
*
* @param records
* measurement records to find in this baseline
* @param recordManager
* an ImaBaselineRecordManager that can be used to retrieve persisted records
* @param imaPolicy
* the IMA policy to use while determining if a baseline contains the given records
*
* @return batch match status for the measurement records, according only to hashes
*/
@JsonIgnore
public abstract BatchImaMatchStatus<IMABaselineRecord> containsHashes(
Collection<IMAMeasurementRecord> records,
ImaBaselineRecordManager recordManager,
IMAPolicy imaPolicy
);
/**
* Returns an unmodifiable set of IMA baseline records found in the IMA
* baseline. The returned set only contains the baseline records from this
* baseline.
*
* @return list of IMA records
*/
@JsonIgnore
public abstract Set<IMABaselineRecord> getBaselineRecords();
/**
* Retrieve the {@link IMABaselineRecord}s from this baseline that are not contained
* in the given set of records. In other words, the returned set is the relative complement of
* the given records in {@link IMABaselineRecord}s.
*
* @param recordManager
* an ImaBaselineRecordManager that can be used to retrieve persisted records
* @param foundRecords
* the records that shall not be included in the returned set
* @return all of the baseline's records except the set of given records
*/
@JsonIgnore
public abstract Collection<IMABaselineRecord> getRecordsExcept(
ImaBaselineRecordManager recordManager,
Set<IMABaselineRecord> foundRecords
);
}

View File

@ -1,114 +0,0 @@
package hirs.data.persist.baseline;
import hirs.data.persist.IMAMeasurementRecord;
import hirs.data.persist.IMAPolicy;
import hirs.ima.matching.BatchImaMatchStatus;
import hirs.persist.ImaBaselineRecordManager;
import org.hibernate.annotations.Type;
import javax.persistence.Access;
import javax.persistence.AccessType;
import javax.persistence.Column;
import javax.persistence.Entity;
import java.util.Collection;
import java.util.Date;
/**
* Class represents the basic functionality of an IMA baseline: determining whether a baseline
* 'contains' {@link IMAMeasurementRecord}s that were collected from a machine's IMA log.
* Extending classes represent different ways to assemble and manipulate these baselines. See
* {@link SimpleImaBaseline} for an example of a baseline with records that can be manually
* added and removed.
*
* @param <T> the type of record that this baseline holds
*/
@Entity
@Access(AccessType.FIELD)
public abstract class ImaBaseline<T extends AbstractImaBaselineRecord> extends Baseline {
@Column
@Type(type = "timestamp")
private Date date;
/**
* Creates a new ImaBaseline with the given name.
*
* @param name a name used to uniquely identify and reference the IMA baseline
*/
public ImaBaseline(final String name) {
super(name);
date = new Date();
}
/**
* Default constructor necessary for Hibernate.
*/
protected ImaBaseline() {
super();
date = new Date();
}
/**
* Tests whether the record is found in the baseline. This returns a
* <code>ReportMatchStatus</code> representing the result of the search for
* the record. The returns conditions are as follows:
* <ul>
* <li>MATCH - if an <code>IMABaselineRecord</code> is found with a matching
* path and hash</li>
* <li>MISMATCH - if at least one <code>IMABaselineRecord</code> is found
* with a matching path but none with a matching path and hash</li>
* <li>UNKNOWN - if no <code>IMABaselineRecord</code>s found with a matching
* path</li>
* </ul>
* <p>
* If partial paths are enabled, records not starting with '/' are compared
* against all baseline records not starting with '/' and the last segment
* (the filename after the last '/') of each full path baseline record.
* Records starting with '/' are compared against all full path baseline
* records and the last segment of the record is compared against all
* partial path baseline records.
* <p>
* If partial paths are disabled, records are only compared using the full
* path of the baseline record and the report record.
*
* @param records
* measurement records to find in this baseline
* @param recordManager
* an ImaBaselineRecordManager that can be used to retrieve persisted records
* @param imaPolicy
* the IMA policy to use while determining if a baseline contains the given records
*
* @return batch match status for the measurement records
*/
public abstract BatchImaMatchStatus<T> contains(
Collection<IMAMeasurementRecord> records,
ImaBaselineRecordManager recordManager,
IMAPolicy imaPolicy
);
/**
* Set this <code>IMABaselines</code>'s <code>date</code>, which can either
* be the date that it was added, or some other date such as the patch date
* this baseline is associated with.
*
* @param newDate
* the new date to set, can be null
*/
public final void setDate(final Date newDate) {
if (newDate == null) {
this.date = null;
} else {
this.date = new Date(newDate.getTime());
}
}
/**
* Get this <code>IMABaselines</code>'s <code>date</code>, which can either
* be the date that it was added, or some other date such as the patch date
* this baseline is associated with.
*
* @return this baseline's date, can be null
*/
public final Date getDate() {
return new Date(date.getTime());
}
}

View File

@ -1,107 +0,0 @@
package hirs.data.persist.baseline;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.google.common.base.Preconditions;
import hirs.data.persist.IMAMeasurementRecord;
import hirs.data.persist.IMAPolicy;
import hirs.data.persist.ImaBlacklistRecord;
import hirs.ima.matching.BatchImaMatchStatus;
import hirs.ima.matching.ImaBlacklistRecordMatcher;
import hirs.persist.ImaBaselineRecordManager;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.OneToMany;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Set;
/**
* This class holds baseline records that represent known undesirable
* facts, such as the existence of an IMA log entry with a certain
* filename, or a certain hash, or both.
*/
@Entity
public class ImaBlacklistBaseline extends ImaBaseline<ImaBlacklistRecord> {
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER,
orphanRemoval = true, mappedBy = "baseline")
@JsonIgnore
private Set<ImaBlacklistRecord> imaBlacklistRecords;
/**
* Construct a new ImaBlacklistBaseline.
*
* @param name the name of the new baseline
*/
public ImaBlacklistBaseline(final String name) {
super(name);
imaBlacklistRecords = new LinkedHashSet<>();
}
/**
* Default constructor necessary for Hibernate.
*/
protected ImaBlacklistBaseline() {
super();
imaBlacklistRecords = null;
}
@Override
public BatchImaMatchStatus<ImaBlacklistRecord> contains(
final Collection<IMAMeasurementRecord> records,
final ImaBaselineRecordManager recordManager,
final IMAPolicy imaPolicy) {
Preconditions.checkArgument(records != null, "Records cannot be null");
Preconditions.checkArgument(imaPolicy != null, "IMA policy cannot be null");
return new ImaBlacklistRecordMatcher(imaBlacklistRecords, imaPolicy, this)
.batchMatch(records);
}
/**
* Adds an {@link ImaBlacklistRecord} to this baseline.
*
* @param record the record to add to this baseline
* @return true if the record was added to this baseline; false otherwise
*/
public final boolean addToBaseline(final ImaBlacklistRecord record) {
record.setBaseline(this);
return imaBlacklistRecords.add(record);
}
/**
* Removes an {@link ImaBlacklistRecord} to this baseline.
*
* @param record the record to remove from this baseline
* @return true if the record was removed from this baseline; false otherwise
*/
public final boolean removeFromBaseline(final ImaBlacklistRecord record) {
record.setBaseline(null);
return imaBlacklistRecords.remove(record);
}
/**
* Associates the given records with this baseline.
*
* @param records the records that the baseline should contain
*/
public final void setBaselineRecords(final Set<ImaBlacklistRecord> records) {
Preconditions.checkNotNull(records);
imaBlacklistRecords.clear();
imaBlacklistRecords.addAll(records);
for (ImaBlacklistRecord record : records) {
record.setBaseline(this);
}
}
/**
* Returns the set of blacklist records in this baseline.
*
* @return the set of blacklist records contained in this baseline
*/
@JsonIgnore
public final Set<ImaBlacklistRecord> getRecords() {
return Collections.unmodifiableSet(imaBlacklistRecords);
}
}

View File

@ -1,236 +0,0 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package hirs.data.persist.baseline;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.google.common.base.Preconditions;
import hirs.data.persist.IMAMeasurementRecord;
import hirs.data.persist.IMAPolicy;
import hirs.data.persist.ImaIgnoreSetRecord;
import hirs.ima.matching.BatchImaMatchStatus;
import hirs.ima.matching.ImaIgnoreSetRecordMatcher;
import hirs.persist.ImaBaselineRecordManager;
import hirs.utils.RegexFilePathMatcher;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.Access;
import javax.persistence.AccessType;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.OneToMany;
import static org.apache.logging.log4j.LogManager.getLogger;
import org.apache.logging.log4j.Logger;
/**
* This class holds baseline records that indicate which measurements should
* be ignored in an IMA measurement log, as determined by their paths.
*/
@Entity
@Access(AccessType.FIELD)
public class ImaIgnoreSetBaseline extends ImaBaseline<ImaIgnoreSetRecord> {
private static final Logger LOGGER = getLogger(ImaIgnoreSetBaseline.class);
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER,
orphanRemoval = true, mappedBy = "baseline")
@Access(AccessType.PROPERTY)
@JsonIgnore
private Set<ImaIgnoreSetRecord> imaIgnoreSetRecords;
/**
* Constructor used to initialize ImaIgnoreSetBaseline object. Makes an empty
* <code>Set</code> of Strings and passes up the user provided name.
*
* @param name
* a name used to uniquely identify and reference the IMA ignore set
*/
public ImaIgnoreSetBaseline(final String name) {
super(name);
imaIgnoreSetRecords = new HashSet<>();
}
/**
* Default constructor necessary for Hibernate. Makes an empty
* <code>Set</code> of Strings and passes up the user provided name.
*/
protected ImaIgnoreSetBaseline() {
super();
imaIgnoreSetRecords = new HashSet<>();
}
/**
* Adds an IMA ignore set record to this ignore set baseline. If the record is not already in
* the list, it is added. If the record already exists in the list, then this method will
* quietly ignore the request because it already exists in the list.
*
* @param record
* ignore set record to be added to the ignore set
* @return
* returns true if record was added to the baseline, false if it wasn't
*
* @throws IllegalArgumentException if the new record has a malformed matcher pattern
*/
public final boolean addToBaseline(final ImaIgnoreSetRecord record)
throws IllegalArgumentException {
validateMatcherPattern(record.getPath());
record.setOnlyBaseline(this);
return addOnlyToBaseline(record);
}
/**
* Checks whether or not the given ignore record path can be used as a valid pattern according
* to this ignore set's matcher.
*
* @throws IllegalArgumentException if an ignore set record has a path that cannot be used as a
* valid pattern by this ignore set's matcher
*/
private void validateMatcherPattern(final String ignoreRecordPattern)
throws IllegalArgumentException {
// the exception will be thrown here if a pattern cannot be added to the matcher
RegexFilePathMatcher matcher = new RegexFilePathMatcher("default pattern");
matcher.setPatterns(ignoreRecordPattern);
}
/**
* Remove IMA Ignore Set record from baseline.
*
* @param record
* to remove from baseline
* @return a boolean indicated whether or not the ima ignore record was
* successfully removed from the list.
*/
public final boolean removeFromBaseline(final ImaIgnoreSetRecord record) {
LOGGER.debug("removing record {} from baseline {}", record, getName());
if (record == null) {
LOGGER.error("null record");
return false;
}
boolean retVal = imaIgnoreSetRecords.remove(record);
if (retVal) {
record.setBaseline(null);
}
LOGGER.debug("record removed: {}", record);
return retVal;
}
/**
* Returns a BatchImaMatchStatus indicating, for each of the given records, whether a matching
* entry is contained in this ignore set baseline. The match status will be MATCH if one
* of the following cases applies:
*
* <p>&nbsp;
* <ul>
* <li>if any of of the ignore set records contain a regex that matches the given path</li>
* <li>if any of of the ignore set records are an exact match with the given path</li>
* <li>if any of of the ignore set records are the initial substring of the given path</li>
* <li>if any of of the ignore set records are partial paths and the given path is a full path
* with the same filename</li>
* <li>if the given path is a partial path and any of of the ignore set records are full paths
* with the same filename</li>
* </ul>
*
* Otherwise, a record's match status will be UNKNOWN.
*
* @param records
* measurement records to find in this baseline
* @param recordManager
* an ImaBaselineRecordManager that can be used to retrieve persisted records
* @param imaPolicy
* the IMA policy to use while determining if a baseline contains the given records
*
* @return a BatchImaMatchStatus containing the match status for the given records
*/
public final BatchImaMatchStatus<ImaIgnoreSetRecord> contains(
final Collection<IMAMeasurementRecord> records,
final ImaBaselineRecordManager recordManager,
final IMAPolicy imaPolicy
) {
Preconditions.checkArgument(records != null, "Records cannot be null");
Preconditions.checkArgument(imaPolicy != null, "IMA policy cannot be null");
return new ImaIgnoreSetRecordMatcher(imaIgnoreSetRecords, imaPolicy, this)
.batchMatch(records);
}
/**
* Returns the set of file paths in this IMA Ignore Set in this Baseline.
*
* @return list of optional measurement records representing optional list
*/
@JsonIgnore
public final synchronized Set<ImaIgnoreSetRecord> getImaIgnoreRecords() {
return Collections.unmodifiableSet(imaIgnoreSetRecords);
}
/**
* Returns the actual <code>Set</code> that contains the IMA records. Needed for
* Hibernate due to the AccessType.FIELD configuration on the IMA baseline classes.
*
* @return IMA ignore set records
*/
private Set<ImaIgnoreSetRecord> getImaIgnoreSetRecords() {
return imaIgnoreSetRecords;
}
/**
* Sets the IMA Ignore records. Needed for Hibernate due to the AccessType.FIELD
* configuration on the IMA baseline classes.
*
* @param imaIgnoreSetRecords IMA ignore set records to set
*/
private void setImaIgnoreSetRecords(final Set<ImaIgnoreSetRecord> imaIgnoreSetRecords) {
this.imaIgnoreSetRecords = imaIgnoreSetRecords;
}
/**
* Adds an IMA ignore record to this IMA ignore baseline. If the record does not exist
* then it is added. If an equal record exists, based upon
* {@link ImaIgnoreSetRecord#equals(Object)}, then this method quietly ignores the
* request to add the record because one already exists in the baseline.
*
* @param record
* record to add to baseline
* @return
* returns true is the record was added to the list, false if not
*/
public final synchronized boolean addOnlyToBaseline(final ImaIgnoreSetRecord record) {
if (record == null) {
LOGGER.error("invalid parameter (NULL value) "
+ "passed to ImaIgnoreSetBaseline.addOnlyToBaseline");
throw new IllegalArgumentException("null ignore set record");
}
if (imaIgnoreSetRecords.add(record)) {
LOGGER.info("added file path " + record.getPath()
+ " to ImaIgnoreSetBaseline " + getName());
} else {
LOGGER.info("file path" + record.getPath()
+ " already added to ImaIgnoreSetBaseline " + getName());
return false;
}
return true;
}
/**
* Remove IMA Ignore record from the baseline.
*
* @param record
* record to remove
* @return a boolean indicating if the removal was successful
*/
public final boolean removeOnlyBaseline(final ImaIgnoreSetRecord record) {
return imaIgnoreSetRecords.remove(record);
}
}

View File

@ -1,156 +0,0 @@
package hirs.data.persist.baseline;
import com.google.common.base.Preconditions;
import hirs.data.persist.Digest;
import hirs.data.persist.IMAMeasurementRecord;
import hirs.data.persist.IMAPolicy;
import hirs.ima.matching.BatchImaMatchStatus;
import hirs.ima.matching.IMAMatchStatus;
import hirs.ima.matching.ImaAcceptableHashRecordMatcher;
import hirs.ima.matching.ImaAcceptablePathAndHashRecordMatcher;
import hirs.ima.matching.ImaRecordMatcher;
import hirs.persist.ImaBaselineRecordManager;
import hirs.utils.Callback;
import org.hibernate.Criteria;
import java.util.Collection;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
/**
* This class defines the basis of operation for a baseline that supports querying
* a persistence layer for its component {@link IMABaselineRecord}s. A QueryableRecordImaBaseline
* uses this functionality to implement its <code>contains</code> method.
*/
public abstract class QueryableRecordImaBaseline extends ImaAcceptableRecordBaseline {
/**
* Constructor used to initialize an <code>QueryableRecordImaBaseline</code> with a name.
*
* @param name the name of the new baseline
*/
public QueryableRecordImaBaseline(final String name) {
super(name);
}
/**
* Default constructor necessary for Hibernate.
*/
protected QueryableRecordImaBaseline() {
super();
}
/**
* Check membership of the given {@link IMAMeasurementRecord}s in this baseline.
*
* @param records the records to attempt to match
* @param recordManager the {@link ImaBaselineRecordManager} to query
* @param imaPolicy the IMA policy to use while determining if a baseline contains the records
*
* @return a collection of {@link IMAMatchStatus}es reflecting the results
*/
@Override
public final BatchImaMatchStatus<IMABaselineRecord> contains(
final Collection<IMAMeasurementRecord> records,
final ImaBaselineRecordManager recordManager,
final IMAPolicy imaPolicy) {
Preconditions.checkArgument(records != null, "records cannot be null");
Preconditions.checkArgument(recordManager != null, "record manager cannot be null");
final Collection<String> pathsToFind = new HashSet<>();
for (IMAMeasurementRecord record : records) {
if (record != null) {
pathsToFind.addAll(ImaRecordMatcher.getMatchingPaths(imaPolicy, record.getPath()));
}
}
Collection<IMABaselineRecord> retrievedRecords = recordManager.iterateOverBaselineRecords(
this, new Callback<IMABaselineRecord, IMABaselineRecord>() {
@Override
public IMABaselineRecord call(final IMABaselineRecord baselineRecord) {
if (pathsToFind.contains(baselineRecord.getPath())) {
return baselineRecord;
} else if (imaPolicy.isPartialPathEnable()
&& pathsToFind.contains(baselineRecord.getPartialPath())) {
return baselineRecord;
}
return null;
}
});
return new ImaAcceptablePathAndHashRecordMatcher(retrievedRecords, imaPolicy, this)
.batchMatch(records);
}
/**
* Check membership of the given {@link IMAMeasurementRecord}s in this baseline.
*
* @param records the records to attempt to match
* @param recordManager the {@link ImaBaselineRecordManager} to query
* @param imaPolicy the IMA policy to use while determining if a baseline contains the records
*
* @return a collection of {@link IMAMatchStatus}es reflecting the results
*/
@Override
public final BatchImaMatchStatus<IMABaselineRecord> containsHashes(
final Collection<IMAMeasurementRecord> records,
final ImaBaselineRecordManager recordManager,
final IMAPolicy imaPolicy) {
Preconditions.checkArgument(records != null, "records cannot be null");
Preconditions.checkArgument(recordManager != null, "record manager cannot be null");
final Set<Digest> hashesToFind = records.stream()
.filter(Objects::nonNull)
.map(IMAMeasurementRecord::getHash)
.collect(Collectors.toSet());
Collection<IMABaselineRecord> retrievedRecords = recordManager.iterateOverBaselineRecords(
this, new Callback<IMABaselineRecord, IMABaselineRecord>() {
@Override
public IMABaselineRecord call(final IMABaselineRecord baselineRecord) {
if (hashesToFind.contains(baselineRecord.getHash())) {
return baselineRecord;
}
return null;
}
});
return new ImaAcceptableHashRecordMatcher(retrievedRecords, imaPolicy, this)
.batchMatch(records);
}
@Override
public final Collection<IMABaselineRecord> getRecordsExcept(
final ImaBaselineRecordManager recordManager,
final Set<IMABaselineRecord> foundRecords) {
if (foundRecords == null) {
throw new IllegalArgumentException("foundRecords cannot be null");
}
if (recordManager == null) {
throw new IllegalArgumentException("ImaBaselineRecordManager cannot be null");
}
return recordManager.iterateOverBaselineRecords(
this, new Callback<IMABaselineRecord, IMABaselineRecord>() {
@Override
public IMABaselineRecord call(final IMABaselineRecord param) {
if (!foundRecords.contains(param)) {
return param;
}
return null;
}
});
}
/**
* This method configures the provided criteria to retrieve all of its component
* {@link IMABaselineRecord}s. The given bucket should be used by the receiving code
* to only retrieve {@link IMABaselineRecord}s that are in the given bucket.
*
* @param criteria the criteria to configure
* @param bucket the bucket that should be configured on the criteria
*/
public abstract void configureCriteriaForBaselineRecords(Criteria criteria, int bucket);
}

View File

@ -1,308 +0,0 @@
package hirs.data.persist.baseline;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.google.common.base.Preconditions;
import hirs.data.persist.IMAMeasurementRecord;
import hirs.data.persist.IMAPolicy;
import hirs.ima.matching.BatchImaMatchStatus;
import hirs.ima.matching.ImaAcceptableHashRecordMatcher;
import hirs.ima.matching.ImaAcceptablePathAndHashRecordMatcher;
import hirs.persist.ImaBaselineRecordManager;
import org.apache.logging.log4j.Logger;
import javax.persistence.Access;
import javax.persistence.AccessType;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.OneToMany;
import java.net.URL;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
import static org.apache.logging.log4j.LogManager.getLogger;
/**
* Class represents a simple, flexible IMA measurement baseline. A baseline contains one or more
* IMA records. A baseline is used to define a collection of approved files that
* may be accessed or executed on an IMA supported computing platform. Each IMA
* record contains information pertaining to a specific file including file name
* and path, file hash, and other file attributes.
* <p>
* An IMA record can be either a full path record or a partial path record. Both
* types can always be added to a baseline, but when a baseline is checked using
* the contains() method, a parameter is passed in to determine whether or not
* partial path records can be considered.
* <p>
* NOTE: This class is not thread-safe.
*/
@Entity
@Access(AccessType.FIELD)
public class SimpleImaBaseline extends ImaAcceptableRecordBaseline {
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER,
orphanRemoval = true, mappedBy = "baseline")
@Access(AccessType.PROPERTY)
@JsonIgnore
private Set<IMABaselineRecord> imaRecords;
@Column(nullable = true)
private URL yumRepoURL;
private static final Logger LOGGER = getLogger(ImaBaseline.class);
/**
* Constructor used to initialize ImaBaseline object. Partial path support
* is not enabled by default. Makes an empty <code>Set</code> of
* <code>IMABaselineRecord</code>s and initializes the date to the current
* date.
*
* @param name
* a name used to uniquely identify and reference the IMA
* baseline
*/
public SimpleImaBaseline(final String name) {
super(name);
imaRecords = new LinkedHashSet<>();
}
/**
* Constructor used to initialize an ImaBaseline object with a link to a Yum repository.
*
* @param name the name for this ImaBaseline
* @param yumRepoURL the base URL of the repository from which to add package measurements
*/
public SimpleImaBaseline(final String name, final URL yumRepoURL) {
this(name);
this.yumRepoURL = yumRepoURL;
}
/**
* Default constructor necessary for Hibernate and BaselineAlertResolver. Makes an empty
* <code>Set</code> of <code>IMABaselineRecord</code>s.
*/
public SimpleImaBaseline() {
super();
imaRecords = new LinkedHashSet<>();
}
/**
* Returns an unmodifiable set of IMA baseline records found in the IMA
* baseline. The returned set only contains the baseline records from this
* baseline.
*
* @return list of IMA records
*/
public final synchronized Set<IMABaselineRecord> getBaselineRecords() {
return Collections.unmodifiableSet(imaRecords);
}
/**
* Adds a record to this baseline. If the record is not already part of the baseline,
* then it is added. If an equal record is already part of the baseline, then the
* request to add the record will be quietly ignored. This method also sets
* <code>Baseline</code> field on the <code>IMABaselineRecord</code>.
*
* @param record
* record to add to the baseline
* @return
* returns true if record was added to the baseline, false if it wasn't
*/
public final boolean addToBaseline(final IMABaselineRecord record) {
record.setOnlyBaseline(this);
return addOnlyToBaseline(record);
}
/**
* Remove IMA record from baseline.
*
* @param record
* to remove from baseline
* @return a boolean indicated whether or not the ima record was
* successfully removed from the list.
*/
public final boolean removeFromBaseline(final IMABaselineRecord record) {
LOGGER.debug("removing record {} from baseline {}", record, getName());
if (record == null) {
LOGGER.error("null record");
return false;
}
boolean retVal = imaRecords.remove(record);
if (retVal) {
record.setBaseline(null);
}
LOGGER.debug("record removed: {}", record);
return retVal;
}
/**
* Tests whether a collection of records are found in the baseline. This returns a
* <code>BatchImaMatchStatus</code> representing the result of the search for
* the records, which is itself a mapping of IMAMeasurementRecords to IMAMatchStatuses.
* IMAMatchStatus conditions are as follows:
* <ul>
* <li>MATCH - if an <code>IMABaselineRecord</code> is found with a matching
* path and hash</li>
* <li>MISMATCH - if at least one <code>IMABaselineRecord</code> is found
* with a matching path but none with a matching path and hash</li>
* <li>UNKNOWN - if no <code>IMABaselineRecord</code>s found with a matching
* path</li>
* </ul>
* <p>
* If partial paths are enabled, records not starting with '/' are compared
* against all baseline records not starting with '/' and the last segment
* (the filename after the last '/') of each full path baseline record.
* Records starting with '/' are compared against all full path baseline
* records and the last segment of the record is compared against all
* partial path baseline records.
* <p>
* If partial paths are disabled, records are only compared using the full
* path of the baseline record and the report record.
*
* @param records
* measurement records
* @param recordManager
* an ImaBaselineRecordManager that can be used to retrieve persisted records
* @param imaPolicy
* the IMA policy to use while determining if a baseline contains the records
* @return search status for the measurement record
*/
@Override
public final BatchImaMatchStatus<IMABaselineRecord> contains(
final Collection<IMAMeasurementRecord> records,
final ImaBaselineRecordManager recordManager,
final IMAPolicy imaPolicy) {
Preconditions.checkArgument(records != null, "Records cannot be null");
Preconditions.checkArgument(imaPolicy != null, "IMA policy cannot be null");
return new ImaAcceptablePathAndHashRecordMatcher(imaRecords, imaPolicy, this)
.batchMatch(records);
}
@Override
public BatchImaMatchStatus<IMABaselineRecord> containsHashes(
final Collection<IMAMeasurementRecord> records,
final ImaBaselineRecordManager recordManager,
final IMAPolicy imaPolicy) {
Preconditions.checkArgument(records != null, "Records cannot be null");
Preconditions.checkArgument(imaPolicy != null, "IMA policy cannot be null");
return new ImaAcceptableHashRecordMatcher(imaRecords, imaPolicy, this)
.batchMatch(records);
}
@Override
public Collection<IMABaselineRecord> getRecordsExcept(
final ImaBaselineRecordManager recordManager,
final Set<IMABaselineRecord> foundRecords) {
if (foundRecords == null) {
throw new IllegalArgumentException("foundRecords cannot be null");
}
if (recordManager == null) {
throw new IllegalArgumentException("ImaBaselineRecordManager cannot be null");
}
Set<IMABaselineRecord> leftover = new HashSet<>();
leftover.addAll(imaRecords);
leftover.removeAll(foundRecords);
return leftover;
}
/**
* Set the Yum Repo URL.
*
* @param yumRepoURL a URL to the yum repository that measurements will be gathered from
*/
public final void setYumRepoURL(final URL yumRepoURL) {
this.yumRepoURL = yumRepoURL;
}
/**
* Retrieve the Yum Repo URL.
*
* @return the Yum repository URL
*/
public final URL getYumRepoURL() {
return yumRepoURL;
}
/**
* Adds an IMA record to this IMA baseline. If the record does not exist
* then it is added. If an equal record exists, based upon
* {@link IMABaselineRecord#equals(Object)}, then this method quietly
* ignores the request to add the record because one already exists in the
* baseline.
*
* @param record
* record to add to baseline
* @return
* returns true is the record was added to the list, false if not
*/
final synchronized boolean addOnlyToBaseline(final IMABaselineRecord record) {
LOGGER.debug("adding record {} to baseline {}", record, getName());
if (record == null) {
LOGGER.error("null record");
throw new NullPointerException("record");
}
if (imaRecords.contains(record)) {
final String msg = String.format(
"record already exists in baseline: %s", record);
LOGGER.debug(msg);
return false;
} else {
imaRecords.add(record);
LOGGER.debug("record added: {}", record);
}
return true;
}
/**
* Remove record from the baseline.
*
* @param record
* record to remove
* @return a boolean indicating if the removal was successful
*/
final boolean removeOnlyBaseline(final IMABaselineRecord record) {
return imaRecords.remove(record);
}
/**
* Returns the actual <code>Set</code> that contains the IMA records. See
* {@link #setImaRecords(Set)} for more details on why this is needed.
*
* @return IMA records
*/
private Set<IMABaselineRecord> getImaRecords() {
return imaRecords;
}
/**
* Sets the IMA records. This is needed for Hibernate. The issue is that
* this class needs to be aware of when the <code>imaRecords</code>
* <code>Set</code> is set. This allows isUpdateNeeded to be set, indicating
* that the transient elements fullMap and partialMap should be populated
* using the imaRecords set that comes back from the database. This method
* should only be invoked by Hibernate.
* <p>
* Hibernate cannot use a public method like
* {@link #getAllMeasurementRecords()} and a corresponding private setter
* method. The reason is that the set pointer would be changing and confuse
* Hibernate.
*
* @param imaRecords IMA records
*/
private void setImaRecords(final Set<IMABaselineRecord> imaRecords) {
this.imaRecords = imaRecords;
}
}

View File

@ -1,288 +0,0 @@
package hirs.data.persist.baseline;
import hirs.data.persist.DeviceInfoReport;
import hirs.data.persist.Digest;
import hirs.data.persist.info.FirmwareInfo;
import hirs.data.persist.info.HardwareInfo;
import hirs.data.persist.info.OSInfo;
import hirs.data.persist.info.TPMInfo;
import hirs.data.persist.TPMMeasurementRecord;
import hirs.data.persist.info.RIMInfo;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import javax.persistence.CollectionTable;
import javax.persistence.ElementCollection;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Set;
/**
* Class represents a Trusted Platform Module (TPM) measurement baseline. A TPM baseline consists of
* a set of <code>TPMMeasurementRecord</code>s. The set of
* <code>TPMMeasurementRecord</code>s may have multiple entries for the same PCR ID. This is useful
* for scenarios where the PCR may have a few possible valid entries.
*/
@Entity
public abstract class TPMBaseline extends Baseline {
private static final Logger LOGGER = LogManager.getLogger(TPMBaseline.class);
@ElementCollection(fetch = FetchType.EAGER)
@CollectionTable(name = "TPMBaselineRecords",
joinColumns = { @JoinColumn(name = "BaselineID", nullable = false) })
private final Set<TPMMeasurementRecord> pcrRecords = new LinkedHashSet<>();
@Embedded
private FirmwareInfo firmwareInfo;
@Embedded
private HardwareInfo hardwareInfo;
@Embedded
private OSInfo osInfo;
@Embedded
private TPMInfo tpmInfo;
@Embedded
private RIMInfo rimInfo;
/**
* Creates a new <code>TPMBaseline</code> with no valid PCR entries and no device-specific PCRs.
*
* @param name
* a name used to uniquely identify and reference the PCR baseline
*/
public TPMBaseline(final String name) {
super(name);
initDeviceInfo();
}
/**
* Default constructor necessary for Hibernate and BaselineAlertResolver.
*/
public TPMBaseline() {
super();
initDeviceInfo();
}
private void initDeviceInfo() {
firmwareInfo = new FirmwareInfo();
hardwareInfo = new HardwareInfo();
osInfo = new OSInfo();
tpmInfo = new TPMInfo();
rimInfo = new RIMInfo();
}
/**
* Retrieves the FirmwareInfo for this <code>TPMBaseline</code>.
* @return FirmwareInfo
*/
public final FirmwareInfo getFirmwareInfo() {
return firmwareInfo;
}
/**
* Retrieves the HardwareInfo for this <code>TPMBaseline</code>.
* @return HardwareInfo
*/
public final HardwareInfo getHardwareInfo() {
return hardwareInfo;
}
/**
* Retrieves the OSInfo for this <code>TPMBaseline</code>.
* @return OSInfo
*/
public final OSInfo getOSInfo() {
return osInfo;
}
/**
* Retrieves the TPMInfo for this <code>TPMBaseline</code>.
* @return TPMInfo
*/
public final TPMInfo getTPMInfo() {
return tpmInfo;
}
/**
* Retrieves the RIMInfo for this <code>TPMBaseline</code>.
* @return an instance of RIMInfo
*/
public final RIMInfo getRIMInfo() {
return rimInfo;
}
/**
* Copy the Firmware data from another object. If null, the default
* FirmwareInfo data will be used.
* @param firmwareInfo FirmwareInfo object or null.
*/
public final void setFirmwareInfo(final FirmwareInfo firmwareInfo) {
if (firmwareInfo == null) {
this.firmwareInfo = new FirmwareInfo();
} else {
this.firmwareInfo = firmwareInfo;
}
}
/**
* Copy the Hardware data from another object. If null, the default
* HardwareInfo data will be used.
* @param hardwareInfo HardwareInfo object or null.
*/
public final void setHardwareInfo(final HardwareInfo hardwareInfo) {
if (hardwareInfo == null) {
this.hardwareInfo = new HardwareInfo();
} else {
this.hardwareInfo = hardwareInfo;
}
}
/**
* Copy the OSInfo data from another object. If null, the default
* OSInfo data will be used.
* @param osInfo OSInfo object or null.
*/
public final void setOSInfo(final OSInfo osInfo) {
if (osInfo == null) {
this.osInfo = new OSInfo();
} else {
this.osInfo = osInfo;
}
}
/**
* Copy the TPMInfo data from another object. If null, the default
* TPMInfo data will be used.
* @param tpmInfo TPMInfo object or null.
*/
public final void setTPMInfo(final TPMInfo tpmInfo) {
if (tpmInfo == null) {
this.tpmInfo = new TPMInfo();
} else {
this.tpmInfo = tpmInfo;
}
}
/**
* Returns acceptable hash values for a PCR ID. This returns a set of all the acceptable PCR
* hash values. The set may be empty if none are found.
*
* @param pcrId
* PCR index
* @return list of acceptable hash values
*/
public final Set<Digest> getPCRHashes(final int pcrId) {
TPMMeasurementRecord.checkForValidPcrId(pcrId);
final Set<Digest> ret = new LinkedHashSet<>();
for (TPMMeasurementRecord record : pcrRecords) {
if (record.getPcrId() == pcrId) {
ret.add(record.getHash());
}
}
return ret;
}
/**
* Returns a set of all PCR records associated with baseline.
*
* @return set of PCR records found in TPM baseline
*/
public final Set<TPMMeasurementRecord> getPcrRecords() {
return Collections.unmodifiableSet(pcrRecords);
}
/**
* Searches this baseline for the supplied <code>TPMMeasurementRecord</code> . This returns true
* if a measurement record was found with a matching PCR ID and hash value. Otherwise this
* returns false.
*
* @param record
* record to find
* @return true if measurement record is found in list, otherwise false
*/
public final boolean isInBaseline(final TPMMeasurementRecord record) {
return pcrRecords.contains(record);
}
/**
* Adds a PCR measurement record to baseline. If there is already a measurement with the same
* PCR ID and hash value then an <code>IllegalArgumentException</code> is thrown.
*
* @param record
* record to add to TPM baseline
*/
public final void addToBaseline(final TPMMeasurementRecord record) {
LOGGER.debug("adding record {} to baseline {}", record, getName());
if (record == null) {
LOGGER.error("null record");
throw new NullPointerException("TPMMeasurementRecord");
}
if (pcrRecords.contains(record)) {
final String msg = String.format("record already exist: %s", record);
LOGGER.info(msg);
throw new IllegalArgumentException(msg);
}
pcrRecords.add(record);
LOGGER.debug("record added");
}
/**
* Removes the <code>TPMMeasurementRecord</code> from this baseline. If the record is found and
* successfully removed then true is returned. Otherwise false is returned.
*
* @param record
* record to remove from baseline
* @return true if found and removed, otherwise false
*/
public final boolean removeFromBaseline(final TPMMeasurementRecord record) {
LOGGER.debug("removing record {} from baseline {}", record, getName());
if (record == null) {
LOGGER.error("null record can not be removed");
return false;
}
return pcrRecords.remove(record);
}
/**
* Checks the properties of FirmwareInfo, HardwareInfo, OSInfo, and TPMInfo and the contents of
* pcrRecords to determine if this instance of TPMBaseline is empty or not.
*
* @return true if baseline has no data
*/
public boolean isEmpty() {
LOGGER.debug("Check for empty baseline");
return (firmwareInfo.getBiosReleaseDate().equals(DeviceInfoReport.NOT_SPECIFIED)
&& firmwareInfo.getBiosVendor().equals(DeviceInfoReport.NOT_SPECIFIED)
&& firmwareInfo.getBiosVersion().equals(DeviceInfoReport.NOT_SPECIFIED)
&& hardwareInfo.getBaseboardSerialNumber().equals(DeviceInfoReport.NOT_SPECIFIED)
&& hardwareInfo.getChassisSerialNumber().equals(DeviceInfoReport.NOT_SPECIFIED)
&& hardwareInfo.getManufacturer().equals(DeviceInfoReport.NOT_SPECIFIED)
&& hardwareInfo.getProductName().equals(DeviceInfoReport.NOT_SPECIFIED)
&& hardwareInfo.getSystemSerialNumber().equals(DeviceInfoReport.NOT_SPECIFIED)
&& hardwareInfo.getVersion().equals(DeviceInfoReport.NOT_SPECIFIED)
&& osInfo.getDistribution().equals(DeviceInfoReport.NOT_SPECIFIED)
&& osInfo.getDistributionRelease().equals(DeviceInfoReport.NOT_SPECIFIED)
&& osInfo.getOSArch().equals(DeviceInfoReport.NOT_SPECIFIED)
&& osInfo.getOSName().equals(DeviceInfoReport.NOT_SPECIFIED)
&& osInfo.getOSVersion().equals(DeviceInfoReport.NOT_SPECIFIED)
&& tpmInfo.getTPMMake().equals(DeviceInfoReport.NOT_SPECIFIED)
&& tpmInfo.getTPMVersionMajor() == 0
&& tpmInfo.getTPMVersionMinor() == 0
&& tpmInfo.getTPMVersionRevMajor() == 0
&& tpmInfo.getTPMVersionRevMinor() == 0
&& rimInfo.getRimManufacturer().equals(DeviceInfoReport.NOT_SPECIFIED)
&& rimInfo.getModel().equals(DeviceInfoReport.NOT_SPECIFIED)
&& pcrRecords.isEmpty());
}
}

View File

@ -1,244 +0,0 @@
package hirs.data.persist.baseline;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import hirs.persist.RepositoryManager;
import hirs.repository.RepoPackage;
import hirs.repository.Repository;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.hibernate.Criteria;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.springframework.util.CollectionUtils;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ExecutionException;
import javax.persistence.Access;
import javax.persistence.AccessType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.OneToMany;
import javax.persistence.Transient;
/**
* An IMA baseline that references a specified set of <code>RepoPackage</code>s. These packages are
* used during appraisal to generate a set of measurement records. An update() will use the source
* repository referenced within each package to refresh the measurements of that package.
*
*/
@Entity
@Access(AccessType.FIELD)
public class TargetedRepoImaBaseline extends QueryableRecordImaBaseline
implements UpdatableImaBaseline {
private static final Logger LOGGER = LogManager.getLogger(TargetedRepoImaBaseline.class);
private static final int MAX_REPO_CACHE_SIZE = 10;
/**
* Name of the repoPackages field.
*/
public static final String REPO_PACKAGES_FIELD = "repoPackages";
/**
* The packages used for an appraisal against this baseline.
*/
@OneToMany(fetch = FetchType.EAGER)
private Set<RepoPackage> repoPackages;
@Transient
private final Set<IMABaselineRecord> cachedBaselineRecords = new HashSet<>();
@Transient
private boolean shouldUpdateCache = true;
/**
* Constructor used to initialize a <code>TargetedRepoImaBaseline</code> with the given name and
* an empty <code>Set</code> of <code>RepoPackage</code>s.
* @param name the name of the new baseline
*/
public TargetedRepoImaBaseline(final String name) {
super(name);
repoPackages = new HashSet<>();
}
/** Default constructor necessary for Hibernate. Makes an empty <code>Set</code> of
* <code>RepoPackage</code>s.
*/
protected TargetedRepoImaBaseline() {
super();
repoPackages = new HashSet<>();
}
/**
* Iterate through the <code>RepoPackage</code>s referenced in this baseline and check the
* associated repository for any updated versions or releases.
*
* @param repositoryManager a repository manager to use to gather data about repositories, or
* null if object already contains all info (no lazy-loaded data)
*/
@Override
public final void update(final RepositoryManager repositoryManager) {
LoadingCache<UUID, Repository<? extends RepoPackage>> repositoryCache =
CacheBuilder.newBuilder()
.maximumSize(MAX_REPO_CACHE_SIZE)
.build(
new CacheLoader<UUID, Repository<? extends RepoPackage>>() {
@Override
public Repository<? extends RepoPackage> load(final UUID id)
throws Exception {
LOGGER.debug("Retrieving repository {}", id);
return repositoryManager.getRepository(id);
}
}
);
Set<RepoPackage> newPackages = new HashSet<>();
Repository<? extends RepoPackage> repoWithPackages;
for (RepoPackage baselineRepoPackage : repoPackages) {
try {
if (repositoryManager != null) {
repoWithPackages = repositoryCache.get(
baselineRepoPackage.getSourceRepository().getId()
);
} else {
repoWithPackages = baselineRepoPackage.getSourceRepository();
}
} catch (ExecutionException e) {
throw new RuntimeException("Couldn't retrieve persisted repository via cache.");
}
newPackages.addAll(repoWithPackages.getUpdatedPackages(baselineRepoPackage));
}
repoPackages.addAll(newPackages);
synchronized (cachedBaselineRecords) {
this.shouldUpdateCache = true;
}
}
@Override
public final Set<IMABaselineRecord> getBaselineRecords() {
synchronized (cachedBaselineRecords) {
if (!shouldUpdateCache) {
return Collections.unmodifiableSet(cachedBaselineRecords);
}
cachedBaselineRecords.clear();
for (RepoPackage repoPackage : repoPackages) {
cachedBaselineRecords.addAll(repoPackage.getPackageRecords());
}
shouldUpdateCache = false;
return Collections.unmodifiableSet(cachedBaselineRecords);
}
}
@Override
public void configureCriteriaForBaselineRecords(final Criteria criteria, final int bucket) {
criteria.add(Restrictions.eq("id", getId()))
.setProjection(Projections.projectionList()
.add(Projections.property(
String.format("%s.%s",
RepoPackage.PACKAGE_RECORDS_FIELD,
IMABaselineRecord.PATH_FIELD)
), IMABaselineRecord.PATH_FIELD)
.add(Projections.property(
String.format("%s.%s",
RepoPackage.PACKAGE_RECORDS_FIELD,
IMABaselineRecord.HASH_FIELD)
), IMABaselineRecord.HASH_FIELD)
);
criteria.add(Restrictions.eq(
String.format("%s.%s",
RepoPackage.PACKAGE_RECORDS_FIELD,
IMABaselineRecord.BUCKET_FIELD),
bucket)
);
criteria.createAlias(REPO_PACKAGES_FIELD, REPO_PACKAGES_FIELD);
criteria.createAlias(
String.format("%s.%s", REPO_PACKAGES_FIELD, RepoPackage.PACKAGE_RECORDS_FIELD),
RepoPackage.PACKAGE_RECORDS_FIELD
);
}
/**
* Get the <code>Set</code> of <code>RepoPackage</code>s associated with this baseline.
*
* @return the RepoPackages tracked by this baseline
*/
public final Set<RepoPackage> getRepositoryPackages() {
return Collections.unmodifiableSet(repoPackages);
}
/**
* Returns the actual <code>Set</code> that contains the IMA records. This is needed for
* Hibernate.
*
* @return RepoPackages
*/
private Set<RepoPackage> getRepoPackages() {
return this.repoPackages;
}
/**
* Set the <code>Set</code> of <code>RepoPackage</code>s associated with this baseline. Also
* flips the map update needed flags so the next call to contains will require map updates.
*
* @param newRepoPackages the new RepoPackages to be tracked by this baseline
*/
public final void setRepoPackages(final Set<RepoPackage> newRepoPackages) {
this.repoPackages = newRepoPackages;
}
/**
* Adds to the <code>Set</code> of <code>RepoPackage</code>s. Also
* flips the map update needed flags so the next call to contains will require map updates.
*
* @param repoPackage the new RepoPackage to be tracked by this baseline
*/
public final void addRepoPackage(final RepoPackage repoPackage) {
this.repoPackages.add(repoPackage);
}
/**
* Deletes from the <code>Set</code> of <code>RepoPackage</code>s. Also
* flips the map update needed flags so the next call to contains will require map updates.
*
* @param repoPackage this package should no longer be tracked by this baseline
*/
public final void removeRepoPackage(final RepoPackage repoPackage) {
this.repoPackages.remove(repoPackage);
}
/**
* Checks if this baseline's set of packages is associated with the specified set of
* repositories. This is determined by checking each repo package's source repository.
* @param repositories the set of repositories to check for association
* @return true if any repository packages are linked to the set of specified repositories
*/
public boolean isAssociatedWithRepositories(final Collection<Repository> repositories) {
Set<RepoPackage> repositoryPackages = getRepositoryPackages();
if (CollectionUtils.isEmpty(repositoryPackages) || CollectionUtils.isEmpty(repositories)) {
return false;
}
for (RepoPackage repoPackage : repositoryPackages) {
if (repositories.contains(repoPackage.getSourceRepository())) {
return true;
}
}
return false;
}
}

View File

@ -1,29 +0,0 @@
package hirs.data.persist.baseline;
import javax.persistence.Entity;
/**
* A {@link TPMBaseline} that represents TPM measurement values that are not allowed in the system.
* If a device provides a TPM Report that includes TPM measurements matching a blacklist in its
* TPM Policy, an alert will be generated.
*/
@Entity
public class TpmBlackListBaseline extends TPMBaseline {
/**
* Creates a new baseline with no PCR.
*
* @param name
* a name used to uniquely identify and reference the PCR baseline
*/
public TpmBlackListBaseline(final String name) {
super(name);
}
/**
* Default constructor necessary for Hibernate and BaselineAlertResolver.
*/
public TpmBlackListBaseline() {
super();
}
}

View File

@ -1,29 +0,0 @@
package hirs.data.persist.baseline;
import javax.persistence.Entity;
/**
* A {@link TPMBaseline} that represents expected TPM measurement values.
* If a device provides a TPM Report that includes TPM measurements not matching the whitelist
* in its TPM Policy, an alert will be generated.
*/
@Entity
public class TpmWhiteListBaseline extends TPMBaseline {
/**
* Creates a new baseline with no valid PCR entries and no device-specific PCRs.
*
* @param name
* a name used to uniquely identify and reference the PCR baseline
*/
public TpmWhiteListBaseline(final String name) {
super(name);
}
/**
* Default constructor necessary for Hibernate and BaselineAlertResolver.
*/
public TpmWhiteListBaseline() {
super();
}
}

View File

@ -1,18 +0,0 @@
package hirs.data.persist.baseline;
import hirs.persist.RepositoryManager;
/**
* An IMA baseline that supports an update capability through which the associated records can be
* managed by an external source, such as a Yum repository.
*
*/
public interface UpdatableImaBaseline {
/**
* Update this baseline from an external source.
*
* @param repositoryManager a repository manager to use to gather data about repositories, or
* null if object already contains all info (no lazy-loaded data)
*/
void update(RepositoryManager repositoryManager);
}

View File

@ -1,4 +0,0 @@
/**
* This package contains a set of classes for accessing baseline code.
*/
package hirs.data.persist.baseline;

View File

@ -1,185 +0,0 @@
package hirs.ima;
import hirs.data.persist.Digest;
import hirs.data.persist.info.FirmwareInfo;
import hirs.data.persist.info.HardwareInfo;
import hirs.data.persist.baseline.IMABaselineRecord;
import hirs.data.persist.baseline.ImaAcceptableRecordBaseline;
import hirs.data.persist.baseline.ImaBlacklistBaseline;
import hirs.data.persist.ImaBlacklistRecord;
import hirs.data.persist.baseline.ImaIgnoreSetBaseline;
import hirs.data.persist.ImaIgnoreSetRecord;
import hirs.data.persist.info.OSInfo;
import hirs.data.persist.baseline.TPMBaseline;
import hirs.data.persist.info.TPMInfo;
import hirs.data.persist.TPMMeasurementRecord;
import hirs.tpm.TPMBaselineGenerator.TPMBaselineFields;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVPrinter;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.IOException;
import java.util.HashMap;
/**
* Class used to generate CSV from baselines and ignore sets. These utility functions are useful
* for exporting the objects to files.
*/
public final class CSVGenerator {
private static final Logger LOGGER = LogManager.getLogger(CSVGenerator.class);
/**
* Private constructor, should never be called.
*/
private CSVGenerator() {
// intentionally blank
}
/**
* Returns all IMA records stored in IMABaselineRecords for IMABaseline.
*
* Adds logic to remove stray commas that were appearing in large baselines.
*
* @param imaBaseline baseline
* @return CSV in a String
*/
public static String imaRecordsToCsv(final ImaAcceptableRecordBaseline imaBaseline) {
LOGGER.info("Retrieved and parsing all records");
StringBuilder sb = new StringBuilder();
for (IMABaselineRecord record : imaBaseline.getBaselineRecords()) {
String stringHashValue;
Digest theHash = record.getHash();
if (theHash == null) {
stringHashValue = "";
} else {
final byte[] digest = theHash.getDigest();
final char[] hash = Hex.encodeHex(digest);
stringHashValue = String.valueOf(hash);
}
sb.append("\"")
.append(record.getPath().replace("\"", "\"\""))
.append("\",")
.append(stringHashValue)
.append(System.lineSeparator());
}
return sb.toString();
}
/**
* Returns all of the file paths of records that should be ignored.
*
* @param ignoreSetBaseline ignoreSetBaseline
* @return CSV in a String
*/
public static String ignoreSetToCsv(final ImaIgnoreSetBaseline ignoreSetBaseline) {
LOGGER.info("Retrieved and parsing all records");
StringBuilder sb = new StringBuilder();
for (ImaIgnoreSetRecord record : ignoreSetBaseline.getImaIgnoreRecords()) {
sb.append(record.getPath())
.append(",")
.append(StringUtils.defaultString(record.getDescription()))
.append(",")
.append(System.lineSeparator());
}
return sb.toString();
}
/**
* Serializes an {@link ImaBlacklistBaseline} into a CSV file, whose rows represent
* entries in the baseline.
*
* @param blacklistBaseline the baseline to serialize
* @return the resulting CSV in a String
*/
public static String blacklistToCsv(final ImaBlacklistBaseline blacklistBaseline) {
StringBuilder sb = new StringBuilder();
CSVPrinter csvPrinter;
try {
csvPrinter = CSVFormat.DEFAULT.builder()
.setRecordSeparator(System.lineSeparator())
.build().print(sb);
for (ImaBlacklistRecord record : blacklistBaseline.getRecords()) {
String digest = "";
Digest hash = record.getHash();
if (hash != null) {
digest = hash.toString();
}
csvPrinter.printRecord(
nullToEmpty(record.getPath()),
digest,
nullToEmpty(record.getDescription())
);
}
} catch (IOException e) {
throw new RuntimeException("Could not instantiate CSV printer");
}
return sb.toString();
}
/**
* Returns the TPM records in the TPMBaseline.
*
* @param tpmBaseline tpmBaseline
* @return CSV in a String
*/
public static String tpmRecordsToCsv(final TPMBaseline tpmBaseline) {
LOGGER.info("Retrieved and parsing all records");
StringBuilder sb = new StringBuilder();
// Add device info records to the map
HashMap<TPMBaselineFields, String> map = new HashMap<TPMBaselineFields, String>();
final FirmwareInfo firmwareInfo = tpmBaseline.getFirmwareInfo();
map.put(TPMBaselineFields.BIOS_VENDOR, firmwareInfo.getBiosVendor());
map.put(TPMBaselineFields.BIOS_VERSION, firmwareInfo.getBiosVersion());
map.put(TPMBaselineFields.BIOS_RELEASE_DATE, firmwareInfo.getBiosReleaseDate());
final HardwareInfo hardwareInfo = tpmBaseline.getHardwareInfo();
map.put(TPMBaselineFields.MANUFACTURER, hardwareInfo.getManufacturer());
map.put(TPMBaselineFields.PRODUCT_NAME, hardwareInfo.getProductName());
map.put(TPMBaselineFields.VERSION, hardwareInfo.getVersion());
map.put(TPMBaselineFields.SYSTEM_SERIAL_NUMBER, hardwareInfo.getSystemSerialNumber());
map.put(TPMBaselineFields.CHASSIS_SERIAL_NUMBER, hardwareInfo.getChassisSerialNumber());
map.put(TPMBaselineFields.BASEBOARD_SERIAL_NUMBER, hardwareInfo.getBaseboardSerialNumber());
final OSInfo osInfo = tpmBaseline.getOSInfo();
map.put(TPMBaselineFields.OS_NAME, osInfo.getOSName());
map.put(TPMBaselineFields.OS_VERSION, osInfo.getOSVersion());
map.put(TPMBaselineFields.OS_ARCH, osInfo.getOSArch());
map.put(TPMBaselineFields.DISTRIBUTION, osInfo.getDistribution());
map.put(TPMBaselineFields.DISTRIBUTION_RELEASE, osInfo.getDistributionRelease());
final TPMInfo tpmInfo = tpmBaseline.getTPMInfo();
map.put(TPMBaselineFields.TPM_MAKE, tpmInfo.getTPMMake());
map.put(TPMBaselineFields.TPM_VERSION_MAJOR, "" + tpmInfo.getTPMVersionMajor());
map.put(TPMBaselineFields.TPM_VERSION_MINOR, "" + tpmInfo.getTPMVersionMinor());
map.put(TPMBaselineFields.TPM_VERSION_REV_MAJOR, "" + tpmInfo.getTPMVersionRevMajor());
map.put(TPMBaselineFields.TPM_VERSION_REV_MINOR, "" + tpmInfo.getTPMVersionRevMinor());
// Add device info records to the CSV file
sb.append(TPMBaselineFields.toCSV(map));
// Add measurement records to the CSV file
for (TPMMeasurementRecord record : tpmBaseline.getPcrRecords()) {
final byte[] digest = record.getHash().getDigest();
final char[] hash = Hex.encodeHex(digest);
sb.append(record.getPcrId())
.append(",")
.append(String.valueOf(hash))
.append(System.lineSeparator());
}
return sb.toString();
}
/**
* Convers a null String to an empty String, for serialization purposes.
*
* @param str the input string
* @return the same string, or an empty String if the original was null
*/
public static String nullToEmpty(final String str) {
if (str == null) {
return "";
}
return str;
}
}

View File

@ -1,46 +0,0 @@
package hirs.ima;
/**
* This class represents an <code>Exception</code> generated by a
* <code>CreateIMABaseline</code>.
*/
public class IMABaselineGeneratorException extends Exception {
private static final long serialVersionUID = 1704308568386321875L;
/**
* Creates a new <code>CreateIMABaselineException</code> that has the
* message <code>msg</code>.
*
* @param msg
* exception message
*/
IMABaselineGeneratorException(final String msg) {
super(msg);
}
/**
* Creates a new <code>CreateIMABaselineException</code> that wraps the
* given <code>Throwable</code>.
*
* @param t
* root cause
*/
IMABaselineGeneratorException(final Throwable t) {
super(t);
}
/**
* Creates a new <code>CreateIMABaselineException</code> that has the
* message <code>msg</code> and wraps the root cause.
*
* @param msg
* exception message
* @param t
* root cause
*/
IMABaselineGeneratorException(final String msg, final Throwable t) {
super(msg, t);
}
}

View File

@ -1,99 +0,0 @@
package hirs.ima;
import com.google.common.base.Charsets;
import com.google.common.base.Preconditions;
import hirs.data.persist.Digest;
import hirs.data.persist.baseline.ImaBlacklistBaseline;
import hirs.data.persist.ImaBlacklistRecord;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVParser;
import org.apache.commons.csv.CSVRecord;
import org.apache.commons.lang3.StringUtils;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
/**
* This class provides methods for generating {@link ImaBlacklistBaseline}s as serialized
* by {@link CSVGenerator}.
*/
public final class ImaBlacklistBaselineGenerator {
private static final int NUM_CSV_FIELDS = 3;
/**
* This is a utility class that should not be constructed.
*/
private ImaBlacklistBaselineGenerator() {
}
/**
* Creates a new {@link ImaBlacklistBaseline} instance from the provided CSV input.
*
* @param baselineName the name that the resultant baseline should have
* @param inputStream input stream containing the CSV data
* @return the resulting blacklist baseline
* @throws IOException if there is a problem deserializing the baseline records
*/
public static ImaBlacklistBaseline generateBaselineFromCSV(
final String baselineName,
final InputStream inputStream
) throws IOException {
Preconditions.checkArgument(
!StringUtils.isBlank(baselineName),
"Cannot generate a baseline with a blank name"
);
ImaBlacklistBaseline blacklistBaseline = new ImaBlacklistBaseline(baselineName);
updateBaselineFromCSVFile(blacklistBaseline, inputStream);
return blacklistBaseline;
}
/**
* Adds blacklist baseline records from the provided CSV input to the given
* {@link ImaBlacklistBaseline} instance.
*
* @param baseline the baseline whose blacklist records should be updated
* @param inputStream input stream containing the CSV data
* @throws IOException if there is a problem deserializing the baseline records
*/
public static void updateBaselineFromCSVFile(
final ImaBlacklistBaseline baseline,
final InputStream inputStream
) throws IOException {
Preconditions.checkNotNull(baseline, "Cannot update null baseline");
Preconditions.checkNotNull(inputStream, "Cannot update from null input");
BufferedReader buffReader = new BufferedReader(new InputStreamReader(
inputStream, Charsets.UTF_8
));
CSVParser parser = CSVFormat.DEFAULT.parse(buffReader);
try {
for (CSVRecord record : parser.getRecords()) {
if (record.size() != NUM_CSV_FIELDS) {
throw new IOException(String.format(
"Expected %d fields for record %s", NUM_CSV_FIELDS, record.toString()
));
}
String path = StringUtils.defaultIfBlank(record.get(0), null);
String description = StringUtils.defaultIfBlank(record.get(2), null);
Digest digest = null;
if (!StringUtils.isBlank(record.get(1))) {
digest = Digest.fromString(record.get(1));
}
baseline.addToBaseline(new ImaBlacklistRecord(path, digest, description));
}
} catch (IOException e) {
throw e;
} finally {
parser.close();
buffReader.close();
}
}
}

View File

@ -1,134 +0,0 @@
package hirs.ima;
import hirs.data.persist.baseline.ImaIgnoreSetBaseline;
import hirs.data.persist.ImaIgnoreSetRecord;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.text.ParseException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
/**
* Class used to process comma separated value measurement files or HIRS
* integrity reports to generate an IMA measurement baseline. Generating an IMA
* measurement baseline from a HIRS integrity report is considered experimental
* and provided as a tool to assist with creating, analyzing, and refining
* measurement baselines.
*/
public class ImaIgnoreSetBaselineGenerator {
private static final Logger LOGGER
= LogManager.getLogger(ImaIgnoreSetBaseline.class);
private static final int PATH_INDEX = 0;
private static final int DESCRIPTION_INDEX = 1;
/**
* Method generates an IMA measurement baseline from a .csv file containing
* IMA baseline records. An IMA record consists of properties associated
* with an IMA measured file such as file hash, and path. An off-line IMA
* measurement baseline process is used to create the .csv file. IMA
* baseline records are expected to adhere to the following record
* structure separated by commas:
* <ul>
* <li>file Path (includes file name)</li>
* <li>Description of why path was chosen to be ignored</li>
* </ul>
*
* @param baselineName
* name applied to baseline
* @param in
* is input stream containing IMA baseline records
* @return IMAbaseline
* @throws IOException
* if error encountered reading data from input stream
* @throws ParseException
* if error encountered parsing data
* @throws ImaIgnoreSetBaselineGeneratorException
* if error encountered when retrieving baseline records from
* input stream
*/
public final ImaIgnoreSetBaseline generateBaselineFromCSVFile(
final String baselineName, final InputStream in)
throws IOException, ParseException, ImaIgnoreSetBaselineGeneratorException {
if (baselineName == null) {
LOGGER.error("null argument: baselineName");
throw new NullPointerException("baselineName");
}
ImaIgnoreSetBaseline ignoreBaseline = new ImaIgnoreSetBaseline(baselineName);
updateBaselineFromCSVFile(ignoreBaseline, in);
LOGGER.debug("meaurement baseline initialized: {}", ignoreBaseline.getName());
return ignoreBaseline;
}
/**
* Method parses a .csv file containing IMA ignore baseline records and adds then to
* a IMA ignore baseline object.
*
* @param baseline The baseline to be updated with records from the stream
* @param inStream
* containing file contents to be read. inStream is closed by
* this method.
* @throws IOException
* if error encountered reading data from input stream
* @throws ParseException
* if error encountered parsing data
* @throws ImaIgnoreSetBaselineGeneratorException
* if error encountered when retrieving baseline records from
* input stream
*/
public final void updateBaselineFromCSVFile(final ImaIgnoreSetBaseline baseline,
final InputStream inStream) throws IOException, ParseException,
ImaIgnoreSetBaselineGeneratorException {
if (baseline == null) {
LOGGER.error("null argument: baseline");
throw new NullPointerException("baseline");
}
if (inStream == null) {
LOGGER.error("null argument: in");
throw new NullPointerException("in");
}
// (tmmcgil) I realize this is not the most robust way to parse, but it works
// better than what was here before and it doesn't require a lot of changes.
String regex = "\"?(.*?)\"?,(.*)";
Pattern p = Pattern.compile(regex);
BufferedReader reader = new BufferedReader(new InputStreamReader(
inStream, "UTF8"));
String dataRow;
while ((dataRow = reader.readLine()) != null) {
if (StringUtils.isBlank(dataRow)) {
continue;
}
Matcher m = p.matcher(dataRow);
if (!m.matches() || m.groupCount() != 2) {
final String msg = "row does not match regex: " + dataRow;
LOGGER.error(msg);
throw new ImaIgnoreSetBaselineGeneratorException(msg);
}
String path = m.group(1);
path = path.replace("\"\"", "\"");
String description = m.group(2);
if (StringUtils.defaultString(description).equalsIgnoreCase("")) {
description = null;
}
final ImaIgnoreSetRecord imaRecord = new ImaIgnoreSetRecord(path,
description);
baseline.addToBaseline(imaRecord);
final String msg = String.format("added record %s", imaRecord);
LOGGER.debug(msg);
}
reader.close();
}
}

View File

@ -1,46 +0,0 @@
package hirs.ima;
/**
* This class represents an <code>Exception</code> generated by a
* <code>CreateImaIgnoreSetBaseline</code>.
*/
public class ImaIgnoreSetBaselineGeneratorException extends Exception {
private static final long serialVersionUID = 1704308568386321875L;
/**
* Creates a new <code>CreateImaIgnoreSetBaselineException</code> that has the
* message <code>msg</code>.
*
* @param msg
* exception message
*/
ImaIgnoreSetBaselineGeneratorException(final String msg) {
super(msg);
}
/**
* Creates a new <code>CreateImaIgnoreSetBaselineException</code> that wraps the
* given <code>Throwable</code>.
*
* @param t
* root cause
*/
ImaIgnoreSetBaselineGeneratorException(final Throwable t) {
super(t);
}
/**
* Creates a new <code>CreateImaIgnoreSetBaselineException</code> that has the
* message <code>msg</code> and wraps the root cause.
*
* @param msg
* exception message
* @param t
* root cause
*/
ImaIgnoreSetBaselineGeneratorException(final String msg, final Throwable t) {
super(msg, t);
}
}

View File

@ -1,259 +0,0 @@
package hirs.ima;
import hirs.data.persist.IMAReport;
import hirs.data.persist.baseline.SimpleImaBaseline;
import hirs.data.persist.Digest;
import hirs.data.persist.enums.DigestAlgorithm;
import hirs.data.persist.baseline.ImaBaseline;
import hirs.data.persist.baseline.IMABaselineRecord;
import hirs.data.persist.IMAMeasurementRecord;
import hirs.data.persist.IntegrityReport;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.text.ParseException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
/**
* Class used to process comma separated value measurement files or HIRS
* integrity reports to generate an IMA measurement baseline. Generating an IMA
* measurement baseline from a HIRS integrity report is considered experimental
* and provided as a tool to assist with creating, analyzing, and refining
* measurement baselines.
*/
public class SimpleImaBaselineGenerator {
private static final Logger LOGGER
= LogManager.getLogger(ImaBaseline.class);
/**
* Method generates an IMA measurement baseline from a .csv file containing
* IMA baseline records. An IMA record consists of properties associated
* with an IMA measured file such as file hash, and path. An off-line IMA
* measurement baseline process is used to create the .csv file. IMA
* baseline records are expected to adhere to the following record
* structure separated by commas:
* <ul>
* <li>file Path (includes file name)</li>
* <li>SHA1 of file</li>
* </ul>
*
* @param baselineName
* name applied to baseline
* @param in
* is input stream containing IMA baseline records
* @return IMAbaseline
* @throws IOException
* if error encountered reading data from input stream
* @throws ParseException
* if error encountered parsing data
* @throws IMABaselineGeneratorException
* if error encountered when retrieving baseline records from
* input stream
*/
public final SimpleImaBaseline generateBaselineFromCSVFile(
final String baselineName, final InputStream in)
throws IOException, ParseException, IMABaselineGeneratorException {
if (baselineName == null) {
LOGGER.error("null argument: baselineName");
throw new NullPointerException("baselineName");
}
SimpleImaBaseline imaBaseline = new SimpleImaBaseline(baselineName);
updateBaselineFromCSVFile(imaBaseline, in);
LOGGER.debug("meaurement baseline initialized: {}", imaBaseline.getName());
return imaBaseline;
}
/**
* Produces IMA baseline from IMA report. The method extracts the list of
* IMA records from the trusted report then it uses each IMA report record
* to construct the baseline. Note: The HIRS portal selects an IMA report
* to use as a seed to generate IMA baseline, the IMA report should be
* generated with sufficient (complete list of files measurements) and
* should be in trusted state to use as basis for baseline. However, IMA
* baselines generated from measurement reports are expected to have high
* rate of false positives because many alerts will be generated for files
* that change every boot cycle that need to be filtered by system
* operators that will build expertise regarding IMA measurements in their
* specific deployment configuration, and who will utilize the portal to
* adjust the baseline to identify all files that should have policy set
* to ignore hash. there are many other cases that may cause false
* positive which will require human in the loop also to refine the
* produced baseline.
*
* @param baselineName
* name of the new baseline
* @param report
* IMAReport instance of IMA integrity report object. The IMA
* Integrity report is extracted from a host integrity report.
*
* @return ImaBaseline
* @throws IMABaselineGeneratorException
* if we find no IMA records in the trusted report that method
* should use to generate IMA baseline.
* @throws NullPointerException
* if baselineName or report parameters are null.
*/
public final SimpleImaBaseline generateBaselineFromIMAReport(
final String baselineName, final IMAReport report)
throws IMABaselineGeneratorException, NullPointerException {
IMABaselineRecord imaBaselineRecord;
if (baselineName == null) {
LOGGER.error("null argument: baselineName");
throw new NullPointerException("baselineName");
}
if (report == null) {
LOGGER.error("null argument: report");
throw new NullPointerException("report");
}
if (report.getRecords().size() < 1) {
String msg;
msg = "no IMA records in the report";
LOGGER.error(msg);
throw new IMABaselineGeneratorException(msg);
}
SimpleImaBaseline newBaseline = new SimpleImaBaseline(baselineName);
for (IMAMeasurementRecord record : report.getRecords()) {
imaBaselineRecord = new IMABaselineRecord(record.getPath(), record.getHash());
newBaseline.addToBaseline(imaBaselineRecord);
}
return newBaseline;
}
/**
* Produces IMA baseline from a HIRS full integrity report that complies
* with HIRS new XML report format. The method the IMA report from the full
* integrity report, then it extracts the the list of IMA records from the
* trusted report then it uses each IMA report record to construct the IMA
* baseline.
* @param baselineName
* name of the new baseline
* @param report
* IMAReport instance of IMA integrity report object. The IMA
* Integrity report is extracted from a host integrity report.
*
* @return ImaBaseline
* @throws IMABaselineGeneratorException
* if no IMA report, or IMA records, in the trusted integrity
* report passed to the method to generate IMA baseline.
* @throws NullPointerException
* if baselineName or report parameters are null.
*/
public final SimpleImaBaseline generateBaselineFromIntegrityReport(
final String baselineName, final IntegrityReport report)
throws IMABaselineGeneratorException, NullPointerException {
IMABaselineRecord imaBaselineRecord;
if (baselineName == null) {
LOGGER.error("null argument: baselineName");
throw new NullPointerException("baselineName");
}
if (report == null) {
LOGGER.error("null argument: report");
throw new NullPointerException("report");
}
if (!report.contains(IMAReport.class)) {
String msg = "no IMA report in the integrity report";
LOGGER.error(msg);
throw new IMABaselineGeneratorException(msg);
}
IMAReport imaReport = report.extractReport(IMAReport.class);
if (imaReport.getRecords().size() < 1) {
String msg = "no IMA records in the report";
LOGGER.error(msg);
throw new IMABaselineGeneratorException(msg);
}
SimpleImaBaseline newBaseline = new SimpleImaBaseline(baselineName);
for (IMAMeasurementRecord imaRecord : imaReport.getRecords()) {
imaBaselineRecord = new IMABaselineRecord(imaRecord.getPath(),
imaRecord.getHash());
newBaseline.addToBaseline(imaBaselineRecord);
}
return newBaseline;
}
/**
* Method parses a .csv file containing IMA baseline records and adds then to
* a IMA baseline object.
*
* @param baseline The baseline to be updated with records from the stream
* @param inStream
* containing file contents to be read. inStream is closed by
* this method.
* @throws IOException
* if error encountered reading data from input stream
* @throws ParseException
* if error encountered parsing data
* @throws IMABaselineGeneratorException
* if error encountered when retrieving baseline records from
* input stream
*/
public final void updateBaselineFromCSVFile(final SimpleImaBaseline baseline,
final InputStream inStream) throws IOException, ParseException,
IMABaselineGeneratorException {
if (baseline == null) {
LOGGER.error("null argument: baseline");
throw new NullPointerException("baseline");
}
if (inStream == null) {
LOGGER.error("null argument: in");
throw new NullPointerException("in");
}
String regex = "\"?(.*?)\"?,([a-fA-F0-9]{40})";
Pattern p = Pattern.compile(regex);
BufferedReader reader = new BufferedReader(new InputStreamReader(
inStream, "UTF8"));
String dataRow;
while ((dataRow = reader.readLine()) != null) {
if (StringUtils.isBlank(dataRow)) {
continue;
}
Matcher m = p.matcher(dataRow);
if (!m.matches() || m.groupCount() != 2) {
final String msg = "row does not match regex: " + dataRow;
LOGGER.error(msg);
throw new IMABaselineGeneratorException(msg);
}
String path = m.group(1);
path = path.replace("\"\"", "\"");
try {
final byte[] hash = Hex.decodeHex(m.group(2).toCharArray());
final Digest digest = new Digest(DigestAlgorithm.SHA1, hash);
final IMABaselineRecord imaRecord = new IMABaselineRecord(path,
digest);
baseline.addToBaseline(imaRecord);
final String msg = String.format("added record %s", imaRecord);
LOGGER.debug(msg);
} catch (DecoderException e) {
String msg = "File " + path + " has invalid hash sting. "
+ "Record not added to baseline";
LOGGER.error(msg, e);
}
}
reader.close();
}
}

View File

@ -1,317 +0,0 @@
package hirs.ima.matching;
import com.google.common.base.Preconditions;
import hirs.data.persist.IMAMeasurementRecord;
import hirs.data.persist.baseline.AbstractImaBaselineRecord;
import hirs.data.persist.enums.ReportMatchStatus;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
/**
* This class holds the results of the appraisal of a batch of {@link IMAMeasurementRecord}s against
* one or many {@link hirs.data.persist.baseline.ImaBaseline}s.
*
* @param <T> the type of IMA baseline record that an instance of this class matches against
*/
public class BatchImaMatchStatus<T extends AbstractImaBaselineRecord> {
// mapping from measurement record to match statuses, one per baseline
private Map<IMAMeasurementRecord, Set<IMAMatchStatus<T>>> matchStatuses = new HashMap<>();
/**
* Create an empty instance of this class.
*/
public BatchImaMatchStatus() {
}
/**
* Given a set of {@link IMAMatchStatus}es that result from appraising one or many measurement
* records against a baseline.
*
* @param matchStatuses the results of matching measurement records against a baseline
*/
public BatchImaMatchStatus(final Collection<IMAMatchStatus<T>> matchStatuses) {
if (matchStatuses == null) {
throw new IllegalArgumentException("Cannot construct from null matches");
}
for (IMAMatchStatus<T> match : matchStatuses) {
add(match);
}
}
/**
* Add the result of a match to this instance.
*
* @param status the match status to add
*/
public void add(final IMAMatchStatus<T> status) {
if (status == null) {
throw new IllegalArgumentException("Cannot add a null match status");
}
IMAMeasurementRecord measurementRecord = status.getRecordToMatch();
if (!matchStatuses.containsKey(measurementRecord)) {
matchStatuses.put(measurementRecord, new HashSet<IMAMatchStatus<T>>());
}
for (IMAMatchStatus<T> existingMatchStatus : matchStatuses.get(measurementRecord)) {
if (existingMatchStatus.getBaseline().equals(status.getBaseline())) {
throw new IllegalArgumentException(String.format(
"A conflicting match result exists: %s",
existingMatchStatus.toString())
);
}
}
matchStatuses.get(measurementRecord).add(status);
}
/**
* Retrieve the {@link IMAMatchStatus} that results from checking whether an
* {@link IMAMeasurementRecord} was in a baseline.
*
* @param record the record whose match should be returned
* @return the relevant {@link IMAMatchStatus}
*/
public Set<IMAMatchStatus<T>> getIMAMatchStatuses(final IMAMeasurementRecord record) {
Set<IMAMatchStatus<T>> imaMatchStatusSet = matchStatuses.get(record);
if (imaMatchStatusSet == null) {
throw new IllegalArgumentException("No match status stored for this record.");
}
return imaMatchStatusSet;
}
/**
* Retrieve the {@link IMAMatchStatus} that results from checking whether an
* {@link IMAMeasurementRecord} was in a baseline.
*
* @param record the record whose match should be returned
* @return the relevant {@link IMAMatchStatus}, or null if no match was attempted for the record
*/
public Set<IMAMatchStatus<T>> getMatchingIMAMatchStatuses(final IMAMeasurementRecord record) {
Preconditions.checkArgument(contains(record), "No match status stored for this record.");
HashSet<IMAMatchStatus<T>> matchingStatuses = new HashSet<>();
for (IMAMatchStatus<T> matchStatus : getIMAMatchStatuses(record)) {
if (matchStatus.getStatus().equals(ReportMatchStatus.MATCH)) {
matchingStatuses.add(matchStatus);
}
}
return matchingStatuses;
}
/**
* Returns true if this BatchImaMatchStatus indicates that the given record has an associated
* {@link ReportMatchStatus}.
*
* @param record the IMAMeasurementRecord to consider
* @param matchStatus the match status to find for the given record
* @return true if the given matchStatus was found associated with the given record;
* false otherwise
*/
private boolean foundMatchStatusForRecord(final IMAMeasurementRecord record,
final ReportMatchStatus matchStatus) {
Preconditions.checkArgument(contains(record), "No match status stored for this record.");
for (IMAMatchStatus<T> status : getIMAMatchStatuses(record)) {
if (status.getStatus().equals(matchStatus)) {
return true;
}
}
return false;
}
/**
* Returns true if this BatchImaMatchStatus indicates that an actual (path &amp; hash) match was
* found for the given {@link IMAMeasurementRecord}. Not mutually exclusive
* with the other 'found' methods.
*
* @param record the IMAMeasurementRecord to consider
* @return true if there an actual (path &amp; hash) match was found, false otherwise
*/
public boolean foundMatch(final IMAMeasurementRecord record) {
return foundMatchStatusForRecord(record, ReportMatchStatus.MATCH);
}
/**
* Returns true if this BatchImaMatchStatus indicates that a mismatch was found
* for the given {@link IMAMeasurementRecord} (matching path, but not hash.) Not mutually
* exclusive with the other 'found' methods.
*
* @param record the IMAMeasurementRecord to consider
* @return true if there a mismatch was found, false otherwise
*/
public boolean foundMismatch(final IMAMeasurementRecord record) {
return foundMatchStatusForRecord(record, ReportMatchStatus.MISMATCH);
}
/**
* Returns true if this BatchImaMatchStatus indicates that the given record produced only an
* UNKNOWN match status, and no matches or mismatches.
*
* @param record the IMAMeasurementRecord to consider
* @return true if relevant IMAMatchStatuses are UNKNOWN, false otherwise
*/
public boolean foundOnlyUnknown(final IMAMeasurementRecord record) {
Preconditions.checkArgument(contains(record), "No match status stored for this record.");
for (IMAMatchStatus<T> status : getIMAMatchStatuses(record)) {
if (!status.getStatus().equals(ReportMatchStatus.UNKNOWN)) {
return false;
}
}
return true;
}
/**
* Retrieves all IMA baseline records held in this instance whose file paths match the given
* record. If the second parameter is non-null, only matches with the given match status will
* be returned. If the second parameter is null, all matching records will be returned.
*
* @param record the record whose paths should be considered when retrieving IMA baseline
* records that have matching file paths
* @param reportMatchStatus if non-null, only IMA baseline records that are of the given match
* type will be returned (this is only useful for MATCH and MISMATCH.) If
* null, both matching and mismatching baseline records will be returned.
* @return a set of all matching IMABaselineRecords
*/
private Set<T> getBaselineRecords(
final IMAMeasurementRecord record,
final ReportMatchStatus reportMatchStatus) {
Preconditions.checkArgument(contains(record), "No match status stored for this record.");
HashSet<T> baselineRecords = new HashSet<>();
for (IMAMatchStatus<T> imaMatchStatus : getIMAMatchStatuses(record)) {
if (reportMatchStatus == null || imaMatchStatus.getStatus().equals(reportMatchStatus)) {
baselineRecords.addAll(imaMatchStatus.getBaselineRecords());
}
}
return baselineRecords;
}
/**
* Returns a Set of the IMABaselineRecords that are an actual match (path &amp; hash)
* of the given {@link IMAMeasurementRecord}.
*
* @param record the IMAMeasurementRecord to consider
* @return the Set of all records that have a MATCH to the given record; may be empty
*/
public Set<T> getMatchingBaselineRecords(final IMAMeasurementRecord record) {
return getBaselineRecords(record, ReportMatchStatus.MATCH);
}
/**
* Returns a Set of the IMABaselineRecords that are a mismatch with the given
* {@link IMAMeasurementRecord}.
*
* @param record the IMAMeasurementRecord to consider
* @return the Set of all records that have a MISMATCH to the given record; may be empty
*/
public Set<T> getMismatchingBaselineRecords(final IMAMeasurementRecord record) {
return getBaselineRecords(record, ReportMatchStatus.MISMATCH);
}
/**
* Returns a Set of the IMABaselineRecords matched or mismatched with the given record.
* {@link IMAMeasurementRecord}.
*
* @param record the IMAMeasurementRecord to consider
* @return the Set of all records that match or mismatch the given record
*/
public Set<T> getBaselineRecords(final IMAMeasurementRecord record) {
return getBaselineRecords(record, null);
}
/**
* Returns a Set containing all {@link IMAMeasurementRecord}s that were evaluated against a
* baseline in this instance.
*
* @return the set of all IMAMeasurementRecords in this instance
*/
public Set<IMAMeasurementRecord> getAppraisedMeasurementRecords() {
return Collections.unmodifiableSet(matchStatuses.keySet());
}
/**
* Gets a collection of all IMAMatchStatuses with a status of ReportMatchStatus.MATCH.
*
* @return matching IMAMatchStatuses
*/
public Collection<IMAMatchStatus<T>> getAllMatches() {
List<IMAMatchStatus<T>> matches = new ArrayList<>();
for (Map.Entry<IMAMeasurementRecord, Set<IMAMatchStatus<T>>> e : matchStatuses.entrySet()) {
for (IMAMatchStatus<T> matchStatus : e.getValue()) {
if (matchStatus.getStatus().equals(ReportMatchStatus.MATCH)) {
matches.add(matchStatus);
}
}
}
return matches;
}
/**
* This method indicates whether or not the given {@link IMAMeasurementRecord} has one
* or more recorded match statuses in this instance.
*
* @param record the record whose presence will be determined
* @return true if this object contains results related to the given record; false otherwise
*/
public boolean contains(final IMAMeasurementRecord record) {
return matchStatuses.containsKey(record);
}
private Set<IMAMatchStatus<T>> getMatchStatuses() {
Set<IMAMatchStatus<T>> matchSet = new HashSet<>();
for (Map.Entry<IMAMeasurementRecord, Set<IMAMatchStatus<T>>> e : matchStatuses.entrySet()) {
matchSet.addAll(e.getValue());
}
return matchSet;
}
/**
* Given another BatchImaMatchStatus, merge its match statuses into this instance. Useful in
* collecting match results from multiple baselines.
*
* @param other the other BatchImaMatchStatus whose results should be merged into this instance
*/
public void merge(final BatchImaMatchStatus<T> other) {
for (IMAMatchStatus<T> match : other.getMatchStatuses()) {
add(match);
}
}
@Override
public boolean equals(final Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
BatchImaMatchStatus that = (BatchImaMatchStatus) o;
return Objects.equals(matchStatuses, that.matchStatuses);
}
@Override
public int hashCode() {
return Objects.hash(matchStatuses);
}
@Override
public String toString() {
return "BatchImaMatchStatus{"
+ "matchStatuses=" + matchStatuses
+ '}';
}
}

View File

@ -1,184 +0,0 @@
package hirs.ima.matching;
import hirs.data.persist.baseline.Baseline;
import hirs.data.persist.IMAMeasurementRecord;
import hirs.data.persist.baseline.AbstractImaBaselineRecord;
import hirs.data.persist.baseline.ImaBaseline;
import hirs.data.persist.enums.ReportMatchStatus;
import java.util.Collections;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
/**
* This represents the match status for when an <code>ImaBaseline</code> tests
* if an <code>IMAMeasurementRecord</code> is contained in it. This contains the
* <code>ReportMatchStatus</code> as well as a set of records.
* <p>
* The set of records has different meanings depending upon the return value.
* If the match status return MATCH then the list contains all of the matching
* entries. If partial path support is disabled then this can only return one
* entry. If partial path is enabled then this can return multiple matches,
* consider /usr/bin/gradle and /home/foo/bin/gradle as an example.
* <p>
* If the report status is a mismatch then this returns the set of baseline
* records that have the same path but a different hash. This can happen if
* multiple values are acceptable for a file. This can also happen if partial
* path is enabled and different files have the same name but in different
* directories.
* <p>
* If the report status is unknown then the set is empty.
*
* @param <T> the type of IMA baseline record that this class matches against
*/
public final class IMAMatchStatus<T extends AbstractImaBaselineRecord> {
private ReportMatchStatus status;
private IMAMeasurementRecord recordToMatch;
private HashSet<T> baselineRecords; // these should all be from the same baseline
private ImaBaseline baseline;
/**
* Convenience constructor for an UNKNOWN match status. This creates
* a new <code>IMAMatchStatus</code> that must have a status of
* UNKNOWN. If not UNKNOWN then an Exception will be thrown. The set of
* records is initialized to an empty list.
*
* @param recordToMatch the record associated with this match status
* @param status must be UNKNOWN
* @param baseline the baseline from which this match originated
*/
public IMAMatchStatus(final IMAMeasurementRecord recordToMatch,
final ReportMatchStatus status,
final ImaBaseline baseline) {
this(recordToMatch, status, new HashSet<T>(), baseline);
}
/**
* Convenience constructor for creating a match status that only has one
* record. The record can only be null if status is UNKNOWN. In that case an
* empty set is created. Otherwise it cannot be null and the status must be
* either MATCH or MISMATCH.
*
* @param recordToMatch the record associated with this match status
* @param status status
* @param record record (can be null if status is UNKNOWN)
* @param baseline the baseline from which this match originated
*/
public IMAMatchStatus(
final IMAMeasurementRecord recordToMatch,
final ReportMatchStatus status,
final T record,
final ImaBaseline baseline) {
this(recordToMatch, status, Collections.singleton(record), baseline);
}
/**
* Creates a new <code>IMAMatchStatus</code>. If status is MATCH or
* MISMATCH then the records set cannot be empty. Else the records set
* must be empty.
*
* @param recordToMatch the record associated with this match status
* @param status match status
* @param baselineRecords records
* @param baseline the baseline from which this match originated
*/
public IMAMatchStatus(
final IMAMeasurementRecord recordToMatch,
final ReportMatchStatus status,
final Set<T> baselineRecords,
final ImaBaseline baseline) {
if (recordToMatch == null) {
throw new IllegalArgumentException("Cannot have a null IMAMeasurementRecord.");
}
if (status == null) {
throw new IllegalArgumentException("Cannot have a null match status.");
}
if (baselineRecords == null) {
throw new IllegalArgumentException("Cannot have null baseline records.");
}
if (baseline == null) {
throw new IllegalArgumentException("Cannot have a null baseline.");
}
if (status == ReportMatchStatus.UNKNOWN && baselineRecords.size() > 0) {
throw new IllegalArgumentException("Cannot have an unknown status with associated"
+ "baseline records.");
}
if (status != ReportMatchStatus.UNKNOWN && baselineRecords.size() == 0) {
throw new IllegalArgumentException("Cannot have a match or mismatch status without"
+ "associated baseline records.");
}
this.recordToMatch = recordToMatch;
this.status = status;
this.baselineRecords = new HashSet<>(baselineRecords);
this.baseline = baseline;
}
/**
* Returns the match status as to whether or not the record was found.
*
* @return match status
*/
public ReportMatchStatus getStatus() {
return status;
}
/**
* Returns the records associated with the match status. See the class
* JavaDocs for a complete description of what to expect in the set.
*
* @return records
*/
public Set<T> getBaselineRecords() {
return Collections.unmodifiableSet(baselineRecords);
}
/**
* Returns the record for which matches were either found or not found.
*
* @return the record that has been matched (or not)
*/
public IMAMeasurementRecord getRecordToMatch() {
return recordToMatch;
}
/**
* Return the <code>Baseline</code> used to generate this match status.
*
* @return baseline used to generate status
*/
public Baseline getBaseline() {
return baseline;
}
@Override
public boolean equals(final Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
IMAMatchStatus<?> that = (IMAMatchStatus<?>) o;
return status == that.status
&& Objects.equals(recordToMatch, that.recordToMatch)
&& Objects.equals(baselineRecords, that.baselineRecords)
&& Objects.equals(baseline, that.baseline);
}
@Override
public int hashCode() {
return Objects.hash(status, recordToMatch, baselineRecords, baseline);
}
@Override
public String toString() {
return "IMAMatchStatus{"
+ "status=" + status
+ ", recordToMatch=" + recordToMatch
+ ", baselineRecords=" + baselineRecords
+ ", baseline=" + baseline
+ '}';
}
}

View File

@ -1,59 +0,0 @@
package hirs.ima.matching;
import com.google.common.base.Preconditions;
import hirs.data.persist.baseline.IMABaselineRecord;
import hirs.data.persist.IMAMeasurementRecord;
import hirs.data.persist.IMAPolicy;
import hirs.data.persist.baseline.ImaBaseline;
import hirs.data.persist.enums.ReportMatchStatus;
import java.util.Collection;
import java.util.Set;
/**
* This class extends the base matching functionality of {@link ImaRecordMatcher} to
* compare {@link IMAMeasurementRecord}s against a collection of {@link IMABaselineRecord}s
* based solely on their hashes.
*/
public class ImaAcceptableHashRecordMatcher extends ImaRecordMatcher<IMABaselineRecord> {
/**
* Construct a new ImaAcceptablePathAndHashRecordMatcher.
*
* @param records the baseline records to use for matching
* @param imaPolicy the IMA policy to reference during matching; its partial path and path
* equivalence settings influence matching behavior
* @param imaBaseline the IMA baseline these records were sourced from; this is only used to
*/
public ImaAcceptableHashRecordMatcher(
final Collection<IMABaselineRecord> records,
final IMAPolicy imaPolicy,
final ImaBaseline imaBaseline) {
super(records, imaPolicy, imaBaseline);
}
/**
* Returns an IMAMatchStatus indicating whether the given {@link IMAMeasurementRecord} is
* contained within the originally provided {@link IMABaselineRecord}s.
*
* @param record the record to look up
* @return an IMAMatchStatus indicating whether the record is a match or unknown to
* the given baseline records
*/
@Override
public IMAMatchStatus<IMABaselineRecord> contains(final IMAMeasurementRecord record) {
Preconditions.checkArgument(record != null, "Cannot match on null record.");
final Set<IMABaselineRecord> matchingRecords = getRelatedBaselineRecordsByHash(record);
if (matchingRecords.isEmpty()) {
return new IMAMatchStatus<>(record, ReportMatchStatus.UNKNOWN, getImaBaseline());
}
return new IMAMatchStatus<>(
record,
ReportMatchStatus.MATCH,
matchingRecords,
getImaBaseline()
);
}
}

View File

@ -1,106 +0,0 @@
package hirs.ima.matching;
import com.google.common.base.Preconditions;
import hirs.data.persist.enums.DigestComparisonResultType;
import hirs.data.persist.baseline.IMABaselineRecord;
import hirs.data.persist.IMAMeasurementRecord;
import hirs.data.persist.IMAPolicy;
import hirs.data.persist.baseline.ImaBaseline;
import hirs.data.persist.enums.ReportMatchStatus;
import org.apache.logging.log4j.Logger;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import static org.apache.logging.log4j.LogManager.getLogger;
/**
* This class extends the base matching functionality of {@link ImaRecordMatcher} to
* compare {@link IMAMeasurementRecord}s against a collection of {@link IMABaselineRecord}s
* based on both their paths and hashes.
*/
public class ImaAcceptablePathAndHashRecordMatcher extends ImaRecordMatcher<IMABaselineRecord> {
private static final Logger LOGGER = getLogger(ImaAcceptablePathAndHashRecordMatcher.class);
/**
* Construct a new ImaAcceptablePathAndHashRecordMatcher.
*
* @param records the baseline records to use for matching
* @param imaPolicy the IMA policy to reference during matching; its partial path and path
* equivalence settings influence matching behavior
* @param imaBaseline the IMA baseline these records were sourced from; this is only used to
*/
public ImaAcceptablePathAndHashRecordMatcher(
final Collection<IMABaselineRecord> records,
final IMAPolicy imaPolicy,
final ImaBaseline imaBaseline) {
super(records, imaPolicy, imaBaseline);
}
/**
* Returns an IMAMatchStatus indicating whether the given {@link IMAMeasurementRecord} is
* contained within the originally provided {@link IMABaselineRecord}s.
*
* @param record the record to look up
* @return an IMAMatchStatus indicating whether the record is a match, mismatch, or unknown to
* the given baseline records
*/
@Override
public IMAMatchStatus<IMABaselineRecord> contains(final IMAMeasurementRecord record) {
Preconditions.checkArgument(record != null, "Cannot match on null record.");
final Set<IMABaselineRecord> matchRecords = new HashSet<>();
final Set<IMABaselineRecord> mismatchRecords = new HashSet<>();
final Collection<IMABaselineRecord> matchingRecords = getRelatedBaselineRecordsByPath(
record
);
for (IMABaselineRecord baselineRecord : matchingRecords) {
compareDigestsAndPopulateMatchLists(
baselineRecord, record, matchRecords, mismatchRecords
);
}
if (matchRecords.isEmpty() && mismatchRecords.isEmpty()) {
return new IMAMatchStatus<>(record, ReportMatchStatus.UNKNOWN, getImaBaseline());
}
if (matchRecords.isEmpty()) {
return new IMAMatchStatus<>(
record, ReportMatchStatus.MISMATCH, mismatchRecords, getImaBaseline()
);
}
return new IMAMatchStatus<>(
record,
ReportMatchStatus.MATCH,
matchRecords,
getImaBaseline()
);
}
private static void compareDigestsAndPopulateMatchLists(
final IMABaselineRecord baselineRecord,
final IMAMeasurementRecord measurementRecord,
final Set<IMABaselineRecord> matchRecords,
final Set<IMABaselineRecord> mismatchRecords) {
DigestComparisonResultType comparison =
measurementRecord.getHash().compare(baselineRecord.getHash());
switch (comparison) {
case MATCH:
matchRecords.add(baselineRecord);
break;
case MISMATCH:
mismatchRecords.add(baselineRecord);
break;
default:
LOGGER.warn("{} comparison result when comparing {} with {}.",
comparison, baselineRecord, measurementRecord);
break;
}
}
}

View File

@ -1,101 +0,0 @@
package hirs.ima.matching;
import hirs.data.persist.IMAMeasurementRecord;
import hirs.data.persist.IMAPolicy;
import hirs.data.persist.baseline.ImaBaseline;
import hirs.data.persist.ImaBlacklistRecord;
import hirs.data.persist.enums.AlertType;
import hirs.data.persist.enums.ReportMatchStatus;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
/**
* This class extends the base matching functionality of {@link ImaRecordMatcher} to
* compare {@link IMAMeasurementRecord}s against a collection of {@link ImaBlacklistRecord}s.
*/
public class ImaBlacklistRecordMatcher extends ImaRecordMatcher<ImaBlacklistRecord> {
/**
* Construct a new ImaBlacklistRecordMatcher.
*
* @param records the baseline records to use for matching
* @param imaPolicy the IMA policy to reference during matching; its partial path and path
* equivalence settings influence matching behavior
* @param imaBaseline the IMA baseline these records were sourced from; this is only used to
*/
public ImaBlacklistRecordMatcher(
final Collection<ImaBlacklistRecord> records,
final IMAPolicy imaPolicy,
final ImaBaseline imaBaseline) {
super(records, imaPolicy, imaBaseline);
}
/**
* Returns an IMAMatchStatus indicating whether the given {@link IMAMeasurementRecord} is
* contained within the originally provided {@link ImaBlacklistRecord}s.
*
* @param record the record to look up
* @return an IMAMatchStatus indicating whether the record is a match, mismatch, or unknown to
* the given baseline records
*/
public IMAMatchStatus<ImaBlacklistRecord> contains(final IMAMeasurementRecord record) {
if (record == null) {
throw new IllegalArgumentException("Cannot match on null record.");
}
final Set<ImaBlacklistRecord> matchesByPath = getRelatedBaselineRecordsByPath(record);
final Set<ImaBlacklistRecord> matchesByHash = getRelatedBaselineRecordsByHash(record);
final Set<ImaBlacklistRecord> matchingRecords = new HashSet<>();
for (ImaBlacklistRecord blacklistRecord : matchesByPath) {
if (blacklistRecord.getHash() == null || matchesByHash.contains(blacklistRecord)) {
matchingRecords.add(blacklistRecord);
}
}
for (ImaBlacklistRecord blacklistRecord : matchesByHash) {
if (blacklistRecord.getPath() == null || matchesByPath.contains(blacklistRecord)) {
matchingRecords.add(blacklistRecord);
}
}
if (matchingRecords.isEmpty()) {
return new IMAMatchStatus<>(record, ReportMatchStatus.UNKNOWN, getImaBaseline());
} else {
return new IMAMatchStatus<>(
record,
ReportMatchStatus.MATCH,
matchingRecords,
getImaBaseline()
);
}
}
/**
* Return the type of IMA blacklist alert that should be generated from the given list
* of blacklist matches. If all matches are of a single type, it will return the type of alert
* as given by {@link ImaBlacklistRecord#getAlertMatchType()}. Otherwise, it will return
* <code>Alert.AlertType.IMA_BLACKLIST_MIXED_MATCH</code>.
*
* @param blacklistMatches the list of matches
* @return the relevant alert type
*/
public static AlertType getBlacklistAlertType(
final Set<IMAMatchStatus<ImaBlacklistRecord>> blacklistMatches) {
AlertType type = null;
for (IMAMatchStatus<ImaBlacklistRecord> match : blacklistMatches) {
for (ImaBlacklistRecord blacklistRecord : match.getBaselineRecords()) {
if (type == null) {
type = blacklistRecord.getAlertMatchType();
} else {
if (type != blacklistRecord.getAlertMatchType()) {
return AlertType.IMA_BLACKLIST_MIXED_MATCH;
}
}
}
}
return type;
}
}

View File

@ -1,86 +0,0 @@
package hirs.ima.matching;
import hirs.data.persist.IMAMeasurementRecord;
import hirs.data.persist.IMAPolicy;
import hirs.data.persist.baseline.ImaBaseline;
import hirs.data.persist.ImaIgnoreSetRecord;
import hirs.data.persist.enums.ReportMatchStatus;
import hirs.utils.RegexFilePathMatcher;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* This class extends the base matching functionality of {@link ImaRecordMatcher} to
* compare {@link IMAMeasurementRecord}s against a collection of {@link ImaIgnoreSetRecord}s.
*/
public class ImaIgnoreSetRecordMatcher extends ImaRecordMatcher<ImaIgnoreSetRecord> {
private Map<ImaIgnoreSetRecord, RegexFilePathMatcher> matchers = new HashMap<>();
/**
* Construct a new ImaBlacklistRecordMatcher.
*
* @param records the baseline records to use for matching
* @param imaPolicy the IMA policy to reference during matching; its partial path and path
* equivalence settings influence matching behavior
* @param imaBaseline the IMA baseline these records were sourced from; this is only used to
*/
public ImaIgnoreSetRecordMatcher(
final Collection<ImaIgnoreSetRecord> records,
final IMAPolicy imaPolicy,
final ImaBaseline imaBaseline) {
super(records, imaPolicy, imaBaseline);
for (ImaIgnoreSetRecord ignoreRecord : records) {
matchers.put(ignoreRecord, new RegexFilePathMatcher(ignoreRecord.getPath()));
}
}
/**
* Returns an IMAMatchStatus indicating whether the given {@link IMAMeasurementRecord} is
* contained within the originally provided {@link ImaIgnoreSetRecord}s.
*
* A measurement record's path will match this ignore set in the following cases:
* <p>&nbsp;
* <ul>
* <li>if any of of the ignore set records contain a regex that matches the given path</li>
* <li>if any of of the ignore set records are an exact match with the given path</li>
* <li>if any of of the ignore set records are the initial substring of the given path</li>
* <li>if any of of the ignore set records are partial paths and the given path is a full path
* with the same filename</li>
* <li>if the given path is a partial path and any of of the ignore set records are full paths
* with the same filename</li>
* </ul>
*
* @param record the record to look up
* @return an IMAMatchStatus indicating whether the record is a match, mismatch, or unknown to
* the given baseline records
*/
public IMAMatchStatus<ImaIgnoreSetRecord> contains(final IMAMeasurementRecord record) {
if (record == null) {
throw new IllegalArgumentException("Cannot match on null record.");
}
Set<ImaIgnoreSetRecord> matchingRecords = getRelatedBaselineRecordsByPath(record);
for (Map.Entry<ImaIgnoreSetRecord, RegexFilePathMatcher> recordMatcher
: matchers.entrySet()) {
if (recordMatcher.getValue().isMatch(record.getPath())) {
matchingRecords.add(recordMatcher.getKey());
}
}
if (matchingRecords.isEmpty()) {
return new IMAMatchStatus<>(record, ReportMatchStatus.UNKNOWN, getImaBaseline());
} else {
return new IMAMatchStatus<>(
record,
ReportMatchStatus.MATCH,
matchingRecords,
getImaBaseline()
);
}
}
}

View File

@ -1,211 +0,0 @@
package hirs.ima.matching;
import com.google.common.collect.ImmutableListMultimap;
import com.google.common.collect.Multimap;
import hirs.data.persist.Digest;
import hirs.data.persist.baseline.IMABaselineRecord;
import hirs.data.persist.IMAMeasurementRecord;
import hirs.data.persist.IMAPolicy;
import hirs.data.persist.baseline.AbstractImaBaselineRecord;
import hirs.data.persist.baseline.ImaBaseline;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* This class contains the logic used to match IMA measurement records against
* IMA baseline records. Given a collection of IMABaselineRecords, an IMAPolicy,
* and an ImaBaseline, it is able to determine which measurement records should be considered
* matches, mismatches, or unknown to the given set of baseline records.
*
* @param <T> the type of IMA baseline record that this class matches against
*/
public abstract class ImaRecordMatcher<T extends AbstractImaBaselineRecord> {
private final IMAPolicy imaPolicy;
private final ImaBaseline imaBaseline;
private final Collection<T> records;
// lookup maps
private Multimap<String, T> pathMap = null;
private Multimap<String, T> hashMap = null;
/**
* Construct a new IMARecordMatcher.
*
* @param records the baseline records to use for matching
* @param imaPolicy the IMA policy to reference during matching; its partial path and path
* equivalence settings influence matching behavior
* @param imaBaseline the IMA baseline these records were sourced from; this is only used to
* record references to mismatched records
*/
public ImaRecordMatcher(
final Collection<T> records,
final IMAPolicy imaPolicy,
final ImaBaseline imaBaseline) {
this.records = records;
this.imaPolicy = imaPolicy;
this.imaBaseline = imaBaseline;
}
/**
* Retrieve the baseline associated with this record matcher.
*
* @return the associated IMA baseline
*/
protected ImaBaseline getImaBaseline() {
return this.imaBaseline;
}
/**
* Returns an IMAMatchStatus indicating whether the given {@link IMAMeasurementRecord} is
* contained within the originally provided baseline records.
*
* @param record the record to look up
* @return an IMAMatchStatus indicating whether the record is a match, mismatch, or unknown to
* the given baseline records
*/
public abstract IMAMatchStatus<T> contains(IMAMeasurementRecord record);
/**
* Given a collection of measurement records, populate and return a BatchImaMatchStatus
* instance containing the match results according to this ImaRecordMatcher's matching
* behavior and the given IMA policy, baseline, and baseline records.
*
* @param records the measurement records to match to baseline records
* @return a BatchImaMatchStatus containing the match status of all the given records
*/
public BatchImaMatchStatus<T> batchMatch(final Collection<IMAMeasurementRecord> records) {
List<IMAMatchStatus<T>> matchStatuses = new ArrayList<>();
for (IMAMeasurementRecord record : records) {
matchStatuses.add(contains(record));
}
return new BatchImaMatchStatus<>(matchStatuses);
}
/**
* Gets all IMA baseline records that are related to the given IMA measurement record
* as determined by path similarity or equivalency. This method respects the IMA policy
* that was given at construction time with respect to partial path matching.
*
* @param record the record for which all matching IMA baseline records should be returned
* @return the resulting set of IMA baseline records
*/
protected Set<T> getRelatedBaselineRecordsByPath(final IMAMeasurementRecord record) {
if (record == null) {
throw new IllegalArgumentException("Cannot match on null record.");
}
if (pathMap == null) {
pathMap = createPathMap(this.records);
}
final Set<T> matchingRecords = new HashSet<>();
matchingRecords.addAll(pathMap.get(record.getPath()));
if (imaPolicy.isPartialPathEnable() && isFullPath(record.getPath())) {
for (T matchingPartialRecord
: pathMap.get(IMABaselineRecord.getPartialPath(record.getPath()))) {
// ensure that we're not about to match two unequal full paths
if (isFullPath(matchingPartialRecord.getPath())
&& !matchingPartialRecord.getPath().equals(record.getPath())) {
continue;
} else {
matchingRecords.add(matchingPartialRecord);
}
}
}
return matchingRecords;
}
/**
* Gets all IMA baseline records that are related to the given IMA measurement record
* as determined by their hash values.
*
* @param record the record for which all matching IMA baseline records should be returned
* @return the resulting set of IMA baseline records
*/
protected Set<T> getRelatedBaselineRecordsByHash(final IMAMeasurementRecord record) {
if (record == null) {
throw new IllegalArgumentException("Cannot match on null record.");
}
if (hashMap == null) {
hashMap = createHashMap(this.records);
}
return new HashSet<>(hashMap.get(record.getHash().toString()));
}
private Multimap<String, T> createPathMap(
final Collection<T> imaBaselineRecords) {
ImmutableListMultimap.Builder<String, T> mapBuilder =
ImmutableListMultimap.builder();
for (T record : imaBaselineRecords) {
if (record.getPath() != null) {
for (String matchingPath : getMatchingPaths(imaPolicy, record.getPath())) {
mapBuilder.put(matchingPath, record);
}
}
}
return mapBuilder.build();
}
private Multimap<String, T> createHashMap(
final Collection<T> imaBaselineRecords) {
ImmutableListMultimap.Builder<String, T> mapBuilder =
ImmutableListMultimap.builder();
for (T record : imaBaselineRecords) {
Digest hash = record.getHash();
if (hash != null) {
mapBuilder.put(hash.toString(), record);
}
}
return mapBuilder.build();
}
/**
* Calculates all paths that should be considered as 'matching' the given path, according to
* the given IMAPolicy, including the original path itself. For instance, if partial paths are
* enabled, the path's filename will be included in the returned collection. Additionally, if
* the IMA policy is configured with equivalent paths, these are evaluated against the given
* path and any relevant permutations are returned as well.
*
* @param imaPolicy the IMAPolicy to use in calculating matching paths
* @param targetPath the original path whose matching paths will calculated and returned
* @return a collection of paths that this IMAPolicy would consider as matching the path
*/
public static Collection<String> getMatchingPaths(
final IMAPolicy imaPolicy,
final String targetPath) {
Multimap<String, String> pathEquivalences = imaPolicy.getPathEquivalences();
Set<String> pathsToFind = new HashSet<>();
pathsToFind.add(targetPath);
for (String path : pathEquivalences.keySet()) {
if (targetPath.startsWith(path)) {
for (String equivalentPath : pathEquivalences.get(path)) {
pathsToFind.add(targetPath.replaceFirst(path, equivalentPath));
}
}
}
if (imaPolicy.isPartialPathEnable() && isFullPath(targetPath)) {
pathsToFind.add(IMABaselineRecord.getPartialPath(targetPath));
}
return pathsToFind;
}
private static boolean isFullPath(final String path) {
return path.startsWith("/");
}
}

View File

@ -1,4 +0,0 @@
/**
* Contains classes related to matching IMA measurement records against IMA baseline records.
*/
package hirs.ima.matching;

View File

@ -1,6 +0,0 @@
/**
* Non-persistant classes related to IMA.
*/
package hirs.ima;

View File

@ -56,14 +56,14 @@ import static org.hibernate.criterion.Restrictions.sqlRestriction;
* This class exists primarily to reduce code in {@link DBManager} which retries these methods
* using a RetryTemplate.
*
* @param <T> type of objects to manage by this manager
* @param <AbstractEntity> type of objects to manage by this manager
*/
public abstract class AbstractDbManager<T> implements CrudManager<T> {
public abstract class AbstractDbManager<AbstractEntity> implements CrudManager<AbstractEntity> {
private static final Logger LOGGER = LogManager.getLogger(AbstractDbManager.class);
private static final int MAX_CLASS_CACHE_ENTRIES = 500;
private final Class<T> clazz;
private final AbstractEntity entity;
private SessionFactory factory;
@ -74,8 +74,8 @@ public abstract class AbstractDbManager<T> implements CrudManager<T> {
* unfortunately class type of T cannot be determined using only T
* @param sessionFactory the session factory to use to interact with the database
*/
public AbstractDbManager(final Class<T> clazz, final SessionFactory sessionFactory) {
if (clazz == null) {
public AbstractDbManager(final AbstractEntity entity, final SessionFactory sessionFactory) {
if (entity == null) {
LOGGER.error("AbstractDbManager cannot be instantiated with a null class");
throw new IllegalArgumentException(
"AbstractDbManager cannot be instantiated with a null class"
@ -87,26 +87,24 @@ public abstract class AbstractDbManager<T> implements CrudManager<T> {
"AbstractDbManager cannot be instantiated with a null SessionFactory"
);
}
this.clazz = clazz;
this.entity = entity;
this.factory = sessionFactory;
}
private static final LoadingCache<Class, Set<Field>> PERSISTED_FIELDS =
private static final LoadingCache<AbstractEntity, Set<Field>> PERSISTED_FIELDS =
CacheBuilder.newBuilder()
.maximumSize(MAX_CLASS_CACHE_ENTRIES)
.build(
new CacheLoader<Class, Set<Field>>() {
.build(new CacheLoader<AbstractEntity, Set<Field>>() {
@Override
public Set<Field> load(final Class clazz) throws Exception {
return getPersistedFields(clazz);
public Set<Field> load(final AbstractEntity entity) throws Exception {
return getPersistedFields(entity);
}
}
);
});
private static Set<Field> getPersistedFields(final Class clazz) {
private static Set<Field> getPersistedFields(final AbstractEntity entity) {
Set<Field> fields = new HashSet<>();
for (Field f : clazz.getDeclaredFields()) {
for (Field f : entity.getDeclaredFields()) {
if (f.isAnnotationPresent(OneToMany.class)
|| f.isAnnotationPresent(ManyToMany.class)
|| f.isAnnotationPresent(ManyToOne.class)
@ -116,8 +114,8 @@ public abstract class AbstractDbManager<T> implements CrudManager<T> {
}
}
if (clazz.getSuperclass() != Object.class) {
fields.addAll(getPersistedFields(clazz.getSuperclass()));
if (entity.getSuperclass() != Object.class) {
fields.addAll(getPersistedFields(entity.getSuperclass()));
}
return fields;
@ -205,9 +203,9 @@ public abstract class AbstractDbManager<T> implements CrudManager<T> {
try {
LOGGER.debug("retrieving object from db");
tx = session.beginTransaction();
Object o = session.get(clazz, id);
if (o != null && clazz.isInstance(o)) {
T objectOfTypeT = clazz.cast(o);
Object obj = session.get(entity, id);
if (obj instanceof AbstractEntity) {
AbstractEntity objectOfTypeT = (AbstractEntity) obj;
LOGGER.debug("found object, deleting it");
session.delete(objectOfTypeT);
deleted = true;
@ -250,16 +248,16 @@ public abstract class AbstractDbManager<T> implements CrudManager<T> {
Transaction tx = null;
Session session = factory.getCurrentSession();
CriteriaBuilder builder = session.getCriteriaBuilder();
CriteriaQuery<T> criteria = builder.createQuery(clazz);
CriteriaQuery<AbstractEntity> criteria = builder.createQuery(entity);
try {
LOGGER.debug("retrieving object from db");
tx = session.beginTransaction();
Root<T> myObjectRoot = criteria.from(clazz);
Join<T, JoinObject> joinObject = myObjectRoot.join("joinObject");
Root<AbstractEntity> myObjectRoot = criteria.from(clazz);
Join<AbstractEntity, JoinObject> joinObject = myObjectRoot.join("joinObject");
Object object = session.getSessionFactory().getCurrentSession().createCriteria(clazz)
.add(Restrictions.eq("name", name)).uniqueResult();
if (object != null && clazz.isInstance(object)) {
T objectOfTypeT = clazz.cast(object);
if (object instanceof AbstractEntity) {
AbstractEntity objectOfTypeT = (AbstractEntity) object;
LOGGER.debug("found object, deleting it");
session.delete(objectOfTypeT);
deleted = true;
@ -289,7 +287,7 @@ public abstract class AbstractDbManager<T> implements CrudManager<T> {
* @throws DBManagerException if unable to find the baseline or delete it
* from the database
*/
protected boolean doDelete(final T object) throws DBManagerException {
protected boolean doDelete(final AbstractEntity object) throws DBManagerException {
LOGGER.debug("deleting object: {}", object);
if (object == null) {
LOGGER.debug("null object argument");
@ -329,14 +327,14 @@ public abstract class AbstractDbManager<T> implements CrudManager<T> {
LOGGER.debug("Deleting instances of class: {}", clazz);
tx = session.beginTransaction();
CriteriaBuilder builder = session.getCriteriaBuilder();
CriteriaQuery<T> criteriaQuery = builder.createQuery(clazz);
Root<T> root = criteriaQuery.from(clazz);
CriteriaQuery<AbstractEntity> criteriaQuery = builder.createQuery(clazz);
Root<AbstractEntity> root = criteriaQuery.from(clazz);
Predicate recordPredicate = builder.and(
);
criteriaQuery.select(root).where(recordPredicate);
Query<T> query = session.createQuery(criteriaQuery);
List<T> results = query.getResultList();
T ret = null;
Query<AbstractEntity> query = session.createQuery(criteriaQuery);
List<AbstractEntity> results = query.getResultList();
AbstractEntity ret = null;
if (results != null && !results.isEmpty()) {
ret = results.get(0);
}
@ -344,8 +342,8 @@ public abstract class AbstractDbManager<T> implements CrudManager<T> {
List instances = session.createCriteria(clazz)
.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY).list();
for (Object instance : instances) {
if (instance != null && clazz.isInstance(instance)) {
session.delete(clazz.cast(instance));
if (instance instanceof AbstractEntity) {
session.delete((AbstractEntity) instance);
numEntitiesDeleted++;
}
}
@ -372,16 +370,16 @@ public abstract class AbstractDbManager<T> implements CrudManager<T> {
* @throws DBManagerException if an error is encountered while performing the query or creating
* the result objects
*/
protected List<T> doGetWithCriteria(final Collection<Criterion> criteriaCollection)
protected List<AbstractEntity> doGetWithCriteria(final Collection<Criterion> criteriaCollection)
throws DBManagerException {
return doGetWithCriteria(clazz, criteriaCollection);
return doGetWithCriteria(entity, criteriaCollection);
}
/**
* Runs a Criteria query using the given collection of Criterion over the
* associated class.
*
* @param <U> the specific type of class to retrieve
* @param <AbstractEntity> the specific type of class to retrieve
* (should extend this class' &lt;T&gt; parameter)
* @param clazzToGet the class of object to retrieve
* @param criteriaCollection the collection of Criterion to apply
@ -390,8 +388,8 @@ public abstract class AbstractDbManager<T> implements CrudManager<T> {
* @throws DBManagerException if an error is encountered while performing the query or creating
* the result objects
*/
protected final <U extends T> List<U> doGetWithCriteria(
final Class<U> clazzToGet,
protected final List<AbstractEntity> doGetWithCriteria(
final Class<AbstractEntity> clazzToGet,
final Collection<Criterion> criteriaCollection
) throws DBManagerException {
LOGGER.debug("running criteria query over: {}", clazzToGet);
@ -399,7 +397,7 @@ public abstract class AbstractDbManager<T> implements CrudManager<T> {
LOGGER.debug("null object argument");
throw new NullPointerException("criteria or restrictions");
}
List<U> ret = new ArrayList<>();
List<AbstractEntity> ret = new ArrayList<>();
Transaction tx = null;
Session session = factory.getCurrentSession();
try {
@ -439,7 +437,7 @@ public abstract class AbstractDbManager<T> implements CrudManager<T> {
* @throws DBManagerException if object has previously been saved or an
* error occurs while trying to save it to the database
*/
protected T doSave(final T object) throws DBManagerException {
protected AbstractEntity doSave(final AbstractEntity object) throws DBManagerException {
LOGGER.debug("saving object: {}", object);
if (object == null) {
LOGGER.debug("null object argument");
@ -454,7 +452,7 @@ public abstract class AbstractDbManager<T> implements CrudManager<T> {
final Serializable id = session.save(object);
Object o = session.get(object.getClass(), id);
session.getTransaction().commit();
return clazz.cast(o);
return (AbstractEntity) o;
} catch (Exception e) {
final String msg = "unable to save object";
LOGGER.error(msg, e);
@ -473,7 +471,7 @@ public abstract class AbstractDbManager<T> implements CrudManager<T> {
* @param object object to update
* @throws DBManagerException if unable to update the record
*/
protected void doUpdate(final T object) throws DBManagerException {
protected void doUpdate(final AbstractEntity object) throws DBManagerException {
LOGGER.debug("updating object");
if (object == null) {
LOGGER.debug("null object argument");
@ -508,7 +506,7 @@ public abstract class AbstractDbManager<T> implements CrudManager<T> {
* @throws DBManagerException if unable to search the database or recreate
* the <code>Object</code>
*/
protected T doGet(final String name) throws DBManagerException {
protected AbstractEntity doGet(final String name) throws DBManagerException {
LOGGER.debug("getting object: {}", name);
if (name == null) {
LOGGER.debug("null name argument");
@ -518,17 +516,17 @@ public abstract class AbstractDbManager<T> implements CrudManager<T> {
Transaction tx = null;
Session session = factory.getCurrentSession();
try {
LOGGER.debug("retrieving " + clazz.toString() + " from db");
LOGGER.debug("retrieving " + entity.toString() + " from db");
tx = session.beginTransaction();
CriteriaBuilder builder = session.getCriteriaBuilder();
CriteriaQuery<T> criteriaQuery = builder.createQuery(clazz);
Root<T> root = criteriaQuery.from(clazz);
CriteriaQuery<AbstractEntity> criteriaQuery = builder.createQuery(entity);
Root<AbstractEntity> root = criteriaQuery.from(entity);
Predicate recordPredicate = builder.and(
builder.equal(root.get("name"), name));
criteriaQuery.select(root).where(recordPredicate);
Query<T> query = session.createQuery(criteriaQuery);
List<T> results = query.getResultList();
T ret = null;
Query<AbstractEntity> query = session.createQuery(criteriaQuery);
List<AbstractEntity> results = query.getResultList();
AbstractEntity ret = null;
if (results != null && !results.isEmpty()) {
ret = results.get(0);
}
@ -557,7 +555,7 @@ public abstract class AbstractDbManager<T> implements CrudManager<T> {
* @throws DBManagerException if unable to search the database or recreate
* the <code>Object</code>
*/
protected T doGet(final Serializable id) throws DBManagerException {
protected AbstractEntity doGet(final Serializable id) throws DBManagerException {
LOGGER.debug("getting object: {}", id);
if (id == null) {
LOGGER.debug("null id argument");
@ -568,7 +566,7 @@ public abstract class AbstractDbManager<T> implements CrudManager<T> {
try {
LOGGER.debug("retrieving object from db");
tx = session.beginTransaction();
T ret = clazz.cast(session.get(clazz, id));
AbstractEntity ret = (AbstractEntity) session.get(entity, id);
tx.commit();
return ret;
} catch (Exception e) {
@ -645,7 +643,7 @@ public abstract class AbstractDbManager<T> implements CrudManager<T> {
* @throws DBManagerException if unable to search the database or recreate
* the <code>Object</code>
*/
protected T doGetAndLoadLazyFields(final String name, final boolean recurse)
protected AbstractEntity doGetAndLoadLazyFields(final String name, final boolean recurse)
throws DBManagerException {
LOGGER.debug("getting object: {}", name);
if (name == null) {
@ -656,17 +654,17 @@ public abstract class AbstractDbManager<T> implements CrudManager<T> {
Transaction tx = null;
Session session = factory.getCurrentSession();
try {
LOGGER.debug("retrieving " + clazz.toString() + " from db");
LOGGER.debug("retrieving " + entity.toString() + " from db");
tx = session.beginTransaction();
CriteriaBuilder builder = session.getCriteriaBuilder();
CriteriaQuery<T> criteriaQuery = builder.createQuery(clazz);
Root<T> root = criteriaQuery.from(clazz);
CriteriaQuery<AbstractEntity> criteriaQuery = builder.createQuery(entity);
Root<AbstractEntity> root = criteriaQuery.from(entity);
Predicate recordPredicate = builder.and(
builder.equal(root.get("name"), name));
criteriaQuery.select(root).where(recordPredicate);
Query<T> query = session.createQuery(criteriaQuery);
List<T> results = query.getResultList();
T ret = null;
Query<AbstractEntity> query = session.createQuery(criteriaQuery);
List<AbstractEntity> results = query.getResultList();
AbstractEntity ret = null;
if (results != null && !results.isEmpty()) {
ret = results.get(0);
}
@ -702,7 +700,7 @@ public abstract class AbstractDbManager<T> implements CrudManager<T> {
* @throws DBManagerException if unable to search the database or recreate
* the <code>Object</code>
*/
protected T doGetAndLoadLazyFields(final Serializable id, final boolean recurse)
protected AbstractEntity doGetAndLoadLazyFields(final Serializable id, final boolean recurse)
throws DBManagerException {
LOGGER.debug("getting object: {}", id);
if (id == null) {
@ -715,7 +713,7 @@ public abstract class AbstractDbManager<T> implements CrudManager<T> {
try {
LOGGER.debug("retrieving object from db");
tx = session.beginTransaction();
T ret = clazz.cast(session.get(clazz, id));
AbstractEntity ret = (AbstractEntity) session.get(entity, id);
doLoadLazyFields(ret, recurse);
tx.commit();
return ret;
@ -744,17 +742,17 @@ public abstract class AbstractDbManager<T> implements CrudManager<T> {
* @return list of <code>T</code> names
* @throws DBManagerException if unable to search the database
*/
protected List<T> doGetList(final Class<? extends T> clazz,
protected List<AbstractEntity> doGetList(final AbstractEntity entity,
final Criterion additionalRestriction)
throws DBManagerException {
LOGGER.debug("Getting object list");
Class<? extends T> searchClass = clazz;
if (clazz == null) {
LOGGER.debug("clazz is null");
searchClass = this.clazz;
AbstractEntity searchClass = entity;
if (entity == null) {
LOGGER.debug("entity is null");
searchClass = this.entity;
}
List<T> objects = new ArrayList<>();
List<AbstractEntity> objects = new ArrayList<>();
Transaction tx = null;
Session session = factory.getCurrentSession();
try {
@ -776,8 +774,8 @@ public abstract class AbstractDbManager<T> implements CrudManager<T> {
}
// List list = criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY).list();
for (Object o : results) {
if (searchClass.isInstance(o)) {
objects.add(searchClass.cast(o));
if (o instanceof AbstractEntity) {
objects.add((AbstractEntity) o);
}
}
tx.commit();
@ -814,12 +812,12 @@ public abstract class AbstractDbManager<T> implements CrudManager<T> {
* @throws DBManagerException if unable to create the list
*/
@SuppressWarnings("checkstyle:parameternumber")
protected FilteredRecordsList<T> doGetOrderedList(final Class<? extends T> clazz,
protected FilteredRecordsList<AbstractEntity> doGetOrderedList(final AbstractEntity clazz,
final String columnToOrder, final boolean ascending, final int firstResult,
final int maxResults, final String search, final Map<String, Boolean> searchableColumns,
final CriteriaModifier criteriaModifier) throws DBManagerException {
LOGGER.debug("Getting object list");
Class<? extends T> searchClass = clazz;
AbstractEntity searchClass = clazz;
if (clazz == null) {
LOGGER.debug("clazz is null");
searchClass = this.clazz;
@ -832,9 +830,9 @@ public abstract class AbstractDbManager<T> implements CrudManager<T> {
}
//Object that will store query values
FilteredRecordsList<T> aqr = new FilteredRecordsList<>();
FilteredRecordsList<AbstractEntity> aqr = new FilteredRecordsList<>();
List<T> objects = new ArrayList<>();
List<AbstractEntity> objects = new ArrayList<>();
Transaction tx = null;
Session session = factory.getCurrentSession();
try {

View File

@ -1,230 +0,0 @@
package hirs.persist;
import hirs.FilteredRecordsList;
import hirs.data.persist.Alert;
import hirs.data.persist.baseline.Baseline;
import hirs.data.persist.Device;
import hirs.data.persist.DeviceGroup;
import hirs.data.persist.Policy;
import hirs.data.persist.Report;
import hirs.data.persist.enums.AlertSource;
import org.hibernate.criterion.Criterion;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.UUID;
/**
* An <code>AlertManager</code> manages <code>Alert</code> objects. An
* <code>AlertManager</code> is used to store and manage alerts. It has support
* for the basic create and read methods. Update and delete are being discussed
* but will not be implemented at this time.
*/
public interface AlertManager {
/**
* Enumeration identify the type of list to return when querying for the ordered alert list.
*/
enum AlertListType {
/**
* List will contain only resolved alerts.
*/
RESOLVED_ALERTS,
/**
* List will contain only unresolved alerts.
*/
UNRESOLVED_ALERTS
}
/**
* Stores a new <code>Alert</code>. This stores a new
* <code>Alert</code> to be managed by the <code>AlertManager</code>.
* If the <code>Alert</code> is successfully saved then a reference to it
* is returned.
*
* @param alert
* Alert to save
* @return reference to saved Alert
* @throws AlertManagerException
* if the Alert has previously been saved or unexpected error
* occurs
*/
Alert saveAlert(Alert alert) throws AlertManagerException;
/**
* Updates all of the {@link Alert}s provided in the list.
*
* @param alerts list of alerts to be updated
* @return list of updated Alerts
* @throws AlertManagerException
* if unable to update the list of Alerts
*/
List<Alert> updateAlerts(List<Alert> alerts) throws AlertManagerException;
/**
* Returns a list of all <code>Alert</code>s managed by this manager.
*
* @return list of all managed <code>Alert</code> objects
* @throws AlertManagerException
* if unable to create the list
*/
List<Alert> getAlertList() throws AlertManagerException;
/**
* Retrieves the <code>Alert</code> identified by <code>name</code>. If
* the <code>Alert</code> cannot be found then null is returned.
*
* @param id
* id of the <code>Alert</code>
* @return <code>Alert</code> whose name is <code>name</code> or null if
* not found
* @throws AlertManagerException
* if unable to retrieve the Alert
*/
Alert getAlert(UUID id) throws AlertManagerException;
/**
* Returns a list of all <code>Alert</code>s that relate to the provided <code>Report</code>
* ID. The Alerts are ordered by a column and direction (ASC, DESC) that is provided by the
* user. The alerts can be filtered by begin and/or end date.
* This method helps support the server-side processing in the JQuery DataTables.
*
* @param reportId - ID of the Report to return Alerts from
* @param columnToOrder - Column to be ordered
* @param ascending - direction of sort
* @param firstResult starting point of first result in set
* @param maxResults total number we want returned for display in table
* @param search string of criteria to be matched to visible columns
* @param listType enumeration indicating if the returned list conatins resolved or
* unresolved alerts
* @param searchableColumns Map of String and boolean values with column
* headers and whether they are to. Boolean is true if field provides
* a typical String that can be searched by Hibernate without
* transformation.
* @param beginDate the earliest date of any alert returned from this method. Can be null.
* @param endDate the latest date of any alert returned from this method. Can be null.
* @return FilteredRecordsList object with fields for DataTables
* @throws AlertManagerException
* if unable to create the list
*/
@SuppressWarnings("checkstyle:parameternumber")
FilteredRecordsList<Alert> getOrderedAlertList(
String reportId, String columnToOrder, boolean ascending,
int firstResult, int maxResults, String search,
AlertListType listType,
Map<String, Boolean> searchableColumns, Date beginDate, Date endDate)
throws AlertManagerException;
/**
* Overloads the resolveAlerts method and provides a null description for the
* alert resolution.
*
* @param alerts - list of Alert objects to be marked as resolved
* @throws AlertManagerException
* if unable to save the list
*/
void resolveAlerts(List<Alert> alerts) throws AlertManagerException;
/**
* Marks all Alerts that are provided as arguments as resolved. This is used as
* a "soft delete" method and will ensure they no longer appear in the Alert
* table on the Portal.
*
* @param alerts - list of Alert objects to be marked as resolved
* @param description - description of action taken. The description can be null
* @throws AlertManagerException
* if unable to save the list
*/
void resolveAlerts(List<Alert> alerts, String description)
throws AlertManagerException;
/**
* Retrieves unresolved {@link Alert}s associated with the provided {@link Policy}.
*
* @param policy policy that is being evaluated
* @return list of unresolved alerts associated with {@link Policy}
* @throws AlertManagerException
* If there is a query error
*/
List<Alert> getAlertsForPolicy(Policy policy) throws AlertManagerException;
/**
* Retrieves unresolved {@link Alert}s associated with the provided {@link Baseline}.
*
* @param baseline baseline that is being evaluated
* @return list of unresolved alerts associated with {@link Baseline}
* @throws AlertManagerException
* If there is a query error
*/
List<Alert> getAlertsForBaseline(Baseline baseline) throws AlertManagerException;
/**
* Retrieves the total number of Unresolved {@link Alert}s associated with the provided
* {@link Baseline}.
*
* @param baseline baseline that is being evaluated
* @return number of unresolved alerts associated with Baseline
* @throws AlertManagerException
* If there is a query error
*/
long getTotalAlertsForBaseline(Baseline baseline) throws AlertManagerException;
/**
* Gets the set of alerts for a device in order to determine the status of
* the device (trusted or untrusted).
*
* The alerts meet one or more of these specifications:
* <ol>
* <li> Have no report associated (missed periodic report alerts) for this device </li>
* <li> Are associated with the provided integrity report </li>
* <li> Match the specified criteria. e.g. leftover alerts from
* delta reports in the current series of delta reports). </li>
* </ol>
* @param device the device to query for alerts on
* @param integrityReport the integrity report to find associated alerts with
* @param optionalCriterion the optional additional criteria for which to query on
* @return the set of device alerts associated with trust
*/
List<Alert> getTrustAlerts(Device device, Report integrityReport,
Criterion optionalCriterion);
/**
* Gets the count of trust alerts for a device. See {@link #getTrustAlerts} for more
* information about which alerts are counted.
*
* @param device the device to query for alerts on
* @param integrityReport the integrity report to find associated alerts with
* @param optionalCriterion the optional additional criteria for which to query on
* @return the count of alerts associated with trust
*/
int getTrustAlertCount(Device device, Report integrityReport,
Criterion optionalCriterion);
/**
* Return the count of unresolved alerts associated with the given device.
*
* @param device associated with unresolved alerts being counted
* @return count of unresolved alerts
*/
int countUnresolvedAlerts(Device device);
/**
* Return the count of unresolved alerts associated with the given device that originate from
* the given AlertSource.
*
* @param device associated with unresolved alerts being counted
* @param source counted alerts must originate from
* @return count of unresolved alerts
*/
int countUnresolvedAlerts(Device device, AlertSource source);
/**
* Count the total number of devices with at least one unresolved alert within the given group.
*
* @param deviceGroup to count devices from
* @return count of devices with unresolved alerts
*/
int countUnresolvedDevices(DeviceGroup deviceGroup);
}

View File

@ -1,45 +0,0 @@
package hirs.persist;
/**
* This class represents an <code>Exception</code> generated by a
* <code>AlertManageer</code>.
*/
public class AlertManagerException extends RuntimeException {
private static final long serialVersionUID = 3081536085161873284L;
/**
* Creates a new <code>AlertManagerException</code> that has the message
* <code>msg</code>.
*
* @param msg
* exception message
*/
AlertManagerException(final String msg) {
super(msg);
}
/**
* Creates a new <code>AlertManagerException</code> that wraps the given
* <code>Throwable</code>.
*
* @param t
* root cause
*/
AlertManagerException(final Throwable t) {
super(t);
}
/**
* Creates a new <code>AlertManagerException</code> that has the message
* <code>msg</code> and wraps the root cause.
*
* @param msg
* exception message
* @param t
* root cause
*/
AlertManagerException(final String msg, final Throwable t) {
super(msg, t);
}
}

View File

@ -1,89 +0,0 @@
package hirs.persist;
import hirs.data.persist.alert.AlertMonitor;
import java.util.List;
/**
* An <code>AlertMonitorManager</code> manages <code>AlertMonitor</code>. An
* <code>AlertMonitorManager</code> is used to store and manage AlertMonitors.
* It has support for the basic create, read, update, and delete methods.
*/
public interface AlertMonitorManager {
/**
* Stores a new <code>AlertMonitor</code>. This stores a new
* <code>AlertMonitor</code> to be managed by the
* <code>AlertMonitorManager</code>. If the <code>AlertMonitor</code> is
* successfully saved then a reference to it is returned.
*
* @param monitor
* the AlertMonitor to save AlertMonitor to save
* @return reference to saved AlertMonitor
* @throws AlertMonitorManagerException
* if the AlertMonitor has previously been saved or unexpected
* error occurs
*/
AlertMonitor saveAlertMonitor(AlertMonitor monitor)
throws AlertMonitorManagerException;
/**
* Updates a <code>AlertMonitor</code>. This updates the
* <code>AlertMonitor</code> that is managed so subsequent calls to get this
* <code>AlertMonitor</code> will return the values set by the incoming
* <code>AlertMonitor</code>.
*
* @param alertMonitor
* AlertMonitor
* @throws AlertMonitorManagerException
* if unable to update the AlertMonitor
*/
void updateAlertMonitor(AlertMonitor alertMonitor)
throws AlertMonitorManagerException;
/**
* Returns a list of all AlertMonitor names managed by this manager. Every
* <code>AlertMonitor</code> must have a name that users can use to
* reference the <code>AlertMonitor</code>. This returns a listing of all
* the <code>AlertMonitor</code>s.
* <p>
* A <code>Class</code> argument may be specified to limit which types of
* <code>AlertMonitor</code>s to return. This argument may be null to return
* all <code>AlertMonitor</code>s.
*
* @param clazz class type of <code>AlertMonitor</code>s to return (may be null)
* @return list of <code>AlertMonitor</code> names
* @throws AlertMonitorManagerException
* if unable to create the list
*/
List<AlertMonitor> getAlertMonitorList(Class<? extends AlertMonitor> clazz)
throws AlertMonitorManagerException;
/**
* Retrieves the <code>AlertMonitor</code> identified by <code>name</code>.
* If the <code>AlertMonitor</code> cannot be found then null is returned.
*
* @param name
* name of the <code>AlertMonitor</code>
* @return <code>AlertMonitor</code> whose name is <code>name</code> or null
* if not found
* @throws AlertMonitorManagerException
* if unable to retrieve the AlertMonitor
*/
AlertMonitor getAlertMonitor(String name)
throws AlertMonitorManagerException;
/**
* Deletes the <code>AlertMonitor</code> identified by <code>name</code>. If
* the <code>AlertMonitor</code> is found and deleted then true is returned,
* otherwise false.
*
* @param name
* name of the <code>AlertMonitor</code> to delete
* @return true if successfully found and deleted from repo, otherwise false
* @throws AlertMonitorManagerException
* if unable to delete the AlertMonitor for any reason other
* than not found
*/
boolean deleteAlertMonitor(String name) throws AlertMonitorManagerException;
}

View File

@ -1,41 +0,0 @@
package hirs.persist;
/**
* This class represents an <code>AlertMonitorManagerException</code> generated by a
* <code>AlertMonitorConfigManager</code>.
*/
public class AlertMonitorManagerException extends RuntimeException {
private static final long serialVersionUID = 4732897562100987654L;
/**
* Creates a new <code>AlertMonitorManagerException</code> that has the message
* <code>msg</code>.
*
* @param msg exception message
*/
AlertMonitorManagerException(final String msg) {
super(msg);
}
/**
* Creates a new <code>AlertMonitorManagerException</code> that wraps the given
* <code>Throwable</code>.
*
* @param t root cause
*/
AlertMonitorManagerException(final Throwable t) {
super(t);
}
/**
* Creates a new <code>AlertMonitorManagerException</code> that has the message <code>msg</code>
* and wraps the root cause.
*
* @param msg exception message
* @param t root cause
*/
AlertMonitorManagerException(final String msg, final Throwable t) {
super(msg, t);
}
}

View File

@ -1,78 +0,0 @@
package hirs.persist;
import hirs.data.persist.alert.AlertServiceConfig;
import java.util.List;
/**
* An <code>AlertServiceManager</code> manages <code>AlertServiceConfig</code>s. An
* <code>AlertServiceManager</code> is used to store and manage AlertServiceConfigs. It has support
* for the basic create, read, update, and delete methods.
*/
public interface AlertServiceConfigManager {
/**
* Stores a new <code>AlertServiceConfig</code>. This stores a new
* <code>AlertServiceConfig</code> to be managed by the <code>AlertServiceManager</code>. If the
* <code>AlertServiceConfig</code> is successfully saved then a reference to it is returned.
*
* @param service the AlertServiceConfig to save AlertServiceConfig to save
* @return reference to saved AlertServiceConfig
* @throws AlertServiceConfigManagerException if the AlertServiceConfig has previously been
* saved or unexpected error occurs
*/
AlertServiceConfig saveAlertServiceConfig(AlertServiceConfig service)
throws AlertServiceConfigManagerException;
/**
* Updates a <code>AlertServiceConfig</code>. This updates the <code>AlertServiceConfig</code>
* that is managed so subsequent calls to get this <code>AlertServiceConfig</code> will return
* the values set by the incoming <code>AlertServiceConfig</code>.
*
* @param serviceConfig the AlertServiceConfig
* @throws AlertServiceConfigManagerException if unable to update the AlertServiceConfig
*/
void updateAlertServiceConfig(AlertServiceConfig serviceConfig)
throws AlertServiceConfigManagerException;
/**
* Returns a list of all AlertServiceConfig names managed by this manager. Every
* <code>AlertServiceConfig</code> must have a name that users can use to reference the
* <code>AlertServiceConfig</code>. This returns a listing of all the
* <code>AlertServiceConfig</code>s.
* <p>
* A <code>Class</code> argument may be specified to limit which types of
* <code>AlertServiceConfig</code>s to return. This argument may be null to return all
* <code>AlertServiceConfig</code>s.
*
* @param clazz class type of <code>AlertServiceConfig</code>s to return (may be null)
* @return list of <code>AlertServiceConfig</code> names
* @throws AlertServiceConfigManagerException if unable to create the list
*/
List<AlertServiceConfig>
getAlertServiceConfigList(Class<? extends AlertServiceConfig> clazz)
throws AlertServiceConfigManagerException;
/**
* Retrieves the <code>AlertServiceConfig</code> identified by <code>name</code>. If the
* <code>AlertServiceConfig</code> cannot be found then null is returned.
*
* @param type type of the <code>AlertServiceConfig</code>
* @return <code>AlertServiceConfig</code> whose name is <code>name</code> or null if not found
* @throws AlertServiceConfigManagerException if unable to retrieve the AlertServiceConfig
*/
AlertServiceConfig getAlertServiceConfig(String type)
throws AlertServiceConfigManagerException;
/**
* Deletes the <code>AlertServiceConfig</code> identified by <code>name</code>. If the
* <code>AlertServiceConfig</code> is found and deleted then true is returned, otherwise false.
*
* @param type type of the <code>AlertServiceConfig</code> to delete
* @return true if successfully found and deleted from repo, otherwise false
* @throws AlertServiceConfigManagerException if unable to delete the AlertServiceConfig for any
* reason other than not found
*/
boolean deleteAlertServiceConfig(String type)
throws AlertServiceConfigManagerException;
}

View File

@ -1,41 +0,0 @@
package hirs.persist;
/**
* This class represents an <code>AlertServiceConfigManagerException</code> generated by a
* <code>AlertServiceConfigManager</code>.
*/
public class AlertServiceConfigManagerException extends RuntimeException {
private static final long serialVersionUID = 4732897562100987655L;
/**
* Creates a new <code>AlertServiceManagerException</code> that has the message
* <code>msg</code>.
*
* @param msg exception message
*/
AlertServiceConfigManagerException(final String msg) {
super(msg);
}
/**
* Creates a new <code>AlertServiceManagerException</code> that wraps the given
* <code>Throwable</code>.
*
* @param t root cause
*/
AlertServiceConfigManagerException(final Throwable t) {
super(t);
}
/**
* Creates a new <code>AlertServiceManagerException</code> that has the message <code>msg</code>
* and wraps the root cause.
*
* @param msg exception message
* @param t root cause
*/
AlertServiceConfigManagerException(final String msg, final Throwable t) {
super(msg, t);
}
}

View File

@ -1,231 +0,0 @@
package hirs.persist;
import hirs.FilteredRecordsList;
import hirs.data.bean.SimpleBaselineBean;
import hirs.data.persist.baseline.Baseline;
import hirs.data.persist.baseline.IMABaselineRecord;
import hirs.data.persist.ImaBlacklistRecord;
import hirs.repository.RepoPackage;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
import java.util.UUID;
/**
* A <code>BaselineManager</code> manages <code>Baseline</code>s. A <code>BaselineManager</code> can
* read, update, and archive <code>Baseline</code>s.
*/
public interface BaselineManager extends OrderedListQuerier<Baseline> {
/**
* Stores a new <code>Baseline</code>. This stores a new
* <code>Baseline</code> to be managed by the <code>BaselineManager</code>.
* If the <code>Baseline</code> is successfully saved then a reference to it
* is returned.
*
* @param baseline baseline to save
* @return reference to saved baseline
* @throws BaselineManagerException if baseline is already saved or other error occurs
*/
Baseline saveBaseline(Baseline baseline) throws BaselineManagerException;
/**
* Updates a <code>Baseline</code>. This updates the <code>Baseline</code>
* that is managed so subsequent calls to get this <code>Baseline</code>
* will return the values set by the incoming <code>Baseline</code>.
*
* @param baseline baseline
* @throws BaselineManagerException if unable to update the baseline
*/
void updateBaseline(Baseline baseline) throws BaselineManagerException;
/**
* Returns a list of all baseline names managed by this manager. Every
* <code>Baseline</code> must have a name that users can use to reference
* the <code>Baseline</code>. This returns a listing of all the
* <code>Baseline</code>s.
* <p>
* A <code>Class</code> argument may be specified to limit which types of
* <code>Baseline</code>s to return. This argument may be null to return all
* <code>Baseline</code>s.
*
* @param clazz
* class type of <code>Baseline</code>s to return (may be null)
* @return list of <code>Baseline</code> names
* @throws BaselineManagerException if unable to create the list
*/
List<Baseline> getBaselineList(Class<? extends Baseline> clazz)
throws BaselineManagerException;
/**
* Returns a list of all <code>Baseline</code>s that are ordered by a column
* and direction (ASC, DESC) that is provided by the user. This method
* helps support the server-side processing in the JQuery DataTables. The returned list does not
* contain <code>Baseline</code>s that have been soft-deleted.
*
* @param columnToOrder Column to be ordered
* @param ascending direction of sort
* @param firstResult starting point of first result in set
* @param maxResults total number we want returned for display in table
* @param search string of criteria to be matched to visible columns
* @param searchableColumns Map of String and boolean values with column
* headers and whether they are to. Boolean is true if field provides
* a typical String that can be searched by Hibernate without
* transformation.
* @return FilteredRecordsList object with fields for DataTables
* @throws BaselineManagerException if unable to create the list
*/
FilteredRecordsList<Baseline> getOrderedBaselineList(
String columnToOrder, boolean ascending,
int firstResult, int maxResults, String search,
Map<String, Boolean> searchableColumns)
throws BaselineManagerException;
/**
* Returns a list of all ImaBaseline Records that are ordered by a column
* and direction (ASC, DESC) that is provided by the user. This method
* helps support the server-side processing in the JQuery DataTables.
*
* @param baselineId id of the baseline
* @param columnToOrder Column to be ordered
* @param ascending direction of sort
* @param firstResult starting point of first result in set
* @param maxResults total number we want returned for display in table
* @param search string of criteria to be matched to visible columns
* @return FilteredRecordsList object with fields for DataTables
* @throws BaselineManagerException if unable to create the list
*/
FilteredRecordsList<IMABaselineRecord> getOrderedRecordList(
UUID baselineId, String columnToOrder, boolean ascending,
int firstResult, int maxResults, String search)
throws BaselineManagerException;
/**
* Returns a list of all ImaBlacklistBaseline Records that are ordered by a column
* and direction (ASC, DESC) that is provided by the user. This method
* helps support the server-side processing in the JQuery DataTables.
*
* @param baselineId id of the baseline
* @param columnToOrder Column to be ordered
* @param ascending direction of sort
* @param firstResult starting point of first result in set
* @param maxResults total number we want returned for display in table
* @param search string of criteria to be matched to visible columns
* @return FilteredRecordsList object with fields for DataTables
* @throws BaselineManagerException if unable to create the list
*/
FilteredRecordsList<ImaBlacklistRecord> getOrderedBlacklistRecordList(
UUID baselineId, String columnToOrder, boolean ascending,
int firstResult, int maxResults, String search)
throws BaselineManagerException;
/**
* Returns a list of all RepoPackages that are ordered by a column
* and direction (ASC, DESC) that is provided by the user. This method
* helps support the server-side processing in the JQuery DataTables.
*
* @param name name of the baseline
* @param columnToOrder Column to be ordered
* @param ascending direction of sort
* @param firstResult starting point of first result in set
* @param maxResults total number we want returned for display in table
* @param search string of criteria to be matched to visible columns
* @return FilteredRecordsList object with fields for DataTables
* @throws BaselineManagerException if unable to create the list
*/
FilteredRecordsList<RepoPackage> getOrderedPackageList(
String name, String columnToOrder, boolean ascending,
int firstResult, int maxResults, String search)
throws BaselineManagerException;
/**
* Returns a list of all IMABaselineRecords in the specified package.
*
* @param id of the package
* @param search string of criteria to be matched to visible columns
* @return List the records
* @throws BaselineManagerException if unable to create the list
*/
List<IMABaselineRecord> getPackageRecords(
UUID id, String search) throws BaselineManagerException;
/**
* Retrieves the <code>Baseline</code> identified by <code>name</code>. If
* the <code>Baseline</code> cannot be found then null is returned.
*
* @param name name of the <code>Baseline</code>
* @return <code>Baseline</code> whose name is <code>name</code> or null if not found
* @throws BaselineManagerException if unable to retrieve the baseline
*/
Baseline getBaseline(String name) throws BaselineManagerException;
/**
* Retrieves the <code>Baseline</code> identified by the given <code>id</code>. If
* the <code>Baseline</code> cannot be found then null is returned.
*
* @param id the id of the desired <code>Baseline</code>
* @return <code>Baseline</code> whose id is <code>id</code> or null if not found
* @throws BaselineManagerException if unable to retrieve the baseline
*/
Baseline getBaseline(Serializable id) throws BaselineManagerException;
/**
* Retrieves the <code>Baseline</code> identified by <code>name</code>. This method
* fully loads a Baseline object; any lazy fields will be recursively loaded. This is
* necessary when conducting an appraisal. If the <code>Baseline</code> cannot be found
* then null is returned.
*
* @param name name of the <code>Baseline</code>
* @return <code>Baseline</code> whose name is <code>name</code> or null if not found
* @throws BaselineManagerException if unable to retrieve the baseline
*/
Baseline getCompleteBaseline(String name) throws BaselineManagerException;
/**
* Archives the named {@link Baseline} and updates it in the database.
*
* @param name name of the {@link Baseline} to <code>archive</code>
* @return true if the {@link Baseline} was successfully found and archived, false if the
* {@link Baseline} was not found
* @throws DBManagerException
* if the {@link Baseline} is not an instance of ArchivableEntity.
*/
boolean archive(String name) throws DBManagerException;
/**
* Deletes the named {@link Baseline} from the database.
*
* @param baseline {@link Baseline} to be deleted
* @return <code>true</code> if the {@link Baseline} was successfully found and
* deleted, <code>false</code> if the {@link Baseline} was not found
* @throws DBManagerException
* if the {@link Baseline} is not an instance of ArchivableEntity.
*/
boolean delete(Baseline baseline) throws DBManagerException;
/**
* Returns a list of all <code>Baseline</code>s that are ordered by a column
* and direction (ASC, DESC) that is provided by the user. This method
* helps support the server-side processing in the JQuery DataTables. The returned list does not
* contain <code>Baseline</code>s that have been soft-deleted. The records stored within each
* baseline are not loaded.
*
* @param columnToOrder Column to be ordered
* @param ascending direction of sort
* @param firstResult starting point of first result in set
* @param maxResults total number we want returned for display in table
* @param search string of criteria to be matched to visible columns
* @param searchableColumns Map of String and boolean values with column
* headers and whether they are to. Boolean is true if field provides
* a typical String that can be searched by Hibernate without
* transformation.
* @return FilteredRecordsList object with fields for DataTables
* @throws BaselineManagerException if unable to create the list
*/
FilteredRecordsList<SimpleBaselineBean> getOrderedBaselineListWithoutRecords(
String columnToOrder, boolean ascending,
int firstResult, int maxResults, String search,
Map<String, Boolean> searchableColumns)
throws BaselineManagerException;
}

View File

@ -1,46 +0,0 @@
package hirs.persist;
/**
* This class represents an <code>Exception</code> generated by a
* <code>BaselineManageer</code>.
*/
public class BaselineManagerException extends RuntimeException {
private static final long serialVersionUID = 3081536085161873284L;
/**
* Creates a new <code>BaselineManagerException</code> that has the message
* <code>msg</code>.
*
* @param msg
* exception message
*/
BaselineManagerException(final String msg) {
super(msg);
}
/**
* Creates a new <code>BaselineManagerException</code> that wraps the given
* <code>Throwable</code>.
*
* @param t
* root cause
*/
BaselineManagerException(final Throwable t) {
super(t);
}
/**
* Creates a new <code>BaselineManagerException</code> that has the message
* <code>msg</code> and wraps the root cause.
*
* @param msg
* exception message
* @param t
* root cause
*/
BaselineManagerException(final String msg, final Throwable t) {
super(msg, t);
}
}

View File

@ -9,7 +9,7 @@ import java.util.List;
* Interface defining database CRUD operations (Create, Read, Update, Delete).
* @param <T> the object type, T.
*/
public interface CrudManager<T> extends OrderedListQuerier<T> {
public interface CrudManager<AbstractEntity> extends OrderedListQuerier<AbstractEntity> {
/**
* Deletes all instances of the associated class.
@ -27,7 +27,7 @@ public interface CrudManager<T> extends OrderedListQuerier<T> {
* @throws DBManagerException if object has previously been saved or an
* error occurs while trying to save it to the database
*/
T save(T object) throws DBManagerException;
AbstractEntity save(AbstractEntity object) throws DBManagerException;
/**
* Updates an object stored in the database. This updates the database
@ -36,7 +36,7 @@ public interface CrudManager<T> extends OrderedListQuerier<T> {
* @param object object to update
* @throws DBManagerException if an error occurs while trying to save it to the database
*/
void update(T object) throws DBManagerException;
void update(AbstractEntity object) throws DBManagerException;
/**
* Retrieves the <code>Object</code> from the database. This searches the
@ -48,7 +48,7 @@ public interface CrudManager<T> extends OrderedListQuerier<T> {
* @throws DBManagerException if unable to search the database or recreate
* the <code>Object</code>
*/
T get(String name) throws DBManagerException;
AbstractEntity get(String name) throws DBManagerException;
/**
* Retrieves the <code>Object</code> from the database. This searches the
@ -65,7 +65,7 @@ public interface CrudManager<T> extends OrderedListQuerier<T> {
* @throws DBManagerException if unable to search the database or recreate
* the <code>Object</code>
*/
T getAndLoadLazyFields(String name, boolean recurse)
AbstractEntity getAndLoadLazyFields(String name, boolean recurse)
throws DBManagerException;
/**
@ -78,7 +78,7 @@ public interface CrudManager<T> extends OrderedListQuerier<T> {
* @throws DBManagerException if unable to search the database or recreate
* the <code>Object</code>
*/
T get(Serializable id) throws DBManagerException;
AbstractEntity get(Serializable id) throws DBManagerException;
/**
* Retrieves the <code>Object</code> from the database. This searches the
@ -95,7 +95,7 @@ public interface CrudManager<T> extends OrderedListQuerier<T> {
* @throws DBManagerException if unable to search the database or recreate
* the <code>Object</code>
*/
T getAndLoadLazyFields(Serializable id, boolean recurse)
AbstractEntity getAndLoadLazyFields(Serializable id, boolean recurse)
throws DBManagerException;
/**
@ -111,7 +111,7 @@ public interface CrudManager<T> extends OrderedListQuerier<T> {
* @return list of <code>T</code> names
* @throws DBManagerException if unable to search the database
*/
List<T> getList(Class<? extends T> clazz)
List<AbstractEntity> getList(AbstractEntity entity)
throws DBManagerException;
/**
@ -128,7 +128,7 @@ public interface CrudManager<T> extends OrderedListQuerier<T> {
* @return list of <code>T</code> names
* @throws DBManagerException if unable to search the database
*/
List<T> getList(Class<? extends T> clazz, Criterion additionalRestriction)
List<AbstractEntity> getList(AbstractEntity entity, Criterion additionalRestriction)
throws DBManagerException;
/**
@ -171,7 +171,7 @@ public interface CrudManager<T> extends OrderedListQuerier<T> {
* @return true if successfully found and deleted the object
* @throws DBManagerException if unable to delete the object from the database
*/
boolean delete(T object) throws DBManagerException;
boolean delete(AbstractEntity object) throws DBManagerException;
/**
* Archives the named object and updates it in the database.

View File

@ -1,773 +0,0 @@
package hirs.persist;
import hirs.FilteredRecordsList;
import hirs.data.persist.Alert;
import hirs.data.persist.Device;
import hirs.data.persist.DeviceGroup;
import hirs.data.persist.Policy;
import hirs.data.persist.Report;
import hirs.data.persist.baseline.Baseline;
import hirs.data.persist.enums.AlertSource;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.Logger;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Restrictions;
import org.hibernate.query.Query;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import static org.apache.logging.log4j.LogManager.getLogger;
/**
* This class defines a <code>AlertManager</code> that stores policies in a
* database.
*/
public class DBAlertManager extends DBManager<Alert> implements AlertManager {
private static final Logger LOGGER = getLogger(DBAlertManager.class);
/**
* Creates a new <code>DBAlertManager</code>. The optional SessionFactory
* parameter is used to initialize a session factory to manage all hibernate
* sessions.
*
* @param factory session factory to manage connections to hibernate db
*/
public DBAlertManager(final SessionFactory factory) {
super(Alert.class, factory);
}
/**
* Saves the <code>Alert</code> in the database and returns it.
*
* @param alert
* alert to save
* @return <code>Alert</code> that was saved
* @throws AlertManagerException
* if alert has previously been saved or an error occurs while
* trying to save it to the database
*/
@Override
public final Alert saveAlert(final Alert alert)
throws AlertManagerException {
LOGGER.debug("saving alert: {}", alert);
try {
return super.save(alert);
} catch (DBManagerException e) {
throw new AlertManagerException(e);
}
}
/**
* Updates all of the {@link Alert}s provided in the list.
*
* @param alerts list of alerts to be updated
* @return list of updated Alerts
* @throws AlertManagerException
* if unable to update the list of Alerts
*/
@Override
public final List<Alert> updateAlerts(final List<Alert> alerts) throws AlertManagerException {
LOGGER.debug("updating object");
if (alerts == null) {
LOGGER.debug("null object argument");
throw new NullPointerException("object");
}
Transaction tx = null;
List<Alert> updatedAlerts = new ArrayList<>();
Session session = getFactory().getCurrentSession();
try {
LOGGER.debug("updating object in db");
tx = session.beginTransaction();
for (Alert alert : alerts) {
updatedAlerts.add((Alert) session.merge(alert));
}
tx.commit();
} catch (Exception e) {
final String msg = "unable to update alert";
LOGGER.error(msg, e);
if (tx != null) {
LOGGER.debug("rolling back transaction");
tx.rollback();
}
throw new AlertManagerException(msg, e);
}
return updatedAlerts;
}
/**
* Returns a list of all <code>Alert</code>s.
* This searches through the database for this information.
*
* @return list of <code>Alert</code>s
* @throws AlertManagerException
* if unable to search the database
*/
@Override
public final List<Alert> getAlertList() throws AlertManagerException {
LOGGER.debug("getting alert list");
try {
return super.getList(Alert.class);
} catch (DBManagerException e) {
throw new AlertManagerException(e);
}
}
/**
* Returns a list of all <code>Alert</code>s that relate to the provided <code>Report</code>
* ID. If the given reportId is null or an empty, alerts for all reports are provided. The
* Alerts are ordered by a column and direction (ASC, DESC) that is provided by the user.
* This method helps support the server-side processing in the JQuery DataTables. Alerts with a
* non-null archivedTime are not included in the returned list.
*
* @param reportId ID of the Report to return Alerts from, empty or null for all Alerts
* @param columnToOrder Column to be ordered
* @param ascending direction of sort
* @param firstResult starting point of first result in set
* @param maxResults total number we want returned for display in table
* @param search string of criteria to be matched to visible columns
* @param listType enumeration indicating if the returned list conatins resolved or
* unresolved alerts
* @param searchableColumns Map of String and boolean values with column
* headers and whether they are to. Boolean is true if field provides
* a typical String that can be searched by Hibernate without
* transformation.
* @param beginDate the earliest date of any alert returned from this method. Can be null.
* @param endDate the latest date of any alert returned from this method. Can be null.
* @return FilteredRecordsList object with fields for DataTables
* @throws AlertManagerException
* if unable to create the list
*/
@Override
@SuppressWarnings("checkstyle:parameternumber")
public final FilteredRecordsList<Alert> getOrderedAlertList(
final String reportId, final String columnToOrder, final boolean ascending,
final int firstResult, final int maxResults, final String search,
final AlertListType listType,
final Map<String, Boolean> searchableColumns, final Date beginDate, final Date endDate)
throws AlertManagerException {
if (columnToOrder == null) {
LOGGER.debug("null object argument");
throw new NullPointerException("object");
}
// verify that the report ID is a legit UUID
if (StringUtils.isNotEmpty(reportId)) {
try {
UUID.fromString(reportId);
} catch (IllegalArgumentException iae) {
throw new AlertManagerException(reportId + " is not a valid UUID", iae);
}
}
final FilteredRecordsList<Alert> alerts;
// check that the alert is not archived and that it is in the specified report
CriteriaModifier modifier = new CriteriaModifier() {
@Override
public void modify(final Criteria criteria) {
if (listType == AlertListType.RESOLVED_ALERTS) {
criteria.add(Restrictions.isNotNull("archivedTime"));
} else {
criteria.add(Restrictions.isNull("archivedTime"));
}
// filter by date, if specified
if (null != beginDate) {
criteria.add(Restrictions.ge("createTime", beginDate));
}
if (null != endDate) {
criteria.add(Restrictions.le("createTime", endDate));
}
if (StringUtils.isNotEmpty(reportId)) {
// creating a separate criteria associated with the report field is necessary
// for this to work in HSQL and MySQL to avoid column ambiguity.
Criteria reportCriteria = criteria.createCriteria("report");
reportCriteria.add(Restrictions.eq("id", UUID.fromString(reportId)));
}
}
};
try {
LOGGER.debug("querying db for alerts");
alerts = super.getOrderedList(Alert.class, columnToOrder, ascending, firstResult,
maxResults, search, searchableColumns, modifier);
} catch (DBManagerException e) {
throw new AlertManagerException(e);
}
return alerts;
}
/**
* Retrieves the <code>Alert</code> from the database. This searches the
* database for an entry whose name matches <code>name</code>. It then
* reconstructs a <code>Alert</code> object from the database entry
*
* @param id
* id of the <code>Alert</code>
* @return alert if found, otherwise null.
* @throws AlertManagerException
* if unable to search the database or recreate the
* <code>Alert</code>
*/
@Override
public final Alert getAlert(final UUID id) throws AlertManagerException {
LOGGER.debug("getting alert: {}", id);
try {
return super.get(id);
} catch (DBManagerException e) {
throw new AlertManagerException(e);
}
}
/**
* Retrieves all {@link Alert}s associated with the provided {@link Policy}.
*
* @param policy policy that is being evaluated
* @return list of all alerts associated with {@link Policy}
* @throws AlertManagerException
* If there is a query error
*/
@Override
public final List<Alert> getAlertsForPolicy(final Policy policy)
throws AlertManagerException {
LOGGER.debug("");
if (policy == null) {
throw new NullPointerException("policy was null");
}
List<Alert> alerts = new ArrayList<>();
Transaction tx = null;
Session session = getFactory().getCurrentSession();
try {
tx = session.beginTransaction();
// query hibernate to count alerts with the given deviceName and null archivedTime
CriteriaBuilder criteriaBuilder = session.getCriteriaBuilder();
CriteriaQuery<Alert> criteriaQuery = criteriaBuilder.createQuery(Alert.class);
Root<Alert> root = criteriaQuery.from(Alert.class);
Predicate recordPredicate = criteriaBuilder
.and(criteriaBuilder.equal(root.get("policyId"), policy.getId()));
criteriaQuery.select(root).where(recordPredicate);
Query<Alert> query = session.createQuery(criteriaQuery);
List<Alert> results = query.getResultList();
// criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
for (Object o : results) {
if (o instanceof Alert) {
alerts.add((Alert) o);
}
}
tx.commit();
} catch (HibernateException e) {
final String msg = "unable to query alerts table";
LOGGER.error(msg, e);
if (tx != null) {
LOGGER.debug("rolling back transaction");
tx.rollback();
}
throw e;
}
return alerts;
}
/**
* Retrieves all {@link Alert}s associated with the provided {@link Baseline}.
*
* @param baseline baseline that is being evaluated
* @return list of all alerts associated with {@link Baseline}
* @throws AlertManagerException
* If there is a query error
*/
@Override
public final List<Alert> getAlertsForBaseline(final Baseline baseline)
throws AlertManagerException {
LOGGER.debug("");
if (baseline == null) {
throw new NullPointerException("baseline was null");
}
List<Alert> alerts = new ArrayList<>();
Transaction tx = null;
Session session = getFactory().getCurrentSession();
try {
tx = session.beginTransaction();
// query hibernate to retrieve alerts with the given baseline id
CriteriaBuilder criteriaBuilder = session.getCriteriaBuilder();
CriteriaQuery<Alert> criteriaQuery = criteriaBuilder.createQuery(Alert.class);
Root<Alert> root = criteriaQuery.from(Alert.class);
Predicate recordPredicate = criteriaBuilder
.and(criteriaBuilder.equal(root.get("baselineId"), baseline.getId()));
criteriaQuery.select(root).where(recordPredicate);
Query<Alert> query = session.createQuery(criteriaQuery);
List<Alert> results = query.getResultList();
// criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
for (Object o : results) {
if (o instanceof Alert) {
alerts.add((Alert) o);
}
}
tx.commit();
} catch (HibernateException e) {
final String msg = "unable to query alerts table";
LOGGER.error(msg, e);
if (tx != null) {
LOGGER.debug("rolling back transaction");
tx.rollback();
}
throw e;
}
return alerts;
}
/**
* Retrieves the total number of Unresolved {@link Alert}s associated with the provided
* {@link Baseline}.
*
* @param baseline baseline that is being evaluated
* @return number of unresolved alerts associated with Baseline
* @throws AlertManagerException
* If there is a query error
*/
@Override
public final long getTotalAlertsForBaseline(final Baseline baseline)
throws AlertManagerException {
LOGGER.debug("");
if (baseline == null) {
throw new NullPointerException("baseline was null");
}
Transaction tx = null;
Session session = getFactory().getCurrentSession();
try {
tx = session.beginTransaction();
// query hibernate to count alerts with the given deviceName and null archivedTime
CriteriaBuilder criteriaBuilder = session.getCriteriaBuilder();
CriteriaQuery<Alert> criteriaQuery = criteriaBuilder.createQuery(Alert.class);
Root<Alert> root = criteriaQuery.from(Alert.class);
Predicate recordPredicate = criteriaBuilder
.and(criteriaBuilder.equal(root.get("baselineId"), baseline.getId()),
criteriaBuilder.isNull(root.get("archivedTime")));
criteriaQuery.select(root).where(recordPredicate);
Query<Alert> query = session.createQuery(criteriaQuery);
List<Alert> results = query.getResultList();
Long result = results.stream().count();
tx.commit();
if (result == null) {
throw new AlertManagerException("failed to query unresolved alert count");
} else {
return result;
}
} catch (HibernateException e) {
final String msg = "unable to query alerts table";
LOGGER.error(msg, e);
if (tx != null) {
LOGGER.debug("rolling back transaction");
tx.rollback();
}
throw e;
}
}
private Query<Alert> getCriteriaForTrustAlertsForDevice(final Device device,
final Report integrityReport,
final Criterion optionalCriterion,
final Session session) {
if (device == null) {
throw new NullPointerException("device was null");
}
if (integrityReport == null) {
throw new NullPointerException("integrityReport was null");
}
if (session == null) {
throw new NullPointerException("session was null");
}
// query hibernate to count alerts with the given deviceName and null archivedTime
// alerts for this report, or alerts not associated with any report (case 1 and 2)
CriteriaBuilder criteriaBuilder = session.getCriteriaBuilder();
CriteriaQuery<Alert> criteriaQuery = criteriaBuilder.createQuery(Alert.class);
Root<Alert> root = criteriaQuery.from(Alert.class);
Predicate recordPredicate = criteriaBuilder.and(
criteriaBuilder.isNull(root.get("archivedTime")),
criteriaBuilder.equal(root.get("deviceName"), device.getName()));
Predicate reportEqualsDisjunction = criteriaBuilder.disjunction();
Predicate reportNullDisjunction = criteriaBuilder.disjunction();
// alerts for this report, or alerts not associated with any report (case 1 and 2)
// Criterion reportEqualsCriterion = Restrictions.eq("report", integrityReport);
// Criterion reportNullCriterion = Restrictions.isNull("report");
reportEqualsDisjunction = criteriaBuilder.equal(root.get("report"), integrityReport);
reportNullDisjunction = criteriaBuilder.isNull(root.get("report"));
criteriaBuilder.or(reportEqualsDisjunction, reportNullDisjunction);
// only apply the optional criterion to the disjunction if there is one.
if (optionalCriterion != null) {
LOGGER.error("optional criterion needs to be updated");
}
criteriaQuery.select(root).where(recordPredicate,
reportEqualsDisjunction,
reportNullDisjunction);
return session.createQuery(criteriaQuery);
}
/**
* Gets the set of alerts for a device in order to determine the status of
* the device (trusted or untrusted).
*
* The alerts meet one or more of these specifications:
* <ol>
* <li>Have no report associated (missed periodic report alerts) for this device</li>
* <li>Are associated with the provided integrity report</li>
* <li>Match the specified criteria. e.g. leftover alerts from
* delta reports in the current series of delta reports).</li>
* </ol>
* @param device the device to query for alerts on
* @param integrityReport the integrity report to find associated alerts with
* @param optionalCriterion the optional additional criteria for which to query on
* @return the set of device alerts associated with trust
*/
@Override
public List<Alert> getTrustAlerts(final Device device, final Report integrityReport,
final Criterion optionalCriterion) {
LOGGER.debug("getting trust alerts for {}", device);
Transaction tx = null;
Session session = getFactory().getCurrentSession();
try {
tx = session.beginTransaction();
Query<Alert> criteria = getCriteriaForTrustAlertsForDevice(device, integrityReport,
optionalCriterion, session);
List<Alert> alerts = new ArrayList<>();
List list = criteria.list();
for (Object o : list) {
if (o instanceof Alert) {
alerts.add((Alert) o);
}
}
tx.commit();
return alerts;
} catch (HibernateException | NullPointerException e) {
final String msg = "unable to query alerts table";
LOGGER.error(msg, e);
if (tx != null) {
LOGGER.debug("rolling back transaction");
tx.rollback();
}
throw e;
}
}
/**
* Gets the count of trust alerts for a device. See {@link #getTrustAlerts} for more
* information about which alerts are counted.
*
* @param device the device to query for alerts on
* @param integrityReport the integrity report to find associated alerts with
* @param optionalCriterion the optional additional criteria for which to query on
* @return the count of alerts associated with trust
*/
@Override
public final int getTrustAlertCount(final Device device, final Report integrityReport,
final Criterion optionalCriterion) {
LOGGER.debug("getting trust alert count for {}", device);
Transaction tx = null;
Session session = getFactory().getCurrentSession();
try {
tx = session.beginTransaction();
Query<Alert> criteria = getCriteriaForTrustAlertsForDevice(device, integrityReport,
optionalCriterion, session);
Long result = criteria.stream().count();
tx.commit();
return result.intValue();
} catch (HibernateException | NullPointerException e) {
final String msg = "unable to query alerts table";
LOGGER.error(msg, e);
if (tx != null) {
LOGGER.debug("rolling back transaction");
tx.rollback();
}
throw e;
}
}
/**
* Overloads the resolveAlerts method and provides a null description for the
* alert resolution.
*
* @param alerts - list of Alert objects to be marked as resolved.
* @throws AlertManagerException
* if unable to save the list
*/
@Override
public final void resolveAlerts(final List<Alert> alerts)
throws AlertManagerException {
resolveAlerts(alerts, null);
}
/**
* Marks all Alerts that are provided as arguments as resolved. This is used as
* a "soft delete" method and will ensure they no longer appear in the Alert
* table on the Portal.
*
* @param alerts - Alert objects to be marked as resolved
* @param description - description of action taken. The description can be null
* @throws AlertManagerException
* if unable to save the list
*/
@Override
public final void resolveAlerts(final List<Alert> alerts, final String description)
throws AlertManagerException {
if (alerts == null) {
String message = "list of alert objects was null";
LOGGER.debug(message);
throw new NullPointerException(message);
}
LOGGER.debug("Marking " + alerts.size() + " alerts to resolved and saving.");
Transaction tx = null;
Session session = getFactory().getCurrentSession();
try {
LOGGER.debug("saving object in db");
tx = session.beginTransaction();
for (Alert alert : alerts) {
alert.archive(description);
session.merge(alert);
LOGGER.info("Alert {} is marked as resolved.", alert.getId());
}
tx.commit();
} catch (Exception e) {
final String msg = "unable to save alert";
LOGGER.error(msg, e);
if (tx != null) {
LOGGER.debug("rolling back transaction");
tx.rollback();
}
throw new DBManagerException(msg, e);
}
}
/**
* Return the count of unresolved alerts associated with the given device.
*
* @param device associated with unresolved alerts being counted
* @return count of unresolved alerts
*/
public final int countUnresolvedAlerts(final Device device) {
if (device == null) {
LOGGER.warn("null device found, returning 0");
return 0;
}
Long result = null;
Transaction tx = null;
Session session = getFactory().getCurrentSession();
try {
LOGGER.debug("querying alerts table for unresolved alerts");
tx = session.beginTransaction();
// query hibernate to count alerts with the given deviceName and null archivedTime
CriteriaBuilder criteriaBuilder = session.getCriteriaBuilder();
CriteriaQuery<Alert> criteriaQuery = criteriaBuilder.createQuery(Alert.class);
Root<Alert> root = criteriaQuery.from(Alert.class);
Predicate recordPredicate = criteriaBuilder
.and(criteriaBuilder.equal(root.get("deviceName"), device.getName()),
criteriaBuilder.isNull(root.get("archivedTime")));
criteriaQuery.select(root).where(recordPredicate);
Query<Alert> query = session.createQuery(criteriaQuery);
List<Alert> results = query.getResultList();
if (results != null && !results.isEmpty()) {
result = results.stream().count();
}
// Criteria criteria = session.createCriteria(Alert.class);
// criteria.add(Restrictions.isNull("archivedTime"));
// criteria.add(Restrictions.eq("deviceName", device.getName()));
// criteria.setProjection(Projections.rowCount()).uniqueResult();
// Long result = (Long) criteria.uniqueResult();
tx.commit();
if (result == null) {
throw new AlertManagerException("failed to query unresolved alert count");
} else {
return result.intValue();
}
} catch (HibernateException e) {
final String msg = "unable to query alerts table";
LOGGER.error(msg, e);
if (tx != null) {
LOGGER.debug("rolling back transaction");
tx.rollback();
}
throw e;
}
}
/**
* Return the count of unresolved alerts associated with the given device that originate from
* the given AlertSource.
*
* @param device associated with unresolved alerts being counted
* @param source counted alerts must originate from
* @return count of unresolved alerts
*/
public final int countUnresolvedAlerts(final Device device, final AlertSource source) {
if (device == null) {
String msg = "invalid argument - null value for device";
LOGGER.error(msg);
throw new IllegalArgumentException(msg);
}
if (source == null) {
String msg = "invalid argument - null value for source";
LOGGER.error(msg);
throw new IllegalArgumentException(msg);
}
Long result = null;
Transaction tx = null;
Session session = getFactory().getCurrentSession();
try {
LOGGER.debug("querying alerts table for unresolved alerts");
tx = session.beginTransaction();
CriteriaBuilder criteriaBuilder = session.getCriteriaBuilder();
CriteriaQuery<Alert> criteriaQuery = criteriaBuilder.createQuery(Alert.class);
Root<Alert> root = criteriaQuery.from(Alert.class);
Predicate recordPredicate = criteriaBuilder
.and(criteriaBuilder.equal(root.get("deviceName"), device.getName()),
criteriaBuilder.equal(root.get("source"), source),
criteriaBuilder.isNull(root.get("archivedTime")));
criteriaQuery.select(root).where(recordPredicate);
Query<Alert> query = session.createQuery(criteriaQuery);
List<Alert> results = query.getResultList();
if (results != null && !results.isEmpty()) {
result = results.stream().count();
}
// Criteria criteria = session.createCriteria(Alert.class);
// criteria.add(Restrictions.isNull("archivedTime"));
// criteria.add(Restrictions.eq("deviceName", device.getName()));
// criteria.add(Restrictions.eq("source", source));
// criteria.setProjection(Projections.rowCount()).uniqueResult();
// result = (Long) criteria.uniqueResult();
tx.commit();
if (result == null) {
throw new AlertManagerException("failed to query unresolved alert count");
} else {
return result.intValue();
}
} catch (HibernateException e) {
final String msg = "unable to query alerts table";
LOGGER.error(msg, e);
if (tx != null) {
LOGGER.debug("rolling back transaction");
tx.rollback();
}
throw e;
}
}
/**
* Count the total number of devices with at least one unresolved alert within the given group.
*
* @param deviceGroup to count devices from
* @return count of devices with unresolved alerts
*/
public final int countUnresolvedDevices(final DeviceGroup deviceGroup) {
if (deviceGroup == null) {
String msg = "invalid argument - null value for device group";
LOGGER.error(msg);
throw new IllegalArgumentException(msg);
}
Transaction tx = null;
Session session = getFactory().getCurrentSession();
try {
LOGGER.debug("querying alerts table for unresolved devices");
// tx = session.beginTransaction();
// first use a subquery to list the devices in the given group
// DetachedCriteria deviceQuery = DetachedCriteria.forClass(Device.class);
// deviceQuery.createAlias("deviceGroup", "g");
// deviceQuery.add(Restrictions.eq("g.name", deviceGroup.getName()));
// deviceQuery.setProjection(Property.forName("name"));
// now query within that group for unique device names among unresolved alerts
// Criteria criteria = session.createCriteria(Alert.class);
// criteria.add(Restrictions.isNull("archivedTime"));
// criteria.add(Subqueries.propertyIn("deviceName", deviceQuery));
// criteria.setProjection(Projections.countDistinct("deviceName"));
// Long result = (Long) criteria.uniqueResult();
// CriteriaBuilder criteriaBuilder = session.getCriteriaBuilder();
// CriteriaQuery<Alert> criteriaQuery = criteriaBuilder.createQuery(Alert.class);
// Root<Alert> root = criteriaQuery.from(Alert.class);
// Predicate recordPredicate = criteriaBuilder.and(
// criteriaBuilder.equal(criteriaBuilder.Subqueries.propertiesIn("deviceName", deviceQuery)),
// criteriaBuilder.isNull(root.get("archivedTime"))
//
// );
// criteriaQuery.select(root).where(recordPredicate);
// Query<Alert> query = session.createQuery(criteriaQuery);
// List<Alert> results = query.getResultList();
// if (results != null && !results.isEmpty()) {
// result = results.stream().count();
// }
// tx.commit();
// if (result == null) {
// throw new AlertManagerException("failed to query unresolved alert count");
// } else {
// return result.intValue();
// }
} catch (HibernateException e) {
final String msg = "unable to query alerts table";
LOGGER.error(msg, e);
if (tx != null) {
LOGGER.debug("rolling back transaction");
tx.rollback();
}
throw e;
}
return 0;
}
}

View File

@ -1,134 +0,0 @@
package hirs.persist;
import java.util.List;
import org.hibernate.SessionFactory;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
import hirs.data.persist.alert.AlertMonitor;
/**
* A <code>DBAlertMonitorManager</code> is a service (extends <code>DBManager</code>) that
* implements the <code>AlertMonitorManager</code> that stores and retrieves Alert Monitors.
*/
public class DBAlertMonitorManager
extends DBManager<AlertMonitor> implements AlertMonitorManager {
private static final Logger LOGGER = LogManager.getLogger(DBAlertMonitorManager.class);
/**
* Creates the DBAlertMonitoringManager.
*
* @param sessionFactory session factory used to access database connections
*/
public DBAlertMonitorManager(final SessionFactory sessionFactory) {
super(AlertMonitor.class, sessionFactory);
}
/**
* Saves the <code>AlertMonitor</code> in the database. This creates a new database
* session and saves the AlertMonitor. If the <code>AlertMonitor</code> had previously
* been saved then a <code>AlertMonitorManagerException</code> is thrown.
*
* @param monitor AlertMonitor to save
* @return reference to saved AlertMonitor
* @throws AlertMonitorManagerException if AlertMonitor has previously been saved or an
error occurs while trying to save it to the database
*/
@Override
public final AlertMonitor saveAlertMonitor(final AlertMonitor monitor)
throws AlertMonitorManagerException {
LOGGER.debug("saving Alert Monitor {}", monitor);
try {
return super.save(monitor);
} catch (DBManagerException e) {
throw new AlertMonitorManagerException(e);
}
}
/**
* Updates an <code>AlertMonitor</code>. This updates the database entries to reflect the new
* values that should be set.
*
* @param monitor AlertMonitor
* @throws AlertMonitorManagerException if AlertMonitor has not previously been saved or
an error occurs while trying to save it to the database
*/
@Override
public final void updateAlertMonitor(final AlertMonitor monitor)
throws AlertMonitorManagerException {
LOGGER.debug("updating Alert Monitor: {}", monitor);
try {
super.update(monitor);
} catch (DBManagerException e) {
throw new AlertMonitorManagerException(e);
}
}
/**
* Returns a list of all <code>AlertMonitor</code>s of type <code>clazz</code>. This
* searches through the database for this information.
*
* @param clazz class type of <code>AlertMonitor</code>s to return (may be null)
* @return list of <code>AlertMonitor</code> names
* @throws AlertMonitorManagerException if unable to retrieve the list
*/
@Override
public final List<AlertMonitor> getAlertMonitorList(final Class<? extends AlertMonitor> clazz)
throws AlertMonitorManagerException {
LOGGER.debug("Getting Alert Monitor list");
final List<AlertMonitor> monitors;
try {
monitors = super.getList(clazz);
} catch (DBManagerException e) {
throw new AlertMonitorManagerException(e);
}
LOGGER.debug("Got {} Alert Monitors", monitors.size());
return monitors;
}
/**
* Retrieves the <code>AlertMonitor</code> from the database. This searches the database for an
* entry whose name matches <code>name</code>. It then reconstructs a <code>AlertMonitor</code>
* object from the database entry.
*
* @param name name of the AlertMonitor
* @return AlertMonitor if found, otherwise null.
* @throws AlertMonitorManagerException if unable to search the database or recreate the
* <code>AlertMonitor</code>
*/
@Override
public final AlertMonitor getAlertMonitor(final String name)
throws AlertMonitorManagerException {
LOGGER.debug("getting Alert Monitor: {}", name);
try {
return super.get(name);
} catch (DBManagerException e) {
throw new AlertMonitorManagerException(e);
}
}
/**
* Deletes the <code>AlertMonitor</code> from the database. This removes all of the database
* entries that stored information with regards to the this <code>AlertMonitor</code>.
* Currently, iterates over <code>Policy</code> entries and removes the selected
* <code>AlertMonitor</code> from them if it exists. This needs to be fixed as this should not
* be performed without user action. Update is expected soon.
*
* @param name name of the <code>AlertMonitor</code> to delete
* @return true if successfully found and deleted <code>AlertMonitor</code>
* @throws AlertMonitorManagerException if unable to find the AlertMonitor or delete it
from the database
*/
@Override
public final boolean deleteAlertMonitor(final String name)
throws AlertMonitorManagerException {
LOGGER.debug("deleting Alert Monitor: {}", name);
try {
return super.delete(name);
} catch (DBManagerException e) {
throw new AlertMonitorManagerException(e);
}
}
}

View File

@ -1,208 +0,0 @@
package hirs.persist;
import hirs.data.persist.alert.AlertServiceConfig;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.query.Query;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.List;
/**
* A <code>DBAlertServiceManager</code> is a service (extends <code>DBManager</code>) that
* implements the <code>AlertServiceConfigManager</code> that stores and retrieves Alert Services.
*/
public class DBAlertServiceManager
extends DBManager<AlertServiceConfig> implements AlertServiceConfigManager {
private static final Logger LOGGER = LogManager.getLogger(DBAlertServiceManager.class);
/**
* Creates a new <code>DBReportSummaryManager</code>. The optional SessionFactory parameter is
* used to manage sessions with a hibernate db.
*
* @param factory a hibernate session factory
*/
public DBAlertServiceManager(final SessionFactory factory) {
super(AlertServiceConfig.class, factory);
}
/**
* Saves the <code>AlertServiceConfig</code> in the database. This creates a new database
* session and saves the AlertServiceConfig. If the <code>AlertServiceConfig</code> had
* previously been saved then a <code>AlertServiceManagerException</code> is thrown.
*
* @param serviceConfig AlertServiceConfig to save
* @return reference to saved AlertServiceConfig
* @throws AlertServiceConfigManagerException if baseline has previously been saved or an error
* occurs while trying to save it to the database
*/
@Override
public final AlertServiceConfig saveAlertServiceConfig(final AlertServiceConfig serviceConfig)
throws AlertServiceConfigManagerException {
LOGGER.debug("saving Alert Monitor {}", serviceConfig);
try {
return super.save(serviceConfig);
} catch (DBManagerException e) {
throw new AlertServiceConfigManagerException(e);
}
}
/**
* Updates a <code>AlertServiceConfig</code>. This updates the database entries to reflect the
* new values that should be set.
*
* @param serviceConfig baseline
* @throws AlertServiceConfigManagerException if baseline has not previously been saved or an
* error occurs while trying to save it to the database
*/
@Override
public final void updateAlertServiceConfig(final AlertServiceConfig serviceConfig)
throws AlertServiceConfigManagerException {
LOGGER.debug("updating Alert Monitor: {}", serviceConfig);
try {
super.update(serviceConfig);
} catch (DBManagerException e) {
throw new AlertServiceConfigManagerException(e);
}
}
/**
* Returns a list of all <code>AlertServiceConfig</code>s of type <code>clazz</code>. This
* searches through the database for this information.
*
* @param clazz class type of <code>AlertServiceConfig</code>s to return (may be null)
* @return list of <code>AlertServiceConfig</code> names
* @throws AlertServiceConfigManagerException if unable to retrieve the list
*/
@Override
public final List<AlertServiceConfig> getAlertServiceConfigList(
final Class<? extends AlertServiceConfig> clazz)
throws AlertServiceConfigManagerException {
LOGGER.debug("Getting Alert Service Config list");
final List<AlertServiceConfig> serviceConfigs;
try {
serviceConfigs = super.getList(clazz);
} catch (DBManagerException e) {
throw new BaselineManagerException(e);
}
LOGGER.debug("Got {} Alert Monitors", serviceConfigs.size());
return serviceConfigs;
}
/**
* Retrieves the <code>AlertServiceConfig</code> from the database. This searches the database
* for an entry whose name matches <code>name</code>. It then reconstructs a
* <code>AlertServiceConfig</code> object from the database entry.
*
* @param type type of the AlertServiceConfig
* @return baseline if found, otherwise null.
* @throws AlertServiceConfigManagerException if unable to search the database or recreate the
* <code>AlertServiceConfig</code>
*/
@Override
public final AlertServiceConfig getAlertServiceConfig(final String type)
throws AlertServiceConfigManagerException {
if (type == null) {
LOGGER.debug("null name argument");
return null;
}
LOGGER.debug("getting Alert Monitor: {}", type);
AlertServiceConfig ret = null;
Transaction tx = null;
Session session = getFactory().getCurrentSession();
try {
LOGGER.debug("retrieving AlertServiceConfig from db");
tx = session.beginTransaction();
CriteriaBuilder criteriaBuilder = session.getCriteriaBuilder();
CriteriaQuery<AlertServiceConfig> criteriaQuery = criteriaBuilder.createQuery(AlertServiceConfig.class);
Root<AlertServiceConfig> root = criteriaQuery.from(AlertServiceConfig.class);
Predicate recordPredicate = criteriaBuilder
.and(criteriaBuilder.equal(root.get("type"), type));
criteriaQuery.select(root).where(recordPredicate);
Query<AlertServiceConfig> query = session.createQuery(criteriaQuery);
List<AlertServiceConfig> results = query.getResultList();
if (results != null && !results.isEmpty()) {
ret = results.get(0);
}
// ret = (AlertServiceConfig) session.createCriteria(AlertServiceConfig.class)
// .add(Restrictions.eq("type", type)).uniqueResult();
tx.commit();
} catch (Exception e) {
final String msg = "unable to retrieve object";
LOGGER.error(msg, e);
if (tx != null) {
LOGGER.debug("rolling back transaction");
tx.rollback();
}
return null;
}
return ret;
}
/**
* Deletes the <code>AlertServiceConfig</code> from the database. This removes all of the
* database entries that stored information with regards to the this
* <code>AlertServiceConfig</code>. Currently, iterates over <code>Policy</code> entries and
* removes the selected <code>AlertServiceConfig</code> from them if it exists. This needs to be
* fixed as this should not be performed without user action. Update is expected soon.
*
* @param type type of the <code>AlertServiceConfig</code> to delete
* @return true if successfully found and deleted <code>AlertServiceConfig</code>
* @throws AlertServiceConfigManagerException if unable to find the baseline or delete it from
* the database
*/
@Override
public final boolean deleteAlertServiceConfig(final String type)
throws AlertServiceConfigManagerException {
if (type == null) {
LOGGER.debug("null name argument");
return false;
}
LOGGER.debug("deleting Alert Monitor: {}", type);
boolean deleted = false;
AlertServiceConfig object = null;
Transaction tx = null;
Session session = getFactory().getCurrentSession();
try {
LOGGER.debug("retrieving object from db");
tx = session.beginTransaction();
CriteriaBuilder criteriaBuilder = session.getCriteriaBuilder();
CriteriaQuery<AlertServiceConfig> criteriaQuery = criteriaBuilder.createQuery(AlertServiceConfig.class);
Root<AlertServiceConfig> root = criteriaQuery.from(AlertServiceConfig.class);
Predicate recordPredicate = criteriaBuilder
.and(criteriaBuilder.equal(root.get("type"), type));
criteriaQuery.select(root).where(recordPredicate);
Query<AlertServiceConfig> query = session.createQuery(criteriaQuery);
List<AlertServiceConfig> results = query.getResultList();
if (results != null && !results.isEmpty()) {
object = results.get(0);
}
// object = (AlertServiceConfig) session.createCriteria(AlertServiceConfig.class)
// .add(Restrictions.eq("type", type)).uniqueResult();
if (object != null) {
LOGGER.debug("found object, deleting it");
session.delete(object);
deleted = true;
}
tx.commit();
} catch (Exception e) {
final String msg = "unable to retrieve object";
LOGGER.error(msg, e);
if (tx != null) {
LOGGER.debug("rolling back transaction");
tx.rollback();
}
return false;
}
return deleted;
}
}

View File

@ -1,764 +0,0 @@
package hirs.persist;
import hirs.FilteredRecordsList;
import hirs.data.bean.SimpleBaselineBean;
import hirs.data.persist.baseline.Baseline;
import hirs.data.persist.baseline.BroadRepoImaBaseline;
import hirs.data.persist.baseline.IMABaselineRecord;
import hirs.data.persist.ImaBlacklistRecord;
import hirs.repository.RepoPackage;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.UUID;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.criterion.Disjunction;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import static org.hibernate.criterion.Restrictions.ilike;
import static org.hibernate.criterion.Restrictions.sqlRestriction;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.criterion.Conjunction;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Property;
import org.hibernate.criterion.Subqueries;
import org.hibernate.exception.SQLGrammarException;
import org.hibernate.transform.Transformers;
/**
* This class defines a <code>BaselineManager</code> that stores the baselines
* in a database.
*/
public class DBBaselineManager extends DBManager<Baseline> implements BaselineManager {
private static final Logger LOGGER = LogManager.getLogger(DBBaselineManager.class);
/**
* Creates a new <code>DBBaselineManager</code> that uses the default
* database. The default database is used to store all of the
* <code>Baseline</code>s.
*
* @param sessionFactory session factory used to access database connections
*/
public DBBaselineManager(final SessionFactory sessionFactory) {
super(Baseline.class, sessionFactory);
}
/**
* Saves the <code>Baseline</code> in the database. This creates a new
* database session and saves the baseline. If the <code>Baseline</code> had
* previously been saved then a <code>BaselineManagerException</code> is
* thrown.
*
* @param baseline
* baseline to save
* @return reference to saved baseline
* @throws BaselineManagerException
* if baseline has previously been saved or an error occurs
* while trying to save it to the database
*/
@Override
public final Baseline saveBaseline(final Baseline baseline)
throws BaselineManagerException {
LOGGER.debug("saving baseline: {}", baseline);
try {
return super.save(baseline);
} catch (DBManagerException e) {
throw new BaselineManagerException(e);
}
}
/**
* Updates a <code>Baseline</code>. This updates the database entries to
* reflect the new values that should be set.
*
* @param baseline
* baseline
* @throws BaselineManagerException
* if baseline has not previously been saved or an error occurs
* while trying to save it to the database
*/
@Override
public final void updateBaseline(final Baseline baseline) throws BaselineManagerException {
LOGGER.debug("updating baseline: {}", baseline);
try {
super.update(baseline);
} catch (DBManagerException e) {
throw new BaselineManagerException(e);
}
}
/**
* Queries the database for a list of all the <code>Baseline</code>s of type <code>clazz</code>
* that have not been soft-deleted.
*
* @param clazz
* class type of <code>Baseline</code>s to return (may be null)
* @return list of <code>Baseline</code> names
* @throws BaselineManagerException
* if unable to search the database
*/
@Override
public final List<Baseline> getBaselineList(final Class<? extends Baseline> clazz)
throws BaselineManagerException {
LOGGER.debug("Getting baseline list");
final List<Baseline> baselines = new ArrayList<>();
Class<? extends Baseline> searchClass = clazz;
if (clazz == null) {
LOGGER.debug("null clazz, using Baseline as the default search class");
searchClass = Baseline.class;
}
Session session = getFactory().getCurrentSession();
Transaction tx = session.beginTransaction();
try {
Criteria criteria = session.createCriteria(searchClass)
.add(Restrictions.isNull("archivedTime"))
.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
List list = criteria.list();
for (Object o : list) {
if (o instanceof Baseline) {
baselines.add((Baseline) o);
}
}
tx.commit();
LOGGER.debug("Got {} baselines", baselines.size());
} catch (HibernateException e) {
LOGGER.error("Unable to retrieve baselines", e);
LOGGER.debug("Rolling back transaction");
tx.rollback();
throw e;
}
LOGGER.debug("Got {} baselines", baselines.size());
return baselines;
}
/**
* Returns a list of all <code>Baseline</code>s that are ordered by a column
* and direction (ASC, DESC) that is provided by the user. This method
* helps support the server-side processing in the JQuery DataTables. Soft-deleted
* <code>Baseline</code>s are not included in the returned list.
*
* @param columnToOrder Column to be ordered
* @param ascending direction of sort
* @param firstResult starting point of first result in set
* @param maxResults total number we want returned for display in table
* @param search string of criteria to be matched to visible columns
* @param searchableColumns Map of String and boolean values with column
* headers and whether they are to. Boolean is true if field provides
* a typical String that can be searched by Hibernate without
* transformation.
* @return FilteredRecordsList object with fields for DataTables
* @throws BaselineManagerException
* if unable to create the list
*/
@Override
public final FilteredRecordsList<Baseline> getOrderedBaselineList(
final String columnToOrder, final boolean ascending,
final int firstResult, final int maxResults, final String search,
final Map<String, Boolean> searchableColumns)
throws BaselineManagerException {
if (columnToOrder == null) {
LOGGER.debug("null object argument");
throw new NullPointerException("object");
}
// check that the baseline is not archived
CriteriaModifier modifier = new CriteriaModifier() {
@Override
public void modify(final Criteria criteria) {
criteria.add(Restrictions.isNull("archivedTime"));
}
};
final FilteredRecordsList<Baseline> baselines;
try {
LOGGER.debug("querying db for baselines");
baselines = super.getOrderedList(Baseline.class, columnToOrder, ascending, firstResult,
maxResults, search, searchableColumns, modifier);
} catch (DBManagerException e) {
throw new BaselineManagerException(e);
}
return baselines;
}
/**
* Returns a list of all IMABaselineRecord that are ordered by a column
* and direction (ASC, DESC) that is provided by the user. This method
* helps support the server-side processing in the JQuery DataTables.
*
* @param baselineId id of the baseline
* @param columnToOrder Column to be ordered
* @param ascending direction of sort
* @param firstResult starting point of first result in set
* @param maxResults total number we want returned for display in table
* @param search string of criteria to be matched to visible columns
* @return FilteredRecordsList object with fields for DataTables
* @throws BaselineManagerException
* if unable to create the list
*/
@Override
public final FilteredRecordsList<IMABaselineRecord> getOrderedRecordList(
final UUID baselineId, final String columnToOrder, final boolean ascending,
final int firstResult, final int maxResults, final String search)
throws BaselineManagerException {
if (columnToOrder == null) {
LOGGER.debug("null object argument");
throw new NullPointerException("object");
}
LOGGER.debug("Getting baseline list");
//Object that will store query values
FilteredRecordsList<IMABaselineRecord> queryResults = new FilteredRecordsList<>();
Transaction tx = null;
Session session = getFactory().getCurrentSession();
try {
LOGGER.debug("updating object in db");
tx = session.beginTransaction();
Criteria criteria = session
.createCriteria(IMABaselineRecord.class, "record")
.add(sqlRestriction("ima_baseline_id='" + baselineId + "'"))
.setProjection(Projections.count("id"));
Long totalResultCount = (Long) criteria.uniqueResult();
// Search for all words in all searchable columns
Conjunction and = buildBaselineRecordSearchFilter(search);
criteria.add(and);
Long recordsFiltered = (Long) criteria.uniqueResult();
criteria.setProjection(null)
.setFirstResult(firstResult)
.setMaxResults(maxResults);
if (ascending) {
criteria.addOrder(Order.asc(columnToOrder));
} else {
criteria.addOrder(Order.desc(columnToOrder));
}
//Stores results of all the queries for the JQuery Datatable
queryResults.setRecordsTotal(totalResultCount);
queryResults.setRecordsFiltered(recordsFiltered);
List list = criteria.list();
for (Object o : list) {
if (o instanceof IMABaselineRecord) {
queryResults.add((IMABaselineRecord) o);
}
}
tx.commit();
} catch (HibernateException e) {
final String msg = "unable to update object";
LOGGER.error(msg, e);
if (tx != null) {
LOGGER.debug("rolling back transaction");
tx.rollback();
}
throw e;
}
return queryResults;
}
/**
* Returns a list of all ImaBlacklistBaseline Records that are ordered by a column
* and direction (ASC, DESC) that is provided by the user. This method
* helps support the server-side processing in the JQuery DataTables.
*
* @param baselineId id of the baseline
* @param columnToOrder Column to be ordered
* @param ascending direction of sort
* @param firstResult starting point of first result in set
* @param maxResults total number we want returned for display in table
* @param search string of criteria to be matched to visible columns
* @return FilteredRecordsList object with fields for DataTables
* @throws BaselineManagerException
* if unable to create the list
*/
@Override
public final FilteredRecordsList<ImaBlacklistRecord> getOrderedBlacklistRecordList(
final UUID baselineId, final String columnToOrder, final boolean ascending,
final int firstResult, final int maxResults, final String search)
throws BaselineManagerException {
if (columnToOrder == null) {
LOGGER.debug("null object argument");
throw new NullPointerException("object");
}
LOGGER.debug("Getting baseline list");
//Object that will store query values
FilteredRecordsList<ImaBlacklistRecord> queryResults = new FilteredRecordsList<>();
Transaction tx = null;
Session session = getFactory().getCurrentSession();
try {
LOGGER.debug("updating object in db");
tx = session.beginTransaction();
Criteria criteria = session
.createCriteria(ImaBlacklistRecord.class, "record")
.add(sqlRestriction("ima_baseline_id='" + baselineId + "'"))
.setProjection(Projections.count("id"));
Long totalResultCount = (Long) criteria.uniqueResult();
// Search for all words in all searchable columns
Conjunction and = buildBaselineRecordSearchFilter(search);
criteria.add(and);
Long recordsFiltered = (Long) criteria.uniqueResult();
criteria.setProjection(null)
.setFirstResult(firstResult)
.setMaxResults(maxResults);
if (ascending) {
criteria.addOrder(Order.asc(columnToOrder));
} else {
criteria.addOrder(Order.desc(columnToOrder));
}
//Stores results of all the queries for the JQuery Datatable
queryResults.setRecordsTotal(totalResultCount);
queryResults.setRecordsFiltered(recordsFiltered);
List list = criteria.list();
for (Object o : list) {
if (o instanceof ImaBlacklistRecord) {
queryResults.add((ImaBlacklistRecord) o);
}
}
tx.commit();
} catch (HibernateException e) {
final String msg = "unable to update object";
LOGGER.error(msg, e);
if (tx != null) {
LOGGER.debug("rolling back transaction");
tx.rollback();
}
throw e;
}
return queryResults;
}
/**
* Returns a list of all RepoPackages that are ordered by a column
* and direction (ASC, DESC) that is provided by the user. This method
* helps support the server-side processing in the JQuery DataTables.
*
* @param name name of the baseline
* @param columnToOrder Column to be ordered
* @param ascending direction of sort
* @param firstResult starting point of first result in set
* @param maxResults total number we want returned for display in table
* @param search string of criteria to be matched to visible columns
* @return FilteredRecordsList object with fields for DataTables
* @throws BaselineManagerException
* if unable to create the list
*/
@Override
public final FilteredRecordsList<RepoPackage> getOrderedPackageList(
final String name, final String columnToOrder, final boolean ascending,
final int firstResult, final int maxResults, final String search)
throws BaselineManagerException {
if (columnToOrder == null) {
LOGGER.debug("null columnToOrder argument");
throw new NullPointerException("columnToOrder");
}
LOGGER.debug("Getting package list");
//Object that will store query values
FilteredRecordsList<RepoPackage> queryResults = new FilteredRecordsList<>();
Transaction tx = null;
Session session = getFactory().getCurrentSession();
try {
tx = session.beginTransaction();
// first use a subquery to list the ids for the packages in the baseline
Criteria criteria = session.createCriteria(BroadRepoImaBaseline.class)
.createAlias("repoPackages", "pkg")
.add(Restrictions.eq("name", name));
// Get the total result count
long totalResultCount = (long) criteria
.setProjection(Projections.countDistinct("pkg.id"))
.uniqueResult();
queryResults.setRecordsTotal(totalResultCount);
if (totalResultCount > 0) {
// Get the package ids related to the baseline
List firstList = criteria.setProjection(Property.forName("pkg.id"))
.list();
final List<UUID> packageIds = new ArrayList<>();
for (Object o : firstList) {
if (o instanceof UUID) {
packageIds.add((UUID) o);
}
}
// Get the IDs for the packages that match the search filter
criteria = session.createCriteria(RepoPackage.class)
.createAlias("sourceRepository", "repo")
.createAlias("packageRecords", "rec")
.add(Restrictions.in("id", packageIds));
final long recordsFiltered;
// Add the search filters
if (StringUtils.isNotBlank(search)) {
Conjunction and = buildPackageSearchFilter(search, session);
criteria.add(and);
recordsFiltered = (long) criteria
.setProjection(Projections.countDistinct("id"))
.uniqueResult();
} else {
// If there s no search, there are no filtered records
recordsFiltered = totalResultCount;
}
queryResults.setRecordsFiltered(recordsFiltered);
if (recordsFiltered > 0) {
// Get the filtered ids
List secondList = criteria.setProjection(
Projections.distinct(Property.forName("id"))).list();
final List<UUID> morePackageIds = new ArrayList<>();
for (Object o : secondList) {
if (o instanceof UUID) {
morePackageIds.add((UUID) o);
}
}
// Remove the count projection, and sort and page to get results
criteria = session.createCriteria(RepoPackage.class)
.createAlias("sourceRepository", "repo")
.add(Restrictions.in("id", morePackageIds))
.setFirstResult(firstResult)
.setMaxResults(maxResults);
if (ascending) {
criteria.addOrder(Order.asc(columnToOrder));
} else {
criteria.addOrder(Order.desc(columnToOrder));
}
List list = criteria.list();
for (Object o : list) {
if (o instanceof RepoPackage) {
queryResults.add((RepoPackage) o);
}
}
}
}
tx.commit();
} catch (SQLGrammarException ex) {
// This sometimes happens when the result set is empty,
// due to the ugly auto-built SQL
LOGGER.error("Error getting (probably empty) package list", ex);
if (tx != null) {
LOGGER.debug("rolling back transaction");
tx.rollback();
}
} catch (HibernateException e) {
final String msg = "unable to get packages";
LOGGER.error(msg, e);
if (tx != null) {
LOGGER.debug("rolling back transaction");
tx.rollback();
}
throw e;
}
return queryResults;
}
private Conjunction buildPackageSearchFilter(final String search, final Session session) {
final List<String> searchableColumns = Arrays.asList(
"repo.name", "name", "version", "release", "rec.path");
// Search for all words in all searchable columns
Conjunction and = Restrictions.conjunction();
String[] searchWords = search.split(" ");
for (String word : searchWords) {
// Every word must be in at least one column
Disjunction or = Restrictions.disjunction();
for (String column : searchableColumns) {
or.add(ilike(column, word, MatchMode.ANYWHERE));
}
// Add additional search filter for records, since aliasing wasn't
// working properly for searching the hash/digest field
or.add(Restrictions.in("rec.id", getMatchingRecordIds(word, session)));
and.add(or);
}
return and;
}
private List<Long> getMatchingRecordIds(final String search, final Session session) {
// Get the IDs for records that match the search filter.
List<Long> matchingRecordIds = new ArrayList<>();
if (StringUtils.isNotBlank(search)) {
// Search for all words in all searchable columns
Conjunction and = buildBaselineRecordSearchFilter(search);
List list = session.createCriteria(IMABaselineRecord.class)
.add(and)
.setProjection(Property.forName("id"))
.list();
for (Object o : list) {
matchingRecordIds.add(Long.parseLong(o.toString()));
}
}
return matchingRecordIds;
}
/**
* Returns a list of all IMABaselineRecords in the specified package.
*
* @param id id of the package
* @param search string of criteria to be matched to visible columns
* @return List the records
* @throws BaselineManagerException if unable to create the list
*/
@Override
public List<IMABaselineRecord> getPackageRecords(final UUID id, final String search)
throws BaselineManagerException {
LOGGER.debug("Getting package records");
//Object that will store query values
Transaction tx = null;
Session session = getFactory().getCurrentSession();
try {
tx = session.beginTransaction();
// first use a subquery to list the ids for the records in the package
DetachedCriteria ids = DetachedCriteria.forClass(RepoPackage.class)
.createAlias("packageRecords", "rec")
.add(Restrictions.eq("id", id))
.setProjection(Property.forName("rec.id"));
Conjunction and = buildBaselineRecordSearchFilter(search);
// Get the records
List list = session.createCriteria(IMABaselineRecord.class)
.add(Subqueries.propertyIn("id", ids))
.add(and)
.addOrder(Order.asc("path"))
.list();
List<IMABaselineRecord> records = new ArrayList<>();
for (Object o : list) {
if (o instanceof IMABaselineRecord) {
records.add((IMABaselineRecord) o);
}
}
//Stores results of all the queries for the JQuery Datatable
tx.commit();
return records;
} catch (HibernateException e) {
final String msg = "unable to get packages";
LOGGER.error(msg, e);
if (tx != null) {
LOGGER.debug("rolling back transaction");
tx.rollback();
}
throw e;
}
}
private Conjunction buildBaselineRecordSearchFilter(final String search) {
// Search for all words in all searchable columns
Conjunction and = Restrictions.conjunction();
String[] searchWords = StringUtils.split(search);
for (String word : searchWords) {
// Every word must be in at least one column
Disjunction or = Restrictions.disjunction();
or.add(ilike("path", word, MatchMode.ANYWHERE));
or.add(ilikeHex("digest", word));
and.add(or);
}
return and;
}
/**
* Retrieves the <code>Baseline</code> from the database. This searches the
* database for an entry whose name matches <code>name</code>. It then
* reconstructs a <code>Baseline</code> object from the database entry
*
* @param name
* name of the baseline
* @return baseline if found, otherwise null.
* @throws BaselineManagerException
* if unable to search the database or recreate the
* <code>Baseline</code>
*/
@Override
public final Baseline getBaseline(final String name)
throws BaselineManagerException {
LOGGER.debug("getting baseline: {}", name);
try {
return super.get(name);
} catch (DBManagerException e) {
throw new BaselineManagerException(e);
}
}
@Override
public final Baseline getBaseline(final Serializable id) {
LOGGER.debug("getting baseline with id: {}", id);
try {
return super.get(id);
} catch (DBManagerException e) {
throw new BaselineManagerException(e);
}
}
@Override
public final Baseline getCompleteBaseline(final String name) throws BaselineManagerException {
LOGGER.debug("getting full baseline: {}", name);
try {
return super.getAndLoadLazyFields(name, true);
} catch (DBManagerException e) {
throw new BaselineManagerException(e);
}
}
@Override
public final FilteredRecordsList<SimpleBaselineBean> getOrderedBaselineListWithoutRecords(
final String columnToOrder, final boolean ascending,
final int firstResult, final int maxResults, final String search,
final Map<String, Boolean> searchableColumns)
throws BaselineManagerException {
if (columnToOrder == null) {
LOGGER.debug("null object argument");
throw new NullPointerException("object");
}
final FilteredRecordsList<SimpleBaselineBean> baselines =
new FilteredRecordsList<>();
final SessionFactory factory = getFactory();
Transaction tx = null;
Session session = factory.getCurrentSession();
Long totalResultCount;
Long filteredResultCount = 0L;
try {
tx = session.beginTransaction();
LOGGER.debug("retrieving baseline list without records");
// The first query gets the total number of non-archived baselines
Criteria cr = session.createCriteria(Baseline.class)
.add(Restrictions.isNull("archivedTime"))
.setProjection(Projections.countDistinct("id"));
totalResultCount = (Long) cr.uniqueResult();
// This second query finds the number of non-archived baselines matching the filter
cr = session.createCriteria(Baseline.class)
.add(Restrictions.isNull("archivedTime"))
.setProjection(Projections.countDistinct("id"));
// Filter using the search terms provided by the user
Conjunction and = Restrictions.conjunction();
if (totalResultCount != 0) {
//Builds the search criteria from all of the searchable columns
if (searchableColumns != null) {
// Search for all words in all searchable columns
String[] searchWords = search.split(" ");
for (String word : searchWords) {
// Every word must be in at least one column
Disjunction or = Restrictions.disjunction();
for (Entry<String, Boolean> entry : searchableColumns.entrySet()) {
if (entry.getValue()) {
or.add(ilike(entry.getKey(), word, MatchMode.ANYWHERE));
} else {
or.add(ilikeCast(entry.getKey(), word));
}
}
and.add(or);
}
}
cr.add(and);
filteredResultCount = (Long) cr.uniqueResult();
}
if (filteredResultCount != 0) {
// The third query builds a list from the filters, limits, and sorting options
cr = session.createCriteria(Baseline.class)
.add(Restrictions.isNull("archivedTime"))
.add(and)
.setProjection(Projections.projectionList()
.add(Projections.property("id"), "id")
.add(Projections.property("createTime"), "createTime")
.add(Projections.property("name"), "name")
.add(Projections.property("severity"), "severity")
.add(Projections.property("type"), "type"))
.setResultTransformer(Transformers.aliasToBean(SimpleBaselineBean.class))
.setFirstResult(firstResult)
.setMaxResults(maxResults);
if (ascending) {
cr.addOrder(Order.asc(columnToOrder));
} else {
cr.addOrder(Order.desc(columnToOrder));
}
// Perform the query and add all baselines to the list
List list = cr.list();
for (Object o : list) {
if (o instanceof SimpleBaselineBean) {
baselines.add((SimpleBaselineBean) o);
}
}
}
// Update meta data for the Data Table.
baselines.setRecordsTotal(totalResultCount);
baselines.setRecordsFiltered(filteredResultCount);
tx.commit();
} catch (HibernateException e) {
final String msg = "Error getting the SimpleBaselineBean list";
LOGGER.error(msg, e);
if (tx != null) {
LOGGER.debug("rolling back transaction");
tx.rollback();
}
throw e;
} finally {
if (session != null && session.isConnected()) {
session.close();
}
}
return baselines;
}
}

View File

@ -1,205 +0,0 @@
package hirs.persist;
import hirs.data.persist.Device;
import hirs.data.persist.DeviceState;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.criterion.Restrictions;
import org.hibernate.query.Query;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.List;
/**
* A <code>DBDeviceStateManager</code> manages <code>DeviceState</code> objects using a database.
*/
public class DBDeviceStateManager extends DBManager<DeviceState> implements DeviceStateManager {
private static final Logger LOGGER = LogManager.getLogger();
/**
* Creates a new <code>DBDeviceStateManager</code> that uses the default
* database. The default database is used to store all of the
* <code>DeviceState</code> objects.
*
* @param sessionFactory session factory used to access database connections
*/
public DBDeviceStateManager(final SessionFactory sessionFactory) {
super(DeviceState.class, sessionFactory);
}
/**
* Saves the <code>DeviceState</code> in the database and returns it.
*
* @param state
* state to save
* @return <code>DeviceState</code> that was saved
* @throws DeviceStateManagerException
* if state has previously been saved or an error occurs while
* trying to save it to the database
*/
@Override
public final DeviceState saveState(final DeviceState state)
throws DeviceStateManagerException {
LOGGER.debug("saving state: {}", state);
try {
return save(state);
} catch (DBManagerException e) {
throw new DeviceStateManagerException(e);
}
}
/**
* Returns the <code>DeviceState</code> for a <code>Device</code>.
*
* @param device
* device
* @param clazz
* Class to specify which type of <code>DeviceState</code> to retrieve
* @return state
* @throws DeviceStateManagerException
* if state has not previously been saved or an error occurs
* while trying to retrieve it from the database
*/
@Override
public final DeviceState getState(final Device device, final Class<? extends DeviceState> clazz)
throws DeviceStateManagerException {
LOGGER.debug("getting state for device: {}", device);
if (device == null) {
LOGGER.error("null device argument");
throw new NullPointerException("null device");
}
DeviceState ret;
Transaction tx = null;
Session session = getFactory().getCurrentSession();
try {
LOGGER.debug("retrieving state from db");
tx = session.beginTransaction();
CriteriaBuilder builder = session.getCriteriaBuilder();
CriteriaQuery<?> criteriaQuery = builder.createQuery(DeviceState.class);
Root<?> root = criteriaQuery.from();
Predicate recordPredicate = builder.and(
);
criteriaQuery.select(root).where(recordPredicate).distinct(true);
Query<?> query = session.createQuery(criteriaQuery);
List<?> results = query.getResultList();
ret = (DeviceState) session.createCriteria(clazz)
.add(Restrictions.eq("device", device)).uniqueResult();
tx.commit();
} catch (Exception e) {
final String msg = "unable to retrieve object";
LOGGER.error(msg, e);
if (tx != null) {
LOGGER.debug("rolling back transaction");
tx.rollback();
}
throw new DBManagerException(msg, e);
}
return ret;
}
/**
* Returns a <code>List</code> of the <code>DeviceStates</code> associated with the
* <code>Device</code>. If there are no states are associated, an empty list is returned.
*
* @param device
* device
* @return list of device states
* @throws DeviceStateManagerException
* if any unexpected errors occur while trying to retrieve the states
*/
@Override
public final List<DeviceState> getStates(final Device device) throws
DeviceStateManagerException {
LOGGER.debug("getting all states for device: {}", device);
if (device == null) {
LOGGER.error("null device argument");
throw new NullPointerException("null device");
}
try {
return super.getList(DeviceState.class);
} catch (DBManagerException e) {
throw new DeviceStateManagerException(e);
}
}
/**
* Updates a <code>DeviceState</code>. This updates the database entries
* to reflect the new values that should be set.
*
* @param state
* state
* @throws DeviceStateManagerException
* if state has not previously been saved or an error occurs
* while trying to save it to the database
*/
@Override
public final void updateState(final DeviceState state)
throws DeviceStateManagerException {
LOGGER.debug("updating state: {}", state);
try {
super.update(state);
} catch (DBManagerException e) {
throw new DeviceStateManagerException(e);
}
}
/**
* Deletes the <code>DeviceState</code> from the database.
*
* @param device
* device whose state is to be remove
* @param clazz
* Class to specify which type of <code>DeviceState</code> to delete
* @return true if successfully found and deleted the
* <code>DeviceState</code>
* @throws DeviceStateManagerException
* if any unexpected errors occur while trying to delete it from
* the database
*/
@Override
public final boolean deleteState(final Device device, final Class<? extends DeviceState> clazz)
throws DeviceStateManagerException {
LOGGER.debug("deleting state for device: {}", device);
if (device == null) {
LOGGER.error("null device argument");
throw new NullPointerException("null device");
}
boolean ret = false;
Transaction tx = null;
Session session = getFactory().getCurrentSession();
try {
LOGGER.debug("retrieving state from db");
tx = session.beginTransaction();
final DeviceState state = (DeviceState) session
.createCriteria(clazz)
.add(Restrictions.eq("device", device)).uniqueResult();
if (state != null) {
session.delete(state);
ret = true;
}
tx.commit();
} catch (Exception e) {
final String msg = "unable to retrieve object";
LOGGER.error(msg, e);
if (tx != null) {
LOGGER.debug("rolling back transaction");
tx.rollback();
}
throw new DBManagerException(msg, e);
}
return ret;
}
}

View File

@ -1,103 +0,0 @@
package hirs.persist;
import org.hibernate.SessionFactory;
import hirs.data.persist.Device;
import hirs.data.persist.IMADeviceState;
/**
* A <code>DBIMADeviceStateManager</code> manages <code>IMADeviceState</code> objects using a
* database.
*/
public class DBIMADeviceStateManager extends DBDeviceStateManager implements IMADeviceStateManager {
/**
* Creates a new <code>DBIMADeviceStateManager</code>. The optional SessionFactory parameter
* is used to initialize a session factory to manage all hibernate sessions.
*
* @param factory session factory to manage connections to hibernate db
*/
public DBIMADeviceStateManager(final SessionFactory factory) {
super(factory);
}
/**
* Saves the <code>IMADeviceState</code> in the database and returns it.
*
* @param state
* state to save
* @return <code>IMADeviceState</code> that was saved
* @throws IMADeviceStateManagerException
* if state has previously been saved or an error occurs while trying to save it
* to the database
*/
@Override
public final IMADeviceState saveState(final IMADeviceState state)
throws IMADeviceStateManagerException {
try {
return (IMADeviceState) super.saveState(state);
} catch (DeviceStateManagerException e) {
throw new IMADeviceStateManagerException(e);
}
}
/**
* Returns the <code>IMADeviceState</code> for a <code>Device</code>.
*
* @param device
* device
* @return state
* @throws IMADeviceStateManagerException
* if state has not previously been saved or an error occurs while trying to
* retrieve it from the database
*/
@Override
public final IMADeviceState getState(final Device device)
throws IMADeviceStateManagerException {
try {
return (IMADeviceState) super.getState(device, IMADeviceState.class);
} catch (DeviceStateManagerException e) {
throw new IMADeviceStateManagerException(e);
}
}
/**
* Updates an <code>IMADeviceState</code>. This updates the database entries to reflect the
* new values that should be set.
*
* @param state
* state
* @throws IMADeviceStateManagerException
* if state has not previously been saved or an error occurs while trying to save
* it to the database
*/
@Override
public final void updateState(final IMADeviceState state)
throws IMADeviceStateManagerException {
try {
super.updateState(state);
} catch (DeviceStateManagerException e) {
throw new IMADeviceStateManagerException(e);
}
}
/**
* Deletes the <code>IMADeviceState</code> from the database.
*
* @param device
* device whose state is to be remove
* @return true if successfully found and deleted the
* <code>IMADeviceState</code>
* @throws IMADeviceStateManagerException
* if any unexpected errors occur while trying to delete it from the database
*/
@Override
public final boolean deleteState(final Device device)
throws IMADeviceStateManagerException {
try {
return super.deleteState(device, IMADeviceState.class);
} catch (DeviceStateManagerException e) {
throw new IMADeviceStateManagerException(e);
}
}
}

View File

@ -26,9 +26,8 @@ import java.util.Map;
* Generic database manager for managing objects in a database. This provides create, read, update,
* archive, and delete operations for managing objects in a database.
*
* @param <T> type of objects to manage by this manager
*/
public class DBManager<T> extends AbstractDbManager<T> {
public class DBManager<AbstractEntity> extends AbstractDbManager<AbstractEntity> {
private static final Logger LOGGER = LogManager.getLogger(DBManager.class);
/**
@ -66,7 +65,7 @@ public class DBManager<T> extends AbstractDbManager<T> {
* @param sessionFactory the session factory to use to connect to the database
* unfortunately class type of T cannot be determined using only T
*/
public DBManager(final Class<T> clazz, final SessionFactory sessionFactory) {
public DBManager(final AbstractEntity clazz, final SessionFactory sessionFactory) {
super(clazz, sessionFactory);
setRetryTemplate(DEFAULT_MAX_RETRY_ATTEMPTS, DEFAULT_RETRY_WAIT_TIME_MS);
}
@ -115,12 +114,12 @@ public class DBManager<T> extends AbstractDbManager<T> {
* @throws DBManagerException if an error is encountered while performing the query or creating
* the result objects
*/
public final List<T> getWithCriteria(final Collection<Criterion> criteriaCollection)
public final List<AbstractEntity> getWithCriteria(final Collection<Criterion> criteriaCollection)
throws DBManagerException {
return retryTemplate.execute(
new RetryCallback<List<T>, DBManagerException>() {
new RetryCallback<List<AbstractEntity>, DBManagerException>() {
@Override
public List<T> doWithRetry(final RetryContext context)
public List<AbstractEntity> doWithRetry(final RetryContext context)
throws DBManagerException {
return doGetWithCriteria(criteriaCollection);
}
@ -131,8 +130,6 @@ public class DBManager<T> extends AbstractDbManager<T> {
* Runs a Criteria query using the given collection of Criterion over the
* associated class.
*
* @param <U> the specific type of class to retrieve
* (should extend this class' &lt;T&gt; parameter)
* @param clazzToGet the class of object to retrieve
* @param criteriaCollection the collection of Criterion to apply
*
@ -140,13 +137,13 @@ 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 <U extends T> List<U> getWithCriteria(
final Class<U> clazzToGet,
protected final List<AbstractEntity> getWithCriteria(
final Class<AbstractEntity> clazzToGet,
final Collection<Criterion> criteriaCollection) throws DBManagerException {
return retryTemplate.execute(
new RetryCallback<List<U>, DBManagerException>() {
new RetryCallback<List<AbstractEntity>, DBManagerException>() {
@Override
public List<U> doWithRetry(final RetryContext context)
public List<AbstractEntity> doWithRetry(final RetryContext context)
throws DBManagerException {
return doGetWithCriteria(clazzToGet, criteriaCollection);
}
@ -180,10 +177,10 @@ public class DBManager<T> extends AbstractDbManager<T> {
* @throws DBManagerException if object has previously been saved or an
* error occurs while trying to save it to the database
*/
public final T save(final T object) throws DBManagerException {
return retryTemplate.execute(new RetryCallback<T, DBManagerException>() {
public final AbstractEntity save(final AbstractEntity object) throws DBManagerException {
return retryTemplate.execute(new RetryCallback<AbstractEntity, DBManagerException>() {
@Override
public T doWithRetry(final RetryContext context) throws DBManagerException {
public AbstractEntity doWithRetry(final RetryContext context) throws DBManagerException {
return doSave(object);
}
});
@ -196,7 +193,7 @@ public class DBManager<T> extends AbstractDbManager<T> {
* @param object object to update
* @throws DBManagerException if an error occurs while trying to save it to the database
*/
public final void update(final T object) throws DBManagerException {
public final void update(final AbstractEntity object) throws DBManagerException {
retryTemplate.execute(new RetryCallback<Void, DBManagerException>() {
@Override
public Void doWithRetry(final RetryContext context) throws DBManagerException {
@ -216,10 +213,10 @@ public class DBManager<T> extends AbstractDbManager<T> {
* @throws DBManagerException if unable to search the database or recreate
* the <code>Object</code>
*/
public final T get(final String name) throws DBManagerException {
return retryTemplate.execute(new RetryCallback<T, DBManagerException>() {
public final AbstractEntity get(final String name) throws DBManagerException {
return retryTemplate.execute(new RetryCallback<AbstractEntity, DBManagerException>() {
@Override
public T doWithRetry(final RetryContext context) throws DBManagerException {
public AbstractEntity doWithRetry(final RetryContext context) throws DBManagerException {
return doGet(name);
}
});
@ -235,10 +232,10 @@ public class DBManager<T> extends AbstractDbManager<T> {
* @throws DBManagerException if unable to search the database or recreate
* the <code>Object</code>
*/
public final T get(final Serializable id) throws DBManagerException {
return retryTemplate.execute(new RetryCallback<T, DBManagerException>() {
public final AbstractEntity get(final Serializable id) throws DBManagerException {
return retryTemplate.execute(new RetryCallback<AbstractEntity, DBManagerException>() {
@Override
public T doWithRetry(final RetryContext context) throws DBManagerException {
public AbstractEntity doWithRetry(final RetryContext context) throws DBManagerException {
return doGet(id);
}
});
@ -259,11 +256,11 @@ public class DBManager<T> extends AbstractDbManager<T> {
* @throws DBManagerException if unable to search the database or recreate
* the <code>Object</code>
*/
public final T getAndLoadLazyFields(final String name, final boolean recurse)
public final AbstractEntity getAndLoadLazyFields(final String name, final boolean recurse)
throws DBManagerException {
return retryTemplate.execute(new RetryCallback<T, DBManagerException>() {
return retryTemplate.execute(new RetryCallback<AbstractEntity, DBManagerException>() {
@Override
public T doWithRetry(final RetryContext context) throws DBManagerException {
public AbstractEntity doWithRetry(final RetryContext context) throws DBManagerException {
return doGetAndLoadLazyFields(name, recurse);
}
});
@ -284,7 +281,7 @@ public class DBManager<T> extends AbstractDbManager<T> {
* @throws DBManagerException if unable to search the database or recreate
* the <code>Object</code>
*/
public final T getAndLoadLazyFields(final Serializable id, final boolean recurse)
public final AbstractEntity getAndLoadLazyFields(final Serializable id, final boolean recurse)
throws DBManagerException {
return doGetAndLoadLazyFields(id, recurse);
}
@ -297,14 +294,14 @@ public class DBManager<T> extends AbstractDbManager<T> {
* managed. This class argument allows the caller to limit which types of
* <code>T</code> should be returned.
*
* @param clazz class type of <code>T</code>s to search for (may be null to
* @param entity class type of <code>T</code>s to search for (may be null to
* use Class&lt;T&gt;)
* @return list of <code>T</code> names
* @throws DBManagerException if unable to search the database
*/
public List<T> getList(final Class<? extends T> clazz)
public List<AbstractEntity> getList(final AbstractEntity entity)
throws DBManagerException {
return getList(clazz, null);
return getList(entity, null);
}
/**
@ -315,19 +312,19 @@ public class DBManager<T> extends AbstractDbManager<T> {
* managed. This class argument allows the caller to limit which types of
* <code>T</code> should be returned.
*
* @param clazz class type of <code>T</code>s to search for (may be null to
* @param entity class type of <code>T</code>s to search for (may be null to
* use Class&lt;T&gt;)
* @param additionalRestriction additional restrictions to apply to criteria.
* @return list of <code>T</code> names
* @throws DBManagerException if unable to search the database
*/
@Override
public List<T> getList(final Class<? extends T> clazz, final Criterion additionalRestriction)
public List<AbstractEntity> getList(final AbstractEntity entity, final Criterion additionalRestriction)
throws DBManagerException {
return retryTemplate.execute(new RetryCallback<List<T>, DBManagerException>() {
return retryTemplate.execute(new RetryCallback<List<AbstractEntity>, DBManagerException>() {
@Override
public List<T> doWithRetry(final RetryContext context) throws DBManagerException {
return doGetList(clazz, additionalRestriction);
public List<AbstractEntity> doWithRetry(final RetryContext context) throws DBManagerException {
return doGetList(entity, additionalRestriction);
}
});
}
@ -352,7 +349,7 @@ public class DBManager<T> extends AbstractDbManager<T> {
*/
@Override
public final FilteredRecordsList getOrderedList(
final Class<? extends T> clazz, final String columnToOrder,
final AbstractEntity clazz, final String columnToOrder,
final boolean ascending, final int firstResult,
final int maxResults, final String search,
final Map<String, Boolean> searchableColumns)
@ -390,17 +387,17 @@ public class DBManager<T> extends AbstractDbManager<T> {
* @throws DBManagerException if unable to create the list
*/
@SuppressWarnings("checkstyle:parameternumber")
public final FilteredRecordsList<T> getOrderedList(
final Class<? extends T> clazz, final String columnToOrder,
public final FilteredRecordsList<AbstractEntity> getOrderedList(
final AbstractEntity clazz, final String columnToOrder,
final boolean ascending, final int firstResult,
final int maxResults, final String search,
final Map<String, Boolean> searchableColumns, final CriteriaModifier criteriaModifier)
throws DBManagerException {
return retryTemplate.execute(
new RetryCallback<FilteredRecordsList<T>, DBManagerException>() {
new RetryCallback<FilteredRecordsList<AbstractEntity>, DBManagerException>() {
@Override
public FilteredRecordsList<T> doWithRetry(final RetryContext context)
public FilteredRecordsList<AbstractEntity> doWithRetry(final RetryContext context)
throws DBManagerException {
return doGetOrderedList(clazz, columnToOrder, ascending,
firstResult, maxResults,
@ -466,7 +463,7 @@ public class DBManager<T> extends AbstractDbManager<T> {
* @throws DBManagerException if unable to delete the object from the database
*/
@Override
public final boolean delete(final T object) throws DBManagerException {
public final boolean delete(final AbstractEntity object) throws DBManagerException {
return retryTemplate.execute(new RetryCallback<Boolean, DBManagerException>() {
@Override
public Boolean doWithRetry(final RetryContext context) throws DBManagerException {
@ -491,7 +488,7 @@ public class DBManager<T> extends AbstractDbManager<T> {
return false;
}
T target = get(name);
AbstractEntity target = get(name);
if (target == null) {
return false;
}

View File

@ -8,19 +8,14 @@ import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.ProjectionList;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.hibernate.criterion.Subqueries;
import org.hibernate.query.Query;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.persistence.criteria.Subquery;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@ -170,57 +165,6 @@ public class DBReportSummaryManager extends DBManager<ReportSummary>
return reportSummaryList;
}
/**
* Returns a list of all <code>ReportSummary</code> objects that are ordered
* by a column and direction (ASC, DESC) that is provided by the user. This
* method helps support the server-side processing in the JQuery DataTables.
*
* @param columnToOrder Column to be ordered
* @param ascending direction of sort
* @param firstResult starting point of first result in set
* @param maxResults total number we want returned for display in table
* @param search string of criteria to be matched to visible columns
* @param searchableColumns Map of String and boolean values with column
* headers and whether they are to. Boolean is true if field provides
* a typical String that can be searched by Hibernate without
* transformation.
* @param hostname name of the device to filter on
* @return FilteredRecordsList object with fields for DataTables
* @throws ReportSummaryManagerException
* if unable to create the list
*/
@Override
public final FilteredRecordsList<ReportSummary> getOrderedReportSummaryList(
final String columnToOrder, final boolean ascending, final int firstResult,
final int maxResults, final String search,
final Map<String, Boolean> searchableColumns,
final String hostname) throws ReportSummaryManagerException {
if (columnToOrder == null) {
LOGGER.debug("null object argument");
throw new NullPointerException("object");
}
// allows filtering by specific hostname. If no hostname specified, always match.
CriteriaModifier modifier = new CriteriaModifier() {
@Override
public void modify(final Criteria criteria) {
criteria.add(Restrictions.ilike("clientHostname",
StringUtils.defaultIfBlank(hostname, "%")));
}
};
LOGGER.debug("Getting report summary list");
final FilteredRecordsList<ReportSummary> summaries;
try {
summaries = super.getOrderedList(ReportSummary.class, columnToOrder,
ascending, firstResult, maxResults, search,
searchableColumns, modifier);
} catch (DBManagerException e) {
throw new BaselineManagerException(e);
}
LOGGER.debug("Got {} report summaries", summaries.size());
return summaries;
}
/**
* Retrieves the <code>ReportSummary</code> from the database. This
* searches the database for an entry whose id matches <code>id</code>.
@ -339,33 +283,30 @@ public class DBReportSummaryManager extends DBManager<ReportSummary>
try {
LOGGER.debug("retrieving objects from db");
tx = session.beginTransaction();
DetachedCriteria uniqueHosts = DetachedCriteria.forClass(
ReportSummary.class);
// DetachedCriteria uniqueHosts = DetachedCriteria.forClass(
// ReportSummary.class);
ProjectionList properties = Projections.projectionList();
properties.add(Projections.groupProperty("clientHostname"));
properties.add(Projections.max("timestamp"), "timestamp");
uniqueHosts.setProjection(properties);
List list = session.createCriteria(ReportSummary.class)
.add(Subqueries.propertiesIn(
new String[]{"clientHostname", "timestamp"},
uniqueHosts))
.list();
for (Object o : list) {
if (o instanceof ReportSummary) {
reportSummaryList.add((ReportSummary) o);
}
}
// ProjectionList properties = Projections.projectionList();
// properties.add(Projections.groupProperty("clientHostname"));
// properties.add(Projections.max("timestamp"), "timestamp");
//
// uniqueHosts.setProjection(properties);
//
// List list = session.createCriteria(ReportSummary.class)
// .add(Subqueries.propertiesIn(
// new String[]{"clientHostname", "timestamp"},
// uniqueHosts))
// .list();
// for (Object o : list) {
// if (o instanceof ReportSummary) {
// reportSummaryList.add((ReportSummary) o);
// }
// }
CriteriaBuilder criteriaBuilder = session.getCriteriaBuilder();
CriteriaQuery<ReportSummary> criteriaQuery = criteriaBuilder.createQuery(ReportSummary.class);
Root<ReportSummary> root = criteriaQuery.from(ReportSummary.class);
Predicate recordPredicate = criteriaBuilder
.exists();
criteriaQuery.select(root).where(recordPredicate);
criteriaQuery.multiselect(root.get("clientHostname"), root.get("timestamp"));
Query<ReportSummary> query = session.createQuery(criteriaQuery);
List<ReportSummary> results = query.getResultList();
if (results != null) {

View File

@ -1,103 +0,0 @@
package hirs.persist;
import org.hibernate.SessionFactory;
import hirs.data.persist.Device;
import hirs.data.persist.TPMDeviceState;
/**
* A <code>DBTPMDeviceStateManager</code> manages <code>TPMDeviceState</code> objects using a
* database.
*/
public class DBTPMDeviceStateManager extends DBDeviceStateManager implements TPMDeviceStateManager {
/**
* Creates a new <code>DBTPMDeviceStateManager</code>. The optional SessionFactory parameter is
* used to initialize a session factory to manage all hibernate sessions.
*
* @param factory
* session factory to manage connections to hibernate db
*/
public DBTPMDeviceStateManager(final SessionFactory factory) {
super(factory);
}
/**
* Saves the <code>TPMDeviceState</code> in the database and returns it.
*
* @param state
* state to save
* @return <code>TPMDeviceState</code> that was saved
* @throws TPMDeviceStateManagerException
* if state has previously been saved or an error occurs while trying to save it to
* the database
*/
@Override
public final TPMDeviceState saveState(final TPMDeviceState state)
throws TPMDeviceStateManagerException {
try {
return (TPMDeviceState) super.saveState(state);
} catch (DeviceStateManagerException e) {
throw new TPMDeviceStateManagerException(e);
}
}
/**
* Returns the <code>TPMDeviceState</code> for a <code>Device</code>.
*
* @param device
* device
* @return state
* @throws TPMDeviceStateManagerException
* if state has not previously been saved or an error occurs while trying to
* retrieve it from the database
*/
@Override
public final TPMDeviceState getState(final Device device)
throws TPMDeviceStateManagerException {
try {
return (TPMDeviceState) super.getState(device, TPMDeviceState.class);
} catch (DeviceStateManagerException e) {
throw new TPMDeviceStateManagerException(e);
}
}
/**
* Updates an <code>TPMDeviceState</code>. This updates the database entries to reflect the new
* values that should be set.
*
* @param state
* state
* @throws TPMDeviceStateManagerException
* if state has not previously been saved or an error occurs while trying to save it
* to the database
*/
@Override
public final void updateState(final TPMDeviceState state)
throws TPMDeviceStateManagerException {
try {
super.updateState(state);
} catch (DeviceStateManagerException e) {
throw new TPMDeviceStateManagerException(e);
}
}
/**
* Deletes the <code>TPMDeviceState</code> from the database.
*
* @param device
* device whose state is to be remove
* @return true if successfully found and deleted the <code>TPMDeviceState</code>
* @throws TPMDeviceStateManagerException
* if any unexpected errors occur while trying to delete it from the database
*/
@Override
public final boolean deleteState(final Device device) throws TPMDeviceStateManagerException {
try {
return super.deleteState(device, TPMDeviceState.class);
} catch (DeviceStateManagerException e) {
throw new TPMDeviceStateManagerException(e);
}
}
}

View File

@ -1,344 +0,0 @@
package hirs.persist;
import hirs.data.persist.Digest;
import hirs.data.persist.baseline.IMABaselineRecord;
import hirs.data.persist.OptionalDigest;
import hirs.data.persist.baseline.QueryableRecordImaBaseline;
import hirs.data.persist.baseline.SimpleImaBaseline;
import hirs.utils.Callback;
import hirs.utils.Job;
import hirs.utils.JobExecutor;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.ScrollMode;
import org.hibernate.ScrollableResults;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.StatelessSession;
import org.hibernate.Transaction;
import org.hibernate.criterion.Restrictions;
import org.hibernate.transform.Transformers;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicInteger;
/**
*
*/
public class DbImaBaselineRecordManager extends DBManager<IMABaselineRecord>
implements ImaBaselineRecordManager {
private static final Logger LOGGER =
LogManager.getLogger(DbImaBaselineRecordManager.class);
private static final int LOGGING_INTERVAL = 500;
/**
* Creates a new <code>DBImaBaselineRecordManager</code> that uses the default
* database. The default database is used to store all of the
* <code>IMABaselineRecord</code>s.
*
* @param sessionFactory session factory used to access database connections
*/
public DbImaBaselineRecordManager(final SessionFactory sessionFactory) {
super(IMABaselineRecord.class, sessionFactory);
}
/**
* Stores a new <code>IMABaselineRecord</code>. This stores a new
* <code>IMABaselineRecord</code> to be managed by the <code>IMABaselineRecordManager</code>.
* If the <code>IMABaselineRecord</code> is successfully saved then a reference to it is
* returned.
* <p>
* Should only save the record to a <code>SimpleImaBaseline</code> Other baselines should
* not be controlled by the user.
* <p> Records added in this manner MUST have a baseline set to them.
*
* @param record
* Record to save
* @return reference to saved IMABaselineRecord
* @throws ImaBaselineRecordManagerException
* if the record has previously been saved or unexpected error
* occurs
*/
@Override
public IMABaselineRecord saveRecord(final IMABaselineRecord record)
throws ImaBaselineRecordManagerException {
LOGGER.debug("saving ima baseline record: {}", record);
//When adding a record through the manager, the record should be associated with a baseline
if (record == null || record.getBaseline() == null) {
throw new ImaBaselineRecordManagerException("Record cannot be saved without setting"
+ " baseline.");
}
try {
//Checks to make sure a duplicate record does not already exist in the baseline. This
//is done in this fashion due to the inability to put constraints on the table.
if (getRecord(record.getPath(), record.getHash(),
(SimpleImaBaseline) record.getBaseline()) != null) {
throw new ImaBaselineRecordManagerException("Record already exists.");
} else {
return super.save(record);
}
} catch (DBManagerException e) {
throw new ImaBaselineRecordManagerException(e);
}
}
/**
* Retrieves an <code>IMABaselineRecord</code> based on the id of the record.
*
* @param id
* id of the <code>IMABaselineRecord</code>
* @return
* instance of the requested <code>IMABaselineRecord</code>
* @throws ImaBaselineRecordManagerException
* if the record has previously been saved or unexpected error occurs
*/
@Override
public IMABaselineRecord getRecord(final long id) throws ImaBaselineRecordManagerException {
LOGGER.debug("getting baseline: {}", id);
try {
return super.get(id);
} catch (DBManagerException e) {
throw new ImaBaselineRecordManagerException(e);
}
}
/**
* Retrieves <code>IMABaselineRecord</code> with the given path, hash, and assigned IMA
* baseline id.
*
* @param path
* path of the record to be retrieved
* @param hash
* hash of the record to be retrieved
* @param baseline
* baseline that is associated with the desired record.
* @return
* IMABaselineRecord that matches the provided path, hash, and baseline ID
*/
private IMABaselineRecord getRecord(final String path, final OptionalDigest hash,
final SimpleImaBaseline baseline) {
LOGGER.debug("Getting object list");
if (path == null || hash == null || baseline == null) {
LOGGER.error("path, hash, or baseline was null");
return null;
}
IMABaselineRecord record = null;
Transaction tx = null;
Session session = getFactory().getCurrentSession();
try {
tx = session.beginTransaction();
record = (IMABaselineRecord) session.createCriteria(IMABaselineRecord.class)
.add(Restrictions.eq("path", path))
.add(Restrictions.eq("hash", hash))
.add(Restrictions.eq("baseline", baseline))
.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY).uniqueResult();
tx.commit();
LOGGER.debug("Retrieved record object");
} catch (HibernateException e) {
LOGGER.error("Unable to retrieve record", e);
if (tx != null) {
LOGGER.debug("Rolling back transaction");
tx.rollback();
}
throw e;
}
return record;
}
/**
* Retrieves <code>IMABaselineRecord</code> with the given path, hash, and assigned IMA
* baseline id.
*
* @param path
* path of the record to be retrieved
* @param hash
* hash of the record to be retrieved
* @param baseline
* baseline that is associated with the desired record.
* @return
* IMABaselineRecord that matches the provided path, hash, and baseline ID
*/
@Override
public IMABaselineRecord getRecord(final String path, final Digest hash,
final SimpleImaBaseline baseline) {
OptionalDigest optionalDigest = null;
if (hash != null) {
optionalDigest = hash.asOptionalDigest();
}
return getRecord(path, optionalDigest, baseline);
}
/**
* Deletes the <code>ImaBaselineRecord</code> identified by <code>id</code>. If the
* <code>ImaBaselineRecord</code> is found and deleted then true is returned,
* otherwise false.
* <p>
* Will likely be used to delete records of a <code>SimpleImaBaseline</code> Other IMA
* baselines would not be controlled by the user at this time.
*
* @param id
* id of the <code>ImaBaselineRecord</code> to delete
* @return true if successfully found and deleted from database, otherwise false
* @throws ImaBaselineRecordManagerException
* if unable to delete the ImaBaselineRecord for any reason other than
* not found
*/
@Override
public boolean deleteRecord(final Long id) throws ImaBaselineRecordManagerException {
LOGGER.debug("deleting ima baseline record: {}", id);
try {
return super.delete(id);
} catch (DBManagerException e) {
throw new ImaBaselineRecordManagerException(e);
}
}
/**
* Deletes the <code>ImaBaselineRecord</code> provided. If the
* <code>ImaBaselineRecord</code> is found and deleted then true is returned,
* otherwise false.
* @param record
* record object to be deleted.
* @return true if successfully found and deleted from database, otherwise false
* @throws ImaBaselineRecordManagerException
* if unable to delete the ImaBaselineRecord for any reason other than
* not found
*/
@Override
public boolean deleteRecord(final IMABaselineRecord record)
throws ImaBaselineRecordManagerException {
if (record == null || record.getBaseline() == null) {
throw new ImaBaselineRecordManagerException("record or baseline of record not set");
}
LOGGER.debug("deleting ima baseline record: {}", record.getId());
try {
return super.delete(record);
} catch (DBManagerException e) {
throw new ImaBaselineRecordManagerException(e);
}
}
/**
* Iterates over the {@link IMABaselineRecord}s in the given baseline, and calls the given
* Callback on each record. If the callback returns a non-null value, the returned value will
* be added to a collection, which is returned when iteration is finished.
*
* @param baseline the baseline whose {@link IMABaselineRecord}s we should iterate over
* @param callback the callback to run on each record
* @param <T> the return type of the callback
* @return the total collection of objects returned as results from the given Callback
*/
public final <T> Collection<T> iterateOverBaselineRecords(
final QueryableRecordImaBaseline baseline,
final Callback<IMABaselineRecord, T> callback) {
final Collection<T> allResults = new ConcurrentLinkedQueue<>();
Collection<Callable<Void>> tasks = new ArrayList<>();
int fetchSize;
switch (getConfiguredImplementation()) {
case MYSQL:
fetchSize = Integer.MIN_VALUE;
break;
case HSQL:
default:
fetchSize = 1;
}
DBImpl impl = getConfiguredImplementation();
if (impl == DBImpl.MYSQL) {
// provides a hint to the JDBC connector that records should be streamed
fetchSize = Integer.MIN_VALUE;
} else if (impl == DBImpl.HSQL) {
fetchSize = 1;
}
final AtomicInteger recCounter = new AtomicInteger();
for (int i = 0; i < IMABaselineRecord.FILENAME_HASH_BUCKET_COUNT; i++) {
final int bucket = i;
final int finalFetchSize = fetchSize;
tasks.add(new Callable<Void>() {
@Override
public Void call() throws Exception {
LOGGER.debug(String.format(
"IMA record iteration: starting examiner thread %d",
bucket
));
List<T> results = new LinkedList<>();
StatelessSession statelessSession = getStatelessSession();
try {
Transaction tx = statelessSession.beginTransaction();
Criteria criteria = statelessSession.createCriteria(baseline.getClass());
baseline.configureCriteriaForBaselineRecords(criteria, bucket);
criteria.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
criteria.setReadOnly(true);
criteria.setFetchSize(finalFetchSize);
ScrollableResults records = criteria.scroll(ScrollMode.FORWARD_ONLY);
Map entry;
IMABaselineRecord baselineRecord;
while (records.next()) {
// get(0) guarantees other rows won't be initialized
entry = (Map) records.get(0);
String path = (String) entry.get(IMABaselineRecord.PATH_FIELD);
OptionalDigest digest =
(OptionalDigest) entry.get(IMABaselineRecord.HASH_FIELD);
baselineRecord = new IMABaselineRecord(path, digest.asDigest());
T result = callback.call(baselineRecord);
if (result != null) {
results.add(result);
}
int count = recCounter.incrementAndGet();
if (count % LOGGING_INTERVAL == 0) {
LOGGER.debug(String.format(
"IMA record iteration: examined %d records", count
));
}
}
tx.commit();
} catch (Exception e) {
throw e;
} finally {
statelessSession.close();
}
allResults.addAll(results);
return null;
}
});
}
JobExecutor executor = new JobExecutor();
Job<Void> job = new Job<>(tasks);
executor.scheduleJob(job);
try {
executor.shutdown();
} catch (InterruptedException e) {
throw new DBManagerException(e);
}
if (job.getState() != Job.State.COMPLETED) {
LOGGER.error("Appraisal job finished in state {}", job.getState().toString());
for (String s : job.getAllFailures()) {
throw new DBManagerException(s);
}
}
return allResults;
}
}

View File

@ -1,344 +0,0 @@
package hirs.persist;
import hirs.data.persist.Digest;
import hirs.data.persist.ImaBlacklistRecord;
import hirs.data.persist.OptionalDigest;
import hirs.data.persist.baseline.QueryableRecordImaBaseline;
import hirs.data.persist.baseline.ImaBlacklistBaseline;
import hirs.utils.Callback;
import hirs.utils.Job;
import hirs.utils.JobExecutor;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.ScrollMode;
import org.hibernate.ScrollableResults;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.StatelessSession;
import org.hibernate.Transaction;
import org.hibernate.criterion.Restrictions;
import org.hibernate.transform.Transformers;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicInteger;
/**
*
*/
public class DbImaBlacklistBaselineRecordManager extends DBManager<ImaBlacklistRecord>
implements ImaBlacklistBaselineRecordManager {
private static final Logger LOGGER =
LogManager.getLogger(DbImaBlacklistBaselineRecordManager.class);
private static final int LOGGING_INTERVAL = 500;
/**
* Creates a new <code>DBImaBaselineRecordManager</code>. The optional
* SessionFactory parameter is used to manage sessions with a
* hibernate db.
*
* @param factory session factory used to access database connections
*/
public DbImaBlacklistBaselineRecordManager(final SessionFactory factory) {
super(ImaBlacklistRecord.class, factory);
}
/**
* Stores a new <code>ImaBlacklistRecord</code>. This stores a new
* <code>ImaBlacklistRecord</code> to be managed by the <code>IMABaselineRecordManager</code>.
* If the <code>ImaBlacklistRecord</code> is successfully saved then a reference to it is
* returned.
* <p>
* Should only save the record to a <code>ImaBlacklistBaseline</code> Other baselines should
* not be controlled by the user.
* <p> Records added in this manner MUST have a baseline set to them.
*
* @param record
* Record to save
* @return reference to saved ImaBlacklistRecord
* @throws ImaBaselineRecordManagerException
* if the record has previously been saved or unexpected error
* occurs
*/
@Override
public ImaBlacklistRecord saveRecord(final ImaBlacklistRecord record)
throws ImaBaselineRecordManagerException {
LOGGER.debug("saving ima baseline record: {}", record);
//When adding a record through the manager, the record should be associated with a baseline
if (record == null || record.getBaseline() == null) {
throw new ImaBaselineRecordManagerException("Record cannot be saved without setting"
+ " baseline.");
}
try {
//Checks to make sure a duplicate record does not already exist in the baseline. This
//is done in this fashion due to the inability to put constraints on the table.
if (getRecord(record.getPath(), record.getHash(),
(ImaBlacklistBaseline) record.getBaseline()) != null) {
throw new ImaBaselineRecordManagerException("Record already exists.");
} else {
return super.save(record);
}
} catch (DBManagerException e) {
throw new ImaBaselineRecordManagerException(e);
}
}
/**
* Retrieves an <code>ImaBlacklistRecord</code> based on the id of the record.
*
* @param id
* id of the <code>ImaBlacklistRecord</code>
* @return
* instance of the requested <code>ImaBlacklistRecord</code>
* @throws ImaBaselineRecordManagerException
* if the record has previously been saved or unexpected error occurs
*/
@Override
public ImaBlacklistRecord getRecord(final long id) throws ImaBaselineRecordManagerException {
LOGGER.debug("getting baseline: {}", id);
try {
return super.get(id);
} catch (DBManagerException e) {
throw new ImaBaselineRecordManagerException(e);
}
}
/**
* Retrieves <code>ImaBlacklistRecord</code> with the given path, hash, and assigned IMA
* baseline id.
*
* @param path
* path of the record to be retrieved
* @param hash
* hash of the record to be retrieved
* @param baseline
* baseline that is associated with the desired record.
* @return
* ImaBlacklistRecord that matches the provided path, hash, and baseline ID
*/
private ImaBlacklistRecord getRecord(final String path, final OptionalDigest hash,
final ImaBlacklistBaseline baseline) {
LOGGER.debug("Getting object list");
if (path == null || hash == null || baseline == null) {
LOGGER.error("path, hash, or baseline was null");
return null;
}
ImaBlacklistRecord record = null;
Transaction tx = null;
Session session = getFactory().getCurrentSession();
try {
tx = session.beginTransaction();
record = (ImaBlacklistRecord) session.createCriteria(ImaBlacklistRecord.class)
.add(Restrictions.eq("path", path))
.add(Restrictions.eq("hash", hash))
.add(Restrictions.eq("baseline", baseline))
.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY).uniqueResult();
tx.commit();
LOGGER.debug("Retrieved record object");
} catch (HibernateException e) {
LOGGER.error("Unable to retrieve record", e);
if (tx != null) {
LOGGER.debug("Rolling back transaction");
tx.rollback();
}
throw e;
}
return record;
}
/**
* Retrieves <code>ImaBlacklistRecord</code> with the given path, hash, and assigned IMA
* baseline id.
*
* @param path
* path of the record to be retrieved
* @param hash
* hash of the record to be retrieved
* @param baseline
* baseline that is associated with the desired record.
* @return
* ImaBlacklistRecord that matches the provided path, hash, and baseline ID
*/
@Override
public ImaBlacklistRecord getRecord(final String path, final Digest hash,
final ImaBlacklistBaseline baseline) {
OptionalDigest optionalDigest = null;
if (hash != null) {
optionalDigest = hash.asOptionalDigest();
}
return getRecord(path, optionalDigest, baseline);
}
/**
* Deletes the <code>ImaBaselineRecord</code> identified by <code>id</code>. If the
* <code>ImaBaselineRecord</code> is found and deleted then true is returned,
* otherwise false.
* <p>
* Will likely be used to delete records of a <code>ImaBlacklistBaseline</code> Other IMA
* baselines would not be controlled by the user at this time.
*
* @param id
* id of the <code>ImaBaselineRecord</code> to delete
* @return true if successfully found and deleted from database, otherwise false
* @throws ImaBaselineRecordManagerException
* if unable to delete the ImaBaselineRecord for any reason other than
* not found
*/
@Override
public boolean deleteRecord(final Long id) throws ImaBaselineRecordManagerException {
LOGGER.debug("deleting ima baseline record: {}", id);
try {
return super.delete(id);
} catch (DBManagerException e) {
throw new ImaBaselineRecordManagerException(e);
}
}
/**
* Deletes the <code>ImaBaselineRecord</code> provided. If the
* <code>ImaBaselineRecord</code> is found and deleted then true is returned,
* otherwise false.
* @param record
* record object to be deleted.
* @return true if successfully found and deleted from database, otherwise false
* @throws ImaBaselineRecordManagerException
* if unable to delete the ImaBaselineRecord for any reason other than
* not found
*/
@Override
public boolean deleteRecord(final ImaBlacklistRecord record)
throws ImaBaselineRecordManagerException {
if (record == null || record.getBaseline() == null) {
throw new ImaBaselineRecordManagerException("record or baseline of record not set");
}
LOGGER.debug("deleting ima baseline record: {}", record.getId());
try {
return super.delete(record);
} catch (DBManagerException e) {
throw new ImaBaselineRecordManagerException(e);
}
}
/**
* Iterates over the {@link ImaBlacklistRecord}s in the given baseline, and calls the given
* Callback on each record. If the callback returns a non-null value, the returned value will
* be added to a collection, which is returned when iteration is finished.
*
* @param baseline the baseline whose {@link ImaBlacklistRecord}s we should iterate over
* @param callback the callback to run on each record
* @param <T> the return type of the callback
* @return the total collection of objects returned as results from the given Callback
*/
public final <T> Collection<T> iterateOverBaselineRecords(
final QueryableRecordImaBaseline baseline,
final Callback<ImaBlacklistRecord, T> callback) {
final Collection<T> allResults = new ConcurrentLinkedQueue<>();
Collection<Callable<Void>> tasks = new ArrayList<>();
int fetchSize;
switch (getConfiguredImplementation()) {
case MYSQL:
fetchSize = Integer.MIN_VALUE;
break;
case HSQL:
default:
fetchSize = 1;
}
DBImpl impl = getConfiguredImplementation();
if (impl == DBImpl.MYSQL) {
// provides a hint to the JDBC connector that records should be streamed
fetchSize = Integer.MIN_VALUE;
} else if (impl == DBImpl.HSQL) {
fetchSize = 1;
}
final AtomicInteger recCounter = new AtomicInteger();
for (int i = 0; i < ImaBlacklistRecord.FILENAME_HASH_BUCKET_COUNT; i++) {
final int bucket = i;
final int finalFetchSize = fetchSize;
tasks.add(new Callable<Void>() {
@Override
public Void call() throws Exception {
LOGGER.debug(String.format(
"IMA record iteration: starting examiner thread %d",
bucket
));
List<T> results = new LinkedList<>();
StatelessSession statelessSession = getStatelessSession();
try {
Transaction tx = statelessSession.beginTransaction();
Criteria criteria = statelessSession.createCriteria(baseline.getClass());
baseline.configureCriteriaForBaselineRecords(criteria, bucket);
criteria.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
criteria.setReadOnly(true);
criteria.setFetchSize(finalFetchSize);
ScrollableResults records = criteria.scroll(ScrollMode.FORWARD_ONLY);
Map entry;
ImaBlacklistRecord baselineRecord;
while (records.next()) {
// get(0) guarantees other rows won't be initialized
entry = (Map) records.get(0);
String path = (String) entry.get(ImaBlacklistRecord.PATH_FIELD);
OptionalDigest digest =
(OptionalDigest) entry.get(ImaBlacklistRecord.HASH_FIELD);
baselineRecord = new ImaBlacklistRecord(path, digest.asDigest());
T result = callback.call(baselineRecord);
if (result != null) {
results.add(result);
}
int count = recCounter.incrementAndGet();
if (count % LOGGING_INTERVAL == 0) {
LOGGER.debug(String.format(
"IMA record iteration: examined %d records", count
));
}
}
tx.commit();
} catch (Exception e) {
throw e;
} finally {
statelessSession.close();
}
allResults.addAll(results);
return null;
}
});
}
JobExecutor executor = new JobExecutor();
Job<Void> job = new Job<>(tasks);
executor.scheduleJob(job);
try {
executor.shutdown();
} catch (InterruptedException e) {
throw new DBManagerException(e);
}
if (job.getState() != Job.State.COMPLETED) {
LOGGER.error("Appraisal job finished in state {}", job.getState().toString());
for (String s : job.getAllFailures()) {
throw new DBManagerException(s);
}
}
return allResults;
}
}

View File

@ -1,35 +0,0 @@
package hirs.persist;
import hirs.data.persist.Alert;
import java.util.List;
/**
* Class for managing the {@link hirs.data.persist.enums.HealthStatus}
* of a {@link hirs.data.persist.Device}.
*/
public interface DeviceHealthManager {
/**
* Updates the health of a device given the name of the device.
*
* Finds the latest report for the device. Finds all device state objects for the device to get
* additional criterion to use to search for alerts. Device health is updated to UNKNOWN if
* there are no previous reports, UNTRUSTED if there are still relevant alerts given the search
* criteria, and TRUSTED if there are no relevant alerts.
*
* @param deviceName name of device
*/
void updateHealth(String deviceName);
/**
* Updates the health of a device or devices given a list of alerts.
*
* Useful for updating health after resolving a list of alerts, this method pulls all the
* unique device names from the alerts list and calls {@link #updateHealth(String)} for each
* device once.
*
* @param alerts list of alerts
*/
void updateHealth(List<Alert> alerts);
}

View File

@ -1,113 +0,0 @@
package hirs.persist;
import hirs.data.persist.Alert;
import hirs.data.persist.Device;
import hirs.data.persist.DeviceState;
import hirs.data.persist.enums.HealthStatus;
import hirs.data.persist.Report;
import hirs.data.persist.ReportSummary;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.Logger;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Disjunction;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import static org.apache.logging.log4j.LogManager.getLogger;
/**
* Implementation class for DeviceHealthManager.
*/
public class DeviceHealthManagerImpl implements DeviceHealthManager {
private static final Logger LOGGER = getLogger(DeviceHealthManagerImpl.class);
@Autowired
private DeviceManager deviceManager;
@Autowired
private AlertManager alertManager;
@Autowired
@Qualifier(PersistenceConfiguration.DEVICE_STATE_MANAGER_BEAN_NAME)
private DeviceStateManager deviceStateManager;
@Autowired
private ReportSummaryManager reportSummaryManager;
@Override
public void updateHealth(final String deviceName) {
Device device = deviceManager.getDevice(deviceName);
if (null == device) {
throw new IllegalArgumentException("No device with name: " + deviceName);
}
List<DeviceState> deviceStates = deviceStateManager.getStates(device);
Report report = null;
try {
ReportSummary latestReportSummary =
reportSummaryManager.getNewestReport(device.getName());
// if there's no (latest) report for this device, set the health to Unknown
if (null == latestReportSummary) {
LOGGER.warn("No latest report for {}. Setting health status to Unknown", device);
device.setHealthStatus(HealthStatus.UNKNOWN);
} else {
report = latestReportSummary.getReport();
}
} catch (Exception e) {
LOGGER.warn("Failed to get latest report for {}. "
+ "Setting health status to Unknown", device, e);
device.setHealthStatus(HealthStatus.UNKNOWN);
}
if (null != report) {
Disjunction disjunction = Restrictions.disjunction();
boolean hasValidCriterions = false;
for (DeviceState state : deviceStates) {
Criterion criterion = state.getDeviceTrustAlertCriterion();
if (null != criterion) {
disjunction.add(criterion);
hasValidCriterions = true;
}
}
if (!hasValidCriterions) {
disjunction = null;
}
int alertCount = alertManager.getTrustAlertCount(device, report, disjunction);
LOGGER.info("Found {} trust alerts for {}", alertCount, device);
if (alertCount > 0) {
device.setHealthStatus(HealthStatus.UNTRUSTED);
} else {
device.setHealthStatus(HealthStatus.TRUSTED);
}
}
deviceManager.updateDevice(device);
}
@Override
public void updateHealth(final List<Alert> alerts) {
if (alerts == null) {
throw new NullPointerException("alert list");
}
Set<String> deviceNames = new HashSet<>();
// get the set of unique device names for these alerts
for (Alert alert : alerts) {
String deviceName = alert.getDeviceName();
if (StringUtils.isNotEmpty(deviceName)) {
deviceNames.add(deviceName);
}
}
for (String deviceName : deviceNames) {
updateHealth(deviceName);
}
}
}

View File

@ -1,81 +0,0 @@
package hirs.persist;
import hirs.data.persist.Device;
import hirs.data.persist.DeviceState;
import java.util.List;
/**
* Manages the device state for an appraisal. See {@link DeviceState} for more details.
*
* @see DeviceState
*/
public interface DeviceStateManager {
/**
* Stores a new <code>DeviceState</code>. This stores a new <code>DeviceState</code> to be
* managed by the <code>DeviceStateManager</code>. If the <code>DeviceState</code> is
* successfully saved then a reference to it is returned.
*
* @param state
* state to save
* @return reference to saved <code>DeviceState</code>
* @throws DeviceStateManagerException
* if the Policy has previously been saved or unexpected error occurs
*/
DeviceState saveState(DeviceState state) throws DeviceStateManagerException;
/**
* Returns the state associated with the <code>Device</code> or null if not found.
*
* @param device
* device
* @param clazz
* Class to specify which type of <code>DeviceState</code> to retrieve
* @return device state for <code>Device</code>
* @throws DeviceStateManagerException
* if any unexpected errors occur while trying to retrieve the state
*/
DeviceState getState(Device device, Class<? extends DeviceState> clazz)
throws DeviceStateManagerException;
/**
* Returns a <code>List</code> of the <code>DeviceStates</code> associated with the
* <code>Device</code>. If there are no states are associated, an empty list is returned.
*
* @param device
* device
* @return list of device states
* @throws DeviceStateManagerException
* if any unexpected errors occur while trying to retrieve the states
*/
List<DeviceState> getStates(Device device) throws DeviceStateManagerException;
/**
* Updates the state for the <code>Device</code>.
*
* @param state
* new state for the <code>Device</code>
* @throws DeviceStateManagerException
* if any unexpected errors occur while trying to retrieve the state
*/
void updateState(DeviceState state) throws DeviceStateManagerException;
/**
* Removes the saved state for the <code>Device</code>. If the device state was successfully
* found and removed then true is returned. If there was no device state currently being managed
* by this manager then false is returned. If device state is found but unable to be deleted
* because of unexpected errors then an <code>DeviceStateManagerException</code> is thrown
*
* @param device
* device whose state is to be removed
* @param clazz
* Class to specify which type of <code>DeviceState</code> to retrieve
* @return true if successfully found state for device and deleted it, otherwise false
* @throws DeviceStateManagerException
* if any unexpected errors occur while trying to retrieve the state
*/
boolean deleteState(Device device, Class<? extends DeviceState> clazz)
throws DeviceStateManagerException;
}

View File

@ -1,46 +0,0 @@
package hirs.persist;
/**
* This class represents an <code>Exception</code> generated by a
* <code>DeviceStateManager</code>.
*/
public class DeviceStateManagerException extends RuntimeException {
private static final long serialVersionUID = 1266522688839309858L;
/**
* Creates a new <code>DeviceStateManagerException</code> that has the
* message <code>msg</code>.
*
* @param msg
* exception message
*/
DeviceStateManagerException(final String msg) {
super(msg);
}
/**
* Creates a new <code>DeviceStateManagerException</code> that wraps the
* given <code>Throwable</code>.
*
* @param t
* root cause
*/
DeviceStateManagerException(final Throwable t) {
super(t);
}
/**
* Creates a new <code>DeviceStateManagerException</code> that has the
* message <code>msg</code> and wraps the root cause.
*
* @param msg
* exception message
* @param t
* root cause
*/
DeviceStateManagerException(final String msg, final Throwable t) {
super(msg, t);
}
}

View File

@ -1,62 +0,0 @@
package hirs.persist;
import hirs.data.persist.Device;
import hirs.data.persist.IMADeviceState;
/**
* Manages the device state for an IMA appraisal. See {@link IMADeviceState} for more details.
*
* @see IMADeviceState
*/
public interface IMADeviceStateManager {
/**
* Stores a new <code>IMADeviceState</code>. This stores a new <code>IMADeviceState</code> to be
* managed by the <code>IMADeviceStateManager</code>. If the <code>IMADeviceState</code> is
* successfully saved then a reference to it is returned.
*
* @param state
* state to save
* @return reference to saved <code>IMADeviceState</code>
* @throws IMADeviceStateManagerException
* if the Policy has previously been saved or unexpected error occurs
*/
IMADeviceState saveState(IMADeviceState state) throws IMADeviceStateManagerException;
/**
* Returns the state associated with the <code>Device</code> or null if not found.
*
* @param device
* device
* @return device state for <code>Device</code>
* @throws IMADeviceStateManagerException
* if any unexpected errors occur while trying to retrieve the state
*/
IMADeviceState getState(Device device) throws IMADeviceStateManagerException;
/**
* Updates the state for the <code>Device</code>.
*
* @param state
* new state for the <code>Device</code>
* @throws IMADeviceStateManagerException
* if any unexpected errors occur while trying to retrieve the state
*/
void updateState(IMADeviceState state) throws IMADeviceStateManagerException;
/**
* Removes the saved state for the <code>Device</code>. If the device state was successfully
* found and removed then true is returned. If there was no device state currently being
* managed by this manager then false is returned. If device state is found but unable to be
* deleted because of unexpected errors then an <code>IMADeviceStateManagerException</code> is
* thrown
*
* @param device
* device whose state is to be removed
* @return true if successfully found state for device and deleted it, otherwise false
* @throws IMADeviceStateManagerException
* if any unexpected errors occur while trying to retrieve the state
*/
boolean deleteState(Device device) throws IMADeviceStateManagerException;
}

View File

@ -1,46 +0,0 @@
package hirs.persist;
/**
* This class represents an <code>Exception</code> generated by a
* <code>IMADeviceStateManageer</code>.
*/
public class IMADeviceStateManagerException extends RuntimeException {
private static final long serialVersionUID = 1266522688839309858L;
/**
* Creates a new <code>IMADeviceStateManagerException</code> that has the
* message <code>msg</code>.
*
* @param msg
* exception message
*/
IMADeviceStateManagerException(final String msg) {
super(msg);
}
/**
* Creates a new <code>IMADeviceStateManagerException</code> that wraps the
* given <code>Throwable</code>.
*
* @param t
* root cause
*/
IMADeviceStateManagerException(final Throwable t) {
super(t);
}
/**
* Creates a new <code>IMADeviceStateManagerException</code> that has the
* message <code>msg</code> and wraps the root cause.
*
* @param msg
* exception message
* @param t
* root cause
*/
IMADeviceStateManagerException(final String msg, final Throwable t) {
super(msg, t);
}
}

View File

@ -1,53 +0,0 @@
package hirs.persist;
/**
* List of valid IMAMeasurementRecord fields to prevent query injection since parameterization of
* field names is not possible in HQL.
*/
public enum IMARecordField {
/**
* The path associated with the record.
*/
PATH("path"),
/**
* The hash associated with the record.
*/
HASH("hash");
private final String field;
/**
* Constructor for {@link IMARecordField}.
* @param field the field
*/
IMARecordField(final String field) {
this.field = field;
}
/**
* Returns the HQL name for the field.
*
* @return the HQL name for the field.
*/
public String getHQL() {
return field;
}
/**
* Translates the HQL name of the field to an IMARecordField object.
*
* @param field the field name to get the value of
* @return the DBIMARecordField matching the field name
*/
public static IMARecordField valueOfHQL(final String field) {
for (IMARecordField f : IMARecordField.values()) {
if (f.getHQL().equals(field)) {
return f;
}
}
throw new IllegalArgumentException("No field matched string '" + field + "'.");
}
}

View File

@ -1,23 +0,0 @@
package hirs.persist;
/**
* Scope of a query to search for IMAMeasurementRecords.
*/
public enum IMARecordScope {
/**
* Scope not limited.
*/
NONE,
/**
* Scope limited to a single report.
*/
REPORT,
/**
* Scope limited to a single device.
*/
DEVICE;
}

View File

@ -1,90 +0,0 @@
package hirs.persist;
import hirs.data.persist.Digest;
import hirs.data.persist.baseline.IMABaselineRecord;
import hirs.data.persist.baseline.QueryableRecordImaBaseline;
import hirs.data.persist.baseline.SimpleImaBaseline;
import hirs.utils.Callback;
import java.util.Collection;
/**
* A <code>ImaBaselineRecordManager</code> manages <code>IMABaselineRecord</code>s. It has support
* for the basic create, read, update, and delete methods.
*/
public interface ImaBaselineRecordManager {
/**
* Stores a new <code>IMABaselineRecord</code>. This stores a new
* <code>IMABaselineRecord</code> to be managed by the <code>IMABaselineRecordManager</code>.
* If the <code>IMABaselineRecord</code> is successfully saved then a reference to it is
* returned.
*
* @param record Alert to save
* @return reference to saved IMABaselineRecord
* @throws ImaBaselineRecordManagerException if the Alert has previously been saved or
* unexpected error occurs
*/
IMABaselineRecord saveRecord(IMABaselineRecord record)
throws ImaBaselineRecordManagerException;
/**
* Retrieves the <code>IMABaselineRecord</code> identified by <code>id</code>. If
* the <code>IMABaselineRecord</code> cannot be found then null is returned.
*
* @param id id of the <code>IMABaselineRecord</code>
* @return <code>IMABaselineRecord</code> whose name is <code>id</code> or null if
* not found
* @throws ImaBaselineRecordManagerException if unable to retrieve the IMABaselineRecord
*/
IMABaselineRecord getRecord(long id) throws ImaBaselineRecordManagerException;
/**
* Retrieves <code>IMABaselineRecord</code> with the given path, hash, and assigned IMA
* baseline id.
*
* @param path path of the record to be retrieved
* @param hash hash of the record to be retrieved
* @param baseline baseline that is associated with the desired record.
* @return IMABaselineRecord that matches the provided path, hash, and baseline ID
*/
IMABaselineRecord getRecord(String path, Digest hash,
SimpleImaBaseline baseline);
/**
* Deletes the <code>ImaBaselineRecord</code> identified by <code>id</code>. If the
* <code>ImaBaselineRecord</code> is found and deleted then true is returned,
* otherwise false.
*
* @param id id of the <code>ImaBaselineRecord</code> to delete
* @return true if successfully found and deleted from database, otherwise false
* @throws ImaBaselineRecordManagerException if unable to delete the ImaBaselineRecord for any
* reason other than not found
*/
boolean deleteRecord(Long id) throws ImaBaselineRecordManagerException;
/**
* Deletes the <code>ImaBaselineRecord</code> provided. If the
* <code>ImaBaselineRecord</code> is found and deleted then true is returned,
* otherwise false.
*
* @param record record object to be deleted.
* @return true if successfully found and deleted from database, otherwise false
* @throws ImaBaselineRecordManagerException if unable to delete the ImaBaselineRecord for any
* reason other than not found
*/
boolean deleteRecord(IMABaselineRecord record) throws ImaBaselineRecordManagerException;
/**
* Iterates over the {@link IMABaselineRecord}s in the given baseline, and calls the given
* Callback on each record. If the callback returns a non-null value, the returned value will
* be added to a collection, which is returned when iteration is finished.
*
* @param baseline the baseline whose {@link IMABaselineRecord}s we should iterate over
* @param callback the callback to run on each record
* @param <T> the return type of the callback
* @return the total collection of objects returned as results from the given Callback
*/
<T> Collection<T> iterateOverBaselineRecords(QueryableRecordImaBaseline baseline,
Callback<IMABaselineRecord, T> callback);
}

View File

@ -1,46 +0,0 @@
package hirs.persist;
/**
* This class represents an <code>Exception</code> generated by a
* <code>ImaBaselineRecordManageer</code>.
*/
public class ImaBaselineRecordManagerException extends RuntimeException {
private static final long serialVersionUID = 631895376025870284L;
/**
* Creates a new <code>ImaBaselineRecordManagerException</code> that has the message
* <code>msg</code>.
*
* @param msg
* exception message
*/
ImaBaselineRecordManagerException(final String msg) {
super(msg);
}
/**
* Creates a new <code>ImaBaselineRecordManagerException</code> that wraps the given
* <code>Throwable</code>.
*
* @param t
* root cause
*/
ImaBaselineRecordManagerException(final Throwable t) {
super(t);
}
/**
* Creates a new <code>ImaBaselineRecordManagerException</code> that has the message
* <code>msg</code> and wraps the root cause.
*
* @param msg
* exception message
* @param t
* root cause
*/
ImaBaselineRecordManagerException(final String msg, final Throwable t) {
super(msg, t);
}
}

View File

@ -1,90 +0,0 @@
package hirs.persist;
import hirs.data.persist.Digest;
import hirs.data.persist.ImaBlacklistRecord;
import hirs.data.persist.baseline.QueryableRecordImaBaseline;
import hirs.data.persist.baseline.ImaBlacklistBaseline;
import hirs.utils.Callback;
import java.util.Collection;
/**
* A <code>ImaBaselineRecordManager</code> manages <code>ImaBlacklistRecord</code>s. It has support
* for the basic create, read, update, and delete methods.
*/
public interface ImaBlacklistBaselineRecordManager {
/**
* Stores a new <code>ImaBlacklistRecord</code>. This stores a new
* <code>ImaBlacklistRecord</code> to be managed by the <code>IMABaselineRecordManager</code>.
* If the <code>ImaBlacklistRecord</code> is successfully saved then a reference to it is
* returned.
*
* @param record Alert to save
* @return reference to saved ImaBlacklistRecord
* @throws ImaBaselineRecordManagerException if the Alert has previously been saved or
* unexpected error occurs
*/
ImaBlacklistRecord saveRecord(ImaBlacklistRecord record)
throws ImaBaselineRecordManagerException;
/**
* Retrieves the <code>ImaBlacklistRecord</code> identified by <code>id</code>. If
* the <code>ImaBlacklistRecord</code> cannot be found then null is returned.
*
* @param id id of the <code>ImaBlacklistRecord</code>
* @return <code>ImaBlacklistRecord</code> whose name is <code>id</code> or null if
* not found
* @throws ImaBaselineRecordManagerException if unable to retrieve the ImaBlacklistRecord
*/
ImaBlacklistRecord getRecord(long id) throws ImaBaselineRecordManagerException;
/**
* Retrieves <code>ImaBlacklistRecord</code> with the given path, hash, and assigned IMA
* baseline id.
*
* @param path path of the record to be retrieved
* @param hash hash of the record to be retrieved
* @param baseline baseline that is associated with the desired record.
* @return ImaBlacklistRecord that matches the provided path, hash, and baseline ID
*/
ImaBlacklistRecord getRecord(String path, Digest hash,
ImaBlacklistBaseline baseline);
/**
* Deletes the <code>ImaBaselineRecord</code> identified by <code>id</code>. If the
* <code>ImaBaselineRecord</code> is found and deleted then true is returned,
* otherwise false.
*
* @param id id of the <code>ImaBaselineRecord</code> to delete
* @return true if successfully found and deleted from database, otherwise false
* @throws ImaBaselineRecordManagerException if unable to delete the ImaBaselineRecord for any
* reason other than not found
*/
boolean deleteRecord(Long id) throws ImaBaselineRecordManagerException;
/**
* Deletes the <code>ImaBaselineRecord</code> provided. If the
* <code>ImaBaselineRecord</code> is found and deleted then true is returned,
* otherwise false.
*
* @param record record object to be deleted.
* @return true if successfully found and deleted from database, otherwise false
* @throws ImaBaselineRecordManagerException if unable to delete the ImaBaselineRecord for any
* reason other than not found
*/
boolean deleteRecord(ImaBlacklistRecord record) throws ImaBaselineRecordManagerException;
/**
* Iterates over the {@link ImaBlacklistRecord}s in the given baseline, and calls the given
* Callback on each record. If the callback returns a non-null value, the returned value will
* be added to a collection, which is returned when iteration is finished.
*
* @param baseline the baseline whose {@link ImaBlacklistRecord}s we should iterate over
* @param callback the callback to run on each record
* @param <T> the return type of the callback
* @return the total collection of objects returned as results from the given Callback
*/
<T> Collection<T> iterateOverBaselineRecords(QueryableRecordImaBaseline baseline,
Callback<ImaBlacklistRecord, T> callback);
}

View File

@ -1,84 +0,0 @@
package hirs.persist;
import hirs.data.persist.baseline.Baseline;
import hirs.ima.IMABaselineGeneratorException;
import hirs.ima.ImaIgnoreSetBaselineGenerator;
import hirs.ima.ImaIgnoreSetBaselineGeneratorException;
import hirs.ima.ImaBlacklistBaselineGenerator;
import hirs.ima.SimpleImaBaselineGenerator;
import hirs.tpm.TPMBaselineGenerator;
import hirs.tpm.TPMBaselineGeneratorException;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.ParseException;
/**
* This class imports a baseline from a csv file uploaded to the HIRS portal.
*/
public final class ImportBaselineCSV {
/**
* private entry so the class isn't invoked.
*/
private ImportBaselineCSV() {
}
/**
* Sets up the logger.
*/
private static final Logger LOGGER = LogManager.getLogger(ImportBaselineCSV.class);
/**
* Imports a new baseline.
*
* @param name User defined name of baseline
* @param inputStream Input stream to the CSV file
* @param type Represents the type of Baseline being created (IMA, TPM)
* @return create baseline
*/
public static Baseline createBaseline(final String name, final InputStream inputStream,
final String type) {
LOGGER.debug("import csv started");
try (InputStream is = new BufferedInputStream(inputStream)) {
Baseline baseline = null;
// IMA baselines only
LOGGER.debug("specified IMA import");
if (type.equalsIgnoreCase("IMA")) {
final SimpleImaBaselineGenerator imaGenerator = new SimpleImaBaselineGenerator();
baseline = imaGenerator.generateBaselineFromCSVFile(name, is);
} else if (type.equalsIgnoreCase("Ignore")) {
final ImaIgnoreSetBaselineGenerator ignoreGenerator =
new ImaIgnoreSetBaselineGenerator();
baseline = ignoreGenerator.generateBaselineFromCSVFile(name, is);
} else if (type.equalsIgnoreCase("IMABlack")) {
baseline = ImaBlacklistBaselineGenerator.generateBaselineFromCSV(name, is);
} else if (type.equalsIgnoreCase("TPMWhite")) {
final TPMBaselineGenerator tpmGenerator = new TPMBaselineGenerator();
baseline = tpmGenerator.generateWhiteListBaselineFromCSVFile(name, is);
} else if (type.equalsIgnoreCase("TPMBlack")) {
final TPMBaselineGenerator tpmGenerator = new TPMBaselineGenerator();
baseline = tpmGenerator.generateBlackListBaselineFromCSVFile(name, is);
} else {
String error = type + " baseline type not supported";
LOGGER.error(error);
throw new BaselineManagerException(error);
}
/* CSV files only */
LOGGER.debug("importing csv file");
return baseline;
} catch (IMABaselineGeneratorException e) {
throw new RuntimeException("Type mismatch, verify import baseline type", e);
} catch (IOException | ParseException | ImaIgnoreSetBaselineGeneratorException
| TPMBaselineGeneratorException | BaselineManagerException e) {
LOGGER.error("unable to generate baseline", e);
throw new RuntimeException(e);
}
}
}

View File

@ -7,16 +7,16 @@ import java.util.Map;
/**
* Interface defining methods for getting ordered lists from a data source. Includes
* properties for sorting, paging, and searching.
* @param <T> the record type, T.
* @param <AbstractEntity> the record type, AbstractEntity.
*/
public interface OrderedListQuerier<T> {
public interface OrderedListQuerier<AbstractEntity> {
/**
* Returns a list of all <code>T</code>s that are ordered by a column and
* direction (ASC, DESC) that is provided by the user. This method helps
* support the server-side processing in the JQuery DataTables.
*
* @param clazz class type of <code>T</code>s to search for (may be null to
* @param entity class type of <code>T</code>s to search for (may be null to
* use Class&lt;T&gt;)
* @param columnToOrder Column to be ordered
* @param ascending direction of sort
@ -30,7 +30,7 @@ public interface OrderedListQuerier<T> {
* @throws DBManagerException if unable to create the list
*/
FilteredRecordsList getOrderedList(
Class<? extends T> clazz, String columnToOrder,
AbstractEntity entity, String columnToOrder,
boolean ascending, int firstResult,
int maxResults, String search,
Map<String, Boolean> searchableColumns)
@ -43,7 +43,7 @@ public interface OrderedListQuerier<T> {
* support the server-side processing in the JQuery DataTables. For entities that support
* soft-deletes, the returned list does not contain <code>T</code>s that have been soft-deleted.
*
* @param clazz class type of <code>T</code>s to search for (may be null to
* @param entity class type of <code>T</code>s to search for (may be null to
* use Class&lt;T&gt;)
* @param columnToOrder Column to be ordered
* @param ascending direction of sort
@ -58,8 +58,8 @@ public interface OrderedListQuerier<T> {
* @throws DBManagerException if unable to create the list
*/
@SuppressWarnings("checkstyle:parameternumber")
FilteredRecordsList<T> getOrderedList(
Class<? extends T> clazz, String columnToOrder,
FilteredRecordsList<AbstractEntity> getOrderedList(
AbstractEntity entity, String columnToOrder,
boolean ascending, int firstResult,
int maxResults, String search,
Map<String, Boolean> searchableColumns, CriteriaModifier criteriaModifier)

View File

@ -20,7 +20,7 @@ import org.springframework.orm.hibernate5.LocalSessionFactoryBean;
public class PersistenceConfiguration {
/**
* The bean name to retrieve the default/general implementation of {@link DeviceStateManager}.
* The bean name to retrieve the default/general implementation of {@link }.
*/
public static final String DEVICE_STATE_MANAGER_BEAN_NAME = "general_db_man_bean";
@ -45,30 +45,6 @@ public class PersistenceConfiguration {
return manager;
}
/**
* Creates a {@link AlertManager} ready to use.
*
* @return {@link AlertManager}
*/
@Bean
public AlertManager alertManager() {
DBAlertManager manager = new DBAlertManager(sessionFactory.getObject());
setDbManagerRetrySettings(manager);
return manager;
}
/**
* Creates a {@link BaselineManager} ready to use.
*
* @return {@link BaselineManager}
*/
@Bean
public BaselineManager baselineManager() {
DBBaselineManager manager = new DBBaselineManager(sessionFactory.getObject());
setDbManagerRetrySettings(manager);
return manager;
}
/**
* Creates a {@link PolicyManager} ready to use.
*
@ -180,41 +156,6 @@ public class PersistenceConfiguration {
return manager;
}
/**
* Creates a {@link DeviceStateManager} ready to use.
*
* @return {@link DeviceStateManager}
*/
@Bean(name = DEVICE_STATE_MANAGER_BEAN_NAME)
public DeviceStateManager generalDeviceStateManager() {
DBDeviceStateManager manager = new DBDeviceStateManager(sessionFactory.getObject());
setDbManagerRetrySettings(manager);
return manager;
}
/**
* Creates a {@link IMADeviceStateManager} ready to use.
*
* @return {@link IMADeviceStateManager}
*/
@Bean
public IMADeviceStateManager imaDeviceStateManager() {
DBIMADeviceStateManager manager = new DBIMADeviceStateManager(sessionFactory.getObject());
setDbManagerRetrySettings(manager);
return manager;
}
/**
* Creates a {@link TPMDeviceStateManager} ready to use.
*
* @return {@link TPMDeviceStateManager}
*/
@Bean
public TPMDeviceStateManager tpmDeviceStateManager() {
DBTPMDeviceStateManager manager = new DBTPMDeviceStateManager(sessionFactory.getObject());
setDbManagerRetrySettings(manager);
return manager;
}
/**
* Creates a {@link ReportRequestStateManager} ready to use.
*
@ -240,65 +181,6 @@ public class PersistenceConfiguration {
return manager;
}
/**
* Creates a {@link ImaBaselineRecordManager} ready to use.
*
* @return {@link ImaBaselineRecordManager}
*/
@Bean
public ImaBaselineRecordManager imaBaselineRecordManager() {
DbImaBaselineRecordManager manager =
new DbImaBaselineRecordManager(sessionFactory.getObject());
setDbManagerRetrySettings(manager);
return manager;
}
/**
* Creates a {@link ImaBlacklistBaselineRecordManager} ready to use.
*
* @return {@link ImaBlacklistBaselineRecordManager}
*/
@Bean
public ImaBlacklistBaselineRecordManager imaBlacklistBaselineRecordManager() {
DbImaBlacklistBaselineRecordManager manager =
new DbImaBlacklistBaselineRecordManager(sessionFactory.getObject());
setDbManagerRetrySettings(manager);
return manager;
}
/**
* Creates a {@link AlertMonitorManager} ready to use.
*
* @return {@link AlertMonitorManager}
*/
@Bean
public AlertMonitorManager alertMonitorManager() {
DBAlertMonitorManager manager = new DBAlertMonitorManager(sessionFactory.getObject());
setDbManagerRetrySettings(manager);
return manager;
}
/**
* Creates a {@link AlertServiceConfigManager} ready to use.
*
* @return {@link AlertServiceConfigManager}
*/
@Bean
public AlertServiceConfigManager alertServiceConfigManager() {
DBAlertServiceManager manager = new DBAlertServiceManager(sessionFactory.getObject());
setDbManagerRetrySettings(manager);
return manager;
}
/**
* Creates a {@link DeviceHealthManager} ready to use.
* @return {@link DeviceHealthManager}
*/
@Bean
public DeviceHealthManager deviceHealthManager() {
return new DeviceHealthManagerImpl();
}
/**
* Creates a {@link PortalInfoManager} ready to use.
*
@ -318,7 +200,7 @@ public class PersistenceConfiguration {
*/
@Bean
public CrudManager<SupplyChainValidationSummary> supplyChainValidationSummaryManager() {
DBManager<SupplyChainValidationSummary> manager = new DBManager<>(
DBManager<SupplyChainValidationSummary> manager = new DBManager<SupplyChainValidationSummary>(
SupplyChainValidationSummary.class,
sessionFactory.getObject()
);
@ -326,21 +208,6 @@ public class PersistenceConfiguration {
return manager;
}
/**
* Creates a {@link DBManager} for TPM2ProvisionerState persistence, ready for use.
*
* @return {@link DBManager} for TPM2ProvisionerState
*/
@Bean
public DBManager<TPM2ProvisionerState> tpm2ProvisionerStateDBManager() {
DBManager<TPM2ProvisionerState> manager = new DBManager<>(
TPM2ProvisionerState.class,
sessionFactory.getObject()
);
setDbManagerRetrySettings(manager);
return manager;
}
/**
* Apply the spring-wired retry template settings to the db manager.
* @param dbManager the manager to apply the retry settings to

View File

@ -1,7 +1,6 @@
package hirs.persist;
import hirs.appraiser.Appraiser;
import hirs.data.persist.baseline.Baseline;
import hirs.data.persist.Device;
import hirs.data.persist.DeviceGroup;
import hirs.data.persist.Policy;
@ -59,18 +58,6 @@ public interface PolicyManager {
List<Policy> getPolicyList(Class<? extends Policy> clazz)
throws PolicyManagerException;
/**
* Return a list of all the policies that contain the given baseline.
*
* @param clazz the class of Policy to search
* @param baseline the baseline that should be a member of returned Policies
* @return the list of matching Policies
*/
List<Policy> getPoliciesContainingBaseline(
Class<? extends Policy> clazz,
Baseline baseline
);
/**
* Retrieves the <code>Policy</code> identified by <code>name</code>. If
* the <code>Policy</code> cannot be found then null is returned.

View File

@ -1,10 +1,8 @@
package hirs.persist;
import hirs.FilteredRecordsList;
import hirs.data.persist.ReportSummary;
import java.util.List;
import java.util.Map;
import java.util.UUID;
/**
@ -67,29 +65,6 @@ public interface ReportSummaryManager {
List<ReportSummary> getReportSummaryListByHostname(String hostname)
throws ReportSummaryManagerException;
/**
* Returns a list of all <code>ReportSummary</code> objects that are ordered
* by a column and direction (ASC, DESC) that is provided by the user. This
* method helps support the server-side processing in the JQuery DataTables.
*
* @param columnToOrder Column to be ordered
* @param ascending direction of sort
* @param firstResult starting point of first result in set
* @param maxResults total number we want returned for display in table
* @param search string of criteria to be matched to visible columns
* @param searchableColumns Map of String and boolean values with column
* headers and whether they are to. Boolean is true if field provides
* a typical String that can be searched by Hibernate without
* transformation.
* @param hostname name of the device to filter on
* @return FilteredRecordsList object with fields for DataTables
* @throws ReportSummaryManagerException if unable to create the list
*/
FilteredRecordsList<ReportSummary> getOrderedReportSummaryList(
String columnToOrder, boolean ascending, int firstResult,
int maxResults, String search,
Map<String, Boolean> searchableColumns,
String hostname) throws ReportSummaryManagerException;
/**
* Retrieves the <code>ReportSummary</code> identified by <code>id</code>.
* If the <code>ReportSummary</code> cannot be found then null is returned.

View File

@ -9,13 +9,7 @@ import hirs.appraiser.IMAAppraiser;
import hirs.appraiser.TPMAppraiser;
import hirs.data.persist.DeviceGroup;
import hirs.data.persist.HIRSPolicy;
import hirs.data.persist.IMAPolicy;
import hirs.data.persist.baseline.ImaAcceptableRecordBaseline;
import hirs.data.persist.baseline.ImaIgnoreSetBaseline;
import hirs.data.persist.Policy;
import hirs.data.persist.baseline.SimpleImaBaseline;
import hirs.data.persist.TPMPolicy;
import hirs.data.persist.baseline.TpmWhiteListBaseline;
import hirs.utils.HIRSProfiles;
import hirs.utils.SpringContextProvider;
import org.apache.logging.log4j.LogManager;
@ -25,7 +19,6 @@ import org.springframework.context.annotation.AnnotationConfigApplicationContext
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import org.springframework.core.type.filter.AssignableTypeFilter;
import org.springframework.orm.hibernate5.LocalSessionFactoryBean;
import hirs.alert.ManagedAlertService;
import java.util.Collection;
import java.util.HashSet;
@ -72,7 +65,6 @@ public final class SystemInit {
scanner.addIncludeFilter(new AssignableTypeFilter(AppraiserPlugin.class));
scanner.addIncludeFilter(new AssignableTypeFilter(SpringContextProvider.class));
scanner.addIncludeFilter(new AssignableTypeFilter(AppraiserPluginManager.class));
scanner.addIncludeFilter(new AssignableTypeFilter(ManagedAlertService.class));
// scan for appraiser plugins
int registeredBeanCount = scanner.scan("hirs");
@ -90,8 +82,6 @@ public final class SystemInit {
final DeviceGroupManager deviceGroupManager = new DBDeviceGroupManager(sessionFactory);
final AppraiserManager appraiserManager = new DBAppraiserManager(sessionFactory);
final PolicyManager policyManager = new DBPolicyManager(sessionFactory);
final BaselineManager baselineManager = new DBBaselineManager(sessionFactory);
final DBAlertServiceManager alertServiceManager = new DBAlertServiceManager(sessionFactory);
// save the default group
LOGGER.info("Checking for default device group...");
@ -198,62 +188,6 @@ public final class SystemInit {
LOGGER.info("HIRS policy found.");
}
// initiate the default ima policy
LOGGER.info("Checking for IMA policy...");
IMAPolicy imaPolicy = (IMAPolicy) policyManager.getPolicy(IMA_POLICY_NAME);
if (imaPolicy == null) {
LOGGER.info("IMA policy not found, creating...");
imaPolicy = new IMAPolicy(IMA_POLICY_NAME);
imaPolicy.setFailOnUnknowns(false);
imaPolicy.setWhitelist((ImaAcceptableRecordBaseline) baselineManager.saveBaseline(
new SimpleImaBaseline("Test Policy Baseline")));
imaPolicy.setRequiredSet((ImaAcceptableRecordBaseline) baselineManager.saveBaseline(
new SimpleImaBaseline("Test Policy Required Set")));
imaPolicy.setImaIgnoreSetBaseline((ImaIgnoreSetBaseline) baselineManager.saveBaseline(
new ImaIgnoreSetBaseline("Test Policy Ignore Set")));
imaPolicy = (IMAPolicy) policyManager.savePolicy(imaPolicy);
policyManager.setDefaultPolicy(imaApp, imaPolicy);
} else {
LOGGER.info("IMA policy found.");
}
// initiate the default tpm policy
LOGGER.info("Checking for TPM policy...");
TPMPolicy tpmPolicy = (TPMPolicy) policyManager.getPolicy(TPM_POLICY_NAME);
if (tpmPolicy == null) {
LOGGER.info("TPM policy not found, creating...");
tpmPolicy = new TPMPolicy(TPM_POLICY_NAME);
tpmPolicy.setAppraiseFullReport(true);
tpmPolicy.setAppraisePcrMask(NONE_MASK);
tpmPolicy.setDefaultPcrAppraisalValues();
tpmPolicy.setReportPcrMask(ALL_MASK);
tpmPolicy.setTpmWhiteListBaseline((TpmWhiteListBaseline) baselineManager.saveBaseline(
new TpmWhiteListBaseline("Test TPM White List Baseline")));
tpmPolicy = (TPMPolicy) policyManager.savePolicy(tpmPolicy);
policyManager.setDefaultPolicy(tpmApp, tpmPolicy);
} else {
LOGGER.info("TPM policy found.");
}
// ensure all alert services are created
LOGGER.info("Checking for alert services...");
LOGGER.info(String.format("Checking for presence of %d alert services.",
context.getBeansOfType(ManagedAlertService.class).size())
);
for (ManagedAlertService alertService
: context.getBeansOfType(ManagedAlertService.class).values()) {
String alertServiceName = alertService.getName();
if (alertServiceManager.getAlertServiceConfig(alertServiceName) == null) {
LOGGER.info(
String.format("%s alert services not found; creating.", alertServiceName)
);
alertService.persist(alertServiceManager);
} else {
LOGGER.info(String.format("%s alert service found.", alertServiceName));
}
}
LOGGER.info("Complete.");
}
}

View File

@ -1,116 +0,0 @@
package hirs.persist;
import org.bouncycastle.util.Arrays;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Lob;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.util.Date;
/**
* This class is for saving the Identity Claim and the Nonce between the two passes of the
* TPM 2.0 Provisioner.
*/
@Entity
public class TPM2ProvisionerState {
private static final int MAX_BLOB_SIZE = 65535;
@Id
private Long firstPartOfNonce;
@Column(nullable = false)
private byte[] nonce;
@Lob
@Column(nullable = false, length = MAX_BLOB_SIZE)
private byte[] identityClaim;
@Column(nullable = false)
private Date timestamp = new Date();
/**
* 0-argument constructor for Hibernate use.
*/
protected TPM2ProvisionerState() {
}
/**
* Constructor.
*
* @param nonce the nonce
* @param identityClaim the identity claim
*/
public TPM2ProvisionerState(final byte[] nonce, final byte[] identityClaim) {
if (nonce == null) {
throw new IllegalArgumentException("Nonce should not be null");
}
if (identityClaim == null) {
throw new IllegalArgumentException("Identity Claim should not be null");
}
if (nonce.length < Long.BYTES) {
throw new IllegalArgumentException(
String.format("Nonce must be larger than 8 bytes. (Received %d.)",
nonce.length));
}
this.nonce = Arrays.clone(nonce);
this.identityClaim = Arrays.clone(identityClaim);
try (DataInputStream dis = new DataInputStream(new ByteArrayInputStream(nonce))) {
firstPartOfNonce = dis.readLong();
} catch (IOException e) {
// This would only happen if there were not enough bytes; that is handled above.
throw new RuntimeException(e);
}
}
/**
* Get the nonce.
*
* @return the nonce
*/
public byte[] getNonce() {
return Arrays.clone(nonce);
}
/**
* Get the identity claim.
*
* @return the identity claim
*/
public byte[] getIdentityClaim() {
return Arrays.clone(identityClaim);
}
/**
* Convenience method for finding the {@link TPM2ProvisionerState} associated with the nonce.
*
* @param crudManager the {@link CrudManager} to use when looking for the
* {@link TPM2ProvisionerState}
* @param nonce the nonce to use as the key for the {@link TPM2ProvisionerState}
* @return the {@link TPM2ProvisionerState} associated with the nonce;
* null if a match is not found
*/
public static TPM2ProvisionerState getTPM2ProvisionerState(
final CrudManager<TPM2ProvisionerState> crudManager,
final byte[] nonce) {
try (DataInputStream dis
= new DataInputStream(new ByteArrayInputStream(nonce))) {
long firstPartOfNonce = dis.readLong();
TPM2ProvisionerState stateFound = crudManager.get(firstPartOfNonce);
if (Arrays.areEqual(stateFound.getNonce(), nonce)) {
return stateFound;
}
} catch (IOException | NullPointerException e) {
return null;
}
return null;
}
}

Some files were not shown because too many files have changed in this diff Show More