Integrating with TERYT - Polish Government web ser

2019-09-14 23:58发布

问题:

I am trying to connect (without success) to the following WS using Java:

  • Service address - https://uslugaterytws1test.stat.gov.pl/terytws1.svc
  • WSDL address - https://uslugaterytws1test.stat.gov.pl/wsdl/terytws1.wsdl
  • User - TestPubliczny
  • Password - 1234abcd

I tried to use soapui without success. Tried Basic and NTLM authentication, and I always get the following error:

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" xmlns:a="http://www.w3.org/2005/08/addressing">
   <s:Header>
      <a:Action s:mustUnderstand="1">http://www.w3.org/2005/08/addressing/soap/fault</a:Action>
   </s:Header>
   <s:Body>
      <s:Fault>
         <faultcode xmlns:a="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">a:InvalidSecurity</faultcode>
         <faultstring xml:lang="en-US">An error occurred when verifying security for the message.</faultstring>
      </s:Fault>
   </s:Body>
</s:Envelope>

The official instructions for this web service shows following example to connect using C#. I havn't tested this, but I assume it works correctly.

try { 
  var proxy = new ChannelFactory<ServiceReferenceWCF.ITerytWs1>("custom");
  proxy.Credentials.UserName.UserName = login;
  proxy.Credentials.UserName.Password = haslo;
  var result = proxy.CreateChannel(); 
  var test = result.CzyZalogowany(); // should return true if connected correctly
} catch (Exception ex) { }

And below setting:

   <client>
      <endpoint address="https://uslugaterytws1.stat.gov.pl/TerytWs1.svc" binding="customBinding" bindingConfiguration="custom" contract="ServiceReference1.ITerytWs1" name="custom" />
   </client>
   <bindings>
      <customBinding>
         <binding name="custom">
            <security defaultAlgorithmSuite="Default" authenticationMode="UserNameOverTransport" requireDerivedKeys="true" includeTimestamp="true" messageSecurityVersion="WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10">
               <localClientSettings detectReplays="false" />
               <localServiceSettings detectReplays="false" />
            </security>
            <textMessageEncoding messageVersion="Soap11WSAddressing10" />
            <httpsTransport maxReceivedMessageSize="2147483647" maxBufferPoolSize="2147483647" />
         </binding>
      </customBinding>
   </bindings>

So I tried to connect using Java following way:

public static void main(String[] args) {
    try {
        final String wsdlResourcePath = "wsdl/jaxb/teryt/terytws1.wsdl";
        final String url = "https://uslugaterytws1test.stat.gov.pl/TerytWs1.svc";
        ITerytWs1 teryt = createSoapEndpoint((wsdlLocation) -> new TerytWs1(wsdlLocation).getCustom(), wsdlResourcePath, url);
        System.out.println(teryt.czyZalogowany());
    } catch (Exception e) { }
}

private static <SOAP> SOAP createSoapEndpoint(SoapCreator<SOAP> soapCreator, String wsdlResourcePath, String url) {
    ClassLoader cl = Thread.currentThread().getContextClassLoader();
    URL wsdlLocation = cl.getResource(wsdlResourcePath);
    SOAP soap = soapCreator.create(wsdlLocation);

    BindingProvider provider = (BindingProvider) soap;

    Map<String, Object> context = provider.getRequestContext();
    context.put(BindingProvider.USERNAME_PROPERTY, "TestPubliczny");
    context.put(BindingProvider.PASSWORD_PROPERTY, "1234abcd");
    context.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, url);
    return soap;
}

Unfortunately the code freezes during call "teryt.czyZalogowany()". Gives no timeout - anything, just processing this line for ever, or is being blocked at it.

My Java code produces following warning messages:

