spade.reporter.audit.artifact.ArtifactManager.java Source code

Java tutorial

Introduction

Here is the source code for spade.reporter.audit.artifact.ArtifactManager.java

Source

/*
 --------------------------------------------------------------------------------
 SPADE - Support for Provenance Auditing in Distributed Environments.
 Copyright (C) 2015 SRI International
    
 This program is free software: you can redistribute it and/or
 modify it under the terms of the GNU General Public License as
 published by the Free Software Foundation, either version 3 of the
 License, or (at your option) any later version.
    
 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 General Public License for more details.
    
 You should have received a copy of the GNU General Public License
 along with this program. If not, see <http://www.gnu.org/licenses/>.
 --------------------------------------------------------------------------------
 */
package spade.reporter.audit.artifact;

import java.math.BigInteger;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang.StringUtils;

import spade.core.Settings;
import spade.edge.opm.WasDerivedFrom;
import spade.reporter.Audit;
//import spade.reporter.Audit;
import spade.reporter.audit.Globals;
import spade.reporter.audit.OPMConstants;
import spade.utility.CommonFunctions;
import spade.utility.ExternalMemoryMap;
import spade.utility.FileUtility;
import spade.utility.Hasher;
import spade.vertex.opm.Artifact;

public class ArtifactManager {

    private final Audit reporter;

    private final Map<Class<? extends ArtifactIdentifier>, ArtifactConfig> artifactConfigs;

    private final String artifactsMapId = "Audit[ArtifactsMap]";
    private ExternalMemoryMap<ArtifactIdentifier, ArtifactState> artifactsMap;

    public ArtifactManager(Audit reporter, Globals globals) throws Exception {
        if (reporter == null) {
            throw new IllegalArgumentException("NULL Audit reporter");
        }
        if (globals == null) {
            throw new IllegalArgumentException("NULL Globals object");
        }
        this.reporter = reporter;
        if (globals.keepingArtifactPropertiesMap) {
            String configFilePath = Settings.getDefaultConfigFilePath(this.getClass());
            Map<String, String> configMap = FileUtility.readConfigFileAsKeyValueMap(configFilePath, "=");
            artifactsMap = CommonFunctions.createExternalMemoryMapInstance(artifactsMapId,
                    configMap.get("cacheSize"), configMap.get("bloomfilterFalsePositiveProbability"),
                    configMap.get("bloomFilterExpectedNumberOfElements"), configMap.get("tempDir"),
                    configMap.get("dbName"), configMap.get("reportingIntervalSeconds"),
                    new Hasher<ArtifactIdentifier>() {
                        @Override
                        public String getHash(ArtifactIdentifier t) {
                            if (t != null) {
                                Map<String, String> annotations = t.getAnnotationsMap();
                                String subtype = t.getSubtype();
                                String stringToHash = String.valueOf(annotations) + "," + String.valueOf(subtype);
                                return DigestUtils.sha256Hex(stringToHash);
                            } else {
                                return DigestUtils.sha256Hex("(null)");
                            }
                        }
                    });
        } else {
            artifactsMap = null;
        }
        artifactConfigs = getArtifactConfig(globals);
    }

