1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.wss4j.dom.transform;
20
21 import org.apache.jcp.xml.dsig.internal.dom.ApacheOctetStreamData;
22 import org.apache.wss4j.common.ext.Attachment;
23 import org.apache.wss4j.common.ext.AttachmentRequestCallback;
24 import org.apache.wss4j.common.ext.AttachmentResultCallback;
25 import org.apache.wss4j.common.ext.WSSecurityException;
26 import org.apache.wss4j.common.util.AttachmentUtils;
27 import org.apache.wss4j.common.util.CRLFOutputStream;
28 import org.apache.wss4j.dom.WSConstants;
29 import org.apache.xml.security.c14n.CanonicalizationException;
30 import org.apache.xml.security.c14n.Canonicalizer;
31 import org.apache.xml.security.c14n.InvalidCanonicalizerException;
32 import org.apache.xml.security.parser.XMLParserException;
33 import org.apache.xml.security.signature.XMLSignatureInput;
34 import org.apache.xml.security.signature.XMLSignatureStreamInput;
35
36 import javax.security.auth.callback.Callback;
37 import javax.security.auth.callback.CallbackHandler;
38 import javax.xml.crypto.Data;
39 import javax.xml.crypto.MarshalException;
40 import javax.xml.crypto.OctetStreamData;
41 import javax.xml.crypto.XMLCryptoContext;
42 import javax.xml.crypto.XMLStructure;
43 import javax.xml.crypto.dsig.TransformException;
44 import javax.xml.crypto.dsig.TransformService;
45 import javax.xml.crypto.dsig.spec.TransformParameterSpec;
46
47 import java.io.BufferedInputStream;
48 import java.io.ByteArrayInputStream;
49 import java.io.ByteArrayOutputStream;
50 import java.io.FilterInputStream;
51 import java.io.IOException;
52 import java.io.InputStream;
53 import java.io.OutputStream;
54 import java.security.InvalidAlgorithmParameterException;
55 import java.security.spec.AlgorithmParameterSpec;
56 import java.util.List;
57
58 public class AttachmentContentSignatureTransform extends TransformService {
59
60 public static final String TRANSFORM_URI = WSConstants.SWA_ATTACHMENT_CONTENT_SIG_TRANS;
61 public static final String ATTACHMENT_CALLBACKHANDLER = "AttachmentContentTransform.attachmentCallbackHandler";
62
63 private AttachmentTransformParameterSpec attachmentTransformParameterSpec;
64
65 @Override
66 public void init(TransformParameterSpec params) throws InvalidAlgorithmParameterException {
67 if (!(params instanceof AttachmentTransformParameterSpec)) {
68 throw new InvalidAlgorithmParameterException("Expected AttachmentTransformParameterSpec");
69 }
70 this.attachmentTransformParameterSpec = (AttachmentTransformParameterSpec) params;
71 }
72
73 protected AttachmentTransformParameterSpec getAttachmentTransformParameterSpec() {
74 return attachmentTransformParameterSpec;
75 }
76
77 @Override
78 public void init(XMLStructure parent, XMLCryptoContext context) throws InvalidAlgorithmParameterException {
79 }
80
81 @Override
82 public void marshalParams(XMLStructure parent, XMLCryptoContext context) throws MarshalException {
83 }
84
85 @Override
86 public AlgorithmParameterSpec getParameterSpec() {
87 return attachmentTransformParameterSpec;
88 }
89
90 @Override
91 public Data transform(Data data, XMLCryptoContext context) throws TransformException {
92 return transform(data, context, null);
93 }
94
95
96
97
98
99
100
101
102
103 @Override
104 public Data transform(Data data, XMLCryptoContext context, OutputStream os) throws TransformException {
105
106 String attachmentUri = ((ApacheOctetStreamData) data).getURI();
107 String attachmentId = null;
108 try {
109 attachmentId = AttachmentUtils.getAttachmentId(attachmentUri);
110 } catch (WSSecurityException e) {
111 throw new TransformException(e);
112 }
113
114 Attachment attachment;
115 if (attachmentTransformParameterSpec != null) {
116 attachment = attachmentTransformParameterSpec.getAttachment();
117 context.setProperty(ATTACHMENT_CALLBACKHANDLER,
118 attachmentTransformParameterSpec.getAttachmentCallbackHandler());
119 } else {
120 attachment = attachmentRequestCallback(context, attachmentId);
121 }
122 return processAttachment(context, os, attachmentUri, attachment);
123 }
124
125 protected Attachment attachmentRequestCallback(XMLCryptoContext context, String attachmentId)
126 throws TransformException {
127 CallbackHandler attachmentCallbackHandler =
128 (CallbackHandler) context.getProperty(ATTACHMENT_CALLBACKHANDLER);
129 if (attachmentCallbackHandler == null) {
130 throw new TransformException("No attachment callbackhandler supplied");
131 }
132 AttachmentRequestCallback attachmentRequestCallback = new AttachmentRequestCallback();
133 attachmentRequestCallback.setAttachmentId(attachmentId);
134 try {
135 attachmentCallbackHandler.handle(new Callback[]{attachmentRequestCallback});
136 } catch (Exception e) {
137 throw new TransformException(e);
138 }
139 List<Attachment> attachments = attachmentRequestCallback.getAttachments();
140 if (attachments == null || attachments.isEmpty() || !attachmentId.equals(attachments.get(0).getId())) {
141 throw new TransformException("Attachment not found");
142 }
143 return attachments.get(0);
144 }
145
146 protected void attachmentResultCallback(XMLCryptoContext context, Attachment attachment)
147 throws TransformException {
148 CallbackHandler attachmentCallbackHandler =
149 (CallbackHandler) context.getProperty(ATTACHMENT_CALLBACKHANDLER);
150 if (attachmentCallbackHandler == null) {
151 throw new TransformException("No attachment callbackhandler supplied");
152 }
153 AttachmentResultCallback attachmentResultCallback = new AttachmentResultCallback();
154 attachmentResultCallback.setAttachmentId(attachment.getId());
155 attachmentResultCallback.setAttachment(attachment);
156 try {
157 attachmentCallbackHandler.handle(new Callback[]{attachmentResultCallback});
158 } catch (Exception e) {
159 throw new TransformException(e);
160 }
161 }
162
163 @SuppressWarnings("resource")
164 protected Data processAttachment(XMLCryptoContext context, OutputStream os, String attachmentUri,
165 Attachment attachment) throws TransformException {
166 try {
167
168 InputStream inputStream = attachment.getSourceStream();
169 if (!inputStream.markSupported()) {
170 inputStream = new BufferedInputStream(inputStream);
171 }
172 inputStream.mark(Integer.MAX_VALUE);
173 inputStream = new FilterInputStream(inputStream) {
174 @Override
175 public void close() throws IOException {
176
177 }
178 };
179
180 OutputStream outputStream = os;
181 if (outputStream == null) {
182 outputStream = new ByteArrayOutputStream();
183 }
184
185 String mimeType = attachment.getMimeType();
186
187 if (mimeType != null
188 && (mimeType.matches("(?i)(text/xml).*")
189 || mimeType.matches("(?i)(application/xml).*")
190 || mimeType.matches("(?i)(application|image)/.*\\+xml.*"))) {
191
192
193
194
195
196
197
198
199
200
201 Canonicalizer canon = Canonicalizer.getInstance(WSConstants.C14N_EXCL_OMIT_COMMENTS);
202
203 XMLSignatureInput xmlSignatureInput = new XMLSignatureStreamInput(inputStream);
204 canon.canonicalizeXPathNodeSet(xmlSignatureInput.getNodeSet(), outputStream);
205
206 } else if (mimeType != null && mimeType.matches("(?i)(text/).*")) {
207 CRLFOutputStream crlfOutputStream = new CRLFOutputStream(outputStream);
208 int numBytes;
209 byte[] buf = new byte[8192];
210 while ((numBytes = inputStream.read(buf)) != -1) {
211 crlfOutputStream.write(buf, 0, numBytes);
212 }
213
214 } else {
215 int numBytes;
216 byte[] buf = new byte[8192];
217 while ((numBytes = inputStream.read(buf)) != -1) {
218 outputStream.write(buf, 0, numBytes);
219 }
220 }
221
222
223 inputStream.reset();
224
225
226 final Attachment resultAttachment = new Attachment();
227 resultAttachment.setId(attachment.getId());
228 resultAttachment.setMimeType(mimeType);
229 resultAttachment.addHeaders(attachment.getHeaders());
230 resultAttachment.setSourceStream(inputStream);
231 attachmentResultCallback(context, resultAttachment);
232
233 if (os == null) {
234 return new OctetStreamData(
235 new ByteArrayInputStream(
236 ((ByteArrayOutputStream)outputStream).toByteArray()
237 ),
238 attachmentUri, mimeType);
239 }
240 return null;
241 } catch (IOException | InvalidCanonicalizerException | CanonicalizationException
242 | XMLParserException e) {
243 throw new TransformException(e);
244 }
245 }
246
247 @Override
248 public boolean isFeatureSupported(String feature) {
249 if (feature == null) {
250 throw new NullPointerException();
251 } else {
252 return false;
253 }
254 }
255 }