blob: 5053156221e6fd4bd99eabc51d3934e8ea5a2b40 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * reserved comment block
3 * DO NOT REMOVE OR ALTER!
4 */
5/*
6 * Copyright 1999-2004 The Apache Software Foundation.
7 *
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 *
20 */
21package com.sun.org.apache.xml.internal.security.utils;
22
23
24
25
26import org.w3c.dom.Attr;
27import org.w3c.dom.Document;
28import org.w3c.dom.Element;
29import org.w3c.dom.Node;
30
31import java.util.Arrays;
32import java.util.WeakHashMap;
33import java.lang.ref.WeakReference;
34
35
36/**
37 * Purpose of this class is to enable the XML Parser to keep track of ID
38 * attributes. This is done by 'registering' attributes of type ID at the
39 * IdResolver. This is necessary if we create a document from scratch and we
40 * sign some resources with a URI using a fragent identifier...
41 * <BR />
42 * The problem is that if you do not validate a document, you cannot use the
43 * <CODE>getElementByID</CODE> functionality. So this modules uses some implicit
44 * knowledge on selected Schemas and DTDs to pick the right Element for a given
45 * ID: We know that all <CODE>@Id</CODE> attributes in an Element from the XML
46 * Signature namespace are of type <CODE>ID</CODE>.
47 *
48 * @author $Author: raul $
49 * @see <A HREF="http://www.xml.com/lpt/a/2001/11/07/id.html">"Identity Crisis" on xml.com</A>
50 */
51public class IdResolver {
52
53 /** {@link java.util.logging} logging facility */
54 static java.util.logging.Logger log =
55 java.util.logging.Logger.getLogger(IdResolver.class.getName());
56
57 static WeakHashMap docMap = new WeakHashMap();
58
59 /**
60 * Constructor IdResolver
61 *
62 */
63 private IdResolver() {
64
65 // we don't allow instantiation
66 }
67
68 /**
69 * Method registerElementById
70 *
71 * @param element
72 * @param idValue
73 */
74 public static void registerElementById(Element element, String idValue) {
75 Document doc = element.getOwnerDocument();
76 WeakHashMap elementMap = (WeakHashMap) docMap.get(doc);
77 if(elementMap == null) {
78 elementMap = new WeakHashMap();
79 docMap.put(doc, elementMap);
80 }
81 elementMap.put(idValue, new WeakReference(element));
82 }
83
84 /**
85 * Method registerElementById
86 *
87 * @param element
88 * @param id
89 */
90 public static void registerElementById(Element element, Attr id) {
91 IdResolver.registerElementById(element, id.getNodeValue());
92 }
93
94 /**
95 * Method getElementById
96 *
97 * @param doc
98 * @param id
99 * @return the element obtained by the Id, or null if it is not found.
100 */
101 public static Element getElementById(Document doc, String id) {
102
103 Element result = null;
104
105 result = IdResolver.getElementByIdType(doc, id);
106
107 if (result != null) {
108 if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE,
109 "I could find an Element using the simple getElementByIdType method: "
110 + result.getTagName());
111
112 return result;
113 }
114
115 result = IdResolver.getElementByIdUsingDOM(doc, id);
116
117 if (result != null) {
118 if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE,
119 "I could find an Element using the simple getElementByIdUsingDOM method: "
120 + result.getTagName());
121
122 return result;
123 }
124 // this must be done so that Xalan can catch ALL namespaces
125 //XMLUtils.circumventBug2650(doc);
126 result = IdResolver.getElementBySearching(doc, id);
127
128 if (result != null) {
129 IdResolver.registerElementById(result, id);
130
131 return result;
132 }
133
134 return null;
135 }
136
137
138 /**
139 * Method getElementByIdUsingDOM
140 *
141 * @param doc
142 * @param id
143 * @return the element obtained by the Id, or null if it is not found.
144 */
145 private static Element getElementByIdUsingDOM(Document doc, String id) {
146 if (true)
147 if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "getElementByIdUsingDOM() Search for ID " + id);
148 return doc.getElementById(id);
149 }
150
151 /**
152 * Method getElementByIdType
153 *
154 * @param doc
155 * @param id
156 * @return the element obtained by the Id, or null if it is not found.
157 */
158 private static Element getElementByIdType(Document doc, String id) {
159 if (true)
160 if (log.isLoggable(java.util.logging.Level.FINE)) log.log(java.util.logging.Level.FINE, "getElementByIdType() Search for ID " + id);
161 WeakHashMap elementMap = (WeakHashMap) docMap.get(doc);
162 if (elementMap != null) {
163 WeakReference weakReference = (WeakReference) elementMap.get(id);
164 if (weakReference != null)
165 {
166 return (Element) weakReference.get();
167 }
168 }
169 return null;
170 }
171
172
173 static java.util.List names;
174 static {
175 String namespaces[]={ Constants.SignatureSpecNS,
176 EncryptionConstants.EncryptionSpecNS,
177 "http://schemas.xmlsoap.org/soap/security/2000-12",
178 "http://www.w3.org/2002/03/xkms#"
179 };
180 names=Arrays.asList(namespaces);
181 }
182
183
184 private static Element getElementBySearching(Node root,String id) {
185 Element []els=new Element[5];
186 getElementBySearching(root,id,els);
187 for (int i=0;i<els.length;i++) {
188 if (els[i]!=null) {
189 return els[i];
190 }
191 }
192 return null;
193
194 }
195 private static int getElementBySearching(Node root,String id,Element []els) {
196 switch (root.getNodeType()) {
197 case Node.ELEMENT_NODE:
198 Element el=(Element)root;
199 if (el.hasAttributes()) {
200 int index=names.indexOf(el.getNamespaceURI());
201 if (index<0) {
202 index=4;
203 }
204 if (el.getAttribute("Id").equals(id)) {
205 els[index]=el;
206 if (index==0) {
207 return 1;
208 }
209 } else if ( el.getAttribute("id").equals(id) ) {
210 if (index!=2) {
211 index=4;
212 }
213 els[index]=el;
214 } else if ( el.getAttribute("ID").equals(id) ) {
215 if (index!=3) {
216 index=4;
217 }
218 els[index]=el;
219 } else if ((index==3)&&(
220 el.getAttribute("OriginalRequestID").equals(id) ||
221 el.getAttribute("RequestID").equals(id) ||
222 el.getAttribute("ResponseID" ).equals(id))) {
223 els[3]=el;
224 }
225 }
226 case Node.DOCUMENT_NODE:
227 Node sibling=root.getFirstChild();
228 while (sibling!=null) {
229 if (getElementBySearching(sibling,id,els)==1)
230 return 1;
231 sibling=sibling.getNextSibling();
232 }
233 }
234 return 0;
235 }
236
237}