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                         resolverTmp =
 103                             new ResourceResolver(resolver.resolverSpi.getClass().newInstance());
 104                     } catch (InstantiationException e) {
 105                         throw new ResourceResolverException("", e, context.attr, context.baseUri);
 106                     } catch (IllegalAccessException e) {
 107                         throw new ResourceResolverException("", e, context.attr, context.baseUri);
 108                     }
 109                 }
 110 
 111                 if (log.isLoggable(java.util.logging.Level.FINE)) {
 112                     log.log(java.util.logging.Level.FINE,
 113                         "check resolvability by class " + resolverTmp.getClass().getName()
 114                     );
 115                 }
 116 
 117                 if ((resolverTmp != null) && resolverTmp.canResolve(context)) {
 118                     // Check to see whether the Resolver is allowed
 119                     if (context.secureValidation
 120                         && (resolverTmp.resolverSpi instanceof ResolverLocalFilesystem
 121                             || resolverTmp.resolverSpi instanceof ResolverDirectHTTP)) {
 122                         Object exArgs[] = { resolverTmp.resolverSpi.getClass().getName() };
 123                         throw new ResourceResolverException(
 124                             "signature.Reference.ForbiddenResolver", exArgs, context.attr, context.baseUri
 125                         );
 126                     }
 127                     return resolverTmp;
 128                 }
 129             }
 130         }
 131 
 132         Object exArgs[] = { ((context.uriToResolve != null)
 133                 ? context.uriToResolve : "null"), context.baseUri };
 134 
 135         throw new ResourceResolverException("utils.resolver.noClass", exArgs, context.attr, context.baseUri);
 136     }
 137 
 138     /**
 139      * Method getInstance
 140      *
 141      * @param uri
 142      * @param baseURI
 143      * @param individualResolvers
 144      * @return the instance
 145      *
 146      * @throws ResourceResolverException
 147      */
 148     public static ResourceResolver getInstance(
 149         Attr uri, String baseURI, List<ResourceResolver> individualResolvers
 150     ) throws ResourceResolverException {
 151         return getInstance(uri, baseURI, individualResolvers, false);
 152     }
 153 
 154     /**
 155      * Method getInstance
 156      *
 157      * @param uri
 158      * @param baseURI
 159      * @param individualResolvers
 160      * @param secureValidation
 161      * @return the instance
 162      *
 163      * @throws ResourceResolverException
 164      */
 165     public static ResourceResolver getInstance(
 166         Attr uri, String baseURI, List<ResourceResolver> individualResolvers, boolean secureValidation
 167     ) throws ResourceResolverException {
 168         if (log.isLoggable(java.util.logging.Level.FINE)) {
 169             log.log(java.util.logging.Level.FINE,
 170                 "I was asked to create a ResourceResolver and got "
 171                 + (individualResolvers == null ? 0 : individualResolvers.size())
 172             );
 173         }
 174 
 175         ResourceResolverContext context = new ResourceResolverContext(uri, baseURI, secureValidation);
 176 
 177         // first check the individual Resolvers
 178         if (individualResolvers != null) {
 179             for (int i = 0; i < individualResolvers.size(); i++) {
 180                 ResourceResolver resolver = individualResolvers.get(i);
 181 
 182                 if (resolver != null) {
 183                     if (log.isLoggable(java.util.logging.Level.FINE)) {
 184                         String currentClass = resolver.resolverSpi.getClass().getName();
 185                         log.log(java.util.logging.Level.FINE, "check resolvability by class " + currentClass);
 186                     }
 187 
 188                     if (resolver.canResolve(context)) {
 189                         return resolver;
 190                     }
 191                 }
 192             }
 193         }
 194 
 195         return internalGetInstance(context);
 196     }
 197 
 198     /**
 199      * Registers a ResourceResolverSpi class. This method logs a warning if
 200      * the class cannot be registered.
 201      *
 202      * @param className the name of the ResourceResolverSpi class to be registered
 203      * @throws SecurityException if a security manager is installed and the
 204      *    caller does not have permission to register a resource resolver
 205      */
 206     @SuppressWarnings("unchecked")
 207     public static void register(String className) {
 208         JavaUtils.checkRegisterPermission();
 209         try {
 210             Class<ResourceResolverSpi> resourceResolverClass =
 211                 (Class<ResourceResolverSpi>) Class.forName(className);
 212             register(resourceResolverClass, false);
 213         } catch (ClassNotFoundException e) {
 214             log.log(java.util.logging.Level.WARNING, "Error loading resolver " + className + " disabling it");
 215         }
 216     }
 217 
 218     /**
 219      * Registers a ResourceResolverSpi class at the beginning of the provider
 220      * list. This method logs a warning if the class cannot be registered.
 221      *
 222      * @param className the name of the ResourceResolverSpi class to be registered
 223      * @throws SecurityException if a security manager is installed and the
 224      *    caller does not have permission to register a resource resolver
 225      */
 226     @SuppressWarnings("unchecked")
 227     public static void registerAtStart(String className) {
 228         JavaUtils.checkRegisterPermission();
 229         try {
 230             Class<ResourceResolverSpi> resourceResolverClass =
 231                 (Class<ResourceResolverSpi>) Class.forName(className);
 232             register(resourceResolverClass, true);
 233         } catch (ClassNotFoundException e) {
 234             log.log(java.util.logging.Level.WARNING, "Error loading resolver " + className + " disabling it");
 235         }
 236     }
 237 
 238     /**
 239      * Registers a ResourceResolverSpi class. This method logs a warning if the class
 240      * cannot be registered.
 241      * @param className
 242      * @param start
 243      * @throws SecurityException if a security manager is installed and the
 244      *    caller does not have permission to register a resource resolver
 245      */
 246     public static void register(Class<? extends ResourceResolverSpi> className, boolean start) {
 247         JavaUtils.checkRegisterPermission();
 248         try {
 249             ResourceResolverSpi resourceResolverSpi = className.newInstance();
 250             register(resourceResolverSpi, start);
 251         } catch (IllegalAccessException e) {
 252             log.log(java.util.logging.Level.WARNING, "Error loading resolver " + className + " disabling it");
 253         } catch (InstantiationException e) {
 254             log.log(java.util.logging.Level.WARNING, "Error loading resolver " + className + " disabling it");
 255         }
 256     }
 257 
 258     /**
 259      * Registers a ResourceResolverSpi instance. This method logs a warning if the class
 260      * cannot be registered.
 261      * @param resourceResolverSpi
 262      * @param start
 263      * @throws SecurityException if a security manager is installed and the
 264      *    caller does not have permission to register a resource resolver
 265      */
 266     public static void register(ResourceResolverSpi resourceResolverSpi, boolean start) {
 267         JavaUtils.checkRegisterPermission();
 268         synchronized(resolverList) {
 269             if (start) {
 270                 resolverList.add(0, new ResourceResolver(resourceResolverSpi));
 271             } else {
 272                 resolverList.add(new ResourceResolver(resourceResolverSpi));
 273             }
 274         }
 275         if (log.isLoggable(java.util.logging.Level.FINE)) {
 276             log.log(java.util.logging.Level.FINE, "Registered resolver: " + resourceResolverSpi.toString());
 277         }
 278     }
 279 
 280     /**
 281      * This method registers the default resolvers.
 282      */
 283     public static void registerDefaultResolvers() {
 284         synchronized(resolverList) {
 285             resolverList.add(new ResourceResolver(new ResolverFragment()));
 286             resolverList.add(new ResourceResolver(new ResolverLocalFilesystem()));
 287             resolverList.add(new ResourceResolver(new ResolverXPointer()));
 288             resolverList.add(new ResourceResolver(new ResolverDirectHTTP()));
 289         }
 290     }
 291 
 292     /**
 293      * @deprecated New clients should use {@link #resolve(Attr, String, boolean)}
 294      */
 295     @Deprecated
 296     public XMLSignatureInput resolve(Attr uri, String baseURI)
 297         throws ResourceResolverException {
 298         return resolve(uri, baseURI, true);
 299     }
 300 
 301     /**
 302      * Method resolve
 303      *
 304      * @param uri
 305      * @param baseURI
 306      * @return the resource
 307      *
 308      * @throws ResourceResolverException
 309      */
 310     public XMLSignatureInput resolve(Attr uri, String baseURI, boolean secureValidation)
 311         throws ResourceResolverException {
 312         ResourceResolverContext context = new ResourceResolverContext(uri, baseURI, secureValidation);
 313         return resolverSpi.engineResolveURI(context);
 314     }
 315 
 316     /**
 317      * Method setProperty
 318      *
 319      * @param key
 320      * @param value
 321      */
 322     public void setProperty(String key, String value) {
 323         resolverSpi.engineSetProperty(key, value);
 324     }
 325 
 326     /**
 327      * Method getProperty
 328      *
 329      * @param key
 330      * @return the value of the property
 331      */
 332     public String getProperty(String key) {
 333         return resolverSpi.engineGetProperty(key);
 334     }
 335 
 336     /**
 337      * Method addProperties
 338      *
 339      * @param properties
 340      */
 341     public void addProperties(Map<String, String> properties) {
 342         resolverSpi.engineAddProperies(properties);
 343     }
 344 
 345     /**
 346      * Method getPropertyKeys
 347      *
 348      * @return all property keys.
 349      */
 350     public String[] getPropertyKeys() {
 351         return resolverSpi.engineGetPropertyKeys();
 352     }
 353 
 354     /**
 355      * Method understandsProperty
 356      *
 357      * @param propertyToTest
 358      * @return true if the resolver understands the property
 359      */
 360     public boolean understandsProperty(String propertyToTest) {
 361         return resolverSpi.understandsProperty(propertyToTest);
 362     }
 363 
 364     /**
 365      * Method canResolve
 366      *
 367      * @param uri
 368      * @param baseURI
 369      * @return true if it can resolve the uri
 370      */
 371     private boolean canResolve(ResourceResolverContext context) {
 372         return this.resolverSpi.engineCanResolveURI(context);
 373     }
 374 }