    private Map<Class<? extends ArtifactIdentifier>, ArtifactConfig> getArtifactConfig(Globals globals) {
        Map<Class<? extends ArtifactIdentifier>, ArtifactConfig> map = new HashMap<Class<? extends ArtifactIdentifier>, ArtifactConfig>();
        map.put(BlockDeviceIdentifier.class,
                new ArtifactConfig(true, globals.epochs, globals.versions, globals.permissions, true, true, true));
        map.put(CharacterDeviceIdentifier.class,
                new ArtifactConfig(true, globals.epochs, globals.versions, globals.permissions, true, true, true));
        map.put(DirectoryIdentifier.class,
                new ArtifactConfig(true, globals.epochs, globals.versions, globals.permissions, true, true, true));
        map.put(FileIdentifier.class, new ArtifactConfig(true, globals.epochs, globals.versions,
                globals.permissions, true, globals.versionFiles, true));
        map.put(LinkIdentifier.class,
                new ArtifactConfig(true, globals.epochs, globals.versions, globals.permissions, true, true, true));
        map.put(MemoryIdentifier.class,
                new ArtifactConfig(true, false, globals.versions, false, false, globals.versionMemorys, false));
        map.put(NamedPipeIdentifier.class, new ArtifactConfig(true, globals.epochs, globals.versions,
                globals.permissions, true, globals.versionNamedPipes, true));
        map.put(NetworkSocketIdentifier.class, new ArtifactConfig(true, globals.epochs, globals.versions, false,
                true, globals.versionNetworkSockets, false));
        map.put(UnixSocketIdentifier.class, new ArtifactConfig(globals.unixSockets, globals.epochs,
                globals.versions, globals.permissions, true, globals.versionUnixSockets, true));
        map.put(UnknownIdentifier.class, new ArtifactConfig(true, globals.epochs, globals.versions, false, true,
                globals.versionUnknowns, false));
        map.put(UnnamedNetworkSocketPairIdentifier.class,
                new ArtifactConfig(true, globals.epochs, globals.versions, false, true, true, false));
        map.put(UnnamedPipeIdentifier.class, new ArtifactConfig(true, globals.epochs, globals.versions, false, true,
                globals.versionUnnamedPipes, false));
        map.put(UnnamedUnixSocketPairIdentifier.class, new ArtifactConfig(true, globals.epochs, globals.versions,
                false, true, globals.versionUnnamedUnixSocketPairs, false));
        return map;
    }

    private boolean outputArtifact(ArtifactIdentifier identifier) {
        return artifactConfigs.get(identifier.getClass()).output;
    }

    private boolean hasEpoch(ArtifactIdentifier identifier) {
        return artifactConfigs.get(identifier.getClass()).hasEpoch;
    }

    private boolean hasVersion(ArtifactIdentifier identifier) {
        return artifactConfigs.get(identifier.getClass()).hasVersion;
    }

    private boolean hasPermissions(ArtifactIdentifier identifier) {
        return artifactConfigs.get(identifier.getClass()).hasPermissions;
    }

    private boolean isEpochUpdatable(ArtifactIdentifier identifier) {
        return artifactConfigs.get(identifier.getClass()).canBeCreated;
    }

    private boolean isVersionUpdatable(ArtifactIdentifier identifier) {
        // Special checks
        if (identifier instanceof PathIdentifier) {
            PathIdentifier pathIdentifier = (PathIdentifier) identifier;
            String path = pathIdentifier.getPath();
            if (path.startsWith("/dev/")) {
                return false;
            }
        }
        return artifactConfigs.get(identifier.getClass()).canBeVersioned;
    }

    private boolean isPermissionsUpdatable(ArtifactIdentifier identifier) {
        return artifactConfigs.get(identifier.getClass()).canBePermissioned;
    }

    public void artifactCreated(ArtifactIdentifier identifier) {
        boolean incrementEpoch = outputArtifact(identifier) && hasEpoch(identifier) && isEpochUpdatable(identifier);
        if (incrementEpoch) {
            if (artifactsMap != null) {
                boolean update = false;
                ArtifactState state = artifactsMap.get(identifier);
                if (state == null) {
                    state = new ArtifactState();
                    artifactsMap.put(identifier, state);
                    update = false;
                } else {
                    update = true;
                }
                if (update) {
                    state.incrementEpoch();
                }
            }
        }
    }

    public void artifactVersioned(ArtifactIdentifier identifier) {
        boolean incrementVersion = outputArtifact(identifier) && hasVersion(identifier)
                && isVersionUpdatable(identifier);
        if (incrementVersion) {
            if (artifactsMap != null) {
                boolean update = false;
                ArtifactState state = artifactsMap.get(identifier);
                if (state == null) {
                    state = new ArtifactState();
                    artifactsMap.put(identifier, state);
                    update = false;
                } else {
                    update = true;
                }
                if (update) {
                    state.incrementVersion();
                }
            }
        }
    }

    public void artifactPermissioned(ArtifactIdentifier identifier, String permissions) {
        boolean updatePermissions = outputArtifact(identifier) && hasPermissions(identifier)
                && isPermissionsUpdatable(identifier);
        if (updatePermissions) {
            if (artifactsMap != null) {
                ArtifactState state = artifactsMap.get(identifier);
                if (state == null) {
                    state = new ArtifactState();
                    artifactsMap.put(identifier, state);
                }
                state.updatePermissions(permissions);
            }
        }
    }

