KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > enterprise > webservice > WSSCallbackHandler


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 /*
25  * WSSCallbackHandler.java
26  *
27  * Created on April 21, 2004, 11:56 AM
28  */

29
30 package com.sun.enterprise.webservice;
31
32 import java.io.IOException JavaDoc;
33 import java.math.BigInteger JavaDoc;
34 import java.security.Key JavaDoc;
35 import java.security.KeyStore JavaDoc;
36 import java.security.KeyStore.PrivateKeyEntry;
37 import java.security.KeyStoreException JavaDoc;
38 import java.security.InvalidAlgorithmParameterException JavaDoc;
39 import java.security.NoSuchAlgorithmException JavaDoc;
40 import java.security.PrivateKey JavaDoc;
41 import java.security.cert.Certificate JavaDoc;
42 import java.security.cert.CertStore JavaDoc;
43 import java.security.cert.CollectionCertStoreParameters JavaDoc;
44 import java.security.cert.X509Certificate JavaDoc;
45 import java.util.ArrayList JavaDoc;
46 import java.util.Arrays JavaDoc;
47 import java.util.Enumeration JavaDoc;
48 import java.util.List JavaDoc;
49 import java.util.logging.Level JavaDoc;
50 import java.util.logging.Logger JavaDoc;
51
52 import javax.crypto.SecretKey;
53 import javax.security.auth.x500.X500Principal JavaDoc;
54 import javax.security.auth.callback.Callback JavaDoc;
55 import javax.security.auth.callback.CallbackHandler JavaDoc;
56 import javax.security.auth.callback.UnsupportedCallbackException JavaDoc;
57
58 import com.sun.enterprise.security.jauth.callback.CertStoreCallback;
59 import com.sun.enterprise.security.jauth.callback.PasswordValidationCallback;
60 import com.sun.enterprise.security.jauth.callback.PrivateKeyCallback;
61 import com.sun.enterprise.security.jauth.callback.SecretKeyCallback;
62 import com.sun.enterprise.security.jauth.callback.TrustStoreCallback;
63
64 import com.sun.enterprise.Switch;
65 import com.sun.enterprise.security.SecurityUtil;
66 import com.sun.enterprise.security.SSLUtils;
67 import com.sun.enterprise.security.auth.LoginContextDriver;
68 import com.sun.enterprise.security.LoginException;
69 import com.sun.enterprise.security.auth.realm.Realm;
70 import com.sun.enterprise.webservice.AppclientWSSCallbackHandler;
71 import com.sun.enterprise.webservice.EjbServletWSSCallbackHandler;
72 import com.sun.logging.LogDomains;
73
74 import sun.security.util.DerValue;
75
76 /**
77  * Callback Handler for WebServices Security
78  * @author Harpreet Singh
79  * @author Shing Wai Chan
80  */

