Java tutorial
/** * OWASP Benchmark Project * * This file is part of the Open Web Application Security Project (OWASP) * Benchmark Project For details, please see * <a href="https://www.owasp.org/index.php/Benchmark">https://www.owasp.org/index.php/Benchmark</a>. * * The OWASP Benchmark 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, version 2. * * The OWASP Benchmark 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 * * @author Dave Wichers <a href="https://www.aspectsecurity.com">Aspect Security</a> * @created 2015 */ package org.owasp.benchmark.score.report; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Font; import java.awt.Stroke; import java.awt.geom.Point2D; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.security.SecureRandom; import java.text.DecimalFormat; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map.Entry; import javax.swing.JFrame; import org.jfree.chart.ChartFactory; import org.jfree.chart.ChartPanel; import org.jfree.chart.ChartUtilities; import org.jfree.chart.JFreeChart; import org.jfree.chart.StandardChartTheme; import org.jfree.chart.annotations.XYLineAnnotation; import org.jfree.chart.annotations.XYPointerAnnotation; import org.jfree.chart.annotations.XYTextAnnotation; import org.jfree.chart.axis.NumberAxis; import org.jfree.chart.axis.NumberTickUnit; import org.jfree.chart.plot.PlotOrientation; import org.jfree.chart.plot.XYPlot; import org.jfree.chart.renderer.category.StandardBarPainter; import org.jfree.data.xy.XYDataItem; import org.jfree.data.xy.XYSeries; import org.jfree.data.xy.XYSeriesCollection; import org.jfree.ui.RectangleInsets; import org.jfree.ui.TextAnchor; import org.owasp.benchmark.score.BenchmarkScore; import org.owasp.benchmark.score.parsers.OverallResults; public class ScatterScores { JFreeChart chart = null; StandardChartTheme theme = null; /** * This calculates the summary chart across all the tools analyzed against the Benchmark. * @param title - The title of the chart to be produced. * @param height - Height of the chart (typically 800) * @param width - Width of the chart (typically 800) * @param toolResults - A list of each individual tool's results. */ public ScatterScores(String title, int height, int width, List<Report> toolResults) { Collections.sort(toolResults); display(" " + title, height, width, toolResults); } private JFreeChart display(String title, int height, int width, List<Report> toolResults) { JFrame f = new JFrame(title); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); XYSeriesCollection dataset = new XYSeriesCollection(); XYSeries series = new XYSeries("Scores"); for (int i = 0; i < toolResults.size(); i++) { Report toolReport = toolResults.get(i); OverallResults overallResults = toolReport.getOverallResults(); series.add(overallResults.getFalsePositiveRate() * 100, overallResults.getTruePositiveRate() * 100); } dataset.addSeries(series); chart = ChartFactory.createScatterPlot(title, "False Positive Rate", "True Positive Rate", dataset, PlotOrientation.VERTICAL, true, true, false); String fontName = "Arial"; DecimalFormat pctFormat = new DecimalFormat("0'%'"); theme = (StandardChartTheme) org.jfree.chart.StandardChartTheme.createJFreeTheme(); theme.setExtraLargeFont(new Font(fontName, Font.PLAIN, 24)); // title theme.setLargeFont(new Font(fontName, Font.PLAIN, 20)); // axis-title theme.setRegularFont(new Font(fontName, Font.PLAIN, 16)); theme.setSmallFont(new Font(fontName, Font.PLAIN, 12)); theme.setRangeGridlinePaint(Color.decode("#C0C0C0")); theme.setPlotBackgroundPaint(Color.white); theme.setChartBackgroundPaint(Color.white); theme.setGridBandPaint(Color.red); theme.setAxisOffset(new RectangleInsets(0, 0, 0, 0)); theme.setBarPainter(new StandardBarPainter()); theme.setAxisLabelPaint(Color.decode("#666666")); theme.apply(chart); XYPlot xyplot = chart.getXYPlot(); NumberAxis rangeAxis = (NumberAxis) xyplot.getRangeAxis(); NumberAxis domainAxis = (NumberAxis) xyplot.getDomainAxis(); xyplot.setOutlineVisible(true); rangeAxis.setRange(-5, 109.99); rangeAxis.setNumberFormatOverride(pctFormat); rangeAxis.setTickLabelPaint(Color.decode("#666666")); rangeAxis.setMinorTickCount(5); rangeAxis.setTickUnit(new NumberTickUnit(10)); rangeAxis.setAxisLineVisible(true); rangeAxis.setMinorTickMarksVisible(true); rangeAxis.setTickMarksVisible(true); rangeAxis.setLowerMargin(10); rangeAxis.setUpperMargin(10); xyplot.setRangeGridlineStroke(new BasicStroke()); xyplot.setRangeGridlinePaint(Color.lightGray); xyplot.setRangeMinorGridlinePaint(Color.decode("#DDDDDD")); xyplot.setRangeMinorGridlinesVisible(true); domainAxis.setRange(-5, 105); domainAxis.setNumberFormatOverride(pctFormat); domainAxis.setTickLabelPaint(Color.decode("#666666")); domainAxis.setMinorTickCount(5); domainAxis.setTickUnit(new NumberTickUnit(10)); domainAxis.setAxisLineVisible(true); domainAxis.setTickMarksVisible(true); domainAxis.setMinorTickMarksVisible(true); domainAxis.setLowerMargin(10); domainAxis.setUpperMargin(10); xyplot.setDomainGridlineStroke(new BasicStroke()); xyplot.setDomainGridlinePaint(Color.lightGray); xyplot.setDomainMinorGridlinePaint(Color.decode("#DDDDDD")); xyplot.setDomainMinorGridlinesVisible(true); chart.setTextAntiAlias(true); chart.setAntiAlias(true); chart.removeLegend(); chart.setPadding(new RectangleInsets(20, 20, 20, 20)); xyplot.getRenderer().setSeriesPaint(0, Color.decode("#4572a7")); // // setup item labels // XYItemRenderer renderer = xyplot.getRenderer(); // Shape circle = new Ellipse2D.Float(-2.0f, -2.0f, 7.0f, 7.0f); // for ( int i = 0; i < dataset.getSeriesCount(); i++ ) { // renderer.setSeriesShape(i, circle); // renderer.setSeriesPaint(i, Color.blue); // String label = ""+((String)dataset.getSeries(i).getKey()); // int idx = label.indexOf( ':'); // label = label.substring( 0, idx ); // StandardXYItemLabelGenerator generator = new StandardXYItemLabelGenerator(label); // renderer.setSeriesItemLabelGenerator(i, generator); // renderer.setSeriesItemLabelsVisible(i, true); // ItemLabelPosition position = new ItemLabelPosition(ItemLabelAnchor.OUTSIDE12, TextAnchor.BASELINE_CENTER ); // renderer.setSeriesPositiveItemLabelPosition(i, position); // } makeDataLabels(toolResults, xyplot); makeLegend(toolResults, 57, 48, dataset, xyplot); Stroke dashed = new BasicStroke(1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL, 0, new float[] { 6, 3 }, 0); for (XYDataItem item : (List<XYDataItem>) series.getItems()) { double x = item.getX().doubleValue(); double y = item.getY().doubleValue(); double z = (x + y) / 2; XYLineAnnotation score = new XYLineAnnotation(x, y, z, z, dashed, Color.blue); xyplot.addAnnotation(score); } // // put legend inside plot // LegendTitle lt = new LegendTitle(xyplot); // lt.setItemFont(theme.getSmallFont()); // lt.setPosition(RectangleEdge.RIGHT); // lt.setItemFont(theme.getSmallFont()); // XYTitleAnnotation ta = new XYTitleAnnotation(.7, .55, lt, RectangleAnchor.TOP_LEFT); // ta.setMaxWidth(0.48); // xyplot.addAnnotation(ta); // draw guessing line XYLineAnnotation guessing = new XYLineAnnotation(-5, -5, 105, 105, dashed, Color.red); xyplot.addAnnotation(guessing); XYPointerAnnotation worse = makePointer(75, 5, "Worse than guessing", TextAnchor.TOP_CENTER, 90); xyplot.addAnnotation(worse); XYPointerAnnotation better = makePointer(25, 100, "Better than guessing", TextAnchor.BOTTOM_CENTER, 270); xyplot.addAnnotation(better); XYTextAnnotation stroketext = new XYTextAnnotation(" Random Guess", 88, 107); stroketext.setTextAnchor(TextAnchor.CENTER_RIGHT); stroketext.setBackgroundPaint(Color.white); stroketext.setPaint(Color.red); stroketext.setFont(theme.getRegularFont()); xyplot.addAnnotation(stroketext); XYLineAnnotation strokekey = new XYLineAnnotation(58, 107, 68, 107, dashed, Color.red); xyplot.setBackgroundPaint(Color.white); xyplot.addAnnotation(strokekey); ChartPanel cp = new ChartPanel(chart, height, width, 400, 400, 1200, 1200, false, false, false, false, false, false); f.add(cp); f.pack(); f.setLocationRelativeTo(null); // f.setVisible(true); return chart; } private void makeDataLabels(List<Report> toolResults, XYPlot xyplot) { HashMap<Point2D, String> map = makePointList(toolResults); for (Entry<Point2D, String> e : map.entrySet()) { if (e.getValue() != null) { Point2D p = e.getKey(); String label = sort(e.getValue()); XYTextAnnotation annotation = new XYTextAnnotation(label, p.getX(), p.getY()); annotation.setTextAnchor(p.getX() < 3 ? TextAnchor.TOP_LEFT : TextAnchor.TOP_CENTER); annotation.setBackgroundPaint(Color.white); annotation.setPaint(Color.blue); annotation.setFont(theme.getRegularFont()); xyplot.addAnnotation(annotation); } } } private String sort(String value) { String[] parts = value.split(","); Arrays.sort(parts); StringBuilder sb = new StringBuilder(); for (int i = 0; i < parts.length; i++) { sb.append(parts[i]); if (i < parts.length - 1) sb.append(","); } return sb.toString(); } SecureRandom sr = new SecureRandom(); private HashMap<Point2D, String> makePointList(List<Report> toolResults) { HashMap<Point2D, String> map = new HashMap<Point2D, String>(); char ch = 'A'; // make a list of all points. Add in a tiny random to prevent exact duplicate coordinates in map for (Report r : toolResults) { double x = r.getOverallResults().getFalsePositiveRate() * 100 + sr.nextDouble() * .000001; double y = r.getOverallResults().getTruePositiveRate() * 100 + sr.nextDouble() * .000001 - 1; // this puts the label just below the point Point2D p = new Point2D.Double(x, y); String label = "" + ch; map.put(p, label); ch++; } dedupify(map); return map; } private void dedupify(HashMap<Point2D, String> map) { for (Entry<Point2D, String> e1 : map.entrySet()) { Entry<Point2D, String> e2 = getMatch(map, e1); while (e2 != null) { StringBuilder label = new StringBuilder(); if (e1.getValue() != null) label.append(e1.getValue()); if (e1.getValue() != null && e2.getValue() != null) label.append(","); if (e2.getValue() != null) label.append(e2.getValue()); e1.setValue(label.toString()); e2.setValue(null); e2 = getMatch(map, e1); } } } private Entry<Point2D, String> getMatch(HashMap<Point2D, String> map, Entry<Point2D, String> e1) { for (Entry<Point2D, String> e2 : map.entrySet()) { Double xd = Math.abs(e1.getKey().getX() - e2.getKey().getX()); Double yd = Math.abs(e1.getKey().getY() - e2.getKey().getY()); boolean close = xd < 1 && yd < 3; if (e1 != e2 && e1.getValue() != null && e2.getValue() != null && close) { return e2; } } return null; } private void makeLegend(List<Report> toolResults, int x, int y, XYSeriesCollection dataset, XYPlot xyplot) { char ch = 'A'; int i = 0; for (Report r : toolResults) { OverallResults or = r.getOverallResults(); String label = (ch == 'I' ? ch + ": " : "" + ch + ": "); int score = (int) (or.getScore() * 100); String msg = "\u25A0 " + label + r.getToolName() + " (" + score + "%)"; XYTextAnnotation stroketext = new XYTextAnnotation(msg, x, y + i * -3.3); stroketext.setTextAnchor(TextAnchor.CENTER_LEFT); stroketext.setBackgroundPaint(Color.white); stroketext.setPaint(Color.blue); stroketext.setFont(theme.getRegularFont()); xyplot.addAnnotation(stroketext); i++; ch++; } } private XYPointerAnnotation makePointer(int x, int y, String msg, TextAnchor anchor, int angle) { XYPointerAnnotation pointer = new XYPointerAnnotation(msg, x, y, Math.toRadians(angle)); pointer.setBackgroundPaint(Color.white); pointer.setTextAnchor(anchor); pointer.setArrowWidth(4); pointer.setArrowLength(8); pointer.setArrowPaint(Color.red); pointer.setLabelOffset(2); pointer.setPaint(Color.red); pointer.setFont(theme.getRegularFont()); return pointer; } public void writeChartToFile(File f, int height, int width) throws IOException { FileOutputStream stream = new FileOutputStream(f); ChartUtilities.writeChartAsPNG(stream, chart, height, width); stream.close(); } public static void generateComparisonChart(List toolResults) { try { ScatterScores scatter = new ScatterScores( "OWASP Benchmark v" + BenchmarkScore.benchmarkVersion + " Results Comparison", 800, 800, toolResults); scatter.writeChartToFile(new File("scorecard/benchmark_comparison.png"), 800, 800); } catch (IOException e) { System.out.println("Couldn't generate Benchmark comparison chart for some reason."); e.printStackTrace(); } } }