You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@ant.apache.org by ma...@apache.org on 2010/08/31 09:47:07 UTC

svn commit: r991108 - in /ant/ivy/core/trunk: ./ doc/ doc/settings/ src/java/org/apache/ivy/core/settings/ src/java/org/apache/ivy/plugins/resolver/ src/java/org/apache/ivy/plugins/signer/ src/java/org/apache/ivy/plugins/signer/bouncycastle/

Author: maartenc
Date: Tue Aug 31 07:47:06 2010
New Revision: 991108

URL: http://svn.apache.org/viewvc?rev=991108&view=rev
Log:
NEW: Ivy can now generate OpenPGP compatible ASCII armored detached signatures when publishing artifacts.

Added:
    ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/signer/
    ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/signer/SignatureGenerator.java
    ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/signer/bouncycastle/
    ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/signer/bouncycastle/OpenPGPSignatureGenerator.java
Modified:
    ant/ivy/core/trunk/CHANGES.txt
    ant/ivy/core/trunk/README
    ant/ivy/core/trunk/build-release.xml
    ant/ivy/core/trunk/doc/settings/resolvers.html
    ant/ivy/core/trunk/doc/toc.json
    ant/ivy/core/trunk/ivy.xml
    ant/ivy/core/trunk/ivysettings-release.xml
    ant/ivy/core/trunk/optional.patterns
    ant/ivy/core/trunk/src/java/org/apache/ivy/core/settings/IvySettings.java
    ant/ivy/core/trunk/src/java/org/apache/ivy/core/settings/XmlSettingsParser.java
    ant/ivy/core/trunk/src/java/org/apache/ivy/core/settings/typedef.properties
    ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/RepositoryResolver.java
    ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/ResolverSettings.java

Modified: ant/ivy/core/trunk/CHANGES.txt
URL: http://svn.apache.org/viewvc/ant/ivy/core/trunk/CHANGES.txt?rev=991108&r1=991107&r2=991108&view=diff
==============================================================================
--- ant/ivy/core/trunk/CHANGES.txt (original)
+++ ant/ivy/core/trunk/CHANGES.txt Tue Aug 31 07:47:06 2010
@@ -115,6 +115,7 @@ for detailed view of each issue, please 
 - DOCUMENTATION: Grammar, spelling, and clarity of Settings File documentation (IVY-1216) (thanks to Steve Miller)
 - DOCUMENTATION: Grammar, spelling, and clarity of Tutorial documentation (IVY-1222) (thanks to Steve Miller)
 
+- NEW: Ivy can now generate OpenPGP compatible ASCII armored detached signatures when publishing artifacts.
 
 - IMPROVEMENT: the <artifact> child of ivy:publish now accepts any attribute
 - IMPROVEMENT: Handle attributes in description subelements (IVY-1214) (thanks to Jean-Louis Boudart)

Modified: ant/ivy/core/trunk/README
URL: http://svn.apache.org/viewvc/ant/ivy/core/trunk/README?rev=991108&r1=991107&r2=991108&view=diff
==============================================================================
--- ant/ivy/core/trunk/README (original)
+++ ant/ivy/core/trunk/README Tue Aug 31 07:47:06 2010
@@ -53,9 +53,11 @@ code and source code.
 The following provides more details on the included cryptographic
 software:
 
-For the Ivy ssh resolver requires the JSch 
-<http://www.jcraft.com/jsch/index.html> library. 
+The Ivy ssh resolver requires the JSch library
+<http://www.jcraft.com/jsch/index.html>. 
 The sftp and https resolvers requires the Java Cryptography extensions
 <http://java.sun.com/javase/technologies/security/>.
+The PGP signature generator requires the BouncyCastle Java cryptography APIs
+<http://www.bouncycastle.org/java.html>.
 
 

