All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.denimgroup.threadfix.data.entities.Finding Maven / Gradle / Ivy

Go to download

ThreadFix is a software vulnerability aggregation and management system that reduces the time it takes to fix software vulnerabilities. ThreadFix imports the results from dynamic, static and manual testing to provide a centralized view of software security defects across development teams and applications. The system allows companies to correlate testing results and streamline software remediation efforts by simplifying feeds to software issue trackers. By auto generating application firewall rules, this tool allows organizations to continue remediation work uninterrupted. ThreadFix empowers managers with vulnerability trending reports that show progress over time, giving them justification for their efforts. ThreadFix is developed and maintained by Denim Group, Ltd (http://www.denimgroup.com) For information about commercial support and other services, contact Denim Group about ThreadFix http://www.denimgroup.com/resources-threadfix/

There is a newer version: 2.5
Show newest version
////////////////////////////////////////////////////////////////////////
//
//     Copyright (c) 2009-2015 Denim Group, Ltd.
//
//     The contents of this file are subject to the Mozilla Public License
//     Version 2.0 (the "License"); you may not use this file except in
//     compliance with the License. You may obtain a copy of the License at
//     http://www.mozilla.org/MPL/
//
//     Software distributed under the License is distributed on an "AS IS"
//     basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
//     License for the specific language governing rights and limitations
//     under the License.
//
//     The Original Code is ThreadFix.
//
//     The Initial Developer of the Original Code is Denim Group, Ltd.
//     Portions created by Denim Group, Ltd. are Copyright (C)
//     Denim Group, Ltd. All Rights Reserved.
//
//     Contributor(s): Denim Group, Ltd.
//
////////////////////////////////////////////////////////////////////////
package com.denimgroup.threadfix.data.entities;

import com.denimgroup.threadfix.logging.SanitizedLogger;
import com.denimgroup.threadfix.views.AllViews;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonView;
import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.Index;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.persistence.*;
import javax.validation.constraints.Size;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Calendar;
import java.util.List;

import static com.denimgroup.threadfix.CollectionUtils.list;
import static com.denimgroup.threadfix.data.entities.AuthenticationRequired.UNKNOWN;

@Entity
@Table(name = "Finding")
public class Finding extends AuditableEntity implements FindingLike {

	private static final long serialVersionUID = 5978786078427181952L;

	private Calendar scannedDate; // used in SSVL but available in all scanners

	public static final int LONG_DESCRIPTION_LENGTH = 2047;
	public static final int ATTACK_STRING_LENGTH = 1048575;
	public static final int ATTACK_REQUEST_LENGTH = 1048575;
	public static final int ATTACK_RESPONSE_LENGTH = 1048575;
	public static final int SCANNER_DETAIL_LENGTH = 1048575;
	public static final int SCANNER_RECOMMENDATION_LENGTH = 1048575;
	public static final int RAW_FINDING_LENGTH = 1048575;
	public static final int NATIVE_ID_LENGTH = 50;
	public static final int URL_REFERENCE_LENGTH = 256;
	public static final int SOURCE_FILE_LOCATION_LENGTH = 128;
	public static final int ISSUE_ID_LENGTH = 128;

    // TODO figure out the appropriate place for this
    public static final int NUMBER_ITEM_PER_PAGE = 100;

    private Vulnerability vulnerability;

	private Scan scan;

	@Size(max = LONG_DESCRIPTION_LENGTH, message = "{errors.maxlength} "
			+ LONG_DESCRIPTION_LENGTH + ".")
	private String longDescription;

	@Size(max = ATTACK_STRING_LENGTH, message = "{errors.maxlength} "
			+ ATTACK_STRING_LENGTH + ".")
	private String attackString;

	@Size(max = ATTACK_STRING_LENGTH, message = "{errors.maxlength} "
			+ ATTACK_STRING_LENGTH + ".")
	private String issueId;

	@Size(max = ATTACK_REQUEST_LENGTH, message = "{errors.maxlength} "
			+ ATTACK_REQUEST_LENGTH + ".")
	private String attackRequest;

	@Size(max = ATTACK_RESPONSE_LENGTH, message = "{errors.maxlength} "
			+ ATTACK_RESPONSE_LENGTH + ".")
	private String attackResponse;

	@Size(max = SCANNER_DETAIL_LENGTH, message = "{errors.maxlength} "
			+ SCANNER_DETAIL_LENGTH + ".")
	private String scannerDetail;

	@Size(max = SCANNER_RECOMMENDATION_LENGTH, message = "{errors.maxlength} "
			+ SCANNER_RECOMMENDATION_LENGTH + ".")
	private String scannerRecommendation;

	@Size(max = RAW_FINDING_LENGTH, message = "{errors.maxlength} "
			+ RAW_FINDING_LENGTH + ".")
	private String rawFinding;

    @Size(max = URL_REFERENCE_LENGTH, message = "{errors.maxlength} "
            + URL_REFERENCE_LENGTH + ".")
    private String urlReference = null;

	private ChannelVulnerability channelVulnerability;

	@Size(max = NATIVE_ID_LENGTH, message = "{errors.maxlength} "
			+ NATIVE_ID_LENGTH + ".")
	private String nativeId;

	@Size(max = NATIVE_ID_LENGTH, message = "{errors.maxlength} "
			+ NATIVE_ID_LENGTH + ".")
	private String displayId;

	private ChannelSeverity channelSeverity;
	private SurfaceLocation surfaceLocation;
	private StaticPathInformation staticPathInformation;

	private int numberMergedResults = 1;
	private Integer entryPointLineNumber = -1;

	@Size(max = SOURCE_FILE_LOCATION_LENGTH, message = "{errors.maxlength} "
			+ SOURCE_FILE_LOCATION_LENGTH + ".")
	private String sourceFileLocation;
	private boolean isStatic;
	private boolean isFirstFindingForVuln;
	private boolean isMarkedFalsePositive = false;
	private Boolean hasStatisticsCounter = false;
	private Boolean foundHAMEndpoint = false;

	private User user;

	private List dataFlowElements;
	private List scanRepeatFindingMaps;
	private List endpointPermissions = list();
	private List rawPermissions = list();

	private String calculatedUrlPath = "", calculatedFilePath = "";
	private Dependency dependency;

    private Boolean hidden;

	public Finding() {}

	public Finding(Finding finding) {
		this.issueId = finding.getIssueId();
		this.surfaceLocation = finding.getSurfaceLocation();
		this.attackString = finding.getAttackString();
		this.attackRequest = finding.getAttackRequest();
		this.attackResponse = finding.getAttackResponse();
		this.scannerDetail = finding.getScannerDetail();
		this.scannerRecommendation = finding.getScannerRecommendation();
		this.rawFinding = finding.getRawFinding();
		this.urlReference = finding.getUrlReference();
		this.attackString = finding.getAttackString();
		this.channelVulnerability = finding.getChannelVulnerability();
		this.channelSeverity = finding.getChannelSeverity();
		this.sourceFileLocation = finding.getSourceFileLocation();
		this.nativeId = finding.getNativeId();
		this.isStatic = finding.getIsStatic();
		this.displayId = finding.getDisplayId();
		this.dataFlowElements = finding.getDataFlowElements();
		this.dependency = finding.getDependency();
		this.longDescription = finding.getLongDescription();
	}

	@Temporal(TemporalType.TIMESTAMP)
	public Calendar getScannedDate() {
		return scannedDate;
	}

	public void setScannedDate(Calendar scannedDate) {
		this.scannedDate = scannedDate;
	}

	@Override
	@ManyToOne
	@JsonIgnore
	@JoinColumn(name = "vulnerabilityId")
	public Vulnerability getVulnerability() {
		return vulnerability;
	}

	public void setVulnerability(Vulnerability vulnerability) {
		this.vulnerability = vulnerability;
	}

	@ManyToOne
	@JoinColumn(name = "scanId")
	@JsonIgnore
	public Scan getScan() {
		return scan;
	}

	public void setScan(Scan scan) {
		this.scan = scan;
	}

    @ManyToOne
	@JoinColumn(name = "channelVulnerabilityId")
	@JsonView({AllViews.TableRow.class, AllViews.VulnerabilityDetail.class})
	public ChannelVulnerability getChannelVulnerability() {
		return channelVulnerability;
	}

	public void setChannelVulnerability(
			ChannelVulnerability channelVulnerability) {
		this.channelVulnerability = channelVulnerability;
	}

	@Column(length = NATIVE_ID_LENGTH)
    @JsonView({AllViews.RestView2_1.class, AllViews.VulnerabilityDetail.class})
    public String getNativeId() {
		return nativeId;
	}

	public void setNativeId(String nativeId) {
		this.nativeId = nativeId;
	}

	// TODO add more information to the native ID
    @Transient
    @JsonIgnore
    public String getNonMergingKey() {
        return getDependency() == null ? getNativeId() : getDependency().getKey();
    }

	@Column(length = NATIVE_ID_LENGTH)
    @JsonView({AllViews.TableRow.class, AllViews.RestView2_1.class, AllViews.VulnerabilityDetail.class })
	public String getDisplayId() {
		return displayId;
	}

	public void setDisplayId(String displayId) {
		this.displayId = displayId;
	}

	@ManyToOne
	@JoinColumn(name = "channelSeverityId")
	@JsonView({AllViews.TableRow.class, AllViews.VulnerabilityDetail.class})
	public ChannelSeverity getChannelSeverity() {
		return channelSeverity;
	}

	public void setChannelSeverity(ChannelSeverity channelSeverity) {
		this.channelSeverity = channelSeverity;
	}

	@OneToOne(cascade = CascadeType.ALL)
	@JoinColumn(name = "surfaceLocationId")
	@JsonView({AllViews.TableRow.class, AllViews.RestView2_1.class, AllViews.VulnerabilityDetail.class})
	public SurfaceLocation getSurfaceLocation() {
		return surfaceLocation;
	}

	public void setSurfaceLocation(SurfaceLocation surfaceLocation) {
		this.surfaceLocation = surfaceLocation;
	}

	@OneToOne(cascade = CascadeType.ALL)
	@JoinColumn(name = "staticPathInformationId")
	public StaticPathInformation getStaticPathInformation() {
		return staticPathInformation;
	}

	public void setStaticPathInformation(
			StaticPathInformation staticPathInformation) {
		this.staticPathInformation = staticPathInformation;
	}

	@OneToMany(mappedBy = "finding")
	@Cascade({ org.hibernate.annotations.CascadeType.ALL })
	@OrderBy("sequence DESC")
    @JsonView({ AllViews.RestView2_1.class, AllViews.VulnerabilityDetail.class, AllViews.UIVulnSearch.class })
	public List getDataFlowElements() {
		return dataFlowElements;
	}

	public void setDataFlowElements(List dataFlowElements) {
		this.dataFlowElements = dataFlowElements;
	}

	@Column(nullable = false)
    @JsonView(AllViews.VulnerabilityDetail.class)
	public boolean getIsStatic() {
		return isStatic;
	}

	public void setIsStatic(boolean isStatic) {
		this.isStatic = isStatic;
	}

	@OneToMany(mappedBy = "finding", cascade = CascadeType.ALL)
	@JsonIgnore
	public List getScanRepeatFindingMaps() {
		return scanRepeatFindingMaps;
	}

	public void setScanRepeatFindingMaps(
			List scanRepeatFindingMaps) {
		this.scanRepeatFindingMaps = scanRepeatFindingMaps;
	}

    @JsonView(AllViews.RestView2_1.class)
	public String getSourceFileLocation() {
		return sourceFileLocation;
	}

	@Column(length = SOURCE_FILE_LOCATION_LENGTH)
	public void setSourceFileLocation(String sourceFileLocation) {
		this.sourceFileLocation = sourceFileLocation;
	}

	@Column
	@JsonView({AllViews.TableRow.class, AllViews.RestView2_1.class, AllViews.VulnerabilityDetail.class })
	public String getCalculatedUrlPath() {
		return calculatedUrlPath;
	}

	public void setCalculatedUrlPath(String calculatedUrlPath) {
		this.calculatedUrlPath = calculatedUrlPath;
	}

	@Column
    @JsonView({AllViews.TableRow.class, AllViews.RestView2_1.class, AllViews.VulnerabilityDetail.class })
	public String getCalculatedFilePath() {
		return calculatedFilePath;
	}

	public void setCalculatedFilePath(String calculatedFilePath) {
		this.calculatedFilePath = calculatedFilePath;
	}

	@Column
	public void setNumberMergedResults(int numMergedResults) {
		this.numberMergedResults = numMergedResults;
	}

	@JsonView(AllViews.TableRow.class)
	public int getNumberMergedResults() {
		return numberMergedResults;
	}

	@Column
	public Integer getEntryPointLineNumber() {
		if (entryPointLineNumber == null) {
			return -1;
		}
		return entryPointLineNumber;
	}

	public void setEntryPointLineNumber(Integer entryPointLineNumber) {
		this.entryPointLineNumber = entryPointLineNumber;
	}

	@ManyToOne
	@JoinColumn(name = "userId")
	@JsonIgnore
	public User getUser() {
		return user;
	}

	public void setUser(User user) {
		this.user = user;
	}

	@Column(length = LONG_DESCRIPTION_LENGTH)
    @JsonView({AllViews.RestView2_1.class, AllViews.VulnerabilityDetail.class})
	public void setLongDescription(String longDescription) {
		this.longDescription = longDescription;
	}

	public String getLongDescription() {
		return longDescription;
	}

    @JsonView({AllViews.RestView2_1.class, AllViews.VulnerabilityDetail.class})
    @Column(length = ATTACK_STRING_LENGTH)
	public String getAttackString() {
		return attackString;
	}

    public void setAttackString(String attackString) {
        this.attackString = attackString;
    }

    @JsonView({AllViews.RestView2_1.class, AllViews.UIVulnSearch.class, AllViews.VulnerabilityDetail.class})
    @Column(length = ATTACK_REQUEST_LENGTH)
	public String getAttackRequest() {
		return attackRequest;
	}

	public void setAttackRequest(String attackRequest) {
		this.attackRequest = attackRequest;
	}

	@JsonView({AllViews.RestView2_1.class, AllViews.UIVulnSearch.class, AllViews.VulnerabilityDetail.class})
    @Column(length = ATTACK_RESPONSE_LENGTH)
	public String getAttackResponse() {
		return attackResponse;
	}

	public void setAttackResponse(String attackResponse) {
		this.attackResponse = attackResponse;
	}

    @Column(length = SCANNER_DETAIL_LENGTH)
	@JsonView(AllViews.VulnerabilityDetail.class)
	public String getScannerDetail() {
		return scannerDetail;
	}

	public void setScannerDetail(String scannerDetail) {
		this.scannerDetail = scannerDetail;
	}

    @Column(length = SCANNER_RECOMMENDATION_LENGTH)
	@JsonView(AllViews.VulnerabilityDetail.class)
	public String getScannerRecommendation() {
		return scannerRecommendation;
	}

	public void setScannerRecommendation(String scannerRecommendation) {
		this.scannerRecommendation = scannerRecommendation;
	}

	@Column(length = URL_REFERENCE_LENGTH)
	@JsonView(AllViews.VulnerabilityDetail.class)
	public String getUrlReference() {
		return urlReference;
	}

	public void setUrlReference(String urlReference) {
		this.urlReference = urlReference;
	}

	@Column(length = RAW_FINDING_LENGTH)
	public String getRawFinding() {
		return rawFinding;
	}

	public void setRawFinding(String rawFinding) {
		this.rawFinding = rawFinding;
	}

	@Index(name = "firstFinding")
	@Column(nullable = false)
	public boolean isFirstFindingForVuln() {
		return isFirstFindingForVuln;
	}

	public void setFirstFindingForVuln(boolean isFirstFindingForVuln) {
		this.isFirstFindingForVuln = isFirstFindingForVuln;
	}

	@Column
	public boolean isMarkedFalsePositive() {
		return isMarkedFalsePositive;
	}

	public void setMarkedFalsePositive(boolean isMarkedFalsePositive) {
		this.isMarkedFalsePositive = isMarkedFalsePositive;
	}

	@Column
	public Boolean getFoundHAMEndpoint() {
		return foundHAMEndpoint == null ? false : foundHAMEndpoint;
	}

	public void setFoundHAMEndpoint(Boolean foundHAMEndpoint) {
		this.foundHAMEndpoint = foundHAMEndpoint;
	}

	@OneToOne(cascade = CascadeType.ALL)
	@JoinColumn(name = "dependencyId")
	@JsonView({ AllViews.TableRow.class, AllViews.RestView2_1.class, AllViews.VulnerabilityDetail.class })
	public Dependency getDependency() {
		return dependency;
	}

	public void setDependency(Dependency dependency) {
		this.dependency = dependency;
	}

	@Column(length = ISSUE_ID_LENGTH)
	@JsonIgnore
	public String getIssueId() {
		return issueId;
	}

	public void setIssueId(String issueId) {
		this.issueId = issueId;
	}

	@ManyToMany(mappedBy = "findingList")
	@JsonIgnore
	public List getEndpointPermissions() {
		return endpointPermissions;
	}

	public void setEndpointPermissions(List endpointPermissions) {
		this.endpointPermissions = endpointPermissions;
	}

	AuthenticationRequired authenticationRequired = UNKNOWN;

	@Column
	@Enumerated
	public AuthenticationRequired getAuthenticationRequired() {
		return authenticationRequired;
	}

	public void setAuthenticationRequired(AuthenticationRequired authenticationRequired) {
		this.authenticationRequired = authenticationRequired;
	}

	List statisticsCounters = list();

	@OneToMany(mappedBy = "finding")
	@Cascade({ org.hibernate.annotations.CascadeType.ALL })
	@JsonIgnore
	public List getStatisticsCounters() {
		return statisticsCounters;
	}

	public void setStatisticsCounters(List statisticsCounters) {
		this.statisticsCounters = statisticsCounters;
	}

	@Column
	@Index(name = "statsCounter")
	public Boolean getHasStatisticsCounter() {
		return hasStatisticsCounter != null && hasStatisticsCounter;
	}

	public void setHasStatisticsCounter(Boolean hasStatisticsCounter) {
		this.hasStatisticsCounter = hasStatisticsCounter;
	}

	@Transient
    @Column
    public Boolean isHidden() {
        return hidden;
    }

    public void setHidden(Boolean hidden) {
        this.hidden = hidden;
    }

    @Transient
	@JsonView({ AllViews.TableRow.class, AllViews.VulnerabilityDetail.class,
			AllViews.UIVulnSearch.class, AllViews.RestVulnSearch.class })
	private String getScannerName() {
		return getScan().getApplicationChannel().getChannelType().getName();
	}

	@Transient
	@JsonView({ AllViews.TableRow.class, AllViews.VulnerabilityDetail.class })
	private Integer getScanId() {
		return getScan().getId();
	}

	@Transient
	@JsonView(AllViews.TableRow.class)
	private Calendar getImportTime() {
		return getScan().getImportTime();
	}

	@Transient
	@JsonView(AllViews.TableRow.class)
	private User getScanOrManualUser() {
		if (getScan().getUser() != null) {
			return getScan().getUser();
		} else {
			return getUser();
		}
	}

    @Transient
    @JsonView(AllViews.RestView2_1.class)
    private String getVulnerabilityType() {
        return getChannelVulnerability() == null ? null :
                getChannelVulnerability().getName();
    }

    @Transient
    @JsonView(AllViews.TableRow.class)
    private String getGenericVulnerabilityName() {
        return getChannelVulnerability() == null ? null :
                getChannelVulnerability().getGenericVulnerability() == null ? null :
                getChannelVulnerability().getGenericVulnerability().getName();
    }

    @Transient
    @JsonView(AllViews.RestView2_1.class)
    private String getSeverity() {
        return getChannelSeverity() == null ? null :
                getChannelSeverity().getName();
    }

    @Override
    public String toString() {

        if (dependency != null) {
            return "Finding{ Dependency{ CVEID=" + dependency.getCve() + "}}";
        } else if (isStatic) {
            return "Finding{ " +
                    "staticPath=" + getSourceFileLocation() +
                    ", channelSeverity=" + channelSeverity +
                    ", channelVulnerability=" + channelVulnerability +
                    "}";
        } else {
            return "Finding {" +
                    "channelSeverity=" + channelSeverity +
                    ", channelVulnerability=" + channelVulnerability +
                    ", surfaceLocation=" + surfaceLocation +
                    '}';
        }
    }
    
    @Transient
    @JsonIgnore
    @Nullable
    public String getChannelNameOrNull() {
        return getScan() != null &&
                getScan().getApplicationChannel() != null &&
                getScan().getApplicationChannel().getChannelType() != null &&
                getScan().getApplicationChannel().getChannelType().getName() != null ?
                    getScan().getApplicationChannel().getChannelType().getName() :
                    null;
    }

	@JsonIgnore
	@Transient
	public List getRawPermissions() {
		return rawPermissions;
	}

	public void setRawPermissions(List rawPermissions) {
		this.rawPermissions = rawPermissions;
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy