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.wss4j.dom.handler;
21  
22  import java.security.cert.X509Certificate;
23  import java.util.*;
24  import java.util.concurrent.ConcurrentHashMap;
25  import java.util.regex.Pattern;
26  import java.util.regex.PatternSyntaxException;
27  
28  import javax.security.auth.callback.Callback;
29  import javax.security.auth.callback.CallbackHandler;
30  
31  import org.apache.wss4j.dom.WSConstants;
32  import org.apache.wss4j.dom.WSDocInfo;
33  import org.apache.wss4j.dom.engine.WSSConfig;
34  import org.apache.wss4j.dom.engine.WSSecurityEngineResult;
35  import org.apache.wss4j.common.EncryptionActionToken;
36  import org.apache.wss4j.common.SignatureActionToken;
37  import org.apache.wss4j.common.SignatureEncryptionActionToken;
38  import org.apache.wss4j.common.WSEncryptionPart;
39  import org.apache.wss4j.common.crypto.AlgorithmSuite;
40  import org.apache.wss4j.common.crypto.Crypto;
41  import org.apache.wss4j.common.crypto.CryptoFactory;
42  import org.apache.wss4j.common.crypto.JasyptPasswordEncryptor;
43  import org.apache.wss4j.common.crypto.PasswordEncryptor;
44  import org.apache.wss4j.common.ext.WSPasswordCallback;
45  import org.apache.wss4j.common.ext.WSSecurityException;
46  import org.apache.wss4j.common.util.Loader;
47  import org.apache.wss4j.dom.message.WSSecHeader;
48  import org.apache.wss4j.dom.message.token.SignatureConfirmation;
49  import org.apache.wss4j.dom.util.WSSecurityUtil;
50  import org.w3c.dom.Document;
51  
52  /**
53   * Extracted from WSDoAllReceiver and WSDoAllSender
54   * Extended to all passwordless UsernameTokens and configurable identities.
55   */
56  public abstract class WSHandler {
57      private static final org.slf4j.Logger LOG =
58          org.slf4j.LoggerFactory.getLogger(WSHandler.class);
59      protected Map<String, Crypto> cryptos = new ConcurrentHashMap<>();
60  
61      /**
62       * Performs all defined security actions to set-up the SOAP request.
63       *
64       * @param doc   the request as DOM document
65       * @param reqData a data storage to pass values around between methods
66       * @param actions a list holding the actions to do in the order defined
67       *                in the deployment file or property, plus an optional
68       *                associated SecurityActionToken object for that Action
69       * @throws WSSecurityException
70       */
71      protected void doSenderAction(
72              Document doc,
73              RequestData reqData,
74              List<HandlerAction> actions,
75              boolean isRequest
76      ) throws WSSecurityException {
77  
78          WSSConfig wssConfig = reqData.getWssConfig();
79          if (wssConfig == null) {
80              wssConfig = WSSConfig.getNewInstance();
81              reqData.setWssConfig(wssConfig);
82          }
83  
84          if (reqData.getWsDocInfo() == null) {
85              WSDocInfo wsDocInfo = new WSDocInfo(doc);
86              reqData.setWsDocInfo(wsDocInfo);
87          }
88  
89          Object mc = reqData.getMsgContext();
90          reqData.setEncodePasswords(
91              decodeBooleanConfigValue(mc, WSHandlerConstants.USE_ENCODED_PASSWORDS, false)
92          );
93          reqData.setPrecisionInMilliSeconds(
94              decodeBooleanConfigValue(mc, WSHandlerConstants.TIMESTAMP_PRECISION, true)
95          );
96          reqData.setAddInclusivePrefixes(
97              decodeBooleanConfigValue(mc, WSHandlerConstants.ADD_INCLUSIVE_PREFIXES, true)
98          );
99          reqData.setEnableSignatureConfirmation(
100             decodeBooleanConfigValue(mc, WSHandlerConstants.ENABLE_SIGNATURE_CONFIRMATION, false)
101         );
102         reqData.setTimeStampTTL(decodeTimeToLive(reqData, true));
103 
104         String actor = getString(WSHandlerConstants.ACTOR, mc);
105         reqData.setActor(actor);
106 
107         boolean mu = decodeBooleanConfigValue(mc, WSHandlerConstants.MUST_UNDERSTAND, true);
108         WSSecHeader secHeader = new WSSecHeader(actor, mu, doc);
109         secHeader.insertSecurityHeader();
110         reqData.setSecHeader(secHeader);
111         reqData.setSoapConstants(WSSecurityUtil.getSOAPConstants(doc.getDocumentElement()));
112 
113         // Load CallbackHandler
114         if (reqData.getCallbackHandler() == null) {
115             CallbackHandler passwordCallbackHandler = getPasswordCallbackHandler(reqData);
116             reqData.setCallbackHandler(passwordCallbackHandler);
117         }
118 
119         if (!reqData.isStoreBytesInAttachment()) {
120             boolean storeBytesInAttachment =
121                 decodeBooleanConfigValue(mc, WSHandlerConstants.STORE_BYTES_IN_ATTACHMENT, false);
122             reqData.setStoreBytesInAttachment(storeBytesInAttachment);
123         }
124 
125         // Perform configuration
126         boolean encryptionFound = false;
127         for (HandlerAction actionToDo : actions) {
128             if (actionToDo.getAction() == WSConstants.SC) {
129                 reqData.setEnableSignatureConfirmation(true);
130             } else if ((actionToDo.getAction() == WSConstants.UT
131                 || actionToDo.getAction() == WSConstants.UT_NOPASSWORD)
132                 && actionToDo.getActionToken() == null) {
133                 decodeUTParameter(reqData);
134                 if (actionToDo.getAction() == WSConstants.UT_NOPASSWORD) {
135                     reqData.setPwType(null);
136                 }
137             } else if (actionToDo.getAction() == WSConstants.UT_SIGN
138                 && actionToDo.getActionToken() == null) {
139                 decodeUTParameter(reqData);
140                 decodeSignatureParameter(reqData);
141             } else if ((actionToDo.getAction() == WSConstants.SIGN
142                 || actionToDo.getAction() == WSConstants.DKT_SIGN)
143                 && actionToDo.getActionToken() == null) {
144                 SignatureActionToken actionToken = reqData.getSignatureToken();
145                 if (actionToken == null) {
146                     actionToken = new SignatureActionToken();
147                     reqData.setSignatureToken(actionToken);
148                 }
149                 if (actionToken.getCrypto() == null) {
150                     actionToken.setCrypto(loadSignatureCrypto(reqData));
151                 }
152                 decodeSignatureParameter(reqData);
153                 if (encryptionFound && reqData.isStoreBytesInAttachment()) {
154                     LOG.warn("Turning off storeBytesInAttachment as we have encryption before signature."
155                              + " The danger here is that the actual encryption bytes will not be signed");
156                     reqData.setStoreBytesInAttachment(false);
157                 }
158             } else if (actionToDo.getAction() == WSConstants.ST_SIGNED
159                 && actionToDo.getActionToken() == null) {
160                 decodeSignatureParameter(reqData);
161             } else if ((actionToDo.getAction() == WSConstants.ENCR
162                 || actionToDo.getAction() == WSConstants.DKT_ENCR)
163                 && actionToDo.getActionToken() == null) {
164                 encryptionFound = true;
165                 EncryptionActionToken actionToken = reqData.getEncryptionToken();
166                 if (actionToken == null) {
167                     actionToken = new EncryptionActionToken();
168                     reqData.setEncryptionToken(actionToken);
169                 }
170                 if (actionToken.getCrypto() == null) {
171                     actionToken.setCrypto(loadEncryptionCrypto(reqData));
172                 }
173                 decodeEncryptionParameter(reqData);
174             }
175         }
176 
177         /*
178          * If after all the parsing no Signature parts defined, set here a
179          * default set. This is necessary because we add SignatureConfirmation
180          * and therefore the default (Body) must be set here. The default setting
181          * in WSSignEnvelope doesn't work because the vector is not empty anymore.
182          */
183         SignatureActionToken signatureToken = reqData.getSignatureToken();
184         if (signatureToken == null) {
185             signatureToken = new SignatureActionToken();
186             reqData.setSignatureToken(signatureToken);
187         }
188         if (signatureToken.getParts().isEmpty()) {
189             signatureToken.getParts().add(WSSecurityUtil.getDefaultEncryptionPart(doc));
190         }
191         /*
192          * If SignatureConfirmation is enabled and this is a response then
193          * insert SignatureConfirmation elements, note their wsu:id in the signature
194          * parts. They will be signed automatically during a (probably) defined
195          * SIGN action.
196          */
197         if (reqData.isEnableSignatureConfirmation() && !isRequest) {
198             String done =
199                 (String)getProperty(reqData.getMsgContext(), WSHandlerConstants.SIG_CONF_DONE);
200             if (done == null) {
201                 wssConfig.getAction(WSConstants.SC).execute(this, null, reqData);
202             }
203         }
204 
205         // See if the Signature and Timestamp actions (in that order) are defined, and if
206         // the Timestamp is to be signed. In this case we need to swap the actions, as the
207         // Timestamp must appear in the security header first for signature creation to work.
208         List<HandlerAction> actionsToPerform = actions;
209         HandlerAction signingAction = getSignatureActionThatSignsATimestamp(actions, reqData);
210 
211         if (signingAction != null) {
212             actionsToPerform = new ArrayList<>(actions);
213 
214             // Find TimestampAction
215             int timestampIndex = -1;
216             for (int i = 0; i < actionsToPerform.size(); i++) {
217                 if (actionsToPerform.get(i).getAction() == WSConstants.TS) {
218                     timestampIndex = i;
219                     break;
220                 }
221             }
222 
223             int signatureIndex = actionsToPerform.indexOf(signingAction);
224             if (timestampIndex >= 0) {
225                 actionsToPerform.set(signatureIndex, actionsToPerform.get(timestampIndex));
226                 actionsToPerform.set(timestampIndex, signingAction);
227             }
228             reqData.setAppendSignatureAfterTimestamp(true);
229             reqData.setOriginalSignatureActionPosition(signatureIndex);
230         }
231 
232         /*
233          * Here we have all necessary information to perform the requested
234          * action(s).
235          */
236         for (HandlerAction actionToDo : actionsToPerform) {
237             LOG.debug("Performing Action: {}", actionToDo.getAction());
238 
239             if (WSConstants.NO_SECURITY != actionToDo.getAction()) {
240                 wssConfig.getAction(actionToDo.getAction()).execute(
241                     this, actionToDo.getActionToken(), reqData);
242             }
243         }
244 
245         /*
246          * If this is a request then store all signature values. Add ours to
247          * already gathered values because of chained handlers, e.g. for
248          * other actors.
249          */
250         if (reqData.isEnableSignatureConfirmation()
251             && isRequest && !reqData.getSignatureValues().isEmpty()) {
252             @SuppressWarnings("unchecked")
253             Set<Integer> savedSignatures =
254                 (Set<Integer>)getProperty(reqData.getMsgContext(), WSHandlerConstants.SEND_SIGV);
255             if (savedSignatures == null) {
256                 savedSignatures = new HashSet<>();
257                 setProperty(
258                     reqData.getMsgContext(), WSHandlerConstants.SEND_SIGV, savedSignatures
259                 );
260             }
261             for (byte[] signatureValue : reqData.getSignatureValues()) {
262                 savedSignatures.add(Arrays.hashCode(signatureValue));
263             }
264         }
265     }
266 
267     private HandlerAction getSignatureActionThatSignsATimestamp(
268         List<HandlerAction> actions, RequestData reqData
269     ) {
270         for (HandlerAction action : actions) {
271             // Only applies if a Signature is before a Timestamp
272             if (action.getAction() == WSConstants.TS) {
273                 return null;
274             } else if (action.getAction() == WSConstants.SIGN) {
275                 if (action.getActionToken() != null
276                     && ((SignatureEncryptionActionToken)action.getActionToken()).getParts() != null) {
277                     for (WSEncryptionPart encP
278                         : ((SignatureEncryptionActionToken)action.getActionToken()).getParts()) {
279                         if (WSConstants.WSU_NS.equals(encP.getNamespace())
280                             && "Timestamp".equals(encP.getName())) {
281                             return action;
282                         }
283                     }
284                 } else {
285                     for (WSEncryptionPart encP : reqData.getSignatureToken().getParts()) {
286                         if (WSConstants.WSU_NS.equals(encP.getNamespace())
287                             && "Timestamp".equals(encP.getName())) {
288                             return action;
289                         }
290                     }
291                 }
292             }
293         }
294         return null;
295     }
296 
297     protected void doReceiverAction(List<Integer> actions, RequestData reqData)
298         throws WSSecurityException {
299 
300         WSSConfig wssConfig = reqData.getWssConfig();
301         if (wssConfig == null) {
302             wssConfig = WSSConfig.getNewInstance();
303             reqData.setWssConfig(wssConfig);
304         }
305 
306         Object mc = reqData.getMsgContext();
307         boolean enableSigConf =
308             decodeBooleanConfigValue(mc, WSHandlerConstants.ENABLE_SIGNATURE_CONFIRMATION, false);
309         reqData.setEnableSignatureConfirmation(
310             enableSigConf || actions.contains(WSConstants.SC)
311         );
312         reqData.setTimeStampStrict(
313             decodeBooleanConfigValue(mc, WSHandlerConstants.TIMESTAMP_STRICT, true)
314         );
315         reqData.setRequiredPasswordType(decodePasswordType(reqData));
316 
317         reqData.setTimeStampTTL(decodeTimeToLive(reqData, true));
318         reqData.setTimeStampFutureTTL(decodeFutureTimeToLive(reqData, true));
319         reqData.setUtTTL(decodeTimeToLive(reqData, false));
320         reqData.setUtFutureTTL(decodeFutureTimeToLive(reqData, false));
321 
322         reqData.setHandleCustomPasswordTypes(
323             decodeBooleanConfigValue(mc, WSHandlerConstants.HANDLE_CUSTOM_PASSWORD_TYPES, false)
324         );
325         reqData.setEncodePasswords(
326             decodeBooleanConfigValue(mc, WSHandlerConstants.USE_ENCODED_PASSWORDS, false)
327         );
328         reqData.setAllowNamespaceQualifiedPasswordTypes(
329             decodeBooleanConfigValue(mc, WSHandlerConstants.ALLOW_NAMESPACE_QUALIFIED_PASSWORD_TYPES, false)
330         );
331         reqData.setAllowUsernameTokenNoPassword(
332             decodeBooleanConfigValue(mc, WSHandlerConstants.ALLOW_USERNAMETOKEN_NOPASSWORD, false)
333         );
334         reqData.setValidateSamlSubjectConfirmation(
335             decodeBooleanConfigValue(mc, WSHandlerConstants.VALIDATE_SAML_SUBJECT_CONFIRMATION, true)
336         );
337 
338         boolean bspCompliant =
339             decodeBooleanConfigValue(mc, WSHandlerConstants.IS_BSP_COMPLIANT, true);
340         if (!bspCompliant) {
341             reqData.setDisableBSPEnforcement(true);
342         }
343 
344         // Load CallbackHandler
345         if (reqData.getCallbackHandler() == null) {
346             CallbackHandler passwordCallbackHandler = getPasswordCallbackHandler(reqData);
347             reqData.setCallbackHandler(passwordCallbackHandler);
348         }
349 
350         if (actions.contains(WSConstants.SIGN) || actions.contains(WSConstants.ST_SIGNED)
351             || actions.contains(WSConstants.ST_UNSIGNED)) {
352             decodeSignatureParameter2(reqData);
353         }
354 
355         if (actions.contains(WSConstants.ENCR)) {
356             decodeDecryptionParameter(reqData);
357         }
358         reqData.setRequireSignedEncryptedDataElements(
359             decodeBooleanConfigValue(
360                 mc, WSHandlerConstants.REQUIRE_SIGNED_ENCRYPTED_DATA_ELEMENTS, false
361             )
362         );
363         reqData.setRequireTimestampExpires(
364             decodeBooleanConfigValue(mc, WSHandlerConstants.REQUIRE_TIMESTAMP_EXPIRES, false)
365         );
366     }
367 
368     protected boolean checkReceiverResults(
369         List<WSSecurityEngineResult> wsResult, List<Integer> actions
370     ) {
371         int size = actions.size();
372         int ai = 0;
373         for (WSSecurityEngineResult result : wsResult) {
374             final Integer actInt = (Integer) result.get(WSSecurityEngineResult.TAG_ACTION);
375             if (actInt != null) {
376                 int act = actInt;
377                 if (act == WSConstants.SC || act == WSConstants.BST) {
378                     continue;
379                 }
380 
381                 if (ai >= size || actions.get(ai++) != act) {
382                     return false;
383                 }
384             }
385         }
386 
387         return ai == size;
388     }
389 
390     protected boolean checkReceiverResultsAnyOrder(
391         List<WSSecurityEngineResult> wsResult, List<Integer> actions
392     ) {
393         List<Integer> recordedActions = new ArrayList<>(actions.size());
394         for (Integer action : actions) {
395             recordedActions.add(action);
396         }
397 
398         for (WSSecurityEngineResult result : wsResult) {
399             final Integer actInt = (Integer) result.get(WSSecurityEngineResult.TAG_ACTION);
400             if (actInt != null) {
401                 int act = actInt;
402                 if (act == WSConstants.SC || act == WSConstants.BST) {
403                     continue;
404                 } else if (act == WSConstants.ENCR
405                     && (result.get(WSSecurityEngineResult.TAG_DATA_REF_URIS) == null
406                         || ((List<?>)result.get(WSSecurityEngineResult.TAG_DATA_REF_URIS)).isEmpty())) {
407                     continue;
408                 }
409 
410 
411                 if (!recordedActions.remove(actInt)) {
412                     return false;
413                 }
414             }
415         }
416 
417         return recordedActions.isEmpty();
418     }
419 
420     @SuppressWarnings("unchecked")
421     protected void checkSignatureConfirmation(
422         RequestData reqData,
423         WSHandlerResult handlerResults
424     ) throws WSSecurityException {
425         LOG.debug("Check Signature confirmation");
426         //
427         // First get all Signature values stored during sending the request
428         //
429         Set<Integer> savedSignatures =
430             (Set<Integer>) getProperty(reqData.getMsgContext(), WSHandlerConstants.SEND_SIGV);
431         //
432         // Now get all results that hold a SignatureConfirmation element from
433         // the current run of receiver (we can have more than one run: if we
434         // have several security header blocks with different actors/roles)
435         //
436         List<WSSecurityEngineResult> sigConf =
437             handlerResults.getActionResults().get(WSConstants.SC);
438         //
439         // now loop over all SignatureConfirmation results and check:
440         // - if there is a signature value and no Signature value generated in request: error
441         // - if there is a signature value and no matching Signature value found: error
442         //
443         //  If a matching value found: remove from vector of stored signature values
444         //
445         if (sigConf != null) {
446             for (WSSecurityEngineResult result : sigConf) {
447                 SignatureConfirmation sc =
448                     (SignatureConfirmation)result.get(
449                         WSSecurityEngineResult.TAG_SIGNATURE_CONFIRMATION
450                     );
451 
452                 if (sc != null && sc.getSignatureValue() != null) {
453                     if (savedSignatures == null || savedSignatures.isEmpty()) {
454                         //
455                         // If there are no stored signature values, and we've received a
456                         // SignatureConfirmation element then throw an Exception
457                         //
458                         if (sc.getSignatureValue().length != 0) {
459                             throw new WSSecurityException(WSSecurityException.ErrorCode.INVALID_SECURITY, "empty",
460                                  new Object[] {"Received a SignatureConfirmation element, but there are no stored"
461                                  + " signature values"}
462                             );
463                         }
464                     } else {
465                         Integer hash = Arrays.hashCode(sc.getSignatureValue());
466                         if (savedSignatures.contains(hash)) {
467                             savedSignatures.remove(hash);
468                         } else {
469                             throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "empty",
470                                 new Object[] {"Received a SignatureConfirmation element, but there are no matching"
471                                 + " stored signature values"}
472                             );
473                         }
474                     }
475                 }
476             }
477         }
478 
479         //
480         // the set holding the stored Signature values must be empty, otherwise we have an error
481         //
482         if (savedSignatures != null && !savedSignatures.isEmpty()) {
483             throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "empty",
484                                           new Object[] {"Check Signature confirmation: the stored signature values"
485                                                         + " list is not empty"}
486             );
487         }
488     }
489 
490     protected void decodeUTParameter(RequestData reqData)
491         throws WSSecurityException {
492         Object mc = reqData.getMsgContext();
493 
494         String type = getString(WSHandlerConstants.PASSWORD_TYPE, mc);
495         if (type != null) {
496             if (WSConstants.PW_TEXT.equals(type)) {
497                 reqData.setPwType(WSConstants.PASSWORD_TEXT);
498             } else if (WSConstants.PW_DIGEST.equals(type)) {
499                 reqData.setPwType(WSConstants.PASSWORD_DIGEST);
500             } else if (WSConstants.PW_NONE.equals(type)) {
501                 reqData.setPwType(null);
502             } else {
503                 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE,
504                         "empty", new Object[] {"Unknown password type encoding: " + type});
505             }
506         }
507 
508         boolean addNonce =
509             decodeBooleanConfigValue(mc, WSHandlerConstants.ADD_USERNAMETOKEN_NONCE, false);
510         reqData.setAddUsernameTokenNonce(addNonce);
511 
512         boolean addCreated =
513             decodeBooleanConfigValue(mc, WSHandlerConstants.ADD_USERNAMETOKEN_CREATED, false);
514         reqData.setAddUsernameTokenCreated(addCreated);
515 
516         String derivedMAC = getString(WSHandlerConstants.USE_DERIVED_KEY_FOR_MAC, mc);
517         boolean useDerivedKeyForMAC = Boolean.parseBoolean(derivedMAC);
518         if (useDerivedKeyForMAC) {
519             reqData.setUseDerivedKeyForMAC(useDerivedKeyForMAC);
520         }
521 
522         String iterations = getString(WSHandlerConstants.DERIVED_KEY_ITERATIONS, mc);
523         if (iterations != null) {
524             try {
525                 int iIterations = Integer.parseInt(iterations);
526                 reqData.setDerivedKeyIterations(iIterations);
527             } catch (NumberFormatException e) {
528                 LOG.warn("Error in configuring a derived key iteration count: " + e.getMessage());
529             }
530         }
531     }
532 
533     // Convert various Signature configuration into a single SignatureActionToken to be set on
534     // the RequestData object
535     protected void decodeSignatureParameter(RequestData reqData)
536         throws WSSecurityException {
537         Object mc = reqData.getMsgContext();
538         String signatureUser = getString(WSHandlerConstants.SIGNATURE_USER, mc);
539 
540         SignatureActionToken actionToken = reqData.getSignatureToken();
541         if (actionToken == null) {
542             actionToken = new SignatureActionToken();
543             reqData.setSignatureToken(actionToken);
544         }
545 
546         if (signatureUser != null) {
547             actionToken.setUser(signatureUser);
548         } else {
549             actionToken.setUser(reqData.getUsername());
550         }
551 
552         String keyId = getString(WSHandlerConstants.SIG_KEY_ID, mc);
553         if (keyId != null) {
554             Integer id = WSHandlerConstants.getKeyIdentifier(keyId);
555             if (id == null) {
556                 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE,
557                         "empty",
558                         new Object[] {"WSHandler: Signature: unknown key identification"}
559                 );
560             }
561             int tmp = id;
562             if (!(tmp == WSConstants.ISSUER_SERIAL
563                     || tmp == WSConstants.ISSUER_SERIAL_QUOTE_FORMAT
564                     || tmp == WSConstants.BST_DIRECT_REFERENCE
565                     || tmp == WSConstants.X509_KEY_IDENTIFIER
566                     || tmp == WSConstants.SKI_KEY_IDENTIFIER
567                     || tmp == WSConstants.THUMBPRINT_IDENTIFIER
568                     || tmp == WSConstants.ENCRYPTED_KEY_SHA1_IDENTIFIER
569                     || tmp == WSConstants.KEY_VALUE)) {
570                 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE,
571                         "empty",
572                         new Object[] {"WSHandler: Signature: illegal key identification"}
573                 );
574             }
575             actionToken.setKeyIdentifierId(tmp);
576         }
577         String algo = getString(WSHandlerConstants.SIG_ALGO, mc);
578         actionToken.setSignatureAlgorithm(algo);
579 
580         String derivedKeyReference = getString(WSHandlerConstants.DERIVED_TOKEN_REFERENCE, mc);
581         actionToken.setDerivedKeyTokenReference(derivedKeyReference);
582 
583         String derivedKeyIdentifier = getString(WSHandlerConstants.DERIVED_TOKEN_KEY_ID, mc);
584         if (derivedKeyIdentifier != null) {
585             Integer id = WSHandlerConstants.getKeyIdentifier(derivedKeyIdentifier);
586             actionToken.setDerivedKeyIdentifier(id);
587         }
588 
589         String derivedKeyLength = getString(WSHandlerConstants.DERIVED_SIGNATURE_KEY_LENGTH, mc);
590         if (derivedKeyLength != null) {
591             try {
592                 int dKL = Integer.parseInt(derivedKeyLength);
593                 if (dKL > 0) {
594                     actionToken.setDerivedKeyLength(dKL);
595                 }
596             } catch (NumberFormatException e) {
597                 LOG.warn("Error in configuring a derived key length: " + e.getMessage());
598             }
599         }
600 
601         String digestAlgo = getString(WSHandlerConstants.SIG_DIGEST_ALGO, mc);
602         actionToken.setDigestAlgorithm(digestAlgo);
603 
604         String c14nAlgo = getString(WSHandlerConstants.SIG_C14N_ALGO, mc);
605         actionToken.setC14nAlgorithm(c14nAlgo);
606 
607         boolean use200512Namespace =
608             decodeBooleanConfigValue(mc, WSHandlerConstants.USE_2005_12_NAMESPACE, true);
609         reqData.setUse200512Namespace(use200512Namespace);
610 
611         String parts = getString(WSHandlerConstants.SIGNATURE_PARTS, mc);
612         if (parts != null) {
613             splitEncParts(true, parts, actionToken.getParts(), reqData);
614         }
615         parts = getString(WSHandlerConstants.OPTIONAL_SIGNATURE_PARTS, mc);
616         if (parts != null) {
617             splitEncParts(false, parts, actionToken.getParts(), reqData);
618         }
619 
620         boolean useSingleCert =
621             decodeBooleanConfigValue(mc, WSHandlerConstants.USE_SINGLE_CERTIFICATE, true);
622         actionToken.setUseSingleCert(useSingleCert);
623 
624         boolean includeToken =
625             decodeBooleanConfigValue(mc, WSHandlerConstants.INCLUDE_SIGNATURE_TOKEN, false);
626         actionToken.setIncludeToken(includeToken);
627 
628         if (!reqData.isExpandXopInclude()) {
629             boolean expandXOP =
630                 decodeBooleanConfigValue(
631                     reqData.getMsgContext(), WSHandlerConstants.EXPAND_XOP_INCLUDE, false
632             );
633             reqData.setExpandXopInclude(expandXOP);
634         }
635     }
636 
637     protected void decodeAlgorithmSuite(RequestData reqData) throws WSSecurityException {
638         Object mc = reqData.getMsgContext();
639         if (mc == null || reqData.getAlgorithmSuite() != null) {
640             return;
641         }
642 
643         AlgorithmSuite algorithmSuite = new AlgorithmSuite();
644 
645         String signatureAlgorithm = getString(WSHandlerConstants.SIG_ALGO, mc);
646         if (signatureAlgorithm != null && signatureAlgorithm.length() != 0) {
647             algorithmSuite.addSignatureMethod(signatureAlgorithm);
648         }
649         String signatureDigestAlgorithm = getString(WSHandlerConstants.SIG_DIGEST_ALGO, mc);
650         if (signatureDigestAlgorithm != null && signatureDigestAlgorithm.length() != 0) {
651             algorithmSuite.addDigestAlgorithm(signatureDigestAlgorithm);
652         }
653 
654         String encrAlgorithm = getString(WSHandlerConstants.ENC_SYM_ALGO, mc);
655         if (encrAlgorithm != null && encrAlgorithm.length() != 0) {
656             algorithmSuite.addEncryptionMethod(encrAlgorithm);
657         }
658         String transportAlgorithm = getString(WSHandlerConstants.ENC_KEY_TRANSPORT, mc);
659         if (transportAlgorithm != null && transportAlgorithm.length() != 0) {
660             algorithmSuite.addKeyWrapAlgorithm(transportAlgorithm);
661         }
662 
663         reqData.setAlgorithmSuite(algorithmSuite);
664     }
665 
666     // Convert various Encryption configuration into a single EncryptionActionToken to be set on
667     // the RequestData object
668     protected void decodeEncryptionParameter(RequestData reqData)
669         throws WSSecurityException {
670         Object mc = reqData.getMsgContext();
671 
672         EncryptionActionToken actionToken = reqData.getEncryptionToken();
673         if (actionToken == null) {
674             actionToken = new EncryptionActionToken();
675             reqData.setEncryptionToken(actionToken);
676         }
677         //
678         // If the following parameters are no used (they return null) then the
679         // default values of WSS4J are used.
680         //
681         String encKeyId = getString(WSHandlerConstants.ENC_KEY_ID, mc);
682         if (encKeyId != null) {
683             Integer id = WSHandlerConstants.getKeyIdentifier(encKeyId);
684             if (id == null) {
685                 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE,
686                         "empty",
687                         new Object[] {"WSHandler: Encryption: unknown key identification"}
688                 );
689             }
690             int tmp = id;
691             actionToken.setKeyIdentifierId(tmp);
692             if (!(tmp == WSConstants.ISSUER_SERIAL
693                     || tmp == WSConstants.ISSUER_SERIAL_QUOTE_FORMAT
694                     || tmp == WSConstants.X509_KEY_IDENTIFIER
695                     || tmp == WSConstants.SKI_KEY_IDENTIFIER
696                     || tmp == WSConstants.BST_DIRECT_REFERENCE
697                     || tmp == WSConstants.THUMBPRINT_IDENTIFIER
698                     || tmp == WSConstants.ENCRYPTED_KEY_SHA1_IDENTIFIER)) {
699                 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE,
700                         "empty",
701                         new Object[] {"WSHandler: Encryption: illegal key identification"}
702                 );
703             }
704         }
705         String encSymAlgo = getString(WSHandlerConstants.ENC_SYM_ALGO, mc);
706         actionToken.setSymmetricAlgorithm(encSymAlgo);
707 
708         String encKeyTransport =
709             getString(WSHandlerConstants.ENC_KEY_TRANSPORT, mc);
710         actionToken.setKeyTransportAlgorithm(encKeyTransport);
711 
712         String derivedKeyReference = getString(WSHandlerConstants.DERIVED_TOKEN_REFERENCE, mc);
713         actionToken.setDerivedKeyTokenReference(derivedKeyReference);
714 
715         String derivedKeyIdentifier = getString(WSHandlerConstants.DERIVED_TOKEN_KEY_ID, mc);
716         if (derivedKeyIdentifier != null) {
717             Integer id = WSHandlerConstants.getKeyIdentifier(derivedKeyIdentifier);
718             actionToken.setDerivedKeyIdentifier(id);
719         }
720 
721         String derivedKeyLength = getString(WSHandlerConstants.DERIVED_ENCRYPTION_KEY_LENGTH, mc);
722         if (derivedKeyLength != null) {
723             try {
724                 int dKL = Integer.parseInt(derivedKeyLength);
725                 if (dKL > 0) {
726                     actionToken.setDerivedKeyLength(dKL);
727                 }
728             } catch (NumberFormatException e) {
729                 LOG.warn("Error in configuring a derived key length: " + e.getMessage());
730             }
731         }
732 
733         boolean use200512Namespace =
734             decodeBooleanConfigValue(mc, WSHandlerConstants.USE_2005_12_NAMESPACE, true);
735         reqData.setUse200512Namespace(use200512Namespace);
736 
737         boolean getSecretKeyFromCallbackHandler =
738             decodeBooleanConfigValue(mc, WSHandlerConstants.GET_SECRET_KEY_FROM_CALLBACK_HANDLER, false);
739         actionToken.setGetSymmetricKeyFromCallbackHandler(getSecretKeyFromCallbackHandler);
740 
741         String digestAlgo = getString(WSHandlerConstants.ENC_DIGEST_ALGO, mc);
742         actionToken.setDigestAlgorithm(digestAlgo);
743 
744         String mgfAlgo = getString(WSHandlerConstants.ENC_MGF_ALGO, mc);
745         actionToken.setMgfAlgorithm(mgfAlgo);
746 
747         String encSymEncKey = getString(WSHandlerConstants.ENC_SYM_ENC_KEY, mc);
748         if (encSymEncKey != null) {
749             boolean encSymEndKeyBoolean = Boolean.parseBoolean(encSymEncKey);
750             actionToken.setEncSymmetricEncryptionKey(encSymEndKeyBoolean);
751         }
752 
753         String encUser = getString(WSHandlerConstants.ENCRYPTION_USER, mc);
754         if (encUser != null) {
755             actionToken.setUser(encUser);
756         } else {
757             actionToken.setUser(reqData.getUsername());
758         }
759         if (actionToken.isEncSymmetricEncryptionKey() && actionToken.getUser() == null) {
760             throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE,
761                     "empty",
762                     new Object[] {"WSHandler: Encryption: no username"});
763         }
764 
765         handleSpecialUser(reqData);
766 
767         String encParts = getString(WSHandlerConstants.ENCRYPTION_PARTS, mc);
768         if (encParts != null) {
769             splitEncParts(true, encParts, actionToken.getParts(), reqData);
770         }
771         encParts = getString(WSHandlerConstants.OPTIONAL_ENCRYPTION_PARTS, mc);
772         if (encParts != null) {
773             splitEncParts(false, encParts, actionToken.getParts(), reqData);
774         }
775 
776         boolean includeToken =
777             decodeBooleanConfigValue(mc, WSHandlerConstants.INCLUDE_ENCRYPTION_TOKEN, false);
778         actionToken.setIncludeToken(includeToken);
779     }
780 
781     /**
782      * Decode the TimeToLive parameter for either a Timestamp or a UsernameToken Created element,
783      * depending on the boolean argument
784      */
785     public int decodeTimeToLive(RequestData reqData, boolean timestamp) {
786         String tag = WSHandlerConstants.TTL_TIMESTAMP;
787         if (!timestamp) {
788             tag = WSHandlerConstants.TTL_USERNAMETOKEN;
789         }
790         String ttl = getString(tag, reqData.getMsgContext());
791         int defaultTimeToLive = 300;
792         if (ttl != null) {
793             try {
794                 int ttlI = Integer.parseInt(ttl);
795                 if (ttlI < 0) {
796                     return defaultTimeToLive;
797                 }
798                 return ttlI;
799             } catch (NumberFormatException e) {
800                 return defaultTimeToLive;
801             }
802         }
803         return defaultTimeToLive;
804     }
805 
806     /**
807      * Decode the FutureTimeToLive parameter for either a Timestamp or a UsernameToken Created
808      * element, depending on the boolean argument
809      */
810     protected int decodeFutureTimeToLive(RequestData reqData, boolean timestamp) {
811         String tag = WSHandlerConstants.TTL_FUTURE_TIMESTAMP;
812         if (!timestamp) {
813             tag = WSHandlerConstants.TTL_FUTURE_USERNAMETOKEN;
814         }
815         String ttl = getString(tag, reqData.getMsgContext());
816         int defaultFutureTimeToLive = 60;
817         if (ttl != null) {
818             try {
819                 int ttlI = Integer.parseInt(ttl);
820                 if (ttlI < 0) {
821                     return defaultFutureTimeToLive;
822                 }
823                 return ttlI;
824             } catch (NumberFormatException e) {
825                 return defaultFutureTimeToLive;
826             }
827         }
828         return defaultFutureTimeToLive;
829     }
830 
831     protected String decodePasswordType(RequestData reqData) throws WSSecurityException {
832         String type = getString(WSHandlerConstants.PASSWORD_TYPE, reqData.getMsgContext());
833         if (type != null) {
834             if (WSConstants.PW_TEXT.equals(type)) {
835                 return WSConstants.PASSWORD_TEXT;
836             } else if (WSConstants.PW_DIGEST.equals(type)) {
837                 return WSConstants.PASSWORD_DIGEST;
838             }
839         }
840         return null;
841     }
842 
843     protected boolean decodeBooleanConfigValue(
844         Object messageContext, String configTag, boolean defaultToTrue
845     ) throws WSSecurityException {
846 
847         String value = getString(configTag, messageContext);
848 
849         if (value == null) {
850             return defaultToTrue;
851         }
852         if ("0".equals(value) || "false".equals(value)) {
853             return false;
854         }
855         if ("1".equals(value) || "true".equals(value)) {
856             return true;
857         }
858 
859         throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE,
860                 "empty",
861                 new Object[] {"WSHandler: illegal " + configTag + " parameter"}
862         );
863     }
864 
865     /**
866      * Hook to allow subclasses to load their Signature creation Crypto however they see
867      * fit.
868      *
869      * @param requestData the RequestData object
870      * @return a Crypto instance to use for Signature creation
871      */
872     public Crypto loadSignatureCrypto(RequestData requestData) throws WSSecurityException {
873         return
874             loadCrypto(
875                 WSHandlerConstants.SIG_PROP_FILE,
876                 WSHandlerConstants.SIG_PROP_REF_ID,
877                 requestData
878             );
879     }
880 
881     /**
882      * Hook to allow subclasses to load their Signature verification Crypto however they see
883      * fit.
884      *
885      * @param requestData the RequestData object
886      * @return a Crypto instance to use for Signature verification
887      */
888     public Crypto loadSignatureVerificationCrypto(RequestData requestData)
889         throws WSSecurityException {
890         return
891             loadCrypto(
892                 WSHandlerConstants.SIG_VER_PROP_FILE,
893                 WSHandlerConstants.SIG_VER_PROP_REF_ID,
894                 requestData
895             );
896     }
897 
898     /**
899      * Hook to allow subclasses to load their Decryption Crypto however they see
900      * fit.
901      *
902      * @param requestData the RequestData object
903      * @return a Crypto instance to use for Decryption creation/verification
904      */
905     protected Crypto loadDecryptionCrypto(RequestData requestData) throws WSSecurityException {
906         return
907             loadCrypto(
908                 WSHandlerConstants.DEC_PROP_FILE,
909                 WSHandlerConstants.DEC_PROP_REF_ID,
910                 requestData
911             );
912     }
913 
914     /**
915      * Hook to allow subclasses to load their Encryption Crypto however they see
916      * fit.
917      *
918      * @param requestData the RequestData object
919      * @return a Crypto instance to use for Encryption creation/verification
920      */
921     protected Crypto loadEncryptionCrypto(RequestData requestData) throws WSSecurityException {
922         return
923             loadCrypto(
924                 WSHandlerConstants.ENC_PROP_FILE,
925                 WSHandlerConstants.ENC_PROP_REF_ID,
926                 requestData
927             );
928     }
929 
930     /**
931      * Load a Crypto instance. Firstly, it tries to use the cryptoPropertyRefId tag to retrieve
932      * a Crypto object via a custom reference Id. Failing this, it tries to load the crypto
933      * instance via the cryptoPropertyFile tag.
934      *
935      * @param requestData the RequestData object
936      * @return a Crypto instance to use for Encryption creation/verification
937      */
938     protected Crypto loadCrypto(
939         String cryptoPropertyFile,
940         String cryptoPropertyRefId,
941         RequestData requestData
942     ) throws WSSecurityException {
943         Object mc = requestData.getMsgContext();
944         Crypto crypto = null;
945 
946         //
947         // Try the Property Ref Id first
948         //
949         String refId = getString(cryptoPropertyRefId, mc);
950         if (refId != null) {
951             crypto = cryptos.get(refId);
952             if (crypto == null) {
953                 Object obj = getProperty(mc, refId);
954                 if (obj instanceof Properties) {
955                     crypto = CryptoFactory.getInstance((Properties)obj,
956                                                        Loader.getClassLoader(CryptoFactory.class),
957                                                        getPasswordEncryptor(requestData));
958                     cryptos.put(refId, crypto);
959                 } else if (obj instanceof Crypto) {
960                     // No need to cache this as it's already loaded
961                     crypto = (Crypto)obj;
962                 }
963             }
964             if (crypto == null) {
965                 LOG.warn("The Crypto reference " + refId + " specified by "
966                     + cryptoPropertyRefId + " could not be loaded"
967                 );
968             }
969         }
970 
971         //
972         // Now try loading the properties file
973         //
974         if (crypto == null) {
975             String propFile = getString(cryptoPropertyFile, mc);
976             if (propFile != null) {
977                 crypto = cryptos.get(propFile);
978                 if (crypto == null) {
979                     crypto = loadCryptoFromPropertiesFile(propFile, requestData);
980                     cryptos.put(propFile, crypto);
981                 }
982                 if (crypto == null) {
983                     LOG.warn(
984                          "The Crypto properties file " + propFile + " specified by "
985                          + cryptoPropertyFile + " could not be loaded or found"
986                     );
987                 }
988             }
989         }
990 
991         return crypto;
992     }
993 
994     /**
995      * A hook to allow subclass to load Crypto instances from property files in a different
996      * way.
997      * @param propFilename The property file name
998      * @param reqData The RequestData object
999      * @return A Crypto instance that has been loaded
1000      */
1001     protected Crypto loadCryptoFromPropertiesFile(
1002         String propFilename,
1003         RequestData reqData
1004     ) throws WSSecurityException {
1005         ClassLoader classLoader = this.getClassLoader();
1006         Properties properties = CryptoFactory.getProperties(propFilename, classLoader);
1007         return
1008             CryptoFactory.getInstance(
1009                 properties, classLoader, getPasswordEncryptor(reqData)
1010             );
1011     }
1012 
1013     /**
1014      * Get a CallbackHandler instance. First try to get an instance via the
1015      * callbackHandlerRef on the message context. Failing that, try to load a new
1016      * instance of the CallbackHandler via the callbackHandlerClass argument.
1017      *
1018      * @param callbackHandlerClass The class name of the CallbackHandler instance
1019      * @param callbackHandlerRef The reference name of the CallbackHandler instance
1020      * @param requestData The RequestData which supplies the message context
1021      * @return a CallbackHandler instance
1022      * @throws WSSecurityException
1023      */
1024     public CallbackHandler getCallbackHandler(
1025         String callbackHandlerClass,
1026         String callbackHandlerRef,
1027         RequestData requestData
1028     ) throws WSSecurityException {
1029         Object mc = requestData.getMsgContext();
1030         CallbackHandler cbHandler = (CallbackHandler) getOption(callbackHandlerRef);
1031         if (cbHandler == null) {
1032             cbHandler = (CallbackHandler) getProperty(mc, callbackHandlerRef);
1033         }
1034         if (cbHandler == null) {
1035             String callback = getString(callbackHandlerClass, mc);
1036             if (callback != null) {
1037                 cbHandler = loadCallbackHandler(callback);
1038             }
1039         }
1040         return cbHandler;
1041     }
1042 
1043     /**
1044      * Get a CallbackHandler instance to obtain passwords.
1045      * @param reqData The RequestData which supplies the message context
1046      * @return the CallbackHandler instance to obtain passwords.
1047      * @throws WSSecurityException
1048      */
1049     public CallbackHandler getPasswordCallbackHandler(RequestData reqData)
1050         throws WSSecurityException {
1051         return
1052             getCallbackHandler(
1053                 WSHandlerConstants.PW_CALLBACK_CLASS,
1054                 WSHandlerConstants.PW_CALLBACK_REF,
1055                 reqData
1056             );
1057     }
1058 
1059     /**
1060      * Load a CallbackHandler instance.
1061      * @param callbackHandlerClass The class name of the CallbackHandler instance
1062      * @return a CallbackHandler instance
1063      * @throws WSSecurityException
1064      */
1065     private CallbackHandler loadCallbackHandler(
1066         String callbackHandlerClass
1067     ) throws WSSecurityException {
1068 
1069         Class<? extends CallbackHandler> cbClass = null;
1070         CallbackHandler cbHandler = null;
1071         try {
1072             cbClass =
1073                 Loader.loadClass(getClassLoader(),
1074                                  callbackHandlerClass,
1075                                  CallbackHandler.class);
1076         } catch (ClassNotFoundException e) {
1077             throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, e,
1078                     "empty",
1079                     new Object[] {"WSHandler: cannot load callback handler class: "
1080                     + callbackHandlerClass}
1081             );
1082         }
1083         try {
1084             cbHandler = cbClass.getDeclaredConstructor().newInstance();
1085         } catch (Exception e) {
1086             throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, e,
1087                     "empty",
1088                     new Object[] {"WSHandler: cannot create instance of callback handler: "
1089                     + callbackHandlerClass
1090                     }
1091             );
1092         }
1093         return cbHandler;
1094     }
1095 
1096     protected PasswordEncryptor getPasswordEncryptor(RequestData requestData) {
1097         PasswordEncryptor passwordEncryptor = requestData.getPasswordEncryptor();
1098         if (passwordEncryptor == null) {
1099             Object o = getOption(WSHandlerConstants.PASSWORD_ENCRYPTOR_INSTANCE);
1100             if (o instanceof PasswordEncryptor) {
1101                 passwordEncryptor = (PasswordEncryptor) o;
1102             }
1103         }
1104         if (passwordEncryptor == null) {
1105             Object mc = requestData.getMsgContext();
1106             Object o = getProperty(mc, WSHandlerConstants.PASSWORD_ENCRYPTOR_INSTANCE);
1107             if (o instanceof PasswordEncryptor) {
1108                 passwordEncryptor = (PasswordEncryptor) o;
1109             }
1110         }
1111         if (passwordEncryptor == null) {
1112             CallbackHandler callbackHandler = requestData.getCallbackHandler();
1113             if (callbackHandler != null) {
1114                 passwordEncryptor = new JasyptPasswordEncryptor(callbackHandler);
1115             }
1116         }
1117 
1118         return passwordEncryptor;
1119     }
1120 
1121     /**
1122      * Get a password callback (WSPasswordCallback object) from a CallbackHandler instance
1123      * @param username The username to supply to the CallbackHandler
1124      * @param doAction The action to perform
1125      * @param callbackHandler The CallbackHandler instance
1126      * @param requestData The RequestData which supplies the message context
1127      * @return the WSPasswordCallback object containing the password
1128      * @throws WSSecurityException
1129      */
1130     public WSPasswordCallback getPasswordCB(
1131          String username,
1132          int doAction,
1133          CallbackHandler callbackHandler,
1134          RequestData requestData
1135     ) throws WSSecurityException {
1136 
1137         if (callbackHandler != null) {
1138             return performPasswordCallback(callbackHandler, username, doAction);
1139         } else {
1140             //
1141             // If a callback isn't configured then try to get the password
1142             // from the message context
1143             //
1144             String password = getPassword(requestData.getMsgContext());
1145             if (password == null) {
1146                 String err = "provided null or empty password";
1147                 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE,
1148                         "empty",
1149                         new Object[] {"WSHandler: application " + err});
1150             }
1151             WSPasswordCallback pwCb = constructPasswordCallback(username, doAction);
1152             pwCb.setPassword(password);
1153             return pwCb;
1154         }
1155     }
1156 
1157     /**
1158      * Perform a callback on a CallbackHandler instance
1159      * @param cbHandler the CallbackHandler instance
1160      * @param username The username to supply to the CallbackHandler
1161      * @param doAction The action to perform
1162      * @return a WSPasswordCallback instance
1163      * @throws WSSecurityException
1164      */
1165     private WSPasswordCallback performPasswordCallback(
1166         CallbackHandler cbHandler,
1167         String username,
1168         int doAction
1169     ) throws WSSecurityException {
1170 
1171         WSPasswordCallback pwCb = constructPasswordCallback(username, doAction);
1172         Callback[] callbacks = new Callback[1];
1173         callbacks[0] = pwCb;
1174         //
1175         // Call back the application to get the password
1176         //
1177         try {
1178             cbHandler.handle(callbacks);
1179         } catch (Exception e) {
1180             throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, e,
1181                     "empty", new Object[] {"WSHandler: password callback failed"});
1182         }
1183         return pwCb;
1184     }
1185 
1186     /**
1187      * Construct a WSPasswordCallback instance
1188      * @param username The username
1189      * @param doAction The action to perform
1190      * @return a WSPasswordCallback instance
1191      * @throws WSSecurityException
1192      */
1193     private WSPasswordCallback constructPasswordCallback(
1194         String username,
1195         int doAction
1196     ) throws WSSecurityException {
1197 
1198         int reason;
1199 
1200         switch (doAction) {
1201         case WSConstants.UT:
1202         case WSConstants.UT_SIGN:
1203             reason = WSPasswordCallback.USERNAME_TOKEN;
1204             break;
1205         case WSConstants.SIGN:
1206             reason = WSPasswordCallback.SIGNATURE;
1207             break;
1208         case WSConstants.DKT_SIGN:
1209             reason = WSPasswordCallback.SECRET_KEY;
1210             break;
1211         case WSConstants.ENCR:
1212             reason = WSPasswordCallback.SECRET_KEY;
1213             break;
1214         case WSConstants.DKT_ENCR:
1215             reason = WSPasswordCallback.SECRET_KEY;
1216             break;
1217         default:
1218             reason = WSPasswordCallback.UNKNOWN;
1219             break;
1220         }
1221         return new WSPasswordCallback(username, reason);
1222     }
1223 
1224     private void splitEncParts(boolean required, String tmpS,
1225                                List<WSEncryptionPart> parts, RequestData reqData)
1226         throws WSSecurityException {
1227         WSEncryptionPart encPart = null;
1228         String[] rawParts = tmpS.split(";");
1229 
1230         for (String rawPart : rawParts) {
1231             String[] partDef = rawPart.split("}");
1232 
1233             if (partDef.length == 1) {
1234                 LOG.debug("single partDef: '{}'", partDef[0]);
1235                 encPart =
1236                     new WSEncryptionPart(partDef[0].trim(),
1237                             reqData.getSoapConstants().getEnvelopeURI(),
1238                             "Content");
1239             } else if (partDef.length == 2) {
1240                 String mode = partDef[0].trim().substring(1);
1241                 String element = partDef[1].trim();
1242                 encPart = new WSEncryptionPart(element, mode);
1243             } else if (partDef.length == 3) {
1244                 String mode = partDef[0].trim();
1245                 if (mode.length() <= 1) {
1246                     mode = "Content";
1247                 } else {
1248                     mode = mode.substring(1);
1249                 }
1250                 String nmSpace = partDef[1].trim();
1251                 if (nmSpace.length() <= 1) {
1252                     nmSpace = reqData.getSoapConstants().getEnvelopeURI();
1253                 } else {
1254                     nmSpace = nmSpace.substring(1);
1255                     if (nmSpace.equals(WSConstants.NULL_NS)) {
1256                         nmSpace = null;
1257                     }
1258                 }
1259                 String element = partDef[2].trim();
1260                 if (LOG.isDebugEnabled()) {
1261                     LOG.debug(
1262                         "partDefs: '" + mode + "' ,'" + nmSpace + "' ,'" + element + "'"
1263                     );
1264                 }
1265                 encPart = new WSEncryptionPart(element, nmSpace, mode);
1266             } else {
1267                 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE,
1268                         "empty",
1269                         new Object[] {"WSHandler: wrong part definition: " + tmpS});
1270             }
1271             encPart.setRequired(required);
1272             parts.add(encPart);
1273         }
1274     }
1275 
1276     @SuppressWarnings("unchecked")
1277     private void handleSpecialUser(RequestData reqData) {
1278         EncryptionActionToken actionToken = reqData.getEncryptionToken();
1279         if (actionToken == null
1280             || !WSHandlerConstants.USE_REQ_SIG_CERT.equals(actionToken.getUser())) {
1281             return;
1282         }
1283         List<WSHandlerResult> results =
1284             (List<WSHandlerResult>) getProperty(
1285                 reqData.getMsgContext(), WSHandlerConstants.RECV_RESULTS
1286             );
1287         if (results == null) {
1288             return;
1289         }
1290         /*
1291          * Scan the results for a matching actor. Use results only if the
1292          * receiving Actor and the sending Actor match.
1293          */
1294         for (WSHandlerResult rResult : results) {
1295             String hActor = rResult.getActor();
1296             if (!WSSecurityUtil.isActorEqual(reqData.getActor(), hActor)) {
1297                 continue;
1298             }
1299             List<WSSecurityEngineResult> wsSecEngineResults = rResult.getResults();
1300             /*
1301              * Scan the results for the first Signature action. Use the
1302              * certificate of this Signature to set the certificate for the
1303              * encryption action :-).
1304              */
1305             for (WSSecurityEngineResult wser : wsSecEngineResults) {
1306                 Integer wserAction = (Integer) wser.get(WSSecurityEngineResult.TAG_ACTION);
1307                 if (wserAction != null && wserAction.intValue() == WSConstants.SIGN) {
1308                     X509Certificate cert =
1309                         (X509Certificate)wser.get(WSSecurityEngineResult.TAG_X509_CERTIFICATE);
1310                     actionToken.setCertificate(cert);
1311                     return;
1312                 }
1313             }
1314         }
1315     }
1316 
1317     @SuppressWarnings("deprecation")
1318     protected void decodeSignatureParameter2(RequestData reqData)
1319         throws WSSecurityException {
1320         if (reqData.getSigVerCrypto() == null) {
1321             reqData.setSigVerCrypto(loadSignatureVerificationCrypto(reqData));
1322         }
1323         if (reqData.getSigVerCrypto() == null) {
1324             reqData.setSigVerCrypto(loadSignatureCrypto(reqData));
1325         }
1326         boolean enableRevocation =
1327             decodeBooleanConfigValue(
1328                 reqData.getMsgContext(), WSHandlerConstants.ENABLE_REVOCATION, false
1329             );
1330         reqData.setEnableRevocation(enableRevocation);
1331 
1332         String certConstraints =
1333             getString(WSHandlerConstants.SIG_SUBJECT_CERT_CONSTRAINTS, reqData.getMsgContext());
1334         if (certConstraints != null) {
1335             String certConstraintsSeparator =
1336                 getString(WSHandlerConstants.SIG_CERT_CONSTRAINTS_SEPARATOR, reqData.getMsgContext());
1337             if (certConstraintsSeparator == null || certConstraintsSeparator.isEmpty()) {
1338                 certConstraintsSeparator = ",";
1339             }
1340             Collection<Pattern> subjectCertConstraints = getCertConstraints(certConstraints, certConstraintsSeparator);
1341             reqData.setSubjectCertConstraints(subjectCertConstraints);
1342         }
1343         String issuerCertConstraintsStringValue =
1344             getString(WSHandlerConstants.SIG_ISSUER_CERT_CONSTRAINTS, reqData.getMsgContext());
1345         if (issuerCertConstraintsStringValue != null) {
1346             String certConstraintsSeparator =
1347                 getString(WSHandlerConstants.SIG_CERT_CONSTRAINTS_SEPARATOR, reqData.getMsgContext());
1348             if (certConstraintsSeparator == null || certConstraintsSeparator.isEmpty()) {
1349                 certConstraintsSeparator = ",";
1350             }
1351             Collection<Pattern> issuerCertConstraints =
1352                 getCertConstraints(issuerCertConstraintsStringValue, certConstraintsSeparator);
1353             reqData.setIssuerDNPatterns(issuerCertConstraints);
1354         }
1355 
1356         String value = getString(WSHandlerConstants.EXPAND_XOP_INCLUDE_FOR_SIGNATURE, reqData.getMsgContext());
1357         boolean expandXOP = false;
1358         if (value != null) {
1359             expandXOP =
1360                 decodeBooleanConfigValue(
1361                     reqData.getMsgContext(), WSHandlerConstants.EXPAND_XOP_INCLUDE_FOR_SIGNATURE, true
1362                 );
1363         } else {
1364             expandXOP =
1365                 decodeBooleanConfigValue(
1366                     reqData.getMsgContext(), WSHandlerConstants.EXPAND_XOP_INCLUDE, true
1367             );
1368         }
1369         reqData.setExpandXopInclude(expandXOP);
1370     }
1371 
1372     private Collection<Pattern> getCertConstraints(String certConstraints, String separator) throws WSSecurityException {
1373         String[] certConstraintsList = certConstraints.split(separator);
1374         if (certConstraintsList != null && certConstraintsList.length > 0) {
1375             Collection<Pattern> certConstraintsCollection =
1376                 new ArrayList<>(certConstraintsList.length);
1377             for (String certConstraint : certConstraintsList) {
1378                 try {
1379                     certConstraintsCollection.add(Pattern.compile(certConstraint.trim()));
1380                 } catch (PatternSyntaxException ex) {
1381                     LOG.debug(ex.getMessage(), ex);
1382                     throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, ex);
1383                 }
1384             }
1385 
1386             return certConstraintsCollection;
1387         }
1388         return Collections.emptyList();
1389     }
1390 
1391     /*
1392      * Set and check the decryption specific parameters, if necessary
1393      * take over signature crypto instance.
1394      */
1395     protected void decodeDecryptionParameter(RequestData reqData)
1396         throws WSSecurityException {
1397         if (reqData.getDecCrypto() == null) {
1398             reqData.setDecCrypto(loadDecryptionCrypto(reqData));
1399         }
1400 
1401         boolean allowRsa15 =
1402             decodeBooleanConfigValue(
1403                 reqData.getMsgContext(), WSHandlerConstants.ALLOW_RSA15_KEY_TRANSPORT_ALGORITHM,
1404                 false
1405             );
1406         reqData.setAllowRSA15KeyTransportAlgorithm(allowRsa15);
1407     }
1408 
1409     /**
1410      * Looks up key first via {@link #getOption(String)} and if not found
1411      * there, via {@link #getProperty(Object, String)}
1412      *
1413      * @param key the key to search for. May not be null.
1414      * @param mc the message context to search.
1415      * @return the value found.
1416      * @throws IllegalArgumentException if <code>key</code> is null.
1417      */
1418     public String getString(String key, Object mc) {
1419         if (key == null) {
1420             throw new IllegalArgumentException("Key cannot be null");
1421         }
1422         String s = getStringOption(key);
1423         if (s != null) {
1424             return s;
1425         }
1426         if (mc == null) {
1427             throw new IllegalArgumentException("Message context cannot be null");
1428         }
1429         return (String) getProperty(mc, key);
1430     }
1431 
1432 
1433     /**
1434      * Returns the option on <code>name</code>.
1435      *
1436      * @param key the non-null key of the option.
1437      * @return the option on <code>key</code> if <code>key</code>
1438      *  exists and is of type java.lang.String; otherwise null.
1439      */
1440     public String getStringOption(String key) {
1441         Object o = getOption(key);
1442         if (o instanceof String) {
1443             return (String) o;
1444         } else {
1445             return null;
1446         }
1447     }
1448 
1449     /**
1450      * Returns the classloader to be used for loading the callback class
1451      * @return class loader
1452      */
1453     public ClassLoader getClassLoader() {
1454         try {
1455             return Loader.getTCL();
1456         } catch (Exception ex) {
1457             return null;
1458         }
1459     }
1460 
1461     public abstract Object getOption(String key);
1462     public abstract Object getProperty(Object msgContext, String key);
1463 
1464     public abstract void setProperty(Object msgContext, String key,
1465             Object value);
1466 
1467 
1468     public abstract String getPassword(Object msgContext);
1469 
1470     public abstract void setPassword(Object msgContext, String password);
1471 }