be.fedict.eid.dss.protocol.simple.client.SignatureRequestUtil.java Source code

Java tutorial

Introduction

Here is the source code for be.fedict.eid.dss.protocol.simple.client.SignatureRequestUtil.java

Source

/*
 * eID Digital Signature Service Project.
 * Copyright (C) 2009-2010 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.dss.protocol.simple.client;

import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
import java.security.Signature;
import java.security.SignatureException;
import java.security.cert.CertificateEncodingException;
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;

import javax.servlet.http.HttpServletResponse;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.runtime.RuntimeConstants;
import org.apache.velocity.runtime.log.JdkLogChute;

/**
 * Utility class for sending out DSS Simple Protocol Signature Requests.
 * 
 * @author Wim Vandenhaute
 */
public abstract class SignatureRequestUtil {

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

    private static final String POST_BINDING_TEMPLATE = "be/fedict/eid/dss/protocol/simple/client/dss-post-binding.vm";

    /**
     * Creates a Signature Request and posts it to the eID DSS Service. If a SP
     * identity is specified, a service signature will be added.
     * 
     * @param signatureRequest
     *            optional signature request containing the base64 encoded
     *            document to be siged. If <code>null</code> signatureRequestId
     *            becomes required.
     * @param signatureRequestId
     *            optional signature request ID, which is the ID returned by the
     *            eID DSS Web Service after a "store" operation. If
     *            <code>null</code> signatureRequest becomes required.
     * @param contentType
     *            optional content type of the document to be signed
     * @param dssDestination
     *            eID DSS Protocol Entry point which will handle the signature
     *            request.
     * @param spDestination
     *            SP destination that will handle the returned DSS Signature
     *            Response.
     * @param relayState
     *            optional relayState to be included (if not <code>null</code>)
     *            in the signature request.
     * @param spIdentity
     *            optional SP Identity, if present the signature request will be
     *            signed.
     * @param response
     *            HTTP Servlet Response used for posting the signature request.
     * @param language
     *            optional language indication which the eID DSS will use.
     * @throws SignatureException
     *             exception setting signature.
     * @throws InvalidKeyException
     *             SP Identity key is invalid
     * @throws NoSuchAlgorithmException
     *             Signature algorithm not available
     * @throws CertificateEncodingException
     *             failed to encode the certificate chain of the SP Identity
     * @throws IOException
     *             IO Exception
     */
    public static void sendRequest(String signatureRequest, String signatureRequestId, String contentType,
            String dssDestination, String spDestination, String relayState, KeyStore.PrivateKeyEntry spIdentity,
            HttpServletResponse response, String language)

