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"); | |||
| } | |||
| } | |||