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 org.apache.wss4j.common.ext.WSSecurityException;
22  import org.apache.wss4j.stax.ext.WSSConstants;
23  import org.apache.wss4j.stax.ext.WSSSecurityProperties;
24  import org.apache.wss4j.stax.impl.SecurityHeaderOrder;
25  import org.apache.wss4j.stax.securityToken.WSSecurityTokenConstants;
26  import org.apache.wss4j.stax.utils.WSSUtils;
27  import org.apache.xml.security.exceptions.XMLSecurityException;
28  import org.apache.xml.security.stax.ext.OutputProcessorChain;
29  import org.apache.xml.security.stax.ext.XMLSecurityConstants;
30  import org.apache.xml.security.stax.ext.stax.XMLSecAttribute;
31  import org.apache.xml.security.stax.ext.stax.XMLSecEvent;
32  import org.apache.xml.security.stax.ext.stax.XMLSecStartElement;
33  import org.apache.xml.security.stax.impl.SignaturePartDef;
34  import org.apache.xml.security.stax.impl.algorithms.SignatureAlgorithm;
35  import org.apache.xml.security.stax.impl.processor.output.AbstractSignatureEndingOutputProcessor;
36  import org.apache.xml.security.stax.impl.util.IDGenerator;
37  import org.apache.xml.security.stax.securityEvent.SignatureValueSecurityEvent;
38  import org.apache.xml.security.stax.securityToken.OutboundSecurityToken;
39  
40  import javax.xml.stream.XMLStreamConstants;
41  import javax.xml.stream.XMLStreamException;
42  
43  import java.security.cert.X509Certificate;
44  import java.security.Key;
45  import java.util.*;
46  
47  public class WSSSignatureEndingOutputProcessor extends AbstractSignatureEndingOutputProcessor {
48  
49      private SignedInfoProcessor signedInfoProcessor;
50  
51      public WSSSignatureEndingOutputProcessor(WSSSignatureOutputProcessor signatureOutputProcessor) throws XMLSecurityException {
52          super(signatureOutputProcessor);
53          this.addAfterProcessor(WSSSignatureOutputProcessor.class);
54          this.addAfterProcessor(UsernameTokenOutputProcessor.class);
55      }
56  
57      @Override
58      protected SignedInfoProcessor newSignedInfoProcessor(
59              SignatureAlgorithm signatureAlgorithm, String signatureId, XMLSecStartElement xmlSecStartElement,
60              OutputProcessorChain outputProcessorChain) throws XMLSecurityException {
61  
62          //we have to search for the SecurityHeaderElement for InclusiveNamespaces (same behavior as in wss-dom):
63          while (!WSSConstants.TAG_WSSE_SECURITY.equals(xmlSecStartElement.getName())) {
64              xmlSecStartElement = xmlSecStartElement.getParentXMLSecStartElement();
65          }
66  
67          this.signedInfoProcessor = new SignedInfoProcessor(signatureAlgorithm, signatureId, xmlSecStartElement);
68          this.signedInfoProcessor.setXMLSecurityProperties(getSecurityProperties());
69          this.signedInfoProcessor.setAction(getAction(), getActionOrder());
70          this.signedInfoProcessor.addAfterProcessor(WSSSignatureEndingOutputProcessor.class);
71          this.signedInfoProcessor.init(outputProcessorChain);
72          return this.signedInfoProcessor;
73      }
74  
75      @Override
76      public void processHeaderEvent(OutputProcessorChain outputProcessorChain) throws XMLStreamException, XMLSecurityException {
77          super.processHeaderEvent(outputProcessorChain);
78  
79          SignatureValueSecurityEvent signatureValueSecurityEvent = new SignatureValueSecurityEvent();
80          signatureValueSecurityEvent.setSignatureValue(this.signedInfoProcessor.getSignatureValue());
81          signatureValueSecurityEvent.setCorrelationID(this.signedInfoProcessor.getSignatureId());
82          outputProcessorChain.getSecurityContext().registerSecurityEvent(signatureValueSecurityEvent);
83      }
84  
85      @Override
86      protected void createKeyInfoStructureForSignature(
87              OutputProcessorChain outputProcessorChain,
88              OutboundSecurityToken securityToken,
89              boolean useSingleCertificate)
90              throws XMLStreamException, XMLSecurityException {
91  
92          if (securityToken.getCustomTokenReference() != null) {
93              outputDOMElement(securityToken.getCustomTokenReference(), outputProcessorChain);
94              return;
95          }
96  
97          WSSecurityTokenConstants.KeyIdentifier keyIdentifier = null;
98          if (!getSecurityProperties().getSignatureKeyIdentifiers().isEmpty()) {
99              keyIdentifier = getSecurityProperties().getSignatureKeyIdentifiers().get(0);
100         }
101 
102         X509Certificate[] x509Certificates = securityToken.getX509Certificates();
103 
104         if (WSSecurityTokenConstants.KeyIdentifier_KeyValue.equals(keyIdentifier)) {
105             WSSUtils.createKeyValueTokenStructure(this, outputProcessorChain, x509Certificates);
106         } else {
107             boolean isSAMLToken = false;
108             List<XMLSecAttribute> attributes = new ArrayList<>(2);
109             attributes.add(createAttribute(WSSConstants.ATT_WSU_ID, IDGenerator.generateID(null)));
110             if (WSSecurityTokenConstants.SAML_10_TOKEN.equals(securityToken.getTokenType())
111                 || WSSecurityTokenConstants.SAML_11_TOKEN.equals(securityToken.getTokenType())) {
112                 attributes.add(createAttribute(WSSConstants.ATT_WSSE11_TOKEN_TYPE, WSSConstants.NS_SAML11_TOKEN_PROFILE_TYPE));
113                 isSAMLToken = true;
114             } else if (WSSecurityTokenConstants.SAML_20_TOKEN.equals(securityToken.getTokenType())) {
115                 attributes.add(createAttribute(WSSConstants.ATT_WSSE11_TOKEN_TYPE, WSSConstants.NS_SAML20_TOKEN_PROFILE_TYPE));
116                 isSAMLToken = true;
117             } else if (WSSecurityTokenConstants.KERBEROS_TOKEN.equals(securityToken.getTokenType())) {
118                 attributes.add(createAttribute(WSSConstants.ATT_WSSE11_TOKEN_TYPE, WSSConstants.NS_GSS_KERBEROS5_AP_REQ));
119             } else if (WSSecurityTokenConstants.EncryptedKeyToken.equals(securityToken.getTokenType())
120                 || WSSecurityTokenConstants.KEYIDENTIFIER_ENCRYPTED_KEY_SHA1_IDENTIFIER.equals(keyIdentifier)
121                 || WSSecurityTokenConstants.KeyIdentifier_EncryptedKey.equals(keyIdentifier)) {
122                 attributes.add(createAttribute(WSSConstants.ATT_WSSE11_TOKEN_TYPE, WSSConstants.NS_WSS_ENC_KEY_VALUE_TYPE));
123             } else if (WSSecurityTokenConstants.KEYIDENTIFIER_SECURITY_TOKEN_DIRECT_REFERENCE.equals(keyIdentifier)
124                 && !useSingleCertificate) {
125                 attributes.add(createAttribute(WSSConstants.ATT_WSSE11_TOKEN_TYPE, WSSConstants.NS_X509_PKIPATH_V1));
126             }
127             createStartElementAndOutputAsEvent(outputProcessorChain, WSSConstants.TAG_WSSE_SECURITY_TOKEN_REFERENCE, false, attributes);
128 
129             String tokenId = securityToken.getId();
130 
131             if (isSAMLToken) {
132                 // Always use KeyIdentifier regardless of the configured KeyIdentifier value
133                 WSSUtils.createSAMLKeyIdentifierStructure(this, outputProcessorChain, securityToken.getTokenType(), tokenId);
134             } else if (WSSecurityTokenConstants.KEYIDENTIFIER_ENCRYPTED_KEY_SHA1_IDENTIFIER.equals(keyIdentifier)) {
135                 String identifier = securityToken.getSha1Identifier();
136                 if (identifier != null) {
137                     WSSUtils.createEncryptedKeySha1IdentifierStructure(this, outputProcessorChain, identifier);
138                 } else {
139                     Key key = securityToken.getSecretKey(getSecurityProperties().getSignatureAlgorithm());
140                     WSSUtils.createEncryptedKeySha1IdentifierStructure(this, outputProcessorChain, key);
141                 }
142             } else if (WSSecurityTokenConstants.KEYIDENTIFIER_KERBEROS_SHA1_IDENTIFIER.equals(keyIdentifier)) {
143                 String identifier = securityToken.getSha1Identifier();
144                 WSSUtils.createKerberosSha1IdentifierStructure(this, outputProcessorChain, identifier);
145             } else if (WSSecurityTokenConstants.EncryptedKeyToken.equals(securityToken.getTokenType())
146                 || WSSecurityTokenConstants.KeyIdentifier_EncryptedKey.equals(keyIdentifier)) {
147                 String id = securityToken.getId();
148                 WSSUtils.createBSTReferenceStructure(this, outputProcessorChain, id, WSSConstants.NS_WSS_ENC_KEY_VALUE_TYPE, true);
149             } else if (WSSecurityTokenConstants.KeyIdentifier_IssuerSerial.equals(keyIdentifier)) {
150                 WSSUtils.createX509IssuerSerialStructure(this, outputProcessorChain, x509Certificates);
151             } else if (WSSecurityTokenConstants.KeyIdentifier_SkiKeyIdentifier.equals(keyIdentifier)) {
152                 WSSUtils.createX509SubjectKeyIdentifierStructure(this, outputProcessorChain, x509Certificates);
153             } else if (WSSecurityTokenConstants.KeyIdentifier_X509KeyIdentifier.equals(keyIdentifier)) {
154                 WSSUtils.createX509KeyIdentifierStructure(this, outputProcessorChain, x509Certificates);
155             } else if (WSSecurityTokenConstants.KEYIDENTIFIER_THUMBPRINT_IDENTIFIER.equals(keyIdentifier)) {
156                 WSSUtils.createThumbprintKeyIdentifierStructure(this, outputProcessorChain, x509Certificates);
157             } else if (WSSecurityTokenConstants.KEYIDENTIFIER_SECURITY_TOKEN_DIRECT_REFERENCE.equals(keyIdentifier)) {
158                 String valueType;
159                 boolean included = true;
160                 if (WSSecurityTokenConstants.SAML_20_TOKEN.equals(securityToken.getTokenType())) {
161                     valueType = null;
162                 } else if (WSSecurityTokenConstants.KERBEROS_TOKEN.equals(securityToken.getTokenType())) {
163                     valueType = WSSConstants.NS_GSS_KERBEROS5_AP_REQ;
164                 } else if (WSSecurityTokenConstants.DerivedKeyToken.equals(securityToken.getTokenType())) {
165                     boolean use200512Namespace = ((WSSSecurityProperties)getSecurityProperties()).isUse200512Namespace();
166                     if (use200512Namespace) {
167                         valueType = WSSConstants.NS_WSC_05_12 + "/dk";
168                     } else {
169                         valueType = WSSConstants.NS_WSC_05_02 + "/dk";
170                     }
171                 } else if (WSSecurityTokenConstants.SPNEGO_CONTEXT_TOKEN.equals(securityToken.getTokenType())
172                     || WSSecurityTokenConstants.SECURITY_CONTEXT_TOKEN.equals(securityToken.getTokenType())
173                     || WSSecurityTokenConstants.SECURE_CONVERSATION_TOKEN.equals(securityToken.getTokenType())) {
174                     boolean use200512Namespace = ((WSSSecurityProperties)getSecurityProperties()).isUse200512Namespace();
175                     if (use200512Namespace) {
176                         valueType = WSSConstants.NS_WSC_05_12 + "/sct";
177                     } else {
178                         valueType = WSSConstants.NS_WSC_05_02 + "/sct";
179                     }
180                     included = ((WSSSecurityProperties)getSecurityProperties()).isIncludeSignatureToken();
181                 } else {
182                     if (useSingleCertificate) {
183                         valueType = WSSConstants.NS_X509_V3_TYPE;
184                     } else {
185                         valueType = WSSConstants.NS_X509_PKIPATH_V1;
186                     }
187                 }
188                 WSSUtils.createBSTReferenceStructure(this, outputProcessorChain, tokenId, valueType, included);
189             } else if (WSSecurityTokenConstants.KEYIDENTIFIER_EMBEDDED_KEY_IDENTIFIER_REF.equals(keyIdentifier)) {
190                 WSSUtils.createEmbeddedKeyIdentifierStructure(this, outputProcessorChain, securityToken.getTokenType(), tokenId);
191             } else if (WSSecurityTokenConstants.KEYIDENTIFIER_USERNAME_TOKEN_REFERENCE.equals(keyIdentifier)) {
192                 WSSUtils.createUsernameTokenReferenceStructure(this, outputProcessorChain, tokenId);
193             } else {
194                 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILED_SIGNATURE, "unsupportedSecurityToken",
195                                               new Object[] {keyIdentifier});
196             }
197             createEndElementAndOutputAsEvent(outputProcessorChain, WSSConstants.TAG_WSSE_SECURITY_TOKEN_REFERENCE);
198         }
199     }
200 
201     @Override
202     protected void createTransformsStructureForSignature(OutputProcessorChain subOutputProcessorChain, SignaturePartDef signaturePartDef)
203         throws XMLStreamException, XMLSecurityException {
204         String[] transforms = signaturePartDef.getTransforms();
205         if (transforms != null && transforms.length > 0) {
206             createStartElementAndOutputAsEvent(subOutputProcessorChain, WSSConstants.TAG_dsig_Transforms, false, null);
207 
208             if (WSSConstants.SOAPMESSAGE_NS10_STR_TRANSFORM.equals(transforms[0])) {
209                 List<XMLSecAttribute> attributes = new ArrayList<>(1);
210                 attributes.add(createAttribute(WSSConstants.ATT_NULL_Algorithm, transforms[0]));
211                 createStartElementAndOutputAsEvent(subOutputProcessorChain, WSSConstants.TAG_dsig_Transform, false, attributes);
212                 if (transforms.length >= 2) {
213                     createStartElementAndOutputAsEvent(subOutputProcessorChain, WSSConstants.TAG_WSSE_TRANSFORMATION_PARAMETERS,
214                                                        false, null);
215                     attributes = new ArrayList<>(1);
216                     attributes.add(createAttribute(WSSConstants.ATT_NULL_Algorithm, transforms[1]));
217                     createStartElementAndOutputAsEvent(subOutputProcessorChain, WSSConstants.TAG_dsig_CanonicalizationMethod,
218                                                        false, attributes);
219                     createEndElementAndOutputAsEvent(subOutputProcessorChain, WSSConstants.TAG_dsig_CanonicalizationMethod);
220                     createEndElementAndOutputAsEvent(subOutputProcessorChain, WSSConstants.TAG_WSSE_TRANSFORMATION_PARAMETERS);
221                 }
222                 createEndElementAndOutputAsEvent(subOutputProcessorChain, WSSConstants.TAG_dsig_Transform);
223             } else {
224                 for (int i = 0; i < transforms.length; i++) {
225                     String transform = transforms[i];
226 
227                     List<XMLSecAttribute> attributes = new ArrayList<>(1);
228                     attributes.add(createAttribute(WSSConstants.ATT_NULL_Algorithm, transform));
229                     createStartElementAndOutputAsEvent(subOutputProcessorChain, WSSConstants.TAG_dsig_Transform, false, attributes);
230 
231                     if (getSecurityProperties().isAddExcC14NInclusivePrefixes()
232                             && !WSSConstants.SWA_ATTACHMENT_CONTENT_SIG_TRANS.equals(transform)
233                             && !WSSConstants.SWA_ATTACHMENT_COMPLETE_SIG_TRANS.equals(transform)) {
234                         attributes = new ArrayList<>(1);
235                         attributes.add(createAttribute(XMLSecurityConstants.ATT_NULL_PrefixList,
236                                                        signaturePartDef.getInclusiveNamespacesPrefixes()));
237                         createStartElementAndOutputAsEvent(subOutputProcessorChain, XMLSecurityConstants.TAG_c14nExcl_InclusiveNamespaces,
238                                                            true, attributes);
239                         createEndElementAndOutputAsEvent(subOutputProcessorChain, XMLSecurityConstants.TAG_c14nExcl_InclusiveNamespaces);
240                     }
241 
242                     createEndElementAndOutputAsEvent(subOutputProcessorChain, WSSConstants.TAG_dsig_Transform);
243                 }
244             }
245             createEndElementAndOutputAsEvent(subOutputProcessorChain, WSSConstants.TAG_dsig_Transforms);
246         }
247     }
248 
249     @Override
250     public void flushBufferAndCallbackAfterHeader(OutputProcessorChain outputProcessorChain,
251                                                    Deque<XMLSecEvent> xmlSecEventDeque)
252             throws XMLStreamException, XMLSecurityException {
253 
254         final String actor = ((WSSSecurityProperties) getSecurityProperties()).getActor();
255 
256         //loop until we reach our security header
257         loop:
258         while (!xmlSecEventDeque.isEmpty()) {
259             XMLSecEvent xmlSecEvent = xmlSecEventDeque.pop();
260             if (XMLStreamConstants.START_ELEMENT == xmlSecEvent.getEventType()
261                     && WSSUtils.isSecurityHeaderElement(xmlSecEvent, actor)) {
262                 OutputProcessorUtils.updateSecurityHeaderOrder(
263                         outputProcessorChain, WSSConstants.TAG_dsig_Signature, getAction(), true);
264 
265                 List<SecurityHeaderOrder> securityHeaderOrderList =
266                         outputProcessorChain.getSecurityContext().getAsList(SecurityHeaderOrder.class);
267                 List<SecurityHeaderOrder> tmpList = null;
268                 if (securityHeaderOrderList != null) {
269                     tmpList = new ArrayList<>(securityHeaderOrderList);
270                     securityHeaderOrderList.clear();
271                 }
272 
273                 outputProcessorChain.reset();
274                 outputProcessorChain.processEvent(xmlSecEvent);
275 
276                 if (securityHeaderOrderList != null) {
277                     securityHeaderOrderList.addAll(tmpList);
278                 }
279                 break loop;
280             }
281             outputProcessorChain.reset();
282             outputProcessorChain.processEvent(xmlSecEvent);
283         }
284         super.flushBufferAndCallbackAfterHeader(outputProcessorChain, xmlSecEventDeque);
285     }
286 }