FileDocCategorySizeDatePackage
SignJar.javaAPI DocApache Ant 1.7015075Wed Dec 13 06:16:18 GMT 2006org.apache.tools.ant.taskdefs

SignJar

public class SignJar extends AbstractJarSignerTask
Signs JAR or ZIP files with the javasign command line tool. The tool detailed dependency checking: files are only signed if they are not signed. The signjar attribute can point to the file to generate; if this file exists then its modification date is used as a cue as to whether to resign any JAR file. Timestamp driven signing is based on the unstable and inadequately documented information in the Java1.5 docs
see
beta documentation
ant.task
category="java"
since
Ant 1.1

Fields Summary
private static final org.apache.tools.ant.util.FileUtils
FILE_UTILS
protected String
sigfile
name to a signature file
protected File
signedjar
name of a single jar
protected boolean
internalsf
flag for internal sf signing
protected boolean
sectionsonly
sign sections only?
private boolean
preserveLastModified
flag to preserve timestamp on modified files
protected boolean
lazy
Whether to assume a jar which has an appropriate .SF file in is already signed.
protected File
destDir
the output directory when using paths.
private org.apache.tools.ant.util.FileNameMapper
mapper
mapper for todir work
protected String
tsaurl
URL for a tsa; null implies no tsa support
protected String
tsacert
alias for the TSA in the keystore
public static final String
ERROR_TODIR_AND_SIGNEDJAR
error string for unit test verification: {@value}
public static final String
ERROR_TOO_MANY_MAPPERS
error string for unit test verification: {@value}
public static final String
ERROR_SIGNEDJAR_AND_PATHS
error string for unit test verification {@value}
public static final String
ERROR_BAD_MAP
error string for unit test verification: {@value}
public static final String
ERROR_MAPPER_WITHOUT_DEST
error string for unit test verification: {@value}
public static final String
ERROR_NO_ALIAS
error string for unit test verification: {@value}
public static final String
ERROR_NO_STOREPASS
error string for unit test verification: {@value}
Constructors Summary
Methods Summary
public voidadd(org.apache.tools.ant.util.FileNameMapper newMapper)
add a mapper to determine file naming policy. Only used with toDir processing.

param
newMapper the mapper to add.
since
Ant 1.7

        if (mapper != null) {
            throw new BuildException(ERROR_TOO_MANY_MAPPERS);
        }
        mapper = newMapper;
    
private voidaddTimestampAuthorityCommands(ExecTask cmd)
If the tsa parameters are set, this passes them to the command. There is no validation of java version, as third party JDKs may implement this on earlier/later jarsigner implementations.

param
cmd the exec task.

        if (tsaurl != null) {
            addValue(cmd, "-tsa");
            addValue(cmd, tsaurl);
        }
        if (tsacert != null) {
            addValue(cmd, "-tsacert");
            addValue(cmd, tsacert);
        }
    
public voidexecute()
sign the jar(s)

throws
BuildException on errors

        //validation logic
        final boolean hasJar = jar != null;
        final boolean hasSignedJar = signedjar != null;
        final boolean hasDestDir = destDir != null;
        final boolean hasMapper = mapper != null;

        if (!hasJar && !hasResources()) {
            throw new BuildException(ERROR_NO_SOURCE);
        }
        if (null == alias) {
            throw new BuildException(ERROR_NO_ALIAS);
        }

        if (null == storepass) {
            throw new BuildException(ERROR_NO_STOREPASS);
        }

        if (hasDestDir && hasSignedJar) {
            throw new BuildException(ERROR_TODIR_AND_SIGNEDJAR);
        }


        if (hasResources() && hasSignedJar) {
            throw new BuildException(ERROR_SIGNEDJAR_AND_PATHS);
        }

        //this isnt strictly needed, but by being fussy now,
        //we can change implementation details later
        if (!hasDestDir && hasMapper) {
            throw new BuildException(ERROR_MAPPER_WITHOUT_DEST);
        }

        beginExecution();


        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 path with one file

            Path sources = createUnifiedSourcePath();
            //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 paths 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 paths
            Iterator iter = sources.iterator();
            while (iter.hasNext()) {
                FileResource fr = (FileResource) iter.next();

                //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 : fr.getBaseDir();

                //determine the destination filename via the mapper
                String[] destFilenames = destMapper.mapFileName(fr.getName());
                if (destFilenames == null || destFilenames.length != 1) {
                    //we only like simple mappers.
                    throw new BuildException(ERROR_BAD_MAP + fr.getFile());
                }
                File destFile = new File(toDir, destFilenames[0]);
                signOneJar(fr.getFile(), destFile);
            }
        } finally {
            endExecution();
        }
    
public org.apache.tools.ant.util.FileNameMappergetMapper()
get the active mapper; may be null

return
mapper or null
since
Ant 1.7

        return mapper;
    
public java.lang.StringgetTsacert()
get the -tsacert option

since
Ant 1.7
return
a certificate alias or null

        return tsacert;
    