WARNING: WSP0075: Policy assertion "{http://schemas.xmlsoap.org/ws/2005/07/securitypolicy}SignedSupportingTokens" was evaluated as "UNKNOWN". lip 27, 2017 11:58:35 AM [com.sun.xml.internal.ws.policy.EffectiveAlternativeSelector] selectAlternatives WARNING: WSP0075: Policy assertion "{http://schemas.xmlsoap.org/ws/2005/07/securitypolicy}TransportBinding" was evaluated as "UNKNOWN". lip 27, 2017 11:58:35 AM [com.sun.xml.internal.ws.policy.EffectiveAlternativeSelector] selectAlternatives WARNING: WSP0075: Policy assertion "{http://schemas.xmlsoap.org/ws/2005/07/securitypolicy}Trust10" was evaluated as "UNKNOWN". lip 27, 2017 11:58:35 AM [com.sun.xml.internal.ws.policy.EffectiveAlternativeSelector] selectAlternatives WARNING: WSP0075: Policy assertion "{http://schemas.xmlsoap.org/ws/2005/07/securitypolicy}Wss11" was evaluated as "UNKNOWN". lip 27, 2017 11:58:35 AM [com.sun.xml.internal.ws.policy.EffectiveAlternativeSelector] selectAlternatives WARNING: WSP0075: Policy assertion "{http://www.w3.org/2006/05/addressing/wsdl}UsingAddressing" was evaluated as "UNKNOWN". lip 27, 2017 11:58:35 AM [com.sun.xml.internal.ws.policy.EffectiveAlternativeSelector] selectAlternatives WARNING: WSP0019: Suboptimal policy alternative selected on the client side with fitness "UNKNOWN".

Perhaps someone knows more about this kind of problem, or will be able to connect to this WS straight away with his own config - at the moment I don't have a single clue what could be the issue, and I see a "time-wasting" perspective in front of me... so please help.

回答1:

please enable addressing feature:

TerytWs1 teryt = new TerytWs1();
//teryt.setHandlerResolver(new HeaderHandlerResolver());
WebServiceFeature wsAddressing = new AddressingFeature(true);
ITerytWs1 client = teryt.getCustom(wsAddressing);


回答2:

I managed to do connect to TERYT using JAX-WS.

First, you need to generate classes for the client using wsimport. Among the generated classes there will be ITerytWs1 and TerytWs1 - they are the only ones of interest to you at this point. Then you can add the SOAPHandler class to handle the headers, like so:

public class TerytHeaderHandler implements SOAPHandler<SOAPMessageContext>
{
    private String wsUser;
    private String wsPassword;

    public TerytHeaderHandler(String wsUser, String wsPassord)
    {
        this.wsUser = wsUser;
        this.wsPassword = wsPassord;
    }

    @Override
    public boolean handleMessage(SOAPMessageContext smc)
    {
        Boolean outboundProperty = (Boolean) smc.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
        if (outboundProperty.booleanValue())
        {
            try
            {
                SOAPEnvelope envelope = smc.getMessage().getSOAPPart().getEnvelope();
                SOAPHeader header = envelope.getHeader(); 
                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");
                SOAPElement username = usernameToken.addChildElement("Username", "wsse");
                username.addTextNode(wsUser);
                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(wsPassword);
            } catch (Exception e)
            {
                e.printStackTrace();
            }
        } else
        {
            //This handler does nothing with the response from the Web Service
            //even though it should probably check its mustUnderstand headers
            SOAPMessage message = smc.getMessage();
        }
        return outboundProperty;
    }

    @Override
    public boolean handleFault(SOAPMessageContext context)
    {
        // TODO Auto-generated method stub
        return false;
    }

    @Override
    public void close(MessageContext context)
    {
        // TODO Auto-generated method stub
    }

    // Gets the header blocks that can be processed by this Handler instance.
    @Override
    public Set<QName> getHeaders()
    {
        QName securityHeader = new QName("http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", 
                "Security"); 
        HashSet<QName> headers = new HashSet<QName>(); 
        headers.add(securityHeader);         
        return headers; 
    }
}

Then you use it all like this:

public class Main {
public static void main(String[] args) {
    ITerytWs1 instance = new TerytWs1().getCustom(new AddressingFeature(true));
    Binding binding = ((BindingProvider) instance).getBinding();
    List<Handler> handlerList = binding.getHandlerChain();
    if (handlerList == null)
        handlerList = new ArrayList<Handler>(); 
    handlerList.add(new TerytHeaderHandler("TestPubliczny", "1234abcd"));
    binding.setHandlerChain(handlerList);
    System.out.println(instance.czyZalogowany());
}
}

In my case, I had a problem with the getHeaders() function. Managed to deal with it thanks to the suggestion on some other question here on StackOverflow.