编写一个 Spring 引导 WSDL *客户端*,提供用于身份验证的证书
Writing a Spring Boot WSDL *client* that presents a certificate for authentication
我正在使用 Spring Boot v 1.2.7.RELEASE 在 Java 1.8 上编写服务器。我的代码完全配置了注释,目前没有 XML 除了 Maven pom。
我的 Spring 引导服务器必须查询 WSDL 服务器来验证用户。在此上下文中,我的服务器是 WSDL 服务的客户端。我的应用程序需要向 WS 服务器出示证书以对自身进行身份验证并获得访问权限,然后进行查询。所以,我有一个带有我的应用程序证书的 JKS 和一个服务器信任库 JKS。
此外,与 WS 服务器的连接是通过 https 完成的,但我认为这是由 WebServiceGatewaySupport 处理的。
我找到了很多 WS 客户端的例子,在 Spring 作为服务器启动中找到了很多配置 SSL 的例子,但是 none 展示了如何使用 SSL 作为客户端。在我的研究中,我看到一些页面暗示这可以通过一些注释来完成,但没有具体说明。
我认为这一定是可能的,任何帮助将不胜感激,谢谢!
这是我所拥有的,使用 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, and same with addition of using basic auth credentials here。他们没有适当的密钥库或信任库(因为很难获得这些的可发布版本),但他们应该提供帮助。
请注意,您不能将 .jks 用于客户端证书,您必须转换为 .jceks 密钥库格式。
我正在使用 Spring Boot v 1.2.7.RELEASE 在 Java 1.8 上编写服务器。我的代码完全配置了注释,目前没有 XML 除了 Maven pom。
我的 Spring 引导服务器必须查询 WSDL 服务器来验证用户。在此上下文中,我的服务器是 WSDL 服务的客户端。我的应用程序需要向 WS 服务器出示证书以对自身进行身份验证并获得访问权限,然后进行查询。所以,我有一个带有我的应用程序证书的 JKS 和一个服务器信任库 JKS。
此外,与 WS 服务器的连接是通过 https 完成的,但我认为这是由 WebServiceGatewaySupport 处理的。
我找到了很多 WS 客户端的例子,在 Spring 作为服务器启动中找到了很多配置 SSL 的例子,但是 none 展示了如何使用 SSL 作为客户端。在我的研究中,我看到一些页面暗示这可以通过一些注释来完成,但没有具体说明。
我认为这一定是可能的,任何帮助将不胜感激,谢谢!
这是我所拥有的,使用 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, and same with addition of using basic auth credentials here。他们没有适当的密钥库或信任库(因为很难获得这些的可发布版本),但他们应该提供帮助。
请注意,您不能将 .jks 用于客户端证书,您必须转换为 .jceks 密钥库格式。