ru.codeinside.gws3572c.GMPClientSignTest.java Source code

Java tutorial

Introduction

Here is the source code for ru.codeinside.gws3572c.GMPClientSignTest.java

Source

/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 * Copyright (c) 2013, MPL CodeInside http://codeinside.ru
 */

package ru.codeinside.gws3572c;

import com.sun.org.apache.xpath.internal.XPathAPI;
import junit.framework.Assert;
import org.apache.commons.lang.time.DateUtils;
import org.apache.xml.security.keys.KeyInfo;
import org.apache.xml.security.signature.XMLSignature;
import org.apache.xml.security.utils.Base64;
import org.apache.xml.security.utils.Constants;
import org.junit.Before;
import org.junit.Test;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import ru.codeinside.gws.api.ClientRequest;
import ru.codeinside.gws.crypto.cryptopro.CryptoProvider;
import ru.codeinside.gws.stubs.DummyContext;
import xmltype.R;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPMessage;
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.ByteArrayInputStream;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.security.PublicKey;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.text.ParseException;

public class GMPClientSignTest {

    private GMPClient3572 client;
    private DocumentBuilder documentBuilder;

    @Before
    public void setUp() throws Exception {
        client = new GMPClient3572();
        CryptoProvider cryptoProvider = new CryptoProvider();
        client.bindCryptoProvider(cryptoProvider);

        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        dbf.setNamespaceAware(true);
        documentBuilder = dbf.newDocumentBuilder();

    }

    private DummyContext createContext() throws ParseException {
        DummyContext ctx = new DummyContext();
        ctx.setVariable("payerType", "1");
        ctx.setVariable("payerPersonDocumentID1", "12345678901");
        ctx.setVariable("postBlockIdRequest", "13454"); //  ?
        ctx.setVariable("postBlockSenderIdentifier", "20091d"); //  ?
        ctx.setVariable("ordinalNumber", "013400000011"); // ?  ?
        ctx.setVariable("postBlockTimeStamp",
                DateUtils.parseDate("25.07.2012 09:40:47", new String[] { "dd.MM.yyyy HH:mm:ss" })); //  ??? ?

        ctx.setVariable("supplierOrgInfoName",
                "   ?  ? ?");
        ctx.setVariable("supplierOrgInfoINN", "1655102196");
        ctx.setVariable("supplierOrgInfoKPP", "165501001");
        ctx.setVariable("accountAccount", "40101810800000010001");
        ctx.setVariable("bankBIK", "049205001");
        ctx.setVariable("bankName", " ?  . ");

        ctx.setVariable("chargeSupplierBillID", "19255500000000000079"); //   ?  
        ctx.setVariable("chargeBillDate", DateUtils.parseDate("10.03.2011", new String[] { "dd.MM.yyyy" })); // ?? ?
        ctx.setVariable("chargeBillFor", "?   ?"); // ?? ?
        ctx.setVariable("chargeTotalAmount", "1000,00");
        ctx.setVariable("chargeChangeStatus",
                "1"); /* ? ? 1 -   2 -   3 -  */
        ctx.setVariable("chargeTreasureBranch", "  ? ?");
        ctx.setVariable("chargeKBK", "19210806000011000110");
        ctx.setVariable("chargeOKATO", "92401000000");
        ctx.setVariable("chargeApplicationID", "455555");
        ctx.setVariable("chargeUnifiedPayerIdentifier", "0100000000006667775555643");

        ctx.setVariable("budgetIndexStatus", "0");
        ctx.setVariable("budgetPaymentType", "0");
        ctx.setVariable("budgetPurpose", "0");
        ctx.setVariable("budgetTaxPeriod", "0");
        ctx.setVariable("budgetTaxDocNumber", "0");
        ctx.setVariable("budgetTaxDocDate", "0");
        ctx.setVariable("operationType", "importCharge");
        return ctx;
    }

    /*
         ??? ? ?? ?  .
        */
    @Test
    public void testSignForEntity() throws Exception {
        ClientRequest request = client.createClientRequest(createContext());
        InputSource is = new InputSource(new StringReader(request.appData));
        Document doc = documentBuilder.parse(is);

        Element elementForSign = (Element) doc.getElementsByTagNameNS(null, "Charge").item(0);

        Node parentNode;
        Document detachedDocument;
        if (!elementForSign.isSameNode(doc.getDocumentElement())) {
            parentNode = elementForSign.getParentNode();
            parentNode.removeChild(elementForSign);

            detachedDocument = documentBuilder.newDocument();
            Node importedElementForSign = detachedDocument.importNode(elementForSign, true);
            detachedDocument.appendChild(importedElementForSign);
        } else {
            detachedDocument = doc;
        }

        Element nscontext = detachedDocument.createElementNS(null, "namespaceContext");
        nscontext.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:" + "ds".trim(),
                "http://www.w3.org/2000/09/xmldsig#");

