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.util.ArrayList;
22  import java.util.List;
23  
24  import javax.xml.namespace.QName;
25  import javax.xml.stream.XMLStreamException;
26  
27  import org.apache.wss4j.common.ext.WSPasswordCallback;
28  import org.apache.wss4j.common.ext.WSSecurityException;
29  import org.apache.wss4j.stax.ext.WSSConstants;
30  import org.apache.wss4j.stax.ext.WSSSecurityProperties;
31  import org.apache.wss4j.stax.utils.WSSUtils;
32  import org.apache.xml.security.exceptions.XMLSecurityException;
33  import org.apache.xml.security.stax.ext.AbstractOutputProcessor;
34  import org.apache.xml.security.stax.ext.OutputProcessorChain;
35  import org.apache.xml.security.stax.ext.stax.XMLSecAttribute;
36  import org.apache.xml.security.stax.ext.stax.XMLSecEvent;
37  import org.apache.xml.security.stax.ext.stax.XMLSecNamespace;
38  import org.w3c.dom.Attr;
39  import org.w3c.dom.Element;
40  import org.w3c.dom.NamedNodeMap;
41  import org.w3c.dom.Node;
42  import org.w3c.dom.Text;
43  
44  public class CustomTokenOutputProcessor extends AbstractOutputProcessor {
45  
46      public CustomTokenOutputProcessor() throws XMLSecurityException {
47          super();
48          addBeforeProcessor(WSSSignatureOutputProcessor.class);
49          addBeforeProcessor(EncryptedKeyOutputProcessor.class);
50      }
51  
52      @Override
53      public void processEvent(XMLSecEvent xmlSecEvent, OutputProcessorChain outputProcessorChain)
54          throws XMLStreamException, XMLSecurityException {
55          try {
56              String tokenId = outputProcessorChain.getSecurityContext().get(WSSConstants.PROP_USE_THIS_TOKEN_ID_FOR_CUSTOM_TOKEN);
57              if (tokenId == null) {
58                  throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE);
59              }
60  
61              WSPasswordCallback wsPasswordCallback = new WSPasswordCallback(tokenId, WSPasswordCallback.CUSTOM_TOKEN);
62              WSSUtils.doPasswordCallback(
63                      ((WSSSecurityProperties) getSecurityProperties()).getCallbackHandler(),
64                      wsPasswordCallback);
65              Element customToken = wsPasswordCallback.getCustomToken();
66              if (customToken == null) {
67                  throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE);
68              }
69  
70              FinalUnknownTokenOutputProcessor outputProcessor =
71                  new FinalUnknownTokenOutputProcessor(customToken);
72              outputProcessor.setXMLSecurityProperties(getSecurityProperties());
73              outputProcessor.setAction(getAction(), getActionOrder());
74              outputProcessor.addBeforeProcessor(WSSSignatureOutputProcessor.class);
75              outputProcessor.addBeforeProcessor(EncryptedKeyOutputProcessor.class);
76              outputProcessor.init(outputProcessorChain);
77          } finally {
78              outputProcessorChain.removeProcessor(this);
79          }
80          outputProcessorChain.processEvent(xmlSecEvent);
81      }
82  
83      static class FinalUnknownTokenOutputProcessor extends AbstractOutputProcessor {
84  
85          private final Element token;
86  
87          FinalUnknownTokenOutputProcessor(Element token) throws XMLSecurityException {
88              super();
89              this.addAfterProcessor(CustomTokenOutputProcessor.class);
90              this.token = token;
91          }
92  
93          @Override
94          public void processEvent(XMLSecEvent xmlSecEvent, OutputProcessorChain outputProcessorChain)
95              throws XMLStreamException, XMLSecurityException {
96  
97              outputProcessorChain.processEvent(xmlSecEvent);
98  
99              if (WSSUtils.isSecurityHeaderElement(xmlSecEvent, ((WSSSecurityProperties) getSecurityProperties()).getActor())) {
100 
101                 final QName headerElementName = new QName(token.getNamespaceURI(), token.getLocalName());
102                 OutputProcessorUtils.updateSecurityHeaderOrder(outputProcessorChain, headerElementName, getAction(), false);
103 
104                 OutputProcessorChain subOutputProcessorChain = outputProcessorChain.createSubChain(this);
105 
106                 outputToken(token, subOutputProcessorChain);
107 
108                 outputProcessorChain.removeProcessor(this);
109             }
110         }
111 
112         private void outputToken(Element element, OutputProcessorChain outputProcessorChain)
113                 throws XMLStreamException, XMLSecurityException {
114 
115             NamedNodeMap namedNodeMap = element.getAttributes();
116             List<XMLSecAttribute> attributes = new ArrayList<>(namedNodeMap.getLength());
117             List<XMLSecNamespace> namespaces = new ArrayList<>(namedNodeMap.getLength());
118             for (int i = 0; i < namedNodeMap.getLength(); i++) {
119                 Attr attribute = (Attr) namedNodeMap.item(i);
120                 if (attribute.getPrefix() == null) {
121                     attributes.add(
122                             createAttribute(
123                                     new QName(attribute.getNamespaceURI(), attribute.getLocalName()), attribute.getValue()));
124                 } else if ("xmlns".equals(attribute.getPrefix()) || "xmlns".equals(attribute.getLocalName())) {
125                     namespaces.add(createNamespace(attribute.getLocalName(), attribute.getValue()));
126                 } else {
127                     attributes.add(
128                             createAttribute(
129                                     new QName(attribute.getNamespaceURI(), attribute.getLocalName(), attribute.getPrefix()),
130                                     attribute.getValue()));
131                 }
132             }
133 
134             QName elementName = new QName(element.getNamespaceURI(), element.getLocalName(), element.getPrefix());
135             createStartElementAndOutputAsEvent(outputProcessorChain, elementName, namespaces, attributes);
136             Node firstChild = element.getFirstChild();
137             while (firstChild != null) {
138                 switch (firstChild.getNodeType()) { //NOPMD
139                     case Node.ELEMENT_NODE:
140                         outputToken((Element) firstChild, outputProcessorChain);
141                         break;
142                     case Node.TEXT_NODE:
143                         createCharactersAndOutputAsEvent(outputProcessorChain, ((Text) firstChild).getData());
144                         break;
145                 }
146                 firstChild = firstChild.getNextSibling();
147             }
148             createEndElementAndOutputAsEvent(outputProcessorChain, elementName);
149         }
150     }
151 }