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.XMLStreamConstants;
26 import javax.xml.stream.XMLStreamException;
27
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.SecurePart;
36 import org.apache.xml.security.stax.ext.stax.XMLSecAttribute;
37 import org.apache.xml.security.stax.ext.stax.XMLSecEndElement;
38 import org.apache.xml.security.stax.ext.stax.XMLSecEvent;
39 import org.apache.xml.security.stax.ext.stax.XMLSecStartElement;
40
41
42
43
44 public class SecurityHeaderOutputProcessor extends AbstractOutputProcessor {
45
46 public SecurityHeaderOutputProcessor() throws XMLSecurityException {
47 super();
48 setPhase(WSSConstants.Phase.PREPROCESSING);
49 }
50
51 @Override
52 public void processEvent(XMLSecEvent xmlSecEvent, OutputProcessorChain outputProcessorChain)
53 throws XMLStreamException, XMLSecurityException {
54
55 boolean eventHandled = false;
56
57 switch (xmlSecEvent.getEventType()) {
58 case XMLStreamConstants.START_ELEMENT:
59 XMLSecStartElement xmlSecStartElement = xmlSecEvent.asStartElement();
60 final String soapMessageVersion = WSSUtils.getSOAPMessageVersionNamespace(xmlSecStartElement);
61 int level = xmlSecStartElement.getDocumentLevel();
62
63 if (level == 1 && soapMessageVersion == null) {
64 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "notASOAPMessage");
65 } else if (level == 1) {
66
67 List<SecurePart> encryptionParts = securityProperties.getEncryptionSecureParts();
68 if (!encryptionParts.isEmpty()) {
69 for (SecurePart securePart : encryptionParts) {
70
71 changeSOAPNamespace(securePart, soapMessageVersion);
72
73 if (securePart.getIdToSecure() == null) {
74 outputProcessorChain.getSecurityContext().putAsMap(
75 WSSConstants.ENCRYPTION_PARTS,
76 securePart.getName(),
77 securePart
78 );
79 } else {
80 outputProcessorChain.getSecurityContext().putAsMap(
81 WSSConstants.ENCRYPTION_PARTS,
82 securePart.getIdToSecure(),
83 securePart
84 );
85 }
86 }
87 }
88 List<SecurePart> signatureParts = securityProperties.getSignatureSecureParts();
89 if (!signatureParts.isEmpty()) {
90 for (SecurePart securePart : signatureParts) {
91
92 changeSOAPNamespace(securePart, soapMessageVersion);
93
94 if (securePart.getIdToSecure() == null) {
95 outputProcessorChain.getSecurityContext().putAsMap(
96 WSSConstants.SIGNATURE_PARTS,
97 securePart.getName(),
98 securePart
99 );
100 } else {
101 outputProcessorChain.getSecurityContext().putAsMap(
102 WSSConstants.SIGNATURE_PARTS,
103 securePart.getIdToSecure(),
104 securePart
105 );
106 }
107 }
108 }
109 } else if (WSSUtils.isSecurityHeaderElement(xmlSecEvent, ((WSSSecurityProperties) getSecurityProperties()).getActor())) {
110
111 outputProcessorChain.removeProcessor(this);
112 } else if (level == 2
113 && WSSConstants.TAG_SOAP_BODY_LN.equals(xmlSecStartElement.getName().getLocalPart())
114 && xmlSecStartElement.getName().getNamespaceURI().equals(soapMessageVersion)) {
115
116
117
118
119 OutputProcessorChain subOutputProcessorChain =
120 outputProcessorChain.createSubChain(this, xmlSecStartElement.getParentXMLSecStartElement());
121 createStartElementAndOutputAsEvent(subOutputProcessorChain,
122 new QName(soapMessageVersion, WSSConstants.TAG_SOAP_HEADER_LN, WSSConstants.PREFIX_SOAPENV), true, null);
123 boolean mustUnderstand = ((WSSSecurityProperties) getSecurityProperties()).isMustUnderstand();
124 buildSecurityHeader(soapMessageVersion, subOutputProcessorChain, mustUnderstand);
125 createEndElementAndOutputAsEvent(subOutputProcessorChain,
126 new QName(soapMessageVersion, WSSConstants.TAG_SOAP_HEADER_LN, WSSConstants.PREFIX_SOAPENV));
127
128
129 outputProcessorChain.processEvent(xmlSecEvent);
130
131 outputProcessorChain.removeProcessor(this);
132
133 eventHandled = true;
134 }
135 break;
136 case XMLStreamConstants.END_ELEMENT:
137 XMLSecEndElement xmlSecEndElement = xmlSecEvent.asEndElement();
138 int documentLevel = xmlSecEndElement.getDocumentLevel();
139 String soapMessageVersionNS =
140 WSSUtils.getSOAPMessageVersionNamespace(xmlSecEndElement.getParentXMLSecStartElement());
141 if (documentLevel == 2 && WSSConstants.TAG_SOAP_HEADER_LN.equals(xmlSecEndElement.getName().getLocalPart())
142 && xmlSecEndElement.getName().getNamespaceURI().equals(soapMessageVersionNS)) {
143 OutputProcessorChain subOutputProcessorChain = outputProcessorChain.createSubChain(this);
144 boolean mustUnderstand = ((WSSSecurityProperties) getSecurityProperties()).isMustUnderstand();
145 buildSecurityHeader(xmlSecEndElement.getName().getNamespaceURI(), subOutputProcessorChain, mustUnderstand);
146
147 outputProcessorChain.processEvent(xmlSecEvent);
148
149 outputProcessorChain.removeProcessor(this);
150
151 eventHandled = true;
152 }
153 break;
154 }
155
156 if (!eventHandled) {
157 outputProcessorChain.processEvent(xmlSecEvent);
158 }
159 }
160
161 private void changeSOAPNamespace(SecurePart securePart, String soapVersion) {
162 final QName secureName = securePart.getName();
163 if (secureName != null) {
164 QName newName = secureName;
165
166 if (WSSConstants.NS_SOAP11.equals(secureName.getNamespaceURI())
167 && WSSConstants.NS_SOAP12.equals(soapVersion)) {
168 newName = new QName(soapVersion, secureName.getLocalPart(), secureName.getPrefix());
169 } else if (WSSConstants.NS_SOAP12.equals(secureName.getNamespaceURI())
170 && WSSConstants.NS_SOAP11.equals(soapVersion)) {
171 newName = new QName(soapVersion, secureName.getLocalPart(), secureName.getPrefix());
172 }
173
174 if (!secureName.equals(newName)) {
175 securePart.setName(newName);
176 }
177 }
178 }
179
180 private void buildSecurityHeader(
181 String soapMessageVersion,
182 OutputProcessorChain subOutputProcessorChain,
183 boolean mustUnderstand
184 ) throws XMLStreamException, XMLSecurityException {
185 List<XMLSecAttribute> attributes = new ArrayList<>(1);
186 final String actor = ((WSSSecurityProperties) getSecurityProperties()).getActor();
187 if (actor != null && !actor.isEmpty()) {
188 if (WSSConstants.NS_SOAP11.equals(soapMessageVersion)) {
189 attributes.add(createAttribute(WSSConstants.ATT_SOAP11_ACTOR, actor));
190 } else {
191 attributes.add(createAttribute(WSSConstants.ATT_SOAP12_ROLE, actor));
192 }
193 }
194 if (mustUnderstand) {
195 if (WSSConstants.NS_SOAP11.equals(soapMessageVersion)) {
196 attributes.add(createAttribute(WSSConstants.ATT_SOAP11_MUST_UNDERSTAND, "1"));
197 } else {
198 attributes.add(createAttribute(WSSConstants.ATT_SOAP12_MUST_UNDERSTAND, "true"));
199 }
200 }
201 createStartElementAndOutputAsEvent(subOutputProcessorChain, WSSConstants.TAG_WSSE_SECURITY, true, attributes);
202 createEndElementAndOutputAsEvent(subOutputProcessorChain, WSSConstants.TAG_WSSE_SECURITY);
203 }
204 }