org.yawlfoundation.yawl.digitalSignature.DigitalSignature.java Source code

Java tutorial

Introduction

Here is the source code for org.yawlfoundation.yawl.digitalSignature.DigitalSignature.java

Source

/*
 * Copyright (c) 2004-2012 The YAWL Foundation. All rights reserved.
 * The YAWL Foundation is a collaboration of individuals and
 * organisations who are committed to improving workflow technology.
 *
 * This file is part of YAWL. YAWL is free software: you can
 * redistribute it and/or modify it under the terms of the GNU Lesser
 * General Public License as published by the Free Software Foundation.
 *
 * YAWL 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 YAWL. If not, see <http://www.gnu.org/licenses/>.
 */

package org.yawlfoundation.yawl.digitalSignature;

import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.cms.*;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.output.DOMOutputter;
import org.jdom2.output.Format;
import org.jdom2.output.XMLOutputter;
import org.yawlfoundation.yawl.elements.data.YParameter;
import org.yawlfoundation.yawl.engine.interfce.WorkItemRecord;
import org.yawlfoundation.yawl.engine.interfce.interfaceB.InterfaceBWebsideController;
import org.yawlfoundation.yawl.util.JDOMUtil;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.*;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.Security;
import java.security.cert.CertStore;
import java.security.cert.CertificateFactory;
import java.security.cert.CollectionCertStoreParameters;
import java.security.cert.X509Certificate;
import java.util.*;

/**
 * The main class of the Digital Signature Service.
 *
 * @author Sebastien Vincente
 * @since 2.0
 */
public class DigitalSignature extends InterfaceBWebsideController {
    private static final String _Document = "Document";
    private static final String _Signature = "Signature";
    private static final String _CheckSignature = "CheckSignature";
    private static final String _Alias = "Name";

    private static String _Certificate = null;
    private static String _P12 = null;
    private static String _Password = null;
    private static String _Pathway = System.getenv("CATALINA_HOME") + "/webapps/digitalSignature/files/";
    private static String _Name = null;
    private static String _sessionHandle = null;
    private static org.jdom2.Document Doc = null;

