假设我们需要信任一个自签名的SSL证书,作为示例,让我们使用https://self-signed.badssl.com/.
由于签名者不是“适当的”权限,Java不信任它,拒绝连接到该服务器。然而,在
$ cd $JAVA_HOME/jre/lib/security
$ keytool -import -trustcacerts -alias ... -file ... -keystore cacerts
并重新启动应用程序,下面的代码工作:
new URL ("https://self-signed.badssl.com/").openConnection ().getResponseCode ()
并返回200(OK),没有引发异常。也就是说,打开HTTPS连接的基本Java方式现在可以工作了,因为证书现在是受信任的。
然而,这并没有对javax.ws.rs客户端有任何可见的影响(至少是在莱斯利实现的),我仍然得到一个例外:
javax.ws.rs.ProcessingException: Unable to invoke request
at org.jboss.resteasy.client.jaxrs.engines.ApacheHttpClient4Engine.invoke(ApacheHttpClient4Engine.java:287)
at org.jboss.resteasy.client.jaxrs.internal.ClientInvocation.invoke(ClientInvocation.java:407)
at org.jboss.resteasy.client.jaxrs.internal.ClientInvocationBuilder.method(ClientInvocationBuilder.java:273)
[...]
Caused by: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1949)
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:302)
at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:296)
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1506)
at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:216)
at sun.security.ssl.Handshaker.processLoop(Handshaker.java:979)
at sun.security.ssl.Handshaker.process_record(Handshaker.java:914)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1062)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1375)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1403)
at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1387)
at org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:535)
at org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:403)
at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:177)
at org.apache.http.impl.conn.ManagedClientConnectionImpl.open(ManagedClientConnectionImpl.java:304)
at org.apache.http.impl.client.DefaultRequestDirector.tryConnect(DefaultRequestDirector.java:611)
at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:446)
at org.apache.http.impl.client.AbstractHttpClient.doExecute(AbstractHttpClient.java:863)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:57)
at org.jboss.resteasy.client.jaxrs.engines.ApacheHttpClient4Engine.invoke(ApacheHttpClient4Engine.java:283)
... 90 more
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:387)
at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:292)
at sun.security.validator.Validator.validate(Validator.java:260)
at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:324)
at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:229)
at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:124)
at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1488)
... 107 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
at sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:146)
at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:131)
at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:280)
at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:382)
... 113 more
Resteasy似乎没有考虑“标准”密钥库。但我更希望有一个中心(特定于机器)位置来存放额外的受信任密钥,而不用担心应用程序如何使用它们,比如URL。openConnection
或javax。ws。卢比。
问题是,是否可以制作javax。ws。rs客户端
是否使用与“普通”Java HTTPS连接机制相同的密钥库?
在ClientBuilder
API中,有一种方法允许您设置SSLContext
:
public abstract ClientBuilder sslContext(sslContext sslContext)
设置从使用此SSL上下文的客户端实例创建的web目标创建到服务器endpoint的安全传输连接时将使用的SSL上下文。SSL上下文将初始化所有安全基础设施,包括密钥和信任管理器。
设置SSL上下文实例会重置之前指定的任何密钥存储或信任存储值。
参数:
sslContext
-安全套接字协议实现,充当安全套接字工厂或SSL引擎的工厂。不能为null
。
返回:
更新的客户端生成器实例。
抛出:
NullPointerException
——如果sslContext
参数为null
。
假设您已将证书添加到cacerts
信任存储中,则在创建客户端
实例时,可以使用默认的SSLContext
。
Client client = ClientBuilder.newBuilder().sslContext(SSLContext.getDefault()).build();
应该够了。然而,出于某种原因,上述代码不适用于RESTEasy,但适用于Jersey。这很可能是一个简单的错误。
RESTEasy文档说明了以下内容:
默认情况下,客户端和服务器之间的网络通信由Apache HttpComponents项目中的HttpClient
(4.x)在RESTEasy中处理。[...]
RESTEasy和HttpClient
做出合理的默认决策,这样就可以在不引用HttpClient
的情况下使用客户端框架,但对于某些应用程序,可能需要深入了解HttpClient
的详细信息。[...]
要自定义RESTEeasy使用的HttpClient
,请执行以下操作:
HttpClient httpClient = HttpClientBuilder.create()
.setSslcontext(SSLContext.getDefault())
.build();
ApacheHttpClient4Engine engine = new ApacheHttpClient4Engine(httpClient);
Client client = new ResteasyClientBuilder().httpEngine(engine).build();
然后您可以执行请求:
Response response = client.target("https://self-signed.badssl.com/").request().get();
System.out.println(response.getStatus());
在创建客户端
时,可以加载KeyStore
,而不是使用SSLContext
。要加载cacerts
信任存储,可以执行以下操作:
String filename = System.getProperty("java.home") +
"/lib/security/cacerts".replace('/', File.separatorChar);
FileInputStream is = new FileInputStream(filename);
KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
String password = "changeit";
keystore.load(is, password.toCharArray());
cacerts
的默认密码是Changeit
。
然后使用以下方法之一创建您的Client
实例:
Client client = ClientBuilder.newBuilder().trustStore(keystore).build();
java prettyprint-override">Client client = ClientBuilder.newBuilder().keyStore(keystore, password).build();
问题是它不适用于RESTEasy,但适用于泽西。
针对以下JAX-RS客户端API实现对上述解决方案进行了测试:
泽西客户端
(版本2.23.1)restease-Client
(版本3.0.18.最终版)我正在开发一个使用JBoss RESTEasy(RESTEasy-jaxrs-3.0.8)的Web应用程序,但我想禁用RoleBasedSecurityFilter。java,只使用我自己的自定义类(它也实现,就像类一样,它们都是安全过滤器)。 这样做的原因是RoleBasedSecurityFilter.java的第43行调用了一个isUserInRole()方法,该方法在我的应用程序中总是返回
我们需要显式地将受信任的CA证书导入java密钥库吗?如果是,为什么? 我可以理解,我们应该始终将自签名SSL证书导入密钥库,因为它们不是经过验证的证书,除非密钥库中有java,否则无法信任。但是,即使对于可信CA生产证书,我们也需要执行同样的操作吗? 注意:我使用的是jdk v1。6.x。
我在处理这种情况。我有一个运行多个服务的Jax-ws应用程序,我需要在REST应用程序中公开这些服务。我怎么把它转换过来?我可以在两个应用程序之间做一个“代理”吗?THX!
我正在使用Java EE7、wildfly11、Resteasy-JAXRS-3.0.24(捆绑在wildfly11中) 我已经通过post json或xml格式成功地调用了rest api。 我使用并获得 此错误显示在客户端。 我使用并获得 此错误显示在服务器端。它意味着resteasyclient向服务器发送字节[]。但调用服务时会发生问题。我在AbstractJAXBProvider.jav
我在实验室工作。我有一个基于Windows的CA和一个IIS上的SSL安全网站(在同一台机器上),其中有来自该CA的证书问题。 当我使用SSL在Firefox中浏览此站点时,我得到一个错误“证书不可信,因为发行者证书未知。” 如果我去工具店- 将CA的证书添加到授权列表中,告诉Firefox,“嘿……你知道这个CA,去相信它发布的证书吧?”这难道不是重点吗 如何解决这个问题?
我有一个电子邮件应用程序发送电子邮件,是在家里写的。我们已经为它设置了使用OAuth2.0与GMail(个人和商业账户)和Outlook.com账户的选项,没有问题。 我们也可以使用用户ID和密码进行身份验证,但是我们更喜欢OAuth2.0,因为我们不会以这种方式将密码保存在任何地方。 我们现在要求为Office365帐户这样做。 我注意到Office365 smtp服务器(smtp.Office