blob: f3de97b2f8d41d243c8ddc73a76f17121ed8b29e [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.xml.security.utils.resolver;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.xml.security.signature.XMLSignatureInput;
import org.apache.xml.security.utils.ClassLoaderUtils;
import org.apache.xml.security.utils.JavaUtils;
import org.apache.xml.security.utils.resolver.implementations.ResolverDirectHTTP;
import org.apache.xml.security.utils.resolver.implementations.ResolverFragment;
import org.apache.xml.security.utils.resolver.implementations.ResolverLocalFilesystem;
import org.apache.xml.security.utils.resolver.implementations.ResolverXPointer;
/**
* During reference validation, we have to retrieve resources from somewhere.
* This is done by retrieving a Resolver. The resolver needs two arguments: The
* URI in which the link to the new resource is defined and the baseURI of the
* file/entity in which the URI occurs (the baseURI is the same as the SystemId).
*/
public class ResourceResolver {
private static final org.slf4j.Logger LOG =
org.slf4j.LoggerFactory.getLogger(ResourceResolver.class);
/** these are the system-wide resolvers */
private static final List<ResourceResolverSpi> resolverList = new CopyOnWriteArrayList<>();
private static final AtomicBoolean defaultResolversAdded = new AtomicBoolean();
/**
* Registers a ResourceResolverSpi class.
*
* @param className the name of the ResourceResolverSpi class to be registered
* @throws InstantiationException
* @throws IllegalAccessException
* @throws ClassNotFoundException
* @throws SecurityException if a security manager is installed and the
* caller does not have permission to register a resource resolver
*/
@SuppressWarnings("unchecked")
public static void register(String className) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
JavaUtils.checkRegisterPermission();
Class<ResourceResolverSpi> resourceResolverClass =
(Class<ResourceResolverSpi>)
ClassLoaderUtils.loadClass(className, ResourceResolver.class);
register(resourceResolverClass.newInstance(), false);
}
/**
* Registers a ResourceResolverSpi class at the beginning of the provider list.
*
* @param className the name of the ResourceResolverSpi class to be registered
* @throws InstantiationException
* @throws IllegalAccessException
* @throws ClassNotFoundException
* @throws SecurityException if a security manager is installed and the
* caller does not have permission to register a resource resolver
*/
@SuppressWarnings("unchecked")
public static void registerAtStart(String className) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
JavaUtils.checkRegisterPermission();
Class<ResourceResolverSpi> resourceResolverClass =
(Class<ResourceResolverSpi>)
ClassLoaderUtils.loadClass(className, ResourceResolver.class);
register(resourceResolverClass.newInstance(), true);
}
/**
* Registers a ResourceResolverSpi instance.
* @param resourceResolverSpi
* @param start
* @throws SecurityException if a security manager is installed and the
* caller does not have permission to register a resource resolver
*/
public static void register(ResourceResolverSpi resourceResolverSpi, boolean start) {
JavaUtils.checkRegisterPermission();
if (start) {
resolverList.add(0, resourceResolverSpi);
} else {
resolverList.add(resourceResolverSpi);
}
LOG.debug("Registered resolver: {}", resourceResolverSpi.toString());
}
/**
* Registers a list of ResourceResolverSpi classes.
*
* @param classNames
* @throws InstantiationException
* @throws IllegalAccessException
* @throws ClassNotFoundException
* @throws SecurityException if a security manager is installed and the
* caller does not have permission to register the key resolver
*/
public static void registerClassNames(List<String> classNames)
throws ClassNotFoundException, IllegalAccessException, InstantiationException {
JavaUtils.checkRegisterPermission();
List<ResourceResolverSpi> resourceResolversToAdd = new ArrayList<>(classNames.size());
for (String className : classNames) {
ResourceResolverSpi resourceResolverSpi =
(ResourceResolverSpi)ClassLoaderUtils.loadClass(className, ResourceResolver.class).newInstance();
resourceResolversToAdd.add(resourceResolverSpi);
}
resolverList.addAll(resourceResolversToAdd);
}
/**
* This method registers the default resolvers.
*/
public static void registerDefaultResolvers() {
// Add a guard so that we don't repeatedly add the default resolvers
if (defaultResolversAdded.compareAndSet(false, true)) {
List<ResourceResolverSpi> resourceResolversToAdd = new ArrayList<>();
resourceResolversToAdd.add(new ResolverFragment());
resourceResolversToAdd.add(new ResolverLocalFilesystem());
resourceResolversToAdd.add(new ResolverXPointer());
resourceResolversToAdd.add(new ResolverDirectHTTP());
resolverList.addAll(resourceResolversToAdd);
}
}
/**
* Method resolve
*
* @param context
* @return the resource
*
* @throws ResourceResolverException
*/
public static XMLSignatureInput resolve(ResourceResolverContext context)
throws ResourceResolverException {
for (ResourceResolverSpi resolver : resolverList) {
LOG.debug("check resolvability by class {}", resolver.getClass().getName());
if (resolver.engineCanResolveURI(context)) {
// Check to see whether the Resolver is allowed
if (context.secureValidation
&& (resolver instanceof ResolverLocalFilesystem
|| resolver instanceof ResolverDirectHTTP)) {
Object[] exArgs = { resolver.getClass().getName() };
throw new ResourceResolverException(
"signature.Reference.ForbiddenResolver", exArgs, context.uriToResolve, context.baseUri
);
}
return resolver.engineResolveURI(context);
}
}
Object[] exArgs = { context.uriToResolve != null
? context.uriToResolve : "null", context.baseUri };
throw new ResourceResolverException("utils.resolver.noClass", exArgs, context.uriToResolve, context.baseUri);
}
/**
* Method resolve
*
* @param individualResolvers
* @param context
* @return the resource
*
* @throws ResourceResolverException
*/
public static XMLSignatureInput resolve(
List<ResourceResolverSpi> individualResolvers, ResourceResolverContext context
) throws ResourceResolverException {
LOG.debug(
"I was asked to create a ResourceResolver and got {}",
individualResolvers == null ? 0 : individualResolvers.size()
);
// first check the individual Resolvers
if (individualResolvers != null) {
for (ResourceResolverSpi resolver : individualResolvers) {
String currentClass = resolver.getClass().getName();
LOG.debug("check resolvability by class {}", currentClass);
if (resolver.engineCanResolveURI(context)) {
return resolver.engineResolveURI(context);
}
}
}
return resolve(context);
}
}