    //Function used by the Custom Service.
    public void handleEnabledWorkItemEvent(WorkItemRecord enabledWorkItem) {
        try {
            if (!checkConnection(_sessionHandle)) {
                _sessionHandle = connect(engineLogonName, engineLogonPassword);
            }
            if (successful(_sessionHandle)) {
                WorkItemRecord child = checkOut(enabledWorkItem.getID(), _sessionHandle);
                if (child != null) {
                    List children = getChildren(enabledWorkItem.getID(), _sessionHandle);
                    for (int i = 0; i < children.size(); i++) {
                        WorkItemRecord itemRecord = (WorkItemRecord) children.get(i);
                        if (WorkItemRecord.statusFired.equals(itemRecord.getStatus())) {
                            checkOut(itemRecord.getID(), _sessionHandle);
                        }

                    }
                    List executingChildren = getChildren(enabledWorkItem.getID(), _sessionHandle);
                    for (int i = 0; i < executingChildren.size(); i++) {
                        WorkItemRecord itemRecord = (WorkItemRecord) executingChildren.get(i);
                        Element element = itemRecord.getDataList();

                        String answer;

                        //Get the signed document
                        String Document = element.getChild(_Signature).getText();
                        Document = Document.replace(" ", "+");
                        System.out.println("Beginning of Checking XmlSignature:");

                        System.out.println(Document);
                        //Decode the BASE64 signature
                        Base64 deCoder = new Base64();

                        byte[] SignedDocument = deCoder.decode(Document.getBytes());
                        System.out.println("Beginning of Checking XmlSignature:");
                        if (checkSignature(SignedDocument))
                            answer = "true";
                        else
                            answer = "false";
                        System.out.println("end of Checking XmlSignature:");
                        System.out.println(answer);

                        //Set the output element
                        Element Outputelement = prepareReplyRootElement(itemRecord, _sessionHandle);
                        Element Child = new Element(_CheckSignature);
                        Child.setText(answer);
                        Outputelement.addContent(Child);

                        Element Child2 = new Element(_Document);
                        Child2.setContent(Doc.cloneContent());
                        Outputelement.addContent(Child2);

                        Element Child3 = new Element(_Alias);
                        Child3.setText(_Name);
                        Outputelement.addContent(Child3);

                        //Check In the work item and finish the task. 
                        this.checkInWorkItem(itemRecord.getID(), itemRecord.getDataList(), Outputelement,
                                _sessionHandle);

                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public YParameter[] describeRequiredParams() {
        YParameter[] params = new YParameter[4];
        YParameter param;

        param = new YParameter(null, YParameter._INPUT_PARAM_TYPE);
        param.setDataTypeAndName(XSD_STRINGTYPE, _Signature, XSD_NAMESPACE);
        param.setDocumentation("This is the document signed");
        params[0] = param;

        param = new YParameter(null, YParameter._OUTPUT_PARAM_TYPE);
        param.setDataTypeAndName(XSD_STRINGTYPE, _CheckSignature, XSD_NAMESPACE);
        param.setDocumentation("This say if the signature is valid or not");
        params[1] = param;

        param = new YParameter(null, YParameter._OUTPUT_PARAM_TYPE);
        param.setDataTypeAndName("anyType", _Document, XSD_NAMESPACE);
        param.setDocumentation("This is the Document Content");
        params[2] = param;

        param = new YParameter(null, YParameter._OUTPUT_PARAM_TYPE);
        param.setDataTypeAndName(XSD_STRINGTYPE, _Alias, XSD_NAMESPACE);
        param.setDocumentation("This is the Document Content");
        params[3] = param;

        return params;
    }

    public void handleCancelledWorkItemEvent(WorkItemRecord workItemRecord) {

    }

    // Function to check the Signature 
    public boolean checkSignature(byte[] Document) {
        try {
            System.out.println("Beginning of Checking XmlSignature:");
            System.out.println(Document);

            Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());

            // extract the Signed Fingerprint data
            CMSSignedData signature = new CMSSignedData(Document);
            System.out.println("Beginning of Checking XmlSignature:");

            SignerInformation signer = (SignerInformation) signature.getSignerInfos().getSigners().iterator()
                    .next();
            System.out.println("Beginning of Checking XmlSignature:");

            // Get from the collection the appropriate registered certificate
            CertStore cs = signature.getCertificatesAndCRLs("Collection", "BC");
            Iterator iter = cs.getCertificates(signer.getSID()).iterator();
            System.out.println("Beginning of Checking XmlSignature:");
            X509Certificate certificate = (X509Certificate) iter.next();
            System.out.println("Beginning of Checking XmlSignature:");
            // get the contents of the document
            CMSProcessable sg = signature.getSignedContent();
            byte[] data = (byte[]) sg.getContent();
            String content = new String(data);

            //convert the document content to a valid xml document for YAWL
            org.w3c.dom.Document XMLNode = ConvertStringToDocument(content);
            org.jdom2.input.DOMBuilder builder = new org.jdom2.input.DOMBuilder();
            Doc = builder.build(XMLNode);

            //Check the document
            System.out.println("xml to Sign:");
            System.out.println(JDOMUtil.documentToString(Doc));

            // get the name of the signer
            _Name = certificate.getSubjectDN().getName().split("(=|, )", -1).toString();
            //return the result of the signature checking
            return signer.verify(certificate, "BC");

        } catch (Exception e) {
            System.out.println("Test error");
            e.printStackTrace();
            return false;
        }

    }

    //convert a String to a valid w3c Document
    public static org.w3c.dom.Document ConvertStringToDocument(String Doc) {

        org.w3c.dom.Document document = null;

        try {
            DocumentBuilderFactory Factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder DocBuild = Factory.newDocumentBuilder();

            StringBuffer Buffer = new StringBuffer(Doc);
            ByteArrayInputStream DocArray = new ByteArrayInputStream(Buffer.toString().getBytes("UTF-8"));
            document = DocBuild.parse(DocArray);

        } catch (ParserConfigurationException pce) {
            pce.printStackTrace();
            System.exit(0);
        } catch (org.xml.sax.SAXException se) {
            se.printStackTrace();
            System.exit(0);
        } catch (IOException ioe) {
            ioe.printStackTrace();
            System.exit(0);
        }
        return document;

    }

    //Function use to Sign Document (used by the Signature.jsp)
    public X509Certificate getCertificate() {

        try {
            //Extract the x.509 certificates
            InputStream inStream = new FileInputStream(_Pathway + _Certificate);
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
            X509Certificate cert = (X509Certificate) cf.generateCertificate(inStream);
            inStream.close();

            _Certificate = null;
            return cert;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }

    }

    //Extract the PrivateKey from the keystore  
    private PrivateKey getPrivateKey() {
        KeyStore keystore = null;

        try {
            char[] password = _Password.toCharArray();
            String _alias = "";
            _Password = null;
            keystore = KeyStore.getInstance("PKCS12");

            keystore.load(new FileInputStream(_Pathway + _P12), password);

            Enumeration enumeration = keystore.aliases();
            Vector vectaliases = new Vector();
            while (enumeration.hasMoreElements())
                vectaliases.add(enumeration.nextElement());

            String[] aliases = (String[]) (vectaliases.toArray(new String[0]));
            for (int i = 0; i < aliases.length; i++)
                if (keystore.isKeyEntry(aliases[i])) {
                    _alias = aliases[i];
                    break;
                }
            PrivateKey pk = (PrivateKey) keystore.getKey(_alias, password);
            password = null;
            return pk;

        } catch (Exception e) {
            System.out.println("Error: " + "Invalid pkcs#12 Certificate");
            return null;
        }

    }

    public String PrepareDocumentToBeSign(Element element) {

        try {
            //extract the Document to sign and transform it in a valid XML DOM 
            Element rootElement = new Element(element.getName());
            rootElement.setContent(element.cloneContent());
            //convert the Element in a JDOM Document
            Document xdoc = new Document(rootElement);
            //create a DOMOutputter to write the content of the JDOM document in a DOM document
            DOMOutputter outputter = new DOMOutputter();
            org.w3c.dom.Document Doctosign = outputter.output(xdoc);

            // Show the document before being sign 
            System.out.println("xml to Sign:");
            XMLOutputter sortie = new XMLOutputter(Format.getPrettyFormat());
            sortie.output(xdoc, System.out);

            //Transform the XML DOM in a String using the xml transformer
            DOMSource domSource = new DOMSource(Doctosign);
            StringWriter writer = new StringWriter();
            StreamResult result = new StreamResult(writer);
            TransformerFactory tf = TransformerFactory.newInstance();
            Transformer transformer = tf.newTransformer();
            transformer.transform(domSource, result);
            String StringTobeSign = writer.toString();

            return StringTobeSign;

        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }

    }

    public CMSSignedData SignedData(Element InputDocument) {

        try {
            X509Certificate cert = getCertificate();
            PrivateKey privatekey = getPrivateKey();
            if (privatekey == null) {
                return null;
            } else {
                String Document = PrepareDocumentToBeSign(InputDocument);
                System.out.println(Document);
                System.out.println("Certificate loaded");
                // define the provider Bouncy castle  
                if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
                    Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
                }

                //register the user certificate in the collection 
                ArrayList certList = new ArrayList();
                certList.add(cert);
                CertStore certs = CertStore.getInstance("Collection", new CollectionCertStoreParameters(certList),
                        "BC");

                System.out.println("provider loaded");
                // create the CMSSignedData
                CMSSignedDataGenerator signGen = new CMSSignedDataGenerator();
                System.out.println("CMS created");
                signGen.addSigner(privatekey, cert, CMSSignedDataGenerator.DIGEST_SHA1);
                signGen.addCertificatesAndCRLs(certs);
                System.out.println("Signer loaded");

                CMSProcessable content = new CMSProcessableByteArray(Document.getBytes());
                System.out.println("BytesArray loaded");
                // the second variable "true" means that the content will be wrap with the signature
                return signGen.generate(content, true, "BC");
            }
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public void setP12AndPassword(String P12, String password, String Certificate) {
        _P12 = P12;
        _Password = password;
        _Certificate = Certificate;

    }

    public String ProgMain(Element Document) {
        try {

            System.out.println("Beginning of XmlSignature:");
            //Call the function to sign the document
            byte[] signeddata = SignedData(Document).getEncoded();
            if (signeddata.toString().compareTo(null) == 0)
                return null;
            else {
                System.out.println("End of Xml Signature");

                // Convert the signed data in a BASE64 string to make it a valid content 
                // for Yawl
                Base64 enCoder = new Base64();
                String base64OfSignatureValue = new String(enCoder.encode(signeddata));
                System.out.println(base64OfSignatureValue);

                return base64OfSignatureValue;
            }

        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

}