Modified: ant/ivy/core/trunk/build-release.xml
URL: http://svn.apache.org/viewvc/ant/ivy/core/trunk/build-release.xml?rev=991108&r1=991107&r2=991108&view=diff
==============================================================================
--- ant/ivy/core/trunk/build-release.xml (original)
+++ ant/ivy/core/trunk/build-release.xml Tue Aug 31 07:47:06 2010
@@ -18,6 +18,7 @@
 -->
 <project name="IvyRelease" default="snapshot" 
 		xmlns:ivy="antlib:org.apache.ivy.ant"
+        xmlns:ivy2="antlib:org.apache.ivy.ant_2"
 		xmlns:xooki="antlib:xooki"
 		xmlns:openpgp="antlib:org.apache.commons.openpgp.ant">
 	<import file="build.xml"/>
@@ -471,10 +472,20 @@
         </fail>
     </target>	
 	
-    <target name="upload-nexus" depends="release-version, init-ivy">
-        <ivy:settings id="upload.settingsId" file="ivysettings-release.xml" />
-        <ivy:resolve file="${basedir}/build/artifact/ivy.xml" transitive="false" />
-        <ivy:publish organisation="org.apache.ivy"
+    <target name="upload-nexus" depends="release-version, init-ivy, jar">
+        <ivy:retrieve conf="default" pattern="${build.dir}/lib/[artifact]-[revision].[ext]" />
+
+        <taskdef resource="org/apache/ivy/ant/antlib.xml"
+                uri="antlib:org.apache.ivy.ant_2">
+            <classpath>
+                <fileset dir="${artifacts.build.dir}/jars" includes="${final.name}" />
+                <fileset dir="${build.dir}/lib" excludes="ant-*.jar" />
+            </classpath>
+        </taskdef>
+    	
+        <ivy2:settings id="upload.settingsId" file="ivysettings-release.xml" />
+        <ivy2:resolve file="${basedir}/build/artifact/ivy.xml" transitive="false" />
+        <ivy2:publish organisation="org.apache.ivy"
                      module="ivy"
                      revision="${build.version}"
                      srcivypattern="${basedir}/build/artifact/ivy.xml"
@@ -487,25 +498,7 @@
             <artifact name="ivy" ext="pom" type="ivy" />
             <artifact name="ivy" ext="jar" type="sources" classifier="sources" />
             <artifact name="ivy" ext="jar" type="javadoc" classifier="javadoc" />
-
-            <!-- The PGP signatures -->
-            <artifact name="ivy" ext="pom.asc" type="asc" />
-            <artifact name="ivy" ext="jar.asc" type="asc" />
-            <artifact name="ivy" ext="jar.asc" type="asc" classifier="sources" />
-            <artifact name="ivy" ext="jar.asc" type="asc" classifier="javadoc" />
-            
-            <!-- The SHA1 checksums -->
-            <artifact name="ivy" ext="pom.sha1" type="sha1" />
-            <artifact name="ivy" ext="jar.sha1" type="sha1" />
-            <artifact name="ivy" ext="jar.sha1" type="sha1" classifier="sources" />
-            <artifact name="ivy" ext="jar.sha1" type="sha1" classifier="javadoc" />
-            
-            <!-- The MD5 checksums -->
-            <artifact name="ivy" ext="pom.md5" type="md5" />
-            <artifact name="ivy" ext="jar.md5" type="md5" />
-            <artifact name="ivy" ext="jar.md5" type="md5" classifier="sources" />
-            <artifact name="ivy" ext="jar.md5" type="md5" classifier="javadoc" />
-        </ivy:publish>
+        </ivy2:publish>
     </target>
 
 	<target name="prepare-snapshot" 

Modified: ant/ivy/core/trunk/doc/settings/resolvers.html
URL: http://svn.apache.org/viewvc/ant/ivy/core/trunk/doc/settings/resolvers.html?rev=991108&r1=991107&r2=991108&view=diff
==============================================================================
--- ant/ivy/core/trunk/doc/settings/resolvers.html (original)
+++ ant/ivy/core/trunk/doc/settings/resolvers.html Tue Aug 31 07:47:06 2010
@@ -169,6 +169,11 @@ By using such a resolver at the beginnin
         <td>No</td>
         <td>Yes</td>
     </tr>
