1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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()) {
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 }