1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19 package org.apache.maven.plugins.gpg;
20
21 import java.io.File;
22 import java.io.IOException;
23 import java.util.List;
24
25 import org.apache.maven.plugin.AbstractMojo;
26 import org.apache.maven.plugin.MojoExecutionException;
27 import org.apache.maven.plugin.MojoFailureException;
28 import org.apache.maven.plugins.annotations.Component;
29 import org.apache.maven.plugins.annotations.Parameter;
30 import org.apache.maven.project.MavenProject;
31 import org.apache.maven.settings.Server;
32 import org.apache.maven.settings.Settings;
33 import org.codehaus.plexus.util.StringUtils;
34 import org.sonatype.plexus.components.sec.dispatcher.SecDispatcher;
35 import org.sonatype.plexus.components.sec.dispatcher.SecDispatcherException;
36
37 /**
38 * @author Benjamin Bentmann
39 */
40 public abstract class AbstractGpgMojo extends AbstractMojo {
41
42 /**
43 * The directory from which gpg will load keyrings. If not specified, gpg will use the value configured for its
44 * installation, e.g. <code>~/.gnupg</code> or <code>%APPDATA%/gnupg</code>.
45 *
46 * @since 1.0
47 */
48 @Parameter(property = "gpg.homedir")
49 private File homedir;
50
51 /**
52 * The passphrase to use when signing. If not given, look up the value under Maven
53 * settings using server id at 'passphraseServerKey' configuration.
54 **/
55 @Parameter(property = "gpg.passphrase")
56 private String passphrase;
57
58 /**
59 * Server id to lookup the passphrase under Maven settings.
60 * @since 1.6
61 */
62 @Parameter(property = "gpg.passphraseServerId", defaultValue = "gpg.passphrase")
63 private String passphraseServerId;
64
65 /**
66 * The "name" of the key to sign with. Passed to gpg as <code>--local-user</code>.
67 */
68 @Parameter(property = "gpg.keyname")
69 private String keyname;
70
71 /**
72 * Passes <code>--use-agent</code> or <code>--no-use-agent</code> to gpg. If using an agent, the passphrase is
73 * optional as the agent will provide it. For gpg2, specify true as --no-use-agent was removed in gpg2 and doesn't
74 * ask for a passphrase anymore.
75 */
76 @Parameter(property = "gpg.useagent", defaultValue = "true")
77 private boolean useAgent;
78
79 /**
80 */
81 @Parameter(defaultValue = "${settings.interactiveMode}", readonly = true)
82 private boolean interactive;
83
84 /**
85 * The path to the GnuPG executable to use for artifact signing. Defaults to either "gpg" or "gpg.exe" depending on
86 * the operating system.
87 *
88 * @since 1.1
89 */
90 @Parameter(property = "gpg.executable")
91 private String executable;
92
93 /**
94 * Whether to add the default keyrings from gpg's home directory to the list of used keyrings.
95 *
96 * @since 1.2
97 */
98 @Parameter(property = "gpg.defaultKeyring", defaultValue = "true")
99 private boolean defaultKeyring;
100
101 /**
102 * <p>The path to a secret keyring to add to the list of keyrings. By default, only the {@code secring.gpg} from
103 * gpg's home directory is considered. Use this option (in combination with {@link #publicKeyring} and
104 * {@link #defaultKeyring} if required) to use a different secret key. <em>Note:</em> Relative paths are resolved
105 * against gpg's home directory, not the project base directory.</p>
106 * <strong>NOTE: </strong>As of gpg 2.1 this is an obsolete option and ignored. All secret keys are stored in the
107 * ‘private-keys-v1.d’ directory below the GnuPG home directory.
108 *
109 * @since 1.2
110 */
111 @Parameter(property = "gpg.secretKeyring")
112 private String secretKeyring;
113
114 /**
115 * The path to a public keyring to add to the list of keyrings. By default, only the {@code pubring.gpg} from gpg's
116 * home directory is considered. Use this option (and {@link #defaultKeyring} if required) to use a different public
117 * key. <em>Note:</em> Relative paths are resolved against gpg's home directory, not the project base directory.
118 *
119 * @since 1.2
120 */
121 @Parameter(property = "gpg.publicKeyring")
122 private String publicKeyring;
123
124 /**
125 * The lock mode to use when invoking gpg. By default no lock mode will be specified. Valid values are {@code once},
126 * {@code multiple} and {@code never}. The lock mode gets translated into the corresponding {@code --lock-___}
127 * command line argument. Improper usage of this option may lead to data and key corruption.
128 *
129 * @see <a href="http://www.gnupg.org/documentation/manuals/gnupg/GPG-Configuration-Options.html">the
130 * --lock-options</a>
131 * @since 1.5
132 */
133 @Parameter(property = "gpg.lockMode")
134 private String lockMode;
135
136 /**
137 * Sets the arguments to be passed to gpg. Example:
138 *
139 * <pre>
140 * <gpgArguments>
141 * <arg>--no-random-seed-file</arg>
142 * <arg>--no-permission-warning</arg>
143 * </gpgArguments>
144 * </pre>
145 *
146 * @since 1.5
147 */
148 @Parameter
149 private List<String> gpgArguments;
150
151 /**
152 * Current user system settings for use in Maven.
153 *
154 * @since 1.6
155 */
156 @Parameter(defaultValue = "${settings}", readonly = true)
157 private Settings settings;
158
159 /**
160 * Maven Security Dispatcher
161 *
162 * @since 1.6
163 */
164 @Component(hint = "mng-4384")
165 private SecDispatcher securityDispatcher;
166
167 AbstractGpgSigner newSigner(MavenProject project) throws MojoExecutionException, MojoFailureException {
168 AbstractGpgSigner signer = new GpgSigner(executable);
169
170 signer.setLog(getLog());
171 signer.setInteractive(interactive);
172 signer.setKeyName(keyname);
173 signer.setUseAgent(useAgent);
174 signer.setHomeDirectory(homedir);
175 signer.setDefaultKeyring(defaultKeyring);
176 signer.setSecretKeyring(secretKeyring);
177 signer.setPublicKeyring(publicKeyring);
178 signer.setLockMode(lockMode);
179 signer.setArgs(gpgArguments);
180
181 loadGpgPassphrase();
182
183 signer.setPassPhrase(passphrase);
184 if (null == passphrase && !useAgent) {
185 if (!interactive) {
186 throw new MojoFailureException("Cannot obtain passphrase in batch mode");
187 }
188 try {
189 signer.setPassPhrase(signer.getPassphrase(project));
190 } catch (IOException e) {
191 throw new MojoExecutionException("Exception reading passphrase", e);
192 }
193 }
194
195 return signer;
196 }
197
198 /**
199 * Load and decrypt gpg passphrase from Maven settings if not given from plugin configuration
200 *
201 * @throws MojoFailureException
202 */
203 private void loadGpgPassphrase() throws MojoFailureException {
204 if (StringUtils.isEmpty(this.passphrase)) {
205 Server server = this.settings.getServer(passphraseServerId);
206
207 if (server != null) {
208 if (server.getPassphrase() != null) {
209 try {
210 this.passphrase = securityDispatcher.decrypt(server.getPassphrase());
211 } catch (SecDispatcherException e) {
212 throw new MojoFailureException("Unable to decrypt gpg passphrase", e);
213 }
214 }
215 }
216 }
217 }
218 }