Java 如何使用SpringWS客户端使用不同的密钥库调用相同的Web服务

Java 如何使用SpringWS客户端使用不同的密钥库调用相同的Web服务,java,spring,ssl,https,spring-ws,Java,Spring,Ssl,Https,Spring Ws,我有一些应用程序需要在同一个应用服务器上运行。每个应用程序都需要使用特定于该应用程序的证书,通过相同的web服务进行身份验证。 显然,我可以将所有证书放在同一个密钥库中,但是如何指定必须使用哪一个呢? 对于这些调用,我使用的是SpringWebServiceTemplate,我想在SpringXML配置文件中找到一些可以轻松配置的东西 我正试着遵循这一点: 整个概念很清楚,但我不明白如何将其与SpringWebServiceTemplate链接,以及如何在调用中指定我必须使用的证书 我找到了解

我有一些应用程序需要在同一个应用服务器上运行。每个应用程序都需要使用特定于该应用程序的证书,通过相同的web服务进行身份验证。 显然,我可以将所有证书放在同一个密钥库中,但是如何指定必须使用哪一个呢? 对于这些调用,我使用的是SpringWebServiceTemplate,我想在SpringXML配置文件中找到一些可以轻松配置的东西

我正试着遵循这一点:


整个概念很清楚,但我不明白如何将其与SpringWebServiceTemplate链接,以及如何在调用中指定我必须使用的证书

我找到了解决办法。它不是完美的,也不是完全干净的。 我需要更多的测试,以确保它的工作,目前正在运行

这是神奇的FactoryBean“CustomSSLHttpClientFactory.java”

这是控制台输出:

########## Test multy call with different cert in same keystore #############
 ----- ----- CASE OK ----- ----- 
------------------ SitoA ----------------------
HTTP/1.1 200 OK
Response content length: -1
<html>
<head></head>
<body>CARICATO SITO A</body>
</html>
------------------ SitoB ----------------------
HTTP/1.1 200 OK
Response content length: -1
<html>
<head></head>
<body>CARICATO SITO B</body>
</html>
 ----- ----- CASE KO ----- ----- 
------------------ SitoA ----------------------
HTTP/1.1 401 Unauthorized
Response content length: 6319
java.util.UnknownFormatConversionException: Conversion = ';'
    at java.util.Formatter.checkText(Formatter.java:2547)
    at java.util.Formatter.parse(Formatter.java:2523)
    at java.util.Formatter.format(Formatter.java:2469)
    at java.io.PrintStream.format(PrintStream.java:970)
    at java.io.PrintStream.printf(PrintStream.java:871)
    at foo.bar.runnable.RunTestHttpClient.testLogic(RunTestHttpClient.java:70)
    at foo.bar.runnable.RunTestHttpClient.main(RunTestHttpClient.java:32)
------------------ SitoB ----------------------
HTTP/1.1 401 Unauthorized
Response content length: 6320
java.util.UnknownFormatConversionException: Conversion = ';'
    at java.util.Formatter.checkText(Formatter.java:2547)
    at java.util.Formatter.parse(Formatter.java:2523)
    at java.util.Formatter.format(Formatter.java:2469)
    at java.io.PrintStream.format(PrintStream.java:970)
    at java.io.PrintStream.printf(PrintStream.java:871)
    at foo.bar.runnable.RunTestHttpClient.testLogic(RunTestHttpClient.java:97)
    at foo.bar.runnable.RunTestHttpClient.main(RunTestHttpClient.java:32)
########## Test multy call with different keystore #############
 ----- ----- CASE OK ----- ----- 
------------------ SitoA ----------------------
HTTP/1.1 200 OK
Response content length: -1
<html>
<head></head>
<body>CARICATO SITO A</body>
</html>
------------------ SitoB ----------------------
HTTP/1.1 200 OK
Response content length: -1
<html>
<head></head>
<body>CARICATO SITO B</body>
</html>
 ----- ----- CASE KO ----- ----- 
------------------ SitoA ----------------------
HTTP/1.1 401 Unauthorized
Response content length: 6319
java.util.UnknownFormatConversionException: Conversion = ';'
    at java.util.Formatter.checkText(Formatter.java:2547)
    at java.util.Formatter.parse(Formatter.java:2523)
    at java.util.Formatter.format(Formatter.java:2469)
    at java.io.PrintStream.format(PrintStream.java:970)
    at java.io.PrintStream.printf(PrintStream.java:871)
    at foo.bar.runnable.RunTestHttpClient.testLogic(RunTestHttpClient.java:70)
    at foo.bar.runnable.RunTestHttpClient.main(RunTestHttpClient.java:37)
