1 package org.apache.maven.plugins.jarsigner;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import org.apache.maven.artifact.Artifact;
23 import org.apache.maven.execution.MavenSession;
24 import org.apache.maven.plugin.AbstractMojo;
25 import org.apache.maven.plugin.MojoExecutionException;
26 import org.apache.maven.plugins.annotations.Component;
27 import org.apache.maven.plugins.annotations.Parameter;
28 import org.apache.maven.project.MavenProject;
29 import org.apache.maven.shared.jarsigner.JarSigner;
30 import org.apache.maven.shared.jarsigner.JarSignerRequest;
31 import org.apache.maven.shared.jarsigner.JarSignerUtil;
32 import org.apache.maven.shared.utils.StringUtils;
33 import org.apache.maven.shared.utils.cli.Commandline;
34 import org.apache.maven.shared.utils.cli.javatool.JavaToolException;
35 import org.apache.maven.shared.utils.cli.javatool.JavaToolResult;
36 import org.apache.maven.shared.utils.io.FileUtils;
37 import org.apache.maven.toolchain.Toolchain;
38 import org.apache.maven.toolchain.ToolchainManager;
39 import org.sonatype.plexus.components.sec.dispatcher.SecDispatcher;
40 import org.sonatype.plexus.components.sec.dispatcher.SecDispatcherException;
41
42 import java.io.File;
43 import java.io.IOException;
44 import java.text.MessageFormat;
45 import java.util.Arrays;
46 import java.util.Collection;
47 import java.util.HashSet;
48 import java.util.List;
49 import java.util.ResourceBundle;
50
51
52
53
54
55
56
57 public abstract class AbstractJarsignerMojo
58 extends AbstractMojo
59 {
60
61
62
63
64 @Parameter( property = "jarsigner.verbose", defaultValue = "false" )
65 private boolean verbose;
66
67
68
69
70 @Parameter( property = "jarsigner.keystore" )
71 private String keystore;
72
73
74
75
76 @Parameter( property = "jarsigner.storetype" )
77 private String storetype;
78
79
80
81
82 @Parameter( property = "jarsigner.storepass" )
83 private String storepass;
84
85
86
87
88 @Parameter( property = "jarsigner.providerName" )
89 private String providerName;
90
91
92
93
94 @Parameter( property = "jarsigner.providerClass" )
95 private String providerClass;
96
97
98
99
100 @Parameter( property = "jarsigner.providerArg" )
101 private String providerArg;
102
103
104
105
106 @Parameter( property = "jarsigner.alias" )
107 private String alias;
108
109
110
111
112
113 @Parameter( property = "jarsigner.maxMemory" )
114 private String maxMemory;
115
116
117
118
119 @Parameter( property = "jarsigner.archive" )
120 private File archive;
121
122
123
124
125
126
127 @Parameter( property = "jarsigner.archiveDirectory" )
128 private File archiveDirectory;
129
130
131
132
133
134
135
136
137 @Parameter
138 private String[] includes = { "**/*.?ar" };
139
140
141
142
143
144
145
146 @Parameter
147 private String[] excludes = {};
148
149
150
151
152 @Parameter( property = "jarsigner.arguments" )
153 private String[] arguments;
154
155
156
157
158 @Parameter( property = "jarsigner.skip", defaultValue = "false" )
159 private boolean skip;
160
161
162
163
164
165
166 @Parameter( property = "jarsigner.processMainArtifact", defaultValue = "true" )
167 private boolean processMainArtifact;
168
169
170
171
172
173
174
175 @Parameter( property = "jarsigner.processAttachedArtifacts", defaultValue = "true" )
176 private boolean processAttachedArtifacts;
177
178
179
180
181
182
183
184 @Parameter( property = "jarsigner.protectedAuthenticationPath", defaultValue = "false" )
185 private boolean protectedAuthenticationPath;
186
187
188
189
190
191
192 @Parameter( property = "jarsigner.attachments" )
193 private Boolean attachments;
194
195
196
197
198
199
200
201 @Parameter
202 private String[] includeClassifiers;
203
204
205
206
207
208
209
210 @Parameter
211 private String[] excludeClassifiers;
212
213
214
215
216 @Parameter( defaultValue = "${project}", readonly = true, required = true )
217 private MavenProject project;
218
219
220
221
222
223
224 @Parameter( defaultValue = "${project.basedir}" )
225 private File workingDirectory;
226
227
228
229 @Component
230 private JarSigner jarSigner;
231
232
233
234
235
236
237
238 @Parameter( defaultValue = "${session}", readonly = true, required = true )
239 private MavenSession session;
240
241
242
243
244
245
246 @Component
247 private ToolchainManager toolchainManager;
248
249
250
251
252 @Component( hint = "mng-4384" )
253 private SecDispatcher securityDispatcher;
254
255 public final void execute()
256 throws MojoExecutionException
257 {
258 if ( !this.skip )
259 {
260 Toolchain toolchain = getToolchain();
261
262 if ( toolchain != null )
263 {
264 getLog().info( "Toolchain in maven-jarsigner-plugin: " + toolchain );
265 jarSigner.setToolchain( toolchain );
266 }
267
268 int processed = 0;
269
270 if ( this.archive != null )
271 {
272 processArchive( this.archive );
273 processed++;
274 }
275 else
276 {
277 if ( processMainArtifact )
278 {
279 processed += processArtifact( this.project.getArtifact() ) ? 1 : 0;
280 }
281
282 if ( processAttachedArtifacts && !Boolean.FALSE.equals( attachments ) )
283 {
284 Collection<String> includes = new HashSet<String>();
285 if ( includeClassifiers != null )
286 {
287 includes.addAll( Arrays.asList( includeClassifiers ) );
288 }
289
290 Collection<String> excludes = new HashSet<String>();
291 if ( excludeClassifiers != null )
292 {
293 excludes.addAll( Arrays.asList( excludeClassifiers ) );
294 }
295
296 for ( Object o : this.project.getAttachedArtifacts() )
297 {
298 final Artifact artifact = (Artifact) o;
299
300 if ( !includes.isEmpty() && !includes.contains( artifact.getClassifier() ) )
301 {
302 continue;
303 }
304
305 if ( excludes.contains( artifact.getClassifier() ) )
306 {
307 continue;
308 }
309
310 processed += processArtifact( artifact ) ? 1 : 0;
311 }
312 }
313 else
314 {
315 if ( verbose )
316 {
317 getLog().info( getMessage( "ignoringAttachments" ) );
318 }
319 else
320 {
321 getLog().debug( getMessage( "ignoringAttachments" ) );
322 }
323 }
324
325 if ( archiveDirectory != null )
326 {
327 String includeList = ( includes != null ) ? StringUtils.join( includes, "," ) : null;
328 String excludeList = ( excludes != null ) ? StringUtils.join( excludes, "," ) : null;
329
330 List<File> jarFiles;
331 try
332 {
333 jarFiles = FileUtils.getFiles( archiveDirectory, includeList, excludeList );
334 }
335 catch ( IOException e )
336 {
337 throw new MojoExecutionException( "Failed to scan archive directory for JARs: "
338 + e.getMessage(), e );
339 }
340
341 for ( File jarFile : jarFiles )
342 {
343 processArchive( jarFile );
344 processed++;
345 }
346 }
347 }
348
349 getLog().info( getMessage( "processed", processed ) );
350 }
351 else
352 {
353 getLog().info( getMessage( "disabled", null ) );
354 }
355 }
356
357
358
359
360
361
362
363
364 protected abstract JarSignerRequest createRequest( File archive )
365 throws MojoExecutionException;
366
367
368
369
370
371
372
373
374
375
376
377 protected String getCommandlineInfo( final Commandline commandLine )
378 {
379 if ( commandLine == null )
380 {
381 throw new NullPointerException( "commandLine" );
382 }
383
384 String commandLineInfo = commandLine.toString();
385 commandLineInfo = StringUtils.replace( commandLineInfo, this.storepass, "'*****'" );
386 return commandLineInfo;
387 }
388
389 public String getStoretype()
390 {
391 return storetype;
392 }
393
394 public String getStorepass()
395 {
396 return storepass;
397 }
398
399
400
401
402
403
404
405 private boolean isZipFile( final Artifact artifact )
406 {
407 return artifact != null && artifact.getFile() != null && JarSignerUtil.isZipFile( artifact.getFile() );
408 }
409
410
411
412
413
414
415
416
417
418 private boolean processArtifact( final Artifact artifact )
419 throws MojoExecutionException
420 {
421 if ( artifact == null )
422 {
423 throw new NullPointerException( "artifact" );
424 }
425
426 boolean processed = false;
427
428 if ( isZipFile( artifact ) )
429 {
430 processArchive( artifact.getFile() );
431
432 processed = true;
433 }
434 else
435 {
436 if ( this.verbose )
437 {
438 getLog().info( getMessage( "unsupported", artifact ) );
439 }
440 else if ( getLog().isDebugEnabled() )
441 {
442 getLog().debug( getMessage( "unsupported", artifact ) );
443 }
444 }
445
446 return processed;
447 }
448
449
450
451
452
453
454
455 protected void preProcessArchive( final File archive )
456 throws MojoExecutionException
457 {
458
459 }
460
461
462
463
464
465
466
467
468 private void processArchive( final File archive )
469 throws MojoExecutionException
470 {
471 if ( archive == null )
472 {
473 throw new NullPointerException( "archive" );
474 }
475
476 preProcessArchive( archive );
477
478 if ( this.verbose )
479 {
480 getLog().info( getMessage( "processing", archive ) );
481 }
482 else if ( getLog().isDebugEnabled() )
483 {
484 getLog().debug( getMessage( "processing", archive ) );
485 }
486
487 JarSignerRequest request = createRequest( archive );
488 request.setVerbose( verbose );
489 request.setAlias( alias );
490 request.setArchive( archive );
491 request.setKeystore( keystore );
492 request.setStoretype( storetype );
493 request.setProviderArg( providerArg );
494 request.setProviderClass( providerClass );
495 request.setProviderName( providerName );
496 request.setWorkingDirectory( workingDirectory );
497 request.setMaxMemory( maxMemory );
498 request.setArguments( arguments );
499 request.setProtectedAuthenticationPath( protectedAuthenticationPath );
500
501
502 request.setStorepass( decrypt( storepass ) );
503
504 try
505 {
506 JavaToolResult result = jarSigner.execute( request );
507
508 Commandline commandLine = result.getCommandline();
509
510 int resultCode = result.getExitCode();
511
512 if ( resultCode != 0 )
513 {
514
515 throw new MojoExecutionException( getMessage( "failure", getCommandlineInfo( commandLine ), resultCode ) );
516
517 }
518
519 }
520 catch ( JavaToolException e )
521 {
522 throw new MojoExecutionException( getMessage( "commandLineException", e.getMessage() ), e );
523 }
524 }
525
526 protected String decrypt( String encoded )
527 throws MojoExecutionException
528 {
529 try
530 {
531 return securityDispatcher.decrypt( encoded );
532 }
533 catch ( SecDispatcherException e )
534 {
535 getLog().error( "error using security dispatcher: " + e.getMessage(), e );
536 throw new MojoExecutionException( "error using security dispatcher: " + e.getMessage(), e );
537 }
538 }
539
540
541
542
543
544
545
546
547
548
549
550
551 private String getMessage( final String key, final Object[] args )
552 {
553 if ( key == null )
554 {
555 throw new NullPointerException( "key" );
556 }
557
558 return new MessageFormat( ResourceBundle.getBundle( "jarsigner" ).getString( key ) ).format( args );
559 }
560
561 private String getMessage( final String key )
562 {
563 return getMessage( key, null );
564 }
565
566 String getMessage( final String key, final Object arg )
567 {
568 return getMessage( key, new Object[] { arg } );
569 }
570
571 private String getMessage( final String key, final Object arg1, final Object arg2 )
572 {
573 return getMessage( key, new Object[] { arg1, arg2 } );
574 }
575
576
577
578
579
580
581
582
583 private Toolchain getToolchain()
584 {
585 Toolchain tc = null;
586 if ( toolchainManager != null )
587 {
588 tc = toolchainManager.getToolchainFromBuildContext( "jdk", session );
589 }
590
591 return tc;
592 }
593 }