1 package org.apache.maven.plugin.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 * The path to a secret keyring to add to the list of keyrings. By default, only the {@code secring.gpg} from gpg's
106 * 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.
109 *
110 * @since 1.2
111 */
112 @Parameter( property = "gpg.secretKeyring" )
113 private String secretKeyring;
114
115 /**
116 * The path to a public keyring to add to the list of keyrings. By default, only the {@code pubring.gpg} from gpg's
117 * home directory is considered. Use this option (and {@link #defaultKeyring} if required) to use a different public
118 * key. <em>Note:</em> Relative paths are resolved against gpg's home directory, not the project base directory.
119 *
120 * @since 1.2
121 */
122 @Parameter( property = "gpg.publicKeyring" )
123 private String publicKeyring;
124
125 /**
126 * The lock mode to use when invoking gpg. By default no lock mode will be specified. Valid values are {@code once},
127 * {@code multiple} and {@code never}. The lock mode gets translated into the corresponding {@code --lock-___}
128 * command line argument. Improper usage of this option may lead to data and key corruption.
129 *
130 * @see <a href="http://www.gnupg.org/documentation/manuals/gnupg/GPG-Configuration-Options.html">the
131 * --lock-options</a>
132 * @since 1.5
133 */
134 @Parameter( property = "gpg.lockMode" )
135 private String lockMode;
136
137 /**
138 * Sets the arguments to be passed to gpg. Example:
139 *
140 * <pre>
141 * <gpgArguments>
142 * <arg>--no-random-seed-file</arg>
143 * <arg>--no-permission-warning</arg>
144 * </gpgArguments>
145 * </pre>
146 *
147 * @since 1.5
148 */
149 @Parameter
150 private List<String> gpgArguments;
151
152 /**
153 * Current user system settings for use in Maven.
154 *
155 * @since 1.6
156 */
157 @Parameter( defaultValue = "${settings}", readonly = true )
158 private Settings settings;
159
160 /**
161 * Maven Security Dispatcher
162 *
163 * @since 1.6
164 */
165 @Component( hint = "mng-4384" )
166 private SecDispatcher securityDispatcher;
167
168 AbstractGpgSigner newSigner( MavenProject project )
169 throws MojoExecutionException, MojoFailureException
170 {
171 AbstractGpgSigner signer = new GpgSigner( executable );
172
173 signer.setLog( getLog() );
174 signer.setInteractive( interactive );
175 signer.setKeyName( keyname );
176 signer.setUseAgent( useAgent );
177 signer.setHomeDirectory( homedir );
178 signer.setDefaultKeyring( defaultKeyring );
179 signer.setSecretKeyring( secretKeyring );
180 signer.setPublicKeyring( publicKeyring );
181 signer.setLockMode( lockMode );
182 signer.setArgs( gpgArguments );
183
184 loadGpgPassphrase();
185
186 signer.setPassPhrase( passphrase );
187 if ( null == passphrase && !useAgent )
188 {
189 if ( !interactive )
190 {
191 throw new MojoFailureException( "Cannot obtain passphrase in batch mode" );
192 }
193 try
194 {
195 signer.setPassPhrase( signer.getPassphrase( project ) );
196 }
197 catch ( IOException e )
198 {
199 throw new MojoExecutionException( "Exception reading passphrase", e );
200 }
201 }
202
203 return signer;
204 }
205
206 /**
207 * Load and decrypt gpg passphrase from Maven settings if not given from plugin configuration
208 *
209 * @throws MojoFailureException
210 */
211 private void loadGpgPassphrase()
212 throws MojoFailureException
213 {
214 if ( StringUtils.isEmpty( this.passphrase ) )
215 {
216 Server server = this.settings.getServer( passphraseServerId );
217
218 if ( server != null )
219 {
220 if ( server.getPassphrase() != null )
221 {
222 try
223 {
224 this.passphrase = securityDispatcher.decrypt( server.getPassphrase() );
225 }
226 catch ( SecDispatcherException e )
227 {
228 throw new MojoFailureException( "Unable to decrypt gpg passphrase", e );
229 }
230 }
231 }
232 }
233 }
234 }