View Javadoc
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      * &lt;gpgArguments&gt;
141      *   &lt;arg&gt;--no-random-seed-file&lt;/arg&gt;
142      *   &lt;arg&gt;--no-permission-warning&lt;/arg&gt;
143      * &lt;/gpgArguments&gt;
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 }