KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > enterprise > appclient > jws > SignedStaticContent


1 /*
2  * The contents of this file are subject to the terms
3  * of the Common Development and Distribution License
4  * (the License). You may not use this file except in
5  * compliance with the License.
6  *
7  * You can obtain a copy of the license at
8  * https://glassfish.dev.java.net/public/CDDLv1.0.html or
9  * glassfish/bootstrap/legal/CDDLv1.0.txt.
10  * See the License for the specific language governing
11  * permissions and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL
14  * Header Notice in each file and include the License file
15  * at glassfish/bootstrap/legal/CDDLv1.0.txt.
16  * If applicable, add the following below the CDDL Header,
17  * with the fields enclosed by brackets [] replaced by
18  * you own identifying information:
19  * "Portions Copyrighted [year] [name of copyright owner]"
20  *
21  * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
22  */

23
24 package com.sun.enterprise.appclient.jws;
25
26 import com.sun.enterprise.deployment.backend.DeploymentLogger;
27 import com.sun.enterprise.security.SSLUtils;
28 import com.sun.enterprise.util.i18n.StringManager;
29 import java.io.File JavaDoc;
30 import java.net.URI JavaDoc;
31 import java.security.AccessControlException JavaDoc;
32 import java.security.KeyStore JavaDoc;
33 import java.security.KeyStoreException JavaDoc;
34 import java.security.Permission JavaDoc;
35 import java.util.ArrayList JavaDoc;
36 import java.util.logging.Logger JavaDoc;
37 import sun.security.tools.JarSigner;
38
39 /**
40  * Represents a jar file that is signed before being served in
41  * response to a Java Web Start request.
42  *
43  * For PE, signing occurs when the jar is first requested.
44  *
45  * @author tjquinn
46  */

