org.apache.xml.security.keys.keyresolver.implementations.RetrievalMethodResolver.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.xml.security.keys.keyresolver.implementations.RetrievalMethodResolver.java

Source

/**
 * 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.implementations;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.security.PublicKey;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Set;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.apache.xml.security.c14n.CanonicalizationException;
import org.apache.xml.security.exceptions.XMLSecurityException;
import org.apache.xml.security.keys.content.RetrievalMethod;
import org.apache.xml.security.keys.content.x509.XMLX509Certificate;
import org.apache.xml.security.keys.keyresolver.KeyResolver;
import org.apache.xml.security.keys.keyresolver.KeyResolverException;
import org.apache.xml.security.keys.keyresolver.KeyResolverSpi;
import org.apache.xml.security.keys.storage.StorageResolver;
import org.apache.xml.security.signature.XMLSignatureInput;
import org.apache.xml.security.transforms.Transforms;
import org.apache.xml.security.utils.Constants;
import org.apache.xml.security.utils.XMLUtils;
import org.apache.xml.security.utils.resolver.ResourceResolver;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.xml.sax.SAXException;

/**
 * The RetrievalMethodResolver can retrieve public keys and certificates from
 * other locations. The location is specified using the ds:RetrievalMethod
 * element which points to the location. This includes the handling of raw
 * (binary) X.509 certificate which are not encapsulated in an XML structure.
 * If the retrieval process encounters an element which the
 * RetrievalMethodResolver cannot handle itself, resolving of the extracted
 * element is delegated back to the KeyResolver mechanism.
 *
 * @author $Author: raul $ modified by Dave Garcia
 */
public class RetrievalMethodResolver extends KeyResolverSpi {

    /** {@link org.apache.commons.logging} logging facility */
    private static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory
            .getLog(RetrievalMethodResolver.class);

    /**
     * Method engineResolvePublicKey
     * @inheritDoc
     * @param element
     * @param BaseURI
     * @param storage
     */
    public PublicKey engineLookupAndResolvePublicKey(Element element, String BaseURI, StorageResolver storage) {
        if (!XMLUtils.elementIsInSignatureSpace(element, Constants._TAG_RETRIEVALMETHOD)) {
            return null;
        }

        try {
            // Create a retrieval method over the given element
            RetrievalMethod rm = new RetrievalMethod(element, BaseURI);
            String type = rm.getType();
            XMLSignatureInput resource = resolveInput(rm, BaseURI);
            if (RetrievalMethod.TYPE_RAWX509.equals(type)) {
                // a raw certificate, direct parsing is done!
                X509Certificate cert = getRawCertificate(resource);
                if (cert != null) {
                    return cert.getPublicKey();
                }
                return null;
            }
            Element e = obtainReferenceElement(resource);
            return resolveKey(e, BaseURI, storage);
        } catch (XMLSecurityException ex) {
            if (log.isDebugEnabled()) {
                log.debug("XMLSecurityException", ex);
            }
        } catch (CertificateException ex) {
            if (log.isDebugEnabled()) {
                log.debug("CertificateException", ex);
            }
        } catch (IOException ex) {
            if (log.isDebugEnabled()) {
                log.debug("IOException", ex);
            }
        } catch (ParserConfigurationException e) {
            if (log.isDebugEnabled()) {
                log.debug("ParserConfigurationException", e);
            }
        } catch (SAXException e) {
            if (log.isDebugEnabled()) {
                log.debug("SAXException", e);
            }
        }
        return null;
    }

    /**
     * Method engineResolveX509Certificate
     * @inheritDoc
     * @param element
     * @param BaseURI
     * @param storage
     */
    public X509Certificate engineLookupResolveX509Certificate(Element element, String BaseURI,
            StorageResolver storage) {
        if (!XMLUtils.elementIsInSignatureSpace(element, Constants._TAG_RETRIEVALMETHOD)) {
            return null;
        }

        try {
            RetrievalMethod rm = new RetrievalMethod(element, BaseURI);
            String type = rm.getType();
            XMLSignatureInput resource = resolveInput(rm, BaseURI);
            if (RetrievalMethod.TYPE_RAWX509.equals(type)) {
                X509Certificate cert = getRawCertificate(resource);
                return cert;
            }
            Element e = obtainReferenceElement(resource);
            return resolveCertificate(e, BaseURI, storage);
        } catch (XMLSecurityException ex) {
            if (log.isDebugEnabled()) {
                log.debug("XMLSecurityException", ex);
            }
        } catch (CertificateException ex) {
            if (log.isDebugEnabled()) {
                log.debug("CertificateException", ex);
            }
        } catch (IOException ex) {
            if (log.isDebugEnabled()) {
                log.debug("IOException", ex);
            }
        } catch (ParserConfigurationException e) {
            if (log.isDebugEnabled()) {
                log.debug("ParserConfigurationException", e);
            }
        } catch (SAXException e) {
            if (log.isDebugEnabled()) {
                log.debug("SAXException", e);
            }
        }
        return null;
    }

