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  package org.apache.wss4j.stax.setup;
20  
21  import java.io.OutputStream;
22  import java.security.Key;
23  import java.security.NoSuchAlgorithmException;
24  import java.security.PublicKey;
25  import java.security.cert.X509Certificate;
26  import java.util.List;
27  
28  import javax.crypto.KeyGenerator;
29  import javax.crypto.spec.SecretKeySpec;
30  import javax.xml.parsers.ParserConfigurationException;
31  import javax.xml.stream.XMLStreamWriter;
32  
33  import org.apache.wss4j.common.crypto.Crypto;
34  import org.apache.wss4j.common.crypto.CryptoType;
35  import org.apache.wss4j.common.ext.WSPasswordCallback;
36  import org.apache.wss4j.common.ext.WSSecurityException;
37  import org.apache.wss4j.stax.ext.DocumentCreatorImpl;
38  import org.apache.wss4j.stax.ext.WSSConstants;
39  import org.apache.wss4j.stax.ext.WSSSecurityProperties;
40  import org.apache.wss4j.stax.impl.processor.output.BinarySecurityTokenOutputProcessor;
41  import org.apache.wss4j.stax.impl.processor.output.CustomTokenOutputProcessor;
42  import org.apache.wss4j.stax.impl.processor.output.DerivedKeyTokenOutputProcessor;
43  import org.apache.wss4j.stax.impl.processor.output.EncryptEndingOutputProcessor;
44  import org.apache.wss4j.stax.impl.processor.output.EncryptOutputProcessor;
45  import org.apache.wss4j.stax.impl.processor.output.EncryptedKeyOutputProcessor;
46  import org.apache.wss4j.stax.impl.processor.output.ReferenceListOutputProcessor;
47  import org.apache.wss4j.stax.impl.processor.output.SAMLTokenOutputProcessor;
48  import org.apache.wss4j.stax.impl.processor.output.SecurityContextTokenOutputProcessor;
49  import org.apache.wss4j.stax.impl.processor.output.SecurityHeaderOutputProcessor;
50  import org.apache.wss4j.stax.impl.processor.output.SecurityHeaderReorderProcessor;
51  import org.apache.wss4j.stax.impl.processor.output.SignatureConfirmationOutputProcessor;
52  import org.apache.wss4j.stax.impl.processor.output.TimestampOutputProcessor;
53  import org.apache.wss4j.stax.impl.processor.output.UsernameTokenOutputProcessor;
54  import org.apache.wss4j.stax.impl.processor.output.WSSSignatureOutputProcessor;
55  import org.apache.wss4j.stax.impl.securityToken.KerberosClientSecurityToken;
56  import org.apache.wss4j.stax.securityToken.WSSecurityTokenConstants;
57  import org.apache.wss4j.stax.utils.WSSUtils;
58  import org.apache.xml.security.exceptions.XMLSecurityException;
59  import org.apache.xml.security.stax.config.JCEAlgorithmMapper;
60  import org.apache.xml.security.stax.ext.OutboundSecurityContext;
61  import org.apache.xml.security.stax.ext.OutputProcessor;
62  import org.apache.xml.security.stax.ext.SecurityContext;
63  import org.apache.xml.security.stax.ext.XMLSecurityConstants;
64  import org.apache.xml.security.stax.impl.DocumentContextImpl;
65  import org.apache.xml.security.stax.impl.OutboundSecurityContextImpl;
66  import org.apache.xml.security.stax.impl.OutputProcessorChainImpl;
67  import org.apache.xml.security.stax.impl.XMLSecurityStreamWriter;
68  import org.apache.xml.security.stax.impl.processor.output.FinalOutputProcessor;
69  import org.apache.xml.security.stax.impl.securityToken.GenericOutboundSecurityToken;
70  import org.apache.xml.security.stax.impl.util.IDGenerator;
71  import org.apache.xml.security.stax.securityEvent.SecurityEvent;
72  import org.apache.xml.security.stax.securityEvent.SecurityEventListener;
73  import org.apache.xml.security.stax.securityEvent.TokenSecurityEvent;
74  import org.apache.xml.security.stax.securityToken.OutboundSecurityToken;
75  import org.apache.xml.security.stax.securityToken.SecurityToken;
76  import org.apache.xml.security.stax.securityToken.SecurityTokenConstants.TokenUsage;
77  import org.apache.xml.security.stax.securityToken.SecurityTokenProvider;
78  
79  /**
80   * Outbound Streaming-WebService-Security
81   * An instance of this class can be retrieved over the WSSec class
82   */
83  public class OutboundWSSec {
84  
85      private final WSSSecurityProperties securityProperties;
86  
87      public OutboundWSSec(WSSSecurityProperties securityProperties) {
88          this.securityProperties = securityProperties;
89      }
90  
91      /**
92       * This method is the entry point for the incoming security-engine.
93       * Hand over a outputStream and use the returned XMLStreamWriter for further processing
94       *
95       * @param outputStream The original outputStream
96       * @return A new XMLStreamWriter which does transparently the security processing.
97       * @throws WSSecurityException thrown when a Security failure occurs
98       */
99      public XMLStreamWriter processOutMessage(
100             OutputStream outputStream, String encoding,
101             List<SecurityEvent> requestSecurityEvents) throws WSSecurityException {
102         return processOutMessage(outputStream, encoding, requestSecurityEvents, null);
103     }
104 
105     /**
106      * This method is the entry point for the incoming security-engine.
107      * Hand over the original XMLStreamWriter and use the returned one for further processing
108      *
109      * @param xmlStreamWriter The original xmlStreamWriter
110      * @return A new XMLStreamWriter which does transparently the security processing.
111      * @throws WSSecurityException thrown when a Security failure occurs
112      */
113     public XMLStreamWriter processOutMessage(
114             XMLStreamWriter xmlStreamWriter, String encoding,
115             List<SecurityEvent> requestSecurityEvents) throws WSSecurityException {
116         return processOutMessage(xmlStreamWriter, encoding, requestSecurityEvents, null);
117     }
118 
119     /**
120      * This method is the entry point for the incoming security-engine.
121      * Hand over a outputstream and use the returned XMLStreamWriter for further processing
122      *
123      * @param outputStream The original outputStream
124      * @return A new XMLStreamWriter which does transparently the security processing.
125      * @throws WSSecurityException thrown when a Security failure occurs
126      */
127     public XMLStreamWriter processOutMessage(
128             OutputStream outputStream, String encoding, List<SecurityEvent> requestSecurityEvents,
129             SecurityEventListener securityEventListener) throws WSSecurityException {
130         final OutboundSecurityContextImpl outboundSecurityContext = new OutboundSecurityContextImpl();
131         outboundSecurityContext.putList(SecurityEvent.class, requestSecurityEvents);
132         outboundSecurityContext.addSecurityEventListener(securityEventListener);
133         return processOutMessage(outputStream, encoding, outboundSecurityContext);
134     }
135 
136     /**
137      * This method is the entry point for the incoming security-engine.
138      * Hand over the original XMLStreamWriter and use the returned one for further processing
139      *
140      * @param xmlStreamWriter The original outputStream
141      * @return A new XMLStreamWriter which does transparently the security processing.
142      * @throws WSSecurityException thrown when a Security failure occurs
143      */
144     public XMLStreamWriter processOutMessage(
145             XMLStreamWriter xmlStreamWriter, String encoding, List<SecurityEvent> requestSecurityEvents,
146             SecurityEventListener securityEventListener) throws WSSecurityException {
147         final OutboundSecurityContextImpl outboundSecurityContext = new OutboundSecurityContextImpl();
148         outboundSecurityContext.putList(SecurityEvent.class, requestSecurityEvents);
149         outboundSecurityContext.addSecurityEventListener(securityEventListener);
150         return processOutMessage((Object) xmlStreamWriter, encoding, outboundSecurityContext);
151     }
152 
153     /**
154      * This method is the entry point for the incoming security-engine.
155      * Hand over the original XMLStreamWriter and use the returned one for further processing
156      *
157      * @param xmlStreamWriter The original outputStream
158      * @return A new XMLStreamWriter which does transparently the security processing.
159      * @throws WSSecurityException thrown when a Security failure occurs
160      */
161     public XMLStreamWriter processOutMessage(
162             XMLStreamWriter xmlStreamWriter, String encoding, OutboundSecurityContext outbounSecurityContext)
163                 throws WSSecurityException {
164         return processOutMessage((Object) xmlStreamWriter, encoding, outbounSecurityContext);
165     }
166 
167     public XMLStreamWriter processOutMessage(
168             Object output, String encoding, OutboundSecurityContext outboundSecurityContext
169         ) throws WSSecurityException {
170 
171         final DocumentContextImpl documentContext = new DocumentContextImpl();
172         documentContext.setEncoding(encoding);
173 
174         OutputProcessorChainImpl outputProcessorChain = new OutputProcessorChainImpl(outboundSecurityContext, documentContext);
175 
176         try {
177             final SecurityHeaderOutputProcessor securityHeaderOutputProcessor = new SecurityHeaderOutputProcessor();
178             initializeOutputProcessor(outputProcessorChain, securityHeaderOutputProcessor, null, -1);
179 
180             ConfiguredAction configuredAction = configureActions(outputProcessorChain);
181 
182             // Set up appropriate keys
183             if (configuredAction.signatureAction) {
184                 setupSignatureKey(outputProcessorChain, securityProperties, configuredAction.signedSAML);
185             }
186             if (configuredAction.encryptionAction) {
187                 setupEncryptionKey(outputProcessorChain, securityProperties);
188             }
189             if (configuredAction.kerberos) {
190                 setupKerberosKey(outputProcessorChain, securityProperties,
191                                  configuredAction.signatureKerberos, configuredAction.encryptionKerberos);
192             }
193             if (configuredAction.derivedSignature) {
194                 String id =
195                     outputProcessorChain.getSecurityContext().get(WSSConstants.PROP_USE_THIS_TOKEN_ID_FOR_SIGNATURE);
196                 setDerivedIdentifier(outputProcessorChain, id);
197             }
198             if (configuredAction.derivedEncryption) {
199                 String id =
200                     outputProcessorChain.getSecurityContext().get(WSSConstants.PROP_USE_THIS_TOKEN_ID_FOR_ENCRYPTED_KEY);
201                 if (id == null) {
202                     // Maybe not encrypting the key here...
203                     id = outputProcessorChain.getSecurityContext().get(WSSConstants.PROP_USE_THIS_TOKEN_ID_FOR_ENCRYPTION);
204                 }
205                 setDerivedIdentifier(outputProcessorChain, id);
206             }
207 
208             final SecurityHeaderReorderProcessor securityHeaderReorderProcessor = new SecurityHeaderReorderProcessor();
209             initializeOutputProcessor(outputProcessorChain, securityHeaderReorderProcessor, null, -1);
210 
211             if (output instanceof OutputStream) {
212                 final FinalOutputProcessor finalOutputProcessor = new FinalOutputProcessor((OutputStream) output, encoding);
213                 initializeOutputProcessor(outputProcessorChain, finalOutputProcessor, null, -1);
214 
215             } else if (output instanceof XMLStreamWriter) {
216                 final FinalOutputProcessor finalOutputProcessor = new FinalOutputProcessor((XMLStreamWriter) output);
217                 initializeOutputProcessor(outputProcessorChain, finalOutputProcessor, null, -1);
218 
219             } else {
220                 throw new IllegalArgumentException(output + " is not supported as output");
221             }
222         } catch (XMLSecurityException e) {
223             throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, e);
224         }
225         return new XMLSecurityStreamWriter(outputProcessorChain);
226     }
227 
228     private void initializeOutputProcessor(
229             OutputProcessorChainImpl outputProcessorChain, OutputProcessor outputProcessor,
230             XMLSecurityConstants.Action action, int actionOrder) throws XMLSecurityException {
231         if (actionOrder > -1) {
232             outputProcessor.addAfterProcessor(TimestampOutputProcessor.class);
233             outputProcessor.addAfterProcessor(UsernameTokenOutputProcessor.class);
234             outputProcessor.addAfterProcessor(SignatureConfirmationOutputProcessor.class);
235             outputProcessor.addAfterProcessor(CustomTokenOutputProcessor.class);
236             outputProcessor.addAfterProcessor(BinarySecurityTokenOutputProcessor.class);
237             outputProcessor.addAfterProcessor(SAMLTokenOutputProcessor.class);
238         }
239         outputProcessor.setXMLSecurityProperties(securityProperties);
240         outputProcessor.setAction(action, actionOrder);
241         outputProcessor.init(outputProcessorChain);
242     }
243 
244     private void setupSignatureKey(
245         OutputProcessorChainImpl outputProcessorChain,
246         WSSSecurityProperties securityProperties,
247         boolean signedSAML
248     ) throws XMLSecurityException {
249         final String signatureAlgorithm = securityProperties.getSignatureAlgorithm();
250 
251         GenericOutboundSecurityToken securityToken =
252             getOutboundSecurityToken(outputProcessorChain, WSSConstants.PROP_USE_THIS_TOKEN_ID_FOR_SIGNATURE);
253         // First off, see if we have a supplied token with the correct keys for
254         // (a)symmetric signature
255         if (securityToken != null && signatureAlgorithm != null) {
256             if (signatureAlgorithm.contains("hmac-sha")
257                 && securityToken.getSecretKey(signatureAlgorithm) != null) {
258                 return;
259             } else if (!signatureAlgorithm.contains("hmac-sha") && securityToken.getX509Certificates() != null) {
260                 if (securityToken.getSecretKey(signatureAlgorithm) != null) {
261                     return;
262                 } else {
263                     // We have certs but no private key set. Use the CallbackHandler
264                     Key key =
265                         securityProperties.getSignatureCrypto().getPrivateKey(
266                             securityToken.getX509Certificates()[0], securityProperties.getCallbackHandler()
267                         );
268                     securityToken.setSecretKey(signatureAlgorithm, key);
269                     return;
270                 }
271             }
272         }
273 
274         // We have no supplied key. So use the PasswordCallback to get a secret key or password
275         String alias = securityProperties.getSignatureUser();
276         WSPasswordCallback pwCb = new WSPasswordCallback(alias, WSPasswordCallback.SIGNATURE);
277             WSSUtils.doPasswordCallback(securityProperties.getCallbackHandler(), pwCb);
278 
279         String password = pwCb.getPassword();
280         byte[] secretKey = pwCb.getKey();
281         Key key = null;
282         X509Certificate[] x509Certificates = null;
283         try {
284             if (password != null && securityProperties.getSignatureCrypto() != null) {
285                 key = securityProperties.getSignatureCrypto().getPrivateKey(alias, password);
286                 CryptoType cryptoType = new CryptoType(CryptoType.TYPE.ALIAS);
287                 cryptoType.setAlias(alias);
288                 x509Certificates = securityProperties.getSignatureCrypto().getX509Certificates(cryptoType);
289                 if (x509Certificates == null || x509Certificates.length == 0) {
290                     throw new WSSecurityException(WSSecurityException.ErrorCode.FAILED_SIGNATURE, "noUserCertsFound",
291                                                   new Object[] {alias});
292                 }
293             } else if (secretKey != null) {
294                 x509Certificates = null;
295                 String algoFamily = JCEAlgorithmMapper.getJCEKeyAlgorithmFromURI(signatureAlgorithm);
296                 key = new SecretKeySpec(secretKey, algoFamily);
297             } else {
298                 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILED_SIGNATURE, "noPassword",
299                                               new Object[] {alias});
300             }
301         } catch (WSSecurityException ex) {
302             if (signedSAML && securityProperties.getSamlCallbackHandler() != null) {
303                 // We may get the keys we require from the SAML CallbackHandler...
304                 return;
305             }
306             throw ex;
307         }
308 
309         // Create a new outbound Signature token for the generated key / cert
310         final String id = IDGenerator.generateID(null);
311         final GenericOutboundSecurityToken binarySecurityToken =
312                 new GenericOutboundSecurityToken(id, WSSecurityTokenConstants.X509V3Token, key, x509Certificates);
313 
314         // binarySecurityToken.setSha1Identifier(reference);
315         final SecurityTokenProvider<OutboundSecurityToken> binarySecurityTokenProvider =
316                 new SecurityTokenProvider<OutboundSecurityToken>() {
317 
318             @Override
319             public OutboundSecurityToken getSecurityToken() throws WSSecurityException {
320                 return binarySecurityToken;
321             }
322 
323             @Override
324             public String getId() {
325                 return id;
326             }
327         };
328 
329         outputProcessorChain.getSecurityContext().registerSecurityTokenProvider(id, binarySecurityTokenProvider);
330         outputProcessorChain.getSecurityContext().put(WSSConstants.PROP_USE_THIS_TOKEN_ID_FOR_SIGNATURE, id);
331     }
332 
333     private void setupEncryptionKey(
334         OutputProcessorChainImpl outputProcessorChain,
335         WSSSecurityProperties securityProperties
336     ) throws XMLSecurityException {
337         final String symmetricEncryptionAlgorithm = securityProperties.getEncryptionSymAlgorithm();
338 
339         // First check to see if a Symmetric key is available
340         GenericOutboundSecurityToken securityToken =
341             getOutboundSecurityToken(outputProcessorChain, WSSConstants.PROP_USE_THIS_TOKEN_ID_FOR_ENCRYPTION);
342         if (securityToken == null || securityToken.getSecretKey(symmetricEncryptionAlgorithm) == null) {
343             //prepare the symmetric session key for all encryption parts
344             String keyAlgorithm = JCEAlgorithmMapper.getJCEKeyAlgorithmFromURI(securityProperties.getEncryptionSymAlgorithm());
345             KeyGenerator keyGen;
346             try {
347                 keyGen = KeyGenerator.getInstance(keyAlgorithm);
348             } catch (NoSuchAlgorithmException e) {
349                 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, e);
350             }
351             //the sun JCE provider expects the real key size for 3DES (112 or 168 bit)
352             //whereas bouncy castle expects the block size of 128 or 192 bits
353             if (keyAlgorithm.contains("AES")) {
354                 int keyLength = JCEAlgorithmMapper.getKeyLengthFromURI(securityProperties.getEncryptionSymAlgorithm());
355                 keyGen.init(keyLength);
356             }
357 
358             final Key symmetricKey = keyGen.generateKey();
359             final String symmId = IDGenerator.generateID(null);
360 
361             final GenericOutboundSecurityToken symmetricSecurityToken =
362                 new GenericOutboundSecurityToken(symmId, WSSecurityTokenConstants.EncryptedKeyToken, symmetricKey);
363             securityToken = symmetricSecurityToken;
364             final SecurityTokenProvider<OutboundSecurityToken> securityTokenProvider =
365                 new SecurityTokenProvider<OutboundSecurityToken>() {
366 
367                 @Override
368                 public OutboundSecurityToken getSecurityToken() throws XMLSecurityException {
369                     return symmetricSecurityToken;
370                 }
371 
372                 @Override
373                 public String getId() {
374                     return symmId;
375                 }
376             };
377 
378             outputProcessorChain.getSecurityContext().registerSecurityTokenProvider(symmId, securityTokenProvider);
379             outputProcessorChain.getSecurityContext().put(WSSConstants.PROP_USE_THIS_TOKEN_ID_FOR_ENCRYPTION, symmId);
380         }
381 
382         if (!securityProperties.isEncryptSymmetricEncryptionKey()) {
383             // No EncryptedKey Token required here, so return
384             return;
385         }
386 
387         // Set up a security token with the certs required to encrypt the symmetric key
388         X509Certificate[] x509Certificates = null;
389         PublicKey publicKey = null;
390         if (securityProperties.isUseReqSigCertForEncryption()) {
391             X509Certificate x509Certificate = getReqSigCert(outputProcessorChain.getSecurityContext());
392             if (x509Certificate == null) {
393                 publicKey = getReqSigPublicKey(outputProcessorChain.getSecurityContext());
394                 if (publicKey == null) {
395                     throw new WSSecurityException(WSSecurityException.ErrorCode.FAILED_ENCRYPTION, "noCert");
396                 }
397             } else {
398                 x509Certificates = new X509Certificate[1];
399                 x509Certificates[0] = x509Certificate;
400             }
401         } else if (securityProperties.getEncryptionUseThisCertificate() != null) {
402             x509Certificates = new X509Certificate[1];
403             x509Certificates[0] = securityProperties.getEncryptionUseThisCertificate();
404         } else {
405             CryptoType cryptoType = new CryptoType(CryptoType.TYPE.ALIAS);
406             cryptoType.setAlias(securityProperties.getEncryptionUser());
407             Crypto crypto = securityProperties.getEncryptionCrypto();
408             x509Certificates = crypto.getX509Certificates(cryptoType);
409             if (x509Certificates == null || x509Certificates.length == 0) {
410                 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILED_ENCRYPTION, "noUserCertsFound",
411                                               new Object[] {securityProperties.getEncryptionUser(), "encryption"});
412             }
413         }
414 
415         // Check for Revocation
416         if (securityProperties.isEnableRevocation() && x509Certificates != null) {
417             Crypto crypto = securityProperties.getEncryptionCrypto();
418             crypto.verifyTrust(x509Certificates, true, null, null);
419         }
420 
421         // Create a new outbound EncryptedKey token for the cert
422         final String id = IDGenerator.generateID(null);
423         final GenericOutboundSecurityToken encryptedKeyToken =
424             new GenericOutboundSecurityToken(id, WSSecurityTokenConstants.X509V3Token, publicKey, x509Certificates);
425 
426         encryptedKeyToken.addWrappedToken(securityToken);
427         securityToken.setKeyWrappingToken(encryptedKeyToken);
428 
429         // binarySecurityToken.setSha1Identifier(reference);
430         final SecurityTokenProvider<OutboundSecurityToken> encryptedKeyTokenProvider =
431             new SecurityTokenProvider<OutboundSecurityToken>() {
432 
433             @Override
434             public OutboundSecurityToken getSecurityToken() throws WSSecurityException {
435                 return encryptedKeyToken;
436             }
437 
438             @Override
439             public String getId() {
440                 return id;
441             }
442         };
443 
444         outputProcessorChain.getSecurityContext().registerSecurityTokenProvider(id, encryptedKeyTokenProvider);
445         outputProcessorChain.getSecurityContext().put(WSSConstants.PROP_USE_THIS_TOKEN_ID_FOR_ENCRYPTED_KEY, id);
446     }
447 
448     private void setupKerberosKey(
449         OutputProcessorChainImpl outputProcessorChain,
450         WSSSecurityProperties securityProperties,
451         boolean signature,
452         boolean encryption
453     ) throws XMLSecurityException {
454         GenericOutboundSecurityToken securityToken =
455             getOutboundSecurityToken(outputProcessorChain, WSSConstants.PROP_USE_THIS_TOKEN_ID_FOR_KERBEROS);
456         String kerberosId = null;
457         // First off, see if we have a supplied token
458         if (securityToken == null) {
459             // If not then generate a new key
460             final String id = IDGenerator.generateID(null);
461             kerberosId = id;
462             final KerberosClientSecurityToken kerberosClientSecurityToken =
463                     new KerberosClientSecurityToken(
464                         securityProperties.getCallbackHandler(), id
465                     );
466 
467             final SecurityTokenProvider<OutboundSecurityToken> kerberosSecurityTokenProvider =
468                     new SecurityTokenProvider<OutboundSecurityToken>() {
469 
470                 @Override
471                 public OutboundSecurityToken getSecurityToken() throws WSSecurityException {
472                     return kerberosClientSecurityToken;
473                 }
474 
475                 @Override
476                 public String getId() {
477                     return id;
478                 }
479             };
480 
481             outputProcessorChain.getSecurityContext().registerSecurityTokenProvider(id, kerberosSecurityTokenProvider);
482             outputProcessorChain.getSecurityContext().put(WSSConstants.PROP_USE_THIS_TOKEN_ID_FOR_KERBEROS, id);
483         } else {
484             kerberosId = securityToken.getId();
485         }
486 
487         if (signature) {
488             outputProcessorChain.getSecurityContext().put(WSSConstants.PROP_USE_THIS_TOKEN_ID_FOR_SIGNATURE, kerberosId);
489         }
490         if (encryption) {
491             outputProcessorChain.getSecurityContext().put(WSSConstants.PROP_USE_THIS_TOKEN_ID_FOR_ENCRYPTION, kerberosId);
492         }
493 
494     }
495 
496     // Return an outbound SecurityToken object for a given id (encryption/signature)
497     private GenericOutboundSecurityToken getOutboundSecurityToken(
498         OutputProcessorChainImpl outputProcessorChain, String id
499     ) throws XMLSecurityException {
500         String tokenId =
501             outputProcessorChain.getSecurityContext().get(id);
502         SecurityTokenProvider<OutboundSecurityToken> signatureTokenProvider = null;
503         if (tokenId != null) {
504             signatureTokenProvider =
505                 outputProcessorChain.getSecurityContext().getSecurityTokenProvider(tokenId);
506             if (signatureTokenProvider != null) {
507                 return (GenericOutboundSecurityToken)signatureTokenProvider.getSecurityToken();
508             }
509         }
510 
511         return null;
512     }
513 
514     private X509Certificate getReqSigCert(SecurityContext securityContext) throws XMLSecurityException {
515         List<SecurityEvent> securityEventList = securityContext.getAsList(SecurityEvent.class);
516         if (securityEventList != null) {
517             for (int i = 0; i < securityEventList.size(); i++) {
518                 SecurityEvent securityEvent = securityEventList.get(i);
519                 if (securityEvent instanceof TokenSecurityEvent) {
520                     @SuppressWarnings("unchecked")
521                     TokenSecurityEvent<? extends SecurityToken> tokenSecurityEvent
522                         = (TokenSecurityEvent<? extends SecurityToken>) securityEvent;
523                     TokenUsage mainSig = WSSecurityTokenConstants.TOKENUSAGE_MAIN_SIGNATURE;
524                     if (!tokenSecurityEvent.getSecurityToken().getTokenUsages().contains(mainSig)) {
525                         continue;
526                     }
527                     X509Certificate[] x509Certificates = tokenSecurityEvent.getSecurityToken().getX509Certificates();
528                     if (x509Certificates != null && x509Certificates.length > 0) {
529                         return x509Certificates[0];
530                     }
531                 }
532             }
533         }
534         return null;
535     }
536 
537     private PublicKey getReqSigPublicKey(SecurityContext securityContext) throws XMLSecurityException {
538         List<SecurityEvent> securityEventList = securityContext.getAsList(SecurityEvent.class);
539         if (securityEventList != null) {
540             for (int i = 0; i < securityEventList.size(); i++) {
541                 SecurityEvent securityEvent = securityEventList.get(i);
542                 if (securityEvent instanceof TokenSecurityEvent) {
543                     @SuppressWarnings("unchecked")
544                     TokenSecurityEvent<? extends SecurityToken> tokenSecurityEvent
545                         = (TokenSecurityEvent<? extends SecurityToken>) securityEvent;
546                     TokenUsage mainSig = WSSecurityTokenConstants.TOKENUSAGE_MAIN_SIGNATURE;
547                     if (!tokenSecurityEvent.getSecurityToken().getTokenUsages().contains(mainSig)) {
548                         continue;
549                     }
550                     PublicKey publicKey = tokenSecurityEvent.getSecurityToken().getPublicKey();
551                     if (publicKey != null) {
552                         return publicKey;
553                     }
554                 }
555             }
556         }
557         return null;
558     }
559 
560     private void setDerivedIdentifier(OutputProcessorChainImpl outputProcessorChain, String id) {
561         WSSConstants.DerivedKeyTokenReference derivedKeyTokenReference = securityProperties.getDerivedKeyTokenReference();
562             switch (derivedKeyTokenReference) {
563 
564             case DirectReference:
565                 outputProcessorChain.getSecurityContext().put(WSSConstants.PROP_USE_THIS_TOKEN_ID_FOR_DERIVED_KEY, id);
566                 break;
567             case EncryptedKey:
568                 String symmId = outputProcessorChain.getSecurityContext().get(WSSConstants.PROP_USE_THIS_TOKEN_ID_FOR_ENCRYPTION);
569                 outputProcessorChain.getSecurityContext().put(WSSConstants.PROP_USE_THIS_TOKEN_ID_FOR_DERIVED_KEY, symmId);
570                 outputProcessorChain.getSecurityContext().put(WSSConstants.PROP_USE_THIS_TOKEN_ID_FOR_ENCRYPTED_KEY, id);
571                 break;
572             case SecurityContextToken:
573                 outputProcessorChain.getSecurityContext().put(WSSConstants.PROP_USE_THIS_TOKEN_ID_FOR_SECURITYCONTEXTTOKEN, id);
574                 break;
575             }
576     }
577 
578     private ConfiguredAction configureActions(OutputProcessorChainImpl outputProcessorChain) throws XMLSecurityException {
579         ConfiguredAction configuredAction = new ConfiguredAction();
580 
581         //todo some combinations are not possible atm: eg Action.SIGNATURE and Action.USERNAMETOKEN_SIGNED
582         //todo they use the same signature parts
583 
584         // Check to see whether we have a derived key signature, but not encryption, using
585         // an encrypted key reference (as we only want one encrypted key here...)
586         boolean derivedSignatureButNotDerivedEncryption = false;
587         if (securityProperties.getDerivedKeyTokenReference() == WSSConstants.DerivedKeyTokenReference.EncryptedKey) {
588             for (XMLSecurityConstants.Action action : securityProperties.getActions()) {
589                 if (WSSConstants.SIGNATURE_WITH_DERIVED_KEY.equals(action)) {
590                     derivedSignatureButNotDerivedEncryption = true;
591                 } else if (WSSConstants.ENCRYPTION_WITH_DERIVED_KEY.equals(action)) {
592                     derivedSignatureButNotDerivedEncryption = false;
593                     break;
594                 }
595             }
596         }
597 
598         int actionOrder = -1;
599         for (XMLSecurityConstants.Action action : securityProperties.getActions()) {
600             if (WSSConstants.TIMESTAMP.equals(action)) {
601                 final TimestampOutputProcessor timestampOutputProcessor = new TimestampOutputProcessor();
602                 initializeOutputProcessor(outputProcessorChain, timestampOutputProcessor, action, -1);
603             } else if (WSSConstants.SIGNATURE.equals(action)) {
604                 configuredAction.signatureAction = true;
605                 final BinarySecurityTokenOutputProcessor binarySecurityTokenOutputProcessor =
606                     new BinarySecurityTokenOutputProcessor();
607                 initializeOutputProcessor(outputProcessorChain, binarySecurityTokenOutputProcessor, action, -1);
608 
609                 final WSSSignatureOutputProcessor signatureOutputProcessor = new WSSSignatureOutputProcessor();
610                 initializeOutputProcessor(outputProcessorChain, signatureOutputProcessor, action, ++actionOrder);
611 
612             } else if (WSSConstants.ENCRYPTION.equals(action)) {
613                 configuredAction.encryptionAction = true;
614                 EncryptedKeyOutputProcessor encryptedKeyOutputProcessor = null;
615                 ++actionOrder;
616                 if (securityProperties.isEncryptSymmetricEncryptionKey()) {
617                     final BinarySecurityTokenOutputProcessor binarySecurityTokenOutputProcessor =
618                         new BinarySecurityTokenOutputProcessor();
619                     initializeOutputProcessor(outputProcessorChain, binarySecurityTokenOutputProcessor, action, -1);
620 
621                     encryptedKeyOutputProcessor = new EncryptedKeyOutputProcessor();
622                     initializeOutputProcessor(outputProcessorChain, encryptedKeyOutputProcessor, action, actionOrder);
623                 }
624 
625                 final EncryptOutputProcessor encryptOutputProcessor = new EncryptOutputProcessor();
626                 initializeOutputProcessor(outputProcessorChain, encryptOutputProcessor, action, actionOrder);
627 
628                 if (encryptedKeyOutputProcessor == null) {
629                     final ReferenceListOutputProcessor referenceListOutputProcessor = new ReferenceListOutputProcessor();
630                     referenceListOutputProcessor.addAfterProcessor(EncryptEndingOutputProcessor.class);
631                     initializeOutputProcessor(outputProcessorChain, referenceListOutputProcessor, action, actionOrder);
632                 }
633 
634             } else if (WSSConstants.USERNAMETOKEN.equals(action)) {
635                 final UsernameTokenOutputProcessor usernameTokenOutputProcessor = new UsernameTokenOutputProcessor();
636                 initializeOutputProcessor(outputProcessorChain, usernameTokenOutputProcessor, action, -1);
637             } else if (WSSConstants.USERNAMETOKEN_SIGNED.equals(action)) {
638                 final UsernameTokenOutputProcessor usernameTokenOutputProcessor = new UsernameTokenOutputProcessor();
639                 initializeOutputProcessor(outputProcessorChain, usernameTokenOutputProcessor, action, -1);
640 
641                 final WSSSignatureOutputProcessor signatureOutputProcessor = new WSSSignatureOutputProcessor();
642                 initializeOutputProcessor(outputProcessorChain, signatureOutputProcessor, action, ++actionOrder);
643 
644             } else if (WSSConstants.SIGNATURE_CONFIRMATION.equals(action)) {
645                 final SignatureConfirmationOutputProcessor signatureConfirmationOutputProcessor =
646                         new SignatureConfirmationOutputProcessor();
647                 initializeOutputProcessor(outputProcessorChain, signatureConfirmationOutputProcessor, action, -1);
648 
649             } else if (WSSConstants.SIGNATURE_WITH_DERIVED_KEY.equals(action)) {
650                 ++actionOrder;
651                 if (securityProperties.getDerivedKeyTokenReference() == WSSConstants.DerivedKeyTokenReference.EncryptedKey) {
652                     if (derivedSignatureButNotDerivedEncryption) {
653                         final EncryptedKeyOutputProcessor encryptedKeyOutputProcessor = new EncryptedKeyOutputProcessor();
654                         initializeOutputProcessor(outputProcessorChain, encryptedKeyOutputProcessor, action, actionOrder);
655                     }
656                     configuredAction.encryptionAction = true;
657                     configuredAction.derivedEncryption = true;
658                 } else if (securityProperties.getDerivedKeyTokenReference()
659                     == WSSConstants.DerivedKeyTokenReference.SecurityContextToken) {
660                     final SecurityContextTokenOutputProcessor securityContextTokenOutputProcessor =
661                             new SecurityContextTokenOutputProcessor();
662                     initializeOutputProcessor(outputProcessorChain, securityContextTokenOutputProcessor, action, -1);
663                     configuredAction.signatureAction = true;
664                     configuredAction.derivedSignature = true;
665                 } else {
666                     configuredAction.signatureAction = true;
667                     configuredAction.derivedSignature = true;
668                 }
669 
670                 final DerivedKeyTokenOutputProcessor derivedKeyTokenOutputProcessor = new DerivedKeyTokenOutputProcessor();
671                 initializeOutputProcessor(outputProcessorChain, derivedKeyTokenOutputProcessor, action, -1);
672 
673                 final WSSSignatureOutputProcessor signatureOutputProcessor = new WSSSignatureOutputProcessor();
674                 initializeOutputProcessor(outputProcessorChain, signatureOutputProcessor, action, actionOrder);
675 
676             } else if (WSSConstants.ENCRYPTION_WITH_DERIVED_KEY.equals(action)) {
677                 configuredAction.encryptionAction = true;
678                 configuredAction.derivedEncryption = true;
679 
680                 EncryptedKeyOutputProcessor encryptedKeyOutputProcessor = null;
681 
682                 ++actionOrder;
683                 if (securityProperties.getDerivedKeyTokenReference() == WSSConstants.DerivedKeyTokenReference.EncryptedKey) {
684                     encryptedKeyOutputProcessor = new EncryptedKeyOutputProcessor();
685                     initializeOutputProcessor(outputProcessorChain, encryptedKeyOutputProcessor, action, actionOrder);
686 
687                 } else if (securityProperties.getDerivedKeyTokenReference()
688                     == WSSConstants.DerivedKeyTokenReference.SecurityContextToken) {
689                     final SecurityContextTokenOutputProcessor securityContextTokenOutputProcessor =
690                             new SecurityContextTokenOutputProcessor();
691                     initializeOutputProcessor(outputProcessorChain, securityContextTokenOutputProcessor, action, actionOrder);
692                 }
693                 final DerivedKeyTokenOutputProcessor derivedKeyTokenOutputProcessor = new DerivedKeyTokenOutputProcessor();
694                 initializeOutputProcessor(outputProcessorChain, derivedKeyTokenOutputProcessor, action, actionOrder);
695 
696                 final EncryptOutputProcessor encryptOutputProcessor = new EncryptOutputProcessor();
697                 initializeOutputProcessor(outputProcessorChain, encryptOutputProcessor, action, actionOrder);
698 
699                 if (encryptedKeyOutputProcessor == null) {
700                     final ReferenceListOutputProcessor referenceListOutputProcessor = new ReferenceListOutputProcessor();
701                     referenceListOutputProcessor.addAfterProcessor(EncryptEndingOutputProcessor.class);
702                     initializeOutputProcessor(outputProcessorChain, referenceListOutputProcessor, action, actionOrder);
703                 }
704             } else if (WSSConstants.SAML_TOKEN_SIGNED.equals(action)) {
705                 configuredAction.signatureAction = true;
706                 configuredAction.signedSAML = true;
707                 final BinarySecurityTokenOutputProcessor binarySecurityTokenOutputProcessor =
708                     new BinarySecurityTokenOutputProcessor();
709                 initializeOutputProcessor(outputProcessorChain, binarySecurityTokenOutputProcessor, action, -1);
710 
711                 final SAMLTokenOutputProcessor samlTokenOutputProcessor = new SAMLTokenOutputProcessor();
712                 initializeOutputProcessor(outputProcessorChain, samlTokenOutputProcessor, action, -1);
713 
714                 final WSSSignatureOutputProcessor signatureOutputProcessor = new WSSSignatureOutputProcessor();
715                 initializeOutputProcessor(outputProcessorChain, signatureOutputProcessor, action, ++actionOrder);
716 
717                 if (securityProperties.getDocumentCreator() == null) {
718                     try {
719                         securityProperties.setDocumentCreator(new DocumentCreatorImpl());
720                     } catch (ParserConfigurationException e) {
721                         throw new XMLSecurityException(e);
722                     }
723                 }
724 
725             } else if (WSSConstants.SAML_TOKEN_UNSIGNED.equals(action)) {
726                 final SAMLTokenOutputProcessor samlTokenOutputProcessor = new SAMLTokenOutputProcessor();
727                 initializeOutputProcessor(outputProcessorChain, samlTokenOutputProcessor, action, -1);
728 
729                 if (securityProperties.getDocumentCreator() == null) {
730                     try {
731                         securityProperties.setDocumentCreator(new DocumentCreatorImpl());
732                     } catch (ParserConfigurationException e) {
733                         throw new XMLSecurityException(e);
734                     }
735                 }
736             } else if (WSSConstants.SIGNATURE_WITH_KERBEROS_TOKEN.equals(action)) {
737                 configuredAction.kerberos = true;
738                 configuredAction.signatureKerberos = true;
739                 final BinarySecurityTokenOutputProcessor kerberosTokenOutputProcessor =
740                         new BinarySecurityTokenOutputProcessor();
741                 initializeOutputProcessor(outputProcessorChain, kerberosTokenOutputProcessor, action, -1);
742 
743                 final WSSSignatureOutputProcessor signatureOutputProcessor = new WSSSignatureOutputProcessor();
744                 initializeOutputProcessor(outputProcessorChain, signatureOutputProcessor, action, ++actionOrder);
745             } else if (WSSConstants.ENCRYPTION_WITH_KERBEROS_TOKEN.equals(action)) {
746                 configuredAction.kerberos = true;
747                 configuredAction.encryptionKerberos = true;
748                 final BinarySecurityTokenOutputProcessor kerberosTokenOutputProcessor =
749                         new BinarySecurityTokenOutputProcessor();
750                 initializeOutputProcessor(outputProcessorChain, kerberosTokenOutputProcessor, action, -1);
751 
752                 final EncryptOutputProcessor encryptOutputProcessor = new EncryptOutputProcessor();
753                 initializeOutputProcessor(outputProcessorChain, encryptOutputProcessor, action, ++actionOrder);
754             } else if (WSSConstants.KERBEROS_TOKEN.equals(action)) {
755                 configuredAction.kerberos = true;
756                 final BinarySecurityTokenOutputProcessor kerberosTokenOutputProcessor =
757                     new BinarySecurityTokenOutputProcessor();
758                 initializeOutputProcessor(outputProcessorChain, kerberosTokenOutputProcessor, action, -1);
759             } else if (WSSConstants.CUSTOM_TOKEN.equals(action)) {
760                 final CustomTokenOutputProcessor unknownTokenOutputProcessor =
761                     new CustomTokenOutputProcessor();
762                 initializeOutputProcessor(outputProcessorChain, unknownTokenOutputProcessor, action, -1);
763             }
764         }
765 
766         return configuredAction;
767     }
768 
769     private static final class ConfiguredAction {
770         boolean signatureAction = false;
771         boolean encryptionAction = false;
772         boolean signedSAML = false;
773         boolean kerberos = false;
774         boolean signatureKerberos = false;
775         boolean encryptionKerberos = false;
776         boolean derivedSignature = false;
777         boolean derivedEncryption = false;
778     }
779 }