Introduction
MSN messenger is a well known program. It lets you communicate with other
users through Instant Messaging. Some people like to write their own MSN
messenger, so that they can make some own adjustments and cool features. I have
written, together with another student, our own MSN client in C#. Recently
Microsoft no longer supported protocols below MSNP 8. So I had to adjust our
program to use MSNP9 (it used MSNP7).
With this little article I would like to explain how you can connect to MSN
again with use of the MSNP9 protocol. Note this article only describes how you
can get a valid TicketId
. The rest of the connection is another
part. If somebody is interested in that part, email me so that I post that information
right here.
Generating a Client Ticket
There are two functions that I have used to write this. You can do this in
one function. But the function GetLoginServerAddres()
is actually
an optional function, because the addresses do not change often. First we define
some variables, to make it a bit easier. We could use a IDictionary
here to get a Key Mapping. But the response is a static response so we could
leave it like this.
public int DARREALM = 0;
public int DALOGIN = 1;
public int DAREG = 2;
public int PROPERTIES = 3;
public int GENERALDIR = 4;
public int HELP = 5;
public int CONFIGVERSION = 6;
public ArrayList PassportUrls;
Now we can start getting the ClientTicket
.
First you call the function GetClientTicket()
with 3 parameters,
first the password, second a valid username and last a valid
ChallengeString
(you get a valid challengestring while connecting
to a MSN server, after that you have to send a clienticket to a MSN server to
get authenticated)
public string GetClientTicket(string Password, string Username,
string ChallengeString)
First thing that the function GetClientTicket()
does is to call
the GetLoginServerAdress()
function.
This function does not need any parameters. Lets look at this function. First
it connects to the nexus server.
HttpWebRequest ServerRequest = (HttpWebRequest)WebRequest.Create(
"https://nexus.passport.com/rdr/pprdr.asp");
HttpWebResponse ServerResponse = (HttpWebResponse)ServerRequest.GetResponse();
If all succeeds, the response will look like this
HTTP/1.1 200 OK \r\n
Server: Microsoft-IIS/5.0\r\n
Date: Mon, 28 Okt 2003 11:57:47 GMT\r\n
Connection: close\r\n
PassportURLs:
DARealm=Passport.Net,DALogin=login.passport.com/login2.srf,
DAReg=http:
Properties=https:
Privacy=http:
GeneralRedir=http:
Help=http:
ConfigVersion=11\r\n
Content-Length: 0\r\n
Content-Type: text/html\r\n
Cache-control: private\r\n
\r\n
If the result is OK
if (ServerResponse.StatusCode == HttpStatusCode.OK)
Then pick up the result
string retrieveddata = ServerResponse.Headers.ToString();
Get the line for PassportURL
s and last split it and put it in
the ArrayList
PassportUrls = new ArrayList();
string[] result = ServerResponse.Headers.Get("PassportURLs").Split(',');
foreach (string s in result)
{
PassportUrls.Add(s.Substring(s.IndexOf('=') + 1));
}
If the GetLoginServerAdress()
is ready, return to the
GetClientTicket()
Now we have a valid address on the DALOGIN
position
string uri = "https://" + PassportUrls[DALOGIN];
HttpWebRequest ServerRequest;
HttpWebResponse ServerResponse;
try
{
The login can be redirected to another server. Because you can not predict
the amount of attempts that you will need for login, so put this step in an
endless loop.
while( true )
{
Make a new request, and set some properties. (protocol 1.0 works better that
1.1)
ServerRequest = (HttpWebRequest)HttpWebRequest.Create(uri);
ServerRequest.AllowAutoRedirect = false;
ServerRequest.Pipelined = false;
ServerRequest.KeepAlive = false;
ServerRequest.ProtocolVersion = new Version(1,0);
Build the authentication header, this will be sent to the TicketServer. And
get the response.
ServerRequest.Headers.Add("Authorization",
"Passport1.4 OrgVerb=GET,OrgURL=http%3A%2F%2Fmessenger%2Emsn%2Ecom,sign-in="
+ Username.Replace("@", "%40") + ",pwd=" + Password + ","
+ ChallengeString + "\n");
ServerResponse = (HttpWebResponse)ServerRequest.GetResponse();
Know we look at the status-code of the response. If it is OK then we have to
parse the Authentication-Info
if (ServerResponse.StatusCode == HttpStatusCode.OK)
{
string AuthenticationInfo = ServerResponse.Headers.Get(
"Authentication-Info");
int startposition = AuthenticationInfo.IndexOf('\'');
// Get the endposition
int endposition = AuthenticationInfo.LastIndexOf('\'');
endposition = endposition - startposition ;
ServerResponse.Close();
return AuthenticationInfo.Substring(startposition + 1, endposition -1 );
}
Here is a OK response from the MSN server, in the Authentication-Info line
you see between two quotes a valid clientticket (start from "from-PP=").
HTTP/1.1 200 OK \r\n
Server: Microsoft-IIS/5.0\r\n
Date: Mon, 28 Okt 2003 11:57:49 GMT\r\n
PPServer: H: LAWPPIIS6B061\r\n
Connection: close\r\n
Content-Type: text/html\r\n
Expires: Mon, 02 Jun 2003 11:58:00 GMT\r\n
Cache-Control: no-cache\r\n
cachecontrol: no-store\r\n
Pragma: no-cache\r\n
P3P: CP="DSP CUR OTPi IND OTRi ONL FIN"\r\n
Set-Cookie:
MSPSec1= ; expires=Thu, 30-Oct-1980 16:00:00 GMT;
domain=.passport.com;path=/;HTTPOnly=;version=1 \r\n
Set-Cookie:
MSPSec=5Cdd1SshOELpwqafsSuYSiDEuEtP1PUaX99YOZca
oJP3vkIn7DXozt868I7eJNjcWG;
HTTPOnly= ; domain=.passport.com;path=/;secure=\r\n
Set-Cookie:
MSPAuth=5yDBU0BqvDa7UiY9W9nVEncRXCLD4gjLmtEr2XkunnafkOgdgG5x
*CEpqe7MyZEOir*EiA1PbwLKzqCGO671TeTQ$$;S
HTTPOnly= ; domain=.passport.com;path=/\r\n
Set-Cookie:
MSPProf=5a0mKE6PKDsxz!*4apQt0amnQOGLYqcCm78ie! MmHq0KnA
iIJM0z0Zajs8NL7ux7Ae0hnH5AAoB!zXIZ9
jTA2rcQttC*RKKRsc9k7JflwThB!H0Qa*6ipGcdj5co6taPir;
HTTPOnly= ; domain=.passport.com;path=/\r\n
Set-Cookie:
MSPVis=507;domain=.passport.com;path=/\r\n
Set-Cookie: MSPPre=esqkk@hotmail.com;
HTTPOnly= ; domain=.passport.com;path=/;
Expires=Wed, 30-Dec-2037 16:00:00 GMT \r\n
Set-Cookie: MSPShared= ;
HTTPOnly= ; domain=.passport.com;path=/;
Expires=Thu, 30-Oct-1980 16:00:00 GMT\r\n
Authentication-Info:
Passport1.4
da-status=success,tname=MSPAuth,tname=MSPProf,tname=MSPSec,
from-PP='t=53*1hAu8ADuD3TEwdXoOMi08sD*2!cMrntTw
VMTjoB3p6stWTqzbkKZPVQzA5NOt19SLI60PY!b8K4YhC!Ooo5ug$$&
p=5eKBBC!yBH6ex5mftp!a9DrSb0B3hU8aqAWpaPn07iCGBw5akemi
WSd7t2ot!okPvIR!Wqk
!MKvi1IMpxfhkao9wpxlMWYAZ!DqRfACmyQGG112Bp9xrk04!BVBUa9
*H9mJLoWw39m63YQRE1yHnYNv08nyz43D3OnMcaCoe
SaEHVM7LpR*LWDme29qq2X3j8N'
,ru=http:
Content-Length: 0\r\n
\r\n
If the statuscode is 302, then there is a redirect, read the new
address and connect again (we are still in the while loop)
else if (ServerResponse.StatusCode == HttpStatusCode.Found)
{
uri = ServerResponse.Headers.Get("Location");
}
Here is a redirect response from the server. You see in the location part
that there is a new login address.
HTTP/1.1 302 Found\r\n
Date: Mon, 28 Okt 2003 11:57:48 GMT\r\n
PPServer: H: LAWPPLOG5C006\r\n
Connection: close\r\n
Content-Type: text/html\r\n
Expires: Mon, 02 Jun 2003 11:57:32 GMT\r\n
Cache-Control: no-cache\r\n
cachecontrol: no-store\r\n
Pragma: no-cache\r\n
P3P: CP="DSP CUR OTPi IND OTRi ONL FIN"\r\n
Authentication-Info: Passport1.4 da-status=redir\r\n
Location: https:
\r\n
A last we have some error handling. If your credentials where not correct you
get a 401 error. Give back the error to the calling function so that the can
warn the user for instance.
catch (WebException e)
{
if (e.Status == WebExceptionStatus.ProtocolError)
{
return "401";
}
else
{
return "0";
}
}
A last here is a 401 response. The official MSN client uses the
"WWW-Authenticate" part to give back a nice error message.
HTTP/1.1 401 Unauthorized\r\n
Server: Microsoft-IIS/5.0\r\n
Date: Mon, 28 Okt 2003 11:58.03 GMT\r\n
PPServer: H: LAWPPIIS6B077\r\n
Connection: close\r\n
Content-Type: text/html\r\n
Expires: Mon, 15 Sep 2003 07:57:14 GMT\r\n
Cache-Control: no-cache\r\n
cachecontrol: no-store\r\n
Pragma: no-cache\r\n
P3P: CP="DSP CUR OTPi IND OTRi ONL FIN"\r\n
PassportConfig: ConfigVersion=11\r\nWWW-Authenticate: Passport1.4
da-status=failed,srealm=Passport.NET,ts=-3,prompt,
cburl=http:
cbtxt=Type%20your%20e-mail%20address%20and%20password
%20correctly.%20If%20you%20haven%E2%80%99t%20registered%20
with%20.NET%20Passport%2C%20click%20the%20Get%20a
%20.NET%20Passport%20link.\r\n
Content-Length: 390\r\n\r\n
Points of Interest
I noticed that this code won't work when you are trying to connect multiple
times. I'm still finding what is causing the error. (I there is a delay in
connecting another account it works quit well)
Conclusion
So now you have read this article you can make your own program that connects
to the MSN server. I'm currently expanding our MSN client, maybe some day it
will be freeware. If you want some more explanation or have some comments, Email me