        Element certificateElement = (Element) XPathAPI.selectSingleNode(detachedDocument,
                "//ds:X509Certificate[1]", nscontext);
        Element sigElement = (Element) certificateElement.getParentNode().getParentNode().getParentNode();

        XMLSignature signature = new XMLSignature(sigElement, "");

        CertificateFactory cf = CertificateFactory.getInstance("X.509");
        X509Certificate certKey = (X509Certificate) cf.generateCertificate(
                new ByteArrayInputStream(Base64.decode(certificateElement.getTextContent().trim().getBytes())));

        Assert.assertNotNull("There are no information about public key. Verification couldn't be implemented",
                certKey);
        Assert.assertTrue("Signature is not valid", signature.checkSignatureValue(certKey));
    }

    /* ??? ?   ? ? */
    @Test
    public void validateGMPSample() throws Exception {
        SOAPMessage sampleDoc = R.getSoapResource("gmp/gmd_sample.xml");
        SOAPBody soapBody = sampleDoc.getSOAPBody();
        Element unifoTransferMsg = first(soapBody, null, "UnifoTransferMsg");
        Assert.assertNotNull(unifoTransferMsg);
        Element messageData = first(unifoTransferMsg, null, "MessageData");
        Assert.assertNotNull(messageData);
        Element appData = first(messageData, null, "AppData");
        Assert.assertNotNull(appData);
        Element importData = first(appData, null, "ImportData");
        Assert.assertNotNull(importData);
        Element importRequest = first(importData, "http://roskazna.ru/xsd/PGU_ImportRequest", "ImportRequest");
        Assert.assertNotNull("importRequest not found", importRequest);
        Element charge = first(importRequest, null, "Charge");
        Assert.assertNotNull("charge not found", charge);
        Document docEntity = createDocumentFromElement(charge);
        Assert.assertNotNull("doc from charge null", docEntity);
        Assert.assertTrue("   ", signDocVer(docEntity));
    }

    private Document createDocumentFromElement(Element element)
            throws ParserConfigurationException, IOException, SAXException {
        final DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        // ? , ?    ? ?   XML-
        dbf.setIgnoringElementContentWhitespace(true);
        // ? , ?   CDATA  ?    XML-
        dbf.setCoalescing(true);
        // ? , ?  ??    XML-
        dbf.setNamespaceAware(true);
        InputSource is = new InputSource(new StringReader(convertElementToString(element)));
        return dbf.newDocumentBuilder().parse(is);

    }

    /**
     *  ? ? XML- ?    34.10-2001.
     *
     * @throws Exception /
     */
    boolean signDocVer(Document doc) throws Exception {
        /*   ? <ds:Signature>  XML- */

        //     ? ??  Signature
        final Element nscontext = doc.createElementNS(null, "namespaceContext");
        nscontext.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:" + "ds".trim(),
                Constants.SignatureSpecNS);

        //    ? ??   ? <ds:Signature>
        final Element sigElement = (Element) XPathAPI.selectSingleNode(doc, "//ds:Signature[1]", nscontext);

        /*  ? XML-  ?    , ??? 
        XML- */

        // ?   ?
        final XMLSignature signature = new XMLSignature(sigElement, "");

        //   <ds:KeyInfo>    
        final KeyInfo ki = signature.getKeyInfo();

        //  ?      
        final X509Certificate certKey = ki.getX509Certificate();

        // ? ? ,  ????? 
        // ?  ? ?
        if (certKey != null) {

            return signature.checkSignatureValue(certKey);

        }
        //   ? ?????    
        else {
            //         
            final PublicKey pk = ki.getPublicKey();

            // ?   ,    ?????  ?
            if (pk != null) {

                return signature.checkSignatureValue(pk);
            }
            //   ?     
            else
                throw new Exception(
                        "There are no information about public key. Verification couldn't be implemented");

        }
    }

    private static String convertElementToString(Element signElement) {
        Transformer transformer;
        try {
            transformer = TransformerFactory.newInstance().newTransformer();
            //            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
            StreamResult result = new StreamResult(new StringWriter());
            DOMSource source = new DOMSource(signElement);
            transformer.transform(source, result);
            return result.getWriter().toString();
        } catch (Exception e) {
            return null;
        }
    }

    private static Element first(final Node parent, final String uri, final String localName) {
        final NodeList nodes = parent.getChildNodes();
        final int n = nodes.getLength();
        for (int i = 0; i < n; i++) {
            final Node node = nodes.item(i);
            if (node instanceof Element) {
                final Element element = (Element) node;
                if (localName.equals(element.getLocalName())
                        && (uri == null || uri.equals(element.getNamespaceURI()))) {
                    return element;
                }
            }
        }
        return null;
    }

}