    public Artifact putArtifact(String time, String eventId, String operation, String pid, String source,
            ArtifactIdentifier identifier) {
        BigInteger epoch = null, version = null;
        String permissions = null;
        if (outputArtifact(identifier)) {
            if (artifactsMap != null) {
                ArtifactState state = artifactsMap.get(identifier);
                if (state == null) {
                    state = new ArtifactState();
                    artifactsMap.put(identifier, state);
                }

                boolean hasBeenPut = state.hasBeenPut();

                epoch = state.getEpoch();
                version = state.getVersion();
                permissions = state.getPermissions();

                Artifact artifact = getArtifact(identifier, epoch, version, permissions, source);

                if (!hasBeenPut) {
                    reporter.putVertex(artifact);
                }

                if (identifier instanceof FileIdentifier) {
                    ArtifactConfig config = artifactConfigs.get(identifier.getClass());

                    BigInteger lastEpoch = state.getLastPutEpoch();
                    BigInteger lastVersion = state.getLastPutVersion();
                    String lastPermissions = state.getLastPutPermissions();

                    // Special check
                    if ((config.hasVersion && lastVersion == null) || (config.hasEpoch
                            && (lastEpoch == null || !CommonFunctions.bigIntegerEquals(lastEpoch, epoch)))) {
                        // First one so no derived edge
                    } else {
                        boolean permissionedUpdated = config.hasPermissions && config.canBePermissioned
                                && !StringUtils.equals(lastPermissions, permissions);
                        boolean versionUpdated = config.hasVersion && config.canBeVersioned && lastVersion != null
                                && !CommonFunctions.bigIntegerEquals(lastVersion, version);
                        if (versionUpdated || permissionedUpdated) {
                            Artifact lastArtifact = getArtifact(identifier, lastEpoch, lastVersion, lastPermissions,
                                    source);
                            WasDerivedFrom derivedEdge = new WasDerivedFrom(artifact, lastArtifact);
                            derivedEdge.addAnnotation(OPMConstants.EDGE_PID, pid);
                            reporter.putEdge(derivedEdge, operation, time, eventId, source);
                        }
                    }
                }

                // Always call put to keep the state in sync
                if (!hasBeenPut) {
                    state.put();
                }
                return artifact;
            }
        }
        return getArtifact(identifier, epoch, version, permissions, source);
    }

    private Artifact getArtifact(ArtifactIdentifier identifier, BigInteger epoch, BigInteger version,
            String permissions, String source) {
        Artifact artifact = new Artifact();
        artifact.addAnnotations(getIdentifierAnnotations(identifier));
        artifact.addAnnotations(getStateAnnotations(identifier, epoch, version, permissions));
        addSourceAnnotation(artifact, source);
        return artifact;
    }

    private Map<String, String> getStateAnnotations(ArtifactIdentifier identifier, BigInteger epoch,
            BigInteger version, String permissions) {
        ArtifactConfig config = artifactConfigs.get(identifier.getClass());
        Map<String, String> annotations = new HashMap<String, String>();
        if (epoch != null && config.hasEpoch) {
            annotations.put(OPMConstants.ARTIFACT_EPOCH, epoch.toString());
        }
        if (version != null && config.hasVersion) {
            annotations.put(OPMConstants.ARTIFACT_VERSION, version.toString());
        }
        if (permissions != null && config.hasPermissions) {
            annotations.put(OPMConstants.ARTIFACT_PERMISSIONS, permissions);
        }
        return annotations;
    }

    private Map<String, String> getIdentifierAnnotations(ArtifactIdentifier identifier) {
        Map<String, String> annotations = identifier.getAnnotationsMap();
        annotations.put(OPMConstants.ARTIFACT_SUBTYPE, identifier.getSubtype());
        return annotations;
    }

    private void addSourceAnnotation(Map<String, String> annotations, String source) {
        annotations.put(OPMConstants.SOURCE, source);
    }

    private void addSourceAnnotation(Artifact artifact, String source) {
        addSourceAnnotation(artifact.getAnnotations(), source);
        ;
    }

    public void doCleanUp() {
        if (artifactsMap != null) {
            CommonFunctions.closePrintSizeAndDeleteExternalMemoryMap(artifactsMapId, artifactsMap);
            artifactsMap = null;
        }
    }
}