blob: 8a3af2b8818d3d98ab9107f849d285091ce5c2ec [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Portions Copyright 2005 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26/*
27 * ===========================================================================
28 *
29 * (C) Copyright IBM Corp. 2003 All Rights Reserved.
30 *
31 * ===========================================================================
32 */
33/*
34 * $Id: DOMRetrievalMethod.java,v 1.24 2005/05/12 19:28:32 mullan Exp $
35 */
36package org.jcp.xml.dsig.internal.dom;
37
38import java.io.ByteArrayInputStream;
39import java.net.URI;
40import java.net.URISyntaxException;
41import java.util.*;
42import javax.xml.crypto.*;
43import javax.xml.crypto.dsig.*;
44import javax.xml.crypto.dom.DOMCryptoContext;
45import javax.xml.crypto.dom.DOMURIReference;
46import javax.xml.crypto.dsig.keyinfo.RetrievalMethod;
47import javax.xml.parsers.*;
48import org.w3c.dom.Attr;
49import org.w3c.dom.Document;
50import org.w3c.dom.Element;
51import org.w3c.dom.Node;
52
53import com.sun.org.apache.xml.internal.security.signature.XMLSignatureInput;
54
55/**
56 * DOM-based implementation of RetrievalMethod.
57 *
58 * @author Sean Mullan
59 * @author Joyce Leung
60 */
61public final class DOMRetrievalMethod extends DOMStructure
62 implements RetrievalMethod, DOMURIReference {
63
64 private final List transforms;
65 private String uri;
66 private String type;
67 private Attr here;
68
69 /**
70 * Creates a <code>DOMRetrievalMethod</code> containing the specified
71 * URIReference and List of Transforms.
72 *
73 * @param uri the URI
74 * @param type the type
75 * @param transforms a list of {@link Transform}s. The list is defensively
76 * copied to prevent subsequent modification. May be <code>null</code>
77 * or empty.
78 * @throws IllegalArgumentException if the format of <code>uri</code> is
79 * invalid, as specified by Reference's URI attribute in the W3C
80 * specification for XML-Signature Syntax and Processing
81 * @throws NullPointerException if <code>uriReference</code>
82 * is <code>null</code>
83 * @throws ClassCastException if <code>transforms</code> contains any
84 * entries that are not of type {@link Transform}
85 */
86 public DOMRetrievalMethod(String uri, String type, List transforms) {
87 if (uri == null) {
88 throw new NullPointerException("uri cannot be null");
89 }
90 if (transforms == null || transforms.isEmpty()) {
91 this.transforms = Collections.EMPTY_LIST;
92 } else {
93 List transformsCopy = new ArrayList(transforms);
94 for (int i = 0, size = transformsCopy.size(); i < size; i++) {
95 if (!(transformsCopy.get(i) instanceof Transform)) {
96 throw new ClassCastException
97 ("transforms["+i+"] is not a valid type");
98 }
99 }
100 this.transforms = Collections.unmodifiableList(transformsCopy);
101 }
102 this.uri = uri;
103 if ((uri != null) && (!uri.equals(""))) {
104 try {
105 new URI(uri);
106 } catch (URISyntaxException e) {
107 throw new IllegalArgumentException(e.getMessage());
108 }
109 }
110
111 this.type = type;
112 }
113
114 /**
115 * Creates a <code>DOMRetrievalMethod</code> from an element.
116 *
117 * @param rmElem a RetrievalMethod element
118 */
119 public DOMRetrievalMethod(Element rmElem, XMLCryptoContext context)
120 throws MarshalException {
121 // get URI and Type attributes
122 uri = DOMUtils.getAttributeValue(rmElem, "URI");
123 type = DOMUtils.getAttributeValue(rmElem, "Type");
124
125 // get here node
126 here = rmElem.getAttributeNodeNS(null, "URI");
127
128 // get Transforms, if specified
129 List transforms = new ArrayList();
130 Element transformsElem = DOMUtils.getFirstChildElement(rmElem);
131 if (transformsElem != null) {
132 Element transformElem =
133 DOMUtils.getFirstChildElement(transformsElem);
134 while (transformElem != null) {
135 transforms.add(new DOMTransform(transformElem, context));
136 transformElem = DOMUtils.getNextSiblingElement(transformElem);
137 }
138 }
139 if (transforms.isEmpty()) {
140 this.transforms = Collections.EMPTY_LIST;
141 } else {
142 this.transforms = Collections.unmodifiableList(transforms);
143 }
144 }
145
146 public String getURI() {
147 return uri;
148 }
149
150 public String getType() {
151 return type;
152 }
153
154 public List getTransforms() {
155 return transforms;
156 }
157
158 public void marshal(Node parent, String dsPrefix, DOMCryptoContext context)
159 throws MarshalException {
160 Document ownerDoc = DOMUtils.getOwnerDocument(parent);
161
162 Element rmElem = DOMUtils.createElement
163 (ownerDoc, "RetrievalMethod", XMLSignature.XMLNS, dsPrefix);
164
165 // add URI and Type attributes
166 DOMUtils.setAttribute(rmElem, "URI", uri);
167 DOMUtils.setAttribute(rmElem, "Type", type);
168
169 // add Transforms elements
170 if (!transforms.isEmpty()) {
171 Element transformsElem = DOMUtils.createElement
172 (ownerDoc, "Transforms", XMLSignature.XMLNS, dsPrefix);
173 rmElem.appendChild(transformsElem);
174 for (int i = 0, size = transforms.size(); i < size; i++) {
175 ((DOMTransform) transforms.get(i)).marshal
176 (transformsElem, dsPrefix, context);
177 }
178 }
179
180 parent.appendChild(rmElem);
181
182 // save here node
183 here = rmElem.getAttributeNodeNS(null, "URI");
184 }
185
186 public Node getHere() {
187 return here;
188 }
189
190 public Data dereference(XMLCryptoContext context)
191 throws URIReferenceException {
192
193 if (context == null) {
194 throw new NullPointerException("context cannot be null");
195 }
196
197 /*
198 * If URIDereferencer is specified in context; use it, otherwise use
199 * built-in.
200 */
201 URIDereferencer deref = context.getURIDereferencer();
202 if (deref == null) {
203 deref = DOMURIDereferencer.INSTANCE;
204 }
205
206 Data data = deref.dereference(this, context);
207
208 // pass dereferenced data through Transforms
209 try {
210 for (int i = 0, size = transforms.size(); i < size; i++) {
211 Transform transform = (Transform) transforms.get(i);
212 data = ((DOMTransform) transform).transform(data, context);
213 }
214 } catch (Exception e) {
215 throw new URIReferenceException(e);
216 }
217 return data;
218 }
219
220 public XMLStructure dereferenceAsXMLStructure(XMLCryptoContext context)
221 throws URIReferenceException {
222
223 try {
224 ApacheData data = (ApacheData) dereference(context);
225 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
226 dbf.setNamespaceAware(true);
227 DocumentBuilder db = dbf.newDocumentBuilder();
228 Document doc = db.parse(new ByteArrayInputStream
229 (data.getXMLSignatureInput().getBytes()));
230 Element kiElem = doc.getDocumentElement();
231 if (kiElem.getLocalName().equals("X509Data")) {
232 return new DOMX509Data(kiElem);
233 } else {
234 return null; // unsupported
235 }
236 } catch (Exception e) {
237 throw new URIReferenceException(e);
238 }
239 }
240
241 public boolean equals(Object obj) {
242 if (this == obj) {
243 return true;
244 }
245 if (!(obj instanceof RetrievalMethod)) {
246 return false;
247 }
248 RetrievalMethod orm = (RetrievalMethod) obj;
249
250 boolean typesEqual = (type == null ? orm.getType() == null :
251 type.equals(orm.getType()));
252
253 return (uri.equals(orm.getURI()) &&
254 transforms.equals(orm.getTransforms()) && typesEqual);
255 }
256}