使用java

时间:2016-02-10 17:06:57

标签: java soap https

尝试在https服务器上发送soap请求时遇到问题。 我似乎并没有发送任何证书,但我不知道该怎么做。我收到SSL握手错误。 这是我的源代码。对不起这个烂摊子...... :)。

    public class Sign {

    static String myToken = "";
    static SOAPMessage signedRequest = null;
    static SOAPEnvelope soapEnvelope = null;

    static String url = "";
    static String fileToSend = "";
    static String receiptDir = "";
    static String jksKey = "";
    static String keyPwd = "";
    static String privKeyAlias = "";
    static TrustManagerFactory tmf = null;

    public static void main(String[] args) throws Exception {

        try {
            url = args[0];
            System.out.println(url);
            fileToSend = args[1];
            System.out.println(fileToSend);
            receiptDir = args[2];
            System.out.println(receiptDir);
            jksKey = args[3];
            System.out.println(jksKey);
            keyPwd = args[4];
            System.out.println(keyPwd);
            privKeyAlias = args[5];
            System.out.println(privKeyAlias);
        } catch (Exception e) {
            System.out.println("Paramètres incorrects !");
            e.printStackTrace();
        }

        // Timestamp to use
        SimpleDateFormat formater = null;
        Date aujourdhui = new Date();
        formater = new SimpleDateFormat("yyyyMMddHHmmss");
        myToken = formater.format(aujourdhui);
        // myToken = "20150112202835";


        ////////////////////////////
        // Constructing the message
        ////////////////////////////
        SOAPMessage soapMessage = MessageFactory.newInstance().createMessage();
        SOAPPart soapPart = soapMessage.getSOAPPart();
        soapEnvelope = soapPart.getEnvelope();
        soapEnvelope.removeNamespaceDeclaration(soapEnvelope.getPrefix());
        soapEnvelope.setPrefix("soapenv");
        soapEnvelope.addNamespaceDeclaration("tem", "http://tempuri.org/");
        soapEnvelope.addNamespaceDeclaration("elc",
                "http://schemas.datacontract.org/2004/07/ZIRE.Match.Presentation.WebService");

        SOAPHeader soapHeader = soapEnvelope.getHeader();
        soapHeader.setPrefix("soapenv");

        Name nameSecurity = soapEnvelope.createName("Security", "wsse",
                "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
        SOAPElement soapSecurity = soapHeader.addChildElement(nameSecurity);
        soapSecurity.addNamespaceDeclaration("wsu",
                "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd");

        Name nameBinSec = soapEnvelope.createName("BinarySecurityToken", "wsse",
                "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
        SOAPElement soapBinSec = soapSecurity.addChildElement(nameBinSec);
        soapBinSec.setAttribute("EncodingType",
                "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary");
        soapBinSec.setAttribute("ValueType",
                "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3");
        soapBinSec.setAttribute("wsu:Id", "X509-" + myToken);

        SOAPBody soapBody = soapEnvelope.getBody();
        soapBody.setPrefix("soapenv");
        soapBody.addAttribute(
                soapEnvelope.createName("id", "wsu",
                        "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"),
                "id-" + myToken);
        soapBody.setIdAttribute("wsu:id", true);


        ////////////////////////////
        // Adding the real content
        ////////////////////////////
//       The real payload new String(readAllBytes(get("test.txt")))
        String xmlValue = "<![CDATA[" + readFile(fileToSend,  StandardCharsets.UTF_8) + "]]>";      
//      String xmlValue = "<![CDATA[" + new String(readAllBytes(get(fileToSend))) + "]]>";
//      System.out.println(xmlValue);

        QName sendMessage = new QName("tem:SendMessage");
        QName request = new QName("tem:request");
        QName xmldata = new QName("elc:XmlData");

        SOAPElement sendMessageNode = soapBody.addChildElement(sendMessage);
        SOAPElement requestNode = soapBody.addChildElement(request);
        SOAPElement xmldataNode = soapBody.addChildElement(xmldata);

        xmldataNode.addTextNode(xmlValue);
        requestNode.addChildElement(xmldataNode);
        sendMessageNode.addChildElement(requestNode);
        Source source = soapPart.getContent();


        ////////////////////////////////////////////////////////
        // Sending the request to the signing function
        ////////////////////////////////////////////////////////
        Node root = ((DOMSource) source).getNode();     
        signedRequest = addSignature(root.getFirstChild().getOwnerDocument());


        ////////////////////////////////////////////////////////
        // SSL mode configuration
        ////////////////////////////////////////////////////////
        TrustManagerFactory tmf = TrustManagerFactory
                .getInstance(TrustManagerFactory.getDefaultAlgorithm());
            // Using null here initialises the TMF with the default trust store.
            tmf.init((KeyStore) null);

            // Get hold of the default trust manager
            X509TrustManager defaultTm = null;
            for (TrustManager tm : tmf.getTrustManagers()) {
                if (tm instanceof X509TrustManager) {
                    defaultTm = (X509TrustManager) tm;
                    break;
                }
            }

            FileInputStream myKeys = new FileInputStream("D:\\ZIRE\\MesCertificats\\myTrustStore");

            // Do the same with your trust store this time
            // Adapt how you load the keystore to your needs
            KeyStore myTrustStore = KeyStore.getInstance(KeyStore.getDefaultType());
            myTrustStore.load(myKeys, "zire2016".toCharArray());

            myKeys.close();

            tmf = TrustManagerFactory
                .getInstance(TrustManagerFactory.getDefaultAlgorithm());
            tmf.init(myTrustStore);

            // Get hold of the default trust manager
            X509TrustManager myTm = null;
            for (TrustManager tm : tmf.getTrustManagers()) {
                if (tm instanceof X509TrustManager) {
                    myTm = (X509TrustManager) tm;
                    break;
                }
            }

            // Wrap it in your own class.
            final X509TrustManager finalDefaultTm = defaultTm;
            final X509TrustManager finalMyTm = myTm;
            X509TrustManager customTm = new X509TrustManager() {
                @Override
                public X509Certificate[] getAcceptedIssuers() {
                    // If you're planning to use client-cert auth,
                    // merge results from "defaultTm" and "myTm".
                    return finalDefaultTm.getAcceptedIssuers();
                }

                @Override
                public void checkServerTrusted(X509Certificate[] chain,
                        String authType) throws CertificateException {
                    try {
                        finalMyTm.checkServerTrusted(chain, authType);
                    } catch (CertificateException e) {
                        // This will throw another CertificateException if this fails too.
                        finalDefaultTm.checkServerTrusted(chain, authType);
                    }
                }

                @Override
                public void checkClientTrusted(X509Certificate[] chain,
                        String authType) throws CertificateException {
                    // If you're planning to use client-cert auth,
                    // do the same as checking the server.
                    finalDefaultTm.checkClientTrusted(chain, authType);
                }
            };


            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, new TrustManager[] { customTm }, null);

            // You don't have to set this as the default context,
            // it depends on the library you're using.
            SSLContext.setDefault(sslContext);



            ////////////////////////////////////////////////////////
            // Sending the request to the receiver
            ////////////////////////////////////////////////////////
            // Create SOAP Connection
            SOAPConnectionFactory soapConnectionFactory = SOAPConnectionFactory.newInstance();
            SOAPConnection soapConnection = soapConnectionFactory.createConnection();       
            // Send SOAP Message to SOAP Server     
//          System.setProperty("javax.net.ssl.trustStore", "D:\\ZIRE\\MesCertificats\\myTrustStore" );
//          System.setProperty("javax.net.ssl.trustStorePassword", "zire2016");     
//          System.setProperty("java.net.useSystemProxies", "true");
//           SOAPMessage soapResponse = soapConnection.call(signedRequest, url);
//          doTrustToCertificates();
            SOAPMessage soapResponse = sendMessage(signedRequest, url);


        ////////////////////////////////////////////////////////
        // Processing the response
        ////////////////////////////////////////////////////////
        // Cleaning of the response
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        soapResponse.writeTo(out);
        String strMsg = new String(out.toByteArray());
        int d = strMsg.indexOf("<s:Envelope");
        int f = strMsg.indexOf("</s:Envelope>") + 13;
        String strMsg2 = strMsg.substring(d, f);
        // System.out.println(strMsg2);
        // Writting of the response on the server
//      PrintWriter printWriter = new PrintWriter("D:\\ZIRE\\Result.xml");
//      fileToSend
//      String receiptFileName = (new File(fileToSend)).getParent() + "Receipt_" +  (new File(fileToSend)).getName();
//      System.out.println(receiptFileName);

        // Writing the response
        String receiptFileName = receiptDir + "Receipt_" +  (new File(fileToSend)).getName();
        System.out.println(receiptFileName);
        PrintWriter printWriter = new PrintWriter( receiptFileName );
        printWriter.println(strMsg2);
        printWriter.close();
        soapConnection.close();

    }

    public static SOAPMessage addSignature(Document contenu)
            throws KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException, CertificateException,
            IOException, InvalidAlgorithmParameterException, InstantiationException, IllegalAccessException,
            ClassNotFoundException, KeyException, SAXException, ParserConfigurationException, MarshalException,
            XMLSignatureException, TransformerException, InvalidKeySpecException, XMLSecurityException, SOAPException {

        // Chargement des clés
//      FileInputStream is = new FileInputStream("D:\\ZIRE\\Step 1\\mock\\NewJKS.jks");
        FileInputStream is = new FileInputStream(jksKey);
        KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
        keystore.load(is, null);

//      tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); // PKIX
//      tmf.init(keystore);

//       Enumeration<String> myEnum = keystore.aliases();
//      for (Enumeration<String> e = keystore.aliases(); e.hasMoreElements();) {
//          String newAlias = e.nextElement();
//          System.out.println(newAlias);
//          if (newAlias != "wsgbit" ) {
//              System.out.println(keystore.getCertificate(newAlias));
//          }   
//      }

        // Recup clé privée
//      String alias = "wsgbit";
        String alias = privKeyAlias;
//      Key key = keystore.getKey(alias, "password".toCharArray());
        Key key = keystore.getKey(alias, keyPwd.toCharArray());
        KeyPair kp = null;
        Certificate cert = null;
        if (key instanceof PrivateKey) {
            // Get certificate of public key
            cert = keystore.getCertificate(alias);
            // Get public key
            PublicKey publicKey = cert.getPublicKey();

            // Return a key pair
            kp = new KeyPair(publicKey, (PrivateKey) key);
        }

        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        dbf.setNamespaceAware(true);
        Document doc = contenu;
//       dumpDocument(doc);


        // MAJ du champ wsse:BinarySecurityToken
        Element elt = doc.getDocumentElement();
        Node myBinSecElt = (Node) (elt.getElementsByTagName("wsse:BinarySecurityToken")).item(0);
        myBinSecElt.setTextContent(Utf8.decode(Base64.encode(cert.getEncoded())));

        // Debut
        org.apache.xml.security.Init.init();

        Node mySecElt = (Node) (elt.getElementsByTagName("wsse:Security")).item(0);
        org.apache.xml.security.signature.XMLSignature xmlSignature = new org.apache.xml.security.signature.XMLSignature(
                doc, "", org.apache.xml.security.signature.XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA1,
                "http://www.w3.org/2001/10/xml-exc-c14n#");
        Element eltSign = xmlSignature.getElement();
        eltSign.setAttribute("Id", "SIG-" + myToken);
        mySecElt.appendChild(eltSign);

        Transforms transforms = new Transforms(doc);
        transforms.addTransform("http://www.w3.org/2001/10/xml-exc-c14n#");
        xmlSignature.addDocument("#id-" + myToken, transforms, Constants.ALGO_ID_DIGEST_SHA1);

        SOAPElement myCanonElt = (SOAPElement) (elt.getElementsByTagName("ds:CanonicalizationMethod")).item(0);
        InclusiveNamespaces inclusiveNamespaces = new InclusiveNamespaces(doc, "elc soapenv tem");
        myCanonElt.appendChild(inclusiveNamespaces.getElement());

        SOAPElement mySoapTransform = (SOAPElement) (elt.getElementsByTagName("ds:Transform")).item(0);
        InclusiveNamespaces inclusiveNamespaces2 = new InclusiveNamespaces(doc, "elc tem");
        mySoapTransform.appendChild(inclusiveNamespaces2.getElement());

        // Ajustements
        // SOAPElement myCanonElt = (SOAPElement)
        // (elt.getElementsByTagName("ds:CanonicalizationMethod")).item(0);
        // myCanonElt.setAttribute("Algorithm",
        // "http://www.w3.org/2001/10/xml-exc-c14n#");
        // Name nameInclusiveNamespaces =
        // soapEnvelope.createName("InclusiveNamespaces", "ec",
        // "http://www.w3.org/2001/10/xml-exc-c14n#");
        // SOAPElement soapInclusiveNamespaces =
        // myCanonElt.addChildElement(nameInclusiveNamespaces);
        // soapInclusiveNamespaces.setAttribute("PrefixList", "elc soapenv
        // tem");
        //
        // SOAPElement mySoapTransform = (SOAPElement)
        // (elt.getElementsByTagName("ds:Transform")).item(0);
        // Name nameInclusiveNamespaces2 =
        // soapEnvelope.createName("InclusiveNamespaces", "ec",
        // "http://www.w3.org/2001/10/xml-exc-c14n#");
        // SOAPElement soapInclusiveNamespaces2 =
        // mySoapTransform.addChildElement(nameInclusiveNamespaces2);
        // soapInclusiveNamespaces2.setAttribute("PrefixList", "elc tem");
        //
        Name nameKeyInfo = soapEnvelope.createName("KeyInfo", "ds", "http://www.w3.org/2000/09/xmldsig#");
        SOAPElement mySoapSign = (SOAPElement) (elt.getElementsByTagName("ds:Signature")).item(0);
        SOAPElement soapKeyInfo = mySoapSign.addChildElement(nameKeyInfo);
        soapKeyInfo.setAttribute("Id", "KI-" + myToken);

        Name nameSecToken = soapEnvelope.createName("SecurityTokenReference", "wsse",
                "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
        SOAPElement soapSecToken = soapKeyInfo.addChildElement(nameSecToken);
        soapSecToken.setAttribute("wsu:Id", "STR-" + myToken);

        Name nameRef = soapEnvelope.createName("Reference", "wsse",
                "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
        SOAPElement soapNameRef = soapSecToken.addChildElement(nameRef);
        soapNameRef.setAttribute("URI", "#X509-" + myToken);
        soapNameRef.setAttribute("ValueType",
                "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3");

        xmlSignature.sign(key);
//      xmlSignature.sign(key);
//      dumpDocument(doc);

        // String xml = new XMLOutputter().outputString(doc);

        // Ecriture du String represantant la requete signée
        StringWriter sw = new StringWriter();
        TransformerFactory tf = TransformerFactory.newInstance();
        Transformer transformer = tf.newTransformer();
//      transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
//      transformer.setOutputProperty(OutputKeys.METHOD, "xml");
//      transformer.setOutputProperty(OutputKeys.INDENT, "no");
        transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
        transformer.transform(new DOMSource(doc), new StreamResult(sw));
//      String xml = sw.toString(); System.out.println(">>>" + xml + "<<<");

        InputStream inputStream = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8));// new
                                                                                                    // InputStream(xml);
        MessageFactory messageFactory = MessageFactory.newInstance();
        return messageFactory.createMessage(null, inputStream);

        // Ecriture dans un fichier
        // Transformer transformer =
        // TransformerFactory.newInstance().newTransformer();
        // Result output = new StreamResult(new
        // FileOutputStream("D:\\ZIRE\\mySignedFile2.xml"));
        // Source input = new DOMSource(doc);
        // transformer.transform(input, output);

    }

    public static String convertToString(Document document) throws TransformerException {

        DOMSource domSource = new DOMSource(document);
        StringWriter sw = new StringWriter();
        Result result = new StreamResult(sw);
        // create an instance of TransformerFactory
        TransformerFactory transFact = TransformerFactory.newInstance();
        Transformer trans = transFact.newTransformer();
        trans.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
        trans.transform(domSource, result);
        return sw.toString();
    }

    private static void dumpDocument(Node root) throws TransformerException {
        Transformer transformer = TransformerFactory.newInstance().newTransformer();
//      transformer.setOutputProperty(OutputKeys.INDENT, "yes");
        transformer.transform(new DOMSource(root), new StreamResult(System.out));
    }

    private static Element getFirstChildElement(Node node) {
        Node child = node.getFirstChild();
        while ((child != null) && (child.getNodeType() != Node.ELEMENT_NODE)) {
            child = child.getNextSibling();
        }
        return (Element) child;
    }

    public static Element getNextSiblingElement(Node node) {
        Node sibling = node.getNextSibling();
        while ((sibling != null) && (sibling.getNodeType() != Node.ELEMENT_NODE)) {
            sibling = sibling.getNextSibling();
        }
        return (Element) sibling;
    }

    static String readFile(String path, Charset encoding) throws IOException {
        byte[] encoded = Files.readAllBytes(Paths.get(path));
        return new String(encoded, encoding);
    }

    static public SOAPMessage sendMessage(SOAPMessage message, String endPoint) throws SOAPException, IOException {
        SOAPMessage result = null;
        if (endPoint != null && message != null) {
            URL url;
            SOAPConnectionFactory scf = SOAPConnectionFactory.newInstance();
            SOAPConnection connection = null;
            try {
                connection = scf.createConnection(); //point-to-point connection
                url = new URL(endPoint);
                HttpsURLConnection con = (HttpsURLConnection) url.openConnection();

                con.connect();
                result = connection.call(message, url);
            } finally {
                if (connection != null) {
                    try {
                        connection.close();
                    } catch (SOAPException soape) {
                        System.out.print("Can't close SOAPConnection:" + soape);
                    }
                }
            }
        }
        return result;
    }

    static public void doTrustToCertificates() throws Exception {
        Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider());
        TrustManager[] trustAllCerts = new TrustManager[]{
                new X509TrustManager() {
                    public X509Certificate[] getAcceptedIssuers() {
                        return null;
                    }

                    public void checkServerTrusted(X509Certificate[] certs, String authType) throws CertificateException {
                        return;
                    }

                    public void checkClientTrusted(X509Certificate[] certs, String authType) throws CertificateException {
                        return;
                    }
                }
        };

        SSLContext sc = SSLContext.getInstance("SSL");
        sc.init(null, trustAllCerts, new SecureRandom());
        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
        HostnameVerifier hv = new HostnameVerifier() {
            public boolean verify(String urlHostName, SSLSession session) {
                if (!urlHostName.equalsIgnoreCase(session.getPeerHost())) {
                    System.out.println("Warning: URL host '" + urlHostName + "' is different to SSLSession host '" + session.getPeerHost() + "'.");
                }
                return true;
            }
        };
        HttpsURLConnection.setDefaultHostnameVerifier(hv);
    }
}

Wireshark告诉我,虽然我使用的是JVM参数-Djavax.net.ssl.keyStore = ...但我没有发送证书。     但我想知道JVM怎么知道我的证书在哪里,因为我可以在jks文件中有很多证书???

1 个答案:

答案 0 :(得分:0)

如果要调用https站点,则默认情况下不必发送证书。服务器必须发送,您的客户端将评估它(通过uri,到期日期,证书链,......)。如果证书有效,您的http客户端应默认接受它。

在其他情况下,您可以将服务器的证书导入到本地密钥库(jks),客户端将接受它,因为您永远不会将“不受信任的”证书导入到本地密钥库。

或者你实现了一个像“谁关心证书?只做它!”的代码。 (链接:telling java to accept self-signed ssl certificate)。 但这不应该用于公共/产品环境(如互联网)