------------------ SitoB ----------------------
HTTP/1.1 401 Unauthorized
Response content length: 6320
java.util.UnknownFormatConversionException: Conversion = ';'
    at java.util.Formatter.checkText(Formatter.java:2547)
    at java.util.Formatter.parse(Formatter.java:2523)
    at java.util.Formatter.format(Formatter.java:2469)
    at java.io.PrintStream.format(PrintStream.java:970)
    at java.io.PrintStream.printf(PrintStream.java:871)
    at foo.bar.runnable.RunTestHttpClient.testLogic(RunTestHttpClient.java:97)
    at foo.bar.runnable.RunTestHttpClient.main(RunTestHttpClient.java:37)
在同一密钥库中使用不同的证书测试多个呼叫#############
----------案例正常------
------------------西托亚----------------------
HTTP/1.1200ok
响应内容长度:-1
加拉卡托斯托A酒店
------------------锡托布----------------------
HTTP/1.1200ok
响应内容长度:-1
加拉卡托斯托B酒店
----------案例KO------
------------------西托亚----------------------
HTTP/1.1 401未经授权
回应内容长度:6319
java.util.UnknownFormatConversionException:转换=';'
位于java.util.Formatter.checkText(Formatter.java:2547)
位于java.util.Formatter.parse(Formatter.java:2523)
位于java.util.Formatter.format(Formatter.java:2469)
位于java.io.PrintStream.format(PrintStream.java:970)
位于java.io.PrintStream.printf(PrintStream.java:871)
位于foo.bar.runnable.RunTestHttpClient.testLogic(RunTestHttpClient.java:70)
位于foo.bar.runnable.RunTestHttpClient.main(RunTestHttpClient.java:32)
------------------锡托布----------------------
HTTP/1.1 401未经授权
回应内容长度:6320
java.util.UnknownFormatConversionException:转换=';'
位于java.util.Formatter.checkText(Formatter.java:2547)
位于java.util.Formatter.parse(Formatter.java:2523)
位于java.util.Formatter.format(Formatter.java:2469)
位于java.io.PrintStream.format(PrintStream.java:970)
位于java.io.PrintStream.printf(PrintStream.java:871)
位于foo.bar.runnable.RunTestHttpClient.testLogic(RunTestHttpClient.java:97)
位于foo.bar.runnable.RunTestHttpClient.main(RunTestHttpClient.java:32)
##########使用不同的密钥库测试多个调用#############
----------案例正常------
------------------西托亚----------------------
HTTP/1.1200ok
响应内容长度:-1
加拉卡托斯托A酒店
------------------锡托布----------------------
HTTP/1.1200ok
响应内容长度:-1
加拉卡托斯托B酒店
----------案例KO------
------------------西托亚----------------------
HTTP/1.1 401未经授权
回应内容长度:6319
java.util.UnknownFormatConversionException:转换=';'
位于java.util.Formatter.checkText(Formatter.java:2547)
位于java.util.Formatter.parse(Formatter.java:2523)
位于java.util.Formatter.format(Formatter.java:2469)
位于java.io.PrintStream.format(PrintStream.java:970)
位于java.io.PrintStream.printf(PrintStream.java:871)
位于foo.bar.runnable.RunTestHttpClient.testLogic(RunTestHttpClient.java:70)
位于foo.bar.runnable.RunTestHttpClient.main(RunTestHttpClient.java:37)
------------------锡托布----------------------
HTTP/1.1 401未经授权
回应内容长度:6320
java.util.UnknownFormatConversionException:转换=';'
位于java.util.Formatter.checkText(Formatter.java:2547)
位于java.util.Formatter.parse(Formatter.java:2523)
位于java.util.Formatter.format(Formatter.java:2469)
位于java.io.PrintStream.format(PrintStream.java:970)
位于java.io.PrintStream.printf(PrintStream.java:871)
位于foo.bar.runnable.RunTestHttpClient.testLogic(RunTestHttpClient.java:97)
位于foo.bar.runnable.RunTestHttpClient.main(RunTestHttpClient.java:37)

我在通过SSL调用WS时遇到了类似的问题。我在我的项目中使用了SpringWebService

在组件类下面创建,该组件类在启动时将ssl证书和pwd加载到系统变量中,仅此而已。希望这对将来的人有帮助

@Component
public class WsVariableLoader
{
  @Value("${keystore.filename}")
  private String keystoreFilename;

  @Value("${keystore.password}")
  private String keystorePassword;

  @PostConstruct
  public void init()
  {
    System.setProperty("javax.net.ssl.trustStore", keystoreFilename);
    System.setProperty("javax.net.ssl.trustStorePassword", keystorePassword);
    System.setProperty("javax.net.ssl.keyStore", keystoreFilename);
    System.setProperty("javax.net.ssl.keyStorePassword", keystorePassword);
}

}

