Remote SOAP web service keeps breaking connection

2019-06-15 00:34发布

问题:

Short Description

I'm using JBoss SwitchYard to connect to secured remote SOAP web service. For some reason after the request is sent; remote web service is stopping any further communication; so I'm not receiving a response.

Question

I need an idea or solution what could be a problem here.

Error

Caused by: java.net.SocketException: SocketException invoking https://**********.asmx: Unexpected end of file from server

Description and notes

  • Remote web service is using self-signed certificate; I have imported server certificate into my local truststore + plus I have my other certificate (in my keystore) to identify myself to the remote server.
  • Thanks to -Djavax.net.debug=all SSL debug logs and Wireshark logs I know that both client and server made a successful SSL handshake and client has successfully sent a request.
  • The server also uses IP filtering to allow a direct communication and my IP is whitelisted.
  • If I try to send the same XML request via SoapUI it works just fine and I receive a response. You should take into account that SoapUI only uses keystore; it is set to always trust remote services so no truststore is needed or used.
  • Now comes the funny part. If I use a Fiddler (free web debugging proxy) as a "man in the middle" between my JBoss SwitchYard and remote web service (to see what is happening), suddenly everything works.
  • The only difference between direct connection and using Fiddler as a proxy is that in real connection Connection = Keep-Alive header parameter is used and in Fiddler case, Proxy-Connection = Keep-Alive parameter is used. I don't know is there any other significant difference.
  • If I manually change these header parameters in SoapUI I still receive a successful response. A connection will fail only if I'm missing SOAPAction and Content-Type header parameters, but they are present in each case (and are the same).
  • When I observe this communication via Wireshark only difference I can see is that remote server is stopping further communication (when JBoss Switchyard application is directly communicating with remote web service).
  • I don't have an access to remote logs nor I'm allowed to get them. So I'm working blind.
  • In each case (With or without Fiddler) I'm using a company Proxy to reach remote web Service. This proxy is not a problem because other SwitchYard applications are working just fine.

Tools

  • JBoss EAP 6.4
  • JBoss SwitchYard 2.0.1.redhat-621159

回答1:

Exception

java.net.SocketException: Unexpected end of file from server

This exception implies that server already accepted your connection, which means your SSL handshake is indeed succeed. But the server closed the connection (by a TCP reset or fin) before you can get the response.

A reset is usually sent in two cases:

  • persistent connection (keep alive connection) with config exceed
  • server restarted lost the connection

Usually, a persistent connection has two config:

Keep-Alive: timeout=15, max=100

timeout means time in seconds, max means max requests.

Connection vs Proxy Connection

Let's compare the three different cases you have described:

  • SoapUI: succeed; ?
  • Direct Connection: fail; Connection = Keep-Alive
  • Fiddler: succeed; Proxy-Connection = Keep-Alive

In the third case, if I understand you right, your persistent connection is from client to proxy and from proxy to server is not clear.

 client----->Proxy----->server

Suggestions

  • try to get the server's persistent connection config from response (like here), to see if direct connection exceed the time or numbers of limit
  • try to not use persistent connection: java -Dhttp.keepalive=false

Ref

  • fin vs rst in tcp
  • keep alive header


回答2:

Issue might be due to invalid header or Invalid format of SOAP request, You can try like below code

1 You need HeaderHandlerResolver

 public class HeaderHandlerResolver implements HandlerResolver {

        public List<Handler> getHandlerChain(PortInfo portInfo) {
            List<Handler> handlerChain = new ArrayList<Handler>();

            HeaderHandler hh = new HeaderHandler();

            handlerChain.add(hh);

            return handlerChain;
        }
    }

Then You need to add on HeaderHandler class

 public class HeaderHandler implements SOAPHandler<SOAPMessageContext> {

        public boolean handleMessage(SOAPMessageContext smc) {

            Boolean outboundProperty = (Boolean) smc.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);

            if (outboundProperty.booleanValue()) {

                SOAPMessage message = smc.getMessage();

                try {

                    SOAPEnvelope envelope = smc.getMessage().getSOAPPart().getEnvelope();

                    SOAPHeader header = envelope.getHeader();
                    header.setPrefix("soapenv");
                    header.setAttribute("xmlns:wsa", "http://www.w3.org/2005/08/addressing");

                    SOAPElement security =
                            header.addChildElement("Security", "wsse", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");

                    SOAPElement usernameToken =
                            security.addChildElement("UsernameToken", "wsse");
                    usernameToken.addAttribute(new QName("xmlns:wsu"), "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd");

                    SOAPElement username =
                            usernameToken.addChildElement("Username", "wsse");
                    username.addTextNode("USERNAME");

                    SOAPElement password =
                            usernameToken.addChildElement("Password", "wsse");
                    password.setAttribute("Type", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText");
                    password.addTextNode("PASSWORD");

                    SOAPElement encode =
                            usernameToken.addChildElement("Nonce", "wsse");
                    encode.setAttribute("EncodingType", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary");
                    encode.addTextNode(generateNonce());

                    Calendar createdTime = new GregorianCalendar(TimeZone.getTimeZone("IST"));
                    Date todayDate = createdTime.getTime();
                    todayDate.setTime(todayDate.getTime()-20000000);

                    SOAPElement created = usernameToken.addChildElement("Created", "wsu");
                    created.addTextNode(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.sss'Z'").format(todayDate));

                    SOAPElement action = header.addChildElement("Action", "wsa");
                    //YOUR ACTION URL SHOULD BE in BELOW Text Content
                    action.setTextContent("SET HERE YOUR ACTION URL");

                    message.saveChanges();
                    message.writeTo(System.out);
                    System.out.println("");

                } catch (Exception e) {
                    e.printStackTrace();
                }

            } else {
                try {

                    //This handler does nothing with the response from the Web Service so
                    //we just print out the SOAP message.
                    SOAPMessage message = smc.getMessage();
                    message.writeTo(System.out);
                    System.out.println("");
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }


            return outboundProperty;

        }

        public Set getHeaders() {
            return null;
        }

        public boolean handleFault(SOAPMessageContext context) {
            return true;
        }

        public void close(MessageContext context) {
        }

        private static String generateNonce() throws NoSuchAlgorithmException, NoSuchProviderException, UnsupportedEncodingException {
            String dateTimeString = Long.toString(new Date().getTime());
            byte[] nonceByte = dateTimeString.getBytes();
            return Base64.encodeBase64String(nonceByte);
        }
    }

Now Finally Your Main class for call SOAP service

public class SoapClientClass {

    public static void main(String[] args) {

        ImplService service = new ImplService();
        HeaderHandlerResolver handlerResolver = new HeaderHandlerResolver();
        service.setHandlerResolver(handlerResolver);

        ResponseClass port = service.getPortClass();

        Response response = null;
        try {
            response = port.getServerMehotd("Params");
        } catch (PolicyException_Exception e) {
            e.printStackTrace();
        } catch (ServiceException_Exception e) {
            e.printStackTrace();
        }

        }
    }
}

Also, make sure your generated code from wsdl file uptodate and server location url also correct.

Hope its resolve your problem