    /**
     * Retrieves a x509Certificate from the given information
     * @param e
     * @param BaseURI
     * @param storage
     * @return
     * @throws KeyResolverException 
     */
    private static X509Certificate resolveCertificate(Element e, String BaseURI, StorageResolver storage)
            throws KeyResolverException {
        if (log.isDebugEnabled()) {
            log.debug("Now we have a {" + e.getNamespaceURI() + "}" + e.getLocalName() + " Element");
        }
        // An element has been provided
        if (e != null) {
            return KeyResolver.getX509Certificate(e, BaseURI, storage);
        }
        return null;
    }

    /**
     * Retrieves a PublicKey from the given information
     * @param e
     * @param BaseURI
     * @param storage
     * @return
     * @throws KeyResolverException 
     */
    private static PublicKey resolveKey(Element e, String BaseURI, StorageResolver storage)
            throws KeyResolverException {
        if (log.isDebugEnabled()) {
            log.debug("Now we have a {" + e.getNamespaceURI() + "}" + e.getLocalName() + " Element");
        }
        // An element has been provided
        if (e != null) {
            return KeyResolver.getPublicKey(e, BaseURI, storage);
        }
        return null;
    }

    private static Element obtainReferenceElement(XMLSignatureInput resource) throws CanonicalizationException,
            ParserConfigurationException, IOException, SAXException, KeyResolverException {
        Element e;
        if (resource.isElement()) {
            e = (Element) resource.getSubNode();
        } else if (resource.isNodeSet()) {
            // Retrieved resource is a nodeSet
            e = getDocumentElement(resource.getNodeSet());
        } else {
            // Retrieved resource is an inputStream
            byte inputBytes[] = resource.getBytes();
            e = getDocFromBytes(inputBytes);
            // otherwise, we parse the resource, create an Element and delegate
            if (log.isDebugEnabled()) {
                log.debug("we have to parse " + inputBytes.length + " bytes");
            }
        }
        return e;
    }

    private static X509Certificate getRawCertificate(XMLSignatureInput resource)
            throws CanonicalizationException, IOException, CertificateException {
        byte inputBytes[] = resource.getBytes();
        // if the resource stores a raw certificate, we have to handle it
        CertificateFactory certFact = CertificateFactory.getInstance(XMLX509Certificate.JCA_CERT_ID);
        X509Certificate cert = (X509Certificate) certFact.generateCertificate(new ByteArrayInputStream(inputBytes));
        return cert;
    }

    /**
     * Resolves the input from the given retrieval method 
     * @return
     * @throws XMLSecurityException 
     */
    private static XMLSignatureInput resolveInput(RetrievalMethod rm, String BaseURI) throws XMLSecurityException {
        Attr uri = rm.getURIAttr();
        // Apply the transforms
        Transforms transforms = rm.getTransforms();
        ResourceResolver resRes = ResourceResolver.getInstance(uri, BaseURI);
        if (resRes != null) {
            XMLSignatureInput resource = resRes.resolve(uri, BaseURI);
            if (transforms != null) {
                if (log.isDebugEnabled()) {
                    log.debug("We have Transforms");
                }
                resource = transforms.performTransforms(resource);
            }
            return resource;
        }
        return null;
    }

    /**
     * Parses a byte array and returns the parsed Element.
     *
     * @param bytes
     * @return the Document Element after parsing bytes 
     * @throws KeyResolverException if something goes wrong
     */
    private static Element getDocFromBytes(byte[] bytes) throws KeyResolverException {
        try {
            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
            dbf.setNamespaceAware(true);
            DocumentBuilder db = dbf.newDocumentBuilder();
            Document doc = db.parse(new ByteArrayInputStream(bytes));
            return doc.getDocumentElement();
        } catch (SAXException ex) {
            throw new KeyResolverException("empty", ex);
        } catch (IOException ex) {
            throw new KeyResolverException("empty", ex);
        } catch (ParserConfigurationException ex) {
            throw new KeyResolverException("empty", ex);
        }
    }

    /**
     * Method engineResolveSecretKey
     * @inheritDoc
     * @param element
     * @param BaseURI
     * @param storage
     */
    public javax.crypto.SecretKey engineLookupAndResolveSecretKey(Element element, String BaseURI,
            StorageResolver storage) {
        return null;
    }

    private static Element getDocumentElement(Set<Node> set) {
        Iterator<Node> it = set.iterator();
        Element e = null;
        while (it.hasNext()) {
            Node currentNode = it.next();
            if (currentNode != null && Node.ELEMENT_NODE == currentNode.getNodeType()) {
                e = (Element) currentNode;
                break;
            }
        }
        List<Node> parents = new ArrayList<Node>();

        // Obtain all the parents of the elemnt
        while (e != null) {
            parents.add(e);
            Node n = e.getParentNode();
            if (n == null || Node.ELEMENT_NODE != n.getNodeType()) {
                break;
            }
            e = (Element) n;
        }
        // Visit them in reverse order.
        ListIterator<Node> it2 = parents.listIterator(parents.size() - 1);
        Element ele = null;
        while (it2.hasPrevious()) {
            ele = (Element) it2.previous();
            if (set.contains(ele)) {
                return ele;
            }
        }
        return null;
    }
}