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.io.BufferedInputStream;
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.util.ArrayList;
25 import java.util.HashMap;
26 import java.util.List;
27 import java.util.Map;
28
29 import javax.security.auth.callback.Callback;
30 import javax.security.auth.callback.CallbackHandler;
31 import javax.xml.stream.XMLStreamConstants;
32 import javax.xml.stream.XMLStreamException;
33 import javax.xml.stream.events.Attribute;
34
35 import org.apache.wss4j.common.ext.Attachment;
36 import org.apache.wss4j.common.ext.AttachmentRequestCallback;
37 import org.apache.wss4j.common.ext.AttachmentResultCallback;
38 import org.apache.wss4j.common.ext.WSSecurityException;
39 import org.apache.wss4j.common.util.AttachmentUtils;
40 import org.apache.wss4j.stax.ext.WSSConstants;
41 import org.apache.wss4j.stax.ext.WSSSecurePart;
42 import org.apache.wss4j.stax.ext.WSSSecurityProperties;
43 import org.apache.wss4j.stax.impl.transformer.AttachmentContentSignatureTransform;
44 import org.apache.wss4j.stax.utils.WSSUtils;
45 import org.apache.xml.security.exceptions.XMLSecurityException;
46 import org.apache.xml.security.stax.ext.OutputProcessorChain;
47 import org.apache.xml.security.stax.ext.SecurePart;
48 import org.apache.xml.security.stax.ext.Transformer;
49 import org.apache.xml.security.stax.ext.XMLSecurityConstants;
50 import org.apache.xml.security.stax.ext.stax.XMLSecAttribute;
51 import org.apache.xml.security.stax.ext.stax.XMLSecEvent;
52 import org.apache.xml.security.stax.ext.stax.XMLSecStartElement;
53 import org.apache.xml.security.stax.impl.SignaturePartDef;
54 import org.apache.xml.security.stax.impl.processor.output.AbstractSignatureOutputProcessor;
55 import org.apache.xml.security.stax.impl.util.DigestOutputStream;
56 import org.apache.xml.security.stax.impl.util.IDGenerator;
57 import org.apache.xml.security.utils.XMLUtils;
58
59 public class WSSSignatureOutputProcessor extends AbstractSignatureOutputProcessor {
60
61 private static final org.slf4j.Logger LOG =
62 org.slf4j.LoggerFactory.getLogger(WSSSignatureOutputProcessor.class);
63
64 public WSSSignatureOutputProcessor() throws XMLSecurityException {
65 super();
66 }
67
68 @Override
69 public void init(OutputProcessorChain outputProcessorChain) throws XMLSecurityException {
70 super.init(outputProcessorChain);
71 WSSSignatureEndingOutputProcessor signatureEndingOutputProcessor = new WSSSignatureEndingOutputProcessor(this);
72 signatureEndingOutputProcessor.setXMLSecurityProperties(getSecurityProperties());
73 signatureEndingOutputProcessor.setAction(getAction(), getActionOrder());
74 signatureEndingOutputProcessor.init(outputProcessorChain);
75 }
76
77 @Override
78 public void processEvent(XMLSecEvent xmlSecEvent, OutputProcessorChain outputProcessorChain)
79 throws XMLStreamException, XMLSecurityException {
80 if (xmlSecEvent.getEventType() == XMLStreamConstants.START_ELEMENT) {
81 XMLSecStartElement xmlSecStartElement = xmlSecEvent.asStartElement();
82
83
84 if (getActiveInternalSignatureOutputProcessor() == null) {
85 SecurePart securePart = securePartMatches(xmlSecStartElement, outputProcessorChain, WSSConstants.SIGNATURE_PARTS);
86 if (securePart != null) {
87 LOG.debug("Matched securePart for signature");
88
89 SignaturePartDef signaturePartDef = new SignaturePartDef();
90 signaturePartDef.setSecurePart(securePart);
91 signaturePartDef.setTransforms(securePart.getTransforms());
92 if (signaturePartDef.getTransforms() == null) {
93 signaturePartDef.setTransforms(new String[]{XMLSecurityConstants.NS_C14N_EXCL_OMIT_COMMENTS});
94 }
95 signaturePartDef.setExcludeVisibleC14Nprefixes(true);
96 signaturePartDef.setDigestAlgo(securePart.getDigestMethod());
97 if (signaturePartDef.getDigestAlgo() == null) {
98 signaturePartDef.setDigestAlgo(getSecurityProperties().getSignatureDigestAlgorithm());
99 }
100
101 if (securePart.getIdToSecure() == null) {
102 signaturePartDef.setGenerateXPointer(securePart.isGenerateXPointer());
103 signaturePartDef.setSigRefId(IDGenerator.generateID(null));
104
105 Attribute attribute = xmlSecStartElement.getAttributeByName(WSSConstants.ATT_WSU_ID);
106 if (attribute != null) {
107 signaturePartDef.setSigRefId(attribute.getValue());
108 } else {
109 List<XMLSecAttribute> attributeList = new ArrayList<>(1);
110 attributeList.add(createAttribute(WSSConstants.ATT_WSU_ID, signaturePartDef.getSigRefId()));
111 xmlSecEvent = addAttributes(xmlSecStartElement, attributeList);
112 }
113 } else {
114 if (WSSConstants.SOAPMESSAGE_NS10_STR_TRANSFORM.equals(securePart.getName().getLocalPart())) {
115 if (securePart instanceof WSSSecurePart) {
116 signaturePartDef.setSigRefId(((WSSSecurePart)securePart).getIdToReference());
117 }
118 String[] transforms = new String[]{
119 WSSConstants.SOAPMESSAGE_NS10_STR_TRANSFORM,
120 WSSConstants.NS_C14N_EXCL
121 };
122 signaturePartDef.setTransforms(transforms);
123 } else {
124 signaturePartDef.setSigRefId(securePart.getIdToSecure());
125 }
126 }
127
128 getSignaturePartDefList().add(signaturePartDef);
129 InternalSignatureOutputProcessor internalSignatureOutputProcessor =
130 new InternalWSSSignatureOutputProcessor(signaturePartDef, xmlSecStartElement);
131 internalSignatureOutputProcessor.setXMLSecurityProperties(getSecurityProperties());
132 internalSignatureOutputProcessor.setAction(getAction(), getActionOrder());
133 internalSignatureOutputProcessor.addAfterProcessor(WSSSignatureOutputProcessor.class);
134 internalSignatureOutputProcessor.addBeforeProcessor(WSSSignatureEndingOutputProcessor.class);
135 internalSignatureOutputProcessor.init(outputProcessorChain);
136
137 setActiveInternalSignatureOutputProcessor(internalSignatureOutputProcessor);
138
139
140 if (WSSConstants.TAG_SOAP_BODY_LN.equals(xmlSecStartElement.getName().getLocalPart())
141 && WSSUtils.isInSOAPBody(xmlSecStartElement)) {
142 doFinalInternal(outputProcessorChain);
143 outputProcessorChain.removeProcessor(this);
144 }
145 }
146 }
147 }
148 outputProcessorChain.processEvent(xmlSecEvent);
149 }
150
151 @Override
152 protected void digestExternalReference(
153 OutputProcessorChain outputProcessorChain, SecurePart securePart)
154 throws XMLSecurityException, XMLStreamException {
155
156 if (securePart.getExternalReference() != null && securePart.getExternalReference().startsWith("cid:")) {
157
158 CallbackHandler attachmentCallbackHandler =
159 ((WSSSecurityProperties) getSecurityProperties()).getAttachmentCallbackHandler();
160 if (attachmentCallbackHandler == null) {
161 throw new WSSecurityException(
162 WSSecurityException.ErrorCode.FAILED_SIGNATURE,
163 "empty",
164 new Object[] {"no attachment callbackhandler supplied"}
165 );
166 }
167
168 AttachmentRequestCallback attachmentRequestCallback = new AttachmentRequestCallback();
169 String id = AttachmentUtils.getAttachmentId(securePart.getExternalReference());
170 attachmentRequestCallback.setAttachmentId(id);
171 try {
172 attachmentCallbackHandler.handle(new Callback[]{attachmentRequestCallback});
173 } catch (Exception e) {
174 throw new WSSecurityException(
175 WSSecurityException.ErrorCode.FAILED_SIGNATURE, e
176 );
177 }
178 List<Attachment> attachments = attachmentRequestCallback.getAttachments();
179 if (attachments != null) {
180 for (int i = 0; i < attachments.size(); i++) {
181 final Attachment attachment = attachments.get(i);
182
183 SignaturePartDef signaturePartDef = new SignaturePartDef();
184 signaturePartDef.setSecurePart(securePart);
185 signaturePartDef.setSigRefId("cid:" + attachment.getId());
186 signaturePartDef.setExternalResource(true);
187 signaturePartDef.setTransforms(securePart.getTransforms());
188 if (signaturePartDef.getTransforms() == null) {
189 if (securePart.getModifier() == SecurePart.Modifier.Element) {
190 signaturePartDef.setTransforms(new String[]{WSSConstants.SWA_ATTACHMENT_COMPLETE_SIG_TRANS});
191 } else {
192 signaturePartDef.setTransforms(new String[]{WSSConstants.SWA_ATTACHMENT_CONTENT_SIG_TRANS});
193 }
194 }
195 signaturePartDef.setExcludeVisibleC14Nprefixes(true);
196 signaturePartDef.setDigestAlgo(securePart.getDigestMethod());
197 if (signaturePartDef.getDigestAlgo() == null) {
198 signaturePartDef.setDigestAlgo(getSecurityProperties().getSignatureDigestAlgorithm());
199 }
200
201 DigestOutputStream digestOutputStream = createMessageDigestOutputStream(signaturePartDef.getDigestAlgo());
202 InputStream inputStream = attachment.getSourceStream();
203 if (!inputStream.markSupported()) {
204 inputStream = new BufferedInputStream(inputStream);
205 }
206 inputStream.mark(Integer.MAX_VALUE);
207
208 try {
209 Transformer transformer = buildTransformerChain(digestOutputStream, signaturePartDef, null);
210
211 Map<String, Object> transformerProperties = new HashMap<>(2);
212 transformerProperties.put(
213 AttachmentContentSignatureTransform.ATTACHMENT, attachment);
214 transformer.setProperties(transformerProperties);
215 transformer.transform(inputStream);
216 transformer.doFinal();
217
218 digestOutputStream.close();
219
220
221 inputStream.reset();
222 } catch (IOException | XMLStreamException e) {
223 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILED_SIGNATURE, e);
224 }
225
226 String calculatedDigest = XMLUtils.encodeToString(digestOutputStream.getDigestValue());
227 LOG.debug("Calculated Digest: {}", calculatedDigest);
228
229 signaturePartDef.setDigestValue(calculatedDigest);
230
231
232 Attachment resultAttachment = new Attachment();
233 resultAttachment.setId(attachment.getId());
234 resultAttachment.setMimeType(attachment.getMimeType());
235 resultAttachment.addHeaders(attachment.getHeaders());
236 resultAttachment.setSourceStream(inputStream);
237
238 AttachmentResultCallback attachmentResultCallback = new AttachmentResultCallback();
239 attachmentResultCallback.setAttachmentId(resultAttachment.getId());
240 attachmentResultCallback.setAttachment(resultAttachment);
241 try {
242 attachmentCallbackHandler.handle(new Callback[]{attachmentResultCallback});
243 } catch (Exception e) {
244 throw new WSSecurityException(WSSecurityException.ErrorCode.FAILED_SIGNATURE, e);
245 }
246
247 getSignaturePartDefList().add(signaturePartDef);
248 }
249 }
250 } else {
251 super.digestExternalReference(outputProcessorChain, securePart);
252 }
253 }
254
255 @Override
256 protected SecurePart securePartMatches(XMLSecStartElement xmlSecStartElement, Map<Object, SecurePart> secureParts) {
257
258 if (!xmlSecStartElement.getOnElementDeclaredAttributes().isEmpty()) {
259 Attribute attribute = xmlSecStartElement.getAttributeByName(WSSConstants.ATT_WSU_ID);
260 if (attribute != null) {
261 SecurePart securePart = secureParts.get(attribute.getValue());
262 if (securePart != null) {
263 return securePart;
264 }
265 }
266 attribute = xmlSecStartElement.getAttributeByName(WSSConstants.ATT_NULL_Id);
267 if (attribute != null) {
268 SecurePart securePart = secureParts.get(attribute.getValue());
269 if (securePart != null) {
270 return securePart;
271 }
272 }
273 attribute = xmlSecStartElement.getAttributeByName(WSSConstants.ATT_NULL_ID);
274 if (attribute != null) {
275 SecurePart securePart = secureParts.get(attribute.getValue());
276 if (securePart != null) {
277 return securePart;
278 }
279 }
280 attribute = xmlSecStartElement.getAttributeByName(WSSConstants.ATT_NULL_ASSERTION_ID);
281 if (attribute != null) {
282 SecurePart securePart = secureParts.get(attribute.getValue());
283 if (securePart != null) {
284 return securePart;
285 }
286 }
287 }
288
289 return secureParts.get(xmlSecStartElement.getName());
290 }
291
292 class InternalWSSSignatureOutputProcessor extends InternalSignatureOutputProcessor {
293
294 InternalWSSSignatureOutputProcessor(SignaturePartDef signaturePartDef, XMLSecStartElement xmlSecStartElement)
295 throws XMLSecurityException {
296 super(signaturePartDef, xmlSecStartElement);
297 this.addBeforeProcessor(InternalWSSSignatureOutputProcessor.class);
298 }
299 }
300 }