简体   繁体   English

如何将pfx文件转换为jks,然后通过使用wsdl生成的类将其用于签署传出的soap请求

[英]How to convert a pfx file into jks and then use it to sign an outgoing soap request by using the classes generated from a wsdl

I am looking for a code example which shows how to access a secure web service over SSL using a PFX certificate. 我正在寻找一个代码示例,该示例演示如何使用PFX证书通过SSL访问安全的Web服务。 I have the certificate and its password and I started by creating a KeyStore instance using the command mentioned below. 我有证书及其密码,我首先使用下面提到的命令创建KeyStore实例。

keytool -importkeystore -destkeystore "C:\Program Files\Java\jdk1.8.0_131\jre\lib\security\dvs.keystore" -srckeystore "C:\Program Files\Java\jdk1.8.0_131\jre\lib\security\key.pfx" -srcstoretype pkcs12 -deststoretype JKS -srcstorepass *******

I then used wsimport -keep -verbose -extension https://sandpit.dvshub.com.au:19443/Bus/VerificationServiceBus.svc?wsdl command to generate Java files. 然后,我使用了wsimport -keep -verbose -extension https://sandpit.dvshub.com.au:19443/Bus/VerificationServiceBus.svc?wsdl命令来生成Java文件。

After which I created a main class in which I specified several parameters such as the location of these certificates. 之后,我创建了一个主类,在其中指定了几个参数,例如这些证书的位置。

        System.setProperty("javax.net.ssl.trustStore", trustStoreFile);
        System.setProperty("javax.net.ssl.trustStorePassword", trustStorePassword);

        System.setProperty("javax.net.ssl.keyStore", certificateFile);
        System.setProperty("javax.net.ssl.keyStorePassword", certificatePassword);
        System.setProperty("sun.security.ssl.allowUnsafeRenegotiation", "true");

        System.setProperty("javax.net.ssl.keyStore", "C:\\Users\\Administrator\\Desktop\\dvs\\key.pfx");
        System.setProperty("javax.net.ssl.keyStoreType", "PKCS12");
        System.setProperty("javax.net.ssl.keyStorePassword", certificatePassword);

Then I eventually called the web method that was created by wsimport using the service it generated. 然后,我最终调用了由wsimport使用其生成的服务创建的Web方法。

CreatedService service = ServiceFactory/Port/Creator.getCreatedService(); // Where 'CreatedService' and 'ServiceFactory/Port/Creator' were created by wsimport: this code entirely depends on the WSDL provided.
service.[ws method](...);

I then created a handler to keep track of what is being passed inside the header but I cannot see any signature being added to it at all. 然后,我创建了一个处理程序以跟踪标头内部传递的内容,但根本看不到任何签名被添加到标头中。 Am I missing something over here. 我在这想念什么吗? I am only getting request timed out errors. 我只收到请求超时错误。

I have a working example of it in Soap UI so I know that the service is running properly. 我在Soap UI中有一个有效的示例,因此我知道该服务运行正常。

Any help with this would be very much appreciated. 任何帮助,将不胜感激。 Please point me in the right direction as I am ready to try anything at this point. 请随时为我指明正确的方向,因为我随时可以尝试任何事情。

Thanks in advance. 提前致谢。

[Edit] Is WSO2 Application server the way to go : Reference [编辑] WSO2 Application Server是要走的路: 参考

This is where I picked up my current approach Reference 这是我拿起我目前的做法参考

So what I was looking for was a way to sign my soap request, I am going to go into details as to how I managed to generate Java classes using the wsdl that was provided to me, how I managed to generate a Java keystore from the pfx file that was provided to me and then managed to sign the soap request going out using it. 因此,我一直在寻找一种签名我的soap请求的方法,我将详细介绍如何使用提供给我的wsdl生成Java类,以及如何从Java生成Java密钥库。提供给我的pfx文件,然后成功使用它签署了soap请求。

WSDL to Java classes: WSDL到Java类:

