如何配置 wildfly 在 resteasy 中将 https 与 ClientBuilder 一起使用?
How to configure wildfly to use https with ClientBuilder in resteasy?
这是我第一次收到连接到 https url 的要求。很快,我就知道我需要 SSLContext
才能通过。
我也开始知道我需要在standalone.xml中进行配置才能完成。
任何指向 solution/link 工作代码的指针都将不胜感激。
我们必须自己生成密钥库吗?或 wildfly 提供任何现有的?
这是我试过的:
SSLContext context = null;
KeyManagerFactory kmf = null;
KeyStore ks = null;
char[] storepass = "somestringhere".toCharArray();
char[] keypass = "somestringhere".toCharArray();
try {
context = SSLContext.getInstance("SSL");
} catch (NoSuchAlgorithmException e3) {
// TODO Auto-generated catch block
e3.printStackTrace();
}
try {
kmf = KeyManagerFactory.getInstance("SunX509");
} catch (NoSuchAlgorithmException e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
}
FileInputStream fin = null;
try {
fin = new FileInputStream("file here");
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
ks = KeyStore.getInstance("JKS");
} catch (KeyStoreException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
ks.load(fin, storepass);
} catch (NoSuchAlgorithmException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (CertificateException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
try {
kmf.init(ks, keypass);
} catch (UnrecoverableKeyException | KeyStoreException | NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
context.init(kmf.getKeyManagers(), null, null);
} catch (KeyManagementException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Client client = ClientBuilder.newBuilder().sslContext(context).build();
WebTarget target = client
.target("https://....");
Builder builder = target.request();
我试了https://whosebug.com,它给了200OK,我试了google.com,它说文档已经移动了302状态。我尝试了我想要连接的 url 我得到了 peer not authenticated exception
Caused by: javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated
at sun.security.ssl.SSLSessionImpl.getPeerCertificates(SSLSessionImpl.java:421) [jsse.jar:1.7.0_71]
at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:128) [httpclient-4.2.5.jar:4.2.5]
at org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:572) [httpclient-4.2.5.jar:4.2.5]
at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:180) [httpclient-4.2.5.jar:4.2.5]
at org.apache.http.impl.conn.ManagedClientConnectionImpl.open(ManagedClientConnectionImpl.java:294) [httpclient-4.2.5.jar:4.2.5]
at org.apache.http.impl.client.DefaultRequestDirector.tryConnect(DefaultRequestDirector.java:640) [httpclient-4.2.5.jar:4.2.5]
at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:479) [httpclient-4.2.5.jar:4.2.5]
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:906) [httpclient-4.2.5.jar:4.2.5]
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:805) [httpclient-4.2.5.jar:4.2.5]
at org.jboss.resteasy.client.jaxrs.engines.ApacheHttpClient4Engine.invoke(ApacheHttpClient4Engine.java:283) [resteasy-client-3.0.6.Final.jar:]
... 30 more
而且服务器要求基本认证,是不是异常的原因?
"Do we have to generate keystores ourselves?"
是的。需要为Server 和Trust store 生成一个(也就是key store,我们只是叫它trust store 来区别)
请参阅 Wildfly 文档中的 SSL setup guide。它将向您展示如何创建密钥库并使用 Wildfly 配置它。只需按照 "Pure Java SSL-Setup using keytool"
部分
然后您需要创建客户端密钥库。您将从服务器存储中导出证书并将其导入到客户端存储中。
它的工作原理是 Client
需要信任服务器。而做到这一点的方法是通过服务器证书。现在如果证书是由知名 CA 签发的,通常 Java 已经支持该证书,我们不需要配置客户端。但是由于您要创建自己的自签名证书,我们需要将客户端配置为通过将服务器证书导入信任库来信任它。
您可以在此处 查看为客户端 和 服务器处理 certs/stores 的所有步骤。向下滚动到第 5 步。以 keytool
开头的三个代码片段是完成此任务的命令。第一个创建名为 tomcat-keystore.jks
的服务器存储(但您可以随意命名)。下一个片段将证书从密钥库导出到一个文件名 tomcat.crt
(但你可以随意命名)。第三个命令会将之前的证书导入 client-truststore.jks
(但您可以随意命名)。您会注意到您不需要显式创建信任库,它会在我们进行导入时隐式创建。
获得服务器密钥库后,按照上面链接的 wildfly 文档中的说明使用服务器配置存储。
要配置 Client
,请参阅上面链接的答案中的第 6 步。它使用我们创建的信任库配置客户端。代码中的所有内容都是标准的 Java 和 JAX-RS,除了 Basic auth 的配置,这是 Jersey 特有的。
这是我使用 Wildly 10.Note 将 JAX-RS 与 HTTPS 结合使用的代码,JAX-RS 的 Wildly 实现是 RestEasy 3.xxxx.
ClientBuilder builder = ClientBuilder.newBuilder();
builder.sslContext(ConnectionFactory.getSslContext());
builder.hostnameVerifier(ConnectionFactory.getHostnameVerifier());
client = builder.build();
String baseURI = acsUser.getSelectedService().getWebserviceBaseUrl();
WebTarget webTarget = client.target(baseURI);
这里是 class 调用的 ConnectionFactory。
public class ConnectionFactory {
Proxy proxy;
String proxyHost;
Integer proxyPort;
public boolean canConnect = true;
private static final Logger log = Logger.getLogger("ReportPortal");
public ConnectionFactory() {
}
/**
*
* @return
*/
public static SSLContext getSslContext() {
SSLContext sslContext = null;
try {
sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, new TrustManager[]{new SecureTrustManager()}, new SecureRandom());
}
catch (NoSuchAlgorithmException | KeyManagementException ex) {
log.error("ERROR OCCURS", ex);
}
return sslContext;
}
/**
*
* @return
*/
public static HostnameVerifier getHostnameVerifier() {
return (String hostname, javax.net.ssl.SSLSession sslSession) -> true;
}
public Boolean isHttps(String url) {
if (url.startsWith("https://")) {
return Boolean.TRUE;
}
else {
return Boolean.FALSE;
}
}
}
这是我第一次收到连接到 https url 的要求。很快,我就知道我需要 SSLContext
才能通过。
我也开始知道我需要在standalone.xml中进行配置才能完成。
任何指向 solution/link 工作代码的指针都将不胜感激。
我们必须自己生成密钥库吗?或 wildfly 提供任何现有的?
这是我试过的:
SSLContext context = null;
KeyManagerFactory kmf = null;
KeyStore ks = null;
char[] storepass = "somestringhere".toCharArray();
char[] keypass = "somestringhere".toCharArray();
try {
context = SSLContext.getInstance("SSL");
} catch (NoSuchAlgorithmException e3) {
// TODO Auto-generated catch block
e3.printStackTrace();
}
try {
kmf = KeyManagerFactory.getInstance("SunX509");
} catch (NoSuchAlgorithmException e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
}
FileInputStream fin = null;
try {
fin = new FileInputStream("file here");
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
ks = KeyStore.getInstance("JKS");
} catch (KeyStoreException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
ks.load(fin, storepass);
} catch (NoSuchAlgorithmException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (CertificateException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
try {
kmf.init(ks, keypass);
} catch (UnrecoverableKeyException | KeyStoreException | NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
context.init(kmf.getKeyManagers(), null, null);
} catch (KeyManagementException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Client client = ClientBuilder.newBuilder().sslContext(context).build();
WebTarget target = client
.target("https://....");
Builder builder = target.request();
我试了https://whosebug.com,它给了200OK,我试了google.com,它说文档已经移动了302状态。我尝试了我想要连接的 url 我得到了 peer not authenticated exception
Caused by: javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated
at sun.security.ssl.SSLSessionImpl.getPeerCertificates(SSLSessionImpl.java:421) [jsse.jar:1.7.0_71]
at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:128) [httpclient-4.2.5.jar:4.2.5]
at org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:572) [httpclient-4.2.5.jar:4.2.5]
at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:180) [httpclient-4.2.5.jar:4.2.5]
at org.apache.http.impl.conn.ManagedClientConnectionImpl.open(ManagedClientConnectionImpl.java:294) [httpclient-4.2.5.jar:4.2.5]
at org.apache.http.impl.client.DefaultRequestDirector.tryConnect(DefaultRequestDirector.java:640) [httpclient-4.2.5.jar:4.2.5]
at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:479) [httpclient-4.2.5.jar:4.2.5]
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:906) [httpclient-4.2.5.jar:4.2.5]
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:805) [httpclient-4.2.5.jar:4.2.5]
at org.jboss.resteasy.client.jaxrs.engines.ApacheHttpClient4Engine.invoke(ApacheHttpClient4Engine.java:283) [resteasy-client-3.0.6.Final.jar:]
... 30 more
而且服务器要求基本认证,是不是异常的原因?
"Do we have to generate keystores ourselves?"
是的。需要为Server 和Trust store 生成一个(也就是key store,我们只是叫它trust store 来区别)
请参阅 Wildfly 文档中的 SSL setup guide。它将向您展示如何创建密钥库并使用 Wildfly 配置它。只需按照 "Pure Java SSL-Setup using keytool"
部分然后您需要创建客户端密钥库。您将从服务器存储中导出证书并将其导入到客户端存储中。
它的工作原理是 Client
需要信任服务器。而做到这一点的方法是通过服务器证书。现在如果证书是由知名 CA 签发的,通常 Java 已经支持该证书,我们不需要配置客户端。但是由于您要创建自己的自签名证书,我们需要将客户端配置为通过将服务器证书导入信任库来信任它。
您可以在此处 keytool
开头的三个代码片段是完成此任务的命令。第一个创建名为 tomcat-keystore.jks
的服务器存储(但您可以随意命名)。下一个片段将证书从密钥库导出到一个文件名 tomcat.crt
(但你可以随意命名)。第三个命令会将之前的证书导入 client-truststore.jks
(但您可以随意命名)。您会注意到您不需要显式创建信任库,它会在我们进行导入时隐式创建。
获得服务器密钥库后,按照上面链接的 wildfly 文档中的说明使用服务器配置存储。
要配置 Client
,请参阅上面链接的答案中的第 6 步。它使用我们创建的信任库配置客户端。代码中的所有内容都是标准的 Java 和 JAX-RS,除了 Basic auth 的配置,这是 Jersey 特有的。
这是我使用 Wildly 10.Note 将 JAX-RS 与 HTTPS 结合使用的代码,JAX-RS 的 Wildly 实现是 RestEasy 3.xxxx.
ClientBuilder builder = ClientBuilder.newBuilder();
builder.sslContext(ConnectionFactory.getSslContext());
builder.hostnameVerifier(ConnectionFactory.getHostnameVerifier());
client = builder.build();
String baseURI = acsUser.getSelectedService().getWebserviceBaseUrl();
WebTarget webTarget = client.target(baseURI);
这里是 class 调用的 ConnectionFactory。
public class ConnectionFactory {
Proxy proxy;
String proxyHost;
Integer proxyPort;
public boolean canConnect = true;
private static final Logger log = Logger.getLogger("ReportPortal");
public ConnectionFactory() {
}
/**
*
* @return
*/
public static SSLContext getSslContext() {
SSLContext sslContext = null;
try {
sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, new TrustManager[]{new SecureTrustManager()}, new SecureRandom());
}
catch (NoSuchAlgorithmException | KeyManagementException ex) {
log.error("ERROR OCCURS", ex);
}
return sslContext;
}
/**
*
* @return
*/
public static HostnameVerifier getHostnameVerifier() {
return (String hostname, javax.net.ssl.SSLSession sslSession) -> true;
}
public Boolean isHttps(String url) {
if (url.startsWith("https://")) {
return Boolean.TRUE;
}
else {
return Boolean.FALSE;
}
}
}