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.impl.processor.output;
20  
21  import java.security.Key;
22  import java.security.PrivateKey;
23  import java.security.cert.X509Certificate;
24  import java.util.ArrayList;
25  import java.util.Iterator;
26  import java.util.List;
27  
28  import javax.crypto.spec.SecretKeySpec;
29  import javax.xml.namespace.QName;
30  import javax.xml.parsers.ParserConfigurationException;
31  import javax.xml.stream.XMLStreamException;
32  
33  import org.apache.wss4j.common.crypto.CryptoType;
34  import org.apache.wss4j.common.ext.WSPasswordCallback;
35  import org.apache.wss4j.common.ext.WSSecurityException;
36  import org.apache.wss4j.common.saml.OpenSAMLUtil;
37  import org.apache.wss4j.common.saml.SAMLCallback;
38  import org.apache.wss4j.common.saml.SAMLUtil;
39  import org.apache.wss4j.common.saml.SamlAssertionWrapper;
40  import org.apache.wss4j.common.saml.bean.KeyInfoBean;
41  import org.apache.wss4j.common.saml.bean.SubjectBean;
42  import org.apache.wss4j.stax.ext.WSSConfigurationException;
43  import org.apache.wss4j.stax.ext.WSSConstants;
44  import org.apache.wss4j.stax.ext.WSSSecurePart;
45  import org.apache.wss4j.stax.ext.WSSSecurityProperties;
46  import org.apache.wss4j.stax.securityEvent.WSSecurityEventConstants;
47  import org.apache.wss4j.stax.securityToken.WSSecurityTokenConstants;
48  import org.apache.wss4j.stax.utils.WSSUtils;
49  import org.apache.xml.security.exceptions.XMLSecurityException;
50  import org.apache.xml.security.stax.config.JCEAlgorithmMapper;
51  import org.apache.xml.security.stax.ext.AbstractOutputProcessor;
52  import org.apache.xml.security.stax.ext.OutputProcessorChain;
53  import org.apache.xml.security.stax.ext.SecurePart;
54  import org.apache.xml.security.stax.ext.XMLSecurityConstants;
55  import org.apache.xml.security.stax.ext.stax.XMLSecAttribute;
56  import org.apache.xml.security.stax.ext.stax.XMLSecEvent;
57  import org.apache.xml.security.stax.impl.securityToken.GenericOutboundSecurityToken;
58  import org.apache.xml.security.stax.impl.util.IDGenerator;
59  import org.apache.xml.security.stax.securityEvent.TokenSecurityEvent;
60  import org.apache.xml.security.stax.securityToken.OutboundSecurityToken;
61  import org.apache.xml.security.stax.securityToken.SecurityTokenProvider;
62  import org.opensaml.saml.common.SAMLVersion;
63  import org.w3c.dom.Document;
64  import org.w3c.dom.Element;
65  
66  public class SAMLTokenOutputProcessor extends AbstractOutputProcessor {
67  
68      private static final org.slf4j.Logger LOG =
69          org.slf4j.LoggerFactory.getLogger(SAMLTokenOutputProcessor.class);
70  
71      public SAMLTokenOutputProcessor() throws XMLSecurityException {
72          super();
73          addBeforeProcessor(BinarySecurityTokenOutputProcessor.class);
74          addBeforeProcessor(WSSSignatureOutputProcessor.class);
75      }
76  
77      @Override
78      public void processEvent(XMLSecEvent xmlSecEvent, final OutputProcessorChain outputProcessorChain)
79              throws XMLStreamException, XMLSecurityException {
80  
81          try {
82              final SAMLCallback samlCallback = new SAMLCallback();
83              SAMLUtil.doSAMLCallback(((WSSSecurityProperties) getSecurityProperties()).getSamlCallbackHandler(), samlCallback);
84              SamlAssertionWrapper samlAssertionWrapper = new SamlAssertionWrapper(samlCallback);
85  
86              if (samlCallback.isSignAssertion()) {
87                  samlAssertionWrapper.signAssertion(
88                          samlCallback.getIssuerKeyName(),
89                          samlCallback.getIssuerKeyPassword(),
90                          samlCallback.getIssuerCrypto(),
91                          samlCallback.isSendKeyValue(),
92                          samlCallback.getCanonicalizationAlgorithm(),
93                          samlCallback.getSignatureAlgorithm(),
94                          samlCallback.getSignatureDigestAlgorithm()
95                  );
96              }
97  
98              boolean senderVouches = false;
99              boolean hok = false;
100             List<String> methods = samlAssertionWrapper.getConfirmationMethods();
101             if (methods != null && !methods.isEmpty()) {
102                 String confirmMethod = methods.get(0);
103                 if (OpenSAMLUtil.isMethodSenderVouches(confirmMethod)) {
104                     senderVouches = true;
105                 } else if (OpenSAMLUtil.isMethodHolderOfKey(confirmMethod)) {
106                     hok = true;
107                 }
108             }
109 
110             final String securityTokenReferenceId = IDGenerator.generateID(null);
111             final String tokenId = samlAssertionWrapper.getId();
112 
113             final FinalSAMLTokenOutputProcessor finalSAMLTokenOutputProcessor;
114 
115             XMLSecurityConstants.Action action = getAction();
116             boolean includeSTR = false;
117 
118             GenericOutboundSecurityToken securityToken = null;
119 
120             // See if a token is already available
121             String sigTokenId =
122                 outputProcessorChain.getSecurityContext().get(WSSConstants.PROP_USE_THIS_TOKEN_ID_FOR_SIGNATURE);
123             SecurityTokenProvider<OutboundSecurityToken> signatureTokenProvider = null;
124             if (sigTokenId != null) {
125                 signatureTokenProvider =
126                     outputProcessorChain.getSecurityContext().getSecurityTokenProvider(sigTokenId);
127                 if (signatureTokenProvider != null) {
128                     securityToken =
129                         (GenericOutboundSecurityToken)signatureTokenProvider.getSecurityToken();
130                 }
131             }
132 
133             if (WSSConstants.SAML_TOKEN_SIGNED.equals(action) && senderVouches) {
134                 includeSTR = true;
135                 if (securityToken == null) {
136                     securityToken = getSecurityToken(samlCallback, outputProcessorChain);
137                 }
138 
139                 finalSAMLTokenOutputProcessor = new FinalSAMLTokenOutputProcessor(securityToken, samlAssertionWrapper,
140                         securityTokenReferenceId, senderVouches, includeSTR);
141                 finalSAMLTokenOutputProcessor.setAction(getAction(), getActionOrder());
142 
143                 securityToken.setProcessor(finalSAMLTokenOutputProcessor);
144 
145             } else if (WSSConstants.SAML_TOKEN_SIGNED.equals(action) && hok) {
146 
147                 final Element ref;
148                 if (securityToken != null) {
149                     ref = securityToken.getCustomTokenReference();
150                 } else {
151                     ref = null;
152                 }
153 
154                 finalSAMLTokenOutputProcessor = new FinalSAMLTokenOutputProcessor(null, samlAssertionWrapper,
155                         securityTokenReferenceId, senderVouches, includeSTR);
156 
157                 final SAMLSecurityTokenProvider securityTokenProvider =
158                     new SAMLSecurityTokenProvider(samlCallback, (WSSSecurityProperties)getSecurityProperties(),
159                                                   tokenId, ref, finalSAMLTokenOutputProcessor);
160 
161                 //fire a tokenSecurityEvent
162                 TokenSecurityEvent<OutboundSecurityToken> tokenSecurityEvent =
163                     new TokenSecurityEvent<OutboundSecurityToken>(WSSecurityEventConstants.SAML_TOKEN) {
164 
165                     public OutboundSecurityToken getSecurityToken() {
166                         try {
167                             return securityTokenProvider.getSecurityToken();
168                         } catch (XMLSecurityException e) {
169                             LOG.debug(e.getMessage(), e);
170                         }
171                         return null;
172                     }
173                 };
174                 outputProcessorChain.getSecurityContext().registerSecurityEvent(tokenSecurityEvent);
175 
176                 outputProcessorChain.getSecurityContext().registerSecurityTokenProvider(tokenId, securityTokenProvider);
177                 outputProcessorChain.getSecurityContext().put(WSSConstants.PROP_USE_THIS_TOKEN_ID_FOR_SIGNATURE, tokenId);
178             } else if (WSSConstants.SAML_TOKEN_UNSIGNED.equals(getAction())) {
179                 // Check to see whether this token is to be signed by the message signature. If so,
180                 // output a STR to be signed instead, and remove this Assertion from the signature parts
181                 // list
182                 QName assertionName = new QName(WSSConstants.NS_SAML2, "Assertion");
183                 if (samlAssertionWrapper.getSamlVersion() == SAMLVersion.VERSION_11) {
184                     assertionName = new QName(WSSConstants.NS_SAML, "Assertion");
185                 }
186 
187                 Iterator<SecurePart> signaturePartsIterator =
188                     securityProperties.getSignatureSecureParts().iterator();
189                 while (signaturePartsIterator.hasNext()) {
190                     SecurePart securePart = signaturePartsIterator.next();
191                     if (samlAssertionWrapper.getId().equals(securePart.getIdToSecure())
192                         || assertionName.equals(securePart.getName())) {
193                         includeSTR = true;
194                         signaturePartsIterator.remove();
195                         break;
196                     }
197                 }
198 
199                 finalSAMLTokenOutputProcessor = new FinalSAMLTokenOutputProcessor(null, samlAssertionWrapper,
200                                                                                   securityTokenReferenceId, senderVouches,
201                                                                                   includeSTR);
202                 if (includeSTR) {
203                     finalSAMLTokenOutputProcessor.addBeforeProcessor(WSSSignatureOutputProcessor.class);
204                 }
205             } else {
206                 finalSAMLTokenOutputProcessor = new FinalSAMLTokenOutputProcessor(null, samlAssertionWrapper,
207                                                                                   securityTokenReferenceId, senderVouches,
208                                                                                   includeSTR);
209             }
210 
211             finalSAMLTokenOutputProcessor.setXMLSecurityProperties(getSecurityProperties());
212             finalSAMLTokenOutputProcessor.setAction(action, getActionOrder());
213             finalSAMLTokenOutputProcessor.init(outputProcessorChain);
214 
215             if (includeSTR) {
216                 WSSSecurePart securePart =
217                         new WSSSecurePart(
218                                 new QName(WSSConstants.SOAPMESSAGE_NS10_STR_TRANSFORM), SecurePart.Modifier.Element);
219                 securePart.setIdToSecure(tokenId);
220                 securePart.setIdToReference(securityTokenReferenceId);
221                 outputProcessorChain.getSecurityContext().putAsMap(WSSConstants.SIGNATURE_PARTS, tokenId, securePart);
222             }
223 
224         } finally {
225             outputProcessorChain.removeProcessor(this);
226         }
227         outputProcessorChain.processEvent(xmlSecEvent);
228     }
229 
230     private GenericOutboundSecurityToken getSecurityToken(SAMLCallback samlCallback,
231                                               OutputProcessorChain outputProcessorChain) throws WSSecurityException {
232         CryptoType cryptoType = new CryptoType(CryptoType.TYPE.ALIAS);
233         cryptoType.setAlias(samlCallback.getIssuerKeyName());
234         X509Certificate[] certificates = null;
235         if (samlCallback.getIssuerCrypto() != null) {
236             certificates = samlCallback.getIssuerCrypto().getX509Certificates(cryptoType);
237         }
238         if (certificates == null) {
239             throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE,
240                     "empty",
241                     new Object[] {"No issuer certs were found to sign the SAML Assertion using issuer name: "
242                     + samlCallback.getIssuerKeyName()}
243             );
244         }
245 
246         PrivateKey privateKey;
247         try {
248             privateKey = samlCallback.getIssuerCrypto().getPrivateKey(
249                     samlCallback.getIssuerKeyName(), samlCallback.getIssuerKeyPassword());
250         } catch (Exception ex) {
251             throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, ex);
252         }
253 
254         final String binarySecurityTokenId = IDGenerator.generateID(null);
255 
256         final GenericOutboundSecurityToken bstSecurityToken =
257                 new GenericOutboundSecurityToken(binarySecurityTokenId, WSSecurityTokenConstants.X509V3Token,
258                         privateKey, certificates);
259 
260         SecurityTokenProvider<OutboundSecurityToken> securityTokenProvider =
261             new SecurityTokenProvider<OutboundSecurityToken>() {
262 
263             @Override
264             public OutboundSecurityToken getSecurityToken() throws WSSecurityException {
265                 return bstSecurityToken;
266             }
267 
268             @Override
269             public String getId() {
270                 return binarySecurityTokenId;
271             }
272         };
273 
274         outputProcessorChain.getSecurityContext().registerSecurityTokenProvider(binarySecurityTokenId,
275                                                                                 securityTokenProvider);
276         outputProcessorChain.getSecurityContext().put(WSSConstants.PROP_USE_THIS_TOKEN_ID_FOR_SIGNATURE,
277                                                       binarySecurityTokenId);
278 
279         return bstSecurityToken;
280     }
281 
282     private static class SAMLSecurityTokenProvider
283         implements SecurityTokenProvider<OutboundSecurityToken> {
284 
285         private GenericOutboundSecurityToken samlSecurityToken;
286         private SAMLCallback samlCallback;
287         private String tokenId;
288         private Element ref;
289         private FinalSAMLTokenOutputProcessor finalSAMLTokenOutputProcessor;
290         private WSSSecurityProperties securityProperties;
291 
292         SAMLSecurityTokenProvider(SAMLCallback samlCallback, WSSSecurityProperties securityProperties, String tokenId,
293                                          Element ref, FinalSAMLTokenOutputProcessor finalSAMLTokenOutputProcessor) {
294             this.samlCallback = samlCallback;
295             this.securityProperties = securityProperties;
296             this.tokenId = tokenId;
297             this.ref = ref;
298             this.finalSAMLTokenOutputProcessor = finalSAMLTokenOutputProcessor;
299         }
300 
301         @Override
302         public OutboundSecurityToken getSecurityToken() throws XMLSecurityException {
303 
304             if (this.samlSecurityToken != null) {
305                 return this.samlSecurityToken;
306             }
307 
308             WSSecurityTokenConstants.TokenType tokenType;
309             if (samlCallback.getSamlVersion() == SAMLVersion.VERSION_10) {
310                 tokenType = WSSecurityTokenConstants.SAML_10_TOKEN;
311             } else if (samlCallback.getSamlVersion() == SAMLVersion.VERSION_11) {
312                 tokenType = WSSecurityTokenConstants.SAML_11_TOKEN;
313             } else {
314                 tokenType = WSSecurityTokenConstants.SAML_20_TOKEN;
315             }
316 
317             PrivateKey privateKey = getPrivateKeyUsingCallback();
318             if (privateKey != null) {
319                 this.samlSecurityToken = new GenericOutboundSecurityToken(
320                         tokenId, tokenType, privateKey, getCertificatesUsingCallback());
321             } else {
322                 this.samlSecurityToken = new GenericOutboundSecurityToken(
323                         tokenId, tokenType) {
324 
325                     @Override
326                     public Key getSecretKey(String algorithmURI) throws WSSecurityException {
327 
328                         Key key;
329                         try {
330                             key = super.getSecretKey(algorithmURI);
331                         } catch (XMLSecurityException e) {
332                             throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, e);
333                         }
334                         if (key != null) {
335                             return key;
336                         }
337                         byte[] secretKey = getSecretKeyUsingCallback();
338                         if (secretKey != null && secretKey.length > 0) {
339                             String algoFamily = JCEAlgorithmMapper.getJCEKeyAlgorithmFromURI(algorithmURI);
340                             key = new SecretKeySpec(secretKey, algoFamily);
341                             setSecretKey(algorithmURI, key);
342                         }
343                         return key;
344                     }
345                 };
346             }
347             this.samlSecurityToken.setProcessor(finalSAMLTokenOutputProcessor);
348             this.samlSecurityToken.setCustomTokenReference(ref);
349             return this.samlSecurityToken;
350         }
351 
352         private PrivateKey getPrivateKeyUsingCallback()
353             throws WSSConfigurationException, WSSecurityException {
354 
355             SubjectBean subjectBean = samlCallback.getSubject();
356             if (subjectBean != null) {
357                 KeyInfoBean keyInfoBean = subjectBean.getKeyInfo();
358                 if (keyInfoBean != null) {
359                     X509Certificate x509Certificate = keyInfoBean.getCertificate();
360                     if (x509Certificate != null) {
361                         String alias = securityProperties.getSignatureCrypto().getX509Identifier(x509Certificate);
362                         if (alias == null) {
363                             throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "aliasIsNull");
364                         }
365                         WSPasswordCallback wsPasswordCallback =
366                             new WSPasswordCallback(alias, WSPasswordCallback.SIGNATURE);
367                         WSSUtils.doPasswordCallback(securityProperties.getCallbackHandler(), wsPasswordCallback);
368                         CryptoType cryptoType = new CryptoType(CryptoType.TYPE.ALIAS);
369                         cryptoType.setAlias(alias);
370                         return securityProperties.getSignatureCrypto().getPrivateKey(alias, wsPasswordCallback.getPassword());
371                     } else if (keyInfoBean.getPublicKey() != null) {
372                         return securityProperties.getSignatureCrypto().getPrivateKey(
373                                         samlCallback.getIssuerKeyName(), samlCallback.getIssuerKeyPassword());
374                     }
375                 }
376             }
377 
378             return null;
379         }
380 
381         private X509Certificate[] getCertificatesUsingCallback()
382             throws WSSConfigurationException, WSSecurityException {
383 
384             SubjectBean subjectBean = samlCallback.getSubject();
385             if (subjectBean != null) {
386                 KeyInfoBean keyInfoBean = subjectBean.getKeyInfo();
387                 if (keyInfoBean != null) {
388                     X509Certificate x509Certificate = keyInfoBean.getCertificate();
389                     if (x509Certificate != null) {
390                         String alias = securityProperties.getSignatureCrypto().getX509Identifier(x509Certificate);
391                         if (alias == null) {
392                             throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "aliasIsNull");
393                         }
394                         CryptoType cryptoType = new CryptoType(CryptoType.TYPE.ALIAS);
395                         cryptoType.setAlias(alias);
396                         return securityProperties.getSignatureCrypto().getX509Certificates(cryptoType);
397                     }
398                 }
399             }
400 
401             return new X509Certificate[0];
402         }
403 
404 
405         private byte[] getSecretKeyUsingCallback()
406             throws WSSConfigurationException, WSSecurityException {
407 
408             SubjectBean subjectBean = samlCallback.getSubject();
409             if (subjectBean != null) {
410                 KeyInfoBean keyInfoBean = subjectBean.getKeyInfo();
411                 if (keyInfoBean != null && keyInfoBean.getCertificate() == null && keyInfoBean.getPublicKey() == null) {
412                    return keyInfoBean.getEphemeralKey();
413                 }
414             }
415 
416             return new byte[0];
417         }
418 
419         @Override
420         public String getId() {
421             return tokenId;
422         }
423     }
424 
425     class FinalSAMLTokenOutputProcessor extends AbstractOutputProcessor {
426 
427         private final OutboundSecurityToken securityToken;
428         private final SamlAssertionWrapper samlAssertionWrapper;
429         private final String securityTokenReferenceId;
430         private boolean senderVouches = false;
431         private boolean includeSTR = false;
432 
433         FinalSAMLTokenOutputProcessor(OutboundSecurityToken securityToken, SamlAssertionWrapper samlAssertionWrapper,
434                                       String securityTokenReferenceId, boolean senderVouches,
435                                       boolean includeSTR) throws XMLSecurityException {
436             super();
437             this.addAfterProcessor(UsernameTokenOutputProcessor.class);
438             this.addAfterProcessor(SAMLTokenOutputProcessor.class);
439             this.addBeforeProcessor(WSSSignatureOutputProcessor.class);
440             this.samlAssertionWrapper = samlAssertionWrapper;
441             this.securityTokenReferenceId = securityTokenReferenceId;
442             this.senderVouches = senderVouches;
443             this.securityToken = securityToken;
444             this.includeSTR = includeSTR;
445         }
446 
447         @Override
448         public void processEvent(XMLSecEvent xmlSecEvent, OutputProcessorChain outputProcessorChain)
449                 throws XMLStreamException, XMLSecurityException {
450 
451             outputProcessorChain.processEvent(xmlSecEvent);
452 
453             if (WSSUtils.isSecurityHeaderElement(xmlSecEvent, ((WSSSecurityProperties) getSecurityProperties()).getActor())) {
454 
455                 OutputProcessorChain subOutputProcessorChain = outputProcessorChain.createSubChain(this);
456                 if (includeBST()) {
457 
458                     OutputProcessorUtils.updateSecurityHeaderOrder(
459                             outputProcessorChain, WSSConstants.TAG_WSSE_BINARY_SECURITY_TOKEN, getAction(), false);
460 
461                     WSSUtils.createBinarySecurityTokenStructure(this, outputProcessorChain, securityToken.getId(),
462                             securityToken.getX509Certificates(), getSecurityProperties().isUseSingleCert());
463                 }
464 
465                 final QName headerElementName;
466                 if (samlAssertionWrapper.getSamlVersion() == SAMLVersion.VERSION_11) {
467                     headerElementName = WSSConstants.TAG_SAML_ASSERTION;
468                 } else {
469                     headerElementName = WSSConstants.TAG_SAML2_ASSERTION;
470                 }
471                 OutputProcessorUtils.updateSecurityHeaderOrder(outputProcessorChain, headerElementName, getAction(), false);
472 
473                 try {
474                     Document doc = ((WSSSecurityProperties) getSecurityProperties()).getDocumentCreator().newDocument();
475                     outputDOMElement(samlAssertionWrapper.toDOM(doc), subOutputProcessorChain);
476                 } catch (ParserConfigurationException ex) {
477                     LOG.debug("Error writing out SAML Assertion", ex);
478                     throw new XMLSecurityException(ex);
479                 }
480                 if (includeSTR) {
481                     OutputProcessorUtils.updateSecurityHeaderOrder(
482                             outputProcessorChain, WSSConstants.TAG_WSSE_SECURITY_TOKEN_REFERENCE, getAction(), false);
483                     outputSecurityTokenReference(subOutputProcessorChain, samlAssertionWrapper,
484                             securityTokenReferenceId, samlAssertionWrapper.getId());
485                 }
486                 outputProcessorChain.removeProcessor(this);
487             }
488         }
489 
490         private boolean includeBST() {
491             return senderVouches
492                 && getSecurityProperties().getSignatureKeyIdentifiers().contains(
493                     WSSecurityTokenConstants.KEYIDENTIFIER_SECURITY_TOKEN_DIRECT_REFERENCE)
494                 && securityToken != null
495                 && !(WSSConstants.SAML_TOKEN_SIGNED.equals(action)
496                     && ((WSSSecurityProperties)getSecurityProperties()).isIncludeSignatureToken());
497         }
498     }
499 
500     private void outputSecurityTokenReference(
501             OutputProcessorChain outputProcessorChain, SamlAssertionWrapper samlAssertionWrapper,
502             String referenceId, String tokenId) throws XMLStreamException, XMLSecurityException {
503 
504         List<XMLSecAttribute> attributes = new ArrayList<>(2);
505         WSSecurityTokenConstants.TokenType tokenType = WSSecurityTokenConstants.SAML_11_TOKEN;
506         if (samlAssertionWrapper.getSamlVersion() == SAMLVersion.VERSION_11) {
507             attributes.add(createAttribute(WSSConstants.ATT_WSSE11_TOKEN_TYPE, WSSConstants.NS_SAML11_TOKEN_PROFILE_TYPE));
508         } else {
509             tokenType = WSSecurityTokenConstants.SAML_20_TOKEN;
510             attributes.add(createAttribute(WSSConstants.ATT_WSSE11_TOKEN_TYPE, WSSConstants.NS_SAML20_TOKEN_PROFILE_TYPE));
511         }
512         attributes.add(createAttribute(WSSConstants.ATT_WSU_ID, referenceId));
513         createStartElementAndOutputAsEvent(outputProcessorChain, WSSConstants.TAG_WSSE_SECURITY_TOKEN_REFERENCE, false, attributes);
514         WSSUtils.createSAMLKeyIdentifierStructure(this, outputProcessorChain, tokenType, tokenId);
515         createEndElementAndOutputAsEvent(outputProcessorChain, WSSConstants.TAG_WSSE_SECURITY_TOKEN_REFERENCE);
516     }
517 
518 }