public java.lang.StringgetTsaurl()
get the -tsaurl url

return
url or null
since
Ant 1.7

        return tsaurl;
    
protected booleanisSigned(java.io.File file)
test for a file being signed, by looking for a signature in the META-INF directory with our alias.

param
file the file to be checked
return
true if the file is signed
see
IsSigned#isSigned(File, String)

        try {
            return IsSigned.isSigned(file, alias);
        } catch (IOException e) {
            //just log this
            log(e.toString(), Project.MSG_VERBOSE);
            return false;
        }
    
protected booleanisUpToDate(java.io.File jarFile, java.io.File signedjarFile)
Compare a jar file with its corresponding signed jar. The logic for this is complex, and best explained in the source itself. Essentially if either file doesnt exist, or the destfile has an out of date timestamp, then the return value is false.

If we are signing ourself, the check {@link #isSigned(File)} is used to trigger the process.

param
jarFile the unsigned jar file
param
signedjarFile the result signed jar file
return
true if the signedjarFile is considered up to date

        if (null == jarFile || !jarFile.exists()) {
            //these are pathological cases, but retained in case somebody
            //subclassed us.
            return false;
        }

        //we normally compare destination with source
        File destFile = signedjarFile;
        if (destFile == null) {
            //but if no dest is specified, compare source to source
            destFile = jarFile;
        }

        //if, by any means, the destfile and source match,
        if (jarFile.equals(destFile)) {
            if (lazy) {
                //we check the presence of signatures on lazy signing
                return isSigned(jarFile);
            }
            //unsigned or non-lazy self signings are always false
            return false;
        }

        //if they are different, the timestamps are used
        return FILE_UTILS.isUpToDate(jarFile, destFile);
    
public voidsetDestDir(java.io.File destDir)
Optionally sets the output directory to be used.

param
destDir the directory in which to place signed jars
since
Ant 1.7

        this.destDir = destDir;
    
public voidsetInternalsf(boolean internalsf)
Flag to include the .SF file inside the signature; optional; default false

param
internalsf if true include the .SF file inside the signature

        this.internalsf = internalsf;
    
public voidsetLazy(boolean lazy)
flag to control whether the presence of a signature file means a JAR is signed; optional, default false

param
lazy flag to control whether the presence of a signature

        this.lazy = lazy;
    
public voidsetPreserveLastModified(boolean preserveLastModified)
true to indicate that the signed jar modification date remains the same as the original. Defaults to false

param
preserveLastModified if true preserve the last modified time

        this.preserveLastModified = preserveLastModified;
    
public voidsetSectionsonly(boolean sectionsonly)
flag to compute hash of entire manifest; optional, default false

param
sectionsonly flag to compute hash of entire manifest

        this.sectionsonly = sectionsonly;
    
public voidsetSigfile(java.lang.String sigfile)
name of .SF/.DSA file; optional

param
sigfile the name of the .SF/.DSA file

    // CheckStyle:VisibilityModifier ON

                      
         
        this.sigfile = sigfile;
    
public voidsetSignedjar(java.io.File signedjar)
name of signed JAR file; optional

param
signedjar the name of the signed jar file

        this.signedjar = signedjar;
    
public voidsetTsacert(java.lang.String tsacert)
set the alias in the keystore of the TSA to use;

param
tsacert the cert alias.

        this.tsacert = tsacert;
    
public voidsetTsaurl(java.lang.String tsaurl)

param
tsaurl the tsa url.
since
Ant 1.7

        this.tsaurl = tsaurl;
    
private voidsignOneJar(java.io.File jarSource, java.io.File jarTarget)
Sign one jar.

The signing only takes place if {@link #isUpToDate(File, File)} indicates that it is needed.

param
jarSource source to sign
param
jarTarget target; may be null
throws
BuildException



        File targetFile = jarTarget;
        if (targetFile == null) {
            targetFile = jarSource;
        }
        if (isUpToDate(jarSource, targetFile)) {
            return;
        }

        long lastModified = jarSource.lastModified();
        final ExecTask cmd = createJarSigner();

        setCommonOptions(cmd);

        bindToKeystore(cmd);
        if (null != 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 != targetFile && !jarSource.equals(targetFile)) {
            addValue(cmd, "-signedjar");
            addValue(cmd, targetFile.getPath());
        }

        if (internalsf) {
            addValue(cmd, "-internalsf");
        }

        if (sectionsonly) {
            addValue(cmd, "-sectionsonly");
        }

        //add -tsa operations if declared
        addTimestampAuthorityCommands(cmd);

        //JAR source is required
        addValue(cmd, jarSource.getPath());

        //alias is required for signing
        addValue(cmd, alias);

        log("Signing JAR: "
            + jarSource.getAbsolutePath()
            + " to "
            + targetFile.getAbsolutePath()
            + " as " + alias);

        cmd.execute();

        // restore the lastModified attribute
        if (preserveLastModified) {
            targetFile.setLastModified(lastModified);
        }