示例#1
0
 public Import Add(Import import)
 {
     return(_importRepository.Add(import));
 }
示例#2
0
        public ImportResult Import(Import import)
        {
            var csvConfiguration = new Configuration();

            csvConfiguration.RegisterClassMap(new ImportDataMap());
            csvConfiguration.MissingFieldFound = null;

            // Get all the records out of the CSV file
            List <ImportData> importRecords;
            bool isDescription = true;

            // Special validation for Verbiage and Description
            using (var reader = _csvFactory.CreateReader(new StreamReader(import.File), csvConfiguration))
            {
                reader.Read();
                reader.ReadHeader();
                List <string> headers = reader.Context.HeaderRecord.ToList();

                if (headers.Contains("Finding (Verbiage)") && headers.Contains("Finding (Description)"))
                {
                    throw new ArgumentException("You can't have both Verbiage and Description columns.");
                }
                else if (headers.Contains("Finding (Verbiage)"))
                {
                    isDescription = false;
                }

                reader.Configuration.UnregisterClassMap();

                if (!isDescription)
                {
                    reader.Configuration.RegisterClassMap(new ImportVerbiageDataMap());
                }
                else
                {
                    reader.Configuration.RegisterClassMap(new ImportDataMap());
                }

                List <ImportData> records = reader.GetRecords <ImportData>().ToList();
                importRecords = records;
            }

            // Get engagement ID and phase ID
            int engagementId = Convert.ToInt32(import.EngagementId);
            var phaseId      = Convert.ToInt32(import.PhaseId);

            // Create and save import entity
            var importEntity = _importMapper.Map(import);

            importEntity.ImportedDate   = DateTime.Now;
            importEntity.AssessmentDate = DateTime.Now;  // TODO: AssessmentDate will eventually be entered in by the user
            _importRepository.Add(importEntity);
            _importRepository.Save();
            _importMapper.Map(importEntity, import);

            // Use this to store HostVulnerabilities and display them properly after importing those rows
            var importId            = importEntity.Id;
            var penultimateImportId = _importRepository.GetPenultimate(engagementId)?.Id ?? null;

            // Get all existing hosts for this engagement and phase
            // Hosts and Vulnerabilities records must be unique (per phase), and so they're only imported once (per phase).
            // Hence, we do not need to worry about the import ID for Hosts and Vulnerabilities.
            var hostEntities = _hostRepository
                               .GetByEngagementId(engagementId)
                               .Where(x => x.PhaseId == phaseId)
                               .ToList();
            var hostsToAdd    = new List <HostEntity>();
            var hostsToUpdate = new List <HostEntity>();

            // Get all existing vulns for this engagement and phase
            var vulnerabilityEntities = _vulnerabilityRepository
                                        .GetByEngagementId(engagementId)
                                        .Where(x => x.PhaseId == phaseId)
                                        .ToList();
            var vulnerabilitiesToAdd    = new List <VulnerabilityEntity>();
            var vulnerabilitiesToUpdate = new List <VulnerabilityEntity>();

            // Get all existing hostVulnerabilities for this engagement and phase
            var hostVulnerabilityEntities = _hostVulnerabilityRepository
                                            .GetByEngagementId(engagementId)
                                            .Where(x => x.Vulnerability.PhaseId == phaseId && x.Host.PhaseId == phaseId && x.ImportId == importId)
                                            .ToList();
            var hostVulnerabilitiesToAdd    = new List <HostVulnerabilityEntity>();
            var hostVulnerabilitiesToUpdate = new List <HostVulnerabilityEntity>();

            // Iterate through each CSV record, grouped by Finding ("Title")
            var hostVulnerabilityImportGroups = importRecords.GroupBy(x => new { x.Title, x.Port, x.Service, x.IPAddress, x.HostName });

            foreach (var importRecordGroup in hostVulnerabilityImportGroups)
            {
                // Encrypt sensitive fields
                var titleBytes             = Encrypt(importRecordGroup.Key.Title);
                var portBytes              = Encrypt(int.Parse(importRecordGroup.Key.Port));
                var serviceBytes           = Encrypt(importRecordGroup.Key.Service);
                var ipAddressBytes         = Encrypt(importRecordGroup.Key.IPAddress);
                var hostNameBytes          = Encrypt(importRecordGroup.Key.HostName);
                var firstImportRecordGroup = importRecordGroup.First();

                // Create or update a vulnerability entity for this CSV record
                // NOTE: All imports share a single set of unique vulnerabilities
                var vulnerabilityEntity = AddOrUpdateEntity(
                    x => x.TitleBytes.SequenceEqual(titleBytes) &&
                    x.PortBytes.SequenceEqual(portBytes) &&
                    x.ServiceBytes.SequenceEqual(serviceBytes),
                    vulnerabilityEntities,
                    vulnerabilitiesToAdd,
                    vulnerabilitiesToUpdate);
                vulnerabilityEntity.IsStatusUnknown = false;
                if (vulnerabilityEntity.IsHistorical)
                {
                    vulnerabilityEntity.IsHistorical        = false;
                    vulnerabilityEntity.RemediationStatusId = 1; // MitigationStatus.NotMitigated.Value;
                    vulnerabilityEntity.MitigatedDate       = null;
                }

                // RemediationStatusId is technically a nullable field, but upon import we should always
                // set a default of NotMitigated.
                if (vulnerabilityEntity.RemediationStatusId == null)
                {
                    vulnerabilityEntity.RemediationStatusId = 1; //MitigationStatus.NotMitigated.Value;
                }
                _importVulnerabilityMapper.Map(firstImportRecordGroup, import, vulnerabilityEntity);

                // Create or update a host for this CSV record
                // NOTE: All imports in a phase share a single set of unique hosts
                var hostEntity = AddOrUpdateEntity(
                    x => x.IPAddressBytes.SequenceEqual(ipAddressBytes) &&
                    x.NameBytes.SequenceEqual(hostNameBytes),
                    hostEntities,
                    hostsToAdd,
                    hostsToUpdate);
                hostEntity.Status  = "Active";
                hostEntity.PhaseId = phaseId;
                _importHostMapper.Map(firstImportRecordGroup, import, hostEntity);

                // Create a partially-encrypted hostVuln for this CSV record
                // NOTE: HostVulnerabilities are always added as new records during the import process
                AddEntity(
                    x => x.Vulnerability.TitleBytes.SequenceEqual(titleBytes) &&
                    x.Vulnerability.PortBytes.SequenceEqual(portBytes) &&
                    x.Vulnerability.ServiceBytes.SequenceEqual(serviceBytes) &&
                    x.Host.IPAddressBytes.SequenceEqual(ipAddressBytes) &&
                    x.Host.NameBytes.SequenceEqual(hostNameBytes),
                    hostVulnerabilityEntities,
                    hostVulnerabilitiesToAdd,
                    hostVulnerabilitiesToUpdate,
                    CreateHostVulnerability(engagementId, phaseId, hostEntity, vulnerabilityEntity, importEntity));
            }

            // Write new HostVulnerabilities to the database
            if (hostVulnerabilitiesToAdd.Any())
            {
                _hostVulnerabilityRepository.AddRange(hostVulnerabilitiesToAdd);
            }
            _hostVulnerabilityRepository.Save();
            _hostRepository.Save();
            _vulnerabilityRepository.Save();

            // Determine status of every host entity
            var hostsToAddOrUpdate = hostsToAdd.Union(hostsToUpdate).ToArray();
            var hostsToMarkOffline = hostEntities.Except(hostsToAddOrUpdate);

            // Another pass through the host entities is required to figure out which hosts are missing, i.e., 'Offline'
            foreach (var hostEntity in hostEntities)
            {
                // TODO offline vs. retired
                if (hostsToMarkOffline.Contains(hostEntity))
                {
                    hostEntity.Status = "Offline";
                }
                else if (hostsToAddOrUpdate.Contains(hostEntity))
                {
                    hostEntity.Status = "Active";
                }
            }

            // Do a vuln delta check between latest and penultimate imports and adjust vuln remediation metadata
            var vulnerabilityEntitiesToAdd = ProcessVulnerabilityChanges(
                hostVulnerabilityEntities,
                vulnerabilityEntities,
                hostEntities,
                importId,
                penultimateImportId,
                phaseId,
                importEntity.AssessmentDate);

            // Save Hosts and Vulnerabilities
            _hostVulnerabilityRepository.Save();
            _hostRepository.Save();
            _vulnerabilityRepository.Save();

            // Return vuln and host insert and update counts
            return(new ImportResult(vulnerabilitiesToAdd.Count, vulnerabilitiesToUpdate.Count, hostsToAdd.Count, hostsToUpdate.Count));
        }