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