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.utils;
20  
21  import java.io.IOException;
22  import java.security.Key;
23  import java.security.MessageDigest;
24  import java.security.NoSuchAlgorithmException;
25  import java.security.cert.CertificateEncodingException;
26  import java.security.cert.CertificateException;
27  import java.security.cert.CertificateFactory;
28  import java.security.cert.X509Certificate;
29  import java.util.ArrayList;
30  import java.util.Arrays;
31  import java.util.Iterator;
32  import java.util.List;
33  
34  import javax.security.auth.callback.Callback;
35  import javax.security.auth.callback.CallbackHandler;
36  import javax.security.auth.callback.UnsupportedCallbackException;
37  import javax.xml.namespace.QName;
38  import javax.xml.stream.XMLStreamException;
39  import javax.xml.stream.events.Attribute;
40  
41  import org.apache.wss4j.common.crypto.Merlin;
42  import org.apache.wss4j.common.ext.WSSecurityException;
43  import org.apache.wss4j.stax.ext.WSSConstants;
44  import org.apache.wss4j.stax.ext.WSSSecurityProperties;
45  import org.apache.wss4j.stax.securityEvent.DerivedKeyTokenSecurityEvent;
46  import org.apache.wss4j.stax.securityEvent.EncryptedKeyTokenSecurityEvent;
47  import org.apache.wss4j.stax.securityEvent.HttpsTokenSecurityEvent;
48  import org.apache.wss4j.stax.securityEvent.KerberosTokenSecurityEvent;
49  import org.apache.wss4j.stax.securityEvent.KeyValueTokenSecurityEvent;
50  import org.apache.wss4j.stax.securityEvent.RelTokenSecurityEvent;
51  import org.apache.wss4j.stax.securityEvent.SamlTokenSecurityEvent;
52  import org.apache.wss4j.stax.securityEvent.SecurityContextTokenSecurityEvent;
53  import org.apache.wss4j.stax.securityEvent.UsernameTokenSecurityEvent;
54  import org.apache.wss4j.stax.securityEvent.X509TokenSecurityEvent;
55  import org.apache.wss4j.stax.securityToken.WSSecurityTokenConstants;
56  import org.apache.xml.security.exceptions.XMLSecurityException;
57  import org.apache.xml.security.stax.ext.AbstractOutputProcessor;
58  import org.apache.xml.security.stax.ext.OutputProcessorChain;
59  import org.apache.xml.security.stax.ext.SecurePart;
60  import org.apache.xml.security.stax.ext.XMLSecurityConstants;
61  import org.apache.xml.security.stax.ext.XMLSecurityUtils;
62  import org.apache.xml.security.stax.ext.stax.XMLSecAttribute;
63  import org.apache.xml.security.stax.ext.stax.XMLSecEvent;
64  import org.apache.xml.security.stax.ext.stax.XMLSecStartElement;
65  import org.apache.xml.security.stax.impl.EncryptionPartDef;
66  import org.apache.xml.security.stax.securityEvent.TokenSecurityEvent;
67  import org.apache.xml.security.stax.securityToken.InboundSecurityToken;
68  import org.apache.xml.security.stax.securityToken.SecurityToken;
69  import org.apache.xml.security.utils.XMLUtils;
70  
71  public class WSSUtils extends XMLSecurityUtils {
72  
73      protected WSSUtils() {
74          super();
75      }
76  
77      /**
78       * Executes the Callback handling. Typically used to fetch passwords
79       *
80       * @param callbackHandler
81       * @param callback
82       * @throws WSSecurityException if the callback couldn't be executed
83       */
84      public static void doPasswordCallback(CallbackHandler callbackHandler, Callback callback)
85              throws WSSecurityException {
86  
87          if (callbackHandler == null) {
88              throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "noCallback");
89          }
90          try {
91              callbackHandler.handle(new Callback[]{callback});
92          } catch (IOException | UnsupportedCallbackException e) {
93              throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, e);
94          }
95      }
96  
97      /**
98       * Try to get the secret key from a CallbackHandler implementation
99       *
100      * @param callbackHandler a CallbackHandler implementation
101      * @throws WSSecurityException
102      */
103     public static void doSecretKeyCallback(CallbackHandler callbackHandler, Callback callback)
104             throws WSSecurityException {
105 
106         if (callbackHandler != null) {
107             try {
108                 callbackHandler.handle(new Callback[]{callback});
109             } catch (IOException | UnsupportedCallbackException e) {
110                 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, e, "noPassword");
111             }
112         }
113     }
114 
115     public static String getSOAPMessageVersionNamespace(XMLSecEvent xmlSecEvent) {
116         XMLSecStartElement xmlSecStartElement = xmlSecEvent.getStartElementAtLevel(1);
117         if (xmlSecStartElement != null) {
118             if (WSSConstants.TAG_SOAP11_ENVELOPE.equals(xmlSecStartElement.getName())) {
119                 return WSSConstants.NS_SOAP11;
120             } else if (WSSConstants.TAG_SOAP12_ENVELOPE.equals(xmlSecStartElement.getName())) {
121                 return WSSConstants.NS_SOAP12;
122             }
123         }
124         return null;
125     }
126 
127     public static boolean isInSOAPHeader(XMLSecEvent xmlSecEvent) {
128         final List<QName> elementPath = xmlSecEvent.getElementPath();
129         return isInSOAPHeader(elementPath);
130     }
131 
132     public static boolean isInSOAPHeader(List<QName> elementPath) {
133         if (elementPath.size() > 1) {
134             final QName secondLevelElementName = elementPath.get(1);
135             return WSSConstants.TAG_SOAP_HEADER_LN.equals(secondLevelElementName.getLocalPart())
136                     && elementPath.get(0).getNamespaceURI().equals(secondLevelElementName.getNamespaceURI());
137         }
138         return false;
139     }
140 
141     public static boolean isInSOAPBody(XMLSecEvent xmlSecEvent) {
142         final List<QName> elementPath = xmlSecEvent.getElementPath();
143         return isInSOAPBody(elementPath);
144     }
145 
146     public static boolean isInSOAPBody(List<QName> elementPath) {
147         if (elementPath.size() > 1) {
148             final QName secondLevelElementName = elementPath.get(1);
149             return WSSConstants.TAG_SOAP_BODY_LN.equals(secondLevelElementName.getLocalPart())
150                     && elementPath.get(0).getNamespaceURI().equals(secondLevelElementName.getNamespaceURI());
151         }
152         return false;
153     }
154 
155     public static boolean isInSecurityHeader(XMLSecEvent xmlSecEvent, String actorOrRole) {
156         final List<QName> elementPath = xmlSecEvent.getElementPath();
157         return isInSecurityHeader(xmlSecEvent, elementPath, actorOrRole);
158     }
159 
160     public static boolean isInSecurityHeader(XMLSecEvent xmlSecEvent, List<QName> elementPath, String actorOrRole) {
161         if (elementPath.size() > 2) {
162             final QName secondLevelElementName = elementPath.get(1);
163             return WSSConstants.TAG_WSSE_SECURITY.equals(elementPath.get(2))
164                     && isResponsibleActorOrRole(xmlSecEvent.getStartElementAtLevel(3), actorOrRole)
165                     && WSSConstants.TAG_SOAP_HEADER_LN.equals(secondLevelElementName.getLocalPart())
166                     && elementPath.get(0).getNamespaceURI().equals(secondLevelElementName.getNamespaceURI());
167         }
168         return false;
169     }
170 
171     public static boolean isSecurityHeaderElement(XMLSecEvent xmlSecEvent, String actorOrRole) {
172         if (!xmlSecEvent.isStartElement()) {
173             return false;
174         }
175 
176         final List<QName> elementPath = xmlSecEvent.getElementPath();
177         if (elementPath.size() == 3) {
178             final QName secondLevelElementName = elementPath.get(1);
179             return WSSConstants.TAG_WSSE_SECURITY.equals(elementPath.get(2))
180                     && isResponsibleActorOrRole(xmlSecEvent.getStartElementAtLevel(3), actorOrRole)
181                     && WSSConstants.TAG_SOAP_HEADER_LN.equals(secondLevelElementName.getLocalPart())
182                     && elementPath.get(0).getNamespaceURI().equals(secondLevelElementName.getNamespaceURI());
183         }
184         return false;
185     }
186 
187     public static boolean isResponsibleActorOrRole(XMLSecStartElement xmlSecStartElement, String responsibleActor) {
188         final QName actorRole;
189         final String soapVersionNamespace = getSOAPMessageVersionNamespace(xmlSecStartElement);
190         if (WSSConstants.NS_SOAP11.equals(soapVersionNamespace)) {
191             actorRole = WSSConstants.ATT_SOAP11_ACTOR;
192         } else {
193             actorRole = WSSConstants.ATT_SOAP12_ROLE;
194         }
195 
196         String actor = null;
197         Attribute attribute = xmlSecStartElement.getAttributeByName(actorRole);
198         if (attribute != null) {
199             actor = attribute.getValue();
200         }
201 
202         if (responsibleActor == null) {
203             return actor == null;
204         } else {
205             return responsibleActor.equals(actor);
206         }
207     }
208 
209     public static void createBinarySecurityTokenStructure(AbstractOutputProcessor abstractOutputProcessor,
210                                                           OutputProcessorChain outputProcessorChain,
211                                                           String referenceId, X509Certificate[] x509Certificates,
212                                                           boolean useSingleCertificate)
213             throws XMLStreamException, XMLSecurityException {
214         String valueType;
215         if (useSingleCertificate) {
216             valueType = WSSConstants.NS_X509_V3_TYPE;
217         } else {
218             valueType = WSSConstants.NS_X509_PKIPATH_V1;
219         }
220         List<XMLSecAttribute> attributes = new ArrayList<>(3);
221         attributes.add(abstractOutputProcessor.createAttribute(WSSConstants.ATT_NULL_ENCODING_TYPE,
222                                                                WSSConstants.SOAPMESSAGE_NS10_BASE64_ENCODING));
223         attributes.add(abstractOutputProcessor.createAttribute(WSSConstants.ATT_NULL_VALUE_TYPE, valueType));
224         attributes.add(abstractOutputProcessor.createAttribute(WSSConstants.ATT_WSU_ID, referenceId));
225         abstractOutputProcessor.createStartElementAndOutputAsEvent(outputProcessorChain,
226                                                                    WSSConstants.TAG_WSSE_BINARY_SECURITY_TOKEN,
227                                                                    false, attributes);
228         try {
229             if (useSingleCertificate) {
230                 String encodedCert =
231                     XMLUtils.encodeToString(x509Certificates[0].getEncoded());
232                 abstractOutputProcessor.createCharactersAndOutputAsEvent(outputProcessorChain, encodedCert);
233             } else {
234                 try {
235                     CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
236                     List<X509Certificate> certificates = Arrays.asList(x509Certificates);
237                     String encodedCert =
238                         XMLUtils.encodeToString(certificateFactory.generateCertPath(certificates).getEncoded());
239                     abstractOutputProcessor.createCharactersAndOutputAsEvent(outputProcessorChain, encodedCert);
240                 } catch (CertificateException e) {
241                     throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, e);
242                 }
243             }
244         } catch (CertificateEncodingException e) {
245             throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, e);
246         }
247         abstractOutputProcessor.createEndElementAndOutputAsEvent(outputProcessorChain,
248                                                                  WSSConstants.TAG_WSSE_BINARY_SECURITY_TOKEN);
249     }
250 
251     public static void createX509SubjectKeyIdentifierStructure(AbstractOutputProcessor abstractOutputProcessor,
252                                                                OutputProcessorChain outputProcessorChain,
253                                                                X509Certificate[] x509Certificates)
254             throws XMLSecurityException, XMLStreamException {
255         // As per the 1.1 specification, SKI can only be used for a V3 certificate
256         if (x509Certificates[0].getVersion() != 3) {
257             throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "invalidCertForSKI");
258         }
259 
260         List<XMLSecAttribute> attributes = new ArrayList<>(2);
261         attributes.add(abstractOutputProcessor.createAttribute(WSSConstants.ATT_NULL_ENCODING_TYPE,
262                                                                WSSConstants.SOAPMESSAGE_NS10_BASE64_ENCODING));
263         attributes.add(abstractOutputProcessor.createAttribute(WSSConstants.ATT_NULL_VALUE_TYPE,
264                                                                WSSConstants.NS_X509_SKI));
265         abstractOutputProcessor.createStartElementAndOutputAsEvent(outputProcessorChain,
266                                                                    WSSConstants.TAG_WSSE_KEY_IDENTIFIER,
267                                                                    false, attributes);
268         byte[] data = new Merlin().getSKIBytesFromCert(x509Certificates[0]);
269         abstractOutputProcessor.createCharactersAndOutputAsEvent(outputProcessorChain,
270                                                                  XMLUtils.encodeToString(data));
271         abstractOutputProcessor.createEndElementAndOutputAsEvent(outputProcessorChain,
272                                                                  WSSConstants.TAG_WSSE_KEY_IDENTIFIER);
273     }
274 
275     public static void createX509KeyIdentifierStructure(AbstractOutputProcessor abstractOutputProcessor,
276                                                         OutputProcessorChain outputProcessorChain,
277                                                         X509Certificate[] x509Certificates)
278             throws XMLStreamException, XMLSecurityException {
279         List<XMLSecAttribute> attributes = new ArrayList<>(2);
280         attributes.add(abstractOutputProcessor.createAttribute(WSSConstants.ATT_NULL_ENCODING_TYPE,
281                                                                WSSConstants.SOAPMESSAGE_NS10_BASE64_ENCODING));
282         attributes.add(abstractOutputProcessor.createAttribute(WSSConstants.ATT_NULL_VALUE_TYPE,
283                                                                WSSConstants.NS_X509_V3_TYPE));
284         abstractOutputProcessor.createStartElementAndOutputAsEvent(outputProcessorChain,
285                                                                    WSSConstants.TAG_WSSE_KEY_IDENTIFIER,
286                                                                    false, attributes);
287         try {
288             String encodedCert = XMLUtils.encodeToString(x509Certificates[0].getEncoded());
289             abstractOutputProcessor.createCharactersAndOutputAsEvent(outputProcessorChain, encodedCert);
290         } catch (CertificateEncodingException e) {
291             throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, e);
292         }
293         abstractOutputProcessor.createEndElementAndOutputAsEvent(outputProcessorChain,
294                                                                  WSSConstants.TAG_WSSE_KEY_IDENTIFIER);
295     }
296 
297     public static void createThumbprintKeyIdentifierStructure(AbstractOutputProcessor abstractOutputProcessor,
298                                                               OutputProcessorChain outputProcessorChain,
299                                                               X509Certificate[] x509Certificates)
300             throws XMLStreamException, XMLSecurityException {
301         List<XMLSecAttribute> attributes = new ArrayList<>(2);
302         attributes.add(abstractOutputProcessor.createAttribute(WSSConstants.ATT_NULL_ENCODING_TYPE,
303                                                                WSSConstants.SOAPMESSAGE_NS10_BASE64_ENCODING));
304         attributes.add(abstractOutputProcessor.createAttribute(WSSConstants.ATT_NULL_VALUE_TYPE,
305                                                                WSSConstants.NS_THUMBPRINT));
306         abstractOutputProcessor.createStartElementAndOutputAsEvent(outputProcessorChain,
307                                                                    WSSConstants.TAG_WSSE_KEY_IDENTIFIER,
308                                                                    false, attributes);
309         try {
310             MessageDigest sha = MessageDigest.getInstance("SHA-1");
311             byte[] data = sha.digest(x509Certificates[0].getEncoded());
312             abstractOutputProcessor.createCharactersAndOutputAsEvent(outputProcessorChain,
313                                                                      XMLUtils.encodeToString(data));
314         } catch (CertificateEncodingException | NoSuchAlgorithmException e) {
315             throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, e);
316         }
317         abstractOutputProcessor.createEndElementAndOutputAsEvent(outputProcessorChain, WSSConstants.TAG_WSSE_KEY_IDENTIFIER);
318     }
319 
320     public static void createEncryptedKeySha1IdentifierStructure(AbstractOutputProcessor abstractOutputProcessor,
321                                                                  OutputProcessorChain outputProcessorChain, Key key)
322             throws XMLStreamException, XMLSecurityException {
323 
324         try {
325             MessageDigest sha = MessageDigest.getInstance("SHA-1");
326             byte[] data = sha.digest(key.getEncoded());
327             createEncryptedKeySha1IdentifierStructure(abstractOutputProcessor, outputProcessorChain,
328                                                       XMLUtils.encodeToString(data));
329         } catch (NoSuchAlgorithmException e) {
330             throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, e);
331         }
332     }
333 
334     public static void createEncryptedKeySha1IdentifierStructure(AbstractOutputProcessor abstractOutputProcessor,
335                                                                  OutputProcessorChain outputProcessorChain, String identifier)
336             throws XMLStreamException, XMLSecurityException {
337 
338         List<XMLSecAttribute> attributes = new ArrayList<>(2);
339         attributes.add(abstractOutputProcessor.createAttribute(WSSConstants.ATT_NULL_ENCODING_TYPE,
340                                                                WSSConstants.SOAPMESSAGE_NS10_BASE64_ENCODING));
341         attributes.add(abstractOutputProcessor.createAttribute(WSSConstants.ATT_NULL_VALUE_TYPE,
342                                                                WSSConstants.NS_ENCRYPTED_KEY_SHA1));
343         abstractOutputProcessor.createStartElementAndOutputAsEvent(outputProcessorChain, WSSConstants.TAG_WSSE_KEY_IDENTIFIER,
344                                                                    false, attributes);
345         abstractOutputProcessor.createCharactersAndOutputAsEvent(outputProcessorChain, identifier);
346         abstractOutputProcessor.createEndElementAndOutputAsEvent(outputProcessorChain, WSSConstants.TAG_WSSE_KEY_IDENTIFIER);
347     }
348 
349     public static void createKerberosSha1IdentifierStructure(AbstractOutputProcessor abstractOutputProcessor,
350                                                                  OutputProcessorChain outputProcessorChain, String identifier)
351             throws XMLStreamException, XMLSecurityException {
352 
353         List<XMLSecAttribute> attributes = new ArrayList<>(2);
354         attributes.add(abstractOutputProcessor.createAttribute(WSSConstants.ATT_NULL_ENCODING_TYPE,
355                                                                WSSConstants.SOAPMESSAGE_NS10_BASE64_ENCODING));
356         attributes.add(abstractOutputProcessor.createAttribute(WSSConstants.ATT_NULL_VALUE_TYPE,
357                                                                WSSConstants.NS_KERBEROS5_AP_REQ_SHA1));
358         abstractOutputProcessor.createStartElementAndOutputAsEvent(outputProcessorChain, WSSConstants.TAG_WSSE_KEY_IDENTIFIER,
359                                                                    false, attributes);
360         abstractOutputProcessor.createCharactersAndOutputAsEvent(outputProcessorChain, identifier);
361         abstractOutputProcessor.createEndElementAndOutputAsEvent(outputProcessorChain, WSSConstants.TAG_WSSE_KEY_IDENTIFIER);
362     }
363 
364     public static void createBSTReferenceStructure(AbstractOutputProcessor abstractOutputProcessor,
365                                                    OutputProcessorChain outputProcessorChain, String referenceId,
366                                                    String valueType, boolean includedInMessage)
367             throws XMLStreamException, XMLSecurityException {
368         List<XMLSecAttribute> attributes = new ArrayList<>(2);
369         String uri = includedInMessage ? "#" + referenceId : referenceId;
370         attributes.add(abstractOutputProcessor.createAttribute(WSSConstants.ATT_NULL_URI, uri));
371         if (valueType != null) {
372             attributes.add(abstractOutputProcessor.createAttribute(WSSConstants.ATT_NULL_VALUE_TYPE, valueType));
373         }
374         abstractOutputProcessor.createStartElementAndOutputAsEvent(outputProcessorChain, WSSConstants.TAG_WSSE_REFERENCE,
375                                                                    false, attributes);
376         abstractOutputProcessor.createEndElementAndOutputAsEvent(outputProcessorChain, WSSConstants.TAG_WSSE_REFERENCE);
377     }
378 
379     public static void createEmbeddedKeyIdentifierStructure(AbstractOutputProcessor abstractOutputProcessor,
380                                                             OutputProcessorChain outputProcessorChain,
381                                                             WSSecurityTokenConstants.TokenType tokenType, String referenceId)
382             throws XMLStreamException, XMLSecurityException {
383         List<XMLSecAttribute> attributes = new ArrayList<>(1);
384         if (WSSecurityTokenConstants.SAML_10_TOKEN.equals(tokenType) || WSSecurityTokenConstants.SAML_11_TOKEN.equals(tokenType)) {
385             attributes.add(abstractOutputProcessor.createAttribute(WSSConstants.ATT_NULL_VALUE_TYPE, WSSConstants.NS_SAML10_TYPE));
386         } else if (WSSecurityTokenConstants.SAML_20_TOKEN.equals(tokenType)) {
387             attributes.add(abstractOutputProcessor.createAttribute(WSSConstants.ATT_NULL_VALUE_TYPE, WSSConstants.NS_SAML20_TYPE));
388         }
389         abstractOutputProcessor.createStartElementAndOutputAsEvent(outputProcessorChain, WSSConstants.TAG_WSSE_KEY_IDENTIFIER,
390                                                                    false, attributes);
391         abstractOutputProcessor.createCharactersAndOutputAsEvent(outputProcessorChain, referenceId);
392         abstractOutputProcessor.createEndElementAndOutputAsEvent(outputProcessorChain, WSSConstants.TAG_WSSE_KEY_IDENTIFIER);
393     }
394 
395     public static void createSAMLKeyIdentifierStructure(AbstractOutputProcessor abstractOutputProcessor,
396                                                             OutputProcessorChain outputProcessorChain,
397                                                             WSSecurityTokenConstants.TokenType tokenType, String referenceId)
398             throws XMLStreamException, XMLSecurityException {
399         List<XMLSecAttribute> attributes = new ArrayList<>(1);
400         if (WSSecurityTokenConstants.SAML_10_TOKEN.equals(tokenType) || WSSecurityTokenConstants.SAML_11_TOKEN.equals(tokenType)) {
401             attributes.add(abstractOutputProcessor.createAttribute(WSSConstants.ATT_NULL_VALUE_TYPE, WSSConstants.NS_SAML10_TYPE));
402         } else if (WSSecurityTokenConstants.SAML_20_TOKEN.equals(tokenType)) {
403             attributes.add(abstractOutputProcessor.createAttribute(WSSConstants.ATT_NULL_VALUE_TYPE, WSSConstants.NS_SAML20_TYPE));
404         }
405         abstractOutputProcessor.createStartElementAndOutputAsEvent(outputProcessorChain, WSSConstants.TAG_WSSE_KEY_IDENTIFIER,
406                                                                    false, attributes);
407         abstractOutputProcessor.createCharactersAndOutputAsEvent(outputProcessorChain, referenceId);
408         abstractOutputProcessor.createEndElementAndOutputAsEvent(outputProcessorChain, WSSConstants.TAG_WSSE_KEY_IDENTIFIER);
409     }
410 
411     public static void createUsernameTokenReferenceStructure(AbstractOutputProcessor abstractOutputProcessor,
412                                                              OutputProcessorChain outputProcessorChain, String tokenId)
413             throws XMLStreamException, XMLSecurityException {
414         List<XMLSecAttribute> attributes = new ArrayList<>(2);
415         attributes.add(abstractOutputProcessor.createAttribute(WSSConstants.ATT_NULL_URI, "#" + tokenId));
416         attributes.add(abstractOutputProcessor.createAttribute(WSSConstants.ATT_NULL_VALUE_TYPE,
417                                                                WSSConstants.NS_USERNAMETOKEN_PROFILE_USERNAME_TOKEN));
418         abstractOutputProcessor.createStartElementAndOutputAsEvent(outputProcessorChain, WSSConstants.TAG_WSSE_REFERENCE,
419                                                                    false, attributes);
420         abstractOutputProcessor.createEndElementAndOutputAsEvent(outputProcessorChain, WSSConstants.TAG_WSSE_REFERENCE);
421     }
422 
423     public static void createReferenceListStructureForEncryption(AbstractOutputProcessor abstractOutputProcessor,
424                                                              OutputProcessorChain outputProcessorChain)
425             throws XMLStreamException, XMLSecurityException {
426         List<EncryptionPartDef> encryptionPartDefs =
427                 outputProcessorChain.getSecurityContext().getAsList(EncryptionPartDef.class);
428         if (encryptionPartDefs == null) {
429             return;
430         }
431         List<XMLSecAttribute> attributes;
432         abstractOutputProcessor.createStartElementAndOutputAsEvent(
433                 outputProcessorChain, XMLSecurityConstants.TAG_xenc_ReferenceList, true, null);
434         //output the references to the encrypted data:
435         Iterator<EncryptionPartDef> encryptionPartDefIterator = encryptionPartDefs.iterator();
436         while (encryptionPartDefIterator.hasNext()) {
437             EncryptionPartDef encryptionPartDef = encryptionPartDefIterator.next();
438 
439             attributes = new ArrayList<>(1);
440             attributes.add(abstractOutputProcessor.createAttribute(
441                     XMLSecurityConstants.ATT_NULL_URI, "#" + encryptionPartDef.getEncRefId()));
442             abstractOutputProcessor.createStartElementAndOutputAsEvent(
443                     outputProcessorChain, XMLSecurityConstants.TAG_xenc_DataReference, false, attributes);
444             final String compressionAlgorithm =
445                     ((WSSSecurityProperties)abstractOutputProcessor.getSecurityProperties()).getEncryptionCompressionAlgorithm();
446             if (compressionAlgorithm != null) {
447                 abstractOutputProcessor.createStartElementAndOutputAsEvent(
448                         outputProcessorChain, XMLSecurityConstants.TAG_dsig_Transforms, true, null);
449                 attributes = new ArrayList<>(1);
450                 attributes.add(abstractOutputProcessor.createAttribute(
451                         XMLSecurityConstants.ATT_NULL_Algorithm, compressionAlgorithm));
452                 abstractOutputProcessor.createStartElementAndOutputAsEvent(
453                         outputProcessorChain, XMLSecurityConstants.TAG_dsig_Transform, false, attributes);
454                 abstractOutputProcessor.createEndElementAndOutputAsEvent(
455                         outputProcessorChain, XMLSecurityConstants.TAG_dsig_Transform);
456                 abstractOutputProcessor.createEndElementAndOutputAsEvent(
457                         outputProcessorChain, XMLSecurityConstants.TAG_dsig_Transforms);
458             }
459             abstractOutputProcessor.createEndElementAndOutputAsEvent(
460                     outputProcessorChain, XMLSecurityConstants.TAG_xenc_DataReference);
461         }
462         abstractOutputProcessor.createEndElementAndOutputAsEvent(
463                 outputProcessorChain, XMLSecurityConstants.TAG_xenc_ReferenceList);
464     }
465 
466     public static void createEncryptedDataStructureForAttachments(
467             AbstractOutputProcessor abstractOutputProcessor, OutputProcessorChain outputProcessorChain)
468             throws XMLStreamException, XMLSecurityException {
469 
470         List<EncryptionPartDef> encryptionPartDefs =
471                 outputProcessorChain.getSecurityContext().getAsList(EncryptionPartDef.class);
472         if (encryptionPartDefs == null) {
473             return;
474         }
475 
476         Iterator<EncryptionPartDef> encryptionPartDefIterator = encryptionPartDefs.iterator();
477         while (encryptionPartDefIterator.hasNext()) {
478             EncryptionPartDef encryptionPartDef = encryptionPartDefIterator.next();
479 
480             if (encryptionPartDef.getCipherReferenceId() == null) {
481                 continue;
482             }
483 
484             List<XMLSecAttribute> attributes = new ArrayList<>(3);
485             attributes.add(abstractOutputProcessor.createAttribute(XMLSecurityConstants.ATT_NULL_Id,
486                     encryptionPartDef.getEncRefId()));
487             if (encryptionPartDef.getModifier() == SecurePart.Modifier.Element) {
488                 attributes.add(
489                         abstractOutputProcessor.createAttribute(XMLSecurityConstants.ATT_NULL_Type,
490                                 WSSConstants.SWA_ATTACHMENT_ENCRYPTED_DATA_TYPE_COMPLETE));
491             } else {
492                 attributes.add(
493                         abstractOutputProcessor.createAttribute(XMLSecurityConstants.ATT_NULL_Type,
494                                 WSSConstants.SWA_ATTACHMENT_ENCRYPTED_DATA_TYPE_CONTENT_ONLY));
495             }
496             attributes.add(
497                     abstractOutputProcessor.createAttribute(XMLSecurityConstants.ATT_NULL_MimeType,
498                             encryptionPartDef.getMimeType()));
499             abstractOutputProcessor.createStartElementAndOutputAsEvent(outputProcessorChain,
500                     XMLSecurityConstants.TAG_xenc_EncryptedData, true, attributes);
501 
502             attributes = new ArrayList<>(1);
503             attributes.add(abstractOutputProcessor.createAttribute(XMLSecurityConstants.ATT_NULL_Algorithm,
504                     abstractOutputProcessor.getSecurityProperties().getEncryptionSymAlgorithm()));
505             abstractOutputProcessor.createStartElementAndOutputAsEvent(outputProcessorChain,
506                     XMLSecurityConstants.TAG_xenc_EncryptionMethod, false, attributes);
507 
508             abstractOutputProcessor.createEndElementAndOutputAsEvent(outputProcessorChain,
509                     XMLSecurityConstants.TAG_xenc_EncryptionMethod);
510 
511             abstractOutputProcessor.createStartElementAndOutputAsEvent(outputProcessorChain,
512                     XMLSecurityConstants.TAG_dsig_KeyInfo, true, null);
513 
514             attributes = new ArrayList<>(1);
515             attributes.add(abstractOutputProcessor.createAttribute(WSSConstants.ATT_WSSE11_TOKEN_TYPE,
516                     WSSConstants.NS_WSS_ENC_KEY_VALUE_TYPE));
517             abstractOutputProcessor.createStartElementAndOutputAsEvent(outputProcessorChain,
518                     WSSConstants.TAG_WSSE_SECURITY_TOKEN_REFERENCE, true, attributes);
519 
520             attributes = new ArrayList<>(1);
521             attributes.add(abstractOutputProcessor.createAttribute(WSSConstants.ATT_NULL_URI,
522                     "#" + encryptionPartDef.getKeyId()));
523             abstractOutputProcessor.createStartElementAndOutputAsEvent(outputProcessorChain,
524                     WSSConstants.TAG_WSSE_REFERENCE, false, attributes);
525             abstractOutputProcessor.createEndElementAndOutputAsEvent(outputProcessorChain,
526                     WSSConstants.TAG_WSSE_REFERENCE);
527             abstractOutputProcessor.createEndElementAndOutputAsEvent(outputProcessorChain,
528                     WSSConstants.TAG_WSSE_SECURITY_TOKEN_REFERENCE);
529             abstractOutputProcessor.createEndElementAndOutputAsEvent(outputProcessorChain,
530                     XMLSecurityConstants.TAG_dsig_KeyInfo);
531 
532             abstractOutputProcessor.createStartElementAndOutputAsEvent(outputProcessorChain,
533                     XMLSecurityConstants.TAG_xenc_CipherData, false, null);
534 
535             attributes = new ArrayList<>(1);
536             attributes.add(abstractOutputProcessor.createAttribute(WSSConstants.ATT_NULL_URI,
537                     "cid:" + encryptionPartDef.getCipherReferenceId()));
538             abstractOutputProcessor.createStartElementAndOutputAsEvent(outputProcessorChain,
539                     XMLSecurityConstants.TAG_xenc_CipherReference, false, attributes);
540 
541             abstractOutputProcessor.createStartElementAndOutputAsEvent(
542                     outputProcessorChain, XMLSecurityConstants.TAG_xenc_Transforms, false, null);
543 
544             attributes = new ArrayList<>(1);
545             attributes.add(abstractOutputProcessor.createAttribute(
546                     XMLSecurityConstants.ATT_NULL_Algorithm, WSSConstants.SWA_ATTACHMENT_CIPHERTEXT_TRANS));
547             abstractOutputProcessor.createStartElementAndOutputAsEvent(
548                     outputProcessorChain, XMLSecurityConstants.TAG_dsig_Transform, true, attributes);
549             abstractOutputProcessor.createEndElementAndOutputAsEvent(
550                     outputProcessorChain, XMLSecurityConstants.TAG_dsig_Transform);
551             abstractOutputProcessor.createEndElementAndOutputAsEvent(
552                     outputProcessorChain, XMLSecurityConstants.TAG_dsig_Transforms);
553 
554             abstractOutputProcessor.createEndElementAndOutputAsEvent(outputProcessorChain,
555                     XMLSecurityConstants.TAG_xenc_CipherReference);
556             abstractOutputProcessor.createEndElementAndOutputAsEvent(outputProcessorChain,
557                     XMLSecurityConstants.TAG_xenc_CipherData);
558             abstractOutputProcessor.createEndElementAndOutputAsEvent(outputProcessorChain,
559                     XMLSecurityConstants.TAG_xenc_EncryptedData);
560         }
561     }
562 
563     @SuppressWarnings("unchecked")
564     public static TokenSecurityEvent<? extends InboundSecurityToken>
565         createTokenSecurityEvent(final InboundSecurityToken inboundSecurityToken, String correlationID)
566             throws WSSecurityException {
567         WSSecurityTokenConstants.TokenType tokenType = inboundSecurityToken.getTokenType();
568 
569         TokenSecurityEvent<? extends SecurityToken> tokenSecurityEvent;
570         if (WSSecurityTokenConstants.X509V1Token.equals(tokenType)
571             || WSSecurityTokenConstants.X509V3Token.equals(tokenType)
572             || WSSecurityTokenConstants.X509Pkcs7Token.equals(tokenType)
573             || WSSecurityTokenConstants.X509PkiPathV1Token.equals(tokenType)) {
574             tokenSecurityEvent = new X509TokenSecurityEvent();
575         } else if (WSSecurityTokenConstants.USERNAME_TOKEN.equals(tokenType)) {
576             tokenSecurityEvent = new UsernameTokenSecurityEvent();
577         } else if (WSSecurityTokenConstants.KERBEROS_TOKEN.equals(tokenType)) {
578             tokenSecurityEvent = new KerberosTokenSecurityEvent();
579         } else if (WSSecurityTokenConstants.SECURITY_CONTEXT_TOKEN.equals(tokenType)) {
580             tokenSecurityEvent = new SecurityContextTokenSecurityEvent();
581         } else if (WSSecurityTokenConstants.SAML_10_TOKEN.equals(tokenType)
582             || WSSecurityTokenConstants.SAML_11_TOKEN.equals(tokenType)
583             || WSSecurityTokenConstants.SAML_20_TOKEN.equals(tokenType)) {
584             tokenSecurityEvent = new SamlTokenSecurityEvent();
585         } else if (WSSecurityTokenConstants.REL_TOKEN.equals(tokenType)) {
586             tokenSecurityEvent = new RelTokenSecurityEvent();
587         } else if (WSSecurityTokenConstants.HTTPS_TOKEN.equals(tokenType)) {
588             tokenSecurityEvent = new HttpsTokenSecurityEvent();
589         } else if (WSSecurityTokenConstants.KeyValueToken.equals(tokenType)) {
590             tokenSecurityEvent = new KeyValueTokenSecurityEvent();
591         } else if (WSSecurityTokenConstants.DerivedKeyToken.equals(tokenType)) {
592             tokenSecurityEvent = new DerivedKeyTokenSecurityEvent();
593         } else if (WSSecurityTokenConstants.EncryptedKeyToken.equals(tokenType)) {
594             tokenSecurityEvent = new EncryptedKeyTokenSecurityEvent();
595         } else {
596             throw new WSSecurityException(WSSecurityException.ErrorCode.UNSUPPORTED_SECURITY_TOKEN);
597         }
598         ((TokenSecurityEvent<SecurityToken>)tokenSecurityEvent).setSecurityToken(inboundSecurityToken);
599         tokenSecurityEvent.setCorrelationID(correlationID);
600         return (TokenSecurityEvent<? extends InboundSecurityToken>)tokenSecurityEvent;
601     }
602 
603     public static boolean pathMatches(List<QName> path1, List<QName> path2) {
604         return pathMatches(path1, path2, false);
605     }
606 
607     public static boolean pathMatches(List<QName> path1, List<QName> path2, boolean lastElementWildCard) {
608         if (path1 == null) {
609             throw new IllegalArgumentException("Internal error");
610         }
611         if (path2 == null || path1.size() != path2.size()) {
612             return false;
613         }
614         Iterator<QName> path1Iterator = path1.iterator();
615         Iterator<QName> path2Iterator = path2.iterator();
616         while (path1Iterator.hasNext()) {
617             QName qName1 = path1Iterator.next();
618             QName qName2 = path2Iterator.next();
619             if (!qName1.equals(qName2)) {
620                 if (!path1Iterator.hasNext() && lastElementWildCard) {
621                     if (!qName1.getNamespaceURI().equals(qName2.getNamespaceURI())) {
622                         return false;
623                     }
624                 } else {
625                     return false;
626                 }
627             }
628         }
629         return true;
630     }
631 
632     public static String pathAsString(List<QName> path) {
633         StringBuilder stringBuilder = new StringBuilder();
634         Iterator<QName> pathIterator = path.iterator();
635         while (pathIterator.hasNext()) {
636             QName qName = pathIterator.next();
637             stringBuilder.append('/');
638             stringBuilder.append(qName.toString());
639         }
640         return stringBuilder.toString();
641     }
642 
643     @SuppressWarnings("unchecked")
644     public static <T extends SecurityToken> T getRootToken(T securityToken) throws XMLSecurityException {
645         T tmp = securityToken;
646         while (tmp.getKeyWrappingToken() != null) {
647             tmp = (T)tmp.getKeyWrappingToken();
648         }
649         return tmp;
650     }
651 
652 }