//////////////////////////////////////////////////////////////////////// // // Copyright (c) 2009-2013 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.service.channel; import org.springframework.beans.factory.annotation.Autowired; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; import com.denimgroup.threadfix.data.dao.ChannelSeverityDao; import com.denimgroup.threadfix.data.dao.ChannelTypeDao; import com.denimgroup.threadfix.data.dao.ChannelVulnerabilityDao; import com.denimgroup.threadfix.data.entities.ChannelSeverity; import com.denimgroup.threadfix.data.entities.ChannelType; import com.denimgroup.threadfix.data.entities.Finding; import com.denimgroup.threadfix.data.entities.Scan; import com.denimgroup.threadfix.webapp.controller.ScanCheckResultBean; /** * * @author mcollins * */ public class NetsparkerChannelImporter extends AbstractChannelImporter { @Autowired public NetsparkerChannelImporter(ChannelTypeDao channelTypeDao, ChannelVulnerabilityDao channelVulnerabilityDao, ChannelSeverityDao channelSeverityDao) { this.channelTypeDao = channelTypeDao; this.channelVulnerabilityDao = channelVulnerabilityDao; this.channelSeverityDao = channelSeverityDao; this.channelType = channelTypeDao.retrieveByName(ChannelType.NETSPARKER); } /* * (non-Javadoc) * * @see * com.denimgroup.threadfix.service.channel.ChannelImporter#parseInput() */ @Override public Scan parseInput() { return parseSAXInput(new NetsparkerSAXParser()); } public class NetsparkerSAXParser extends HandlerWithBuilder { private Boolean getChannelVulnText = false; private Boolean getUrlText = false; private Boolean getParamText = false; private Boolean getSeverityText = false; private String currentChannelVulnCode = null; private String currentUrlText = null; private String currentParameter = null; private String currentSeverityCode = null; private String host = null; public void add(Finding finding) { if (finding != null) { finding.setNativeId(getNativeId(finding)); finding.setIsStatic(false); saxFindingList.add(finding); } } //////////////////////////////////////////////////////////////////// // Event handlers. //////////////////////////////////////////////////////////////////// public void startElement (String uri, String name, String qName, Attributes atts) { if ("type".equals(qName)) { getChannelVulnText = true; } else if ("url".equals(qName)) { getUrlText = true; } else if ("vulnerableparameter".equals(qName)) { getParamText = true; } else if ("severity".equals(qName)) { getSeverityText = true; } else if ("netsparker".equals(qName)) { date = getCalendarFromString("MM/dd/yyyy hh:mm:ss a", atts.getValue("generated")); } } public void endElement (String uri, String name, String qName) { if (getChannelVulnText) { currentChannelVulnCode = getBuilderText(); getChannelVulnText = false; } else if (getUrlText) { if (host == null) host = getBuilderText(); else currentUrlText = getBuilderText(); getUrlText = false; } else if (getParamText) { currentParameter = getBuilderText(); getParamText = false; } else if (getSeverityText) { currentSeverityCode = getBuilderText(); getSeverityText = false; } if ("vulnerability".equals(qName)) { Finding finding = constructFinding(currentUrlText, currentParameter, currentChannelVulnCode, currentSeverityCode); // The old XML format didn't include severities. As severities are required // for vulnerabilities to show on the application page, let's assign medium // severity. This is only known to affect beta versions of Netsparker. if (finding != null && finding.getChannelSeverity() == null) { ChannelSeverity mediumChannelSeverity = channelSeverityDao.retrieveByCode(channelType, "Medium"); finding.setChannelSeverity(mediumChannelSeverity); } add(finding); currentChannelVulnCode = null; currentSeverityCode = null; currentParameter = null; currentUrlText = null; } } public void characters (char ch[], int start, int length) { if (getChannelVulnText || getUrlText || getParamText || getSeverityText) { addTextToBuilder(ch, start, length); } } } @Override public ScanCheckResultBean checkFile() { return testSAXInput(new NetsparkerSAXValidator()); } public class NetsparkerSAXValidator extends DefaultHandler { private boolean hasFindings = false; private boolean hasDate = false; private boolean correctFormat = false; private void setTestStatus() { if (!correctFormat) testStatus = ScanImportStatus.WRONG_FORMAT_ERROR; else if (hasDate) testStatus = checkTestDate(); if (ScanImportStatus.SUCCESSFUL_SCAN == testStatus && !hasFindings) testStatus = ScanImportStatus.EMPTY_SCAN_ERROR; else if (testStatus == null) testStatus = ScanImportStatus.SUCCESSFUL_SCAN; } //////////////////////////////////////////////////////////////////// // Event handlers. //////////////////////////////////////////////////////////////////// public void endDocument() { setTestStatus(); } public void startElement (String uri, String name, String qName, Attributes atts) throws SAXException { if ("netsparker".equals(qName)) { testDate = getCalendarFromString("MM/dd/yyyy hh:mm:ss a", atts.getValue("generated")); if (testDate != null) hasDate = true; correctFormat = true; } if ("vulnerability".equals(qName)) { hasFindings = true; setTestStatus(); throw new SAXException(FILE_CHECK_COMPLETED); } } } }