1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.plugins.gpg;
20
21 import javax.inject.Inject;
22
23 import java.io.File;
24 import java.util.List;
25
26 import org.apache.maven.execution.MavenSession;
27 import org.apache.maven.plugin.AbstractMojo;
28 import org.apache.maven.plugin.MojoExecutionException;
29 import org.apache.maven.plugin.MojoFailureException;
30 import org.apache.maven.plugins.annotations.Parameter;
31 import org.apache.maven.project.MavenProject;
32 import org.apache.maven.settings.Server;
33 import org.apache.maven.settings.Settings;
34 import org.apache.maven.settings.building.SettingsProblem;
35 import org.apache.maven.settings.crypto.DefaultSettingsDecryptionRequest;
36 import org.apache.maven.settings.crypto.SettingsDecrypter;
37 import org.apache.maven.settings.crypto.SettingsDecryptionResult;
38
39
40
41
42 public abstract class AbstractGpgMojo extends AbstractMojo {
43 public static final String DEFAULT_ENV_MAVEN_GPG_KEY = "MAVEN_GPG_KEY";
44 public static final String DEFAULT_ENV_MAVEN_GPG_FINGERPRINT = "MAVEN_GPG_KEY_FINGERPRINT";
45 public static final String DEFAULT_ENV_MAVEN_GPG_PASSPHRASE = "MAVEN_GPG_PASSPHRASE";
46
47
48
49
50
51
52
53 @Parameter(property = "gpg.agentSocketLocations", defaultValue = ".gnupg/S.gpg-agent")
54 private String agentSocketLocations;
55
56
57
58
59
60
61
62
63
64
65
66
67 @Parameter(property = "gpg.keyFilePath", defaultValue = "maven-signing-key.key")
68 private String keyFilePath;
69
70
71
72
73
74
75 @Parameter(property = "gpg.keyFingerprint")
76 private String keyFingerprint;
77
78
79
80
81
82
83
84
85
86
87 @Parameter(property = "gpg.keyEnvName", defaultValue = DEFAULT_ENV_MAVEN_GPG_KEY)
88 private String keyEnvName;
89
90
91
92
93
94
95
96 @Parameter(property = "gpg.keyFingerprintEnvName", defaultValue = DEFAULT_ENV_MAVEN_GPG_FINGERPRINT)
97 private String keyFingerprintEnvName;
98
99
100
101
102
103
104
105 @Parameter(property = "gpg.passphraseEnvName", defaultValue = DEFAULT_ENV_MAVEN_GPG_PASSPHRASE)
106 private String passphraseEnvName;
107
108
109
110
111
112
113
114 @Parameter(property = "gpg.homedir")
115 private File homedir;
116
117
118
119
120
121
122
123
124
125
126 @Deprecated
127 @Parameter(property = GPG_PASSPHRASE)
128 private String passphrase;
129
130
131
132
133
134
135
136
137
138
139
140 @Deprecated
141 @Parameter(property = "gpg.passphraseServerId")
142 private String passphraseServerId;
143
144
145
146
147 @Parameter(property = "gpg.keyname")
148 private String keyname;
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164 @Parameter(property = "gpg.useagent", defaultValue = "true")
165 private boolean useAgent;
166
167
168
169
170
171
172
173 @Parameter(property = "gpg.executable")
174 private String executable;
175
176
177
178
179
180
181 @Parameter(property = "gpg.defaultKeyring", defaultValue = "true")
182 private boolean defaultKeyring;
183
184
185
186
187
188
189
190
191
192
193
194
195
196 @Deprecated
197 @Parameter(property = "gpg.secretKeyring")
198 private String secretKeyring;
199
200
201
202
203
204
205
206
207
208
209
210
211
212 @Deprecated
213 @Parameter(property = "gpg.publicKeyring")
214 private String publicKeyring;
215
216
217
218
219
220
221
222
223
224
225
226 @Parameter(property = "gpg.lockMode")
227 private String lockMode;
228
229
230
231
232 @Parameter(property = "gpg.skip", defaultValue = "false")
233 private boolean skip;
234
235
236
237
238
239
240
241
242
243
244
245
246
247 @Parameter
248 private List<String> gpgArguments;
249
250
251
252
253
254
255
256 @Parameter(property = "gpg.signer", defaultValue = GpgSigner.NAME)
257 private String signer;
258
259
260
261
262
263
264
265
266
267
268
269
270 @Parameter(property = "gpg.bestPractices", defaultValue = "false")
271 private boolean bestPractices;
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286 @Parameter(property = "gpg.terminatePassphrase", defaultValue = "true")
287 private boolean terminatePassphrase;
288
289
290
291
292
293
294 @Parameter(defaultValue = "${settings}", readonly = true, required = true)
295 protected Settings settings;
296
297
298
299
300 @Inject
301 protected MavenSession session;
302
303
304
305
306 @Inject
307 protected SettingsDecrypter settingsDecrypter;
308
309 @Override
310 public final void execute() throws MojoExecutionException, MojoFailureException {
311 if (skip) {
312
313 return;
314 }
315 if (bestPractices) {
316 enforceBestPractices();
317 } else {
318 if (!isNotBlank(passphraseServerId)) {
319
320 passphraseServerId = GPG_PASSPHRASE;
321 }
322 }
323
324 doExecute();
325 }
326
327 protected void enforceBestPractices() throws MojoFailureException {
328
329 if (isNotBlank(passphrase) || isNotBlank(passphraseServerId)) {
330
331 throw new MojoFailureException(
332 "Do not store passphrase in any file (disk or SCM repository), rely on GnuPG agent or provide passphrase in "
333 + passphraseEnvName + " environment variable.");
334 }
335 }
336
337 protected abstract void doExecute() throws MojoExecutionException, MojoFailureException;
338
339 private void logBestPracticeWarning(String source) {
340 getLog().warn("");
341 getLog().warn("W A R N I N G");
342 getLog().warn("");
343 getLog().warn("Do not store passphrase in any file (disk or SCM repository),");
344 getLog().warn("instead rely on GnuPG agent or provide passphrase in ");
345 getLog().warn(passphraseEnvName + " environment variable for batch mode.");
346 getLog().warn("");
347 getLog().warn("Sensitive content loaded from " + source);
348 getLog().warn("");
349 }
350
351 protected AbstractGpgSigner newSigner(MavenProject mavenProject) throws MojoFailureException {
352 AbstractGpgSigner signer = createSigner(this.signer);
353
354 signer.setLog(getLog());
355 signer.setInteractive(settings.isInteractiveMode());
356 signer.setKeyName(keyname);
357 signer.setUseAgent(useAgent);
358 signer.setHomeDirectory(homedir);
359 signer.setDefaultKeyring(defaultKeyring);
360 signer.setSecretKeyring(secretKeyring);
361 signer.setPublicKeyring(publicKeyring);
362 signer.setLockMode(lockMode);
363 signer.setArgs(gpgArguments);
364 signer.setTerminatePassphrase(terminatePassphrase);
365
366
367 String passphrase =
368 (String) session.getRepositorySession().getConfigProperties().get("env." + passphraseEnvName);
369 if (isNotBlank(passphrase)) {
370 signer.setPassPhrase(passphrase);
371 } else if (!bestPractices) {
372
373 passphrase = this.passphrase;
374 if (isNotBlank(passphrase)) {
375 logBestPracticeWarning("Mojo configuration");
376 signer.setPassPhrase(passphrase);
377 } else {
378
379 passphrase = loadGpgPassphrase();
380 if (isNotBlank(passphrase)) {
381 logBestPracticeWarning("settings.xml");
382 signer.setPassPhrase(passphrase);
383 } else {
384
385 passphrase = getPassphrase(mavenProject);
386 if (isNotBlank(passphrase)) {
387 logBestPracticeWarning("Project properties");
388 signer.setPassPhrase(passphrase);
389 }
390 }
391 }
392 }
393 signer.prepare();
394
395 return signer;
396 }
397
398 protected AbstractGpgSigner createSigner(String name) throws MojoFailureException {
399 AbstractGpgSigner signer;
400 if (GpgSigner.NAME.equals(name)) {
401 signer = new GpgSigner(executable);
402 } else if (BcSigner.NAME.equals(name)) {
403 signer = new BcSigner(
404 session.getRepositorySession(),
405 keyEnvName,
406 keyFingerprintEnvName,
407 agentSocketLocations,
408 keyFilePath,
409 keyFingerprint);
410 } else {
411 throw new MojoFailureException("Unknown signer: " + name);
412 }
413 return signer;
414 }
415
416 private boolean isNotBlank(String string) {
417 return string != null && !string.trim().isEmpty();
418 }
419
420
421
422 @Deprecated
423 private static final String GPG_PASSPHRASE = "gpg.passphrase";
424
425 @Deprecated
426 private String loadGpgPassphrase() throws MojoFailureException {
427 if (isNotBlank(passphraseServerId)) {
428 Server server = settings.getServer(passphraseServerId);
429 if (server != null) {
430 if (isNotBlank(server.getPassphrase())) {
431 SettingsDecryptionResult result =
432 settingsDecrypter.decrypt(new DefaultSettingsDecryptionRequest(server));
433 for (SettingsProblem problem : result.getProblems()) {
434 switch (problem.getSeverity()) {
435 case WARNING:
436 case ERROR:
437 getLog().warn(problem.getMessage(), problem.getException());
438 break;
439 case FATAL:
440 getLog().error(problem.getMessage(), problem.getException());
441 throw new MojoFailureException(problem.getMessage(), problem.getException());
442 default:
443 throw new IllegalStateException("Unknown severity: "
444 + problem.getSeverity().toString());
445 }
446 }
447 return result.getServer().getPassphrase();
448 }
449 }
450 }
451 return null;
452 }
453
454 @Deprecated
455 public String getPassphrase(MavenProject project) {
456 String pass = null;
457 if (project != null) {
458 pass = project.getProperties().getProperty(GPG_PASSPHRASE);
459 if (pass == null) {
460 MavenProject prj2 = findReactorProject(project);
461 pass = prj2.getProperties().getProperty(GPG_PASSPHRASE);
462 }
463 }
464 if (project != null && pass != null) {
465 findReactorProject(project).getProperties().setProperty(GPG_PASSPHRASE, pass);
466 }
467 return pass;
468 }
469
470 @Deprecated
471 private MavenProject findReactorProject(MavenProject prj) {
472 if (prj.getParent() != null
473 && prj.getParent().getBasedir() != null
474 && prj.getParent().getBasedir().exists()) {
475 return findReactorProject(prj.getParent());
476 }
477 return prj;
478 }
479 }