Веб-служба с вложением не удалась при двухстороннем соединении SSL - PullRequest
3 голосов
/ 06 сентября 2010

У меня есть два приложения, одно из которых предоставляет веб-сервис (назовем его ws-provider), другое - клиент этого веб-сервиса (назовем его ws-client).Это сообщение защищено с помощью двухстороннего SSL.Оба сервера были правильно настроены с учетом этих ограничений конфиденциальности (установка сертификатов, конфигурация SSL, параметризация Tomcat ...)

Серверы работают на Tomcat (5,5 для ws-provider, 6 для ws-client), Java6 и использует Jax-WS для предоставления / использования веб-службы.

Когда пользователь подключается к приложению ws-client и выполняет действие, которое вызывает веб-службу ws-provider, последнее действие обычно завершается ошибкой со следующей ошибкой:

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-provider я получаю эту ошибку:

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)
        ...

Теперь странная часть состоит в том, что я только что сказалчто это обычно не удалось при вызове веб-службы.По некоторым причинам иногда я получаю успешную попытку при вызове веб-сервиса.Обычно это происходит, если пользователь запускает действие в течение минуты после его входа в приложение (Нет, я не знаю почему!) ...

Запрос веб-службы содержит вложение.Это вложение представляет собой файл PDF размером не более 15 Кб (по крайней мере, во время всех моих тестов, успешно или неудачно, этот размер никогда не превышался).

Поэтому после многих тестов я пытался вызвать один и тот же веб-service без присоединения любого файла PDF, и вызов был успешным.

Для вашей информации, если ограничения безопасности отключены на ws-provider (то есть мы не используем двусторонний SSLсвязь), тогда вызовы веб-службы никогда не завершаются неудачей.

Поэтому я представляю, что мне нужно что-то настроить в моих веб-службах или в Tomcat (или?), чтобы система работала.Любая идея?

Java-код

Вот интерфейс Java, который обеспечивает вызов метода для ws-client (как вы можете видеть, основные классы Java, используемые для WS, генерируются 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);

}

Вызов ws-client выглядит следующим образом (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.Так что не стесняйтесь спрашивать более подробную информацию, если это необходимо!

РЕДАКТИРОВАТЬ 1

Я попытался принудительно интегрировать PDF-файл в сообщение SOAP, задав пороговое значение MTOM до 2 МБ:

Вкл. ws-client:

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

Вкл. ws-provider, я настроил аннотацию MTOM с помощью @MTOM(threshold=2097152)

Это исправление не решило мою проблемупроблема, к сожалению ...

Редактировать 2

Я удалил вложение 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

Я пытался регистрировать SOAP-сообщения, отправленные ws-client, но не вижу в этом ничего плохого ...

1 Ответ

2 голосов
/ 09 сентября 2010

Возможно, я нашел решение своей проблемы.

Как было объяснено, 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 метод (Tomcat 5.5.23):

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");
    }
}

Как видите, идея timeout не была реальной проблемой тайм-аута, по крайней мере, в моем случае.Похоже, ошибка возникает из-за того, что мы читаем данные из SSLSocket, и в конце мы не считаем, что рукопожатие было выполнено правильно.

Другая проблема заключается в том, что у меня возникла другая проблема при удалении вложения PDF вмой звонок WSЭта ошибка говорит о том, что синтаксический анализ XML не удалось.Поэтому я подозревал, что данные, полученные на стороне ws-provider, по некоторым причинам были разбиты на фрагменты.

Затем я наконец нашел интересный параметр в коннекторе Tomcat, который равен maxSavePostSize:

Максимальный размер в байтах POST, который будет сохранен / буферизован контейнером во время аутентификации FORM или CLIENT-CERT.Для обоих типов аутентификации POST будет сохранен / буферизирован до аутентификации пользователя.Для аутентификации CLIENT-CERT POST буферизуется на время рукопожатия SSL, а буфер обрабатывается при обработке запроса.Для аутентификации FORM POST сохраняется, пока пользователь перенаправляется на форму входа в систему и сохраняется до тех пор, пока пользователь не выполнит аутентификацию или не истечет сеанс, связанный с запросом аутентификации.Ограничение можно отключить, установив для этого атрибута значение -1.Установка атрибута в ноль отключит сохранение данных POST во время аутентификации.Если он не указан, для этого атрибута установлено значение 4096 (4 килобайта).

Поэтому я решил изменить конфигурацию Tomcat Connector, установив значение maxSavePostSize="-1" (т. Е. Размер буфера не ограничен 4Kb).

Я не уверен на 100%, что это правильное исправление, применимое в моей ситуации, но все тесты, которые я провел сегодня (с вложением PDF), были успешными, даже тесты, которые всегда не удавались раньше ...

...