测试服务器中需要服务器名称指示(SNI)的Apache CXF客户端错误

时间:2015-09-11 12:07:28

标签: java web-services ssl cxf sni

我们有一个使用Apache CXF的客户端使用某个服务器(即:https://serverexample.com/application/webservice?wsdl)工作正常。

但服务器已移至另一个IP,现在它在同一IP中有两个带有TLS和SNI(服务器名称指示)的SSL证书,现在我们的应用程序因此错误而失败:

javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: No subject alternative DNS name matching serverexample.com found

据我所知,这种情况发生在https获取错误的证书(它有另一个服务器名称)时,因此与我的不匹配。

我试图找出openssl发生了什么,只有当我输入servername时,url才有效:

# openssl s_client -connect serverexample.com:443 -tls1
Certificate chain
 0 s:/CN=otherserver.com/OU=Servers/O=MyOrganization/C=ES
   i:/CN=ACV20/OU=PKACV/O=ACV/C=ES

# openssl s_client -connect serverexample.com:443 -servername serverexample.com
Certificate chain
 0 s:/CN=serverexample.com/OU=Servers/O=MyOrganization/C=ES
   i:/CN=ACV220/OU=PKACV1/O=ACV2/C=ES

此时生成的apache客户端发生错误:

final URL wsdlURL = new URL("https://serverexample.com/application/webservice?wsdl");
final Operation_Service ss = new Operation_Service(wsdlURL, SERVICE_NAME);

新的Operation_Service失败:

@WebServiceClient(name = "ENI.Operation", 
                  wsdlLocation = "https://serverexample.com/application/webservice?wsdl",
                  targetNamespace = "http://inter.ra.es/awrp/wsdl") 
public class Operation_Service extends Service {
    public final static URL WSDL_LOCATION;
    public final static QName SERVICE = new QName("http://inter.ra.es/awrp/wsdl", "ENI.Operation");
    public final static QName Operation = new QName("http://inter.ra.es/awrp/wsdl", "ENI.Operation");
    static {
        URL url = null;
        try {
            url = new URL("https://serverexample.com/application/webservice?wsdl");
        } catch (final MalformedURLException e) {
            java.util.logging.Logger.getLogger(Operation_Service.class.getName())
                .log(java.util.logging.Level.INFO, 
                     "Can not initialize the default wsdl from {0}", "https://serverexample.com/application/webservice?wsdl");
        }
        WSDL_LOCATION = url;
    }

     public Operation_Service(final URL wsdlLocation, final QName serviceName) {
        super(wsdlLocation, serviceName);
    }

javax.xml.ws.Service调用javax.xml.ws.spi.ServiceDelegate,这是一个由org.apache.cxf.jaxws中的某个类实现的abastract类..但是在这里我失去了它,我不知道#39;知道要看什么...

我们的客户端在weblogic 12.1.1.0上使用apache cxf 3.0.4在java 7.0中运行。我在Java 6中看到SNI存在问题,但我们在这里使用7.0。

我不知道该怎么办。在java或我们的客户端中是否有一些选项指示我们正在尝试连接的服务器名称(如在openssl中)?

1 个答案:

答案 0 :(得分:5)

它是JDK 1.8中“改进”的组合,以及服务器具有多个证书的事实。

这里解释了JDK 1.8中的内容: http://lea-ka.blogspot.com/2015/09/wtf-collection-how-not-to-add-api.html

它是这样的:

  • 由于错误https://bugs.openjdk.java.net/browse/JDK-8072464而未发送SNI扩展程序。
  • 服务器返回证书“CN = otherserver.com”,它可能还有SAN(SubjectAlternativeName)“otherserver.com”,而不是其他。
  • JDK中的默认“URL欺骗”检查是perofrmed,并比较URL中的“serverexample.com”和证书中的“otherserver.com”。哎呀,你得到了例外。

最简单修复程序是下载所有WSDL和XSD文件并将它们打包到jar中的某个位置。

如果真的需要从远程服务器获取WSDL,这可能会有所帮助:

最终网址wsdlURL =新网址(“https:// otherserver.com / application / webservice?wsdl”);

但这可能不起作用,因为“/ application / webservice”可能仅为serverexample.com所知。在这种情况下,您将获得TLS连接,然后获得HTTP 404响应代码。

如果这不起作用,你将不得不诉诸各种SSL工厂(这很冗长但确定可能)并尝试将它们挂钩到javax.ws ....类(这应该是可能的但我从来没有完成那部分)。