编写一个Spring Boot WSDL * client *,它提供了一个用于身份验证的证书

时间:2015-10-23 15:10:07

标签: ssl wsdl spring-boot spring-ws

我正在使用Java 1.8上的Spring Boot v 1.2.7.RELEASE编写服务器。我的代码完全配有注释,目前除了Maven pom之外没有其他XML。

My Spring Boot服务器必须查询WSDL服务器以对用户进行身份验证。在此上下文中,我的服务器是WSDL服务的客户端。我的应用程序需要向WS服务器提供证书以对自身进行身份验证并获取访问权限,然后进行查询。所以,我有一个带有我的应用程序证书的JKS和一个服务器信任库JKS。

此外,与WS服务器的连接是通过https完成的,但我认为这是由WebServiceGatewaySupport处理的。

我找到了许多WS客户端的例子,以及在Spring Boot中将SSL配置为服务器的许多示例,但没有显示如何将SSL用作客户端。在我的研究中,我看到的页面暗示这可以通过一些注释来完成,但没有具体的内容。

我认为这一定是可能的,非常感谢任何帮助,谢谢!

1 个答案:

答案 0 :(得分:0)

以下是我使用的Apache HttpClient 4.5.2:

import java.io.IOException;
import java.io.InputStream;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.util.Arrays;
import java.util.List;

import javax.net.ssl.SSLContext;

import org.apache.http.Header;
import org.apache.http.HttpHeaders;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.Credentials;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.conn.socket.LayeredConnectionSocketFactory;
import org.apache.http.conn.ssl.DefaultHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.message.BasicHeader;
import org.apache.http.ssl.SSLContexts;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.oxm.jaxb.Jaxb2Marshaller;
import org.springframework.ws.WebServiceMessageFactory;
import org.springframework.ws.pox.dom.DomPoxMessageFactory;
import org.springframework.ws.transport.WebServiceMessageSender;
import org.springframework.ws.transport.http.HttpComponentsMessageSender;
import org.springframework.ws.transport.http.MessageDispatcherServlet;

@Configuration
class ApplicationIntegrationTestConfiguration {
    @Value("${lcm.request.endpoint}")
    private String endpointUri;
    @Value("${lcm.request.keystorepath}")
    private Resource keyStore;
    @Value("${lcm.request.keystorepass}")
    private char[] keyStorePass;
    @Value("${lcm.request.keystoretype}")
    private String keyStoreType;
    @Value("${lcm.request.truststorepath}")
    private Resource trustStore;
    @Value("${lcm.request.truststorepass}")
    private char[] trustStorePass;
    @Value("${lcm.request.truststoretype}")
    private String trustStoreType;

    private static final String ACCEPT_HEADER_VALUE = "application/xml";
    @Bean
    public WebServiceMessageSender messageSender(
            LayeredConnectionSocketFactory factory) throws Exception {
        Header header = new BasicHeader(HttpHeaders.ACCEPT, ACCEPT_HEADER_VALUE);
        List<Header> defaultHeaders = Arrays.asList(header);
        CloseableHttpClient client = HttpClientBuilder.create()
            .setSSLSocketFactory(factory)
            .setDefaultHeaders(defaultHeaders)
            .build();

        HttpComponentsMessageSender messageSender = new HttpComponentsMessageSender(
                client);

        // needed if used as a standalone client
        //messageSender.afterPropertiesSet(); 
        return messageSender;
    }
    @Bean
    public LayeredConnectionSocketFactory sslFactory() {
        try {
            final KeyStore keystore = KeyStore.getInstance(this.keyStoreType);
            try (InputStream readStream = this.keyStore.getInputStream()) {
                keystore.load(readStream, this.keyStorePass);
            }

            final KeyStore truststore = KeyStore.getInstance(this.trustStoreType);
            try (InputStream readStream = this.trustStore.getInputStream()) {
                truststore.load(readStream, this.trustStorePass);
            } 

            SSLContext sslContext = SSLContexts
                    .custom()
                    .loadTrustMaterial(truststore, null)
                    .loadKeyMaterial(keystore, this.keyStorePass)
                    .build();
            SSLConnectionSocketFactory sslConnectionFactory = new SSLConnectionSocketFactory(sslContext,
                    new DefaultHostnameVerifier()
                    );
            return sslConnectionFactory;
        } catch (KeyManagementException | UnrecoverableKeyException |
                NoSuchAlgorithmException | KeyStoreException
                | CertificateException | IOException e) {
            throw new IllegalArgumentException(String.format("Problem with keystore %s or truststore %s",
                    this.keyStore, this.trustStore), e);
        }
    }
    @Bean
    public PingClient pingClient(Jaxb2Marshaller marshaller,
            WebServiceMessageFactory messageFactory, WebServiceMessageSender messageSender) {
        PingClient client = new PingClient();
        client.setDefaultUri(this.endpointUri + "/Ping/v1");
        client.setMarshaller(marshaller);
        client.setUnmarshaller(marshaller);
        client.setMessageFactory(messageFactory);
        client.setMessageSender(messageSender);
        return client;
    }

    // this bean is the key in selecting between SOAP and POX (plain old XML)
    @Bean(name = MessageDispatcherServlet.DEFAULT_MESSAGE_FACTORY_BEAN_NAME)
    public WebServiceMessageFactory messageFactory() {
        return new DomPoxMessageFactory();
    }

    @Bean
    public Jaxb2Marshaller marshaller() {
        Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
        marshaller.setPackagesToScan("my.packages");
        return marshaller;
    }
}

我还有一个示例项目执行几乎相同的here,同样添加了使用基本身份验证凭据here。他们没有密钥库或信任库(因为它很难获得那些可发布的版本),但他们应该帮忙。

请注意,您不能将.jks用于客户端证书,您必须转换为.jceks密钥库格式。