            throws SignatureException, InvalidKeyException, NoSuchAlgorithmException, CertificateEncodingException,
            IOException {

        // construct service signature
        ServiceSignatureDO serviceSignature = null;
        if (null != spIdentity) {
            serviceSignature = getServiceSignature(spIdentity, signatureRequest, signatureRequestId, spDestination,
                    language, contentType, relayState);
        }

        Properties velocityProperties = new Properties();
        velocityProperties.setProperty("resource.loader", "class");
        velocityProperties.setProperty(RuntimeConstants.RUNTIME_LOG_LOGSYSTEM_CLASS, JdkLogChute.class.getName());
        velocityProperties.setProperty(JdkLogChute.RUNTIME_LOG_JDK_LOGGER, SignatureRequestUtil.class.getName());
        velocityProperties.setProperty("class.resource.loader.class",
                "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
        velocityProperties.setProperty("file.resource.loader.cache ", "false");
        VelocityEngine velocityEngine;
        try {
            velocityEngine = new VelocityEngine(velocityProperties);
            velocityEngine.init();
        } catch (Exception e) {
            throw new RuntimeException("could not initialize velocity engine", e);
        }
        VelocityContext velocityContext = new VelocityContext();
        velocityContext.put("action", dssDestination);
        if (null != signatureRequest) {
            velocityContext.put("SignatureRequest", signatureRequest);
        }
        if (null != signatureRequestId) {
            velocityContext.put("SignatureRequestId", signatureRequestId);
        }
        if (null != contentType) {
            velocityContext.put("ContentType", contentType);
        }
        if (null != relayState) {
            velocityContext.put("RelayState", relayState);
        }
        if (null != dssDestination) {
            velocityContext.put("Target", spDestination);
        }
        if (null != language) {
            velocityContext.put("Language", language);
        }
        if (null != serviceSignature) {
            velocityContext.put("ServiceSigned", serviceSignature.getServiceSigned());
            velocityContext.put("ServiceSignature", serviceSignature.getServiceSignature());
            velocityContext.put("ServiceCertificateChainSize", serviceSignature.getServiceCertificateChainSize());
            velocityContext.put("ServiceCertificates", serviceSignature.getServiceCertificates());
        }

        Template template;
        try {
            template = velocityEngine.getTemplate(POST_BINDING_TEMPLATE);
        } catch (Exception e) {
            throw new RuntimeException("Velocity template error: " + e.getMessage(), e);
        }

        response.setContentType("text/html; charset=UTF-8");
        template.merge(velocityContext, response.getWriter());
    }

    /**
     * Constructs a DSS Simple Protocol service signature.
     * <p/>
     * If no spIdentity is specified returns <code>null</code>
     * 
     * @param spIdentity
     *            the SP Identity used for signing.
     * @param signatureRequest
     *            signature request, if <code>null</code> signatureRequestId
     *            needs to be specified.
     * @param signatureRequestId
     *            signature request ID, if <code>null</code>, signatureRequest
     *            needs to be specified
     * @param target
     *            required target
     * @param language
     *            optional language param
     * @param contentType
     *            optional document content type
     * @param relayState
     *            optional relay state
     * @return service signature DO containing the signature value, service
     *         signed property listing up all signed properties and the SP
     *         certificate chain.
     * @throws NoSuchAlgorithmException
     *             algorithm to sign/digest not found.
     * @throws InvalidKeyException
     *             signing key not valid
     * @throws SignatureException
     *             signature creation failure
     * @throws CertificateEncodingException
     *             certificate encoding failure
     */
    public static ServiceSignatureDO getServiceSignature(

            KeyStore.PrivateKeyEntry spIdentity, String signatureRequest, String signatureRequestId, String target,
            String language, String contentType, String relayState)

            throws NoSuchAlgorithmException, InvalidKeyException, SignatureException, CertificateEncodingException {

        LOG.debug("get service signature");

        if (null == spIdentity) {
            LOG.warn("No SP Identity specified, no signature added.");
            return null;
        }
        if (null == signatureRequest && null == signatureRequestId) {
            throw new RuntimeException(
                    "Either \"SignatureRequest\" or " + "\"SignatureRequestId\" needs to be provided.");
        }

        // construct service signature
        // TODO: configurable?
        Signature serviceSignature = Signature.getInstance("SHA1withRSA");
        serviceSignature.initSign(spIdentity.getPrivateKey());

        serviceSignature.update(target.getBytes());
        if (null != signatureRequest) {
            serviceSignature.update(signatureRequest.getBytes());
        } else {
            serviceSignature.update(signatureRequestId.getBytes());
        }
        if (null != language) {
            serviceSignature.update(language.getBytes());
        }
        if (null != contentType) {
            serviceSignature.update(contentType.getBytes());
        }
        if (null != relayState) {
            serviceSignature.update(relayState.getBytes());
        }

        byte[] serviceSignatureValue = serviceSignature.sign();

        String encodedServiceSignature = Base64.encodeBase64String(serviceSignatureValue);

        // construct service signed
        String serviceSigned = "target";
        if (null != signatureRequest) {
            serviceSigned += ",SignatureRequest";
        } else {
            serviceSigned += ",SignatureRequestId";
        }
        if (null != language) {
            serviceSigned += ",language";
        }
        if (null != contentType) {
            serviceSigned += ",ContentType";
        }
        if (null != relayState) {
            serviceSigned += ",RelayState";
        }

        // construct service certificate chain
        java.security.cert.Certificate[] serviceCertificateChain = spIdentity.getCertificateChain();
        String serviceCertificateChainSize = Integer.toString(serviceCertificateChain.length);

        List<String> serviceCertificates = new LinkedList<String>();
        for (java.security.cert.Certificate certificate : serviceCertificateChain) {
            String encodedServiceCertificate = Base64.encodeBase64String(certificate.getEncoded());
            serviceCertificates.add(encodedServiceCertificate);
        }

        return new ServiceSignatureDO(serviceSigned, encodedServiceSignature, serviceCertificateChainSize,
                serviceCertificates);
    }

}