View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.openpgp.ant;
18  
19  import org.apache.tools.ant.Task;
20  import org.apache.tools.ant.BuildException;
21  import org.apache.tools.ant.DirectoryScanner;
22  import org.apache.tools.ant.util.FileNameMapper;
23  import org.apache.tools.ant.util.GlobPatternMapper;
24  import org.apache.tools.ant.util.FileUtils;
25  import org.apache.tools.ant.types.FileSet;
26  import org.apache.tools.ant.types.Mapper;
27  import org.apache.commons.openpgp.*;
28  import org.bouncycastle.openpgp.PGPException;
29  
30  import java.io.*;
31  import java.util.Collection;
32  import java.util.ArrayList;
33  import java.util.Iterator;
34  
35  /**
36   */
37  public class OpenPgpSignerTask extends Task {
38      private File secring;
39      private File pubring;
40      private String password;
41      private String keyId;
42      private Collection<FileSet> tosign = new ArrayList<FileSet>();
43      private File artefact;
44      private boolean asciiarmor = true;
45      private Mapper mapperElement;
46  
47      /**
48       * set the secret keyring
49       * @param secring secret keyring file
50       */
51      public void setSecring(File secring) {
52          this.secring = secring;
53      }
54  
55      /**
56       * set the public keyring
57       * @param pubring public keyring file
58       */
59      public void setPubring(File pubring) {
60          this.pubring = pubring;
61      }
62  
63      /**
64       * set the key id
65       * @param keyId
66       */
67      public void setKeyId(String keyId) {
68          this.keyId = keyId;
69      }
70  
71      /**
72       * asciiarmor the signature ?
73       * @param asciiarmor ascii armored signature ?
74       */
75      public void setAsciiarmor(boolean asciiarmor) {
76          this.asciiarmor = asciiarmor;
77      }
78  
79      /**
80       * set the value of the password
81       * @param password value of the password
82       */
83      public void setPassword(String password) {
84          this.password = password;
85      }
86  
87      /**
88       * artefact to be signed
89       * @param artefact artefact to be signed
90       */
91      public void setArtefact(File artefact) {
92          this.artefact = artefact;
93      }
94  
95  
96      public void add(FileSet fs) {
97          tosign.add(fs);
98      }
99  
100     /**
101      * Define the mapper to map source to destination files.
102      * @return a mapper to be configured.
103      * @exception org.apache.tools.ant.BuildException if more than one mapper is defined.
104      */
105     public Mapper createMapper() throws BuildException {
106         if (mapperElement != null) {
107             throw new BuildException("Cannot define more than one mapper",
108                     getLocation());
109         }
110         mapperElement = new Mapper(getProject());
111         return mapperElement;
112     }
113 
114     public void execute() {
115         if (secring == null) {
116             throw new BuildException("secring attribute compulsory");
117         }
118         if (pubring == null) {
119             throw new BuildException("pubring attribute compulsory");
120         }
121         if (password == null) {
122             throw new BuildException("password attribute compulsory");
123         }
124         if (tosign.size() == 0 && artefact == null) {
125             throw new BuildException("supply the attribute 'artefact' or one nested fileset");
126         }
127         if (!secring.exists() || !secring.canRead()) {
128             throw new  BuildException("secret keyring file '" + secring.getAbsolutePath() + "' does not exist or is not readable");
129         }
130         if (!pubring.exists() || !pubring.canRead()) {
131             throw new  BuildException("public keyring file '" + pubring.getAbsolutePath() + "' does not exist or is not readable");
132         }
133         FileInputStream secStream;
134         FileInputStream pubStream;
135         KeyRing keyRing = null;
136         try {
137             secStream = new FileInputStream(secring);
138             pubStream = new FileInputStream(pubring);
139             keyRing = new BouncyCastleKeyRing(secStream,
140                     pubStream, password.toCharArray() );
141         } catch (IOException ioe) {
142             throw new BuildException(ioe);
143         } catch (PGPException pgpe) {
144             throw new BuildException(pgpe);
145         }
146         if (artefact != null) {
147             dosign(keyRing, artefact);
148         }
149         if (tosign.size() != 0) {
150             for (FileSet fileset : tosign) {
151                 dosign(keyRing, fileset);
152             }
153         }
154         FileUtils.close(secStream);
155         FileUtils.close(pubStream);
156     }
157     private void dosign(KeyRing keyRing, FileSet fs) {
158         DirectoryScanner ds = fs.getDirectoryScanner(getProject());
159         String[] artefacts = ds.getIncludedFiles();
160         for (String artefact : artefacts) {
161             dosign(keyRing, new File(fs.getDir(getProject()), artefact), fs.getDir(getProject()), artefact);
162         }
163     }
164     private void dosign(KeyRing keyRing, File oneartefact) {
165         dosign(keyRing, oneartefact, oneartefact.getParentFile(), oneartefact.getName());
166     }
167     private void dosign(KeyRing keyRing, File oneartefact, File basedir, String relpath) {
168         FileInputStream fis = null;
169         FileOutputStream fos = null;
170         File signature;
171 
172         try {
173             fis = new FileInputStream(oneartefact);
174             FileNameMapper mapper = getMapper();
175             String [] mappedFiles = mapper.mapFileName(relpath);
176             if (mappedFiles == null || mappedFiles.length != 1) {
177                 throw new BuildException("mapper returned more or less than one output");
178             }
179             signature = new File(basedir, mappedFiles[0]);
180             fos = new FileOutputStream(signature);
181             OpenPgpSigner signer = new BouncyCastleOpenPgpSigner();
182             signer.detachedSign(fis, fos, keyId, keyRing, asciiarmor);
183         } catch (FileNotFoundException fnfe) {
184             throw new BuildException(fnfe);
185         } catch (IOException ioe) {
186             throw new BuildException(ioe);
187         } catch (OpenPgpException opgpe) {
188             throw new BuildException(opgpe);
189         }
190         FileUtils.close(fos);
191         FileUtils.close(fis);
192 
193     }
194     /**
195      * returns the mapper to use based on nested elements or the
196      */
197     private FileNameMapper getMapper() {
198         FileNameMapper mapper = null;
199         if (mapperElement != null) {
200             mapper = mapperElement.getImplementation();
201         } else {
202             mapper = new GlobPatternMapper();
203             mapper.setFrom("*");
204             if (asciiarmor) {
205                 mapper.setTo("*.asc");
206             } else {
207                 mapper.setTo("*.sig");
208             }
209         }
210         return mapper;
211     }
212 
213 }