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