81 public abstract class WSSCallbackHandler implements CallbackHandler JavaDoc {
82     private static String JavaDoc SUBJECT_KEY_IDENTIFIER_OID = "2.5.29.14";
83
84     protected static Logger JavaDoc _logger = LogDomains.getLogger(LogDomains.SECURITY_LOGGER);
85
86     /**
87      * temporary make this method public. refer RealmAdapter.java.
88      */

89     static public CallbackHandler JavaDoc getInstance() {
90         if (Switch.getSwitch().getContainerType() == Switch.APPCLIENT_CONTAINER) {
91             return AppclientWSSCallbackHandler.newInstance();
92         } else {
93             return EjbServletWSSCallbackHandler.newInstance();
94         }
95     }
96
97     /*
98      * To be implemented by a sub-class. The sub class decides
99      * which callbacks it supports.
100      * <i>EjbServletWSSCallbackHandler</i> supports:
101      * <li>SecretKeyCallback</li>
102      * <li>TrustStoreCallback</li>
103      * <li>PasswordValidationCallback</li>
104      * <li>CertStoreCallback</li>
105      * <li>PrivateKeyCallback</li>
106      * <i> AppclientWSSCallbackHandler</i> supports:
107      * <li>NameCallback</li>
108      * <li>PasswordCallback</li>
109      * <li>ChoiceCallback</li>
110      */

111     abstract boolean isSupportedCallback(Callback JavaDoc callback);
112     
113     public void handle(Callback JavaDoc[] callbacks)
114         throws IOException JavaDoc, UnsupportedCallbackException JavaDoc{};
115     
116     /**
117      * gets the appropriate callback processor and hands the callback to
118      * processor to process the callback.
119      */

120     protected void processCallback (Callback JavaDoc callback)
121             throws UnsupportedCallbackException JavaDoc {
122         if (callback instanceof PasswordValidationCallback) {
123             processPasswordValidation((PasswordValidationCallback)callback);
124         } else if (callback instanceof PrivateKeyCallback) {
125             processPrivateKey((PrivateKeyCallback)callback);
126         } else if (callback instanceof TrustStoreCallback) {
127             TrustStoreCallback tstoreCallback = (TrustStoreCallback)callback;
128             if (_logger.isLoggable(Level.FINE)) {
129                 _logger.log(Level.FINE,
130                 "container-auth: wss : In TrustStoreCallback Processor");
131             }
132             tstoreCallback.setStore (SSLUtils.getMergedTrustStore());
133
134         } else if (callback instanceof CertStoreCallback) {
135             processCertStore((CertStoreCallback)callback);
136         } else if (callback instanceof SecretKeyCallback) {
137             processSecretKey((SecretKeyCallback)callback);
138         } else {
139             // sanity check =- should never come here.
140
// the isSupportedCallback method already takes care of this case
141
_logger.log(Level.FINE,"wss-container-auth: UnsupportedCallback : "+
142                     callback.getClass().getName());
143             throw new UnsupportedCallbackException JavaDoc(callback);
144         }
145     }
146
147     private void processPasswordValidation(
148             PasswordValidationCallback pwdCallback) {
149
150         if (Switch.getSwitch().getContainerType() == Switch.APPCLIENT_CONTAINER) {
151             if (_logger.isLoggable(Level.FINE)){
152                 _logger.log(Level.FINE, "container-auth: wss : In PasswordValidationCallback Processor for appclient - will do nothing");
153             }
154             pwdCallback.setResult(true);
155             return;
156         }
157         String JavaDoc username = pwdCallback.getUsername();
158         String JavaDoc password = new String JavaDoc(pwdCallback.getPassword());
159         if (_logger.isLoggable(Level.FINE)) {
160             _logger.log(Level.FINE, "container-auth: wss : In PasswordValidationCallback Processor");
161         }
162         try {
163             String JavaDoc defaultRealm = Realm.getDefaultRealm();
164             LoginContextDriver.wssLoginUsernamePassword(username, password,
165                 defaultRealm);
166             if(_logger.isLoggable(Level.FINE)){
167                 _logger.log(Level.FINE,
168                     "container-auth wss: authentication succeeded for user = ",
169                     username);
170             }
171             // explicitly ditch the password
172
password = null;
173             pwdCallback.setResult(true);
174         } catch(LoginException le) {
175             // login failed
176
_logger.log(Level.INFO,
177                 "container-auth: wss : Login failed for user :",
178                 username);
179             pwdCallback.setResult(false);
180         }
181     }
182
183     private void processPrivateKey(PrivateKeyCallback privKeyCallback) {
184         KeyStore JavaDoc[] kstores = SecurityUtil.getSecuritySupport().getKeyStores();
185         if (_logger.isLoggable(Level.FINE)) {
186             _logger.log(Level.FINE,
187                 "container-auth: wss : In PrivateKeyCallback Processor");
188         }
189         
190         // make sure we have a keystore
191
if (kstores == null || kstores.length == 0) {
192             // cannot get any information
193
privKeyCallback.setKey(null, null);
194             return;
195         }
196
197         String JavaDoc[] passwords =
198             SecurityUtil.getSecuritySupport().getKeyStorePasswords();
199
200         // get the request type
201
PrivateKeyCallback.Request req = privKeyCallback.getRequest();
202         if (req == null) {
203             // no request type - set default key
204
setDefaultKey(privKeyCallback, kstores, passwords);
205             passwords = null;
206             return;
207         }
208
209         // find key based on request type
210
PrivateKey JavaDoc privKey = null;
211         Certificate JavaDoc[] certs = null;
212         try {
213             if (req instanceof PrivateKeyCallback.AliasRequest) {
214                 PrivateKeyCallback.AliasRequest aReq =
215                         (PrivateKeyCallback.AliasRequest)req;
216
217                 String JavaDoc alias = aReq.getAlias();
218                 PrivateKeyEntry privKeyEntry = null;
219                 if (alias == null) {
220                     // set default key
221
setDefaultKey(privKeyCallback, kstores, passwords);
222                     passwords = null;
223                     return;
224                 } else if ((privKeyEntry = SSLUtils.getPrivateKeyEntryFromTokenAlias(alias)) != null) {
225                     privKey = privKeyEntry.getPrivateKey();
226                     certs = privKeyEntry.getCertificateChain();
227                 }
228             } else if (req instanceof PrivateKeyCallback.IssuerSerialNumRequest) {
229                 PrivateKeyCallback.IssuerSerialNumRequest isReq =
230                         (PrivateKeyCallback.IssuerSerialNumRequest)req;
231                 X500Principal JavaDoc issuer = isReq.getIssuer();
232                 BigInteger JavaDoc serialNum = isReq.getSerialNum();
233                 if (issuer != null && serialNum != null) {
234                     boolean found = false;
235                     for (int i = 0; i < kstores.length && !found; i++) {
236                         Enumeration JavaDoc aliases = kstores[i].aliases();
237                         while (aliases.hasMoreElements() && !found) {
238                             String JavaDoc nextAlias = (String JavaDoc)aliases.nextElement();
239                             Key JavaDoc key = kstores[i].getKey(nextAlias, passwords[i].toCharArray());
240                             if (key != null && (key instanceof PrivateKey JavaDoc)) {
241                                 Certificate JavaDoc[] certificates =
242                                         kstores[i].getCertificateChain(nextAlias);
243                                 // check issuer/serial
244
X509Certificate JavaDoc eeCert = (X509Certificate JavaDoc)certificates[0];
245                                 if (eeCert.getIssuerX500Principal().equals(issuer) &&
246                                         eeCert.getSerialNumber().equals(serialNum)) {
247                                     privKey = (PrivateKey JavaDoc)key;
248                                     certs = certificates;
249                                     found = true;
250                                 }
251                             }
252                         }
253                     }
254                 }
255             } else if (req instanceof PrivateKeyCallback.SubjectKeyIDRequest) {
256                 PrivateKeyCallback.SubjectKeyIDRequest skReq =
257                         (PrivateKeyCallback.SubjectKeyIDRequest)req;
258                 byte[] subjectKeyID = skReq.getSubjectKeyID();
259                 if (subjectKeyID != null) {
260                     boolean found = false;
261                     // In DER, subjectKeyID will be an OCTET STRING of OCTET STRING
262
DerValue derValue1 = new DerValue(
263                         DerValue.tag_OctetString, subjectKeyID);
264                     DerValue derValue2 = new DerValue(
265                         DerValue.tag_OctetString, derValue1.toByteArray());
266                     byte[] derSubjectKeyID = derValue2.toByteArray();
267
268                     for (int i = 0; i < kstores.length && !found; i++) {
269                         Enumeration JavaDoc aliases = kstores[i].aliases();
270                         while (aliases.hasMoreElements() && !found) {
271                             String JavaDoc nextAlias = (String JavaDoc)aliases.nextElement();
272                             Key JavaDoc key = kstores[i].getKey(nextAlias, passwords[i].toCharArray());
273                             if (key != null && (key instanceof PrivateKey JavaDoc)) {
274                                 Certificate JavaDoc[] certificates =
275                                         kstores[i].getCertificateChain(nextAlias);
276                                 X509Certificate JavaDoc eeCert = (X509Certificate JavaDoc)certificates[0];
277                                 // Extension: SubjectKeyIdentifier
278
byte[] derSubKeyID = eeCert.getExtensionValue(SUBJECT_KEY_IDENTIFIER_OID);
279                                 if (derSubKeyID != null &&
280                                         Arrays.equals(derSubKeyID, derSubjectKeyID)) {
281                                     privKey = (PrivateKey JavaDoc)key;
282                                     certs = certificates;
283                                     found = true;
284                                 }
285                             }
286                         }
287                     }
288                 }
289             } else {
290                 if (_logger.isLoggable(Level.FINE)) {
291                     _logger.log(Level.FINE,
292                          "invalid request type: " + req.getClass().getName());
293                 }
294             }
295          } catch (Exception JavaDoc e) {
296              // UnrecoverableKeyException
297
// NoSuchAlgorithmException
298
// KeyStoreException
299
if (_logger.isLoggable(Level.FINE)) {
300                  _logger.log(Level.FINE,
301                  "container-auth: wss : In PrivateKeyCallback Processor: " +
302                  " Error reading key !", e);
303              }
304          } finally {
305              privKeyCallback.setKey(privKey, certs);
306              passwords = null;
307          }
308     }
309     
310     /**
311      * Return the first key/chain that we can successfully
312      * get out of the keystore
313      */

314     private void setDefaultKey(PrivateKeyCallback privKeyCallback,
315             KeyStore JavaDoc[] kstores, String JavaDoc[] passwords) {
316         PrivateKey JavaDoc privKey = null;
317         Certificate JavaDoc[] certs = null;
318         try {
319             for (int i = 0; i < kstores.length && privKey == null; i++) {
320                 Enumeration JavaDoc aliases = kstores[i].aliases();
321                 // loop thru aliases and try to get the key/chain
322
while (aliases.hasMoreElements() && privKey == null) {
323                     String JavaDoc nextAlias = (String JavaDoc)aliases.nextElement();
324                     privKey = null;
325                     certs = null;
326                     Key JavaDoc key = kstores[i].getKey(nextAlias, passwords[i].toCharArray());
327                     if (key != null && (key instanceof PrivateKey JavaDoc)) {
328                         privKey = (PrivateKey JavaDoc)key;
329                         certs = kstores[i].getCertificateChain(nextAlias);
330                     }
331                 }
332             }
333         } catch (Exception JavaDoc e) {
334             // UnrecoverableKeyException
335
// NoSuchAlgorithmException
336
// KeyStoreException
337
}
338         
339         privKeyCallback.setKey(privKey, certs);
340     }
341
342     private void processCertStore(CertStoreCallback certStoreCallback) {
343         if (_logger.isLoggable(Level.FINE)) {
344             _logger.log(Level.FINE,
345                 "container-auth: wss : In CertStoreCallback Processor");
346         }
347
348         KeyStore JavaDoc certStore = SSLUtils.getMergedTrustStore();
349         if (certStore == null) {// should never happen
350
certStoreCallback.setStore((CertStore JavaDoc)null);
351         }
352         List JavaDoc list = new ArrayList JavaDoc();
353         CollectionCertStoreParameters JavaDoc ccsp = null;
354         try{
355             Enumeration JavaDoc enu = certStore.aliases();
356             while (enu.hasMoreElements()) {
357                 String JavaDoc alias = (String JavaDoc)enu.nextElement();
358                 if(certStore.isCertificateEntry(alias)){
359                     try{
360                         Certificate JavaDoc cert = certStore.getCertificate(alias);
361                         list.add(cert);
362                     }catch(KeyStoreException JavaDoc kse){
363                         // ignore and move to next
364
_logger.log(Level.FINE, "container-auth : wss: Cannot retrieve" +
365                         "certificate for alias "+alias);
366                     }
367                 }
368             }
369             ccsp = new CollectionCertStoreParameters JavaDoc(list);
370             CertStore JavaDoc certstore = CertStore.getInstance("Collection", ccsp);
371             certStoreCallback.setStore(certstore);
372         } catch(KeyStoreException JavaDoc kse){
373             _logger.log(Level.FINE,
374                 "container-auth: wss : Cannot determine truststore aliases", kse);
375         } catch(InvalidAlgorithmParameterException JavaDoc iape){
376             _logger.log(Level.FINE,
377                 "container-auth: wss : Cannot instantiate CertStore", iape);
378         } catch(NoSuchAlgorithmException JavaDoc nsape){
379             _logger.log(Level.FINE,
380                 "container-auth: wss : Cannot instantiate CertStore", nsape);
381         }
382     }
383
384     private void processSecretKey(SecretKeyCallback secretKeyCallback) {
385         if (_logger.isLoggable(Level.FINE)) {
386             _logger.log(Level.FINE,
387                 "container-auth: wss : In SecretKeyCallback Processor");
388         }
389
390         KeyStore JavaDoc secretStore = SecurityUtil.getSecuritySupport().getKeyStores()[0];
391         if (secretStore == null) {
392             // cannot get any information
393
secretKeyCallback.setKey(null);
394         }
395         String JavaDoc alias = ((SecretKeyCallback.AliasRequest)secretKeyCallback.getRequest()).getAlias();
396         if (alias != null) {
397            // XXX modify SecuritySupport to get the password for the keystore
398
String JavaDoc pass = SSLUtils.getKeyStorePass();
399            try {
400                 Key JavaDoc key = secretStore.getKey(alias, pass.toCharArray());
401                 if (key instanceof SecretKey) {
402                     secretKeyCallback.setKey((SecretKey)key);
403                 } else {
404                     secretKeyCallback.setKey(null);
405                 }
406             } catch(Exception JavaDoc e) {
407                 if (_logger.isLoggable(Level.FINE)) {
408                     _logger.log(Level.FINE,
409                     "container-auth: wss : In SecretKeyCallback Processor: "+
410                     " Error reading key ! for alias "+alias, e);
411                 }
412                 secretKeyCallback.setKey(null);
413             } finally {
414                 pass = null;
415             }
416         } else {
417             // Dont bother about checking for principal
418
// we dont support that feature - typically
419
// used in an environment with kerberos
420
// Principal p = secretKeyCallback.getPrincipal();
421
secretKeyCallback.setKey(null);
422             if (_logger.isLoggable(Level.WARNING)) {
423                 _logger.log(Level.WARNING,
424                     "container-auth: wss : No support to read Principals in SecretKeyCallback");
425             }
426         }
427     }
428 }
429
Popular Tags