Coverage Report - org.apache.maven.plugin.jar.JarSignVerifyMojo
 
Classes in this File Line Coverage Branch Coverage Complexity
JarSignVerifyMojo
76%
54/71
46%
13/28
2.105
JarSignVerifyMojo$1
25%
1/4
N/A
2.105
JarSignVerifyMojo$LineMatcherStreamConsumer
100%
9/9
66%
4/6
2.105
 
 1  
 package org.apache.maven.plugin.jar;
 2  
 
 3  
 /*
 4  
  * Licensed to the Apache Software Foundation (ASF) under one
 5  
  * or more contributor license agreements.  See the NOTICE file
 6  
  * distributed with this work for additional information
 7  
  * regarding copyright ownership.  The ASF licenses this file
 8  
  * to you under the Apache License, Version 2.0 (the
 9  
  * "License"); you may not use this file except in compliance
 10  
  * with the License.  You may obtain a copy of the License at
 11  
  *
 12  
  *  http://www.apache.org/licenses/LICENSE-2.0
 13  
  *
 14  
  * Unless required by applicable law or agreed to in writing,
 15  
  * software distributed under the License is distributed on an
 16  
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 17  
  * KIND, either express or implied.  See the License for the
 18  
  * specific language governing permissions and limitations
 19  
  * under the License.
 20  
  */
 21  
 
 22  
 import java.io.File;
 23  
 import java.io.InputStream;
 24  
 import java.util.ArrayList;
 25  
 import java.util.Iterator;
 26  
 import java.util.List;
 27  
 import java.util.StringTokenizer;
 28  
 
 29  
 import org.apache.commons.lang.SystemUtils;
 30  
 import org.apache.maven.plugin.AbstractMojo;
 31  
 import org.apache.maven.plugin.MojoExecutionException;
 32  
 import org.apache.maven.plugin.logging.Log;
 33  
 import org.codehaus.plexus.util.StringUtils;
 34  
 import org.codehaus.plexus.util.cli.CommandLineException;
 35  
 import org.codehaus.plexus.util.cli.CommandLineUtils;
 36  
 import org.codehaus.plexus.util.cli.Commandline;
 37  
 import org.codehaus.plexus.util.cli.StreamConsumer;
 38  
 
 39  
 /**
 40  
  * Checks the signature of a signed jar using jarsigner.
 41  
  *
 42  
  * @author <a href="jerome@coffeebreaks.org">Jerome Lacoste</a>
 43  
  * @version $Id: JarSignVerifyMojo.java 802529 2009-08-09 12:05:35Z bentmann $
 44  
  * @goal sign-verify
 45  
  * @phase package
 46  
  * @requiresProject
 47  
  * @todo refactor the common code with javadoc plugin
 48  
  * @requiresDependencyResolution runtime
 49  
  * @deprecated As of version 2.3, this goal is no longer supported in favor of the dedicated maven-jarsigner-plugin.
 50  
  */
 51  17
 public class JarSignVerifyMojo
 52  
     extends AbstractMojo
 53  
 {
 54  
     /**
 55  
      * The working directory in which the jarsigner executable will be run.
 56  
      *
 57  
      * @parameter expression="${workingdir}" default-value="${basedir}"
 58  
      * @required
 59  
      */
 60  
     private File workingDirectory;
 61  
 
 62  
     /**
 63  
      * Directory containing the generated JAR.
 64  
      *
 65  
      * @parameter expression="${project.build.directory}"
 66  
      * @required
 67  
      * @readonly
 68  
      */
 69  
     private File basedir;
 70  
 
 71  
     /**
 72  
      * Name of the generated JAR (without classifier and extension).
 73  
      *
 74  
      * @parameter alias="jarname" expression="${project.build.finalName}"
 75  
      * @required
 76  
      */
 77  
     private String finalName;
 78  
 
 79  
     /**
 80  
      * Path of the signed jar. When specified, the finalName is ignored.
 81  
      *
 82  
      * @parameter expression="${jarpath}"
 83  
      */
 84  
     private File jarPath;
 85  
 
 86  
     /**
 87  
      * Check certificates. Requires {@link #setVerbose(boolean)}.
 88  
      * See <a href="http://java.sun.com/j2se/1.4.2/docs/tooldocs/windows/jarsigner.html#Options">options</a>.
 89  
      *
 90  
      * @parameter expression="${checkcerts}" default-value="false"
 91  
      */
 92  
     private boolean checkCerts;
 93  
 
 94  
     /**
 95  
      * Enable verbose
 96  
      * See <a href="http://java.sun.com/j2se/1.4.2/docs/tooldocs/windows/jarsigner.html#Options">options</a>.
 97  
      *
 98  
      * @parameter expression="${verbose}" default-value="false"
 99  
      */
 100  
     private boolean verbose;
 101  
 
 102  
     /** When <code>true</code> this will make the execute() operation fail,
 103  
      * throwing an exception, when verifying a non signed jar.
 104  
      * Primarily to keep backwards compatibility with existing code, and allow reusing the
 105  
      * bean in unattended operations when set to <code>false</code>.
 106  
      *
 107  
      * @parameter expression="${errorWhenNotSigned}" default-value="true"
 108  
      **/
 109  17
     private boolean errorWhenNotSigned = true;
 110  
 
 111  
     /**
 112  
      * Is the jar signed ? output property set by the execute call. The value will be accessible
 113  
      * when execute() ends and if errorWhenNotSigned has been set to false.
 114  
      **/
 115  
     private boolean signed;
 116  
 
 117  
     File getJarFile()
 118  
     {
 119  7
         if ( jarPath != null )
 120  
         {
 121  7
             return jarPath;
 122  
         }
 123  
         else
 124  
         {
 125  0
             return AbstractJarMojo.getJarFile( basedir, finalName, null);
 126  
         }
 127  
     }
 128  
 
 129  
     public void execute()
 130  
         throws MojoExecutionException
 131  
     {
 132  7
         List arguments = new ArrayList();
 133  
 
 134  7
         Commandline commandLine = new Commandline();
 135  
 
 136  7
         commandLine.setExecutable( getJarsignerPath() );
 137  
 
 138  7
         arguments.add( "-verify" );
 139  
 
 140  7
         addArgIf( arguments, this.verbose, "-verbose" );
 141  7
         addArgIf( arguments, this.checkCerts, "-certs" );
 142  
 
 143  7
         arguments.add( getJarFile() );
 144  
 
 145  7
         for ( Iterator it = arguments.iterator() ; it.hasNext() ; )
 146  
         {
 147  16
             commandLine.createArgument().setValue( it.next().toString() );
 148  
         }
 149  
 
 150  7
         commandLine.setWorkingDirectory( workingDirectory.getAbsolutePath() );
 151  
 
 152  7
         getLog().debug("Executing: " + commandLine );
 153  
 
 154  7
         LineMatcherStreamConsumer outConsumer = new LineMatcherStreamConsumer( "jar verified." );
 155  
 
 156  7
         final StringBuffer errBuffer = new StringBuffer();
 157  7
         StreamConsumer errConsumer = new StreamConsumer()
 158  
         {
 159  7
             public void consumeLine(String line)
 160  
             {
 161  0
                  errBuffer.append( line );
 162  0
                  getLog().warn( line );
 163  0
             }
 164  
         };
 165  
 
 166  
 
 167  
         try
 168  
         {
 169  7
             int result = executeCommandLine( commandLine, null, outConsumer, errConsumer );
 170  
 
 171  6
             if ( result != 0 )
 172  
             {
 173  1
                 throw new MojoExecutionException("Result of " + commandLine
 174  
                     + " execution is: \'" + result + "\'." );
 175  
             }
 176  
 
 177  5
             signed = outConsumer.matched;
 178  
 
 179  5
             if ( !signed && errorWhenNotSigned )
 180  
             {
 181  1
                 throw new MojoExecutionException( "Verify failed: " + outConsumer.firstOutLine );
 182  
             }
 183  
         }
 184  1
         catch ( CommandLineException e )
 185  
         {
 186  1
             throw new MojoExecutionException( "command execution failed", e );
 187  4
         }
 188  4
     }
 189  
 
 190  
     // checks if a consumed line matches
 191  
     // also keeps track of the first consumed line.
 192  17
     class LineMatcherStreamConsumer
 193  
         implements StreamConsumer
 194  
     {
 195  
         private String toMatch;
 196  
         private boolean matched;
 197  
         private String firstOutLine;
 198  
 
 199  
         LineMatcherStreamConsumer( String toMatch )
 200  7
         {
 201  7
              this.toMatch = toMatch;
 202  7
         }
 203  
 
 204  
         public void consumeLine(String line)
 205  
         {
 206  5
             if ( firstOutLine == null )
 207  
             {
 208  5
                  firstOutLine = line;
 209  
             }
 210  5
             matched = matched || toMatch.equals( line );
 211  
 
 212  5
             getLog().info( line );
 213  5
         }
 214  
     }
 215  
 
 216  
   // taken from JavadocReport then slightly refactored
 217  
     // should probably share with other plugins that use $JAVA_HOME/bin tools
 218  
 
 219  
     /**
 220  
      * Get the path of jarsigner tool depending the OS.
 221  
      *
 222  
      * @return the path of the jarsigner tool
 223  
      */
 224  
     private String getJarsignerPath()
 225  
     {
 226  7
         return getJDKCommandPath( "jarsigner", getLog() );
 227  
     }
 228  
 
 229  
     private static String getJDKCommandPath( String command, Log logger )
 230  
     {
 231  7
         String path = getJDKCommandExe(command).getAbsolutePath();
 232  7
         logger.debug( command + " executable=[" + path + "]" );
 233  7
         return path;
 234  
     }
 235  
 
 236  
     private static File getJDKCommandExe( String command )
 237  
     {
 238  7
         String fullCommand = command + ( SystemUtils.IS_OS_WINDOWS ? ".exe" : "" );
 239  
 
 240  
         File exe;
 241  
 
 242  
         // For IBM's JDK 1.2
 243  7
         if ( SystemUtils.IS_OS_AIX )
 244  
         {
 245  0
             exe = new File( SystemUtils.getJavaHome() + "/../sh", fullCommand );
 246  
         }
 247  7
         else if ( SystemUtils.IS_OS_MAC_OSX )
 248  
         {
 249  0
             exe = new File( SystemUtils.getJavaHome() + "/bin", fullCommand );
 250  
         }
 251  
         else
 252  
         {
 253  7
             exe = new File( SystemUtils.getJavaHome() + "/../bin", fullCommand );
 254  
         }
 255  
 
 256  7
         return exe;
 257  
     }
 258  
 
 259  
 
 260  
     // Helper methods. Could/should be shared e.g. with JavadocReport
 261  
 
 262  
     /**
 263  
      * Convenience method to add an argument to the <code>command line</code>
 264  
      * conditionally based on the given flag.
 265  
      *
 266  
      * @param arguments
 267  
      * @param b the flag which controls if the argument is added or not.
 268  
      * @param value the argument value to be added.
 269  
      */
 270  
     private void addArgIf( List arguments, boolean b, String value )
 271  
     {
 272  14
         if ( b )
 273  
         {
 274  2
             arguments.add( value );
 275  
         }
 276  14
     }
 277  
 
 278  
     /**
 279  
      * Convenience method to add an argument to the <code>command line</code>
 280  
      * if the the value is not null or empty.
 281  
      * <p>
 282  
      * Moreover, the value could be comma separated.
 283  
      *
 284  
      * @param arguments
 285  
      * @param key the argument name.
 286  
      * @param value the argument value to be added.
 287  
      * @see #addArgIfNotEmpty(java.util.List,String,String,boolean)
 288  
      */
 289  
     private void addArgIfNotEmpty( List arguments, String key, String value )
 290  
     {
 291  0
         addArgIfNotEmpty( arguments, key, value, false );
 292  0
     }
 293  
 
 294  
     /**
 295  
      * Convenience method to add an argument to the <code>command line</code>
 296  
      * if the the value is not null or empty.
 297  
      * <p>
 298  
      * Moreover, the value could be comma separated.
 299  
      *
 300  
      * @param arguments
 301  
      * @param key the argument name.
 302  
      * @param value the argument value to be added.
 303  
      * @param repeatKey repeat or not the key in the command line
 304  
      */
 305  
     private void addArgIfNotEmpty( List arguments, String key, String value, boolean repeatKey )
 306  
     {
 307  0
         if ( !StringUtils.isEmpty( value ) )
 308  
         {
 309  0
             arguments.add( key );
 310  
 
 311  0
             StringTokenizer token = new StringTokenizer( value, "," );
 312  0
             while ( token.hasMoreTokens() )
 313  
             {
 314  0
                 String current = token.nextToken().trim();
 315  
 
 316  0
                 if ( !StringUtils.isEmpty( current ) )
 317  
                 {
 318  0
                     arguments.add( current );
 319  
 
 320  0
                     if ( token.hasMoreTokens() && repeatKey )
 321  
                     {
 322  0
                         arguments.add( key );
 323  
                     }
 324  
                 }
 325  0
             }
 326  
         }
 327  0
     }
 328  
 
 329  
     //
 330  
     // methods used for tests purposes - allow mocking and simulate automatic setters
 331  
     //
 332  
 
 333  
     protected int executeCommandLine( Commandline commandLine, InputStream inputStream,
 334  
                                       StreamConsumer systemOut, StreamConsumer systemErr )
 335  
         throws CommandLineException
 336  
     {
 337  0
         return CommandLineUtils.executeCommandLine( commandLine, inputStream, systemOut, systemErr );
 338  
     }
 339  
 
 340  
     public void setWorkingDir( File workingDir )
 341  
     {
 342  13
         this.workingDirectory = workingDir;
 343  13
     }
 344  
 
 345  
     public void setBasedir( File basedir )
 346  
     {
 347  13
         this.basedir = basedir;
 348  13
     }
 349  
 
 350  
     // hiding for now - I don't think this is required to be seen
 351  
     /*
 352  
     public void setFinalName( String finalName )
 353  
     {
 354  
         this.finalName = finalName;
 355  
     }
 356  
     */
 357  
 
 358  
     public void setJarPath( File jarPath )
 359  
     {
 360  13
         this.jarPath = jarPath;
 361  13
     }
 362  
 
 363  
     public void setCheckCerts( boolean checkCerts )
 364  
     {
 365  1
         this.checkCerts = checkCerts;
 366  1
     }
 367  
 
 368  
     public void setVerbose( boolean verbose )
 369  
     {
 370  8
         this.verbose = verbose;
 371  8
     }
 372  
 
 373  
     /**
 374  
      * Is the JAR file signed ? Output property set by the {@link #execute()} call.
 375  
      *
 376  
      * @return <code>true</code> if the jar was signed, <code>false</code> otherwise.
 377  
      */
 378  
     public boolean isSigned()
 379  
     {
 380  6
         return signed;
 381  
     }
 382  
 
 383  
     /**
 384  
      * Sets a boolean that is to determine if an exception should be thrown when
 385  
      * the JAR file being verified is unsigned. If you just what to check if a
 386  
      * JAR is unsigned and then act on the result, then you probably want to
 387  
      * set this to <code>true</code>.
 388  
      */
 389  
     public void setErrorWhenNotSigned( boolean errorWhenNotSigned )
 390  
     {
 391  2
         this.errorWhenNotSigned = errorWhenNotSigned;
 392  2
     }
 393  
 }