invalid request on wstlogin.srf (WS-Trust)
- Hello,
Each time I try to authenticate with Windows Live Date using RPS I get an "invalid request" error response.
<?xml version='1.0' encoding='UTF-8'?><S:Envelope xmlns
="http://www.w3.org/2003/05/soap-envelope" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns
sf="http://schemas.microsoft.com/Passport/SoapServices/SOAPFault">
<S:Body><S:Fault><S:Code><S:Value>S
ender</S:Value></S:Code><S:Reason><S:Text xml:lang="en-US">Invalid Request</S:Text></S:Reason></S:Fault></S:Body></S:Envelope>
I follow the directives from http://msdn2.microsoft.com/en-us/library/bb447721.aspx replacing username and password values but I always got the same error.
Any help ?
Answers
You can use the following code to acquire RPS tickets.
Code Snippetusing
System;using
System.Net;using
System.Xml;using
System.Xml.XPath;class
Program{
static void Main(string[] args){
TicketAcquirer t = new TicketAcquirer(); string s = t.GetTicket(); Console.WriteLine(s);}
}
public
class TicketAcquirer{
private const string userName = "yourWindowsLiveID@hotmail.com"; private const string password = "yourPassword"; private const string applicationId = "10"; // An arbitrary value that will be defined in the next non-alpha release private const string soapEnvelope = @"<s:Envelopexmlns:s = ""http://www.w3.org/2003/05/soap-envelope""
xmlns:wsse = ""http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd""
xmlns:saml = ""urn:oasis:names:tc:SAML:1.0:assertion""
xmlns:wsp = ""http://schemas.xmlsoap.org/ws/2004/09/policy""
xmlns:wsu = ""http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd""
xmlns:wsa = ""http://www.w3.org/2005/08/addressing""
xmlns:wssc = ""http://schemas.xmlsoap.org/ws/2005/02/sc""
xmlns:wst = ""http://schemas.xmlsoap.org/ws/2005/02/trust"">
<s:Header>
<wlid:ClientInfo xmlns:wlid = ""http://schemas.microsoft.com/wlid"">
<wlid:ApplicationID>"
+ applicationId + @"</wlid:ApplicationID></wlid:ClientInfo>
<wsa:Action s:mustUnderstand = ""1"">http://schemas.xmlsoap.org/ws/2005/02/trust/RST/Issue</wsa:Action>
<wsa:To s:mustUnderstand = ""1"">https://dev.login.live.com/wstlogin.srf</wsa:To>
<wsse:Security>
<wsse:UsernameToken wsu:Id = ""user"">
<wsse:Username>"
+ userName + @"</wsse:Username><wsse:Password>"
+ password + @"</wsse:Password></wsse:UsernameToken>
</wsse:Security>
</s:Header>
<s:Body>
<wst:RequestSecurityToken Id = ""RST0"">
<wst:RequestType>http://schemas.xmlsoap.org/ws/2005/02/trust/Issue</wst:RequestType>
<wsp:AppliesTo>
<wsa:EndpointReference>
<wsa:Address>http://live.com</wsa:Address>
</wsa:EndpointReference>
</wsp:AppliesTo>
<wsp:PolicyReference URI = ""MBI""></wsp:PolicyReference>
</wst:RequestSecurityToken>
</s:Body>
</s:Envelope>
"
; /* methods */ public string GetTicket(){
const string url = @"https://dev.login.live.com/wstlogin.srf"; WebRequest request = WebRequest.Create(url);request.Method =
"POST";request.ContentType =
"application/soap+xml; charset=UTF-8";request.Timeout = 10 * 1000;
// Wait for at most 10 seconds byte[] bytes = System.Text.Encoding.UTF8.GetBytes(soapEnvelope);request.GetRequestStream().Write(bytes, 0, bytes.Length);
request.GetRequestStream().Close();
WebResponse response;response = request.GetResponse();
string xml; using (System.IO.StreamReader reader = new System.IO.StreamReader(response.GetResponseStream()))xml = reader.ReadToEnd();
response.Close();
XmlDocument document = new XmlDocument();document.LoadXml(xml);
XmlNamespaceManager nsManager = new XmlNamespaceManager(document.NameTable);nsManager.AddNamespace(
"wsse", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"); XmlNode node = document.SelectSingleNode(@"//wsse:BinarySecurityToken/text()", nsManager); if (node == null) return null; // The wsse:BinarySecurityToken element is missing. Examine the xml for error information else return node.Value;}
}
- So, as it turns out, I should have wait 10 minutes or so before making that last post. Oh well.... hopefully the code will help somebody else.
ANYWAY, I do not see the exceptions when I set the Proxy property of the request object. I'm still not exactly sure what's going on here, but it works great when I put the following line of code in somewhere before the GetRequestStream() call:
request.Proxy = new WebProxy();
I got this info from: http://www.eggheadcafe.com/forumarchives/netframeworkcompactframework/oct2005/post25272866.asp
OK, there you have it. It still would be nice to know *why* this is happening.
-Aaron
All Replies
Could you please post the code you are using to make the request. Please replace the real Windows Live ID and password with some dummy values when posting on the forum.
- The documentation is possibly out of date, I will post the correct SOAP envelope once I get more information. Thanks for your patience.
- Just before we shipped Cumulus there was a last minute change in the syntax for the WS-Trust requests. We have the new syntax and we need to update our docs. Hopefully that should happen early next week. Sorry for the confusion.
Yaron You can use the following code to acquire RPS tickets.
Code Snippetusing
System;using
System.Net;using
System.Xml;using
System.Xml.XPath;class
Program{
static void Main(string[] args){
TicketAcquirer t = new TicketAcquirer(); string s = t.GetTicket(); Console.WriteLine(s);}
}
public
class TicketAcquirer{
private const string userName = "yourWindowsLiveID@hotmail.com"; private const string password = "yourPassword"; private const string applicationId = "10"; // An arbitrary value that will be defined in the next non-alpha release private const string soapEnvelope = @"<s:Envelopexmlns:s = ""http://www.w3.org/2003/05/soap-envelope""
xmlns:wsse = ""http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd""
xmlns:saml = ""urn:oasis:names:tc:SAML:1.0:assertion""
xmlns:wsp = ""http://schemas.xmlsoap.org/ws/2004/09/policy""
xmlns:wsu = ""http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd""
xmlns:wsa = ""http://www.w3.org/2005/08/addressing""
xmlns:wssc = ""http://schemas.xmlsoap.org/ws/2005/02/sc""
xmlns:wst = ""http://schemas.xmlsoap.org/ws/2005/02/trust"">
<s:Header>
<wlid:ClientInfo xmlns:wlid = ""http://schemas.microsoft.com/wlid"">
<wlid:ApplicationID>"
+ applicationId + @"</wlid:ApplicationID></wlid:ClientInfo>
<wsa:Action s:mustUnderstand = ""1"">http://schemas.xmlsoap.org/ws/2005/02/trust/RST/Issue</wsa:Action>
<wsa:To s:mustUnderstand = ""1"">https://dev.login.live.com/wstlogin.srf</wsa:To>
<wsse:Security>
<wsse:UsernameToken wsu:Id = ""user"">
<wsse:Username>"
+ userName + @"</wsse:Username><wsse:Password>"
+ password + @"</wsse:Password></wsse:UsernameToken>
</wsse:Security>
</s:Header>
<s:Body>
<wst:RequestSecurityToken Id = ""RST0"">
<wst:RequestType>http://schemas.xmlsoap.org/ws/2005/02/trust/Issue</wst:RequestType>
<wsp:AppliesTo>
<wsa:EndpointReference>
<wsa:Address>http://live.com</wsa:Address>
</wsa:EndpointReference>
</wsp:AppliesTo>
<wsp:PolicyReference URI = ""MBI""></wsp:PolicyReference>
</wst:RequestSecurityToken>
</s:Body>
</s:Envelope>
"
; /* methods */ public string GetTicket(){
const string url = @"https://dev.login.live.com/wstlogin.srf"; WebRequest request = WebRequest.Create(url);request.Method =
"POST";request.ContentType =
"application/soap+xml; charset=UTF-8";request.Timeout = 10 * 1000;
// Wait for at most 10 seconds byte[] bytes = System.Text.Encoding.UTF8.GetBytes(soapEnvelope);request.GetRequestStream().Write(bytes, 0, bytes.Length);
request.GetRequestStream().Close();
WebResponse response;response = request.GetResponse();
string xml; using (System.IO.StreamReader reader = new System.IO.StreamReader(response.GetResponseStream()))xml = reader.ReadToEnd();
response.Close();
XmlDocument document = new XmlDocument();document.LoadXml(xml);
XmlNamespaceManager nsManager = new XmlNamespaceManager(document.NameTable);nsManager.AddNamespace(
"wsse", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"); XmlNode node = document.SelectSingleNode(@"//wsse:BinarySecurityToken/text()", nsManager); if (node == null) return null; // The wsse:BinarySecurityToken element is missing. Examine the xml for error information else return node.Value;}
}
Here is an example of a success response:
Code Snippet<?xml version="1.0" encoding="utf-8" ?>
<S:Envelope xmlns:S = "http://www.w3.org/2003/05/soap-envelope">
<S:Header></S:Header>
<S:Body>
<wst:RequestSecurityTokenResponse
xmlns:S = "http://www.w3.org/2003/05/soap-envelope"
xmlns:psf = "http://schemas.microsoft.com/Passport/SoapServices/SOAPFault"
xmlns:wsse = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
xmlns:saml = "urn:oasis:names:tc:SAML:1.0:assertion"
xmlns:wst = "http://schemas.xmlsoap.org/ws/2005/02/trust"
xmlns:wsp = "http://schemas.xmlsoap.org/ws/2004/09/policy"
xmlns:wsu = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<wst:TokenType>urn:passport:compact</wst:TokenType>
<wsp:AppliesTo xmlns:wsa = "http://www.w3.org/2005/08/addressing">
<wsa:EndpointReference>
<wsa:Address>http://live.com</wsa:Address>
</wsa:EndpointReference>
</wsp:AppliesTo>
<wst:Lifetime>
<wsu:Created>2007-06-07T18:49:18Z</wsu:Created>
<wsu:Expires>2007-06-08T02:49:18Z</wsu:Expires>
</wst:Lifetime>
<wst:RequestedSecurityToken>
<wsse:BinarySecurityToken Id = "Compact0">t=EwDQARAnAAAURATre1Nkcu71L953y0QRAvwyKdOAAOvPFywnEgZhxfuteZvux+A1CLkGwMCfwYlgzbRgp4fSlR1uB0MNhh7navf0P0Pj8SFzF4quFfao4hhOdu8KI0A4ZnkK4Tnv45bUThaJZDS87I2FOZyvbe6h9upyej/nDdZTv4L3m6VurwVwNbaRdOjjPCmcz0NB9NBHz/bZwn4LA2YAAAgclX6u5SBpQCABpEvjTYKLQwGktsCM8MapkzNRvEr2OhXJGAhqflDzP7TlQqeoU6EeNuWmntZFFN/RX5DFxkyx2QbLi5Zat7/z9qDBZPcRrx6wm/LbllVS7Bhpk7J0nS8rGyhRMXpCxf1xb9DazXGVBip5o4LGM3f5ZPLbOsLuypO4fTIcZ49FxjdhoyABJcfwFvR8POYDbV+6KpBf8J7XHL5JkUTcAfS7uquZem5nzq+jClxl7EoGzgBktmznQKVhGrkbR69zR82zsD0fuZqFJ/AkQ+1zDL1IDNTcCOT/8st0hhHakrDfbWZfZ6+KxUh7ucx/1z8VZA9jxAyS7RmDtC1cxEjgDooHip227l5zm3WiLPjIrhty9wmjIPP3zw4sxbuh8/UV9yfdQAE=&p=</wsse:BinarySecurityToken>
</wst:RequestedSecurityToken>
<wst:RequestedAttachedReference>
<wsse:SecurityTokenReference>
<wsse:Reference URI = "REXF1JXpv5fuoOdA0CfdEb3d4OQ="></wsse:Reference>
</wsse:SecurityTokenReference>
</wst:RequestedAttachedReference>
<wst:RequestedUnattachedReference>
<wsse:SecurityTokenReference>
<wsse:Reference URI = "REXF1JXpv5fuoOdA0CfdEb3d4OQ="></wsse:Reference>
</wsse:SecurityTokenReference>
</wst:RequestedUnattachedReference>
</wst:RequestSecurityTokenResponse>
</S:Body>
</S:Envelope>Here is an example of a failure response:
Code Snippet<?xml version='1.0' encoding='UTF-8'?>
<S:Envelope
xmlns:S = "http://www.w3.org/2003/05/soap-envelope"
xmlns:wsse = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
xmlns:psf = "http://schemas.microsoft.com/Passport/SoapServices/SOAPFault">
<S:Body>
<S:Fault>
<S:Code>
<S:Value>wsse:FailedAuthentication</S:Value>
</S:Code>
<S:Reason>
<S:Text xml:lang = "en-US">Authentication Failure</S:Text>
</S:Reason>
</S:Fault>
</S:Body>
</S:Envelope>Has anyone gotten this to work with .NET CF? Here are a few things I have picked up:
- The HttpWebRequest must allow write stream buffering:
Code Snippetrequest.AllowWriteStreamBuffering = true;- The TicketAcquirer class should implement the ICertificatePolicy interface, and always return true in CheckValidationResult():
Code Snippet#region
ICertificatePolicy Memberspublic
bool CheckValidationResult(ServicePoint srvPoint, X509Certificate certificate, WebRequest request, int certificateProblem){
return true;}
#endregion
The first line of GetTicket() then becomes:
Code SnippetSystem.Net.
ServicePointManager.CertificatePolicy = this;Even after all of these "fixes" I still get an Invalid Request SOAP fault in the response. I am currently stuck here:
Code Snippet<?xml version='1.0' encoding='UTF-8'?>
<S:Envelope xmlns:S="http://www.w3.org/2003/05/soap-envelope" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:psf="http://schemas.microsoft.com/Passport/SoapServices/SOAPFault">
<S:Body>
<S:Fault>
<S:Code>
<S:Value>S:Sender</S:Value>
</S:Code>
<S:Reason>
<S:Text xml:lang="en-US">Invalid Request</S:Text>
</S:Reason>
</S:Fault>
</S:Body>
</S:Envelope>
- Hi, marsboee, sorry for the delay of response. I cannot get the code snippet running right now since PocketPC simulator just cannot successfully connect to the network. I will try it again back home using my own cellphone and let you know if I get anything out of it.
Hi. Thanks for the effort. I also had the problem where my simulator couldn't connect. The behavior I am describing was seen on my WM5 device in debug mode.
I look forward to the results of your attempt.
Is JavaScript imlementation available for the C# code anywhere, as an alternative?
As it would be great to use this RPS method of requestion a token straigh from JavaScript.
I am developing a gadget which connects to Windows Live account to get contact details
from an address book, and would like to retrieve the auth.token with the help of JavaScript, not C# code. Is it possible?Sergei:
I'm not aware of a JavaScript implementation and I'm not very familiar with gadgets, but I believe can use RPS with JavaScript and the Web Gadgets framework.Also consider using the Contacts Control as an alternative. I just asked Koji Kato, the Program Manager for the Contacts Control and he said you can embedd the control on a Web Gadget.
Let me know how it goes!
Thanks for your help, Federico.
I already had a look at the Contacts Control before, however in doubt if I can customise it enough. What I would like my gadget to display is the list of contacts as a simple list of links, when you click on a name the flyout opens with the specific information on this contact. At the moment to authenticate to the address book of Windows Live I'm using C# code to get auth.token via RPS and then with AJAX I am sending it to the server to get XML data back. Thus, I am not sure that Contacts Control will allow me to do this?
- OK, more on making this work with the .NET CF. Apparently, the request *HAS* to have it's ContentLength property set. By doing this, I can get the ticket successfully (finally).
Here's some code:
Code SnippetHttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
request.Method = "POST";
request.ContentType = "application/soap+xml; charset=UTF-8";
request.Timeout = 60 * 1000; // Wait for at most 60 seconds
byte[] bytes = System.Text.Encoding.UTF8.GetBytes(soapEnvelope);
request.AllowWriteStreamBuffering = true;
request.ContentLength = bytes.Length;
Stream stream = request.GetRequestStream();
stream.Write(bytes, 0, (int)request.ContentLength);
stream.Close();
HttpWebResponse response = null;
response = request.GetResponse() as HttpWebResponse;
The only issue I see now is I see a "System.IO.IOException" first-chance exception and a "System.UriFormatException" first-chance exception roll by as the GetRequestStream() function is called. I'm not sure what's going on here, or if I need to worry about it??
Let me know, community, what you think.
-Aaron Hi, Aaron:
Very nice work. Please let us know what kind of cool app you have come up with for mobile platforms. We will have more exciting new feature in this upcoming beta release (hint: much more interesting than dumb addresses/telephones/last names). Please stay tuned.
As for the exceptions, I am not sure about the IOException, but the UriFormatException is a bit weird. What is the Uri you are using?
- Well, currently, I'm just working on a little app that will synchronize my Live Contacts with my Pocket Outlook address book. It's quite bare-bones at the moment. Also, I'm hoping it will beecome obsolete with WM6 (and all of its built-in Live finctionality).
After I get this sync app going pretty well ,I'm planning on cloning the Windows Live ID Client SDK library so it will work in .NET CF. That is, if you guys don't do it first!!
Now, on to the remaining exceptions. The Uri I'm using is https://dev.login.live.com/wstlogin.srf
Here's the compete code. Sorry for the length (I wanted to maake sure nothing relevant gets left out). The exceptions in question appear during the GetRequestStream() call. It's marked in the code:
private const string ticketUrl = @"https://dev.login.live.com/wstlogin.srf";
public string GetTicket()
{
System.Net.ServicePointManager.CertificatePolicy = this;
Uri address = new Uri(ticketUrl);
// Create the web request
HttpWebRequest request = WebRequest.Create(address) as HttpWebRequest;
// Set type to POST
request.Method = "POST";
request.ContentType = "application/soap+xml; charset=UTF-8";
request.AllowWriteStreamBuffering = true;
// Create a byte array of the data we want to send
byte[] byteData = UTF8Encoding.UTF8.GetBytes(soapEnvelope);
// Set the content length in the request headers
request.ContentLength = byteData.Length;
// Write data
// THIS NEXT LINE CAUSES THE FIRST-CHANCE EXCEPTIONS!!!!!!!!!!!!!!!
using (Stream postStream = request.GetRequestStream())
{
postStream.Write(byteData, 0, byteData.Length);
}
// Get response
string xml = string.Empty;
using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
{
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
xml = reader.ReadToEnd();
}
}
if (string.IsNullOrEmpty(xml))
{
return "";
}
XmlDocument document = new XmlDocument();
document.LoadXml(xml);
XmlNamespaceManager nsManager = new XmlNamespaceManager(document.NameTable);
nsManager.AddNamespace("wsse", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
XmlNode node = document.SelectSingleNode(@"//wsse:BinarySecurityToken/text()", nsManager);
if (node == null)
{
return null; // The wsse:BinarySecurityToken element is missing. Examine the xml for error information
}
else
{
string ticket = node.Value;
ticket = ticket.Substring(2);
return ticket;
}
} - So, as it turns out, I should have wait 10 minutes or so before making that last post. Oh well.... hopefully the code will help somebody else.
ANYWAY, I do not see the exceptions when I set the Proxy property of the request object. I'm still not exactly sure what's going on here, but it works great when I put the following line of code in somewhere before the GetRequestStream() call:
request.Proxy = new WebProxy();
I got this info from: http://www.eggheadcafe.com/forumarchives/netframeworkcompactframework/oct2005/post25272866.asp
OK, there you have it. It still would be nice to know *why* this is happening.
-Aaron Aaron:
I'm glad your problem was solved.
I'm not familiar with the CF, but I suspect the reason your program doesn't work without the WebProxy setting is because your network configuration requires HTTP requests go through a proxy.
If I'm not mistaken, when you don't assign a WebProxy the HTTP request goes directly to the server . If you specify the WebProxy property, on the other hand, by default it would get the proxy from the Internet Explorer setting.
I'll ask around about the plans for Live ID and the CF.
Hi Ashok.
I just implemented the same code that you have posted here. But it throws the following error:
The remote server returned an error: (501) Not Implemented.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.Net.WebException: The remote server returned an error: (501) Not Implemented.Where do u think I have gone wrong?
Thank you very much

