当前位置: 首页 > 知识库问答 >
问题:

是否可以为javax重用Java可信证书。ws。rs(Resteasy实现)?

郗俊能
2023-03-14

假设我们需要信任一个自签名的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连接机制相同的密钥库?

共有1个答案

韦翰音
2023-03-14

ClientBuilderAPI中,有一种方法允许您设置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