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