代码之家  ›  专栏  ›  技术社区  ›  Romain Linsolas

带有附件的Web服务在双向SSL连接上失败

  •  3
  • Romain Linsolas  · 技术社区  · 14 年前

    我有两个应用程序,一个提供Web服务(我们称之为 ws-provider ),另一个是此Web服务的客户端(称为 ws-client ). 此通信通过双向SSL进行保护。两台服务器都已正确配置了此机密性限制(证书安装、SSL配置、Tomcat参数化…)

    ws提供程序 ws客户端 ),并使用Jax-WS提供/使用web服务。

    当用户连接到 并执行调用 web服务,后一个操作 失败并出现以下错误:

    com.sun.xml.ws.client.ClientTransportException: The server sent HTTP status code 400: No client certificate chain in this request
            at com.sun.xml.ws.transport.http.client.HttpClientTransport.checkResponseCode(HttpClientTransport.java:218)
            at com.sun.xml.ws.transport.http.client.HttpTransportPipe.process(HttpTransportPipe.java:137)
            at com.sun.xml.ws.transport.http.client.HttpTransportPipe.processRequest(HttpTransportPipe.java:74)
            at com.sun.xml.ws.api.pipe.Fiber.__doRun(Fiber.java:559)
            at com.sun.xml.ws.api.pipe.Fiber._doRun(Fiber.java:518)
            at com.sun.xml.ws.api.pipe.Fiber.doRun(Fiber.java:503)
            at com.sun.xml.ws.api.pipe.Fiber.runSync(Fiber.java:400)
            at com.sun.xml.ws.client.Stub.process(Stub.java:234)
            at com.sun.xml.ws.client.sei.SEIStub.doProcess(SEIStub.java:120)
            at com.sun.xml.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:230)
            at com.sun.xml.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:210)
            at com.sun.xml.ws.client.sei.SEIStub.invoke(SEIStub.java:103)
            at $Proxy33.createOrRenewRequest(Unknown Source)
            at my.app.MyPushRequest.sendXMLRequest(MyPushRequest.java:29)
            at my.app.MyRequestCreation.sendRequestForDraftApproval(MyRequestCreation.java:284)
    

    ws提供程序 ,我得到这个错误:

    WARNING: Exception getting SSL attributes
    java.net.SocketException: SSL Cert handshake timeout
            at org.apache.tomcat.util.net.jsse.JSSE14Support.synchronousHandshake(JSSE14Support.java:101)
            at org.apache.tomcat.util.net.jsse.JSSE14Support.handShake(JSSE14Support.java:67)
            at org.apache.tomcat.util.net.jsse.JSSESupport.getPeerCertificateChain(JSSESupport.java:121)
            at org.apache.coyote.http11.Http11Processor.action(Http11Processor.java:1127)
            at org.apache.coyote.Request.action(Request.java:349)
            ...
    

    奇怪的是我刚才说 通常地 由于某些原因,有时我在调用web服务时尝试成功。如果用户在登录到应用程序后的一分钟内启动操作,通常会发生这种情况(不,我不知道为什么!)。。。

    web服务请求包含附件。这个附件是一个不超过15Kb的PDF文件(至少在我所有的测试中,无论成功还是失败,都没有超过这个大小)。

    所以在多次测试之后,我尝试调用同一个web服务 没有

    供您参考,如果在 ws提供程序 (即我们不再使用双向SSL连接)那么web服务调用永远不会失败。

    你知道吗?


    Java代码

    下面是提供方法调用的Java接口 (如您所见,用于WS的核心Java类是由Jax-WS库生成的):

    /**
     * This class was generated by the JAX-WS RI.
     * JAX-WS RI 2.1.3-b02-
     * Generated source version: 2.1
     * 
     */
    @WebService(name = "PushServicePortType", targetNamespace = "http://my.app.ws/PushService")
    @XmlSeeAlso({
        ObjectFactory.class
    })
    public interface PushServicePortType {
    
    
        @WebMethod
        @WebResult(name = "response", targetNamespace = "")
        @RequestWrapper(localName = "createOrRenewRequest", targetNamespace = "http://my.app.ws/CwfPushService", className = "my.app.CreateOrRenewRequest")
        @ResponseWrapper(localName = "createOrRenewRequestResponse", targetNamespace = "http://my.app.ws/CwfPushService", className = "my.app.CreateOrRenewRequestResponse")
        public String createOrRenewRequest(
            @WebParam(name = "xmlMessageContent", targetNamespace = "")
            String xmlMessageContent,
            @WebParam(name = "version", targetNamespace = "")
            String version,
            @WebParam(name = "attachments", targetNamespace = "")
            List<DataHandler> attachments);
    
    }
    

    电话接通 如下所示( xmlFile 包含请求的XML, datahandler javax.activation.DataHandler (包含PDF附件):

    PushServicePortType pushServicePort = new PushService(new URL("url/to/wsdl"), new QName("http://my.app.ws/PushService", "PushService")).getPushServiceSOAP(new MTOMFeature());
    PushRequest push = new PushRequest();
    responseXML = push.sendXMLRequest(pushServicePort, xmlFile, datahandler);
    

    有很多配置文件、日志或Java类。因此,如果需要,请不要犹豫询问更多细节!


    MTOM threshold 至2Mb:

    PushServicePortType pushServicePort = new PushService(new URL("url/to/wsdl"), new QName("http://my.app.ws/PushService", "PushService")).getPushServiceSOAP(new MTOMFeature(2097152));
    

    ws提供程序 ,我将MTOM注释配置为 @MTOM(threshold=2097152)

    解决我的问题,不幸的是。。。

    我已经从我的web服务中删除了PDF附件,现在它也失败了,但有一条不同的消息:

    javax.xml.ws.soap.SOAPFaultException: Failed to read a response: javax.xml.bind.UnmarshalException
     - with linked exception:
    [javax.xml.stream.XMLStreamException: ParseError at [row,col]:[1,3834]
    Message: XML document structures must start and end within the same entity.]
            at com.sun.xml.ws.fault.SOAP11Fault.getProtocolException(SOAP11Fault.java:173)
            at com.sun.xml.ws.fault.SOAPFaultBuilder.createException(SOAPFaultBuilder.java:102)
            at com.sun.xml.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:240)
            at com.sun.xml.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:210)
            at com.sun.xml.ws.client.sei.SEIStub.invoke(SEIStub.java:103)
            at $Proxy33.createOrRenewRequest(Unknown Source)
            at my.app.CWFPushRequest.sendXMLRequest(PushRequest.java:29)
            ...
    Caused by: com.sun.xml.ws.encoding.soap.DeserializationException: Failed to read a response: javax.xml.bind.UnmarshalException
     - with linked exception:
    [javax.xml.stream.XMLStreamException: ParseError at [row,col]:[1,3834]
    Message: XML document structures must start and end within the same entity.]
            at com.sun.xml.ws.server.sei.EndpointMethodHandler.invoke(EndpointMethodHandler.java:235)
            at com.sun.xml.ws.server.sei.SEIInvokerTube.processRequest(SEIInvokerTube.java:74)
            at com.sun.xml.ws.api.pipe.Fiber.__doRun(Fiber.java:559)
            at com.sun.xml.ws.api.pipe.Fiber._doRun(Fiber.java:518)
            at com.sun.xml.ws.api.pipe.Fiber.doRun(Fiber.java:503)
            at com.sun.xml.ws.api.pipe.Fiber.runSync(Fiber.java:400)
            at com.sun.xml.ws.server.WSEndpointImpl$2.process(WSEndpointImpl.java:229)
            at com.sun.xml.ws.transport.http.HttpAdapter$HttpToolkit.handle(HttpAdapter.java:430)
            at com.sun.xml.ws.transport.http.HttpAdapter.handle(HttpAdapter.java:230)
            at com.sun.xml.ws.transport.http.servlet.ServletAdapter.handle(ServletAdapter.java:121)
            at com.sun.xml.ws.transport.http.servlet.WSServletDelegate.doGet(WSServletDelegate.java:115)
            at com.sun.xml.ws.transport.http.servlet.WSServletDelegate.doPost(WSServletDelegate.java:146)
            at com.sun.xml.ws.transport.http.servlet.WSSpringServlet.doPost(WSSpringServlet.java:52)
            at javax.servlet.http.HttpServlet.service(HttpServlet.java:710)
            at javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
            at sun.reflect.GeneratedMethodAccessor330.invoke(Unknown Source)
            at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
            at java.lang.reflect.Method.invoke(Method.java:597)
            at org.apache.catalina.security.SecurityUtil$1.run(SecurityUtil.java:244)
            at java.security.AccessController.doPrivileged(Native Method)
            at javax.security.auth.Subject.doAsPrivileged(Subject.java:517)
            at org.apache.catalina.security.SecurityUtil.execute(SecurityUtil.java:276)
            at org.apache.catalina.security.SecurityUtil.doAsPrivilege(SecurityUtil.java:162)
            at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:262)
            at org.apache.catalina.core.ApplicationFilterChain.access$000(ApplicationFilterChain.java:52)
            at org.apache.catalina.core.ApplicationFilterChain$1.run(ApplicationFilterChain.java:171)
            at java.security.AccessController.doPrivileged(Native Method)
            at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:167)
            at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:210)
            at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:174)
            at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:525)
            at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
            at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:117)
            at org.apache.catalina.valves.FastCommonAccessLogValve.invoke(FastCommonAccessLogValve.java:482)
            at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:108)
            at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:151)
            at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:870)
            at org.apache.coyote.http11.Http11BaseProtocol$Http11ConnectionHandler.processConnection(Http11BaseProtocol.java:665)
            at org.apache.tomcat.util.net.PoolTcpEndpoint.processSocket(PoolTcpEndpoint.java:528)
            at org.apache.tomcat.util.net.LeaderFollowerWorkerThread.runIt(LeaderFollowerWorkerThread.java:81)
            at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:685)
            ... 1 more
    Caused by: javax.xml.bind.UnmarshalException
            at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.handleStreamException(UnmarshallerImpl.java:397)
            at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:335)
            at com.sun.xml.bind.v2.runtime.BridgeImpl.unmarshal(BridgeImpl.java:84)
            at com.sun.xml.bind.api.Bridge.unmarshal(Bridge.java:197)
            at com.sun.xml.ws.server.sei.EndpointArgumentsBuilder$DocLit.readRequest(EndpointArgumentsBuilder.java:492)
            at com.sun.xml.ws.server.sei.EndpointMethodHandler.invoke(EndpointMethodHandler.java:233)
            ... 41 more
    Caused by: javax.xml.stream.XMLStreamException: ParseError at [row,col]:[1,3834]
    Message: XML document structures must start and end within the same entity.
            at com.sun.xml.stream.XMLReaderImpl.next(XMLReaderImpl.java:563)
            at com.sun.xml.ws.encoding.MtomCodec$MtomXMLStreamReaderEx.next(MtomCodec.java:413)
            at com.sun.xml.bind.v2.runtime.unmarshaller.StAXStreamConnector.bridge(StAXStreamConnector.java:188)
            at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:333)
            ... 45 more
    

    我试着记录 ws客户端 ,但我看不出有什么不对。。。

    1 回复  |  直到 14 年前
        1
  •  2
  •   Romain Linsolas    14 年前

    如前所述 ws-provider Tomcat给了我以下错误:

    java.net.SocketException: SSL Cert handshake timeout
            at org.apache.tomcat.util.net.jsse.JSSE14Support.synchronousHandshake(JSSE14Support.java:101)
            at org.apache.tomcat.util.net.jsse.JSSE14Support.handShake(JSSE14Support.java:67)
            at org.apache.tomcat.util.net.jsse.JSSESupport.getPeerCertificateChain(JSSESupport.java:121)
    

    synchronousHandshake

    private void synchronousHandshake(SSLSocket socket) throws IOException {
        InputStream in = socket.getInputStream();
        int oldTimeout = socket.getSoTimeout();
        socket.setSoTimeout(1000);
        byte[] b = new byte[0];
        listener.reset();
        socket.startHandshake();
        int maxTries = 60; // 60 * 1000 = example 1 minute time out
        for (int i = 0; i < maxTries; i++) {
            if (logger.isTraceEnabled())
                logger.trace("Reading for try #" + i);
            try {
                int x = in.read(b);
            } catch (SSLException sslex) {
                logger.info("SSL Error getting client Certs", sslex);
                throw sslex;
            } catch (IOException e) {
                // ignore - presumably the timeout
            }
            if (listener.completed) {
                break;
            }
        }
        socket.setSoTimeout(oldTimeout);
        if (listener.completed == false) {
            throw new SocketException("SSL Cert handshake timeout");
        }
    }
    

    超时 这个主意不是真正的超时问题,至少对我来说是这样。这个错误似乎是因为我们从 SSLSocket ,最后,我们认为握手没有正确完成。

    另一件事是,我在WS-call中删除PDF附件时遇到了另一个问题。此错误表示XML解析失败。所以我怀疑 ws提供程序

    maxSavePostSize :

    在窗体或客户端证书身份验证期间,容器将保存/缓冲的最大POST大小(字节)。对于这两种类型的身份验证,在对用户进行身份验证之前,POST将被保存/缓冲。对于CLIENT-CERT身份验证,在SSL握手期间缓冲POST,在处理请求时清空缓冲区。对于表单身份验证,当用户被重新定向到登录表单时,POST将被保存,并被保留,直到用户成功进行身份验证或与身份验证请求相关的会话过期为止。通过将此属性设置为-1,可以禁用限制。将属性设置为零将禁止在身份验证期间保存POST数据。如果未指定,则此属性设置为4096(4 KB)。

    所以我决定修改Tomcat连接器配置来设置 maxSavePostSize="-1" (即缓冲器不再限于4Kb)。

    我不是100%确定这是正确的修复适用于我的情况,但我今天所做的所有测试(PDF附件)都成功了,即使是以前总是失败的测试。。。