View Javadoc
1   /*
2    * reserved comment block
3    * DO NOT REMOVE OR ALTER!
4    */
5   /**
6    * Licensed to the Apache Software Foundation (ASF) under one
7    * or more contributor license agreements. See the NOTICE file
8    * distributed with this work for additional information
9    * regarding copyright ownership. The ASF licenses this file
10   * to you under the Apache License, Version 2.0 (the
11   * "License"); you may not use this file except in compliance
12   * with the License. You may obtain a copy of the License at
13   *
14   * http://www.apache.org/licenses/LICENSE-2.0
15   *
16   * Unless required by applicable law or agreed to in writing,
17   * software distributed under the License is distributed on an
18   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
19   * KIND, either express or implied. See the License for the
20   * specific language governing permissions and limitations
21   * under the License.
22   */
23  package com.sun.org.apache.xml.internal.security.utils.resolver;
24  
25  import java.util.ArrayList;
26  import java.util.List;
27  import java.util.Map;
28  
29  import com.sun.org.apache.xml.internal.security.signature.XMLSignatureInput;
30  import com.sun.org.apache.xml.internal.security.utils.resolver.implementations.ResolverDirectHTTP;
31  import com.sun.org.apache.xml.internal.security.utils.resolver.implementations.ResolverFragment;
32  import com.sun.org.apache.xml.internal.security.utils.resolver.implementations.ResolverLocalFilesystem;
33  import com.sun.org.apache.xml.internal.security.utils.resolver.implementations.ResolverXPointer;
34  import org.w3c.dom.Attr;
35  
36  /**
37   * During reference validation, we have to retrieve resources from somewhere.
38   * This is done by retrieving a Resolver. The resolver needs two arguments: The
39   * URI in which the link to the new resource is defined and the baseURI of the
40   * file/entity in which the URI occurs (the baseURI is the same as the SystemId).
41   */
42  public class ResourceResolver {
43  
44      /** {@link org.apache.commons.logging} logging facility */
45      private static java.util.logging.Logger log =
46          java.util.logging.Logger.getLogger(ResourceResolver.class.getName());
47  
48      /** these are the system-wide resolvers */
49      private static List<ResourceResolver> resolverList = new ArrayList<ResourceResolver>();
50  
51      /** Field resolverSpi */
52      private final ResourceResolverSpi resolverSpi;
53  
54      /**
55       * Constructor ResourceResolver
56       *
57       * @param resourceResolver
58       */
59      public ResourceResolver(ResourceResolverSpi resourceResolver) {
60          this.resolverSpi = resourceResolver;
61      }
62  
63      /**
64       * Method getInstance
65       *
66       * @param uri
67       * @param baseURI
68       * @return the instance
69       *
70       * @throws ResourceResolverException
71       */
72      public static final ResourceResolver getInstance(Attr uri, String baseURI)
73          throws ResourceResolverException {
74          return getInstance(uri, baseURI, false);
75      }
76  
77      /**
78       * Method getInstance
79       *
80       * @param uri
81       * @param baseURI
82       * @param secureValidation
83       * @return the instance
84       *
85       * @throws ResourceResolverException
86       */
87      public static final ResourceResolver getInstance(
88          Attr uriAttr, String baseURI, boolean secureValidation
89      ) throws ResourceResolverException {
90          ResourceResolverContext context = new ResourceResolverContext(uriAttr, baseURI, secureValidation);
91          return internalGetInstance(context);
92      }
93  
94      private static <N> ResourceResolver internalGetInstance(ResourceResolverContext context)
95              throws ResourceResolverException {
96          synchronized (resolverList) {
97              for (ResourceResolver resolver : resolverList) {
98                  ResourceResolver resolverTmp = resolver;
99                  if (!resolver.resolverSpi.engineIsThreadSafe()) {
100                     try {
101                         resolverTmp =
102                             new ResourceResolver(resolver.resolverSpi.getClass().newInstance());
103                     } catch (InstantiationException e) {
104                         throw new ResourceResolverException("", e, context.attr, context.baseUri);
105                     } catch (IllegalAccessException e) {
106                         throw new ResourceResolverException("", e, context.attr, context.baseUri);
107                     }
108                 }
109 
110                 if (log.isLoggable(java.util.logging.Level.FINE)) {
111                     log.log(java.util.logging.Level.FINE,
112                         "check resolvability by class " + resolverTmp.getClass().getName()
113                     );
114                 }
115 
116                 if ((resolverTmp != null) && resolverTmp.canResolve(context)) {
117                     // Check to see whether the Resolver is allowed
118                     if (context.secureValidation
119                         && (resolverTmp.resolverSpi instanceof ResolverLocalFilesystem
120                             || resolverTmp.resolverSpi instanceof ResolverDirectHTTP)) {
121                         Object exArgs[] = { resolverTmp.resolverSpi.getClass().getName() };
122                         throw new ResourceResolverException(
123                             "signature.Reference.ForbiddenResolver", exArgs, context.attr, context.baseUri
124                         );
125                     }
126                     return resolverTmp;
127                 }
128             }
129         }
130 
131         Object exArgs[] = { ((context.uriToResolve != null)
132                 ? context.uriToResolve : "null"), context.baseUri };
133 
134         throw new ResourceResolverException("utils.resolver.noClass", exArgs, context.attr, context.baseUri);
135     }
136 
137     /**
138      * Method getInstance
139      *
140      * @param uri
141      * @param baseURI
142      * @param individualResolvers
143      * @return the instance
144      *
145      * @throws ResourceResolverException
146      */
147     public static ResourceResolver getInstance(
148         Attr uri, String baseURI, List<ResourceResolver> individualResolvers
149     ) throws ResourceResolverException {
150         return getInstance(uri, baseURI, individualResolvers, false);
151     }
152 
153     /**
154      * Method getInstance
155      *
156      * @param uri
157      * @param baseURI
158      * @param individualResolvers
159      * @param secureValidation
160      * @return the instance
161      *
162      * @throws ResourceResolverException
163      */
164     public static ResourceResolver getInstance(
165         Attr uri, String baseURI, List<ResourceResolver> individualResolvers, boolean secureValidation
166     ) throws ResourceResolverException {
167         if (log.isLoggable(java.util.logging.Level.FINE)) {
168             log.log(java.util.logging.Level.FINE,
169                 "I was asked to create a ResourceResolver and got "
170                 + (individualResolvers == null ? 0 : individualResolvers.size())
171             );
172         }
173 
174         ResourceResolverContext context = new ResourceResolverContext(uri, baseURI, secureValidation);
175 
176         // first check the individual Resolvers
177         if (individualResolvers != null) {
178             for (int i = 0; i < individualResolvers.size(); i++) {
179                 ResourceResolver resolver = individualResolvers.get(i);
180 
181                 if (resolver != null) {
182                     if (log.isLoggable(java.util.logging.Level.FINE)) {
183                         String currentClass = resolver.resolverSpi.getClass().getName();
184                         log.log(java.util.logging.Level.FINE, "check resolvability by class " + currentClass);
185                     }
186 
187                     if (resolver.canResolve(context)) {
188                         return resolver;
189                     }
190                 }
191             }
192         }
193 
194         return internalGetInstance(context);
195     }
196 
197     /**
198      * Registers a ResourceResolverSpi class. This method logs a warning if
199      * the class cannot be registered.
200      *
201      * @param className the name of the ResourceResolverSpi class to be registered
202      */
203     @SuppressWarnings("unchecked")
204     public static void register(String className) {
205         try {
206             Class<ResourceResolverSpi> resourceResolverClass =
207                 (Class<ResourceResolverSpi>) Class.forName(className);
208             register(resourceResolverClass, false);
209         } catch (ClassNotFoundException e) {
210             log.log(java.util.logging.Level.WARNING, "Error loading resolver " + className + " disabling it");
211         }
212     }
213 
214     /**
215      * Registers a ResourceResolverSpi class at the beginning of the provider
216      * list. This method logs a warning if the class cannot be registered.
217      *
218      * @param className the name of the ResourceResolverSpi class to be registered
219      */
220     @SuppressWarnings("unchecked")
221     public static void registerAtStart(String className) {
222         try {
223             Class<ResourceResolverSpi> resourceResolverClass =
224                 (Class<ResourceResolverSpi>) Class.forName(className);
225             register(resourceResolverClass, true);
226         } catch (ClassNotFoundException e) {
227             log.log(java.util.logging.Level.WARNING, "Error loading resolver " + className + " disabling it");
228         }
229     }
230 
231     /**
232      * Registers a ResourceResolverSpi class. This method logs a warning if the class
233      * cannot be registered.
234      * @param className
235      * @param start
236      */
237     public static void register(Class<? extends ResourceResolverSpi> className, boolean start) {
238         try {
239             ResourceResolverSpi resourceResolverSpi = className.newInstance();
240             register(resourceResolverSpi, start);
241         } catch (IllegalAccessException e) {
242             log.log(java.util.logging.Level.WARNING, "Error loading resolver " + className + " disabling it");
243         } catch (InstantiationException e) {
244             log.log(java.util.logging.Level.WARNING, "Error loading resolver " + className + " disabling it");
245         }
246     }
247 
248     /**
249      * Registers a ResourceResolverSpi instance. This method logs a warning if the class
250      * cannot be registered.
251      * @param resourceResolverSpi
252      * @param start
253      */
254     public static void register(ResourceResolverSpi resourceResolverSpi, boolean start) {
255         synchronized(resolverList) {
256             if (start) {
257                 resolverList.add(0, new ResourceResolver(resourceResolverSpi));
258             } else {
259                 resolverList.add(new ResourceResolver(resourceResolverSpi));
260             }
261         }
262         if (log.isLoggable(java.util.logging.Level.FINE)) {
263             log.log(java.util.logging.Level.FINE, "Registered resolver: " + resourceResolverSpi.toString());
264         }
265     }
266 
267     /**
268      * This method registers the default resolvers.
269      */
270     public static void registerDefaultResolvers() {
271         synchronized(resolverList) {
272             resolverList.add(new ResourceResolver(new ResolverFragment()));
273             resolverList.add(new ResourceResolver(new ResolverLocalFilesystem()));
274             resolverList.add(new ResourceResolver(new ResolverXPointer()));
275             resolverList.add(new ResourceResolver(new ResolverDirectHTTP()));
276         }
277     }
278 
279     /**
280      * @deprecated New clients should use {@link #resolve(Attr, String, boolean)}
281      */
282     @Deprecated
283     public XMLSignatureInput resolve(Attr uri, String baseURI)
284         throws ResourceResolverException {
285         return resolve(uri, baseURI, true);
286     }
287 
288     /**
289      * Method resolve
290      *
291      * @param uri
292      * @param baseURI
293      * @return the resource
294      *
295      * @throws ResourceResolverException
296      */
297     public XMLSignatureInput resolve(Attr uri, String baseURI, boolean secureValidation)
298         throws ResourceResolverException {
299         ResourceResolverContext context = new ResourceResolverContext(uri, baseURI, secureValidation);
300         return resolverSpi.engineResolveURI(context);
301     }
302 
303     /**
304      * Method setProperty
305      *
306      * @param key
307      * @param value
308      */
309     public void setProperty(String key, String value) {
310         resolverSpi.engineSetProperty(key, value);
311     }
312 
313     /**
314      * Method getProperty
315      *
316      * @param key
317      * @return the value of the property
318      */
319     public String getProperty(String key) {
320         return resolverSpi.engineGetProperty(key);
321     }
322 
323     /**
324      * Method addProperties
325      *
326      * @param properties
327      */
328     public void addProperties(Map<String, String> properties) {
329         resolverSpi.engineAddProperies(properties);
330     }
331 
332     /**
333      * Method getPropertyKeys
334      *
335      * @return all property keys.
336      */
337     public String[] getPropertyKeys() {
338         return resolverSpi.engineGetPropertyKeys();
339     }
340 
341     /**
342      * Method understandsProperty
343      *
344      * @param propertyToTest
345      * @return true if the resolver understands the property
346      */
347     public boolean understandsProperty(String propertyToTest) {
348         return resolverSpi.understandsProperty(propertyToTest);
349     }
350 
351     /**
352      * Method canResolve
353      *
354      * @param uri
355      * @param baseURI
356      * @return true if it can resolve the uri
357      */
358     private boolean canResolve(ResourceResolverContext context) {
359         return this.resolverSpi.engineCanResolveURI(context);
360     }
361 }