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 }