001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.commons.openpgp.ant;
018
019 import org.apache.tools.ant.Task;
020 import org.apache.tools.ant.BuildException;
021 import org.apache.tools.ant.DirectoryScanner;
022 import org.apache.tools.ant.util.FileNameMapper;
023 import org.apache.tools.ant.util.GlobPatternMapper;
024 import org.apache.tools.ant.util.FileUtils;
025 import org.apache.tools.ant.types.FileSet;
026 import org.apache.tools.ant.types.Mapper;
027 import org.apache.commons.openpgp.*;
028 import org.bouncycastle.openpgp.PGPException;
029
030 import java.io.*;
031 import java.util.Collection;
032 import java.util.ArrayList;
033 import java.util.Iterator;
034
035 /**
036 */
037 public class OpenPgpSignerTask extends Task {
038 private File secring;
039 private File pubring;
040 private String password;
041 private String keyId;
042 private Collection<FileSet> tosign = new ArrayList<FileSet>();
043 private File artefact;
044 private boolean asciiarmor = true;
045 private Mapper mapperElement;
046
047 /**
048 * set the secret keyring
049 * @param secring secret keyring file
050 */
051 public void setSecring(File secring) {
052 this.secring = secring;
053 }
054
055 /**
056 * set the public keyring
057 * @param pubring public keyring file
058 */
059 public void setPubring(File pubring) {
060 this.pubring = pubring;
061 }
062
063 /**
064 * set the key id
065 * @param keyId
066 */
067 public void setKeyId(String keyId) {
068 this.keyId = keyId;
069 }
070
071 /**
072 * asciiarmor the signature ?
073 * @param asciiarmor ascii armored signature ?
074 */
075 public void setAsciiarmor(boolean asciiarmor) {
076 this.asciiarmor = asciiarmor;
077 }
078
079 /**
080 * set the value of the password
081 * @param password value of the password
082 */
083 public void setPassword(String password) {
084 this.password = password;
085 }
086
087 /**
088 * artefact to be signed
089 * @param artefact artefact to be signed
090 */
091 public void setArtefact(File artefact) {
092 this.artefact = artefact;
093 }
094
095
096 public void add(FileSet fs) {
097 tosign.add(fs);
098 }
099
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 }