有一种比使用自定义HTTP客户端工厂bean更简单的方法,它可以手动设置SSL上下文并使用拦截器删除内容长度头(如果你问我的话,请使用little Hokie)

Spring有一个HttpsUrlConnectionMessageSender,它将自动正确设置SSLContext,并允许您通过KeyStoreManager和TrustStoreManager指定不同的密钥库和信任库。这种方法使从客户端进行相互SSL身份验证变得更加清晰

public class MyWebServiceClient extends WebServiceGatewaySupport implements MyWebServicePortType {

@Configuration
public static class MyClientConfig {
    @Value("${myws.endpoint.url}")
    private String url;

    @Value("${myws.keystore}")
    private Resource keyStore;
    @Value("${myws.keystore.password}")
    private String keyStorePass;
    @Value("${myws.truststore}")
    private Resource trustStore;
    @Value("${myws.truststore.password}")
    private String trustStorePass;

    @Bean 
    public Jaxb2Marshaller myWebServiceClientMarshaller() {
        Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
        marshaller.setContextPath("com.myws.types");
        return marshaller;
    }

    @Bean
    public MyWebServiceClient myWebServiceClient() throws Exception {
        MyWebServiceClient client = new MyWebServiceClient();
        client.setDefaultUri(this.url);
        client.setMarshaller(myWebServiceClientMarshaller());
        client.setUnmarshaller(myWebServiceClientMarshaller());

        KeyStore ks = KeyStore.getInstance("JKS");
        ks.load(keyStore.getInputStream(), keyStorePass.toCharArray());
        logger.info("Loaded keyStore: "+keyStore.getURI().toString());
        try { keyStore.getInputStream().close(); } catch(IOException e) {}
        KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
        keyManagerFactory.init(ks, keyStorePass.toCharArray());

        KeyStore ts = KeyStore.getInstance("JKS");
        ts.load(trustStore.getInputStream(), trustStorePass.toCharArray());
        logger.info("Loaded trustStore: "+trustStore.getURI().toString());
        try { trustStore.getInputStream().close(); } catch(IOException e) {}
        TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        trustManagerFactory.init(ts);

        HttpsUrlConnectionMessageSender msgSender = new HttpsUrlConnectionMessageSender();
        msgSender.setKeyManagers(keyManagerFactory.getKeyManagers());
        msgSender.setTrustManagers(trustManagerFactory.getTrustManagers());

        client.setMessageSender(msgSender);

        return client;
    }


    // client port method implementations ...
    public MyOperationResponse processMyOperation(MyOperationRequest request) {
        return (MyOperationResponse) getWebServiceTemplate().marshalSendAndReceive(request, new SoapActionCallback("urn:ProcessMyOperation"));
    }

}

在xml配置中发现一个缺少的bean id的小错误。编辑答案请注意,HttpsUrlConnectionMessageSender在SpringWS支持包中!e、 g.org.springframework.ws:springws-support:2.1.4.release您可以发布同一解决方案的xml配置示例吗?我很感兴趣,但我们不能在我们的项目中使用类配置
########## Test multy call with different cert in same keystore #############
 ----- ----- CASE OK ----- ----- 
------------------ SitoA ----------------------
HTTP/1.1 200 OK
Response content length: -1
<html>
<head></head>
<body>CARICATO SITO A</body>
</html>
------------------ SitoB ----------------------
HTTP/1.1 200 OK
Response content length: -1
<html>
<head></head>
<body>CARICATO SITO B</body>
</html>
 ----- ----- CASE KO ----- ----- 
------------------ SitoA ----------------------
HTTP/1.1 401 Unauthorized
Response content length: 6319
java.util.UnknownFormatConversionException: Conversion = ';'
    at java.util.Formatter.checkText(Formatter.java:2547)
    at java.util.Formatter.parse(Formatter.java:2523)
    at java.util.Formatter.format(Formatter.java:2469)
    at java.io.PrintStream.format(PrintStream.java:970)
    at java.io.PrintStream.printf(PrintStream.java:871)
    at foo.bar.runnable.RunTestHttpClient.testLogic(RunTestHttpClient.java:70)
    at foo.bar.runnable.RunTestHttpClient.main(RunTestHttpClient.java:32)
------------------ SitoB ----------------------
HTTP/1.1 401 Unauthorized
Response content length: 6320
java.util.UnknownFormatConversionException: Conversion = ';'
    at java.util.Formatter.checkText(Formatter.java:2547)
    at java.util.Formatter.parse(Formatter.java:2523)
    at java.util.Formatter.format(Formatter.java:2469)
    at java.io.PrintStream.format(PrintStream.java:970)
    at java.io.PrintStream.printf(PrintStream.java:871)
    at foo.bar.runnable.RunTestHttpClient.testLogic(RunTestHttpClient.java:97)
    at foo.bar.runnable.RunTestHttpClient.main(RunTestHttpClient.java:32)
########## Test multy call with different keystore #############
 ----- ----- CASE OK ----- ----- 
------------------ SitoA ----------------------
HTTP/1.1 200 OK
Response content length: -1
<html>
<head></head>
<body>CARICATO SITO A</body>
</html>
------------------ SitoB ----------------------
HTTP/1.1 200 OK
Response content length: -1
<html>
<head></head>
<body>CARICATO SITO B</body>
</html>
 ----- ----- CASE KO ----- ----- 
------------------ SitoA ----------------------
HTTP/1.1 401 Unauthorized
Response content length: 6319
java.util.UnknownFormatConversionException: Conversion = ';'
    at java.util.Formatter.checkText(Formatter.java:2547)
    at java.util.Formatter.parse(Formatter.java:2523)
    at java.util.Formatter.format(Formatter.java:2469)
    at java.io.PrintStream.format(PrintStream.java:970)
    at java.io.PrintStream.printf(PrintStream.java:871)
    at foo.bar.runnable.RunTestHttpClient.testLogic(RunTestHttpClient.java:70)
    at foo.bar.runnable.RunTestHttpClient.main(RunTestHttpClient.java:37)
------------------ SitoB ----------------------
HTTP/1.1 401 Unauthorized
Response content length: 6320
java.util.UnknownFormatConversionException: Conversion = ';'
    at java.util.Formatter.checkText(Formatter.java:2547)
    at java.util.Formatter.parse(Formatter.java:2523)
    at java.util.Formatter.format(Formatter.java:2469)
    at java.io.PrintStream.format(PrintStream.java:970)
    at java.io.PrintStream.printf(PrintStream.java:871)
    at foo.bar.runnable.RunTestHttpClient.testLogic(RunTestHttpClient.java:97)
    at foo.bar.runnable.RunTestHttpClient.main(RunTestHttpClient.java:37)
@Component
public class WsVariableLoader
{
  @Value("${keystore.filename}")
  private String keystoreFilename;