So I copied the content of of the wsdl that was hiding behind an ssl certificate to a file and then used the plugin defined in the pom below to generate Java classes. 因此,我将隐藏在ssl证书后面的wsdl的内容复制到文件中,然后使用下面pom中定义的插件生成Java类。 I then moved these classes from the target folder to the src directory. 然后,我将这些类从目标文件夹移至src目录。

pom.xml pom.xml

 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.javacodegeeks.examples.jaxws.client</groupId>
    <artifactId>JavaWsClient</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.6</source>
                    <target>1.6</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.cxf</groupId>
                <artifactId>cxf-codegen-plugin</artifactId>
                <version>3.1.12</version>
                <executions>
                    <execution>
                        <id>generate-sources</id>
                        <phase>generate-sources</phase>
                        <configuration>
                            <sourceRoot>${project.build.directory}/generated/cxf</sourceRoot>
                            <wsdlOptions>
                                <wsdlOption>
                                    <wsdl>${basedir}/src/main/resources/wsdl.xml</wsdl>
                                </wsdlOption>
                            </wsdlOptions>
                        </configuration>
                        <goals>
                            <goal>wsdl2java</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
    <dependencies>
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-frontend-jaxws</artifactId>
            <version>3.1.12</version>
        </dependency>
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-transports-http</artifactId>
            <version>3.1.12</version>
        </dependency>
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-ws-security</artifactId>
            <version>3.1.12</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.apache.cxf/cxf-rt-transports-http-jetty -->
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-transports-http-jetty</artifactId>
            <version>3.1.12</version>
        </dependency>
<!--

        <dependency>
            <groupId>org.springframework.ws</groupId>
            <artifactId>spring-ws-security</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.apache.santuario</groupId>
                    <artifactId>xmlsec</artifactId>
                </exclusion>
            </exclusions>
        </dependency>-->
        <dependency>
            <groupId>org.apache.santuario</groupId>
            <artifactId>xmlsec</artifactId>
            <version>2.0.8</version>
        </dependency>


    </dependencies>
</project>

Using mvn generate-resources would create Java classes in the target folder for you. 使用mvn generate-resources将为您在目标文件夹中创建Java类。

Next step was to convert the pfx file I was provided with into a JavaKeyStore 'JKS'. 下一步是将提供的pfx文件转换为JavaKeyStore'JKS'。 Steps for which are mentioned down below. 步骤如下所述。 You will have to download weblogic to get the jars necessary for the conversion. 您将必须下载weblogic以获得转换所需的jar。

1.Run the following OpenSSL command to extract your certificates and key from the .pfx file: openssl pkcs12 -in yourfilename.pfx -out tempcertfile.crt -nodes You should now have a file called tempcertfile.crt. 1.运行以下OpenSSL命令以从.pfx文件中提取证书和密钥:openssl pkcs12 -in yourfilename.pfx -out tempcertfile.crt -nodes现在,您应该有一个名为tempcertfile.crt的文件。 Open this file with a text editor (such as WordPad). 使用文本编辑器(如写字板)打开此文件。 You will see the private key listed first, followed by your certificate information. 您将首先看到私钥,然后是证书信息。

-----BEGIN RSA PRIVATE KEY-----
(Block of Encrypted Text)
-----END RSA PRIVATE KEY-----

2.Cut and paste all of the private key, including the BEGIN and END tags to a new text file and save it as your_domain_name.key 2.将所有私钥(包括BEGIN和END标记)剪切并粘贴到新的文本文件中,并将其另存为your_domain_name.key

3.The certificates remaining in your tempcertfile.crt will be in the following order: Server Certificate, Root Certificate, and Intermediate Certificate. 3. tempcertfile.crt中剩余的证书将按照以下顺序排列:服务器证书,根证书和中间证书。 However, depending on your .pfx export there could be 2–4 certificates inside the file. 但是,根据您的.pfx导出,文件内可能有2-4个证书。 As long as you exported the certificates correctly, whatever you have in this file are the certificates that you are supposed to have. 只要您正确地导出了证书,此文件中所拥有的就是您应该拥有的证书。

4.Make sure the private key was removed (not just copied and pasted), then save the file as your_domain_name.pem. 4.确保已删除私钥(不仅仅是复制和粘贴),然后将文件另存为your_domain_name.pem。

