View Javadoc

1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements. See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership. The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License. You may obtain a copy of the License at
9    *
10   * http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied. See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  
20  package org.apache.ws.security.handler;
21  
22  import java.security.cert.X509Certificate;
23  import java.util.ArrayList;
24  import java.util.Arrays;
25  import java.util.Collection;
26  import java.util.Collections;
27  import java.util.List;
28  import java.util.Map;
29  import java.util.Properties;
30  import java.util.concurrent.ConcurrentHashMap;
31  import java.util.regex.Pattern;
32  import java.util.regex.PatternSyntaxException;
33  
34  import javax.security.auth.callback.Callback;
35  import javax.security.auth.callback.CallbackHandler;
36  
37  import org.apache.ws.security.WSConstants;
38  import org.apache.ws.security.WSEncryptionPart;
39  import org.apache.ws.security.WSPasswordCallback;
40  import org.apache.ws.security.WSSConfig;
41  import org.apache.ws.security.WSSecurityEngine;
42  import org.apache.ws.security.WSSecurityEngineResult;
43  import org.apache.ws.security.WSSecurityException;
44  import org.apache.ws.security.action.Action;
45  import org.apache.ws.security.components.crypto.AlgorithmSuite;
46  import org.apache.ws.security.components.crypto.Crypto;
47  import org.apache.ws.security.components.crypto.CryptoFactory;
48  import org.apache.ws.security.message.WSSecHeader;
49  import org.apache.ws.security.message.token.SignatureConfirmation;
50  import org.apache.ws.security.util.Loader;
51  import org.apache.ws.security.util.StringUtil;
52  import org.apache.ws.security.util.WSSecurityUtil;
53  import org.w3c.dom.Document;
54  
55  
56  /**
57   * Extracted from WSDoAllReceiver and WSDoAllSender
58   * Extended to all passwordless UsernameTokens and configurable identities.
59   *
60   * @author Davanum Srinivas (dims@yahoo.com).
61   * @author Werner Dittmann (Werner.Dittmann@t-online.de).
62   * @author Marcel Ammerlaan (marcel.ammerlaan@gmail.com).
63   */
64  public abstract class WSHandler {
65      private static org.apache.commons.logging.Log log = 
66          org.apache.commons.logging.LogFactory.getLog(WSHandler.class);
67      protected WSSecurityEngine secEngine = new WSSecurityEngine();
68      protected Map<String, Crypto> cryptos = new ConcurrentHashMap<String, Crypto>();
69  
70      private boolean doDebug = log.isDebugEnabled();
71  
72      /**                                                             
73       * Performs all defined security actions to set-up the SOAP request.
74       * 
75       * 
76       * @param doAction a set defining the actions to do 
77       * @param doc   the request as DOM document 
78       * @param reqData a data storage to pass values around between methods
79       * @param actions a list holding the actions to do in the order defined
80       *                in the deployment file or property
81       * @throws WSSecurityException
82       */
83      @SuppressWarnings("unchecked")
84      protected void doSenderAction(
85              int doAction, 
86              Document doc,
87              RequestData reqData, 
88              List<Integer> actions, 
89              boolean isRequest
90      ) throws WSSecurityException {
91  
92          boolean mu = decodeMustUnderstand(reqData);
93  
94          WSSConfig wssConfig = reqData.getWssConfig();
95          if (wssConfig == null) {
96              wssConfig = secEngine.getWssConfig();
97          }
98  
99          boolean enableSigConf = decodeEnableSignatureConfirmation(reqData);
100         wssConfig.setEnableSignatureConfirmation(
101             enableSigConf || ((doAction & WSConstants.SC) != 0)
102         );
103         wssConfig.setPasswordsAreEncoded(decodeUseEncodedPasswords(reqData));
104 
105         wssConfig.setPrecisionInMilliSeconds(
106             decodeTimestampPrecision(reqData)
107         );
108         reqData.setWssConfig(wssConfig);
109 
110         Object mc = reqData.getMsgContext();
111         String actor = getString(WSHandlerConstants.ACTOR, mc);
112         reqData.setActor(actor);
113 
114         WSSecHeader secHeader = new WSSecHeader(actor, mu);
115         secHeader.insertSecurityHeader(doc);
116 
117         reqData.setSecHeader(secHeader);
118         reqData.setSoapConstants(
119             WSSecurityUtil.getSOAPConstants(doc.getDocumentElement())
120         );
121         wssConfig.setWsiBSPCompliant(decodeBSPCompliance(reqData));
122         /*
123          * Here we have action, username, password, and actor, mustUnderstand.
124          * Now get the action specific parameters.
125          */
126         if ((doAction & WSConstants.UT) == WSConstants.UT) {
127             decodeUTParameter(reqData);
128         }
129         /*
130          * Here we have action, username, password, and actor, mustUnderstand.
131          * Now get the action specific parameters.
132          */
133         if ((doAction & WSConstants.UT_SIGN) == WSConstants.UT_SIGN) {
134             decodeUTParameter(reqData);
135             decodeSignatureParameter(reqData);
136         }
137         /*
138          * Get and check the Signature specific parameters first because they
139          * may be used for encryption too.
140          */
141         if ((doAction & WSConstants.SIGN) == WSConstants.SIGN) {
142             if (reqData.getSigCrypto() == null) {
143                 reqData.setSigCrypto(loadSignatureCrypto(reqData));
144             }
145             decodeSignatureParameter(reqData);
146         }
147         /*
148          * If we need to handle signed SAML token then we may need the
149          * Signature parameters. The handle procedure loads the signature crypto
150          * file on demand, thus don't do it here.
151          */
152         if ((doAction & WSConstants.ST_SIGNED) == WSConstants.ST_SIGNED) {
153             decodeSignatureParameter(reqData);
154         }
155         /*
156          * Set and check the encryption specific parameters, if necessary take
157          * over signature parameters username and crypto instance.
158          */
159         if ((doAction & WSConstants.ENCR) == WSConstants.ENCR) {
160             if (reqData.getEncCrypto() == null) {
161                 reqData.setEncCrypto(loadEncryptionCrypto(reqData));
162             }
163             decodeEncryptionParameter(reqData);
164         }
165         /*
166          * If after all the parsing no Signature parts defined, set here a
167          * default set. This is necessary because we add SignatureConfirmation
168          * and therefore the default (Body) must be set here. The default setting
169          * in WSSignEnvelope doesn't work because the vector is not empty anymore.
170          */
171         if (reqData.getSignatureParts().isEmpty()) {
172             WSEncryptionPart encP = new WSEncryptionPart(reqData.getSoapConstants()
173                     .getBodyQName().getLocalPart(), reqData.getSoapConstants()
174                     .getEnvelopeURI(), "Content");
175             reqData.getSignatureParts().add(encP);
176         }
177         /*
178          * If SignatureConfirmation is enabled and this is a response then
179          * insert SignatureConfirmation elements, note their wsu:id in the signature
180          * parts. They will be signed automatically during a (probably) defined
181          * SIGN action.
182          */
183         if (wssConfig.isEnableSignatureConfirmation() && !isRequest) {
184             String done = 
185                 (String)getProperty(reqData.getMsgContext(), WSHandlerConstants.SIG_CONF_DONE);
186             if (done == null) {
187                 wssConfig.getAction(WSConstants.SC).execute(this, WSConstants.SC, doc, reqData);
188             }
189         }
190         
191         // See if the Signature and Timestamp actions (in that order) are defined, and if
192         // the Timestamp is to be signed. In this case we need to swap the actions, as the 
193         // Timestamp must appear in the security header first for signature creation to work.
194         List<Integer> actionsToPerform = actions;
195         if (actions.contains(WSConstants.SIGN) && actions.contains(WSConstants.TS)
196             && (actions.indexOf(WSConstants.SIGN) < actions.indexOf(WSConstants.TS))) {
197             boolean signTimestamp = false;
198             for (WSEncryptionPart encP : reqData.getSignatureParts()) {
199                 if (WSConstants.WSU_NS.equals(encP.getNamespace()) 
200                     && "Timestamp".equals(encP.getName())) {
201                     signTimestamp = true;
202                 }
203             }
204             if (signTimestamp) {
205                 actionsToPerform = new ArrayList<Integer>(actions);
206                 Collections.copy(actionsToPerform, actions);
207                 int signatureIndex = actions.indexOf(WSConstants.SIGN);
208                 actionsToPerform.remove(signatureIndex);
209                 actionsToPerform.add(WSConstants.SIGN);
210                 reqData.setAppendSignatureAfterTimestamp(true);
211                 reqData.setOriginalSignatureActionPosition(signatureIndex);
212             }
213         }
214         
215         /*
216          * Here we have all necessary information to perform the requested
217          * action(s).
218          */
219         for (Integer actionToDo : actionsToPerform) {
220             if (doDebug) {
221                 log.debug("Performing Action: " + actionToDo);
222             }
223 
224             switch (actionToDo) {
225             case WSConstants.UT:
226             case WSConstants.ENCR:
227             case WSConstants.SIGN:
228             case WSConstants.ST_SIGNED:
229             case WSConstants.ST_UNSIGNED:
230             case WSConstants.TS:
231             case WSConstants.UT_SIGN:
232                 wssConfig.getAction(actionToDo).execute(this, actionToDo, doc, reqData);
233                 break;
234                 //
235                 // Handle any "custom" actions, similarly,
236                 // but to preserve behavior from previous
237                 // versions, consume (but log) action lookup failures.
238                 //
239             default:
240                 Action doit = null;
241             try {
242                 doit = wssConfig.getAction(actionToDo);
243             } catch (final WSSecurityException e) {
244                 log.warn(
245                         "Error trying to locate a custom action (" + actionToDo + ")", 
246                         e
247                 );
248             }
249             if (doit != null) {
250                 doit.execute(this, actionToDo, doc, reqData);
251             }
252             }
253         }
254         
255         /*
256          * If this is a request then store all signature values. Add ours to
257          * already gathered values because of chained handlers, e.g. for
258          * other actors.
259          */
260         if (wssConfig.isEnableSignatureConfirmation() 
261             && isRequest && reqData.getSignatureValues().size() > 0) {
262             List<byte[]> savedSignatures = 
263                 (List<byte[]>)getProperty(reqData.getMsgContext(), WSHandlerConstants.SEND_SIGV);
264             if (savedSignatures == null) {
265                 savedSignatures = new ArrayList<byte[]>();
266                 setProperty(
267                     reqData.getMsgContext(), WSHandlerConstants.SEND_SIGV, savedSignatures
268                 );
269             }
270             savedSignatures.addAll(reqData.getSignatureValues());
271         }
272     }
273 
274     protected void doReceiverAction(int doAction, RequestData reqData)
275         throws WSSecurityException {
276 
277         WSSConfig wssConfig = reqData.getWssConfig();
278         if (wssConfig == null) {
279             wssConfig = secEngine.getWssConfig();
280         }
281         boolean enableSigConf = decodeEnableSignatureConfirmation(reqData);
282         wssConfig.setEnableSignatureConfirmation(
283             enableSigConf || ((doAction & WSConstants.SC) != 0)
284         );
285         wssConfig.setTimeStampStrict(decodeTimestampStrict(reqData));
286         if (decodePasswordTypeStrict(reqData)) {
287             String passwordType = decodePasswordType(reqData);
288             wssConfig.setRequiredPasswordType(passwordType);
289         }
290         wssConfig.setTimeStampTTL(decodeTimeToLive(reqData, true));
291         wssConfig.setTimeStampFutureTTL(decodeFutureTimeToLive(reqData, true));
292         wssConfig.setUtTTL(decodeTimeToLive(reqData, false));
293         wssConfig.setUtFutureTTL(decodeFutureTimeToLive(reqData, false));
294         
295         wssConfig.setHandleCustomPasswordTypes(decodeCustomPasswordTypes(reqData));
296         wssConfig.setPasswordsAreEncoded(decodeUseEncodedPasswords(reqData));
297         wssConfig.setAllowNamespaceQualifiedPasswordTypes(
298             decodeNamespaceQualifiedPasswordTypes(reqData)
299         );
300         wssConfig.setAllowUsernameTokenNoPassword(
301             decodeAllowUsernameTokenNoPassword(reqData)
302         );
303         
304         wssConfig.setSecretKeyLength(reqData.getSecretKeyLength());
305         wssConfig.setWsiBSPCompliant(decodeBSPCompliance(reqData));
306         reqData.setWssConfig(wssConfig);
307 
308         if (((doAction & WSConstants.SIGN) == WSConstants.SIGN)
309             || ((doAction & WSConstants.ST_SIGNED) == WSConstants.ST_SIGNED)
310             || ((doAction & WSConstants.ST_UNSIGNED) == WSConstants.ST_UNSIGNED)) {
311             decodeSignatureParameter2(reqData);
312         }
313         
314         if ((doAction & WSConstants.ENCR) == WSConstants.ENCR) {
315             decodeDecryptionParameter(reqData);
316         }
317         decodeRequireSignedEncryptedDataElements(reqData);
318     }
319 
320     protected boolean checkReceiverResults(
321         List<WSSecurityEngineResult> wsResult, List<Integer> actions
322     ) {
323         int size = actions.size();
324         int ai = 0;
325         for (WSSecurityEngineResult result : wsResult) {
326             final Integer actInt = (Integer) result.get(WSSecurityEngineResult.TAG_ACTION);
327             int act = actInt.intValue();
328             if (act == WSConstants.SC || act == WSConstants.BST) {
329                 continue;
330             }
331             
332             if (ai >= size || actions.get(ai++).intValue() != act) {
333                 return false;
334             }
335         }
336 
337         if (ai != size) {
338             return false;
339         }
340 
341         return true;
342     }
343     
344     protected boolean checkReceiverResultsAnyOrder(
345         List<WSSecurityEngineResult> wsResult, List<Integer> actions
346     ) {
347         List<Integer> recordedActions = new ArrayList<Integer>(actions.size());
348         for (Integer action : actions) {
349             recordedActions.add(action);
350         }
351         
352         for (WSSecurityEngineResult result : wsResult) {
353             final Integer actInt = (Integer) result.get(WSSecurityEngineResult.TAG_ACTION);
354             int act = actInt.intValue();
355             if (act == WSConstants.SC || act == WSConstants.BST) {
356                 continue;
357             }
358             
359             if (!recordedActions.remove(actInt)) {
360                 return false;
361             }
362         }
363 
364         if (!recordedActions.isEmpty()) {
365             return false;
366         }
367 
368         return true;
369     }
370 
371     @SuppressWarnings("unchecked")
372     protected void checkSignatureConfirmation(
373         RequestData reqData,
374         List<WSSecurityEngineResult> resultList
375     ) throws WSSecurityException{
376         if (doDebug) {
377             log.debug("Check Signature confirmation");
378         }
379         //
380         // First get all Signature values stored during sending the request
381         //
382         List<byte[]> savedSignatures = 
383             (List<byte[]>) getProperty(reqData.getMsgContext(), WSHandlerConstants.SEND_SIGV);
384         //
385         // Now get all results that hold a SignatureConfirmation element from
386         // the current run of receiver (we can have more than one run: if we
387         // have several security header blocks with different actors/roles)
388         //
389         List<WSSecurityEngineResult> sigConf = new ArrayList<WSSecurityEngineResult>();
390         WSSecurityUtil.fetchAllActionResults(resultList, WSConstants.SC, sigConf);
391         //
392         // now loop over all SignatureConfirmation results and check:
393         // - if there is a signature value and no Signature value generated in request: error
394         // - if there is a signature value and no matching Signature value found: error
395         // 
396         //  If a matching value found: remove from vector of stored signature values
397         //
398         for (WSSecurityEngineResult result : sigConf) {
399             SignatureConfirmation sc = 
400                 (SignatureConfirmation)result.get(
401                     WSSecurityEngineResult.TAG_SIGNATURE_CONFIRMATION
402                 );
403 
404             byte[] sigVal = sc.getSignatureValue();
405             if (sigVal != null) {
406                 if (savedSignatures == null || savedSignatures.size() == 0) {
407                     //
408                     // If there are no stored signature values, and we've received a 
409                     // SignatureConfirmation element then throw an Exception
410                     //
411                     if (sigVal.length != 0) {
412                         throw new WSSecurityException(
413                             "Received a SignatureConfirmation element, but there are no stored"
414                              + " signature values"
415                         );
416                     }
417                 } else {
418                     boolean found = false;
419                     for (int j = 0; j < savedSignatures.size(); j++) {
420                         byte[] storedValue = (byte[]) savedSignatures.get(j);
421                         if (Arrays.equals(sigVal, storedValue)) {
422                             found = true;
423                             savedSignatures.remove(j);
424                             break;
425                         }
426                     }
427                     if (!found) {
428                         throw new WSSecurityException(
429                             "Received a SignatureConfirmation element, but there are no matching"
430                             + " stored signature values"
431                         );
432                     } 
433                 }
434             }
435         }
436 
437         //
438         // This indicates this is the last handler: the list holding the
439         // stored Signature values must be empty, otherwise we have an error
440         //
441         if (!reqData.isNoSerialization()) {
442             if (doDebug) {
443                 log.debug("Check Signature confirmation - last handler");
444             }
445             if (savedSignatures != null && !savedSignatures.isEmpty()) {
446                 throw new WSSecurityException(
447                     "Check Signature confirmation: the stored signature values list is not empty"
448                 );
449             }
450         }
451     }
452     
453     protected void decodeUTParameter(RequestData reqData) 
454         throws WSSecurityException {
455         Object mc = reqData.getMsgContext();
456         
457         String type = getString(WSHandlerConstants.PASSWORD_TYPE, mc);
458         if (type != null) {
459             if (WSConstants.PW_TEXT.equals(type)) {
460                 reqData.setPwType(WSConstants.PASSWORD_TEXT);
461             } else if (WSConstants.PW_DIGEST.equals(type)) {
462                 reqData.setPwType(WSConstants.PASSWORD_DIGEST);
463             } else if (WSConstants.PW_NONE.equals(type)) {
464                 reqData.setPwType(null);
465             } else {
466                 throw new WSSecurityException("Unknown password type encoding: " + type);
467             }
468         }
469         
470         String add = getString(WSHandlerConstants.ADD_UT_ELEMENTS, mc);
471         if (add != null) {
472             reqData.setUtElements(StringUtil.split(add, ' '));
473         }
474         
475         String derived = getString(WSHandlerConstants.USE_DERIVED_KEY, mc);
476         if (derived != null) {
477             boolean useDerivedKey = Boolean.parseBoolean(derived);
478             reqData.setUseDerivedKey(useDerivedKey);
479         }
480         
481         String derivedMAC = getString(WSHandlerConstants.USE_DERIVED_KEY_FOR_MAC, mc);
482         boolean useDerivedKeyForMAC = Boolean.parseBoolean(derivedMAC);
483         if (useDerivedKeyForMAC) {
484             reqData.setUseDerivedKeyForMAC(useDerivedKeyForMAC);
485         }
486         
487         String iterations = getString(WSHandlerConstants.DERIVED_KEY_ITERATIONS, mc);
488         if (iterations != null) {
489             int iIterations = Integer.parseInt(iterations);
490             reqData.setDerivedKeyIterations(iIterations);
491         }
492     }
493 
494     protected void decodeSignatureParameter(RequestData reqData) 
495         throws WSSecurityException {
496         Object mc = reqData.getMsgContext();
497         String signatureUser = getString(WSHandlerConstants.SIGNATURE_USER, mc);
498 
499         if (signatureUser != null) {
500             reqData.setSignatureUser(signatureUser);
501         } else {
502             reqData.setSignatureUser(reqData.getUsername());
503         }
504         
505         String keyId = getString(WSHandlerConstants.SIG_KEY_ID, mc);
506         if (keyId != null) {
507             Integer id = (Integer) WSHandlerConstants.getKeyIdentifier(keyId);
508             if (id == null) {
509                 throw new WSSecurityException(
510                     "WSHandler: Signature: unknown key identification"
511                 );
512             }
513             int tmp = id.intValue();
514             if (!(tmp == WSConstants.ISSUER_SERIAL
515                     || tmp == WSConstants.BST_DIRECT_REFERENCE
516                     || tmp == WSConstants.X509_KEY_IDENTIFIER
517                     || tmp == WSConstants.SKI_KEY_IDENTIFIER
518                     || tmp == WSConstants.THUMBPRINT_IDENTIFIER
519                     || tmp == WSConstants.ENCRYPTED_KEY_SHA1_IDENTIFIER
520                     || tmp == WSConstants.KEY_VALUE)) {
521                 throw new WSSecurityException(
522                     "WSHandler: Signature: illegal key identification"
523                 );
524             }
525             reqData.setSigKeyId(tmp);
526         }
527         String algo = getString(WSHandlerConstants.SIG_ALGO, mc);
528         reqData.setSigAlgorithm(algo);
529         
530         String digestAlgo = getString(WSHandlerConstants.SIG_DIGEST_ALGO, mc);
531         reqData.setSigDigestAlgorithm(digestAlgo);
532 
533         String parts = getString(WSHandlerConstants.SIGNATURE_PARTS, mc);
534         if (parts != null) {
535             splitEncParts(parts, reqData.getSignatureParts(), reqData);
536         }
537         
538         String secretKeyLength = getString(WSHandlerConstants.WSE_SECRET_KEY_LENGTH, mc);
539         if (secretKeyLength != null) {
540             int iSecretKeyLength = Integer.parseInt(secretKeyLength);
541             reqData.setSecretKeyLength(iSecretKeyLength);
542         }
543         
544         boolean useSingleCert = decodeUseSingleCertificate(reqData);
545         reqData.setUseSingleCert(useSingleCert);
546     }
547 
548     protected void decodeAlgorithmSuite(RequestData reqData) throws WSSecurityException {
549         Object mc = reqData.getMsgContext();
550         if (mc == null || reqData.getAlgorithmSuite() != null) {
551             return;
552         }
553         
554         AlgorithmSuite algorithmSuite = new AlgorithmSuite();
555         
556         String signatureAlgorithm = getString(WSHandlerConstants.SIG_ALGO, mc);
557         if (signatureAlgorithm != null && !"".equals(signatureAlgorithm)) {
558             algorithmSuite.addSignatureMethod(signatureAlgorithm);
559         }
560         String signatureDigestAlgorithm = getString(WSHandlerConstants.SIG_DIGEST_ALGO, mc);
561         if (signatureDigestAlgorithm != null && !"".equals(signatureDigestAlgorithm)) {
562             algorithmSuite.addDigestAlgorithm(signatureDigestAlgorithm);
563         }
564         
565         String encrAlgorithm = getString(WSHandlerConstants.ENC_SYM_ALGO, mc);
566         if (encrAlgorithm != null && !"".equals(encrAlgorithm)) {
567             algorithmSuite.addEncryptionMethod(encrAlgorithm);
568         }
569         String transportAlgorithm = getString(WSHandlerConstants.ENC_KEY_TRANSPORT, mc);
570         if (transportAlgorithm != null && !"".equals(transportAlgorithm)) {
571             algorithmSuite.addKeyWrapAlgorithm(transportAlgorithm);
572         }
573         
574         reqData.setAlgorithmSuite(algorithmSuite);
575     }
576     
577     protected void decodeEncryptionParameter(RequestData reqData) 
578         throws WSSecurityException {
579         Object mc = reqData.getMsgContext();
580 
581         /*
582          * If the following parameters are no used (they return null) then the
583          * default values of WSS4J are used.
584          */
585         String encKeyId = getString(WSHandlerConstants.ENC_KEY_ID, mc);
586         if (encKeyId != null) {
587             Integer id = (Integer) WSHandlerConstants.getKeyIdentifier(encKeyId);
588             if (id == null) {
589                 throw new WSSecurityException(
590                     "WSHandler: Encryption: unknown key identification"
591                 );
592             }
593             int tmp = id.intValue();
594             reqData.setEncKeyId(tmp);
595             if (!(tmp == WSConstants.ISSUER_SERIAL
596                     || tmp == WSConstants.X509_KEY_IDENTIFIER
597                     || tmp == WSConstants.SKI_KEY_IDENTIFIER
598                     || tmp == WSConstants.BST_DIRECT_REFERENCE
599                     || tmp == WSConstants.EMBEDDED_KEYNAME
600                     || tmp == WSConstants.THUMBPRINT_IDENTIFIER
601                     || tmp == WSConstants.ENCRYPTED_KEY_SHA1_IDENTIFIER)) {
602                 throw new WSSecurityException(
603                     "WSHandler: Encryption: illegal key identification"
604                 );
605             }
606         }
607         String encSymAlgo = getString(WSHandlerConstants.ENC_SYM_ALGO, mc);
608         reqData.setEncSymmAlgo(encSymAlgo);
609 
610         String encKeyTransport = 
611             getString(WSHandlerConstants.ENC_KEY_TRANSPORT, mc);
612         reqData.setEncKeyTransport(encKeyTransport);
613         
614         String digestAlgo = getString(WSHandlerConstants.ENC_DIGEST_ALGO, mc);
615         reqData.setEncDigestAlgorithm(digestAlgo);
616         
617         String encSymEncKey = getString(WSHandlerConstants.ENC_SYM_ENC_KEY, mc);
618         if (encSymEncKey != null) {
619             boolean encSymEndKeyBoolean = Boolean.parseBoolean(encSymEncKey);
620             reqData.setEncryptSymmetricEncryptionKey(encSymEndKeyBoolean);
621         }
622         
623         String encUser = getString(WSHandlerConstants.ENCRYPTION_USER, mc);
624         if (encUser != null) {
625             reqData.setEncUser(encUser);
626         } else {
627             reqData.setEncUser(reqData.getUsername());
628         }
629         if (reqData.getEncryptSymmetricEncryptionKey() && reqData.getEncUser() == null) {
630             throw new WSSecurityException("WSHandler: Encryption: no username");
631         }
632         /*
633          * String msgType = msgContext.getCurrentMessage().getMessageType(); if
634          * (msgType != null && msgType.equals(Message.RESPONSE)) {
635          * handleSpecialUser(encUser); }
636          */
637         handleSpecialUser(reqData);
638 
639         String encParts = getString(WSHandlerConstants.ENCRYPTION_PARTS, mc);
640         if (encParts != null) {
641             splitEncParts(encParts, reqData.getEncryptParts(), reqData);
642         }
643     }
644 
645     /**
646      * Decode the TimeToLive parameter for either a Timestamp or a UsernameToken Created element,
647      * depending on the boolean argument
648      */
649     public int decodeTimeToLive(RequestData reqData, boolean timestamp) {
650         String tag = WSHandlerConstants.TTL_TIMESTAMP;
651         if (!timestamp) {
652             tag = WSHandlerConstants.TTL_USERNAMETOKEN;
653         }
654         String ttl = getString(tag, reqData.getMsgContext());
655         int defaultTimeToLive = 300;
656         if (ttl != null) {
657             try {
658                 int ttlI = Integer.parseInt(ttl);
659                 if (ttlI < 0) {
660                     return defaultTimeToLive;
661                 }
662                 return ttlI;
663             } catch (NumberFormatException e) {
664                 return defaultTimeToLive;
665             }
666         }
667         return defaultTimeToLive;
668     }
669     
670     /**
671      * Decode the FutureTimeToLive parameter for either a Timestamp or a UsernameToken Created 
672      * element, depending on the boolean argument
673      */
674     protected int decodeFutureTimeToLive(RequestData reqData, boolean timestamp) {
675         String tag = WSHandlerConstants.TTL_FUTURE_TIMESTAMP;
676         if (!timestamp) {
677             tag = WSHandlerConstants.TTL_FUTURE_USERNAMETOKEN;
678         }
679         String ttl = getString(tag, reqData.getMsgContext());
680         int defaultFutureTimeToLive = 60;
681         if (ttl != null) {
682             try {
683                 int ttlI = Integer.parseInt(ttl);
684                 if (ttlI < 0) {
685                     return defaultFutureTimeToLive;
686                 }
687                 return ttlI;
688             } catch (NumberFormatException e) {
689                 return defaultFutureTimeToLive;
690             }
691         }
692         return defaultFutureTimeToLive;
693     }
694     
695     protected boolean decodeBSPCompliance(RequestData reqData)
696         throws WSSecurityException {
697         return decodeBooleanConfigValue(
698             reqData, WSHandlerConstants.IS_BSP_COMPLIANT, true
699         );
700     }
701     
702     protected String decodePasswordType(RequestData reqData) throws WSSecurityException {
703         String type = getString(WSHandlerConstants.PASSWORD_TYPE, reqData.getMsgContext());
704         if (type != null) {
705             if (WSConstants.PW_TEXT.equals(type)) {
706                 return WSConstants.PASSWORD_TEXT;
707             } else if (WSConstants.PW_DIGEST.equals(type)) {
708                 return WSConstants.PASSWORD_DIGEST;
709             }
710         }
711         return null;
712     }
713     
714     protected boolean decodeMustUnderstand(RequestData reqData) 
715         throws WSSecurityException {
716         return decodeBooleanConfigValue(
717             reqData, WSHandlerConstants.MUST_UNDERSTAND, true
718         );
719     }
720 
721     protected boolean decodeEnableSignatureConfirmation(
722         RequestData reqData
723     ) throws WSSecurityException {
724         return decodeBooleanConfigValue(
725             reqData, WSHandlerConstants.ENABLE_SIGNATURE_CONFIRMATION, false
726         );
727     }
728     
729     protected boolean decodeTimestampPrecision(
730         RequestData reqData
731     ) throws WSSecurityException {
732         return decodeBooleanConfigValue(
733             reqData, WSHandlerConstants.TIMESTAMP_PRECISION, true
734         );
735     }
736     
737     protected boolean decodeCustomPasswordTypes(
738         RequestData reqData
739     ) throws WSSecurityException {
740         return decodeBooleanConfigValue(
741             reqData, WSHandlerConstants.HANDLE_CUSTOM_PASSWORD_TYPES, false
742         );
743     }
744     
745     protected boolean decodeAllowUsernameTokenNoPassword(
746         RequestData reqData
747         ) throws WSSecurityException {
748         return decodeBooleanConfigValue(
749             reqData, WSHandlerConstants.ALLOW_USERNAMETOKEN_NOPASSWORD, false
750         );
751     }
752 
753     protected boolean decodeUseEncodedPasswords(RequestData reqData) 
754         throws WSSecurityException {
755         return decodeBooleanConfigValue(
756             reqData, WSHandlerConstants.USE_ENCODED_PASSWORDS, false
757         );
758     }
759     
760     protected boolean decodeNamespaceQualifiedPasswordTypes(RequestData reqData) 
761         throws WSSecurityException {
762         return decodeBooleanConfigValue(
763             reqData, WSHandlerConstants.ALLOW_NAMESPACE_QUALIFIED_PASSWORD_TYPES, false
764         );
765     }
766 
767     protected boolean decodeTimestampStrict(RequestData reqData) 
768         throws WSSecurityException {
769         return decodeBooleanConfigValue(
770             reqData, WSHandlerConstants.TIMESTAMP_STRICT, true
771         );
772     }
773     
774     protected boolean decodePasswordTypeStrict(RequestData reqData) 
775         throws WSSecurityException {
776         return decodeBooleanConfigValue(
777             reqData, WSHandlerConstants.PASSWORD_TYPE_STRICT, false
778         );
779     }
780     
781     protected boolean decodeUseSingleCertificate(RequestData reqData) 
782         throws WSSecurityException {
783         return decodeBooleanConfigValue(
784             reqData, WSHandlerConstants.USE_SINGLE_CERTIFICATE, true
785         );
786     }
787     
788     protected void decodeRequireSignedEncryptedDataElements(RequestData reqData) 
789         throws WSSecurityException {
790         reqData.setRequireSignedEncryptedDataElements(decodeBooleanConfigValue(
791             reqData, WSHandlerConstants.REQUIRE_SIGNED_ENCRYPTED_DATA_ELEMENTS, false
792         ));
793     }
794 
795     protected boolean decodeBooleanConfigValue(
796         RequestData reqData, String configTag, boolean defaultToTrue
797     ) throws WSSecurityException {
798 
799         String value = getString(configTag, reqData.getMsgContext());
800 
801         if (value == null) {
802             return defaultToTrue;
803         }
804         if ("0".equals(value) || "false".equals(value)) {
805             return false;
806         } 
807         if ("1".equals(value) || "true".equals(value)) {
808             return true;
809         }
810 
811         throw new WSSecurityException(
812             "WSHandler: illegal " + configTag + " parameter"
813         );
814     }
815     
816     /**
817      * Hook to allow subclasses to load their Signature Crypto however they see
818      * fit. 
819      * 
820      * @param requestData the RequestData object
821      * @return a Crypto instance to use for Signature creation/verification
822      */
823     public Crypto loadSignatureCrypto(RequestData requestData) throws WSSecurityException {
824         return 
825             loadCrypto(
826                 WSHandlerConstants.SIG_PROP_FILE,
827                 WSHandlerConstants.SIG_PROP_REF_ID,
828                 requestData
829             );
830     }
831     
832     /**
833      * Hook to allow subclasses to load their Decryption Crypto however they see
834      * fit. 
835      * 
836      * @param requestData the RequestData object
837      * @return a Crypto instance to use for Decryption creation/verification
838      */
839     protected Crypto loadDecryptionCrypto(RequestData requestData) throws WSSecurityException {
840         return 
841             loadCrypto(
842                 WSHandlerConstants.DEC_PROP_FILE,
843                 WSHandlerConstants.DEC_PROP_REF_ID,
844                 requestData
845             );
846     }
847     
848     /**
849      * Hook to allow subclasses to load their Encryption Crypto however they see
850      * fit. 
851      * 
852      * @param requestData the RequestData object
853      * @return a Crypto instance to use for Encryption creation/verification
854      */
855     protected Crypto loadEncryptionCrypto(RequestData requestData) throws WSSecurityException {
856         return 
857             loadCrypto(
858                 WSHandlerConstants.ENC_PROP_FILE,
859                 WSHandlerConstants.ENC_PROP_REF_ID,
860                 requestData
861             );
862     }
863     
864     /**
865      * Load a Crypto instance. Firstly, it tries to use the cryptoPropertyRefId tag to retrieve
866      * a Crypto object via a custom reference Id. Failing this, it tries to load the crypto 
867      * instance via the cryptoPropertyFile tag.
868      * 
869      * @param requestData the RequestData object
870      * @return a Crypto instance to use for Encryption creation/verification
871      */
872     protected Crypto loadCrypto(
873         String cryptoPropertyFile,
874         String cryptoPropertyRefId,
875         RequestData requestData
876     ) throws WSSecurityException {
877         Object mc = requestData.getMsgContext();
878         Crypto crypto = null;
879         
880         //
881         // Try the Property Ref Id first
882         //
883         String refId = getString(cryptoPropertyRefId, mc);
884         if (refId != null) {
885             crypto = cryptos.get(refId);
886             if (crypto == null) {
887                 Object obj = getProperty(mc, refId);
888                 if (obj instanceof Properties) {
889                     crypto = CryptoFactory.getInstance((Properties)obj);
890                     cryptos.put(refId, crypto);
891                 } else if (obj instanceof Crypto) {
892                     crypto = (Crypto)obj;
893                     cryptos.put(refId, crypto);
894                 }
895             }
896         }
897         
898         //
899         // Now try loading the properties file
900         //
901         if (crypto == null) {
902             String propFile = getString(cryptoPropertyFile, mc);
903             if (propFile != null) {
904                 crypto = cryptos.get(propFile);
905                 if (crypto == null) {
906                     crypto = loadCryptoFromPropertiesFile(propFile, requestData);
907                     cryptos.put(propFile, crypto);
908                 }
909             } 
910         }
911         return crypto;
912     }
913 
914     /**
915      * A hook to allow subclass to load Crypto instances from property files in a different
916      * way.
917      * @param propFilename The property file name
918      * @param reqData The RequestData object
919      * @return A Crypto instance that has been loaded
920      */
921     protected Crypto loadCryptoFromPropertiesFile(
922         String propFilename, 
923         RequestData reqData
924     ) throws WSSecurityException {
925         return 
926             CryptoFactory.getInstance(
927                 propFilename, this.getClassLoader(reqData.getMsgContext())
928             );
929     }
930 
931     /**
932      * Get a CallbackHandler instance. First try to get an instance via the 
933      * callbackHandlerRef on the message context. Failing that, try to load a new 
934      * instance of the CallbackHandler via the callbackHandlerClass argument.
935      * 
936      * @param callbackHandlerClass The class name of the CallbackHandler instance
937      * @param callbackHandlerRef The reference name of the CallbackHandler instance
938      * @param requestData The RequestData which supplies the message context
939      * @return a CallbackHandler instance
940      * @throws WSSecurityException
941      */
942     public CallbackHandler getCallbackHandler(
943         String callbackHandlerClass,
944         String callbackHandlerRef,
945         RequestData requestData
946     ) throws WSSecurityException {
947         Object mc = requestData.getMsgContext();
948         CallbackHandler cbHandler = (CallbackHandler) getOption(callbackHandlerRef);
949         if (cbHandler == null) {
950             cbHandler = (CallbackHandler) getProperty(mc, callbackHandlerRef);
951         }
952         if (cbHandler == null) {
953             String callback = getString(callbackHandlerClass, mc);
954             if (callback != null) {
955                 cbHandler = loadCallbackHandler(callback, requestData);
956             }
957         }
958         return cbHandler;
959     }
960     
961     /**
962      * Get a CallbackHandler instance to obtain passwords.
963      * @param reqData The RequestData which supplies the message context
964      * @return the CallbackHandler instance to obtain passwords.
965      * @throws WSSecurityException
966      */
967     public CallbackHandler getPasswordCallbackHandler(RequestData reqData) 
968         throws WSSecurityException {
969         return 
970             getCallbackHandler(
971                 WSHandlerConstants.PW_CALLBACK_CLASS,
972                 WSHandlerConstants.PW_CALLBACK_REF,
973                 reqData
974             );
975     }
976     
977     /**
978      * Load a CallbackHandler instance.
979      * @param callbackHandlerClass The class name of the CallbackHandler instance
980      * @param requestData The RequestData which supplies the message context
981      * @return a CallbackHandler instance
982      * @throws WSSecurityException
983      */
984     private CallbackHandler loadCallbackHandler(
985         String callbackHandlerClass,
986         RequestData requestData
987     ) throws WSSecurityException {
988 
989         Class<? extends CallbackHandler> cbClass = null;
990         CallbackHandler cbHandler = null;
991         try {
992             cbClass = 
993                 Loader.loadClass(getClassLoader(requestData.getMsgContext()), 
994                                  callbackHandlerClass,
995                                  CallbackHandler.class);
996         } catch (ClassNotFoundException e) {
997             throw new WSSecurityException(
998                 "WSHandler: cannot load callback handler class: " + callbackHandlerClass, e
999             );
1000         }
1001         try {
1002             cbHandler = (CallbackHandler) cbClass.newInstance();
1003         } catch (Exception e) {
1004             throw new WSSecurityException(
1005                 "WSHandler: cannot create instance of callback handler: " + callbackHandlerClass, e
1006             );
1007         }
1008         return cbHandler;
1009     }
1010     
1011     /**
1012      * Get a password callback (WSPasswordCallback object) from a CallbackHandler instance
1013      * @param username The username to supply to the CallbackHandler
1014      * @param doAction The action to perform
1015      * @param callbackHandler The CallbackHandler instance
1016      * @param requestData The RequestData which supplies the message context
1017      * @return the WSPasswordCallback object containing the password
1018      * @throws WSSecurityException
1019      */
1020     public WSPasswordCallback getPasswordCB(
1021          String username,
1022          int doAction,
1023          CallbackHandler callbackHandler,
1024          RequestData requestData
1025     ) throws WSSecurityException {
1026         
1027         if (callbackHandler != null) { 
1028             return performPasswordCallback(callbackHandler, username, doAction);
1029         } else {
1030             //
1031             // If a callback isn't configured then try to get the password
1032             // from the message context
1033             //
1034             String password = getPassword(requestData.getMsgContext());
1035             if (password == null) {
1036                 String err = "provided null or empty password";
1037                 throw new WSSecurityException("WSHandler: application " + err);
1038             }
1039             WSPasswordCallback pwCb = constructPasswordCallback(username, doAction);
1040             pwCb.setPassword(password);
1041             return pwCb;
1042         }
1043     }
1044 
1045     /**
1046      * Perform a callback on a CallbackHandler instance
1047      * @param cbHandler the CallbackHandler instance
1048      * @param username The username to supply to the CallbackHandler
1049      * @param doAction The action to perform
1050      * @return a WSPasswordCallback instance
1051      * @throws WSSecurityException
1052      */
1053     private WSPasswordCallback performPasswordCallback(
1054         CallbackHandler cbHandler,
1055         String username,
1056         int doAction
1057     ) throws WSSecurityException {
1058 
1059         WSPasswordCallback pwCb = constructPasswordCallback(username, doAction);
1060         Callback[] callbacks = new Callback[1];
1061         callbacks[0] = pwCb;
1062         //
1063         // Call back the application to get the password
1064         //
1065         try {
1066             cbHandler.handle(callbacks);
1067         } catch (Exception e) {
1068             throw new WSSecurityException("WSHandler: password callback failed", e);
1069         }
1070         return pwCb;
1071     }
1072 
1073     /**
1074      * Construct a WSPasswordCallback instance
1075      * @param username The username
1076      * @param doAction The action to perform
1077      * @return a WSPasswordCallback instance
1078      * @throws WSSecurityException
1079      */
1080     private WSPasswordCallback constructPasswordCallback(
1081         String username,
1082         int doAction
1083     ) throws WSSecurityException {
1084 
1085         int reason = WSPasswordCallback.UNKNOWN;
1086 
1087         switch (doAction) {
1088         case WSConstants.UT:
1089         case WSConstants.UT_SIGN:
1090             reason = WSPasswordCallback.USERNAME_TOKEN;
1091             break;
1092         case WSConstants.SIGN:
1093             reason = WSPasswordCallback.SIGNATURE;
1094             break;
1095         case WSConstants.ENCR:
1096             reason = WSPasswordCallback.SECRET_KEY;
1097             break;
1098         }
1099         return new WSPasswordCallback(username, reason);
1100     }
1101 
1102     private void splitEncParts(String tmpS, List<WSEncryptionPart> parts, RequestData reqData)
1103         throws WSSecurityException {
1104         WSEncryptionPart encPart = null;
1105         String[] rawParts = StringUtil.split(tmpS, ';');
1106 
1107         for (int i = 0; i < rawParts.length; i++) {
1108             String[] partDef = StringUtil.split(rawParts[i], '}');
1109 
1110             if (partDef.length == 1) {
1111                 if (doDebug) {
1112                     log.debug("single partDef: '" + partDef[0] + "'");
1113                 }
1114                 encPart =
1115                     new WSEncryptionPart(partDef[0].trim(),
1116                             reqData.getSoapConstants().getEnvelopeURI(),
1117                             "Content");
1118             } else if (partDef.length == 3) {
1119                 String mode = partDef[0].trim();
1120                 if (mode.length() <= 1) {
1121                     mode = "Content";
1122                 } else {
1123                     mode = mode.substring(1);
1124                 }
1125                 String nmSpace = partDef[1].trim();
1126                 if (nmSpace.length() <= 1) {
1127                     nmSpace = reqData.getSoapConstants().getEnvelopeURI();
1128                 } else {
1129                     nmSpace = nmSpace.substring(1);
1130                     if (nmSpace.equals(WSConstants.NULL_NS)) {
1131                         nmSpace = null;
1132                     }
1133                 }
1134                 String element = partDef[2].trim();
1135                 if (doDebug) {
1136                     log.debug(
1137                         "partDefs: '" + mode + "' ,'" + nmSpace + "' ,'" + element + "'"
1138                     );
1139                 }
1140                 encPart = new WSEncryptionPart(element, nmSpace, mode);
1141             } else {
1142                 throw new WSSecurityException("WSHandler: wrong part definition: " + tmpS);
1143             }
1144             parts.add(encPart);
1145         }
1146     }
1147 
1148     @SuppressWarnings("unchecked")
1149     private void handleSpecialUser(RequestData reqData) {
1150         if (!WSHandlerConstants.USE_REQ_SIG_CERT.equals(reqData.getEncUser())) {
1151             return;
1152         }
1153         List<WSHandlerResult> results = 
1154             (List<WSHandlerResult>) getProperty(
1155                 reqData.getMsgContext(), WSHandlerConstants.RECV_RESULTS
1156             );
1157         if (results == null) {
1158             return;
1159         }
1160         /*
1161          * Scan the results for a matching actor. Use results only if the
1162          * receiving Actor and the sending Actor match.
1163          */
1164         for (WSHandlerResult rResult : results) {
1165             String hActor = rResult.getActor();
1166             if (!WSSecurityUtil.isActorEqual(reqData.getActor(), hActor)) {
1167                 continue;
1168             }
1169             List<WSSecurityEngineResult> wsSecEngineResults = rResult.getResults();
1170             /*
1171              * Scan the results for the first Signature action. Use the
1172              * certificate of this Signature to set the certificate for the
1173              * encryption action :-).
1174              */
1175             for (WSSecurityEngineResult wser : wsSecEngineResults) {
1176                 int wserAction = 
1177                     ((java.lang.Integer)wser.get(WSSecurityEngineResult.TAG_ACTION)).intValue();
1178                 if (wserAction == WSConstants.SIGN) {
1179                     X509Certificate cert = 
1180                         (X509Certificate)wser.get(WSSecurityEngineResult.TAG_X509_CERTIFICATE);
1181                     reqData.setEncCert(cert);
1182                     return;
1183                 }
1184             }
1185         }
1186     }
1187 
1188     protected void decodeSignatureParameter2(RequestData reqData) 
1189         throws WSSecurityException {
1190         if (reqData.getSigCrypto() == null) {
1191             reqData.setSigCrypto(loadSignatureCrypto(reqData));
1192         }
1193         boolean enableRevocation = 
1194             decodeBooleanConfigValue(
1195                 reqData, WSHandlerConstants.ENABLE_REVOCATION, false
1196             );
1197         reqData.setEnableRevocation(enableRevocation);
1198         
1199         String certConstraints = 
1200             getString(WSHandlerConstants.SIG_SUBJECT_CERT_CONSTRAINTS, reqData.getMsgContext());
1201         if (certConstraints != null) {
1202             String[] certConstraintsList = certConstraints.split(",");
1203             if (certConstraintsList != null) {
1204                 Collection<Pattern> subjectCertConstraints = 
1205                     new ArrayList<Pattern>(certConstraintsList.length);
1206                 for (String certConstraint : certConstraintsList) {
1207                     try {
1208                         subjectCertConstraints.add(Pattern.compile(certConstraint.trim()));
1209                     } catch (PatternSyntaxException ex) {
1210                         log.debug(ex.getMessage(), ex);
1211                         throw new WSSecurityException(ex.getMessage(), ex);
1212                     }
1213                 }
1214                 reqData.setSubjectCertConstraints(subjectCertConstraints);
1215             }
1216         }
1217     }
1218 
1219     /*
1220      * Set and check the decryption specific parameters, if necessary
1221      * take over signature crypto instance.
1222      */
1223     protected void decodeDecryptionParameter(RequestData reqData) 
1224         throws WSSecurityException {
1225         if (reqData.getDecCrypto() == null) {
1226             reqData.setDecCrypto(loadDecryptionCrypto(reqData));
1227         }
1228     }
1229 
1230     /**
1231      * Looks up key first via {@link #getOption(String)} and if not found
1232      * there, via {@link #getProperty(Object, String)}
1233      *
1234      * @param key the key to search for. May not be null.
1235      * @param mc the message context to search. 
1236      * @return the value found.
1237      * @throws IllegalArgumentException if <code>key</code> is null.
1238      */
1239     public String getString(String key, Object mc) { 
1240         if (key == null) {
1241             throw new IllegalArgumentException("Key cannot be null");
1242         }
1243         String s = getStringOption(key);
1244         if (s != null) {
1245             return s;
1246         }
1247         if (mc == null) {
1248             throw new IllegalArgumentException("Message context cannot be null");
1249         }
1250         return (String) getProperty(mc, key);
1251     }
1252 
1253 
1254     /**
1255      * Returns the option on <code>name</code>.
1256      *
1257      * @param key the non-null key of the option.
1258      * @return the option on <code>key</code> if <code>key</code>
1259      *  exists and is of type java.lang.String; otherwise null.
1260      */
1261     public String getStringOption(String key) {
1262         Object o = getOption(key);
1263         if (o instanceof String){
1264             return (String) o;
1265         } else {
1266             return null;
1267         }
1268     }
1269 
1270     /**
1271      * Returns the classloader to be used for loading the callback class
1272      * @param msgCtx The MessageContext 
1273      * @return class loader
1274      */
1275     public ClassLoader getClassLoader(Object msgCtx) {
1276         try {
1277             return Loader.getTCL();
1278         } catch (Exception ex) {
1279             return null;
1280         }
1281     }
1282 
1283     public abstract Object getOption(String key);
1284     public abstract Object getProperty(Object msgContext, String key);
1285 
1286     public abstract void setProperty(Object msgContext, String key, 
1287             Object value);
1288 
1289 
1290     public abstract String getPassword(Object msgContext);
1291 
1292     public abstract void setPassword(Object msgContext, String password);
1293 }