0

I am calling a SOAP API that returns XML and am receiving the following error

Error -

    title>401 - Unauthorized: Access is denied due to invalid credentials.</title>

I have used the information I can find on others SO queries, SOAP info and my specific calls documentation and this is my code that I have put together so far for it

String soap = 
  '''<?xml version="1.0"?>
 <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" 
 xmlns:ns1="http://thalesgroup.com/RTTI/2014-02-20/ldb/" 
 xmlns:ns2="http://thalesgroup.com/RTTI/2017-10-01/ldb/GetDepartureBoard">
  <SOAP-ENV:Header>
    <ns2:AccessToken>
      <ns2:TokenValue>my_token</ns2:TokenValue>
    </ns2:AccessToken>
  </SOAP-ENV:Header>
  <SOAP-ENV:Body>
    <ns1:GetDepartureBoardRequest>
      <ns1:numRows>10</ns1:numRows>
      <ns1:crs>MAN</ns1:crs>
    </ns1:GetDepartureBoardRequest>
  </SOAP-ENV:Body>
 </SOAP-ENV:Envelope>''';

  // Send the POST request, with full SOAP envelope as the request body.
 http.Response response = await http.post(Uri.parse(
  'https://lite.realtime.nationalrail.co.uk/OpenLDBWS/ldb11.asmx'),
  headers: {
    'Content-Type': 'text/xml; charset=utf-8',
    'SOAPAction': 'http://thalesgroup.com/RTTI/2017-10-01/ldb/GetDepartureBoard'
  },
  body: soap
);


var rawXmlResponse = response.body;


final parsedXml = XmlDocument.parse (rawXmlResponse);
print(parsedXml);


}

The provider of the API states in their documentation

    This token shall be passed as a SOAP Header value.

Is my inclusion in the body enough or how do I reference it in the section...

