1 package org.apache.maven.plugin.jar;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import org.apache.commons.lang.SystemUtils;
23 import org.apache.maven.plugin.AbstractMojo;
24 import org.apache.maven.plugin.MojoExecutionException;
25 import org.apache.maven.plugin.logging.Log;
26 import org.apache.maven.project.MavenProject;
27 import org.apache.maven.project.MavenProjectHelper;
28 import org.apache.maven.artifact.handler.ArtifactHandler;
29 import org.codehaus.plexus.util.StringUtils;
30 import org.codehaus.plexus.util.cli.CommandLineException;
31 import org.codehaus.plexus.util.cli.CommandLineUtils;
32 import org.codehaus.plexus.util.cli.Commandline;
33 import org.codehaus.plexus.util.cli.StreamConsumer;
34
35 import java.io.File;
36 import java.io.InputStream;
37 import java.util.ArrayList;
38 import java.util.Iterator;
39 import java.util.List;
40 import java.util.StringTokenizer;
41
42
43
44
45
46
47
48
49
50
51
52
53
54 public class JarSignMojo
55 extends AbstractMojo
56 {
57
58
59
60
61
62
63 private boolean skip;
64
65
66
67
68
69
70
71 private File workingDirectory;
72
73
74
75
76
77
78
79
80 private File basedir;
81
82
83
84
85
86
87
88 private String finalName;
89
90
91
92
93
94
95 private File jarPath;
96
97
98
99
100
101
102 private String keystore;
103
104
105
106
107
108
109 private String storepass;
110
111
112
113
114
115
116 private String keypass;
117
118
119
120
121
122
123
124 private String sigfile;
125
126
127
128
129
130
131
132
133 private File signedjar;
134
135
136
137
138
139
140
141 private String type;
142
143
144
145
146
147
148
149 private String alias;
150
151
152
153
154
155
156
157
158 private boolean verify;
159
160
161
162
163
164
165 private boolean skipAttachSignedArtifact;
166
167
168
169
170
171
172
173 private boolean verbose;
174
175
176
177
178 private MavenProjectHelper projectHelper;
179
180
181
182
183
184
185
186
187 private MavenProject project;
188
189
190
191
192
193
194
195 private String classifier;
196
197 public void execute()
198 throws MojoExecutionException
199 {
200 if ( skip )
201 {
202 getLog().info( "Skipping JAR signing for file: " + getJarFile().getAbsolutePath() );
203 return;
204 }
205
206 if ( project != null )
207 {
208 ArtifactHandler artifactHandler = project.getArtifact().getArtifactHandler();
209 if ( artifactHandler != null && !"java".equals( artifactHandler.getLanguage() ) )
210 {
211 getLog().debug( "Not executing jar:sign as the project is not a Java module" );
212 return;
213 }
214 }
215
216
217
218 JarSignVerifyMojo verifyMojo = createJarSignVerifyMojo();
219
220 verifyMojo.setWorkingDir( workingDirectory );
221
222 verifyMojo.setBasedir( basedir );
223
224 File signedJarFile = signedjar != null ? signedjar : getJarFile();
225
226 verifyMojo.setVerbose( verbose );
227
228 verifyMojo.setJarPath( signedJarFile );
229
230 if ( signedJarFile.exists() )
231 {
232 verifyMojo.setErrorWhenNotSigned( false );
233 verifyMojo.execute();
234 }
235
236 if ( verifyMojo.isSigned() )
237 {
238 getLog().info( "JAR " + signedJarFile.getAbsoluteFile() + " is already signed. Skipping." );
239 return;
240 }
241
242 signJar();
243
244 if ( this.verify )
245 {
246 verifyMojo.setErrorWhenNotSigned( true );
247 verifyMojo.execute();
248 }
249 }
250
251 protected JarSignVerifyMojo createJarSignVerifyMojo()
252 {
253 return new JarSignVerifyMojo();
254 }
255
256
257 File getJarFile()
258 {
259 if ( jarPath != null )
260 {
261 return jarPath;
262 }
263 else
264 {
265 return AbstractJarMojo.getJarFile( basedir, finalName, null );
266 }
267 }
268
269 void signJar()
270 throws MojoExecutionException
271 {
272 List arguments = new ArrayList();
273
274 Commandline commandLine = new Commandline();
275
276 commandLine.setExecutable( getJarsignerPath() );
277
278 addArgIf( arguments, verbose, "-verbose" );
279
280
281
282
283 addArgIfNotEmpty( arguments, "-keystore", this.keystore );
284 addArgIfNotEmpty( arguments, "-storepass", this.storepass );
285 addArgIfNotEmpty( arguments, "-keypass", this.keypass );
286 addArgIfNotEmpty( arguments, "-signedjar", this.signedjar );
287 addArgIfNotEmpty( arguments, "-storetype", this.type );
288 addArgIfNotEmpty( arguments, "-sigfile", this.sigfile );
289
290 arguments.add( getJarFile() );
291
292 addArgIf( arguments, alias != null, this.alias );
293
294 for ( Iterator it = arguments.iterator(); it.hasNext(); )
295 {
296 commandLine.createArgument().setValue( it.next().toString() );
297 }
298
299 commandLine.setWorkingDirectory( workingDirectory.getAbsolutePath() );
300
301 createParentDirIfNecessary( signedjar );
302
303 if ( signedjar == null )
304 {
305 getLog().debug( "Signing JAR in-place (overwritting original JAR)." );
306 }
307
308 if ( getLog().isDebugEnabled() )
309 {
310 getLog().debug( "Executing: " + purgePassword( commandLine ) );
311 }
312
313
314
315 final InputStream inputStream = new InputStream()
316 {
317 public int read()
318 {
319 return -1;
320 }
321 };
322 StreamConsumer outConsumer = new StreamConsumer()
323 {
324 public void consumeLine( String line )
325 {
326 getLog().info( line );
327 }
328 };
329 final StringBuffer errBuffer = new StringBuffer();
330 StreamConsumer errConsumer = new StreamConsumer()
331 {
332 public void consumeLine( String line )
333 {
334 errBuffer.append( line );
335 getLog().warn( line );
336 }
337 };
338
339 try
340 {
341 int result = executeCommandLine( commandLine, inputStream, outConsumer, errConsumer );
342
343 if ( result != 0 )
344 {
345 throw new MojoExecutionException( "Result of " + purgePassword( commandLine ) +
346 " execution is: \'" + result + "\'." );
347 }
348 }
349 catch ( CommandLineException e )
350 {
351 throw new MojoExecutionException( "command execution failed", e );
352 }
353
354
355 if ( signedjar == null || skipAttachSignedArtifact )
356 {
357 return;
358 }
359
360 if ( classifier != null )
361 {
362 projectHelper.attachArtifact( project, "jar", classifier, signedjar );
363 }
364 else
365 {
366 project.getArtifact().setFile( signedjar );
367 }
368 }
369
370 private String purgePassword( Commandline commandLine )
371 {
372 String out = commandLine.toString();
373 if ( keypass != null && out.indexOf( keypass ) != -1 )
374 {
375 out = StringUtils.replace( out, keypass, "******" );
376 }
377 return out;
378 }
379
380 private void createParentDirIfNecessary( File file )
381 {
382 if ( file != null )
383 {
384 File fileDir = file.getParentFile();
385
386 if ( fileDir != null )
387 {
388 boolean mkdirs = fileDir.mkdirs();
389 getLog().debug( "mdkirs: " + mkdirs + " " + fileDir );
390 }
391 }
392 }
393
394
395
396
397
398
399
400
401
402 private String getJarsignerPath()
403 {
404 return getJDKCommandPath( "jarsigner", getLog() );
405 }
406
407 private static String getJDKCommandPath( String command, Log logger )
408 {
409 String path = getJDKCommandExe( command ).getAbsolutePath();
410 logger.debug( command + " executable=[" + path + "]" );
411 return path;
412 }
413
414 private static File getJDKCommandExe( String command )
415 {
416 String fullCommand = command + ( SystemUtils.IS_OS_WINDOWS ? ".exe" : "" );
417
418 File exe;
419
420
421 if ( SystemUtils.IS_OS_AIX )
422 {
423 exe = new File( SystemUtils.getJavaHome() + "/../sh", fullCommand );
424 }
425 else if ( SystemUtils.IS_OS_MAC_OSX )
426 {
427 exe = new File( SystemUtils.getJavaHome() + "/bin", fullCommand );
428 }
429 else
430 {
431 exe = new File( SystemUtils.getJavaHome() + "/../bin", fullCommand );
432 }
433
434 return exe;
435 }
436
437
438
439
440
441
442
443
444
445
446
447 private void addArgIf( List arguments, boolean b, String value )
448 {
449 if ( b )
450 {
451 arguments.add( value );
452 }
453 }
454
455
456
457
458
459
460
461
462
463
464
465
466 private void addArgIfNotEmpty( List arguments, String key, Object value )
467 {
468 addArgIfNotEmpty( arguments, key, value, false );
469 }
470
471
472
473
474
475
476
477
478
479
480
481
482 private void addArgIfNotEmpty( List arguments, String key, Object value, boolean repeatKey )
483 {
484 if ( value != null && !StringUtils.isEmpty( value.toString() ) )
485 {
486 arguments.add( key );
487
488 StringTokenizer token = new StringTokenizer( value.toString(), "," );
489 while ( token.hasMoreTokens() )
490 {
491 String current = token.nextToken().trim();
492
493 if ( !StringUtils.isEmpty( current ) )
494 {
495 arguments.add( current );
496
497 if ( token.hasMoreTokens() && repeatKey )
498 {
499 arguments.add( key );
500 }
501 }
502 }
503 }
504 }
505
506
507
508
509
510 protected int executeCommandLine( Commandline commandLine, InputStream inputStream, StreamConsumer stream1,
511 StreamConsumer stream2 )
512 throws CommandLineException
513 {
514 return CommandLineUtils.executeCommandLine( commandLine, inputStream, stream1, stream2 );
515 }
516
517 public void setWorkingDir( File workingDir )
518 {
519 this.workingDirectory = workingDir;
520 }
521
522 public void setBasedir( File basedir )
523 {
524 this.basedir = basedir;
525 }
526
527 public void setKeystore( String keystore )
528 {
529 this.keystore = keystore;
530 }
531
532 public void setKeypass( String keypass )
533 {
534 this.keypass = keypass;
535 }
536
537 public void setSignedJar( File signedjar )
538 {
539 this.signedjar = signedjar;
540 }
541
542 public void setAlias( String alias )
543 {
544 this.alias = alias;
545 }
546
547
548
549
550
551
552
553
554
555 public void setJarPath( File jarPath )
556 {
557 this.jarPath = jarPath;
558 }
559
560 public void setStorepass( String storepass )
561 {
562 this.storepass = storepass;
563 }
564
565 public void setSigFile( String sigfile )
566 {
567 this.sigfile = sigfile;
568 }
569
570 public void setType( String type )
571 {
572 this.type = type;
573 }
574
575 public void setVerbose( boolean verbose )
576 {
577 this.verbose = verbose;
578 }
579
580 public void setSkipAttachSignedArtifact( boolean skipAttachSignedArtifact )
581 {
582 this.skipAttachSignedArtifact = skipAttachSignedArtifact;
583 }
584
585 public void setProject( MavenProject project )
586 {
587 this.project = project;
588 }
589
590 public void setVerify( boolean verify )
591 {
592 this.verify = verify;
593 }
594 }