Authentication Error when querying Darwin (using Objective C)

946 views
Skip to first unread message

VMS Zealot

unread,
Dec 19, 2014, 6:51:55 AM12/19/14
to openrail...@googlegroups.com
I'm trying to make a query to the National Rail Enquiries system using SOAP, using Objective C. Unfortunately, I'm not getting very far with it. I've tried a few things, and all that happens is that I get an authentication error and an empty set of results back. This is compounded by the fact that I've never used SOAP before now either.


I've tried quite a few different things, including change of host, API version and so forth - but I'm fumbling around in the dark, aimlessly trying to find the right magic words - which isn't very productive. I'm sure that I'm vaguely in the right area, and that it's just a matter of fixing the request (code below). Can anyone see what I've done wrong?

soapMessage = [NSString stringWithFormat:@"<?xml version=\"1.0\" encoding=\"utf-8\"?>"
           "<soap:Header>"
           "<ct:AccessToken>"
           "<ct:TokenValue>MY_TOKEN_GOES_HERE</ct:TokenValue>"
           "</ct:AccessToken>"
           "</soap:Header>"
           "<soap:Body>"
           "<ldbt6:GetDepartureBoardRequest xmlns=\"http://thalesgroup.com/RTTI/2012-01-13/ldb/\">"
           "<ldbt6:numRows>10</ldbt6:numRows>"
           "<ldbt6:crs>LST</ldbt6:crs>"
           "</ldbt6:GetDepartureBoardRequest>"
           "</soap:Body>"
           "</soap:Envelope>"];

NSURL *url = [NSURL URLWithString:@"https://realtime.nationalrail.co.uk/LDBWS/ldb6.asmx"];
NSMutableURLRequest *theRequest = [NSMutableURLRequest requestWithURL:url];
NSString *msgLength = [NSString stringWithFormat:@"%lu", (unsigned long)[soapMessage length]];
[theRequest addValue:@"realtime.nationalrail.co.uk" forHTTPHeaderField:@"Host"];
[theRequest addValue:@"text/xml; charset=utf-8" forHTTPHeaderField:@"Content-Type"];
[theRequest addValue:@"http://thalesgroup.com/RTTI/2012-01-13/ldb/GetDepartureBoard" forHTTPHeaderField:@"SOAPAction"];
[theRequest addValue:msgLength forHTTPHeaderField:@"Content-Length"];
[theRequest setHTTPMethod:@"POST"];
[theRequest setHTTPBody:[soapMessage dataUsingEncoding:NSUTF8StringEncoding]];

NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
if(connection)
{
    webResponseData = [NSMutableData data] ;
}
else
{
    NSLog(@"Connection is NULL");
}

All of which returns the error:

<div id="header"><h1>Server Error</h1></div>
<div id="content">
 <div class="content-container"><fieldset>
  <h2>401 - Unauthorized: Access is denied due to invalid credentials.</h2>
  <h3>You do not have permission to view this directory or page using the credentials that you supplied.</h3>
 </fieldset></div>
</div>

The token I'm using is the token supplied by NationalRail. Does it need to be quoted in any manner?

Dave Robinson

unread,
Dec 19, 2014, 7:13:38 AM12/19/14
to openrail...@googlegroups.com
Don't think the token needs quoting, just put XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX in there as per the email.

However, SOAP seems horribly picky if you're not using Visual studio, there were a few entertainments for us persuading perl to do it - and we ended up giving up on SOAP::Lite. 

The following XML just worked for us

<soap:Envelope
  xmlns:ldb="http://thalesgroup.com/RTTI/2014-02-20/ldb/"
  xmlns:soap="http://www.w3.org/2003/05/soap-envelope"
  xmlns:typ="http://thalesgroup.com/RTTI/2013-11-28/Token/types">
  <soap:Header>
    <typ:AccessToken>
      <typ:TokenValue>TOKEN-HERE</typ:TokenValue>
    </typ:AccessToken>
  </soap:Header>
  <soap:Body>
    <ldb:GetDepartureBoardRequest>
      <ldb:crs>LST</ldb:crs>
      <ldb:numRows>10</ldb:numRows>
      <ldb:timeOffset>0</ldb:timeOffset>
      <ldb:timeWindow>120</ldb:timeWindow>
    </ldb:GetDepartureBoardRequest>
  </soap:Body>
