| /** |
| * 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); |
| } |
| } |