+    <tr><td>signer</td><td>The name of the [[settings/signers detached signature generator]] to use when publishing artifacts. <span class="since">(since 2.2)</span></td>
+        <td>No, by default published artifacts will not get signed by Ivy.</td>
+        <td>No</td>
+        <td>Yes</td>
+    </tr>
 </tbody>
 </table>
 

Modified: ant/ivy/core/trunk/doc/toc.json
URL: http://svn.apache.org/viewvc/ant/ivy/core/trunk/doc/toc.json?rev=991108&r1=991107&r2=991108&view=diff
==============================================================================
--- ant/ivy/core/trunk/doc/toc.json (original)
+++ ant/ivy/core/trunk/doc/toc.json Tue Aug 31 07:47:06 2010
@@ -193,6 +193,13 @@
                             ]
                         },
                         {
+                          "id":"settings/signers",
+                          "title":"signers",
+                          "children": [
+
+                            ]
+                        },
+                        {
                           "id":"settings/lock-strategies",
                           "title":"lock-strategies",
                           "children": [

Modified: ant/ivy/core/trunk/ivy.xml
URL: http://svn.apache.org/viewvc/ant/ivy/core/trunk/ivy.xml?rev=991108&r1=991107&r2=991108&view=diff
==============================================================================
--- ant/ivy/core/trunk/ivy.xml (original)
+++ ant/ivy/core/trunk/ivy.xml Tue Aug 31 07:47:06 2010
@@ -50,6 +50,7 @@
 		<dependency org="oro" name="oro" rev="2.0.8" conf="default,oro->default"/>
 		<dependency org="commons-vfs" name="commons-vfs" rev="1.0" conf="default,vfs->default" />
 		<dependency org="com.jcraft" name="jsch" rev="0.1.31" conf="default,sftp->default" />
+		<dependency org="org.bouncycastle" name="bcpg-jdk14" rev="1.45" conf="default" />
 
 		<!-- Test dependencies -->
 		<dependency org="junit" name="junit" rev="3.8.2" conf="test->default" />

Modified: ant/ivy/core/trunk/ivysettings-release.xml
URL: http://svn.apache.org/viewvc/ant/ivy/core/trunk/ivysettings-release.xml?rev=991108&r1=991107&r2=991108&view=diff
==============================================================================
--- ant/ivy/core/trunk/ivysettings-release.xml (original)
+++ ant/ivy/core/trunk/ivysettings-release.xml Tue Aug 31 07:47:06 2010
@@ -17,8 +17,13 @@
    under the License.    
 -->
 <ivysettings>
-    <property name="upload.url" value="https://repository.apache.org/service/local/staging/deploy/maven2"/>
+    <property name="upload.url" value="https://repository.apache.org/service/local/staging/deploy/maven2" />
+    <property name="pgp.keyId" value="auto" override="false" />
     <credentials host="repository.apache.org" realm="Sonatype Nexus Repository Manager" username="${upload.user}" passwd="${upload.password}"/>
+    
+    <signers>
+        <pgp name="apache-sig" secring="${user.home}/.gnupg/secring.gpg" password="${pgp.password}" keyId="${pgp.keyId}"/>
+    </signers>
 
     <settings defaultResolver="default" />
     <resolvers>
@@ -26,7 +31,7 @@
             <ibiblio name="public" m2compatible="true" />
             <ibiblio name="snapshot" m2compatible="true" root="http://people.apache.org/repo/m2-snapshot-repository" />
         </chain>
-        <url name="nexus" m2compatible="true" checksums="">
+        <url name="nexus" m2compatible="true" signer="apache-sig">
           <artifact pattern="${upload.url}/[organisation]/[module]/[revision]/[artifact]-[revision](-[classifier]).[ext]" />
         </url>
     </resolvers>

Modified: ant/ivy/core/trunk/optional.patterns
URL: http://svn.apache.org/viewvc/ant/ivy/core/trunk/optional.patterns?rev=991108&r1=991107&r2=991108&view=diff
==============================================================================
--- ant/ivy/core/trunk/optional.patterns (original)
+++ ant/ivy/core/trunk/optional.patterns Tue Aug 31 07:47:06 2010
@@ -30,6 +30,7 @@ org/apache/ivy/plugins/resolver/SshResol
 org/apache/ivy/plugins/resolver/VfsResolver.java
 org/apache/ivy/plugins/resolver/VsftpResolver.java
 org/apache/ivy/plugins/resolver/packager/*.java
+org/apache/ivy/plugins/signer/bouncycastle/**/*.java
 org/apache/ivy/util/url/HttpClientHandler.java
 
 #This section defines the resources to copy for ivy-optional.jar

Modified: ant/ivy/core/trunk/src/java/org/apache/ivy/core/settings/IvySettings.java
URL: http://svn.apache.org/viewvc/ant/ivy/core/trunk/src/java/org/apache/ivy/core/settings/IvySettings.java?rev=991108&r1=991107&r2=991108&view=diff
==============================================================================
--- ant/ivy/core/trunk/src/java/org/apache/ivy/core/settings/IvySettings.java (original)
+++ ant/ivy/core/trunk/src/java/org/apache/ivy/core/settings/IvySettings.java Tue Aug 31 07:47:06 2010
@@ -92,6 +92,7 @@ import org.apache.ivy.plugins.resolver.C
 import org.apache.ivy.plugins.resolver.DependencyResolver;
 import org.apache.ivy.plugins.resolver.DualResolver;
 import org.apache.ivy.plugins.resolver.ResolverSettings;
+import org.apache.ivy.plugins.signer.SignatureGenerator;
 import org.apache.ivy.plugins.trigger.Trigger;
 import org.apache.ivy.plugins.version.ChainVersionMatcher;
 import org.apache.ivy.plugins.version.ExactVersionMatcher;
@@ -155,6 +156,9 @@ public class IvySettings implements Sort
 
     // Map (String name -> RepositoryCacheManager)
     private Map repositoryCacheManagers = new HashMap(); 
+    
+    // Map (String name -> SignatureGenerator)
+    private Map signatureGenerators = new HashMap();
 
     // List (Trigger)
     private List triggers = new ArrayList(); 
@@ -684,6 +688,19 @@ public class IvySettings implements Sort
     public void addConfigured(ModuleDescriptorParser parser) {
         ModuleDescriptorParserRegistry.getInstance().addParser(parser);
     }
+    
+    public void addConfigured(SignatureGenerator generator) {
+        addSignatureGenerator(generator);
+    }
+    
+    public void addSignatureGenerator(SignatureGenerator generator) {
+        init(generator);
+        signatureGenerators.put(generator.getName(), generator);
+    }
+    
+    public SignatureGenerator getSignatureGenerator(String name) {
+        return (SignatureGenerator) signatureGenerators.get(name);
+    }
 
     public void addResolver(DependencyResolver resolver) {
         if (resolver == null) {

Modified: ant/ivy/core/trunk/src/java/org/apache/ivy/core/settings/XmlSettingsParser.java
URL: http://svn.apache.org/viewvc/ant/ivy/core/trunk/src/java/org/apache/ivy/core/settings/XmlSettingsParser.java?rev=991108&r1=991107&r2=991108&view=diff
==============================================================================
--- ant/ivy/core/trunk/src/java/org/apache/ivy/core/settings/XmlSettingsParser.java (original)
+++ ant/ivy/core/trunk/src/java/org/apache/ivy/core/settings/XmlSettingsParser.java Tue Aug 31 07:47:06 2010
@@ -107,7 +107,7 @@ public class XmlSettingsParser extends D
     private List configuratorTags = Arrays.asList(new String[] {"resolvers", "namespaces",
             "parsers", "latest-strategies", "conflict-managers", "outputters", "version-matchers",
             "statuses", "circular-dependency-strategies", "triggers", "lock-strategies",
-            "caches"});
+            "caches", "signers"});
 
     private IvySettings ivy;
 

Modified: ant/ivy/core/trunk/src/java/org/apache/ivy/core/settings/typedef.properties
URL: http://svn.apache.org/viewvc/ant/ivy/core/trunk/src/java/org/apache/ivy/core/settings/typedef.properties?rev=991108&r1=991107&r2=991108&view=diff
==============================================================================
--- ant/ivy/core/trunk/src/java/org/apache/ivy/core/settings/typedef.properties (original)
+++ ant/ivy/core/trunk/src/java/org/apache/ivy/core/settings/typedef.properties Tue Aug 31 07:47:06 2010
@@ -54,4 +54,6 @@ ant-build		= org.apache.ivy.ant.AntBuild
 ant-call		= org.apache.ivy.ant.AntCallTrigger
 log		        = org.apache.ivy.plugins.trigger.LogTrigger
 
-cache			= org.apache.ivy.core.cache.DefaultRepositoryCacheManager
\ No newline at end of file
+cache			= org.apache.ivy.core.cache.DefaultRepositoryCacheManager
+
+pgp             = org.apache.ivy.plugins.signer.bouncycastle.OpenPGPSignatureGenerator
\ No newline at end of file

Modified: ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/RepositoryResolver.java
URL: http://svn.apache.org/viewvc/ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/RepositoryResolver.java?rev=991108&r1=991107&r2=991108&view=diff
==============================================================================
--- ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/RepositoryResolver.java (original)
+++ ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/RepositoryResolver.java Tue Aug 31 07:47:06 2010
@@ -45,6 +45,7 @@ import org.apache.ivy.plugins.repository
 import org.apache.ivy.plugins.resolver.util.ResolvedResource;
 import org.apache.ivy.plugins.resolver.util.ResolverHelper;
 import org.apache.ivy.plugins.resolver.util.ResourceMDParser;
+import org.apache.ivy.plugins.signer.SignatureGenerator;
 import org.apache.ivy.plugins.version.VersionMatcher;
 import org.apache.ivy.util.ChecksumHelper;
 import org.apache.ivy.util.FileUtil;
@@ -58,6 +59,8 @@ public class RepositoryResolver extends 
     private Repository repository;
 
     private Boolean alwaysCheckExactRevision = null;
+    
+    private String signerName = null;
 
     public RepositoryResolver() {
     }
@@ -76,6 +79,10 @@ public class RepositoryResolver extends 
             ((AbstractRepository) repository).setName(name);
         }
     }
