Search code examples
cxfwebservice-clientws-securitycxf-client

Could not receive message back from WS service using Apache CXF Client: Read time out


I am trying to call Web Service that is based on IIS WPF and its WSDL has following policy:

<wsp:Policy wsu:Id="custom_policy">
  <wsp:ExactlyOne>
    <wsp:All>
      <sp:TransportBinding xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">
        <wsp:Policy>
          <sp:TransportToken>
            <wsp:Policy>
              <sp:HttpsToken RequireClientCertificate="false"/>
            </wsp:Policy>
          </sp:TransportToken>
          <sp:AlgorithmSuite>
            <wsp:Policy>
              <sp:Basic256/>
            </wsp:Policy>
          </sp:AlgorithmSuite>
          <sp:Layout>
            <wsp:Policy>
              <sp:Strict/>
            </wsp:Policy>
          </sp:Layout>
          <sp:IncludeTimestamp/>
        </wsp:Policy>
      </sp:TransportBinding>
      <sp:SignedSupportingTokens xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">
        <wsp:Policy>
          <sp:UsernameToken sp:IncludeToken="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy/IncludeToken/AlwaysToRecipient">
            <wsp:Policy>
              <sp:WssUsernameToken10/>
            </wsp:Policy>
          </sp:UsernameToken>
        </wsp:Policy>
      </sp:SignedSupportingTokens>
      <sp:Wss11 xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">
        <wsp:Policy/>
      </sp:Wss11>
      <sp:Trust10 xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">
        <wsp:Policy>
          <sp:MustSupportIssuedTokens/>
          <sp:RequireClientEntropy/>
          <sp:RequireServerEntropy/>
        </wsp:Policy>
      </sp:Trust10>
      <wsaw:UsingAddressing/>
    </wsp:All>
  </wsp:ExactlyOne>
</wsp:Policy>

with Apache CXF client and following code:

JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
factory.setServiceClass(ITerytWs1.class);
factory.setAddress("https://uslugaterytws1test.stat.gov.pl/terytws1.svc");
ITerytWs1 info = (ITerytWs1) factory.create();
Map ctx = ((BindingProvider)info).getRequestContext();
ctx.put("ws-security.username", "TestPubliczny");
ctx.put("ws-security.password", "1234abcd");
ctx.put("ws-security.callback-handler", ClientPasswordCallback.class.getName());
var zal = info.isLoggedIn();

Dependencies are:

compile group: 'org.apache.cxf', name: 'cxf-rt-frontend-jaxws', version: '3.3.7'
compile group: 'org.apache.cxf', name: 'cxf-rt-transports-http', version: '3.3.7'
compile group: 'com.sun.activation', name: 'javax.activation', version: '1.2.0'
compile group: 'org.apache.cxf', name: 'cxf-rt-ws-security', version: '3.3.7'
compile group: 'com.sun.xml.messaging.saaj', name: 'saaj-impl', version: '1.5.2'

I receive only Read time out:

lip 16, 2020 1:58:31 PM org.apache.cxf.phase.PhaseInterceptorChain doDefaultLogging
WARNING: Interceptor for {http://tempuri.org/}ITerytWs1Service#{http://tempuri.org/}CiekawostkiSIMC has thrown exception, unwinding now
org.apache.cxf.interceptor.Fault: Could not receive Message.
    at org.apache.cxf.interceptor.MessageSenderInterceptor$MessageSenderEndingInterceptor.handleMessage(MessageSenderInterceptor.java:65)
    at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:308)
    at org.apache.cxf.endpoint.ClientImpl.doInvoke(ClientImpl.java:530)
    at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:441)
    at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:356)
    at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:314)
    at org.apache.cxf.frontend.ClientProxy.invokeSync(ClientProxy.java:96)
  [...]
Caused by: java.net.SocketTimeoutException: SocketTimeoutException invoking https://uslugaterytws1test.stat.gov.pl/terytws1.svc: Read timed out
    at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    [..]
Caused by: java.net.SocketTimeoutException: Read timed out
    at java.base/java.net.SocketInputStream.socketRead0(Native Method)
    [...]
Could not receive Message.
javax.xml.ws.WebServiceException: Could not receive Message.
    at org.apache.cxf.jaxws.JaxWsClientProxy.mapException(JaxWsClientProxy.java:183)

[...] Caused by: java.net.SocketTimeoutException: SocketTimeoutException invoking https://uslugaterytws1test.stat.gov.pl/terytws1.svc: Read timed out at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) [...]

How to configure this WS policy right and is it the problem of client or something else?


Solution

  • I had to use SoapUI to check what kind of envelope is sent to the service to get the right answer, then I had to do the same with the code. Problem before was that wrong request was sent to the server and server got internal exception (probably) and has not returned answer of bad request.

    This is what I have done with the class:

    import lombok.Getter;
    import org.apache.cxf.frontend.ClientProxy;
    import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
    import org.apache.cxf.ws.addressing.WSAddressingFeature;
    import org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor;
    import org.apache.wss4j.dom.WSConstants;
    import org.apache.wss4j.dom.handler.WSHandlerConstants;
    import org.tempuri.ITerytWs1;
    
    import javax.inject.Inject;
    import java.util.HashMap;
    import java.util.Map;
    
    public class WebServiceClient {
    
    @Getter
    private ITerytWs1 service;
    private final ApiClientConfiguration apiClientConfiguration;
    private final ClientPasswordCallback clientPasswordCallback;
    
    @Inject
    public WebServiceClient(ApiClientConfiguration apiClientConfiguration) {
        this.apiClientConfiguration = apiClientConfiguration;
        this.clientPasswordCallback = new ClientPasswordCallback(apiClientConfiguration);
        initializeService();
        configureService();
    }
    
    private void configureService() {
        var client = ClientProxy.getClient(service);
        var endpoint = client.getEndpoint();
        Map<String, Object> outInterceptorProperties = createOutInterceptorProperties();
        var wssOutInterceptor = new WSS4JOutInterceptor(outInterceptorProperties);
        endpoint.getOutInterceptors().add(wssOutInterceptor);
    }
    
    private void initializeService() {
        var factory = new JaxWsProxyFactoryBean();
        var wsAddressingFeature = new WSAddressingFeature();
        factory.getFeatures().add(wsAddressingFeature);
        factory.setServiceClass(ITerytWs1.class);
        factory.setAddress(apiClientConfiguration.getAddress());
        service = (ITerytWs1) factory.create();
    }
    
    private Map<String, Object> createOutInterceptorProperties() {
        Map<String,Object> outInterceptorProperties = new HashMap<>();
        outInterceptorProperties.put(WSHandlerConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN);
        outInterceptorProperties.put(WSHandlerConstants.USER, apiClientConfiguration.getUsername());
        outInterceptorProperties.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_TEXT);
        outInterceptorProperties.put(WSHandlerConstants.ADD_USERNAMETOKEN_NONCE, "true");
        outInterceptorProperties.put(WSHandlerConstants.ADD_USERNAMETOKEN_CREATED, "true");
        outInterceptorProperties.put(WSHandlerConstants.MUST_UNDERSTAND, "false");
        // Callback used to retrieve password for given user.
        outInterceptorProperties.put(WSHandlerConstants.PW_CALLBACK_REF, clientPasswordCallback);
        return outInterceptorProperties;
    }
    }