</soap:Envelope>

Headers:

Content-type: text/xml;charset=UTF-8
SOAPAction: http://thalesgroup.com/RTTI/2012-01-13/ldb/GetDepartureBoard
Accept-encoding: gzip, x-gzip, deflate, x-bzip2

Maybe it's the prefix for your XML tags?

Dave

Peter Hicks

unread,
Dec 19, 2014, 7:15:36 AM12/19/14
to openrail...@googlegroups.com
Hello


On 19/12/14 11:51, VMS Zealot wrote:
I've tried quite a few different things, including change of host, API version and so forth - but I'm fumbling around in the dark, aimlessly trying to find the right magic words - which isn't very productive. I'm sure that I'm vaguely in the right area, and that it's just a matter of fixing the request (code below). Can anyone see what I've done wrong?
I've taken the XML you posted and tried it out with my API key - and I get an authorization failure.

Your request *looks* OK, but SOAP is a fickle beast and it may be that the XML namespaces you're supplying are very subtly wrong.

In the meantime, to get you up and running, does this work?
<?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/2010-11-01/ldb/commontypes">
  <SOAP-ENV:Header>
    <ns2:AccessToken>
      <ns2:TokenValue>*** TOKEN GOES HERE ***</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>
Cheers,


Peter

VMS Zealot

