FileDocCategorySizeDatePackage
ASJarSigner.javaAPI DocGlassfish v2 API23491Fri May 04 22:34:12 BST 2007com.sun.enterprise.appclient.jws

ASJarSigner

public class ASJarSigner extends Object
Signs a specified JAR file.

This implementation searches the available keystores for the signing alias indicated in the domain.xml config or, if not specified, the default alias, the first time it is invoked to sign a JAR file. After the first requested signing it uses the same alias and provider to sign all JARs.

The public interface to this class is the static signJar method.

author
tjquinn

Fields Summary
private static final String
USER_SPECIFIED_ALIAS_PROPERTYNAME
property name optionally set by the admin in domain.xml to select an alias for signing
private static final String
JKS_KEYSTORE_TYPE_VALUE
keystore type for JKS keystores
private static final String
DEFAULT_ALIAS_VALUE
default alias for signing if the admin does not specify one
private static final String
userAlias
user-specified signing alias
private static final Logger
logger
private static final com.sun.enterprise.util.i18n.StringManager
localStrings
private static SigningInfo
signingInfo
info used for signing, saved after being looked up during the first request
private File
unsignedJar
the existing, unsigned JAR file
private File
signedJar
the signed JAR file, to be created
Constructors Summary
private ASJarSigner(File unsignedJar, File signedJar)
Creates a new instance of ASJarSigner

        this.unsignedJar = unsignedJar;
        this.signedJar = signedJar;
    
Methods Summary
private static com.sun.enterprise.appclient.jws.ASJarSigner$SigningInfocreateSigningInfo()
Creates an object containing the signing information provided by the user-specified or default alias from the keystore in which it appears.

return
the SigningInfo object containing the information to be used for signing

        
        String[] keystorePWs = SecurityUtil.getSecuritySupport().getKeyStorePasswords();
        String[] tokenNames = SecurityUtil.getSecuritySupport().getTokenNames();

        /*
         *Assemble lists of signing info objects, one list for matches on the 
         *user-specified alias (if specified at all), the other for matches on 
         *the default alias.
         */
        ArrayList<SigningInfo> signingInfoForDefaultAlias = new ArrayList<SigningInfo>();
        ArrayList<SigningInfo> signingInfoForUserAlias = new ArrayList<SigningInfo>();
        
        int keystoreSlot = 0;
        
        for (KeyStore ks : SecurityUtil.getSecuritySupport().getKeyStores()) {
            if (userAlias != null && ks.containsAlias(userAlias)) {
                /*
                 *The user specified an alias and the current keystore contains
                 *it.  Use this keystore and the user's alias.
                 */
                signingInfoForUserAlias.add(SigningInfo.newInstance(
                        userAlias, 
                        keystorePWs[keystoreSlot], 
                        ks,
                        tokenNames[keystoreSlot]));
            }
            
            if (ks.containsAlias(DEFAULT_ALIAS_VALUE)) {
                signingInfoForDefaultAlias.add(SigningInfo.newInstance(
                        DEFAULT_ALIAS_VALUE, 
                        keystorePWs[keystoreSlot], 
                        ks, 
                        tokenNames[keystoreSlot]));
            }
            keystoreSlot++;
        }
        
        /*
         *Choose which signing information object to use based on whether the user 
         *specified an alias, if so whether it was found among the known keystores,
         *etc.
         */
        SigningInfo result = selectSigningInfo(signingInfoForUserAlias, signingInfoForDefaultAlias);
        logger.fine(localStrings.getString("jws.sign.signingInfo", result.toString()));
        
        return result;
    
private static synchronized com.sun.enterprise.appclient.jws.ASJarSigner$SigningInfogetSigningInfo()
Returns the signing info to use, creating it if it is not already created.

return
the signing information to use in signing JARs

        if (signingInfo == null) {
            signingInfo = createSigningInfo();
        }
        return signingInfo;
    
private static com.sun.enterprise.appclient.jws.ASJarSigner$SigningInfoselectSigningInfo(java.util.ArrayList signingInfoForUserAlias, java.util.ArrayList signingInfoForDefaultAlias)
Selects the signing info instance to be used for signing JAR files. This method may issue warnings if the user-specified alias does not appear in any keystore or if the user-specified or default alias appears in more than one keystore.