47 public class SignedStaticContent extends StaticContent {
48     
49     /** file name suffix used to create the name for the signed jar */
50     private static final String JavaDoc SIGNEDJAR_OPTION = "-signedjar";
51
52     /** jarsigner option name introducing the keystore file spec */
53     private static final String JavaDoc KEYSTORE_OPTION = "-keystore";
54
55     /** jarsigner option name introducing the keystore password value */
56     private static final String JavaDoc STOREPASS_OPTION = "-storepass";
57
58     /** the unsigned jar to be served in signed form */
59     private File JavaDoc unsignedJar;
60     
61     /** the signed jar */
62     private File JavaDoc signedJar;
63     
64     /** URI for the app server installation root */
65     private URI JavaDoc installRootURI;
66
67     /** path to the app server's keystore */
68     private String JavaDoc keystoreAbsolutePath = null;
69     
70     /** property name the value of which points to the keystore */
71     private String JavaDoc KEYSTORE_PATH_PROPERTYNAME = "javax.net.ssl.keyStore";
72
73     /** property name optionally set by the admin in domain.xml to select an alias for signing */
74     private String JavaDoc USER_SPECIFIED_ALIAS_PROPERTYNAME = "com.sun.aas.jws.signing.alias";
75
76     /** default alias for signing if the admin does not specify one */
77     private String JavaDoc DEFAULT_ALIAS_VALUE = "s1as";
78
79     private Logger logger = DeploymentLogger.get();
80
81     private StringManager localStrings;
82     
83     /**
84      * Creates a new instance of SignedStaticContent
85      *
86      * @param origin the origin from which the jar to be signed comes
87      * @param contentKey key by which this jar will be retrievable when requested
88      * @param path the relative path within the app server to the jar
89      * @param signedJar specifies what the resulting signed jar file should be
90      * @param unsignedjar the existing unsigned jar to be signed just-in-time
91      * @param installRootURI the app server's installation directory
92      * @param isMain indicates if the jar contains the mail class that Java Web Start should launch
93      */

94     
95     public SignedStaticContent(
96             ContentOrigin origin,
97             String JavaDoc contentKey,
98             String JavaDoc path,
99             File JavaDoc signedJar,
100             File JavaDoc unsignedJar,
101             URI JavaDoc installRootURI,
102             StringManager localStrings,
103             boolean isMain) throws Exception JavaDoc {
104         super(origin, contentKey, path, signedJar, installRootURI, isMain);
105         
106         /*
107          *Find out as much as we can in order to sign the jar, but do not sign it yet.
108          */

109         this.installRootURI = installRootURI;
110         this.unsignedJar = unsignedJar;
111         this.signedJar = signedJar;
112         this.localStrings = localStrings;
113     }
114     
115     /**
116      *Returns the URI, relative to the app server installation directory, of
117      *the signed jar file to be published, signing the unsigned jar if needed
118      *to create the signed one to serve.
119      *@return relative URI to the jar
120      */

121     public URI JavaDoc getRelativeURI() {
122         try {
123             ensureSignedFileUpToDate();
124             return installRootURI.relativize(signedJar.toURI());
125         } catch (Throwable JavaDoc t) {
126             throw new RuntimeException JavaDoc(t);
127         }
128     }
129
130     /**
131      *Makes sure that the signed jar exists and is up-to-date compared to the
132      *corresponding unsigned jar. If not, create a new signed jar using
133      *the alias provided on this object's constructor.
134      *@throws KeyStoreException in case of errors reading the key store
135      *@throws IllegalArgumentException if the unsigned jar does not exists
136      */

137     private void ensureSignedFileUpToDate() throws KeyStoreException JavaDoc, IllegalArgumentException JavaDoc, Exception JavaDoc {
138         /*
139          *Check to see if the signed version of this jar is present.
140          */

141         if ( ! unsignedJar.exists()) {
142             throw new IllegalArgumentException JavaDoc(
143                     localStrings.getString("jws.sign.noUnsignedJar", unsignedJar.getAbsolutePath()));
144         }
145         if ( ! signedJar.exists() || (signedJar.lastModified() < unsignedJar.lastModified())) {
146             signJar();
147         }
148     }
149     
150     /**
151      *Signs the jar file.
152      *@throws KeyStoreException in case of errors accessing the keystore
153      */

154     private void signJar() throws KeyStoreException JavaDoc, Exception JavaDoc {
155         /*
156          *Compose the arguments to pass to the JarSigner class equivalent to
157          *this command:
158          *jarsigner
159          * -signedjar <signed JAR file spec>
160          * -keystore <keystore file spec>
161          * -storepass <keystore password>
162          * <unsigned JAR file spec>
163          * <alias>
164          *
165          *Note that techniques for importing certs into the AS keystore are
166          *documented as requiring that the key password and the keystore
167          *password be the same. We rely on that here because there is no
168          *provision for extracting the password for an alias from the keystore.
169          */

170         
171         ArrayList JavaDoc<String JavaDoc> args = new ArrayList JavaDoc<String JavaDoc>();
172         args.add(SIGNEDJAR_OPTION);
173         args.add(signedJar.getAbsolutePath());
174         
175         args.add(KEYSTORE_OPTION);
176         args.add(getKeystoreAbsolutePath());
177         
178         args.add(STOREPASS_OPTION);
179         int passwordSlot = args.size();
180         args.add(getKeystorePassword());
181         
182         args.add(unsignedJar.getAbsolutePath());
183         
184         args.add(getAlias());
185         long startTime = System.currentTimeMillis();
186         /*
187          *Save the current security manager; restored later.
188          */

189         SecurityManager JavaDoc mgr = System.getSecurityManager();
190         
191         try {
192             /*
193              *While running the JarSigner use a security manager that forbids
194              *VM exits, because the JarSigner uses them as part of its
195              *error handling and we do not want to exit the app server in case
196              *of jar signing errors.
197              */

198             NoExitSecurityManager noExitMgr = new NoExitSecurityManager(mgr);
199             System.setSecurityManager(noExitMgr);
200
201             /*
202              *Run the jar signer.
203              */

204             JarSigner.main(args.toArray(new String JavaDoc[args.size()]));
205         } catch (Throwable JavaDoc t) {
206             /*
207              *In case of any problems, make sure there is no ill-formed signed
208              *jar file left behind.
209              */

210             signedJar.delete();
211             
212             /*
213              *The jar signer will have written some information to System.out
214              *and/or System.err. Refer the user to those earlier messages.
215              */

216             throw new Exception JavaDoc(localStrings.getString("jws.sign.errorSigning", signedJar.getAbsolutePath()), t);
217         } finally {
218             /*
219              *Restore the saved security manager.
220              */

221             System.setSecurityManager(mgr);
222
223             /*
224              *Clear out the password.
225              */

226             args.set(passwordSlot, null);
227
228             long duration = System.currentTimeMillis() - startTime;
229             logger.fine("Signing " + unsignedJar.getAbsolutePath() + " took " + duration + " ms");
230         }
231     }
232
233     /**
234      *Returns the absolute path to the keystore.
235      *@return path to the keystore
236      */

237     private String JavaDoc getKeystoreAbsolutePath() {
238         if (keystoreAbsolutePath == null) {
239             keystoreAbsolutePath = System.getProperty(KEYSTORE_PATH_PROPERTYNAME);
240         }
241         return keystoreAbsolutePath;
242     }
243
244     /**
245      *Returns the password for the keystore.
246      *@return the keystore password
247      */

248     private String JavaDoc getKeystorePassword() {
249         return SSLUtils.getKeyStorePass();
250     }
251
252     /**
253      *Returns the alias to use for signing the jar file.
254      *@return the alias to use for signing the jar file
255      *@throws KeyStoreException in case of errors accessing the keystore
256      */

257     private String JavaDoc getAlias() throws KeyStoreException JavaDoc, Exception JavaDoc {
258         /*
259          *Choose what alias to use for signing the jar.
260          *If the user specified one, make sure it exists in the keystore.
261          *Even if we fall back to the default alias, make sure it is there
262          *in the keystore. Throw exceptions if neither alias is present.
263          */

264         KeyStore JavaDoc keystore = SSLUtils.getKeyStore();
265         
266         String JavaDoc alias = System.getProperty(USER_SPECIFIED_ALIAS_PROPERTYNAME);
267         if (alias == null || ! checkUserAlias(keystore, alias)) {
268             /*
269              *Either the admin did not specify an alias or s/he did and it
270              *is not in the keystore. Use the default alias in either case,
271              *making sure the default is in the keystore first.
272              */

273             checkDefaultAlias(keystore); // throws exception if alias is absent
274
alias = DEFAULT_ALIAS_VALUE;
275         }
276         return alias;
277     }
278     
279     /**
280      *Makes sure the specified alias is in the keystore. If not, throws an
281      *exception.
282      *@param keystore the keystore to use in checking the default alias
283      *@param candidateAlias the alias to check for
284      *@throws IllegalStateException if the keystore does not contain the default alias
285      */

286     private void checkDefaultAlias(KeyStore JavaDoc keystore) throws KeyStoreException JavaDoc {
287         if ( ! keystore.containsAlias(DEFAULT_ALIAS_VALUE)) {
288             throw new IllegalStateException JavaDoc(localStrings.getString("jws.sign.defaultAliasAbsent", DEFAULT_ALIAS_VALUE));
289         }
290     }
291     
292     /**
293      *Returns whether the specified alias is present in the keystore or not. Also
294      *logs a warning if the user-specified alias is missing.
295      *@param keystore the keystore to use in checking the user alias
296      *@param candidateAlias the alias to look for
297      *@return true if the alias is present in the keystore; false otherwise
298      *@throws KeyStoreException in case of error accessing the keystore
299      */

300     private boolean checkUserAlias(KeyStore JavaDoc keystore, String JavaDoc candidateAlias) throws KeyStoreException JavaDoc {
301         boolean result;
302         if ( ! (result = keystore.containsAlias(candidateAlias)) ) {
303             logger.warning(localStrings.getString("jws.sign.userAliasAbsent", candidateAlias));
304         }
305         return result;
306     }
307     
308     /**
309      *A security manager that rejects any attempt to exit the VM.
310      */

311     private class NoExitSecurityManager extends SecurityManager JavaDoc {
312         
313         private SecurityManager JavaDoc originalManager;
314         
315         public NoExitSecurityManager(SecurityManager JavaDoc originalManager) {
316             this.originalManager = originalManager;
317         }
318         
319         public void checkExit(int status) {
320             /*
321              *Always reject attempts to exit the VM.
322              */

323             throw new AccessControlException JavaDoc("System.exit");
324         }
325         
326         public void checkPermission(Permission JavaDoc p) {
327             /*
328              *Delegate to the other manager, if any.
329              */

330             if (originalManager != null) {
331                 originalManager.checkPermission(p);
332             }
333         }
334     }
335 }
336
Popular Tags