Java tutorial
/* * 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; } }