git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@278052 13f79535-47bb-0310-9956-ffa450edef68master
@@ -24,6 +24,13 @@ | |||
<signjar alias="testonly" keystore="testkeystore" | |||
storepass="apacheant"/> | |||
</presetdef> | |||
<presetdef name="verify-base"> | |||
<verifyjar keystore="testkeystore" | |||
storepass="apacheant"/> | |||
</presetdef> | |||
<presetdef name="sign"> | |||
<sign-base jar="${test.jar}" /> | |||
@@ -174,5 +181,24 @@ | |||
<sign tsaurl="http://localhost:0/" /> | |||
</target> | |||
<target name="testVerifyJar" depends="basic"> | |||
<verify-base jar="${test.jar}"/> | |||
</target> | |||
<target name="testVerifyJarUnsigned" depends="jar"> | |||
<verify-base jar="${test.jar}"/> | |||
</target> | |||
<target name="testVerifyFileset" depends="basic"> | |||
<verify-base > | |||
<fileset file="${test.jar}" /> | |||
</verify-base> | |||
</target> | |||
<target name="testVerifyNoArgs"> | |||
<verify-base /> | |||
</target> | |||
</project> | |||
@@ -0,0 +1,277 @@ | |||
/* | |||
* Copyright 2000-2005 The Apache Software Foundation | |||
* | |||
* Licensed 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.tools.ant.taskdefs; | |||
import org.apache.tools.ant.Task; | |||
import org.apache.tools.ant.util.JavaEnvUtils; | |||
import org.apache.tools.ant.types.FileSet; | |||
import org.apache.tools.ant.types.RedirectorElement; | |||
import java.io.File; | |||
import java.util.Vector; | |||
/** | |||
* This is factored out from {@link SignJar}; a base class that can be used | |||
* for both signing and verifying JAR files using jarsigner | |||
*/ | |||
public abstract class AbstractJarSignerTask extends Task { | |||
/** | |||
* The name of the jar file. | |||
*/ | |||
protected File jar; | |||
/** | |||
* The alias of signer. | |||
*/ | |||
protected String alias; | |||
/** | |||
* The url or path of keystore file. | |||
*/ | |||
protected String keystore; | |||
/** | |||
* password for the store | |||
*/ | |||
protected String storepass; | |||
/** | |||
* type of store,-storetype param | |||
*/ | |||
protected String storetype; | |||
/** | |||
* password for the key in the store | |||
*/ | |||
protected String keypass; | |||
/** | |||
* verbose output | |||
*/ | |||
protected boolean verbose; | |||
/** | |||
* The maximum amount of memory to use for Jar signer | |||
*/ | |||
protected String maxMemory; | |||
/** | |||
* the filesets of the jars to sign | |||
*/ | |||
protected Vector filesets = new Vector(); | |||
/** | |||
* name of JDK program we are looking for | |||
*/ | |||
protected static final String JARSIGNER_COMMAND = "jarsigner"; | |||
/** | |||
* redirector used to talk to the jarsigner program | |||
*/ | |||
private RedirectorElement redirector; | |||
/** | |||
* error string for unit test verification: {@value} | |||
*/ | |||
public static final String ERROR_NO_SOURCE = "jar must be set through jar attribute " | |||
+ "or nested filesets"; | |||
/** | |||
* Set the maximum memory to be used by the jarsigner process | |||
* | |||
* @param max a string indicating the maximum memory according to the JVM | |||
* conventions (e.g. 128m is 128 Megabytes) | |||
*/ | |||
public void setMaxmemory(String max) { | |||
maxMemory = max; | |||
} | |||
/** | |||
* the jar file to sign; required | |||
* | |||
* @param jar the jar file to sign | |||
*/ | |||
public void setJar(final File jar) { | |||
this.jar = jar; | |||
} | |||
/** | |||
* the alias to sign under; required | |||
* | |||
* @param alias the alias to sign under | |||
*/ | |||
public void setAlias(final String alias) { | |||
this.alias = alias; | |||
} | |||
/** | |||
* keystore location; required | |||
* | |||
* @param keystore the keystore location | |||
*/ | |||
public void setKeystore(final String keystore) { | |||
this.keystore = keystore; | |||
} | |||
/** | |||
* password for keystore integrity; required | |||
* | |||
* @param storepass the password for the keystore | |||
*/ | |||
public void setStorepass(final String storepass) { | |||
this.storepass = storepass; | |||
} | |||
/** | |||
* keystore type; optional | |||
* | |||
* @param storetype the keystore type | |||
*/ | |||
public void setStoretype(final String storetype) { | |||
this.storetype = storetype; | |||
} | |||
/** | |||
* password for private key (if different); optional | |||
* | |||
* @param keypass the password for the key (if different) | |||
*/ | |||
public void setKeypass(final String keypass) { | |||
this.keypass = keypass; | |||
} | |||
/** | |||
* Enable verbose output when signing ; optional: default false | |||
* | |||
* @param verbose if true enable verbose output | |||
*/ | |||
public void setVerbose(final boolean verbose) { | |||
this.verbose = verbose; | |||
} | |||
/** | |||
* Adds a set of files to sign | |||
* | |||
* @param set a set of files to sign | |||
* @since Ant 1.4 | |||
*/ | |||
public void addFileset(final FileSet set) { | |||
filesets.addElement(set); | |||
} | |||
/** | |||
* init processing logic; this is retained through our execution(s) | |||
*/ | |||
protected void beginExecution() { | |||
redirector = createRedirector(); | |||
} | |||
/** | |||
* any cleanup logic | |||
*/ | |||
protected void endExecution() { | |||
redirector = null; | |||
} | |||
/** | |||
* Create the redirector to use, if any. | |||
* | |||
* @return a configured RedirectorElement. | |||
*/ | |||
private RedirectorElement createRedirector() { | |||
RedirectorElement result = new RedirectorElement(); | |||
StringBuffer input = new StringBuffer(storepass).append('\n'); | |||
if (keypass != null) { | |||
input.append(keypass).append('\n'); | |||
} | |||
result.setInputString(input.toString()); | |||
result.setLogInputString(false); | |||
return result; | |||
} | |||
/** | |||
* these are options common to signing and verifying | |||
* @param cmd command to configure | |||
*/ | |||
protected void setCommonOptions(final ExecTask cmd) { | |||
if (maxMemory != null) { | |||
cmd.createArg().setValue("-J-Xmx" + maxMemory); | |||
} | |||
if (verbose) { | |||
cmd.createArg().setValue("-verbose"); | |||
} | |||
} | |||
/** | |||
* bind to a keystore if the attributes are there | |||
* @param cmd command to configure | |||
*/ | |||
protected void bindToKeystore(final ExecTask cmd) { | |||
if (null != keystore) { | |||
// is the keystore a file | |||
cmd.createArg().setValue("-keystore"); | |||
String location; | |||
File keystoreFile = getProject().resolveFile(keystore); | |||
if (keystoreFile.exists()) { | |||
location = keystoreFile.getPath(); | |||
} else { | |||
// must be a URL - just pass as is | |||
location = keystore; | |||
} | |||
cmd.createArg().setValue(location); | |||
} | |||
if (null != storetype) { | |||
cmd.createArg().setValue("-storetype"); | |||
cmd.createArg().setValue(storetype); | |||
} | |||
} | |||
/** | |||
* create the jarsigner executable task | |||
* @return a task set up with the executable of jarsigner, failonerror=true | |||
* and bound to our redirector | |||
*/ | |||
protected ExecTask createJarSigner() { | |||
final ExecTask cmd = new ExecTask(this); | |||
cmd.setExecutable(JavaEnvUtils.getJdkExecutable(JARSIGNER_COMMAND)); | |||
cmd.setTaskType(JARSIGNER_COMMAND); | |||
cmd.setFailonerror(true); | |||
cmd.addConfiguredRedirector(redirector); | |||
return cmd; | |||
} | |||
/** | |||
* clone our filesets vector, and patch in the jar attribute as a new | |||
* fileset, if is defined | |||
* @return a vector of FileSet instances | |||
*/ | |||
protected Vector createUnifiedSources() { | |||
Vector sources = (Vector)filesets.clone(); | |||
if (jar != null) { | |||
//we create a fileset with the source file. | |||
//this lets us combine our logic for handling output directories, | |||
//mapping etc. | |||
FileSet sourceJar = new FileSet(); | |||
sourceJar.setFile(jar); | |||
sourceJar.setDir(jar.getParentFile()); | |||
sources.add(sourceJar); | |||
} | |||
return sources; | |||
} | |||
/** | |||
* add a value argument to a command | |||
* @param cmd command to manipulate | |||
* @param value value to add | |||
*/ | |||
protected void addValue(final ExecTask cmd, String value) { | |||
cmd.createArg().setValue(value); | |||
} | |||
} |
@@ -48,40 +48,10 @@ import org.apache.tools.ant.util.FileNameMapper; | |||
* @ant.task category="java" | |||
* @since Ant 1.1 | |||
*/ | |||
public class SignJar extends Task { | |||
public class SignJar extends AbstractJarSignerTask { | |||
private static final FileUtils FILE_UTILS = FileUtils.getFileUtils(); | |||
/** | |||
* The name of the jar file. | |||
*/ | |||
protected File jar; | |||
/** | |||
* The alias of signer. | |||
*/ | |||
protected String alias; | |||
/** | |||
* The url or path of keystore file. | |||
*/ | |||
private String keystore; | |||
/** | |||
* password for the store | |||
*/ | |||
protected String storepass; | |||
/** | |||
* type of store,-storetype param | |||
*/ | |||
protected String storetype; | |||
/** | |||
* password for the key in the store | |||
*/ | |||
protected String keypass; | |||
/** | |||
* name to a signature file | |||
*/ | |||
@@ -92,11 +62,6 @@ public class SignJar extends Task { | |||
*/ | |||
protected File signedjar; | |||
/** | |||
* verbose output | |||
*/ | |||
protected boolean verbose; | |||
/** | |||
* flag for internal sf signing | |||
*/ | |||
@@ -112,21 +77,6 @@ public class SignJar extends Task { | |||
*/ | |||
private boolean preserveLastModified; | |||
/** | |||
* redirector used to talk to the jarsigner program | |||
*/ | |||
private RedirectorElement redirector; | |||
/** | |||
* The maximum amount of memory to use for Jar signer | |||
*/ | |||
private String maxMemory; | |||
/** | |||
* the filesets of the jars to sign | |||
*/ | |||
protected Vector filesets = new Vector(); | |||
/** | |||
* Whether to assume a jar which has an appropriate .SF file in is already | |||
* signed. | |||
@@ -166,11 +116,6 @@ public class SignJar extends Task { | |||
* error string for unit test verification {@value} | |||
*/ | |||
public static final String ERROR_SIGNEDJAR_AND_FILESETS = "You cannot specify the signed JAR when using filesets"; | |||
/** | |||
* error string for unit test verification: {@value} | |||
*/ | |||
public static final String WARN_JAR_AND_FILESET = "nested filesets will be ignored if the jar attribute has" | |||
+ " been specified."; | |||
/** | |||
* error string for unit test verification: {@value} | |||
*/ | |||
@@ -179,11 +124,6 @@ public class SignJar extends Task { | |||
* error string for unit test verification: {@value} | |||
*/ | |||
public static final String ERROR_MAPPER_WITHOUT_DEST = "The destDir attribute is required if a mapper is set"; | |||
/** | |||
* error string for unit test verification: {@value} | |||
*/ | |||
public static final String ERROR_NO_SOURCE = "jar must be set through jar attribute " | |||
+ "or nested filesets"; | |||
/** | |||
* error string for unit test verification: {@value} | |||
*/ | |||
@@ -193,75 +133,6 @@ public class SignJar extends Task { | |||
*/ | |||
public static final String ERROR_NO_STOREPASS = "storepass attribute must be set"; | |||
/** | |||
* name of JDK program we are looking for | |||
*/ | |||
protected static final String JARSIGNER_COMMAND = "jarsigner"; | |||
/** | |||
* Set the maximum memory to be used by the jarsigner process | |||
* | |||
* @param max a string indicating the maximum memory according to the JVM | |||
* conventions (e.g. 128m is 128 Megabytes) | |||
*/ | |||
public void setMaxmemory(String max) { | |||
maxMemory = max; | |||
} | |||
/** | |||
* the jar file to sign; required | |||
* | |||
* @param jar the jar file to sign | |||
*/ | |||
public void setJar(final File jar) { | |||
this.jar = jar; | |||
} | |||
/** | |||
* the alias to sign under; required | |||
* | |||
* @param alias the alias to sign under | |||
*/ | |||
public void setAlias(final String alias) { | |||
this.alias = alias; | |||
} | |||
/** | |||
* keystore location; required | |||
* | |||
* @param keystore the keystore location | |||
*/ | |||
public void setKeystore(final String keystore) { | |||
this.keystore = keystore; | |||
} | |||
/** | |||
* password for keystore integrity; required | |||
* | |||
* @param storepass the password for the keystore | |||
*/ | |||
public void setStorepass(final String storepass) { | |||
this.storepass = storepass; | |||
} | |||
/** | |||
* keystore type; optional | |||
* | |||
* @param storetype the keystore type | |||
*/ | |||
public void setStoretype(final String storetype) { | |||
this.storetype = storetype; | |||
} | |||
/** | |||
* password for private key (if different); optional | |||
* | |||
* @param keypass the password for the key (if different) | |||
*/ | |||
public void setKeypass(final String keypass) { | |||
this.keypass = keypass; | |||
} | |||
/** | |||
* name of .SF/.DSA file; optional | |||
* | |||
@@ -280,15 +151,6 @@ public class SignJar extends Task { | |||
this.signedjar = signedjar; | |||
} | |||
/** | |||
* Enable verbose output when signing ; optional: default false | |||
* | |||
* @param verbose if true enable verbose output | |||
*/ | |||
public void setVerbose(final boolean verbose) { | |||
this.verbose = verbose; | |||
} | |||
/** | |||
* Flag to include the .SF file inside the signature; optional; default | |||
* false | |||
@@ -318,16 +180,6 @@ public class SignJar extends Task { | |||
this.lazy = lazy; | |||
} | |||
/** | |||
* Adds a set of files to sign | |||
* | |||
* @param set a set of files to sign | |||
* @since Ant 1.4 | |||
*/ | |||
public void addFileset(final FileSet set) { | |||
filesets.addElement(set); | |||
} | |||
/** | |||
* Optionally sets the output directory to be used. | |||
* | |||
@@ -436,87 +288,66 @@ public class SignJar extends Task { | |||
throw new BuildException(ERROR_MAPPER_WITHOUT_DEST); | |||
} | |||
//init processing logic; this is retained through our execution(s) | |||
redirector = createRedirector(); | |||
beginExecution(); | |||
//special case single jar handling with signedjar attribute set | |||
if (hasJar && hasSignedJar) { | |||
// single jar processing | |||
signOneJar(jar, signedjar); | |||
//return here. | |||
return; | |||
} | |||
try { | |||
//special case single jar handling with signedjar attribute set | |||
if (hasJar && hasSignedJar) { | |||
// single jar processing | |||
signOneJar(jar, signedjar); | |||
//return here. | |||
return; | |||
} | |||
//the rest of the method treats single jar like | |||
//a nested fileset with one file | |||
if (hasJar) { | |||
//we create a fileset with the source file. | |||
//this lets us combine our logic for handling output directories, | |||
//mapping etc. | |||
FileSet sourceJar = new FileSet(); | |||
sourceJar.setFile(jar); | |||
sourceJar.setDir(jar.getParentFile()); | |||
addFileset(sourceJar); | |||
} | |||
//set up our mapping policy | |||
FileNameMapper destMapper; | |||
if (hasMapper) { | |||
destMapper = mapper; | |||
} else { | |||
//no mapper? use the identity policy | |||
destMapper = new IdentityMapper(); | |||
} | |||
//the rest of the method treats single jar like | |||
//a nested fileset with one file | |||
Vector sources = createUnifiedSources(); | |||
//set up our mapping policy | |||
FileNameMapper destMapper; | |||
if (hasMapper) { | |||
destMapper = mapper; | |||
} else { | |||
//no mapper? use the identity policy | |||
destMapper = new IdentityMapper(); | |||
} | |||
//at this point the filesets are set up with lists of files, | |||
//and the mapper is ready to map from source dirs to dest files | |||
//now we iterate through every JAR giving source and dest names | |||
// deal with the filesets | |||
for (int i = 0; i < filesets.size(); i++) { | |||
FileSet fs = (FileSet) filesets.elementAt(i); | |||
//get all included files in a fileset | |||
DirectoryScanner ds = fs.getDirectoryScanner(getProject()); | |||
String[] jarFiles = ds.getIncludedFiles(); | |||
File baseDir = fs.getDir(getProject()); | |||
//calculate our destination directory; it is either the destDir | |||
//attribute, or the base dir of the fileset (for in situ updates) | |||
File toDir = hasDestDir ? destDir : baseDir; | |||
//loop through all jars in the fileset | |||
for (int j = 0; j < jarFiles.length; j++) { | |||
String jarFile = jarFiles[j]; | |||
//determine the destination filename via the mapper | |||
String[] destFilenames = destMapper.mapFileName(jarFile); | |||
if (destFilenames == null || destFilenames.length != 1) { | |||
//we only like simple mappers. | |||
throw new BuildException(ERROR_BAD_MAP + jarFile); | |||
//at this point the filesets are set up with lists of files, | |||
//and the mapper is ready to map from source dirs to dest files | |||
//now we iterate through every JAR giving source and dest names | |||
// deal with the filesets | |||
for (int i = 0; i < sources.size(); i++) { | |||
FileSet fs = (FileSet) sources.elementAt(i); | |||
//get all included files in a fileset | |||
DirectoryScanner ds = fs.getDirectoryScanner(getProject()); | |||
String[] jarFiles = ds.getIncludedFiles(); | |||
File baseDir = fs.getDir(getProject()); | |||
//calculate our destination directory; it is either the destDir | |||
//attribute, or the base dir of the fileset (for in situ updates) | |||
File toDir = hasDestDir ? destDir : baseDir; | |||
//loop through all jars in the fileset | |||
for (int j = 0; j < jarFiles.length; j++) { | |||
String jarFile = jarFiles[j]; | |||
//determine the destination filename via the mapper | |||
String[] destFilenames = destMapper.mapFileName(jarFile); | |||
if (destFilenames == null || destFilenames.length != 1) { | |||
//we only like simple mappers. | |||
throw new BuildException(ERROR_BAD_MAP + jarFile); | |||
} | |||
File destFile = new File(toDir, destFilenames[0]); | |||
File jarSource = new File(baseDir, jarFile); | |||
signOneJar(jarSource, destFile); | |||
} | |||
File destFile = new File(toDir, destFilenames[0]); | |||
File jarSource = new File(baseDir, jarFile); | |||
signOneJar(jarSource, destFile); | |||
} | |||
} finally { | |||
endExecution(); | |||
} | |||
} | |||
/** | |||
* Create the redirector to use, if any. | |||
* | |||
* @return a configured RedirectorElement. | |||
*/ | |||
private RedirectorElement createRedirector() { | |||
RedirectorElement result = new RedirectorElement(); | |||
StringBuffer input = new StringBuffer(storepass).append('\n'); | |||
if (keypass != null) { | |||
input.append(keypass).append('\n'); | |||
} | |||
result.setInputString(input.toString()); | |||
result.setLogInputString(false); | |||
return result; | |||
} | |||
/** | |||
* Sign one jar. | |||
* <p/> | |||
@@ -540,71 +371,47 @@ public class SignJar extends Task { | |||
} | |||
long lastModified = jarSource.lastModified(); | |||
final ExecTask cmd = new ExecTask(this); | |||
cmd.setExecutable(JavaEnvUtils.getJdkExecutable(JARSIGNER_COMMAND)); | |||
cmd.setTaskType(JARSIGNER_COMMAND); | |||
final ExecTask cmd = createJarSigner(); | |||
if (maxMemory != null) { | |||
cmd.createArg().setValue("-J-Xmx" + maxMemory); | |||
} | |||
setCommonOptions(cmd); | |||
if (null != keystore) { | |||
// is the keystore a file | |||
cmd.createArg().setValue("-keystore"); | |||
String location; | |||
File keystoreFile = getProject().resolveFile(keystore); | |||
if (keystoreFile.exists()) { | |||
location = keystoreFile.getPath(); | |||
} else { | |||
// must be a URL - just pass as is | |||
location = keystore; | |||
} | |||
cmd.createArg().setValue(location); | |||
} | |||
if (null != storetype) { | |||
cmd.createArg().setValue("-storetype"); | |||
cmd.createArg().setValue(storetype); | |||
} | |||
bindToKeystore(cmd); | |||
if (null != sigfile) { | |||
cmd.createArg().setValue("-sigfile"); | |||
cmd.createArg().setValue(sigfile); | |||
addValue(cmd, "-sigfile"); | |||
String value = this.sigfile; | |||
addValue(cmd, value); | |||
} | |||
//DO NOT SET THE -signedjar OPTION if source==dest | |||
//unless you like fielding hotspot crash reports | |||
if (null != target && !jarSource.equals(target)) { | |||
cmd.createArg().setValue("-signedjar"); | |||
cmd.createArg().setValue(target.getPath()); | |||
} | |||
if (verbose) { | |||
cmd.createArg().setValue("-verbose"); | |||
addValue(cmd, "-signedjar"); | |||
addValue(cmd, target.getPath()); | |||
} | |||
if (internalsf) { | |||
cmd.createArg().setValue("-internalsf"); | |||
addValue(cmd, "-internalsf"); | |||
} | |||
if (sectionsonly) { | |||
cmd.createArg().setValue("-sectionsonly"); | |||
addValue(cmd, "-sectionsonly"); | |||
} | |||
//add -tsa operations if declared | |||
addTimestampAuthorityCommands(cmd); | |||
//JAR source is required | |||
cmd.createArg().setValue(jarSource.getPath()); | |||
addValue(cmd, jarSource.getPath()); | |||
//alias is required for signing | |||
cmd.createArg().setValue(alias); | |||
addValue(cmd, alias); | |||
log("Signing JAR: " + | |||
jarSource.getAbsolutePath() | |||
+" to " + | |||
target.getAbsolutePath() | |||
+ " as " + alias); | |||
cmd.setFailonerror(true); | |||
cmd.addConfiguredRedirector(redirector); | |||
cmd.execute(); | |||
// restore the lastModified attribute | |||
@@ -621,12 +428,12 @@ public class SignJar extends Task { | |||
*/ | |||
private void addTimestampAuthorityCommands(final ExecTask cmd) { | |||
if(tsaurl!=null) { | |||
cmd.createArg().setValue("-tsa"); | |||
cmd.createArg().setValue(tsaurl); | |||
addValue(cmd, "-tsa"); | |||
addValue(cmd, tsaurl); | |||
} | |||
if (tsacert != null) { | |||
cmd.createArg().setValue("-tsacert"); | |||
cmd.createArg().setValue(tsacert); | |||
addValue(cmd, "-tsacert"); | |||
addValue(cmd, tsacert); | |||
} | |||
} | |||
@@ -0,0 +1,120 @@ | |||
/* | |||
* Copyright 2000-2005 The Apache Software Foundation | |||
* | |||
* Licensed 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.tools.ant.taskdefs; | |||
import org.apache.tools.ant.BuildException; | |||
import org.apache.tools.ant.DirectoryScanner; | |||
import org.apache.tools.ant.types.FileSet; | |||
import java.util.Vector; | |||
import java.io.File; | |||
/** | |||
* JAR verification task. | |||
* For every JAR passed in, we fork jarsigner to verify | |||
* that it is correctly signed. This is more rigorous than just checking for | |||
* the existence of a signature; the entire certification chain is tested | |||
* @since Ant 1.7 | |||
*/ | |||
public class VerifyJar extends AbstractJarSignerTask { | |||
/** | |||
* no file message {@value} | |||
*/ | |||
public static final String ERROR_NO_FILE = "Not found :"; | |||
/** | |||
* certification flag | |||
*/ | |||
private boolean certificates=false; | |||
/** | |||
* Ask for certificate information to be printed | |||
* @param certificates | |||
*/ | |||
public void setCertificates(boolean certificates) { | |||
this.certificates = certificates; | |||
} | |||
/** | |||
* verify our jar files | |||
* @throws BuildException | |||
*/ | |||
public void execute() throws BuildException { | |||
//validation logic | |||
final boolean hasFileset = filesets.size() > 0; | |||
final boolean hasJar = jar != null; | |||
if (!hasJar && !hasFileset) { | |||
throw new BuildException(ERROR_NO_SOURCE); | |||
} | |||
beginExecution(); | |||
try { | |||
Vector sources = createUnifiedSources(); | |||
for (int i = 0; i < sources.size(); i++) { | |||
FileSet fs = (FileSet) sources.elementAt(i); | |||
//get all included files in a fileset | |||
DirectoryScanner ds = fs.getDirectoryScanner(getProject()); | |||
String[] jarFiles = ds.getIncludedFiles(); | |||
File baseDir = fs.getDir(getProject()); | |||
//loop through all jars in the fileset | |||
for (int j = 0; j < jarFiles.length; j++) { | |||
String jarFile = jarFiles[j]; | |||
File jarSource = new File(baseDir, jarFile); | |||
verifyOneJar(jarSource); | |||
} | |||
} | |||
} finally { | |||
endExecution(); | |||
} | |||
} | |||
/** | |||
* verify a JAR. | |||
* @param jar | |||
* @throws BuildException if the file could not be verified | |||
*/ | |||
private void verifyOneJar(File jar) { | |||
if(!jar.exists()) { | |||
throw new BuildException(ERROR_NO_FILE+jar); | |||
} | |||
final ExecTask cmd = createJarSigner(); | |||
setCommonOptions(cmd); | |||
bindToKeystore(cmd); | |||
//verify special operations | |||
addValue(cmd, "-verify"); | |||
if(certificates) { | |||
addValue(cmd, "-certs"); | |||
} | |||
//JAR is required | |||
addValue(cmd, jar.getPath()); | |||
log("Verifying JAR: " + | |||
jar.getAbsolutePath()); | |||
cmd.execute(); | |||
} | |||
} |
@@ -207,6 +207,7 @@ scriptdef=org.apache.tools.ant.taskdefs.optional.script.ScriptDef | |||
ildasm=org.apache.tools.ant.taskdefs.optional.dotnet.Ildasm | |||
apt=org.apache.tools.ant.taskdefs.Apt | |||
schemavalidate=org.apache.tools.ant.taskdefs.optional.SchemaValidate | |||
verifyjar=org.apache.tools.ant.taskdefs.VerifyJar | |||
# deprecated ant tasks (kept for back compatibility) | |||
starteam=org.apache.tools.ant.taskdefs.optional.scm.AntStarTeamCheckOut | |||
@@ -17,14 +17,7 @@ | |||
package org.apache.tools.ant.taskdefs; | |||
import java.io.File; | |||
import java.io.FileReader; | |||
import java.io.IOException; | |||
import java.util.Date; | |||
import java.util.Vector; | |||
import java.util.Enumeration; | |||
import org.apache.tools.ant.BuildFileTest; | |||
import org.apache.tools.ant.Project; | |||
import org.apache.tools.ant.util.JavaEnvUtils; | |||
/** | |||
@@ -156,4 +149,24 @@ public class SignJarTest extends BuildFileTest { | |||
assertLogContaining("java.net.ConnectException"); | |||
} | |||
} | |||
public void testVerifyJar() { | |||
executeTarget("testVerifyJar"); | |||
} | |||
public void testVerifyNoArgs() { | |||
expectBuildExceptionContaining("testVerifyNoArgs", | |||
"no args", | |||
AbstractJarSignerTask.ERROR_NO_SOURCE); | |||
} | |||
public void NotestVerifyJarUnsigned() { | |||
expectBuildException("testVerifyJarUnsigned", | |||
"unsigned JAR file"); | |||
} | |||
public void testVerifyFileset() { | |||
executeTarget("testVerifyFileset"); | |||
} | |||
} |