View Javadoc

1   /*
2    * Copyright (c) 2007, Ounce Labs, Inc.
3    * All rights reserved.
4    *
5    * Redistribution and use in source and binary forms, with or without
6    * modification, are permitted provided that the following conditions are met:
7    *     * Redistributions of source code must retain the above copyright
8    *       notice, this list of conditions and the following disclaimer.
9    *     * Redistributions in binary form must reproduce the above copyright
10   *       notice, this list of conditions and the following disclaimer in the
11   *       documentation and/or other materials provided with the distribution.
12   *     * Neither the name of the <organization> nor the
13   *       names of its contributors may be used to endorse or promote products
14   *       derived from this software without specific prior written permission.
15   *
16   * THIS SOFTWARE IS PROVIDED BY OUNCE LABS, INC. ``AS IS'' AND ANY
17   * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18   * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19   * DISCLAIMED. IN NO EVENT SHALL OUNCE LABS, INC. BE LIABLE FOR ANY
20   * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25   * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26   */
27  
28  package org.codehaus.mojo.ounce;
29  
30  import java.util.HashMap;
31  import java.util.HashSet;
32  import java.util.Set;
33  
34  import org.apache.maven.plugin.MojoExecutionException;
35  import org.apache.maven.plugin.MojoFailureException;
36  import org.codehaus.mojo.ounce.core.OunceCore;
37  import org.codehaus.mojo.ounce.core.OunceCoreException;
38  import org.codehaus.mojo.ounce.utils.Utils;
39  import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
40  import org.codehaus.plexus.util.StringUtils;
41  
42  /**
43   * This mojo allows an on demand scan of an application and the optional publishing of the results.
44   * 
45   * @author <a href="mailto:brianf@apache.org">Brian Fox</a>
46   * @goal scan
47   * @aggregator
48   * @execute lifecycle="scan" phase="package"
49   */
50  public class ScanMojo
51      extends AbstractOunceMojo
52  {
53  
54      /**
55       * The location of the application file (.paf) to scan.
56       * 
57       * @parameter expression="${ounce.applicationFile}" default-value="${basedir}/${project.artifactId}.paf"
58       */
59      String applicationFile;
60  
61      /**
62       * A name to help identify the assessment.
63       * 
64       * @parameter expression="${project.name}-${project.version}"
65       */
66      String assessmentName;
67  
68      /**
69       * A filename to which to save the assessment. <br/> If filename is not specified, Ounce/Maven generates a name
70       * based on the application name and timestamp and saves it to the applicationŐs working directory.
71       * 
72       * @parameter expression="${ounce.assessmentOutput}"
73       */
74      String assessmentOutput;
75  
76      /**
77       * A short string to help identify the corresponding entries in the ounceauto log file.
78       * 
79       * @parameter expression="${ounce.caller}"
80       */
81      String caller;
82  
83      /**
84       * Generates an Ounce report of the specified type, including findings reports, SmartAudit Reports, and, if
85       * available, custom reports. Ounce/Maven generates a report for this assessment after the scan completes. <br/> The
86       * following report types are included: Findings, Findings By CWE, Findings By API, Findings By Classification,
87       * Findings By File, Findings By Type, Findings By Bundle, OWASP Top Ten, PCI Data Security Standard, Ounce Software
88       * Security Profile, or OWASP Top Ten 2007 <br/> If you specify reportType, then reportOutputType and
89       * reportOutputPath are required.
90       * 
91       * @parameter expression="${ounce.reportType}"
92       */
93      String reportType;
94  
95      /**
96       * The output to generate for the report specified in reportType. Required with reportType. Output type may be html,
97       * zip, pdf-summary, pdf-detailed, pdf-comprehensive, or pdf-annotated.
98       * 
99       * @parameter expression="${ounce.reportOutputType}"
100      */
101     String reportOutputType;
102 
103     /**
104      * The path to which to write the report specified in reportType. Required with reportType.
105      * 
106      * @parameter expression="${ounce.reportOutputPath}"
107      */
108     String reportOutputPath;
109 
110     /**
111      * Number of lines of source code to include in the report before each finding.
112      * 
113      * @parameter expression="${ounce.includeSrcBefore}"
114      */
115     int includeSrcBefore = -1;
116 
117     /**
118      * Number of lines of source code to include in the report after each finding.
119      * 
120      * @parameter expression="${ounce.includeSrcAfter}"
121      */
122     int includeSrcAfter = -1;
123 
124     /**
125      * Automatically publish the assessment following the completion of the scan.
126      * 
127      * @parameter expression="${ounce.publish}" default-value="false"
128      */
129     boolean publish;
130 
131     /**
132      * The location of the Ounce client installation directory if the Ounce client is not on the path.
133      * 
134      * @parameter expression="${ounce.installDir}"
135      */
136     String installDir;
137 
138     /**
139      * Forces the goal to wait until the scan finishes, thus blocking the Maven build. This is useful if the scan is
140      * being performed from the report mojo as part of integration with the site target and the site is getting
141      * deployed.
142      * 
143      * @parameter expression="${ounce.wait}" default-value="false"
144      */
145     boolean waitForScan;
146 
147     /**
148      * This is a static variable used to persist the cached results across plugin invocations.
149      */
150     protected static Set cache = new HashSet();
151 
152     // private List projects;
153     /*
154      * (non-Javadoc)
155      * 
156      * @see org.apache.maven.plugin.Mojo#execute()
157      */
158     public void execute()
159         throws MojoExecutionException, MojoFailureException
160     {
161 
162         if ( StringUtils.isEmpty( applicationFile ) )
163         {
164             throw new MojoExecutionException( "\'applicationFile\' must be defined." );
165         }
166 
167         // check my cache to see if this particular set of params has already been scanned.
168         if ( shouldExecute() )
169         {
170             try
171             {
172                 if ( includeSrcAfter != -1 || includeSrcBefore != -1 )
173                 {
174                     if ( options == null )
175                     {
176                         options = new HashMap();
177                     }
178                     options.put( "includeSrcAfter", new Integer( includeSrcAfter ) );
179                     options.put( "includeSrcBefore", new Integer( includeSrcBefore ) );
180                 }
181                 OunceCore core = getCore();
182                 core.scan( Utils.convertToVariablePath( applicationFile, pathVariableMap ), assessmentName,
183                            assessmentOutput, caller, reportType, reportOutputType, reportOutputPath, publish,
184                            this.options, this.installDir, waitForScan, getLog() );
185             }
186             catch ( ComponentLookupException e )
187             {
188                 throw new MojoExecutionException( "Unable to lookup the core interface for hint: " + coreHint, e );
189             }
190             catch ( OunceCoreException e )
191             {
192                 throw new MojoExecutionException( "Nested Ouncecore exception: " + e.getLocalizedMessage(), e );
193             }
194         }
195         else
196         {
197             this.getLog().info(
198                                 "Skipping Scan because these same parameters where already used in a scan for this project during this build. (build was probably forked)" );
199         }
200     }
201 
202     /**
203      * This method checks the cache to see if the scan should be run. It is used to avoid multiple invocations of scan
204      * in the instance of a forked build.
205      * 
206      * @return
207      */
208     protected boolean shouldExecute()
209     {
210         // get the hash and try to add it.
211         // if it was added, then we need to execute, otherwise it was already there
212         // and we don't.
213         return ( cache.add( getParameterHash() ) );
214     }
215 
216     /**
217      * This method returns a hash of the parameters that may influence scan results. The result of this is used to
218      * determine if a scan should be rerun within the same build lifetime. If any parameters change, then the scan will
219      * continue. This allows multiple executions to be defined with slightly different parameters.
220      * 
221      * @return String of hashCodes
222      */
223     protected String getParameterHash()
224     {
225         StringBuffer buf = new StringBuffer();
226         buf.append( getSafeHash( this.applicationFile ) );
227         buf.append( "-" );
228         buf.append( getSafeHash( this.assessmentOutput ) );
229         buf.append( "-" );
230         buf.append( getSafeHash( this.caller ) );
231         buf.append( "-" );
232         buf.append( getSafeHash( this.pathVariableMap ) );
233         buf.append( "-" );
234         buf.append( getSafeHash( this.reportOutputPath ) );
235         buf.append( "-" );
236         buf.append( getSafeHash( this.reportOutputType ) );
237         buf.append( "-" );
238         buf.append( getSafeHash( this.reportType ) );
239         this.getLog().debug( "Parameter Hash: " + buf.toString() );
240         return buf.toString();
241     }
242 
243     /**
244      * Simple helper to handle null parameters for hash checking.
245      * 
246      * @param o
247      * @return
248      */
249     private final int getSafeHash( Object o )
250     {
251         if ( o != null )
252         {
253             return o.hashCode();
254         }
255         else
256         {
257             return 0;
258         }
259     }
260 
261 }