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.keys.keyresolver;
  24 
  25 import java.security.PublicKey;
  26 import java.security.cert.X509Certificate;
  27 import java.util.ArrayList;
  28 import java.util.Iterator;
  29 import java.util.List;
  30 import java.util.concurrent.CopyOnWriteArrayList;
  31 
  32 import javax.crypto.SecretKey;
  33 
  34 import com.sun.org.apache.xml.internal.security.keys.keyresolver.implementations.DEREncodedKeyValueResolver;
  35 import com.sun.org.apache.xml.internal.security.keys.keyresolver.implementations.DSAKeyValueResolver;
  36 import com.sun.org.apache.xml.internal.security.keys.keyresolver.implementations.KeyInfoReferenceResolver;
  37 import com.sun.org.apache.xml.internal.security.keys.keyresolver.implementations.RSAKeyValueResolver;
  38 import com.sun.org.apache.xml.internal.security.keys.keyresolver.implementations.RetrievalMethodResolver;
  39 import com.sun.org.apache.xml.internal.security.keys.keyresolver.implementations.X509CertificateResolver;
  40 import com.sun.org.apache.xml.internal.security.keys.keyresolver.implementations.X509DigestResolver;
  41 import com.sun.org.apache.xml.internal.security.keys.keyresolver.implementations.X509IssuerSerialResolver;
  42 import com.sun.org.apache.xml.internal.security.keys.keyresolver.implementations.X509SKIResolver;
  43 import com.sun.org.apache.xml.internal.security.keys.keyresolver.implementations.X509SubjectNameResolver;
  44 import com.sun.org.apache.xml.internal.security.keys.storage.StorageResolver;
  45 import org.w3c.dom.Element;
  46 import org.w3c.dom.Node;
  47 
  48 /**
  49  * KeyResolver is factory class for subclass of KeyResolverSpi that
  50  * represent child element of KeyInfo.
  51  */
  52 public class KeyResolver {
  53 
  54     /** {@link org.apache.commons.logging} logging facility */
  55     private static java.util.logging.Logger log = 
  56         java.util.logging.Logger.getLogger(KeyResolver.class.getName());
  57 
  58     /** Field resolverVector */
  59     private static List<KeyResolver> resolverVector = new CopyOnWriteArrayList<KeyResolver>();
  60 
  61     /** Field resolverSpi */
  62     private final KeyResolverSpi resolverSpi;
  63     
  64     /**
  65      * Constructor.
  66      * 
  67      * @param keyResolverSpi a KeyResolverSpi instance
  68      */
  69     private KeyResolver(KeyResolverSpi keyResolverSpi) {
  70         resolverSpi = keyResolverSpi;
  71     }
  72 
  73     /**
  74      * Method length
  75      *
  76      * @return the length of resolvers registered
  77      */
  78     public static int length() {
  79         return resolverVector.size();
  80     }
  81 
  82     /**
  83      * Method getX509Certificate
  84      *
  85      * @param element
  86      * @param baseURI
  87      * @param storage
  88      * @return The certificate represented by the element.
  89      * 
  90      * @throws KeyResolverException
  91      */
  92     public static final X509Certificate getX509Certificate(
  93         Element element, String baseURI, StorageResolver storage
  94     ) throws KeyResolverException {
  95         for (KeyResolver resolver : resolverVector) {
  96             if (resolver == null) {
  97                 Object exArgs[] = {
  98                                    (((element != null)
  99                                        && (element.getNodeType() == Node.ELEMENT_NODE))
 100                                        ? element.getTagName() : "null") 
 101                 };
 102 
 103                 throw new KeyResolverException("utils.resolver.noClass", exArgs);
 104             }
 105             if (log.isLoggable(java.util.logging.Level.FINE)) {
 106                 log.log(java.util.logging.Level.FINE, "check resolvability by class " + resolver.getClass());
 107             }
 108 
 109             X509Certificate cert = resolver.resolveX509Certificate(element, baseURI, storage);
 110             if (cert != null) {
 111                 return cert;
 112             }
 113         }
 114 
 115         Object exArgs[] = {
 116                            (((element != null) && (element.getNodeType() == Node.ELEMENT_NODE))
 117                            ? element.getTagName() : "null") 
 118                           };
 119 
 120         throw new KeyResolverException("utils.resolver.noClass", exArgs);
 121     }
 122 
 123     /**
 124      * Method getPublicKey
 125      *
 126      * @param element
 127      * @param baseURI
 128      * @param storage
 129      * @return the public key contained in the element
 130      * 
 131      * @throws KeyResolverException
 132      */
 133     public static final PublicKey getPublicKey(
 134         Element element, String baseURI, StorageResolver storage
 135     ) throws KeyResolverException {
 136         for (KeyResolver resolver : resolverVector) {
 137             if (resolver == null) {
 138                 Object exArgs[] = {
 139                                    (((element != null)
 140                                        && (element.getNodeType() == Node.ELEMENT_NODE))
 141                                        ? element.getTagName() : "null")
 142                 };
 143 
 144                 throw new KeyResolverException("utils.resolver.noClass", exArgs);
 145             }
 146             if (log.isLoggable(java.util.logging.Level.FINE)) {
 147                 log.log(java.util.logging.Level.FINE, "check resolvability by class " + resolver.getClass());
 148             }
 149 
 150             PublicKey cert = resolver.resolvePublicKey(element, baseURI, storage);
 151             if (cert != null) {
 152                 return cert;
 153             }
 154         }
 155 
 156         Object exArgs[] = {
 157                            (((element != null) && (element.getNodeType() == Node.ELEMENT_NODE))
 158                            ? element.getTagName() : "null") 
 159                           };
 160 
 161         throw new KeyResolverException("utils.resolver.noClass", exArgs);
 162     }
 163 
 164     /**
 165      * This method is used for registering {@link KeyResolverSpi}s which are
 166      * available to <I>all</I> {@link com.sun.org.apache.xml.internal.security.keys.KeyInfo} objects. This means that
 167      * personalized {@link KeyResolverSpi}s should only be registered directly
 168      * to the {@link com.sun.org.apache.xml.internal.security.keys.KeyInfo} using 
 169      * {@link com.sun.org.apache.xml.internal.security.keys.KeyInfo#registerInternalKeyResolver}.
 170      * Please note that this method will create a new copy of the underlying array, as the 
 171      * underlying collection is a CopyOnWriteArrayList.
 172      *
 173      * @param className
 174      * @param globalResolver Whether the KeyResolverSpi is a global resolver or not
 175      * @throws InstantiationException 
 176      * @throws IllegalAccessException 
 177      * @throws ClassNotFoundException 
 178      */
 179     public static void register(String className, boolean globalResolver) 
 180         throws ClassNotFoundException, IllegalAccessException, InstantiationException {
 181         KeyResolverSpi keyResolverSpi =
 182             (KeyResolverSpi) Class.forName(className).newInstance();
 183         keyResolverSpi.setGlobalResolver(globalResolver);
 184         register(keyResolverSpi, false);
 185     }
 186 
 187     /**
 188      * This method is used for registering {@link KeyResolverSpi}s which are
 189      * available to <I>all</I> {@link com.sun.org.apache.xml.internal.security.keys.KeyInfo} objects. This means that
 190      * personalized {@link KeyResolverSpi}s should only be registered directly
 191      * to the {@link com.sun.org.apache.xml.internal.security.keys.KeyInfo} using 
 192      * {@link com.sun.org.apache.xml.internal.security.keys.KeyInfo#registerInternalKeyResolver}.
 193      * Please note that this method will create a new copy of the underlying array, as the 
 194      * underlying collection is a CopyOnWriteArrayList.
 195      *
 196      * @param className
 197      * @param globalResolver Whether the KeyResolverSpi is a global resolver or not
 198      */
 199     public static void registerAtStart(String className, boolean globalResolver) {
 200         KeyResolverSpi keyResolverSpi = null;
 201         Exception ex = null;
 202         try {
 203             keyResolverSpi = (KeyResolverSpi) Class.forName(className).newInstance();
 204         } catch (ClassNotFoundException e) {
 205             ex = e;
 206         } catch (IllegalAccessException e) {
 207             ex = e;
 208         } catch (InstantiationException e) {
 209             ex = e;
 210         }
 211 
 212         if (ex != null) {
 213             throw (IllegalArgumentException) new
 214             IllegalArgumentException("Invalid KeyResolver class name").initCause(ex);
 215         }
 216         keyResolverSpi.setGlobalResolver(globalResolver);
 217         register(keyResolverSpi, true);
 218     }
 219     
 220     /**
 221      * This method is used for registering {@link KeyResolverSpi}s which are
 222      * available to <I>all</I> {@link com.sun.org.apache.xml.internal.security.keys.KeyInfo} objects. This means that
 223      * personalized {@link KeyResolverSpi}s should only be registered directly
 224      * to the {@link com.sun.org.apache.xml.internal.security.keys.KeyInfo} using 
 225      * {@link com.sun.org.apache.xml.internal.security.keys.KeyInfo#registerInternalKeyResolver}.
 226      * Please note that this method will create a new copy of the underlying array, as the 
 227      * underlying collection is a CopyOnWriteArrayList.
 228      *
 229      * @param keyResolverSpi a KeyResolverSpi instance to register
 230      * @param start whether to register the KeyResolverSpi at the start of the list or not
 231      */
 232     public static void register(
 233         KeyResolverSpi keyResolverSpi, 
 234         boolean start
 235     ) {
 236         KeyResolver resolver = new KeyResolver(keyResolverSpi);
 237         if (start) {
 238             resolverVector.add(0, resolver);
 239         } else {
 240             resolverVector.add(resolver);
 241         }
 242     }
 243     
 244     /**
 245      * This method is used for registering {@link KeyResolverSpi}s which are
 246      * available to <I>all</I> {@link com.sun.org.apache.xml.internal.security.keys.KeyInfo} objects. This means that
 247      * personalized {@link KeyResolverSpi}s should only be registered directly
 248      * to the {@link com.sun.org.apache.xml.internal.security.keys.KeyInfo} using 
 249      * {@link com.sun.org.apache.xml.internal.security.keys.KeyInfo#registerInternalKeyResolver}.
 250      * The KeyResolverSpi instances are not registered as a global resolver.
 251      * 
 252      *
 253      * @param classNames
 254      * @throws InstantiationException 
 255      * @throws IllegalAccessException 
 256      * @throws ClassNotFoundException 
 257      */
 258     public static void registerClassNames(List<String> classNames) 
 259         throws ClassNotFoundException, IllegalAccessException, InstantiationException {
 260         List<KeyResolver> keyResolverList = new ArrayList<KeyResolver>(classNames.size());
 261         for (String className : classNames) {
 262             KeyResolverSpi keyResolverSpi =
 263                 (KeyResolverSpi) Class.forName(className).newInstance();
 264             keyResolverSpi.setGlobalResolver(false);
 265             keyResolverList.add(new KeyResolver(keyResolverSpi));
 266         }
 267         resolverVector.addAll(keyResolverList);
 268     }
 269     
 270     /**
 271      * This method registers the default resolvers.
 272      */
 273     public static void registerDefaultResolvers() {
 274         
 275         List<KeyResolver> keyResolverList = new ArrayList<KeyResolver>();
 276         keyResolverList.add(new KeyResolver(new RSAKeyValueResolver()));
 277         keyResolverList.add(new KeyResolver(new DSAKeyValueResolver()));
 278         keyResolverList.add(new KeyResolver(new X509CertificateResolver()));
 279         keyResolverList.add(new KeyResolver(new X509SKIResolver()));
 280         keyResolverList.add(new KeyResolver(new RetrievalMethodResolver()));
 281         keyResolverList.add(new KeyResolver(new X509SubjectNameResolver()));
 282         keyResolverList.add(new KeyResolver(new X509IssuerSerialResolver()));
 283         keyResolverList.add(new KeyResolver(new DEREncodedKeyValueResolver()));
 284         keyResolverList.add(new KeyResolver(new KeyInfoReferenceResolver()));
 285         keyResolverList.add(new KeyResolver(new X509DigestResolver()));
 286         
 287         resolverVector.addAll(keyResolverList);
 288     }
 289 
 290     /**
 291      * Method resolvePublicKey
 292      *
 293      * @param element
 294      * @param baseURI
 295      * @param storage 
 296      * @return resolved public key from the registered from the elements
 297      * 
 298      * @throws KeyResolverException
 299      */
 300     public PublicKey resolvePublicKey(
 301         Element element, String baseURI, StorageResolver storage
 302     ) throws KeyResolverException {
 303         return resolverSpi.engineLookupAndResolvePublicKey(element, baseURI, storage);
 304     }
 305 
 306     /**
 307      * Method resolveX509Certificate
 308      *
 309      * @param element
 310      * @param baseURI
 311      * @param storage
 312      * @return resolved X509certificate key from the registered from the elements
 313      * 
 314      * @throws KeyResolverException
 315      */
 316     public X509Certificate resolveX509Certificate(
 317         Element element, String baseURI, StorageResolver storage
 318     ) throws KeyResolverException {
 319         return resolverSpi.engineLookupResolveX509Certificate(element, baseURI, storage);
 320     }
 321 
 322     /**
 323      * @param element
 324      * @param baseURI
 325      * @param storage
 326      * @return resolved SecretKey key from the registered from the elements
 327      * @throws KeyResolverException
 328      */
 329     public SecretKey resolveSecretKey(
 330         Element element, String baseURI, StorageResolver storage
 331     ) throws KeyResolverException {
 332         return resolverSpi.engineLookupAndResolveSecretKey(element, baseURI, storage);
 333     }
 334 
 335     /**
 336      * Method setProperty
 337      *
 338      * @param key
 339      * @param value
 340      */
 341     public void setProperty(String key, String value) {
 342         resolverSpi.engineSetProperty(key, value);
 343     }
 344 
 345     /**
 346      * Method getProperty
 347      *
 348      * @param key
 349      * @return the property set for this resolver
 350      */
 351     public String getProperty(String key) {
 352         return resolverSpi.engineGetProperty(key);
 353     }
 354 
 355 
 356     /**
 357      * Method understandsProperty
 358      *
 359      * @param propertyToTest
 360      * @return true if the resolver understands property propertyToTest
 361      */
 362     public boolean understandsProperty(String propertyToTest) {
 363         return resolverSpi.understandsProperty(propertyToTest);
 364     }
 365 
 366 
 367     /**
 368      * Method resolverClassName
 369      *
 370      * @return the name of the resolver.
 371      */
 372     public String resolverClassName() {
 373         return resolverSpi.getClass().getName();
 374     }
 375 
 376     /**
 377      * Iterate over the KeyResolverSpi instances
 378      */
 379     static class ResolverIterator implements Iterator<KeyResolverSpi> {
 380         List<KeyResolver> res;
 381         Iterator<KeyResolver> it;
 382 
 383         public ResolverIterator(List<KeyResolver> list) {
 384             res = list;
 385             it = res.iterator();
 386         }
 387 
 388         public boolean hasNext() {
 389             return it.hasNext();
 390         }
 391 
 392         public KeyResolverSpi next() {
 393             KeyResolver resolver = it.next();
 394             if (resolver == null) {
 395                 throw new RuntimeException("utils.resolver.noClass");
 396             }
 397 
 398             return resolver.resolverSpi;
 399         }
 400 
 401         public void remove() {
 402             throw new UnsupportedOperationException("Can't remove resolvers using the iterator");
 403         }
 404     };
 405 
 406     public static Iterator<KeyResolverSpi> iterator() {
 407         return new ResolverIterator(resolverVector);
 408     }
 409 }