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