Skip to content

Commit

Permalink
NEW: Ivy can now generate OpenPGP compatible ASCII armored detached s…
Browse files Browse the repository at this point in the history
…ignatures when publishing artifacts.

git-svn-id: https://svn.apache.org/repos/asf/ant/ivy/core/trunk@991108 13f79535-47bb-0310-9956-ffa450edef68
  • Loading branch information
maartenc committed Aug 31, 2010
1 parent 0cd41d8 commit a53e942
Show file tree
Hide file tree
Showing 15 changed files with 304 additions and 30 deletions.
1 change: 1 addition & 0 deletions CHANGES.txt
Expand Up @@ -115,6 +115,7 @@ for detailed view of each issue, please consult http://issues.apache.org/jira/br
- 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)
Expand Down
6 changes: 4 additions & 2 deletions README
Expand Up @@ -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>.


39 changes: 16 additions & 23 deletions build-release.xml
Expand Up @@ -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"/>
Expand Down Expand Up @@ -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"
Expand All @@ -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"
Expand Down
5 changes: 5 additions & 0 deletions doc/settings/resolvers.html
Expand Up @@ -169,6 +169,11 @@ <h2>Attributes</h2>
<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>

Expand Down
7 changes: 7 additions & 0 deletions doc/toc.json
Expand Up @@ -192,6 +192,13 @@

]
},
{
"id":"settings/signers",
"title":"signers",
"children": [

]
},
{
"id":"settings/lock-strategies",
"title":"lock-strategies",
Expand Down
1 change: 1 addition & 0 deletions ivy.xml
Expand Up @@ -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" />
Expand Down
9 changes: 7 additions & 2 deletions ivysettings-release.xml
Expand Up @@ -17,16 +17,21 @@
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>
<chain name="default">
<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>
Expand Down
1 change: 1 addition & 0 deletions optional.patterns
Expand Up @@ -30,6 +30,7 @@ org/apache/ivy/plugins/resolver/SshResolver.java
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
Expand Down
17 changes: 17 additions & 0 deletions src/java/org/apache/ivy/core/settings/IvySettings.java
Expand Up @@ -92,6 +92,7 @@
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;
Expand Down Expand Up @@ -155,6 +156,9 @@ public class IvySettings implements SortEngineSettings, PublishEngineSettings, P

// 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();
Expand Down Expand Up @@ -684,6 +688,19 @@ public void addConfigured(DependencyResolver resolver) {
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) {
Expand Down
Expand Up @@ -107,7 +107,7 @@ public Object clone() {
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;

Expand Down
4 changes: 3 additions & 1 deletion src/java/org/apache/ivy/core/settings/typedef.properties
Expand Up @@ -54,4 +54,6 @@ ant-build = org.apache.ivy.ant.AntBuildTrigger
ant-call = org.apache.ivy.ant.AntCallTrigger
log = org.apache.ivy.plugins.trigger.LogTrigger

cache = org.apache.ivy.core.cache.DefaultRepositoryCacheManager
cache = org.apache.ivy.core.cache.DefaultRepositoryCacheManager

pgp = org.apache.ivy.plugins.signer.bouncycastle.OpenPGPSignatureGenerator
32 changes: 31 additions & 1 deletion src/java/org/apache/ivy/plugins/resolver/RepositoryResolver.java
Expand Up @@ -45,6 +45,7 @@
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;
Expand All @@ -58,6 +59,8 @@ public class RepositoryResolver extends AbstractPatternsBasedResolver {
private Repository repository;

private Boolean alwaysCheckExactRevision = null;

private String signerName = null;

public RepositoryResolver() {
}
Expand All @@ -76,6 +79,10 @@ public void setName(String name) {
((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) {
Expand Down Expand Up @@ -223,11 +230,15 @@ protected void put(Artifact artifact, File src, String dest, boolean overwrite)
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,
Expand All @@ -243,6 +254,25 @@ protected void putChecksum(Artifact artifact, File src, String dest, boolean ove
}
}

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 {
Expand Down
Expand Up @@ -24,6 +24,7 @@
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 {
Expand Down Expand Up @@ -51,5 +52,7 @@ public interface ResolverSettings extends ParserSettings {
String getResolveMode(ModuleId moduleId);

void filterIgnore(Collection names);

SignatureGenerator getSignatureGenerator(String name);

}
31 changes: 31 additions & 0 deletions src/java/org/apache/ivy/plugins/signer/SignatureGenerator.java
@@ -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();

}

0 comments on commit a53e942

Please sign in to comment.