View Javadoc
1   package org.codehaus.mojo.webstart.sign;
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 org.apache.maven.plugin.MojoExecutionException;
23  import org.apache.maven.shared.jarsigner.JarSigner;
24  import org.apache.maven.shared.jarsigner.JarSignerRequest;
25  import org.apache.maven.shared.jarsigner.JarSignerUtil;
26  import org.apache.maven.shared.utils.cli.CommandLineException;
27  import org.apache.maven.shared.utils.cli.javatool.JavaToolException;
28  import org.apache.maven.shared.utils.cli.javatool.JavaToolResult;
29  import org.codehaus.mojo.keytool.KeyTool;
30  import org.codehaus.mojo.keytool.requests.KeyToolGenerateKeyPairRequest;
31  import org.codehaus.mojo.webstart.util.IOUtil;
32  import org.codehaus.plexus.component.annotations.Component;
33  import org.codehaus.plexus.component.annotations.Requirement;
34  import org.codehaus.plexus.logging.AbstractLogEnabled;
35  
36  import java.io.File;
37  import java.io.IOException;
38  import java.net.URI;
39  
40  /**
41   * Default implementation of the {@link SignTool}.
42   *
43   * @author tchemit <chemit@codelutin.com>
44   * @since 1.0-beta-3
45   */
46  @Component( role = SignTool.class, hint = "default" )
47  public class DefaultSignTool
48      extends AbstractLogEnabled
49      implements SignTool
50  {
51  
52      /**
53       * The component to invoke jarsigner command.
54       */
55      @Requirement
56      private JarSigner jarSigner;
57  
58      /**
59       * The component to invoke keyTool command.
60       */
61      @Requirement
62      private KeyTool keyTool;
63  
64      /**
65       * io helper.
66       */
67      @Requirement
68      protected IOUtil ioUtil;
69  
70      /**
71       * {@inheritDoc}
72       */
73      public void generateKey( SignConfig config, File keystoreFile )
74          throws MojoExecutionException
75      {
76          KeyToolGenerateKeyPairRequest request = config.createKeyGenRequest( keystoreFile );
77  
78          try
79          {
80              JavaToolResult result = keyTool.execute( request );
81  
82              CommandLineException exception = result.getExecutionException();
83              if ( exception != null )
84              {
85                  throw new MojoExecutionException( "Could not generate key store " + keystoreFile, exception );
86              }
87              int exitCode = result.getExitCode();
88              if ( exitCode != 0 )
89              {
90                  throw new MojoExecutionException(
91                      "Could not generate key store " + keystoreFile + ", use -X to have detail of error" );
92              }
93          }
94          catch ( JavaToolException e )
95          {
96              throw new MojoExecutionException( "Could not find keytool", e );
97          }
98      }
99  
100     /**
101      * {@inheritDoc}
102      */
103     public void sign( SignConfig config, File jarFile, File signedJar )
104         throws MojoExecutionException
105     {
106 
107         JarSignerRequest request = config.createSignRequest( jarFile, signedJar );
108 
109         try
110         {
111             JavaToolResult result = jarSigner.execute( request );
112 
113             CommandLineException exception = result.getExecutionException();
114             if ( exception != null )
115             {
116                 throw new MojoExecutionException( "Could not sign jar " + jarFile, exception );
117             }
118             int exitCode = result.getExitCode();
119             if ( exitCode != 0 )
120             {
121                 throw new MojoExecutionException(
122                     "Could not sign jar " + jarFile + ", use -X to have detail of error" );
123             }
124         }
125         catch ( JavaToolException e )
126         {
127             throw new MojoExecutionException( "Could not find jarSigner", e );
128         }
129     }
130 
131     /**
132      * {@inheritDoc}
133      */
134     public void verify( SignConfig config, File jarFile, boolean certs )
135         throws MojoExecutionException
136     {
137 
138         JarSignerRequest request = config.createVerifyRequest( jarFile, certs );
139 
140         try
141         {
142             JavaToolResult result = jarSigner.execute( request );
143 
144             CommandLineException exception = result.getExecutionException();
145             if ( exception != null )
146             {
147                 throw new MojoExecutionException( "Could not verify jar " + jarFile, exception );
148             }
149             int exitCode = result.getExitCode();
150             if ( exitCode != 0 )
151             {
152                 throw new MojoExecutionException(
153                     "Could not verify jar " + jarFile + ", use -X to have detail of error" );
154             }
155         }
156         catch ( JavaToolException e )
157         {
158             throw new MojoExecutionException( "Could not find jarSigner", e );
159         }
160     }
161 
162     /**
163      * {@inheritDoc}
164      */
165     public boolean isJarSigned( File jarFile )
166         throws MojoExecutionException
167     {
168         try
169         {
170             return JarSignerUtil.isArchiveSigned( jarFile );
171         }
172         catch ( IOException e )
173         {
174             throw new MojoExecutionException( "Could not verifiy that jar is signed or not", e );
175         }
176 
177     }
178 
179     /**
180      * {@inheritDoc}
181      */
182     public void unsign( File jarFile, boolean verbose )
183         throws MojoExecutionException
184     {
185 
186         if ( isJarSigned( jarFile ) )
187         {
188 
189             // unsign jar
190 
191             verboseLog( verbose, "Unsign jar " + jarFile );
192             try
193             {
194                 JarSignerUtil.unsignArchive( jarFile );
195             }
196             catch ( IOException e )
197             {
198 
199                 throw new MojoExecutionException( "Could not find unsign jar " + jarFile, e );
200             }
201         }
202         else
203         {
204 
205             // not signed jar do nothing
206             verboseLog( verbose, "Jar " + jarFile + " is not signed." );
207         }
208     }
209 
210     /**
211      * {@inheritDoc}
212      */
213     public void deleteKeyStore( File keystore, boolean verbose )
214     {
215         if ( keystore.exists() )
216         {
217             if ( keystore.delete() )
218             {
219                 infoOrDebug( verbose, "deleted keystore from: " + keystore.getAbsolutePath() );
220             }
221             else
222             {
223                 getLogger().warn( "Couldn't delete keystore from: " + keystore.getAbsolutePath() );
224             }
225         }
226         else
227         {
228             infoOrDebug( verbose, "Skipping deletion of non existing keystore: " + keystore.getAbsolutePath() );
229         }
230     }
231 
232     /**
233      * {@inheritDoc}
234      */
235     public File getKeyStoreFile( String keystore, File workingKeystore, ClassLoader classLoader )
236         throws MojoExecutionException
237     {
238 
239         File result;
240 
241         URI keystoreURI = null;
242         try
243         {
244             keystoreURI = URI.create( keystore );
245         }
246         catch ( IllegalArgumentException e )
247         {
248             // Windows paths like C:\Users throw an IAE due to the '\'  
249         }
250 
251         if ( keystoreURI == null || keystoreURI.getScheme() == null )
252         {
253 
254             // consider it as a simple file
255             result = new File( keystore );
256         }
257         else
258         {
259             // copy stream to working keystore
260             result = workingKeystore;
261 
262             // make parent directory if required
263             ioUtil.makeDirectoryIfNecessary( result.getParentFile() );
264 
265             // copy keystore  to workingKeystore
266             ioUtil.copyResources( keystoreURI, classLoader, result );
267         }
268         return result;
269     }
270 
271     /**
272      * Log as info when verbose or info is enabled, as debug otherwise.
273      *
274      * @param verbose verbose level
275      * @param msg     message to log
276      */
277     protected void verboseLog( boolean verbose, String msg )
278     {
279         infoOrDebug( verbose || getLogger().isInfoEnabled(), msg );
280     }
281 
282     /**
283      * Log a message as info or debug.
284      *
285      * @param info if set to true, log as info(), otherwise as debug()
286      * @param msg  message to log
287      */
288     private void infoOrDebug( boolean info, String msg )
289     {
290         if ( info )
291         {
292             getLogger().info( msg );
293         }
294         else
295         {
296             getLogger().debug( msg );
297         }
298     }
299 
300 }