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