1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.ws.security.transform;
21
22 import org.apache.ws.security.WSConstants;
23 import org.apache.ws.security.WSDocInfo;
24 import org.apache.ws.security.message.token.PKIPathSecurity;
25 import org.apache.ws.security.message.token.SecurityTokenReference;
26 import org.apache.ws.security.message.token.X509Security;
27 import org.apache.ws.security.util.WSSecurityUtil;
28
29 import org.apache.xml.security.c14n.Canonicalizer;
30 import org.apache.xml.security.signature.XMLSignatureInput;
31
32 import org.w3c.dom.Document;
33 import org.w3c.dom.Element;
34 import org.w3c.dom.Node;
35
36 import java.io.ByteArrayOutputStream;
37 import java.io.OutputStream;
38 import java.security.InvalidAlgorithmParameterException;
39 import java.security.spec.AlgorithmParameterSpec;
40 import java.util.Iterator;
41
42 import javax.xml.crypto.Data;
43 import javax.xml.crypto.MarshalException;
44 import javax.xml.crypto.NodeSetData;
45 import javax.xml.crypto.OctetStreamData;
46 import javax.xml.crypto.XMLCryptoContext;
47 import javax.xml.crypto.XMLStructure;
48 import javax.xml.crypto.dom.DOMCryptoContext;
49 import javax.xml.crypto.dsig.TransformException;
50 import javax.xml.crypto.dsig.TransformService;
51 import javax.xml.crypto.dsig.spec.TransformParameterSpec;
52
53
54
55
56
57 public class STRTransform extends TransformService {
58
59 public static final String TRANSFORM_URI =
60 "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#STR-Transform";
61
62 public static final String TRANSFORM_WS_DOC_INFO = "transform_ws_doc_info";
63
64 private TransformParameterSpec params;
65
66 private Element transformElement;
67
68 private static org.apache.commons.logging.Log log =
69 org.apache.commons.logging.LogFactory.getLog(STRTransform.class);
70
71 private static boolean doDebug = false;
72
73 public final AlgorithmParameterSpec getParameterSpec() {
74 return params;
75 }
76
77 public void init(TransformParameterSpec params)
78 throws InvalidAlgorithmParameterException {
79 this.params = params;
80 }
81
82 public void init(XMLStructure parent, XMLCryptoContext context)
83 throws InvalidAlgorithmParameterException {
84 if (context != null && !(context instanceof DOMCryptoContext)) {
85 throw new ClassCastException
86 ("context must be of type DOMCryptoContext");
87 }
88 if (!(parent instanceof javax.xml.crypto.dom.DOMStructure)) {
89 throw new ClassCastException("parent must be of type DOMStructure");
90 }
91 transformElement = (Element)
92 ((javax.xml.crypto.dom.DOMStructure) parent).getNode();
93 }
94
95 public void marshalParams(XMLStructure parent, XMLCryptoContext context)
96 throws MarshalException {
97 if (context != null && !(context instanceof DOMCryptoContext)) {
98 throw new ClassCastException
99 ("context must be of type DOMCryptoContext");
100 }
101 if (!(parent instanceof javax.xml.crypto.dom.DOMStructure)) {
102 throw new ClassCastException("parent must be of type DOMStructure");
103 }
104 Element transformElement2 = (Element)
105 ((javax.xml.crypto.dom.DOMStructure) parent).getNode();
106 appendChild(transformElement2, transformElement);
107 transformElement = transformElement2;
108 }
109
110
111 public Data transform(Data data, XMLCryptoContext xc)
112 throws TransformException {
113 if (data == null) {
114 throw new NullPointerException("data must not be null");
115 }
116 return transformIt(data, xc, null);
117 }
118
119 public Data transform(Data data, XMLCryptoContext xc, OutputStream os)
120 throws TransformException {
121 if (data == null) {
122 throw new NullPointerException("data must not be null");
123 }
124 if (os == null) {
125 throw new NullPointerException("output stream must not be null");
126 }
127 return transformIt(data, xc, os);
128 }
129
130
131 private Data transformIt(Data data, XMLCryptoContext xc, OutputStream os)
132 throws TransformException {
133 doDebug = log.isDebugEnabled();
134
135
136
137
138 String canonAlgo = null;
139 Element transformParams = WSSecurityUtil.getDirectChildElement(
140 transformElement, "TransformationParameters", WSConstants.WSSE_NS
141 );
142 if (transformParams != null) {
143 Element canonElem =
144 WSSecurityUtil.getDirectChildElement(
145 transformParams, "CanonicalizationMethod", WSConstants.SIG_NS
146 );
147 canonAlgo = canonElem.getAttribute("Algorithm");
148 }
149 try {
150
151
152
153 Element str = null;
154 if (data instanceof NodeSetData) {
155 NodeSetData nodeSetData = (NodeSetData)data;
156 Iterator<?> iterator = nodeSetData.iterator();
157 while (iterator.hasNext()) {
158 Node node = (Node)iterator.next();
159 if (node instanceof Element && "SecurityTokenReference".equals(node.getLocalName())) {
160 str = (Element)node;
161 break;
162 }
163 }
164 } else {
165 try {
166 XMLSignatureInput xmlSignatureInput =
167 new XMLSignatureInput(((OctetStreamData)data).getOctetStream());
168 str = (Element)xmlSignatureInput.getSubNode();
169 } catch (Exception ex) {
170 throw new TransformException(ex);
171 }
172 }
173 if (str == null) {
174 throw new TransformException("No SecurityTokenReference found");
175 }
176
177
178
179
180 SecurityTokenReference secRef = new SecurityTokenReference(str);
181
182 Canonicalizer canon = Canonicalizer.getInstance(canonAlgo);
183
184 ByteArrayOutputStream bos = null;
185 byte[] buf = null;
186
187
188
189
190 Object wsDocInfoObject = xc.getProperty(TRANSFORM_WS_DOC_INFO);
191 WSDocInfo wsDocInfo = null;
192 if (wsDocInfoObject instanceof WSDocInfo) {
193 wsDocInfo = (WSDocInfo)wsDocInfoObject;
194 }
195 if (wsDocInfo == null && doDebug) {
196 log.debug("STRTransform: no WSDocInfo found");
197 }
198
199 Document doc = str.getOwnerDocument();
200 Element dereferencedToken =
201 STRTransformUtil.dereferenceSTR(doc, secRef, wsDocInfo);
202
203 if (dereferencedToken != null) {
204 String type = dereferencedToken.getAttribute("ValueType");
205 if ((X509Security.X509_V3_TYPE.equals(type)
206 || PKIPathSecurity.getType().equals(type))) {
207
208
209
210 WSSecurityUtil.setNamespace(
211 dereferencedToken, WSConstants.WSSE_NS, WSConstants.WSSE_PREFIX
212 );
213 WSSecurityUtil.setNamespace(
214 dereferencedToken, WSConstants.WSU_NS, WSConstants.WSU_PREFIX
215 );
216 }
217 }
218
219
220
221
222 buf = canon.canonicalizeSubtree(dereferencedToken, "#default");
223 if (doDebug) {
224 bos = new ByteArrayOutputStream(buf.length);
225 bos.write(buf, 0, buf.length);
226 log.debug("after c14n: " + bos.toString());
227 }
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242 StringBuilder bf = new StringBuilder(new String(buf));
243 String bf1 = bf.toString();
244
245
246
247
248 int gt = bf1.indexOf('>');
249
250
251
252 int idx = bf1.indexOf("xmlns=");
253
254
255
256
257
258 if (idx < 0 || idx > gt) {
259 idx = bf1.indexOf(' ');
260 bf.insert(idx + 1, "xmlns=\"\" ");
261 bf1 = bf.toString();
262 }
263 if (doDebug) {
264 log.debug("last result: ");
265 log.debug(bf1);
266 }
267 XMLSignatureInput output = new XMLSignatureInput(bf1.getBytes());
268 if (os != null) {
269 output.updateOutputStream(os);
270 return null;
271 }
272 return new OctetStreamData(output.getOctetStream());
273 } catch (Exception ex) {
274 throw new TransformException(ex);
275 }
276 }
277
278
279 public final boolean isFeatureSupported(String feature) {
280 if (feature == null) {
281 throw new NullPointerException();
282 } else {
283 return false;
284 }
285 }
286
287 private static void appendChild(Node parent, Node child) {
288 Document ownerDoc = null;
289 if (parent.getNodeType() == Node.DOCUMENT_NODE) {
290 ownerDoc = (Document)parent;
291 } else {
292 ownerDoc = parent.getOwnerDocument();
293 }
294 if (child.getOwnerDocument() != ownerDoc) {
295 parent.appendChild(ownerDoc.importNode(child, true));
296 } else {
297 parent.appendChild(child);
298 }
299 }
300
301 }