+    
+    public void setSigner(String signerName) {
+        this.signerName = signerName;
+    }
 
     protected ResolvedResource findResourceUsingPattern(ModuleRevisionId mrid, String pattern,
             Artifact artifact, ResourceMDParser rmdparser, Date date) {
@@ -223,11 +230,15 @@ public class RepositoryResolver extends 
                 throw new IllegalArgumentException("Unknown checksum algorithm: " + checksums[i]);
             }
         }
-        
+
         repository.put(artifact, src, dest, overwrite);
         for (int i = 0; i < checksums.length; i++) {
             putChecksum(artifact, src, dest, overwrite, checksums[i]);
         }
+
+        if (signerName != null) {
+            putSignature(artifact, src, dest, overwrite);
+        }
     }
 
     protected void putChecksum(Artifact artifact, File src, String dest, boolean overwrite,
@@ -243,6 +254,25 @@ public class RepositoryResolver extends 
         }
     }
 
+    protected void putSignature(Artifact artifact, File src, String dest, boolean overwrite) throws IOException {
+        SignatureGenerator gen = getSettings().getSignatureGenerator(signerName);
+        if (gen == null) {
+            throw new IllegalArgumentException("Couldn't sign the artifacts! " +
+                    "Unknown signer name: '" + signerName + "'");
+        }
+
+        File tempFile = File.createTempFile("ivytemp", gen.getExtension());
+
+        try {
+            gen.sign(src, tempFile);
+            repository.put(DefaultArtifact.cloneWithAnotherTypeAndExt(artifact, 
+                    gen.getExtension(), artifact.getExt() + "." + gen.getExtension()), 
+                    tempFile, dest + "." + gen.getExtension(), overwrite);
+        } finally {
+            tempFile.delete();
+        }
+    }
+
     public DownloadReport download(Artifact[] artifacts, DownloadOptions options) {
         EventManager eventManager = getEventManager();
         try {

Modified: ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/ResolverSettings.java
URL: http://svn.apache.org/viewvc/ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/ResolverSettings.java?rev=991108&r1=991107&r2=991108&view=diff
==============================================================================
--- ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/ResolverSettings.java (original)
+++ ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/resolver/ResolverSettings.java Tue Aug 31 07:47:06 2010
@@ -24,6 +24,7 @@ import org.apache.ivy.core.module.id.Mod
 import org.apache.ivy.plugins.latest.LatestStrategy;
 import org.apache.ivy.plugins.namespace.Namespace;
 import org.apache.ivy.plugins.parser.ParserSettings;
+import org.apache.ivy.plugins.signer.SignatureGenerator;
 import org.apache.ivy.plugins.version.VersionMatcher;
 
 public interface ResolverSettings extends ParserSettings {
@@ -51,5 +52,7 @@ public interface ResolverSettings extend
     String getResolveMode(ModuleId moduleId);
 
     void filterIgnore(Collection names);
+    
+    SignatureGenerator getSignatureGenerator(String name);
 
 }

Added: ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/signer/SignatureGenerator.java
URL: http://svn.apache.org/viewvc/ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/signer/SignatureGenerator.java?rev=991108&view=auto
==============================================================================
--- ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/signer/SignatureGenerator.java (added)
+++ ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/signer/SignatureGenerator.java Tue Aug 31 07:47:06 2010
@@ -0,0 +1,31 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.ivy.plugins.signer;
+
+import java.io.File;
+import java.io.IOException;
+
+public interface SignatureGenerator {
+    
+    String getName();
+    
+    void sign(File src, File dest) throws IOException;
+    
+    String getExtension();
+
+}

Added: ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/signer/bouncycastle/OpenPGPSignatureGenerator.java
URL: http://svn.apache.org/viewvc/ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/signer/bouncycastle/OpenPGPSignatureGenerator.java?rev=991108&view=auto
==============================================================================
--- ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/signer/bouncycastle/OpenPGPSignatureGenerator.java (added)
+++ ant/ivy/core/trunk/src/java/org/apache/ivy/plugins/signer/bouncycastle/OpenPGPSignatureGenerator.java Tue Aug 31 07:47:06 2010
@@ -0,0 +1,176 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+package org.apache.ivy.plugins.signer.bouncycastle;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Security;
+import java.security.SignatureException;
+import java.util.Iterator;
+
+import org.apache.ivy.plugins.signer.SignatureGenerator;
+import org.bouncycastle.bcpg.ArmoredOutputStream;
+import org.bouncycastle.bcpg.BCPGOutputStream;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.openpgp.PGPException;
+import org.bouncycastle.openpgp.PGPPrivateKey;
+import org.bouncycastle.openpgp.PGPSecretKey;
+import org.bouncycastle.openpgp.PGPSecretKeyRing;
+import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
+import org.bouncycastle.openpgp.PGPSignature;
+import org.bouncycastle.openpgp.PGPSignatureGenerator;
+import org.bouncycastle.openpgp.PGPUtil;
+
+public class OpenPGPSignatureGenerator implements SignatureGenerator {
+    
+    private static final long MASK = 0xFFFFFFFFL;
+
+    static {
+        Security.addProvider(new BouncyCastleProvider());
+    }
+
+    private String name;
+    private String secring;
+    private String password;
+    private String keyId;    
+    
+    private PGPSecretKey pgpSec;
+    
+    public String getName() {
+        return name;
+    }
+    
+    public void setName(String name) {
+        this.name = name;
+    }
+    
+    public String getExtension() {
+        return "asc";
+    }
+    
+    public void setPassword(String password) {
+        this.password = password;
+    }
+    
+    public void setSecring(String secring) {
+        this.secring = secring;
+    }
+    
+    public void setKeyId(String keyId) {
+        if (!"auto".equals(keyId)) {
+            this.keyId = keyId;
+        }
+    }
+    
+    public void sign(File src, File dest) throws IOException {
+        OutputStream out = null;
+        InputStream in = null;
+        InputStream keyIn = null;
+        
+        try {
+            if (secring == null) {
+                secring = System.getProperty("user.home") + "/.gnupg/secring.gpg";
+            }
+            
+            if (pgpSec == null) {
+                keyIn = new FileInputStream(secring);
+                pgpSec = readSecretKey(keyIn);
+            }
+            
+            PGPPrivateKey pgpPrivKey = pgpSec.extractPrivateKey(password.toCharArray(), BouncyCastleProvider.PROVIDER_NAME);        
+            PGPSignatureGenerator sGen = new PGPSignatureGenerator(pgpSec.getPublicKey().getAlgorithm(), PGPUtil.SHA1, BouncyCastleProvider.PROVIDER_NAME);
+            sGen.initSign(PGPSignature.BINARY_DOCUMENT, pgpPrivKey);
+    
+            in = new FileInputStream(src);
+            out = new BCPGOutputStream(new ArmoredOutputStream(new FileOutputStream(dest)));
+            
+            int ch = 0;
+            while ((ch = in.read()) >= 0) {
+                sGen.update((byte) ch);
+            }
+            
+            sGen.generate().encode(out);
+        } catch (SignatureException e) {
+            IOException ioexc = new IOException();
+            ioexc.initCause(e);
+            throw ioexc;
+        } catch (PGPException e) {
+            IOException ioexc = new IOException();
+            ioexc.initCause(e);
+            throw ioexc;
+        } catch (NoSuchAlgorithmException e) {
+            IOException ioexc = new IOException();
+            ioexc.initCause(e);
+            throw ioexc;
+        } catch (NoSuchProviderException e) {
+            IOException ioexc = new IOException();
+            ioexc.initCause(e);
+            throw ioexc;
+        } finally {
+            if (out != null) {
+                try {
+                    out.close();
+                } catch (IOException e) {}
+            }
+            if (in != null) {
+                try {
+                    in.close();
+                } catch (IOException e) {}
+            }
+            if (keyIn != null) {
+                try {
+                    keyIn.close();
+                } catch (IOException e) {}
+            }
+        }
+    }
+
+    private PGPSecretKey readSecretKey(InputStream in) throws IOException, PGPException {
+        in = PGPUtil.getDecoderStream(in);
+        PGPSecretKeyRingCollection pgpSec = new PGPSecretKeyRingCollection(in);
+
+        PGPSecretKey key = null; 
+        for (Iterator it = pgpSec.getKeyRings(); key == null && it.hasNext(); ) {
+            PGPSecretKeyRing kRing = (PGPSecretKeyRing) it.next();   
+            
+            for (Iterator it2 = kRing.getSecretKeys(); key == null && it2.hasNext(); ) {
+                PGPSecretKey k = (PGPSecretKey) it2.next();
+                if ((keyId == null) && k.isSigningKey()) {
+                    key = k;
+                }
+                if ((keyId != null) && (Long.valueOf(keyId, 16).longValue() == (k.getKeyID() & MASK))) {
+                    key = k;
+                }
+            }
+        }
+        
+        if (key == null) {
+            throw new IllegalArgumentException("Can't find encryption key" + 
+                (keyId != null ? " '" + keyId + "' " : " ") + "in key ring.");
+        }
+        
+        return key;
+    }
+
+}