unread,
Dec 19, 2014, 10:52:35 AM12/19/14
to openrail...@googlegroups.com
Thank you for taking a look.  I tried your version - alas that doesn't work for me either.  I've sent an email to National Rail requesting a new token (no response so far! I guess that it's all quiet for the holidays)

VMS Zealot

unread,
Dec 19, 2014, 10:54:07 AM12/19/14
to openrail...@googlegroups.com
Thank you for taking a look.  I tried your version - alas that doesn't work for me either.  It's very frustrating.

Peter Hicks

unread,
Dec 19, 2014, 10:54:25 AM12/19/14
to openrail...@googlegroups.com

On 19/12/14 15:52, VMS Zealot wrote:
> Thank you for taking a look. I tried your version - alas that doesn't
> work for me either. I've sent an email to National Rail requesting a
> new token (no response so far! I guess that it's all quiet for the
> holidays)
Just checking - are you using the service at
https://lite.realtime.nationalrail.co.uk/OpenLDBWS/ rather than /ldbws?


Peter

Avgoustinos Kadis

unread,
Dec 20, 2014, 6:09:28 AM12/20/14
to openrail...@googlegroups.com
Had the same issue and what Peter suggests (switching to https://lite.realtime.nationalrail.co.uk/OpenLDBWS/) solved it out.
Thx

Peter Hicks

unread,
Dec 20, 2014, 7:01:23 AM12/20/14
to openrail...@googlegroups.com

On 20/12/14 11:09, Avgoustinos Kadis wrote:
Had the same issue and what Peter suggests (switching to https://lite.realtime.nationalrail.co.uk/OpenLDBWS/) solved it out.
I think I've worked it out:

  * If you've requested a token through the OpenLDBWS signup page at http://realtime.nationalrail.co.uk/OpenLDBWSRegistration, your token will only work on the OpenLDBWS endpoint
  * If you requested a token via email prior to OpenLDBWS coming in to existence, your token will work on both the (soon to be decommissioned) API *and* the new API


Peter

Message has been deleted

Peter Hicks

unread,
Dec 22, 2014, 9:51:33 AM12/22/14
to openrail...@googlegroups.com
Hello!

On 22/12/14 10:58, VMS Zealot wrote:
That's great!  Thank you for this - I feel so close that I can touch the solution (is the finish line in sight!?).  I now get "Result Server did not recognize the value of HTTP Header SOAPAction: http://thalesgroup.com/RTTI/2014-02-20/ldb/GetDepartureBoard."  Looks like login now works, but that something else is broken.
I've the SOAP request (including your token, which you probably shouldn't post!), and I get a valid response back.

I don't grok ObjC, however the following line looks suspect:

    [theRequest addValue: @"http://thalesgroup.com/RTTI/2014-02-20/ldb/GetDepartureBoard" forHTTPHeaderField:@"SOAPAction"];


Are you adding an HTTP header of 'SOAPAction'?  I don't think you need this - I can't tell if Postman is sending this, as the traffic on the wire is HTTPS and I don't have anything here at the moment to proxy it so I can look inside... however, try it without the additional header.


Peter

VMS Zealot

unread,
Dec 22, 2014, 10:22:05 AM12/22/14
to openrail...@googlegroups.com
Thanks Peter.  Damn.  I really shouldn't post when I'm falling out of my seat through tiredness.

For everyone else, the code that doesn't work is 

-(void)getTimeTableData

{


    soapMessage = [NSString stringWithFormat:@"<?xml version=\"1.0\"?>\n"

                   "<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/2010-11-01/ldb/commontypes\">\n"

                   " <SOAP-ENV:Header>\n"

                   "  <ns2:AccessToken>\n"

                   "   <ns2:TokenValue>xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx</ns2:TokenValue>\n"

                   "  </ns2:AccessToken>\n"

                   " </SOAP-ENV:Header>\n"

                   " <SOAP-ENV:Body>\n"

                   "  <ns1:GetDepartureBoardRequest>\n"

                   "   <ns1:crs>LST</ns1:crs>\n"

                   "   <ns1:numRows>10</ns1:numRows>\n"

                   "  </ns1:GetDepartureBoardRequest>\n"

                   " </SOAP-ENV:Body>\n"

                   "</SOAP-ENV:Envelope>"];

    

    NSURL *url = [NSURL URLWithString:@"https://lite.realtime.nationalrail.co.uk/OpenLDBWS/ldb6.asmx"];

    NSMutableURLRequest *theRequest = [NSMutableURLRequest requestWithURL:url];

    NSString *msgLength = [NSString stringWithFormat:@"%lu", (unsigned long)[soapMessage length]];

    

    [theRequest addValue:@"thalesgroup.com" forHTTPHeaderField:@"Host"];

    [theRequest addValue: @"text/xml; charset=utf-8" forHTTPHeaderField:@"Content-Type"];

    [theRequest addValue: @"http://thalesgroup.com/RTTI/2014-02-20/ldb/GetDepartureBoard" forHTTPHeaderField:@"SOAPAction"];

    [theRequest addValue: msgLength forHTTPHeaderField:@"Content-Length"];

    [theRequest setHTTPMethod:@"POST"];

    [theRequest setHTTPBody: [soapMessage dataUsingEncoding:NSUTF8StringEncoding]];


    NSURLConnection *connection =

    [[NSURLConnection alloc] initWithRequest:theRequest delegate:self];

    

    if(connection)

    {

        webResponseData = [NSMutableData data] ;

    }

    else

    {

        NSLog(@"Connection is NULL");

    }


}



VMS Zealot

unread,
Dec 22, 2014, 10:24:34 AM12/22/14
to openrail...@googlegroups.com
And we have lift off!  It's working.  Thank you so much to everyone who helped out.


On Monday, December 22, 2014 2:51:33 PM UTC, Peter Hicks wrote:

Chris Northwood

unread,
Dec 22, 2014, 2:44:25 PM12/22/14
to VMS Zealot, openraildata-talk
tbh, I would highly recommend using a SOAP library instead of trying to roll your own, it'll make life much easier. SOAP is a protocol served over HTTP, rather than RESTful interfaces which are just HTTP, so just doing HTTP requests will be painful.

--
You received this message because you are subscribed to the Google Groups "A gathering place for the Open Rail Data community" group.
To unsubscribe from this group and stop receiving emails from it, send an email to openraildata-t...@googlegroups.com.
To post to this group, send email to openrail...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Peter Hicks

unread,
Dec 22, 2014, 5:52:55 PM12/22/14
to openrail...@googlegroups.com

On 22/12/14 19:44, Chris Northwood wrote:
> tbh, I would highly recommend using a SOAP library instead of trying
> to roll your own, it'll make life much easier. SOAP is a protocol
> served over HTTP, rather than RESTful interfaces which are just HTTP,
> so just doing HTTP requests will be painful.
I think this is part of the issue with having a lightweight SOAP API.
If you have something heavyweight, lots of calls, lots of parameters,
sure - good - but if you've only got a handful of straightforward
requests, the learning curve is high if you're just starting out.

I'll do some research and see if I can do a Wiki page with examples of
using SOAP libraries on various common platforms. We have a SOAP API at
the moment, so the best way to get people up to speed with it is
probably to have examples for just about every common language.


Peter

ma...@bushnet.org

unread,
Apr 17, 2015, 10:01:53 AM4/17/15
to openrail...@googlegroups.com
On Monday, 22 December 2014 15:24:34 UTC, VMS Zealot wrote:
> And we have lift off!  It's working.  Thank you so much to everyone who helped out.

Can you provide details of what your working code looks like? I've been struggling with this as well and have been trying every piece of advice I can find but nothing seems to be working. I am not in a position to be able to use a SOAP client, so people, please don't suggest I do!

I am currently connecting to URL:
https://lite.realtime.nationalrail.co.uk/OpenLDBWS/ldb6.asmx

My request has headers:
Content-Type: 'text/xml; charset=utf-8'
SOAPAction: 'http://thalesgroup.com/RTTI/2014-02-20/ldb/GetDepartureBoard'

My request body is:
<?xml version="1.0"?>
<soap:Envelope
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ldb="http://thalesgroup.com/RTTI/2014-02-20/ldb/"
xmlns:typ="http://thalesgroup.com/RTTI/2010-11-01/ldb/commontypes">
<soap:Header>
<typ:AccessToken>
<typ:TokenValue>MY-TOKEN</typ:TokenValue>
</typ:AccessToken>
</soap:Header>
<soap:Body>
<ldb:GetDepartureBoardRequest>
<ldb:numRows>10</ldb:numRows>
<ldb:crs>RIC</ldb:crs>
</ldb:GetDepartureBoardRequest>
</soap:Body>
</soap:Envelope>

The error is:
Server did not recognize the value of HTTP Header SOAPAction: http://thalesgroup.com/RTTI/2014-02-20/ldb/GetDepartureBoard

If I change the SOAPAction to have date part 2012-01-13 then the response is just:
The server cannot service the request because the media type is unsupported.

If I pass an invalid token, then I get a "401 - Unauthorized" response, so I seem to have a valid SOAP header, at least!

Peter Hicks

unread,
Apr 17, 2015, 11:35:14 AM4/17/15
to openrail...@googlegroups.com
Hi Mark

On 17/04/15 15:01, ma...@bushnet.org wrote:
> The error is:
> Server did not recognize the value of HTTP Header SOAPAction: http://thalesgroup.com/RTTI/2014-02-20/ldb/GetDepartureBoard
You don't need to put the SOAP action in the header - that's the
<ldb:GetDepartureBoardRequest> in the <soap:Body>.
> If I change the SOAPAction to have date part 2012-01-13 then the response is just:
> The server cannot service the request because the media type is unsupported.
>
> If I pass an invalid token, then I get a "401 - Unauthorized" response, so I seem to have a valid SOAP header, at least!
Have you tried simply removing the SOAPAction header? I've made an HTTP
POST to /ldb6.asmx with text/xml encoding with my token and your SOAP
request and it works - no headers at all.


Peter

ma...@bushnet.org

unread,
Apr 17, 2015, 11:52:52 AM4/17/15
to openrail...@googlegroups.com
On Friday, 17 April 2015 16:35:14 UTC+1, Peter Hicks wrote:
> Have you tried simply removing the SOAPAction header? I've made an HTTP
> POST to /ldb6.asmx with text/xml encoding with my token and your SOAP
> request and it works - no headers at all.

Thanks for the response.

If I remove the SOAPAction header, the response is the following SOAP error:
Unable to handle request without a valid action parameter. Please supply a valid soap action.

ma...@bushnet.org

unread,
Apr 17, 2015, 11:59:44 AM4/17/15
to openrail...@googlegroups.com, ma...@bushnet.org
On Friday, 17 April 2015 16:52:52 UTC+1, ma...@bushnet.org wrote:
> If I remove the SOAPAction header, the response is the following SOAP error:
> Unable to handle request without a valid action parameter. Please supply a valid soap action.

Just to clarify, that was the response I got when using:
xmlns:ldb="http://thalesgroup.com/RTTI/2012-01-13/ldb/"

If I use:
xmlns:ldb="http://thalesgroup.com/RTTI/2014-02-20/ldb/"

Peter Hicks

unread,
Apr 17, 2015, 12:09:51 PM4/17/15
to openrail...@googlegroups.com


On 17/04/15 16:52, ma...@bushnet.org wrote:
If I remove the SOAPAction header, the response is the following SOAP error: Unable to handle request without a valid action parameter. Please supply a valid soap action.
I get that error if I use a body of:
<soap:Body>
  <ldb:GetDepartureBoard>

    <ldb:numRows>10</ldb:numRows>
    <ldb:crs>RIC</ldb:crs>
  </ldb:GetDepartureBoard>
</soap:Body>
i.e. GetDepartureBoard rather than GetDepartureBoardRequest.

However, I can't reproduce your error here using the input you've sent.

According to http://stackoverflow.com/questions/6850006/php-curl-with-soap-error-unable-to-handle-request-without-valid-action-paramete, you need the SOAPAction header, but I can't see it in the XML data that Postman sends on my side:

POST /OpenLDBWS/ldb6.asmx HTTP/1.1
Host: lite.realtime.nationalrail.co.uk
Content-Type: text/xml
Cache-Control: no-cache

<?xml version="1.0"?>

Something funky's going on here which I can't work out.

Can you send your code over so somebody else can have a go at running/debugging it?


Peter

ma...@bushnet.org

unread,
Apr 17, 2015, 12:25:53 PM4/17/15
to openrail...@googlegroups.com
On Friday, 17 April 2015 17:09:51 UTC+1, Peter Hicks wrote:
> Can you send your code over so somebody else can have a go at
> running/debugging it?

My code is in Google Apps Script:
var URL = 'https://lite.realtime.nationalrail.co.uk/OpenLDBWS/ldb6.asmx';
var TOKEN = 'MY-TOKEN';
var station = 'station I want to look up';
var sr =
'<?xml version="1.0"?>' +
'<soap:Envelope ' +
'xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" ' +
'xmlns:ldb="http://thalesgroup.com/RTTI/2014-02-20/ldb/" ' +
'xmlns:typ="http://thalesgroup.com/RTTI/2010-11-01/ldb/commontypes">' +
'<soap:Header>' +
'<typ:AccessToken>' +
'<typ:TokenValue>' + TOKEN + '</typ:TokenValue>' +
'</typ:AccessToken>' +
'</soap:Header>' +
'<soap:Body>' +
'<ldb:GetDepartureBoardRequest>' +
'<ldb:numRows>10</ldb:numRows>' +
'<ldb:crs>' + station + '</ldb:crs>' +
'</ldb:GetDepartureBoardRequest>' +
'</soap:Body>' +
'</soap:Envelope>';

var headers = {
'Content-Type': 'text/xml; charset=utf-8'
//'SOAPAction': 'http://thalesgroup.com/RTTI/2012-01-13/ldb/GetDepartureBoard'
};
var options = {
'method': 'post',
'headers': headers,
'payload': sr,
'muteHttpExceptions': true
};

var response = UrlFetchApp.fetch(URL, options);

Peter Hicks

unread,
Apr 17, 2015, 12:43:23 PM4/17/15
to openrail...@googlegroups.com
Hi Mark

I have your script working now - the problem is you're setting
Content-Type as a header, and you need to set contentType as a
parameter, i.e. just use:

var options = {
'method': 'post',
'contentType': 'text/xml',
'payload': sr,
'muteHttpExceptions': true
};

I've run your script with my token and I can grab the departure board
for Watford Junction.


Peter

ma...@bushnet.org

unread,
Apr 17, 2015, 12:49:23 PM4/17/15
to openrail...@googlegroups.com
On Friday, 17 April 2015 17:43:23 UTC+1, Peter Hicks wrote:
> I have your script working now - the problem is you're setting
> Content-Type as a header, and you need to set contentType as a
> parameter, i.e. just use:

I can't believe it was something so simple in the end. I really appreciate the help! Was tearing my hair out!

Thanks!
Reply all
Reply to author
Forward
0 new messages