5Create a identity certificate keystore by running the following two lines as one command in keytool: 5通过在密钥工具中运行以下两行作为一个命令来创建身份证书密钥库:

java utils.ImportPrivateKey -keystore new_identity_keystore.jks -storepass 
YOURPASSWORD -storetype JKS -keypass YOURPASSWORD -alias 
server -certfile tempcertfile.crt -keyfile your_domain_name.key 
-keyfilepass PFXPASSWORD

Remember to replace YOURPASSWORD with your password. 请记住用您的密码替换YOURPASSWORD。 Also replace PFXPASSWORD with the password that you created when you created your .pfx file. 另外,用创建.pfx文件时创建的密码替换PFXPASSWORD。

Reference 参考

Here are the commands that I executed based on the reference. 这是我根据参考执行的命令。

openssl pkcs12 -in "C:\Program Files\Java\jdk1.8.0_131\jre\lib\security\file.pfx" -out "C:\Program Files\Java\jdk1.8.0_131\jre\lib\security\tempcertfile.crt" -nodes

openssl x509 -outform der -in "C:\Program Files\Java\jdk1.8.0_131\jre\lib\security\file.pem" -out "C:\Program Files\Java\jdk1.8.0_131\jre\lib\security\file.der"


java -cp C:\Oracle\Middleware\Oracle_Home\wlserver\server\lib\weblogic.jar utils.ImportPrivateKey -keystore "C:\Program Files\Java\jdk1.8.0_131\jre\lib\security\file.jks" -storepass mypass-storetype JKS -keypass mypass-alias myalias -certfile "C:\Program Files\Java\jdk1.8.0_131\jre\lib\security\file.pem" -keyfile "C:\Program Files\Java\jdk1.8.0_131\jre\lib\security\file.key" -keyfilepass mypass

Next step was to use the jks and sign my outgoing request using cfx. 下一步是使用jks并使用cfx对我的传出请求进行签名。 Here is the Java class along with the configuration file for it. 这是Java类以及它的配置文件。

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package dvstest;


import dvs.common._2014._06.contract.data.Gender;
import dvs.common._2014._06.contract.data.RegistrationState;
import dvs.common._2014._06.contract.data.manager.*;
import dvs.common._2014._06.contract.service.manager.IVerification;
import org.apache.cxf.endpoint.Client;
import org.apache.cxf.endpoint.Endpoint;
import org.apache.cxf.frontend.ClientProxy;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
import org.apache.cxf.transport.http.HTTPConduit;
import org.apache.cxf.transports.http.configuration.HTTPClientPolicy;
import org.apache.cxf.ws.addressing.WSAddressingFeature;
import org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor;
import org.apache.wss4j.dom.WSConstants;
import org.apache.wss4j.dom.handler.WSHandlerConstants;

import javax.xml.bind.JAXBElement;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.XMLGregorianCalendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * @author Sadiq
 */
public class DVSTest {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        try {

            // These params are used to print the soap request going in and out.
            System.setProperty("com.sun.xml.ws.transport.http.client.HttpTransportPipe.dump", "true");
            System.setProperty("com.sun.xml.internal.ws.transport.http.client.HttpTransportPipe.dump", "true");
            System.setProperty("com.sun.xml.ws.transport.http.HttpAdapter.dump", "true");
            System.setProperty("com.sun.xml.internal.ws.transport.http.HttpAdapter.dump", "true");

            //Path to java keystore which holds the ssl certificate, might come in handy later on.
            /*String trustStoreFile = "C:\\Program Files\\Java\\jdk1.8.0_131\\jre\\lib\\security\\cacerts";
            String trustStorePassword = "changeit";


            System.setProperty("javax.net.ssl.trustStore", trustStoreFile);
            System.setProperty("javax.net.ssl.trustStorePassword", trustStorePassword);
            System.setProperty("javax.net.ssl.trustStoreType", "JKS");
            System.setProperty("sun.security.ssl.allowUnsafeRenegotiation", "true");*/


