blob: 82541e5faf88ef68343a00fb92e08f625ebd30d5 [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.keys.keyresolver;
import java.security.PublicKey;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import javax.crypto.SecretKey;
import org.apache.xml.security.keys.keyresolver.implementations.DEREncodedKeyValueResolver;
import org.apache.xml.security.keys.keyresolver.implementations.DSAKeyValueResolver;
import org.apache.xml.security.keys.keyresolver.implementations.ECKeyValueResolver;
import org.apache.xml.security.keys.keyresolver.implementations.KeyInfoReferenceResolver;
import org.apache.xml.security.keys.keyresolver.implementations.RSAKeyValueResolver;
import org.apache.xml.security.keys.keyresolver.implementations.RetrievalMethodResolver;
import org.apache.xml.security.keys.keyresolver.implementations.X509CertificateResolver;
import org.apache.xml.security.keys.keyresolver.implementations.X509DigestResolver;
import org.apache.xml.security.keys.keyresolver.implementations.X509IssuerSerialResolver;
import org.apache.xml.security.keys.keyresolver.implementations.X509SKIResolver;
import org.apache.xml.security.keys.keyresolver.implementations.X509SubjectNameResolver;
import org.apache.xml.security.keys.storage.StorageResolver;
import org.apache.xml.security.utils.ClassLoaderUtils;
import org.apache.xml.security.utils.JavaUtils;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
/**
* KeyResolver is factory class for subclass of KeyResolverSpi that
* represent child element of KeyInfo.
*/
public class KeyResolver {
private static final org.slf4j.Logger LOG =
org.slf4j.LoggerFactory.getLogger(KeyResolver.class);
/** Field resolverVector */
private static List<KeyResolver> resolverVector = new CopyOnWriteArrayList<>();
/** Field resolverSpi */
private final KeyResolverSpi resolverSpi;
/**
* Constructor.
*
* @param keyResolverSpi a KeyResolverSpi instance
*/
private KeyResolver(KeyResolverSpi keyResolverSpi) {
resolverSpi = keyResolverSpi;
}
/**
* Method length
*
* @return the length of resolvers registered
*/
public static int length() {
return resolverVector.size();
}
/**
* Method getX509Certificate
*
* @param element
* @param baseURI
* @param storage
* @return The certificate represented by the element.
*
* @throws KeyResolverException
*/
public static final X509Certificate getX509Certificate(
Element element, String baseURI, StorageResolver storage
) throws KeyResolverException {
for (KeyResolver resolver : resolverVector) {
if (resolver == null) {
Object[] exArgs = {
element != null
&& element.getNodeType() == Node.ELEMENT_NODE
? element.getTagName() : "null"
};
throw new KeyResolverException("utils.resolver.noClass", exArgs);
}
LOG.debug("check resolvability by class {}", resolver.getClass());
X509Certificate cert = resolver.resolveX509Certificate(element, baseURI, storage);
if (cert != null) {
return cert;
}
}
Object[] exArgs = {
element != null && element.getNodeType() == Node.ELEMENT_NODE
? element.getTagName() : "null"
};
throw new KeyResolverException("utils.resolver.noClass", exArgs);
}
/**
* Method getPublicKey
*
* @param element
* @param baseURI
* @param storage
* @return the public key contained in the element
*
* @throws KeyResolverException
*/
public static final PublicKey getPublicKey(
Element element, String baseURI, StorageResolver storage
) throws KeyResolverException {
for (KeyResolver resolver : resolverVector) {
if (resolver == null) {
Object[] exArgs = {
element != null
&& element.getNodeType() == Node.ELEMENT_NODE
? element.getTagName() : "null"
};
throw new KeyResolverException("utils.resolver.noClass", exArgs);
}
LOG.debug("check resolvability by class {}", resolver.getClass());
PublicKey cert = resolver.resolvePublicKey(element, baseURI, storage);
if (cert != null) {
return cert;
}
}
Object[] exArgs = {
element != null && element.getNodeType() == Node.ELEMENT_NODE
? element.getTagName() : "null"
};
throw new KeyResolverException("utils.resolver.noClass", exArgs);
}
/**
* This method is used for registering {@link KeyResolverSpi}s which are
* available to <I>all</I> {@link org.apache.xml.security.keys.KeyInfo} objects. This means that
* personalized {@link KeyResolverSpi}s should only be registered directly
* to the {@link org.apache.xml.security.keys.KeyInfo} using
* {@link org.apache.xml.security.keys.KeyInfo#registerInternalKeyResolver}.
* Please note that this method will create a new copy of the underlying array, as the
* underlying collection is a CopyOnWriteArrayList.
*
* @param className
* @param globalResolver Whether the KeyResolverSpi is a global resolver or not
* @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 register(String className, boolean globalResolver)
throws ClassNotFoundException, IllegalAccessException, InstantiationException {
JavaUtils.checkRegisterPermission();
KeyResolverSpi keyResolverSpi =
(KeyResolverSpi) ClassLoaderUtils.loadClass(className, KeyResolver.class).newInstance();
keyResolverSpi.setGlobalResolver(globalResolver);
register(keyResolverSpi, false);
}
/**
* This method is used for registering {@link KeyResolverSpi}s which are
* available to <I>all</I> {@link org.apache.xml.security.keys.KeyInfo} objects. This means that
* personalized {@link KeyResolverSpi}s should only be registered directly
* to the {@link org.apache.xml.security.keys.KeyInfo} using
* {@link org.apache.xml.security.keys.KeyInfo#registerInternalKeyResolver}.
* Please note that this method will create a new copy of the underlying array, as the
* underlying collection is a CopyOnWriteArrayList.
*
* @param className
* @param globalResolver Whether the KeyResolverSpi is a global resolver or not
* @throws SecurityException if a security manager is installed and the
* caller does not have permission to register the key resolver
*/
public static void registerAtStart(String className, boolean globalResolver) {
JavaUtils.checkRegisterPermission();
KeyResolverSpi keyResolverSpi = null;
Exception ex = null;
try {
keyResolverSpi = (KeyResolverSpi) ClassLoaderUtils.loadClass(className, KeyResolver.class).newInstance();
keyResolverSpi.setGlobalResolver(globalResolver);
register(keyResolverSpi, true);
} catch (ClassNotFoundException e) {
ex = e;
} catch (IllegalAccessException e) {
ex = e;
} catch (InstantiationException e) {
ex = e;
}
if (ex != null) {
throw (IllegalArgumentException) new
IllegalArgumentException("Invalid KeyResolver class name").initCause(ex);
}
}
/**
* This method is used for registering {@link KeyResolverSpi}s which are
* available to <I>all</I> {@link org.apache.xml.security.keys.KeyInfo} objects. This means that
* personalized {@link KeyResolverSpi}s should only be registered directly
* to the {@link org.apache.xml.security.keys.KeyInfo} using
* {@link org.apache.xml.security.keys.KeyInfo#registerInternalKeyResolver}.
* Please note that this method will create a new copy of the underlying array, as the
* underlying collection is a CopyOnWriteArrayList.
*
* @param keyResolverSpi a KeyResolverSpi instance to register
* @param start whether to register the KeyResolverSpi at the start of the list or not
* @throws SecurityException if a security manager is installed and the
* caller does not have permission to register the key resolver
*/
public static void register(
KeyResolverSpi keyResolverSpi,
boolean start
) {
JavaUtils.checkRegisterPermission();
KeyResolver resolver = new KeyResolver(keyResolverSpi);
if (start) {
resolverVector.add(0, resolver);
} else {
resolverVector.add(resolver);
}
}
/**
* This method is used for registering {@link KeyResolverSpi}s which are
* available to <I>all</I> {@link org.apache.xml.security.keys.KeyInfo} objects. This means that
* personalized {@link KeyResolverSpi}s should only be registered directly
* to the {@link org.apache.xml.security.keys.KeyInfo} using
* {@link org.apache.xml.security.keys.KeyInfo#registerInternalKeyResolver}.
* The KeyResolverSpi instances are not registered as a global resolver.
*
*
* @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<KeyResolver> keyResolverList = new ArrayList<>(classNames.size());
for (String className : classNames) {
KeyResolverSpi keyResolverSpi =
(KeyResolverSpi)ClassLoaderUtils.loadClass(className, KeyResolver.class).newInstance();
keyResolverSpi.setGlobalResolver(false);
keyResolverList.add(new KeyResolver(keyResolverSpi));
}
resolverVector.addAll(keyResolverList);
}
/**
* This method registers the default resolvers.
*/
public static void registerDefaultResolvers() {
List<KeyResolver> keyResolverList = new ArrayList<>();
keyResolverList.add(new KeyResolver(new RSAKeyValueResolver()));
keyResolverList.add(new KeyResolver(new DSAKeyValueResolver()));
keyResolverList.add(new KeyResolver(new X509CertificateResolver()));
keyResolverList.add(new KeyResolver(new X509SKIResolver()));
keyResolverList.add(new KeyResolver(new RetrievalMethodResolver()));
keyResolverList.add(new KeyResolver(new X509SubjectNameResolver()));
keyResolverList.add(new KeyResolver(new X509IssuerSerialResolver()));
keyResolverList.add(new KeyResolver(new DEREncodedKeyValueResolver()));
keyResolverList.add(new KeyResolver(new KeyInfoReferenceResolver()));
keyResolverList.add(new KeyResolver(new X509DigestResolver()));
keyResolverList.add(new KeyResolver(new ECKeyValueResolver()));
resolverVector.addAll(keyResolverList);
}
/**
* Method resolvePublicKey
*
* @param element
* @param baseURI
* @param storage
* @return resolved public key from the registered from the elements
*
* @throws KeyResolverException
*/
public PublicKey resolvePublicKey(
Element element, String baseURI, StorageResolver storage
) throws KeyResolverException {
return resolverSpi.engineLookupAndResolvePublicKey(element, baseURI, storage);
}
/**
* Method resolveX509Certificate
*
* @param element
* @param baseURI
* @param storage
* @return resolved X509certificate key from the registered from the elements
*
* @throws KeyResolverException
*/
public X509Certificate resolveX509Certificate(
Element element, String baseURI, StorageResolver storage
) throws KeyResolverException {
return resolverSpi.engineLookupResolveX509Certificate(element, baseURI, storage);
}
/**
* @param element
* @param baseURI
* @param storage
* @return resolved SecretKey key from the registered from the elements
* @throws KeyResolverException
*/
public SecretKey resolveSecretKey(
Element element, String baseURI, StorageResolver storage
) throws KeyResolverException {
return resolverSpi.engineLookupAndResolveSecretKey(element, baseURI, storage);
}
/**
* Method setProperty
*
* @param key
* @param value
*/
public void setProperty(String key, String value) {
resolverSpi.engineSetProperty(key, value);
}
/**
* Method getProperty
*
* @param key
* @return the property set for this resolver
*/
public String getProperty(String key) {
return resolverSpi.engineGetProperty(key);
}
/**
* Method understandsProperty
*
* @param propertyToTest
* @return true if the resolver understands property propertyToTest
*/
public boolean understandsProperty(String propertyToTest) {
return resolverSpi.understandsProperty(propertyToTest);
}
/**
* Method resolverClassName
*
* @return the name of the resolver.
*/
public String resolverClassName() {
return resolverSpi.getClass().getName();
}
/**
* Iterate over the KeyResolverSpi instances
*/
static class ResolverIterator implements Iterator<KeyResolverSpi> {
List<KeyResolver> res;
Iterator<KeyResolver> it;
public ResolverIterator(List<KeyResolver> list) {
res = list;
it = res.iterator();
}
public boolean hasNext() {
return it.hasNext();
}
public KeyResolverSpi next() {
KeyResolver resolver = it.next();
if (resolver == null) {
throw new RuntimeException("utils.resolver.noClass");
}
return resolver.resolverSpi;
}
public void remove() {
throw new UnsupportedOperationException("Can't remove resolvers using the iterator");
}
}
public static Iterator<KeyResolverSpi> iterator() {
return new ResolverIterator(resolverVector);
}
}