headers: {
    'Content-Type': 'text/xml; charset=utf-8',
    'SOAPAction': 'http://thalesgroup.com/RTTI/2017-10-01/ldb/GetDepartureBoard'

Here is an example - https://wiki.openraildata.com/index.php/GetDepBoardWithDetails

Data from - https://realtime.nationalrail.co.uk/OpenLDBWS/

Thank you

Updated call

String soap = 
  '''
<SOAP-ENV:Envelope 
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" 
xmlns:ns1="http://thalesgroup.com/RTTI/2017-10-01/ldb/"
xmlns:ns2="http://thalesgroup.com/RTTI/2013-11-28/Token/ns2es">
 <SOAP-ENV:Header>
   <ns2:AccessToken>
     <ns2:TokenValue>my_token</ns2:TokenValue>
   </ns2:AccessToken>
 </SOAP-ENV:Header>
 <SOAP-ENV:Body>
   <ns1:GetDepartureBoardRequest>
     <ns1:numRows>10</ns1:numRows>
     <ns1:crs>MAN</ns1:crs>
   </ns1:GetDepartureBoardRequest>
 </SOAP-ENV:Body>
</SOAP-ENV:Envelope>''';
 

  // Send the POST request, with full SOAP envelope as the request body.
 http.Response response = await http.post(Uri.parse(
  'https://realtime.nationalrail.co.uk/OpenLDBWS/wsdl.aspx?ver=2017-10-01'),
  headers: {
    'SOAPAction': 'http://thalesgroup.com/RTTI/2017-10-01/ldb/GetDepartureBoard'
  },
  body: soap
);

Updated response

<wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" xmlns:tns="http://thalesgroup.com/RTTI/2017-10-01/ldb/" targetNamespace="http://thalesgroup.com/RTTI/2017-10-01/ldb/">
<wsdl:import namespace="http://thalesgroup.com/RTTI/2017-10-01/ldb/" location="rtti_2017-10-01_ldb.wsdl"/>
<wsdl:service name="ldb">
  <wsdl:port name="LDBServiceSoap" binding="tns:LDBServiceSoap">
    <soap:address location="https://realtime.nationalrail.co.uk/OpenLDBWS/ldb11.asmx"/>
  </wsdl:port>
  <wsdl:port name="LDBServiceSoap12" binding="tns:LDBServiceSoap12">
    <soap12:address location="https://realtime.nationalrail.co.uk/OpenLDBWS/ldb11.asmx"/>
  </wsdl:port>
</wsdl:service>
</wsdl:definitions>

Which is this webpage - https://realtime.nationalrail.co.uk/OpenLDBWS/wsdl.aspx?ver=2017-10-01

al246
  • 220
  • 6
  • 16
  • Your `ns2` looks completely wrong. Compare it with the linked example and you'll see it should be `"http://thalesgroup.com/RTTI/2013-11-28/Token/types" ` Have you tried the exact XML from the example (but with your access token)? One other minor thing: you've said that your content is utf-8 in the content header, so make the body `utf8.encode(soap)` otherwise `http` will encode it for you in Latin-1 which will be the same most of the time, until it isn't... – Richard Heap Feb 05 '22 at 02:22

1 Answers1

2

The correct SOAP message should look like this:

<SOAP-ENV:Envelope 
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" 
xmlns:ns1="http://thalesgroup.com/RTTI/2017-10-01/ldb/"
xmlns:ns2="http://thalesgroup.com/RTTI/2013-11-28/Token/ns2es">
 <SOAP-ENV:Header>
   <ns2:AccessToken>
     <ns2:TokenValue>my_token</ns2:TokenValue>
   </ns2:AccessToken>
 </SOAP-ENV:Header>
 <SOAP-ENV:Body>
   <ns1:GetDepartureBoardRequest>
     <ns1:numRows>10</ns1:numRows>
     <ns1:crs>MAN</ns1:crs>
   </ns1:GetDepartureBoardRequest>
 </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

Pay attention to the ns1 and ns2 namespaces.

Based on the documentation you posted, the WSDL to use is at https://realtime.nationalrail.co.uk/OpenLDBWS/wsdl.aspx?ver=2017-10-01 and the namespaces to use based on that WSDL are the ones from the message I posted. The example you are using look older; the page is published on 18 October 2016, at 20:51, but the version parameter on the WSDL says 2017).

Before writing your code, I suggest you feed that WSDL link to SoapUI and do a few test calls until you make the call work with SoapUI. Then you can write your code to duplicate the request that SoapUI is making.

Obviously, you also need a valid token to send to the service. Since it's used for access, if you are not sending a valid one then you clearly won't get access, even if your SOAP message is properly built.

All licensed users will be issued with a token to access public web services. This token shall be passed as a SOAP Header value. The service will reject all requests with no token or an incorrect token code.

Are you a licensed user? Did you receive a token from them to use in your calls?

EDIT: after the extra details added to the question.

You are not sending your SOAP message to the correct endpoint. You need to do a POST to https://realtime.nationalrail.co.uk/OpenLDBWS/ldb11.asmx not to https://realtime.nationalrail.co.uk/OpenLDBWS/wsdl.aspx?ver=2017-10-01.

The https://realtime.nationalrail.co.uk/OpenLDBWS/wsdl.aspx?ver=2017-10-01 URL just gives you the WSDL of the service, and the SOAP address inside the WSDL tells you where the endpoint of the service actually is:

<soap:address location="https://realtime.nationalrail.co.uk/OpenLDBWS/ldb11.asmx"/>

You may want to read these also:

In regards to how you get the WSDL of a service and its endpoint, usually the convention is to use POST endpoint to invoke the service, and GET endpoint?wsdl to get the WSDL. But that's just a convention. The two things can be separated from each other, and in your case they are. You get the WSDL on one endpoint and the invocation is done on another. That's why you need to use a different endpoint.

Bogdan
  • 23,890
  • 3
  • 69
  • 61
  • Thank you for your comprehensive response. The information I have found is varied and some dated so have struggled piecing it together. I have implemented your edits and have a new response which I have posted as an ```update``` in the Q. Your question about token, yes I am a licensed user and I have the full token with access to the data – al246 Feb 05 '22 at 23:57
  • @al246: see update to my answer. – Bogdan Feb 06 '22 at 14:30