            /*
            This is how we can extra namespaces if needed.

            Map<String, String> nsMap = new HashMap();

            nsMap.put("wsse", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
            nsMap.put("wsu", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd");
            nsMap.put("man", "http://DVS/Common/2014/06/Contract/Service/Manager");
            nsMap.put("man1", "http://DVS/Common/2014/06/Contract/Data/Manager");
            nsMap.put("ds", "http://www.w3.org/2000/09/xmldsig#");
            nsMap.put("ec", "http://www.w3.org/2001/10/xml-exc-c14n#");

            client.getRequestContext().put("soap.env.ns.map", nsMap);
            */


            //Creating a factory and setting the service interface using which we can make soap requests.
            JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
            factory.setServiceClass(IVerification.class);

            //Path to endpoint
            //You can get this path by looking inside the wsdl
            factory.setAddress("https://urlhere/Https");

            //Pointing the post request to be soap12 compliant
            factory.setBindingId("http://schemas.xmlsoap.org/wsdl/soap12/");

            //Adding address feature to the outgoing request, this will add <To><MessageId><ReplyTo> part to soap request.
            factory.getFeatures().add(new WSAddressingFeature());

            //Creating a port for the verification interface using the factory.
            IVerification port = (IVerification) factory.create();

            //Creating client, this will be used to specify various outgoing props.
            Client client = ClientProxy.getClient(port);

            //Setting content type and creating a conduit.
            HTTPConduit http = (HTTPConduit) client.getConduit();
            HTTPClientPolicy httpClientPolicy = new HTTPClientPolicy();
            httpClientPolicy.setContentType("application/soap+xml");
            http.setClient(httpClientPolicy);

            //Endpoint fetched using client
            Endpoint cxfEndpoint = client.getEndpoint();

            //Setting cfx related props
            Map<String, Object> outProps = new HashMap<String, Object>();
            outProps.put(WSHandlerConstants.ACTION, "Signature Timestamp");
            outProps.put(WSHandlerConstants.USER, "myalias");
            outProps.put(WSHandlerConstants.SIG_PROP_FILE, "client_sign.properties");
            //Used to add the digest part to the soap post request
            outProps.put(WSHandlerConstants.SIG_KEY_ID, "DirectReference");
            //Used to sign the <To> element.
            outProps.put(WSHandlerConstants.SIGNATURE_PARTS, "{Element}{http://www.w3.org/2005/08/addressing}To");
            // Password type : plain text
            outProps.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_TEXT);
            // for hashed password use:
            //properties.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_DIGEST);
            // Callback used to retrieve password for given user.
            outProps.put(WSHandlerConstants.PW_CALLBACK_CLASS,
                    ClientPasswordCallback.class.getName());

            //Setting props to post request.
            WSS4JOutInterceptor wssOut = new WSS4JOutInterceptor(outProps);
            cxfEndpoint.getOutInterceptors().add(wssOut);


            System.out.println(passportRequest(port).getVerificationResultCode());