  @Value("${keystore.password}")
  private String keystorePassword;

  @PostConstruct
  public void init()
  {
    System.setProperty("javax.net.ssl.trustStore", keystoreFilename);
    System.setProperty("javax.net.ssl.trustStorePassword", keystorePassword);
    System.setProperty("javax.net.ssl.keyStore", keystoreFilename);
    System.setProperty("javax.net.ssl.keyStorePassword", keystorePassword);
}
public class MyWebServiceClient extends WebServiceGatewaySupport implements MyWebServicePortType {

@Configuration
public static class MyClientConfig {
    @Value("${myws.endpoint.url}")
    private String url;

    @Value("${myws.keystore}")
    private Resource keyStore;
    @Value("${myws.keystore.password}")
    private String keyStorePass;
    @Value("${myws.truststore}")
    private Resource trustStore;
    @Value("${myws.truststore.password}")
    private String trustStorePass;

    @Bean 
    public Jaxb2Marshaller myWebServiceClientMarshaller() {
        Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
        marshaller.setContextPath("com.myws.types");
        return marshaller;
    }

    @Bean
    public MyWebServiceClient myWebServiceClient() throws Exception {
        MyWebServiceClient client = new MyWebServiceClient();
        client.setDefaultUri(this.url);
        client.setMarshaller(myWebServiceClientMarshaller());
        client.setUnmarshaller(myWebServiceClientMarshaller());

        KeyStore ks = KeyStore.getInstance("JKS");
        ks.load(keyStore.getInputStream(), keyStorePass.toCharArray());
        logger.info("Loaded keyStore: "+keyStore.getURI().toString());
        try { keyStore.getInputStream().close(); } catch(IOException e) {}
        KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
        keyManagerFactory.init(ks, keyStorePass.toCharArray());

        KeyStore ts = KeyStore.getInstance("JKS");
        ts.load(trustStore.getInputStream(), trustStorePass.toCharArray());
        logger.info("Loaded trustStore: "+trustStore.getURI().toString());
        try { trustStore.getInputStream().close(); } catch(IOException e) {}
        TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        trustManagerFactory.init(ts);

        HttpsUrlConnectionMessageSender msgSender = new HttpsUrlConnectionMessageSender();
        msgSender.setKeyManagers(keyManagerFactory.getKeyManagers());
        msgSender.setTrustManagers(trustManagerFactory.getTrustManagers());

        client.setMessageSender(msgSender);

        return client;
    }


    // client port method implementations ...
    public MyOperationResponse processMyOperation(MyOperationRequest request) {
        return (MyOperationResponse) getWebServiceTemplate().marshalSendAndReceive(request, new SoapActionCallback("urn:ProcessMyOperation"));
    }

}