param
signingInfoForUserAlias signing info for the user-specified alias
param
signingInfoForDefaultAlias signing info for the default alias
return
the SigningInfo instance to be used for signing JARs

        /*
         *Use the user-specified info if requested and available. Otherwise use
         *the default info.
         */
        ArrayList<SigningInfo> signingInfoOfInterest;
        String aliasOfInterest;
        
        if (userAlias != null) {
            if (signingInfoForUserAlias.size() == 0) {
                logger.log(Level.WARNING, 
                        localStrings.getString("jws.sign.userAliasAbsent", userAlias));
                signingInfoOfInterest = signingInfoForDefaultAlias;
                aliasOfInterest = DEFAULT_ALIAS_VALUE;
            } else {
                signingInfoOfInterest = signingInfoForUserAlias;
                aliasOfInterest = userAlias;
            }
        } else {
            signingInfoOfInterest = signingInfoForDefaultAlias;
            aliasOfInterest = DEFAULT_ALIAS_VALUE;
        }
            
        /*
         *Make sure whichever list of signing info is now of interest has
         *exactly one entry for the alias of interest.
         *
         *If there is no entry for the alias of interest, then we cannot proceed.
         */
        if (signingInfoOfInterest.size() == 0) {
            throw new IllegalArgumentException(
                    localStrings.getString("jws.sign.aliasNotFound", aliasOfInterest));
        }
        
        if (signingInfoOfInterest.size() > 1) {
            /*
             *Prepare a warning identifying all the keystore providers for
             *which the keystore contains the alias of interest.  
             */
            StringBuilder sb = new StringBuilder();
            for (SigningInfo si : signingInfoOfInterest) {
                if (sb.length() > 0) {
                    sb.append(", ");
                }
                sb.append(si);
            }
            logger.log(Level.WARNING, 
                    localStrings.getString("jws.sign.aliasFoundMult", aliasOfInterest, sb.toString()));
        }

        /*
         *Return the first signing info that matched the alias.
         */
        return signingInfoOfInterest.get(0);
    
private longsign()
Signs the jar file using the current signing info.

return
elapsed milliseconds it took to sign the JAR
throws
Exception SSLUtils.getKeyStores() cannot do so

        long startTime = System.currentTimeMillis();
        
        /*
         *Obtain the command-line arguments suitable for signing this JAR
         *based on the signing information already established, which will depend
         *on the keystore type in which the alias was found, etc.
         */
        String[] args = signingInfo.getSigningArgs(unsignedJar, signedJar);

        /*
         *In response to errors, the JarSigner class writes errors directly to 
         *System.out (rather than throw exceptions) and invokes System.exit.  
         *To prevent JarSigner's error handling from forcing the app server to
         *exit establish a security manager that prohibits the use of System.exit,
         *temporarily while JarSigner runs.  
         *
         *Make sure to change the security manager and use the JarSigner
         *class only one thread at a time.
         */
        synchronized(SignedStaticContent.class) {
            
            /*
             *Save the current security manager; restored later.
             */
            SecurityManager mgr = System.getSecurityManager();

            try {
                NoExitSecurityManager noExitMgr = new NoExitSecurityManager(mgr);
                System.setSecurityManager(noExitMgr);

                /*
                 *Run the jar signer.
                 */
                JarSigner.main(args);
            } catch (Throwable t) {
                /*
                 *In case of any problems, make sure there is no ill-formed signed
                 *jar file left behind.
                 */
                signedJar.delete();

                /*
                 *The jar signer will have written some information to System.out
                 *and/or System.err.  Refer the user to those earlier messages.
                 */
                throw new Exception(localStrings.getString("jws.sign.errorSigning", signedJar.getAbsolutePath()), t);
            } finally {
                /*
                 *Restore the saved security manager.
                 */
                System.setSecurityManager(mgr);

                /*
                 *Clear out the args array to hide the password.
                 */
                for (int i = 0; i < args.length; i++) {
                    args[i] = null;
                }
                long duration = System.currentTimeMillis() - startTime;
                logger.fine("Signing " + unsignedJar.getAbsolutePath() + " took " + duration + " ms");
            }
        } 
        
        return System.currentTimeMillis() - startTime;
    
public static longsignJar(java.io.File unsignedJar, java.io.File signedJar)
Creates a signed jar from the specified unsigned jar.

param
unsignedJar the unsigned JAR file
param
signedJar the signed JAR to be created
return
the elapsed time to sign the JAR (in milliseconds)
throws
Exception getting the keystores from SSLUtils fails

    
                                             
             
        /*
         *Make sure the signing information has been initialized.
         */
        synchronized(ASJarSigner.class) {
            if (signingInfo == null) {
                signingInfo = createSigningInfo();
            }
        }
        ASJarSigner signer = new ASJarSigner(unsignedJar, signedJar);
        return signer.sign();