            System.out.println(driverLicenseRequest(port).getVerificationResultCode());



        } catch (Exception ex) {
            Logger.getLogger(DVSTest.class.getName()).log(Level.SEVERE, null, ex);
        }

    }

    /**
     * Sets properties to PassportRequest and makes a soap request using the IVerification object.
     *
     * @param port Needs a IVerification object created by the factory.
     * @return VerificationResponse as a response of soap request.
     * @throws Exception
     */
    public static VerificationResponse passportRequest(IVerification port) throws Exception {

        //Creating a passport request
        PassportRequest request = new PassportRequest();

        //Creating a DVSDate object and the creating a jaxb element to be assigned to the PassportRequest object.
        DVSDate date = new DVSDate();
        date.setDay(1);
        date.setMonth(1);
        date.setYear(2017);
        ObjectFactory objectFactory = new ObjectFactory();
        JAXBElement<DVSDate> documentRequest = objectFactory.createDVSDate(date);
        request.setBirthDate(documentRequest);

        request.setDocumentTypeCode(DocumentType.PP);
        JAXBElement<String> familyName = objectFactory.createCertificateRequestFamilyName2("D");
        request.setFamilyName(familyName);
        JAXBElement<String> givenName = objectFactory.createCertificateRequestGivenName2("T");
        request.setGivenName(givenName);
        request.setOriginatingAgencyCode("1");
        GregorianCalendar c = new GregorianCalendar();
        c.setTime(new Date(System.currentTimeMillis()));
        XMLGregorianCalendar requestDate = DatatypeFactory.newInstance().newXMLGregorianCalendar(c);
        request.setRequestDateTime(requestDate);
        request.setVerificationRequestNumber("1");
        request.setVersionNumber("1");
        JAXBElement<Gender> gender = objectFactory.createPassportRequestGender(Gender.M);
        request.setGender(gender);
        request.setTravelDocumentNumber("1");

        return port.verifyDocument(request);
    }

    /**
     * Sets properties to DriverLicenseRequest and makes a soap request using the IVerification object.
     *
     * @param port Needs a IVerification object created by the factory.
     * @return VerificationResponse as a response of soap request.
     * @throws Exception
     */
    public static VerificationResponse driverLicenseRequest(IVerification port) throws Exception {

        //Creating a passport request
        DriverLicenceRequest request = new DriverLicenceRequest();

        //Creating a DVSDate object and the creating a jaxb element to be assigned to the PassportRequest object.
        DVSDate date = new DVSDate();
        date.setDay(1);
        date.setMonth(1);
        date.setYear(2017);
        ObjectFactory objectFactory = new ObjectFactory();
        JAXBElement<DVSDate> documentRequest = objectFactory.createDVSDate(date);
        request.setBirthDate(documentRequest);

        request.setDocumentTypeCode(DocumentType.DL);
        JAXBElement<String> familyName = objectFactory.createCertificateRequestFamilyName2("D");
        request.setFamilyName(familyName);
        JAXBElement<String> givenName = objectFactory.createCertificateRequestGivenName2("T");
        request.setGivenName(givenName);
        request.setOriginatingAgencyCode("1");
        GregorianCalendar c = new GregorianCalendar();
        c.setTime(new Date(System.currentTimeMillis()));
        XMLGregorianCalendar requestDate = DatatypeFactory.newInstance().newXMLGregorianCalendar(c);
        request.setRequestDateTime(requestDate);
        request.setVerificationRequestNumber("1");
        request.setVersionNumber("1");
        request.setLicenceNumber("1");
        JAXBElement<String> middleName = objectFactory.createDriverLicenceRequestMiddleName("Joseph");
        request.setMiddleName(middleName);

        dvs.common._2014._06.contract.data.ObjectFactory objectFactoryData = new dvs.common._2014._06.contract.data.ObjectFactory();
        JAXBElement<RegistrationState> registrationState = objectFactoryData.createRegistrationState(RegistrationState.NSW);
        request.setStateOfIssue(registrationState.getValue());
        JAXBElement<Gender> gender = objectFactory.createPassportRequestGender(Gender.M);




        return port.verifyDocument(request);
    }


}

client_sign.properties file: client_sign.properties文件:

org.apache.ws.security.crypto.provider=org.apache.ws.security.components.crypto.Merlin
org.apache.ws.security.crypto.merlin.keystore.type=jks
org.apache.ws.security.crypto.merlin.keystore.password=mypass
org.apache.ws.security.crypto.merlin.keystore.alias=myalias
org.apache.ws.security.crypto.merlin.keystore.file=C:\\Program Files\\Java\\jdk1.8.0_131\\jre\\lib\\security\\file.jks

Last but not the least the password callback handler. 最后但并非最不重要的是密码回调处理程序。

package dvstest;

import java.io.IOException;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
import org.apache.wss4j.common.ext.WSPasswordCallback;

public class ClientPasswordCallback implements CallbackHandler {

    @Override
    public void handle(Callback[] callbacks) throws IOException,
            UnsupportedCallbackException {

        WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];

        // set the password for our message.
        pc.setPassword("mypass");
    }

}

I hope this helps somebody. 希望对您有所帮助。 Took me a while to gather all the info that was required. 花了我一段时间来收集所需的所有信息。

Reference2 Reference3 参考2 参考3

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM