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 }