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.ArrayDeque;
22 import java.util.Comparator;
23 import java.util.Deque;
24 import java.util.Iterator;
25 import java.util.LinkedHashMap;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.TreeMap;
29
30 import javax.xml.stream.XMLStreamConstants;
31 import javax.xml.stream.XMLStreamException;
32
33 import org.apache.wss4j.common.ext.WSSecurityException;
34 import org.apache.wss4j.stax.ext.WSSConstants;
35 import org.apache.wss4j.stax.ext.WSSSecurityProperties;
36 import org.apache.wss4j.stax.impl.SecurityHeaderOrder;
37 import org.apache.wss4j.stax.utils.WSSUtils;
38 import org.apache.xml.security.exceptions.XMLSecurityException;
39 import org.apache.xml.security.stax.ext.AbstractOutputProcessor;
40 import org.apache.xml.security.stax.ext.OutputProcessorChain;
41 import org.apache.xml.security.stax.ext.XMLSecurityConstants;
42 import org.apache.xml.security.stax.ext.stax.XMLSecEvent;
43 import org.apache.xml.security.stax.ext.stax.XMLSecStartElement;
44 import org.apache.xml.security.stax.impl.processor.output.FinalOutputProcessor;
45
46
47
48
49
50
51
52
53
54 public class SecurityHeaderReorderProcessor extends AbstractOutputProcessor {
55
56 private final Map<XMLSecurityConstants.Action, Map<SecurityHeaderOrder, Deque<XMLSecEvent>>> actionEventMap =
57 new LinkedHashMap<>();
58
59 private int securityHeaderIndex;
60 private Deque<XMLSecEvent> currentDeque;
61
62 public SecurityHeaderReorderProcessor() throws XMLSecurityException {
63 super();
64 setPhase(XMLSecurityConstants.Phase.POSTPROCESSING);
65 addBeforeProcessor(FinalOutputProcessor.class);
66 }
67
68 @Override
69 public void init(OutputProcessorChain outputProcessorChain) throws XMLSecurityException {
70 super.init(outputProcessorChain);
71
72 List<XMLSecurityConstants.Action> outActions = getSecurityProperties().getActions();
73 for (int i = outActions.size() - 1; i >= 0; i--) {
74 XMLSecurityConstants.Action outAction = outActions.get(i);
75 actionEventMap.put(outAction, new TreeMap<SecurityHeaderOrder, Deque<XMLSecEvent>>(new Comparator<SecurityHeaderOrder>() {
76 @Override
77 public int compare(SecurityHeaderOrder o1, SecurityHeaderOrder o2) {
78 if (WSSConstants.TAG_dsig_Signature.equals(o1.getSecurityHeaderElementName())) {
79 return 1;
80 } else if (WSSConstants.TAG_dsig_Signature.equals(o2.getSecurityHeaderElementName())) {
81 return -1;
82 }
83 return 1;
84 }
85 }));
86 }
87 }
88
89 @Override
90 public void processEvent(XMLSecEvent xmlSecEvent, OutputProcessorChain outputProcessorChain)
91 throws XMLStreamException, XMLSecurityException {
92
93 int documentLevel = xmlSecEvent.getDocumentLevel();
94 if (documentLevel < 3
95 || !WSSUtils.isInSecurityHeader(xmlSecEvent, ((WSSSecurityProperties) getSecurityProperties()).getActor())) {
96 outputProcessorChain.processEvent(xmlSecEvent);
97 return;
98 }
99
100
101
102 if (documentLevel == 3) {
103 if (xmlSecEvent.isEndElement() && xmlSecEvent.asEndElement().getName().equals(WSSConstants.TAG_WSSE_SECURITY)) {
104 OutputProcessorChain subOutputProcessorChain = outputProcessorChain.createSubChain(this);
105
106 Iterator<Map.Entry<XMLSecurityConstants.Action, Map<SecurityHeaderOrder, Deque<XMLSecEvent>>>> iterator =
107 actionEventMap.entrySet().iterator();
108 loop:
109 while (iterator.hasNext()) {
110 Map.Entry<XMLSecurityConstants.Action, Map<SecurityHeaderOrder, Deque<XMLSecEvent>>> next = iterator.next();
111
112 boolean encryptAction = false;
113 Iterator<Map.Entry<SecurityHeaderOrder, Deque<XMLSecEvent>>> entryIterator = next.getValue().entrySet().iterator();
114 while (entryIterator.hasNext()) {
115 Map.Entry<SecurityHeaderOrder, Deque<XMLSecEvent>> entry = entryIterator.next();
116
117 if (!entry.getKey().isEncrypted()) {
118 Deque<XMLSecEvent> xmlSecEvents = entry.getValue();
119 while (!xmlSecEvents.isEmpty()) {
120 XMLSecEvent event = xmlSecEvents.pop();
121 subOutputProcessorChain.reset();
122 subOutputProcessorChain.processEvent(event);
123 }
124
125 entryIterator.remove();
126 }
127
128 if (entry.getKey().getAction().getName().contains("Encrypt")) {
129 encryptAction = true;
130 }
131 }
132
133 if (encryptAction) {
134 break loop;
135 }
136 }
137
138 iterator = actionEventMap.entrySet().iterator();
139 while (iterator.hasNext()) {
140 Map.Entry<XMLSecurityConstants.Action, Map<SecurityHeaderOrder, Deque<XMLSecEvent>>> next = iterator.next();
141 Iterator<Map.Entry<SecurityHeaderOrder, Deque<XMLSecEvent>>> entryIterator = next.getValue().entrySet().iterator();
142 while (entryIterator.hasNext()) {
143 Map.Entry<SecurityHeaderOrder, Deque<XMLSecEvent>> entry = entryIterator.next();
144 Deque<XMLSecEvent> xmlSecEvents = entry.getValue();
145 while (!xmlSecEvents.isEmpty()) {
146 XMLSecEvent event = xmlSecEvents.pop();
147 subOutputProcessorChain.reset();
148 subOutputProcessorChain.processEvent(event);
149 }
150 }
151 }
152 outputProcessorChain.removeProcessor(this);
153 }
154 outputProcessorChain.processEvent(xmlSecEvent);
155 return;
156 } else if (documentLevel == 4 && XMLStreamConstants.START_ELEMENT == xmlSecEvent.getEventType()) {
157 XMLSecStartElement xmlSecStartElement = xmlSecEvent.asStartElement();
158
159 List<SecurityHeaderOrder> securityHeaderOrderList =
160 outputProcessorChain.getSecurityContext().getAsList(SecurityHeaderOrder.class);
161 SecurityHeaderOrder securityHeaderOrder = securityHeaderOrderList.get(securityHeaderIndex);
162 if (!xmlSecStartElement.getName().equals(WSSConstants.TAG_xenc_EncryptedData)
163 && !xmlSecStartElement.getName().equals(securityHeaderOrder.getSecurityHeaderElementName())) {
164 throw new WSSecurityException(
165 WSSecurityException.ErrorCode.FAILURE, "empty",
166 new Object[]{"Invalid security header order. Expected "
167 + securityHeaderOrder.getSecurityHeaderElementName()
168 + " but got " + xmlSecStartElement.getName()});
169 }
170
171 Map<SecurityHeaderOrder, Deque<XMLSecEvent>> map = actionEventMap.get(securityHeaderOrder.getAction());
172 currentDeque = new ArrayDeque<>();
173 map.put(securityHeaderOrder, currentDeque);
174
175 securityHeaderIndex++;
176 }
177 currentDeque.offer(xmlSecEvent);
178 }
179 }