be.fedict.eid.applet.service.signer.odf.AbstractODFSignatureService.java Source code

Java tutorial

Introduction

Here is the source code for be.fedict.eid.applet.service.signer.odf.AbstractODFSignatureService.java

Source

/*
 * eID Applet Project.
 * Copyright (C) 2008-2009 FedICT.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License version
 * 3.0 as published by the Free Software Foundation.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, see 
 * http://www.gnu.org/licenses/.
 */
package be.fedict.eid.applet.service.signer.odf;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

import javax.xml.crypto.URIDereferencer;
import javax.xml.parsers.ParserConfigurationException;

import be.fedict.eid.applet.service.signer.DigestAlgo;
import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.xml.security.utils.Constants;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.SAXException;

import be.fedict.eid.applet.service.signer.AbstractXmlSignatureService;
import be.fedict.eid.applet.service.signer.facets.KeyInfoSignatureFacet;
import be.fedict.eid.applet.service.signer.facets.XAdESSignatureFacet;

/**
 * Signature Service implementation for OpenDocument format signatures.
 * 
 * The signatures created with this class are accepted as valid signature within
 * OpenOffice.org 3.x. They probably don't get accepted by older OOo versions.
 * 
 * @see http://wiki.services.openoffice.org/wiki/Security/Digital_Signatures
 * 
 * @author fcorneli
 * 
 */
abstract public class AbstractODFSignatureService extends AbstractXmlSignatureService {

    private static final Log LOG = LogFactory.getLog(AbstractODFSignatureService.class);

    private final XAdESSignatureFacet xadesSignatureFacet;

    public AbstractODFSignatureService(DigestAlgo digestAlgo) {
        super(digestAlgo);
        addSignatureFacet(new ODFSignatureFacet(this, getSignatureDigestAlgorithm()));
        addSignatureFacet(new OpenOfficeSignatureFacet(getSignatureDigestAlgorithm()));
        this.xadesSignatureFacet = new XAdESSignatureFacet(getSignatureDigestAlgorithm());
        addSignatureFacet(this.xadesSignatureFacet);
        addSignatureFacet(new KeyInfoSignatureFacet(false, true, false));
    }

    /**
     * Gives back the used XAdES signature facet. Allows for extra configuration
     * of the XAdES elements.
     * 
     * @return
     */
    protected XAdESSignatureFacet getXAdESSignatureFacet() {
        return this.xadesSignatureFacet;
    }

    /**
     * Returns the URL of the ODF to be signed.
     * 
     * @return
     */
    abstract protected URL getOpenDocumentURL();

    @Override
    protected final URIDereferencer getURIDereferencer() {
        URL odfUrl = getOpenDocumentURL();
        return new ODFURIDereferencer(odfUrl);
    }

    @Override
    protected String getSignatureDescription() {
        return "ODF Document";
    }

    @Override
    protected final OutputStream getSignedDocumentOutputStream() {
        LOG.debug("get signed document output stream");
        /*
         * Create each time a new object; we want an empty output stream to
         * start with.
         */
        OutputStream signedDocumentOutputStream = new ODFSignedDocumentOutputStream();
        return signedDocumentOutputStream;
    }

    private class ODFSignedDocumentOutputStream extends ByteArrayOutputStream {

        @Override
        public void close() throws IOException {
            LOG.debug("close ODF signed document output stream");
            super.close();
            outputSignedOpenDocument(this.toByteArray());
        }
    }

    private void outputSignedOpenDocument(byte[] signatureData) throws IOException {
        LOG.debug("output signed open document");
        OutputStream signedOdfOutputStream = getSignedOpenDocumentOutputStream();
        if (null == signedOdfOutputStream) {
            throw new NullPointerException("signedOpenDocumentOutputStream is null");
        }
        /*
         * Copy the original ODF content to the signed ODF package.
         */
        ZipOutputStream zipOutputStream = new ZipOutputStream(signedOdfOutputStream);
        ZipInputStream zipInputStream = new ZipInputStream(this.getOpenDocumentURL().openStream());
        ZipEntry zipEntry;
        while (null != (zipEntry = zipInputStream.getNextEntry())) {
            if (!zipEntry.getName().equals(ODFUtil.SIGNATURE_FILE)) {
                zipOutputStream.putNextEntry(zipEntry);
                IOUtils.copy(zipInputStream, zipOutputStream);
            }
        }
        zipInputStream.close();
        /*
         * Add the ODF XML signature file to the signed ODF package.
         */
        zipEntry = new ZipEntry(ODFUtil.SIGNATURE_FILE);
        zipOutputStream.putNextEntry(zipEntry);
        IOUtils.write(signatureData, zipOutputStream);
        zipOutputStream.close();
    }

    /**
     * The output stream to which to write the signed ODF file.
     * 
     * @return
     */
    abstract protected OutputStream getSignedOpenDocumentOutputStream();

    public final String getFilesDigestAlgorithm() {
        /*
         * No local files to digest.
         */
        return null;
    }

    @Override
    protected final Document getEnvelopingDocument()
            throws ParserConfigurationException, IOException, SAXException {
        Document document = getODFSignatureDocument();
        if (null != document) {
            return document;
        }
        document = ODFUtil.getNewDocument();
        Element rootElement = document.createElementNS(ODFUtil.SIGNATURE_NS, ODFUtil.SIGNATURE_ELEMENT);
        rootElement.setAttributeNS(Constants.NamespaceSpecNS, "xmlns", ODFUtil.SIGNATURE_NS);
        document.appendChild(rootElement);
        return document;
    }

    /**
     * Get the XML signature file from the ODF package
     * 
     * @return
     * @throws IOException
     * @throws ParserConfigurationException
     * @throws SAXException
     */
    private Document getODFSignatureDocument() throws IOException, ParserConfigurationException, SAXException {
        URL odfUrl = this.getOpenDocumentURL();

        InputStream inputStream = ODFUtil.findDataInputStream(odfUrl.openStream(), ODFUtil.SIGNATURE_FILE);
        if (null != inputStream) {
            return ODFUtil.loadDocument(inputStream);
        }
        return null;
    }
}