HttpWebRequest: how get the session id - c#

we are using a web service for a web site to communicate with an external server.
External server ask for a session id.
Our following code ask external server:
HttpWebRequest webRequest = WebRequest.Create(ExtUrl) as HttpWebRequest;
webRequest.Credentials = new NetworkCredential(ExtAccountToUse, ExtPassword);
HttpWebResponse webResponse;
webRequest.Method = "POST";
webRequest.ContentType = "application/x-www-form-urlencoded";
StreamWriter writer = new StreamWriter(webRequest.GetRequestStream());
writer.Write(xmlOutput);
writer.Close();
webResponse = webRequest.GetResponse() as HttpWebResponse;
Is it possible to get a session id to send to external server ?
Thanks for your time

That depends on the type of server you are sending the request to. For example, if you have an IIS hosted site, it expects a session id inside a cookie named ASP.NET_SessionId (or on the request string). If you have a Java servlet engine on the other side, it expects a cookie called JSESSIONID (or a request path parameter jsessionid).
So it depends. However, setting cookies inside a HttpWebRequest is not difficult. You can use the property CookieContainer:
CookieContainer cookies = new CookieContainer();
cookies.Add(new Cookie("ASP.NET_SessionId", sessionId));
request.CookieContainer = cookies;
The session identifier you store inside the cookie should have a particular format and again, this depends on the server type at the other end. In ASP.NET by default the class SessionIDManager is used to produce and validate session ids. This class is hard to reuse because it requires an HttpContext. However, you could check with Reflector how it generates a session id.

If you mean the external server requires an existing session ID that identifies a session created by prior requests sent to it then you need to maintain an instance of a CookieContainer for all of the requests involved.
CookieContainer myExternalServerCookies = new CookieContainer();
With every HttpWebRequest you use to talk to the external server include this line:-
request.CookieContainer = myExternalServerCookies;
Now when the external server sets a session cookie, it will see that cookie in subsequent requests.

as far as getting session ID is concerned you can get it using:
Session.SessionID
but I don't think session id on your server is of any interest to external server.

Related

How to create a new SSL session for every HttpWebRequest

I am using HttpWebRequest to make a requests to a server and want to go through the complete SSL handshake for every request. Will the following code guarantee a new SSL session for every request?
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(endPoint);
request.CachePolicy = new HttpRequestCachePolicy(HttpRequestCacheLevel.NoCacheNoStore);

Sending post to creation factory on RTC but getting a 'GET' response

I've hit a strange bit of behaviour and I'm pretty sure is related to my code rather than the RTC instance I'm working with.
I've got a web request setup and configured:
var cookies = new CookieContainer();
var request = (HttpWebRequest)WebRequest.Create(getCreationFactoryUri);
var xmlString = getRDF.ToString();
request.CookieContainer = cookies;
request.Accept = "application/rdf+xml";
request.Method = "POST";
request.ContentType = "application/rdf+xml";
request.Headers.Add("OSLC-Core-Version", "2.0");
request.Timeout = 40000;
request.KeepAlive = true;
byte[] bytes = Encoding.ASCII.GetBytes(xmlString);
request.ContentLength = bytes.Length;
Stream dataStream = request.GetRequestStream();
dataStream.Write(bytes, 0, bytes.Length);
dataStream.Close();
This is passed to another method wrote based on an RTC example using forms authentication for RTC.
Under the OSLC v2 spec, I'm using a creation factory URL to post to. I know the URL is fine because I've setup a call using RESTClient in Firefox. Added the headers that are needed (Content-Type: application/rdf+xml, Accept: application/rdf+xml, OSLC-Core-Version: 2.0) and used the generated XML that my code is trying to pass. My manual call works perfectly and the ticket is created.
In my logs I captured the response from RTC, which is a list of tickets rather than a response showing my ticket as being created. I can re-create this behavior by doing a GET on the creation factory URL I'm using to create an event ticket.
So although I know I'm sending a POST to the creation factory (I debugged to check that my web request method was 100% set to 'POST') RTC instead returns a list of tickets and I can only conclude somewhere my request is treated as a 'GET'.
As a test I changed my request to use PUT instead of POST. This isn't permitted for use on the creation factory URL and in testing it indeed throws an error. So I'm totally miffed as to why RTC isn't creating my ticket, but instead treating my request as a GET and returning a list of tickets.
Anyone have any ideas?
Thanks.
If the server using form authentication, as you state, then I expect what is happening is that the POST is resulting in an HTTP redirection to the authentication form. Even if your other code is handling that authentication (which it sounds like it is), the result of that authentication will be an HTTP redirection to the URL of the original request. However, that redirection is likely to result in a GET to that URL, not the original POST. (Also, I don't believe the redirection after authentication is 100% reliable, if your requests are multi-threaded).
The jazz.net information on form authentication says "After authentication succeeded, you always have to replay the original request at least once to get to the protected resource. More replays may be required if the first replay led to another set of redirections and the original request had a non-GET method."
So if your code received an authentication challenge, you will need to re-send the original POST.
I believe the reason why the RESTClient plug-in in your browser is working first time is that it is sending the cookies from your previous log-in to the RTC web UI in the browser. (I had this experience recently, and also found it very confusing).
Also, if you are not preserving cookies between requests to RTC in your client app, then you will meet an auth challenge for every request. If you preserve cookies between calls from your client app (how you do that will depend on your client library - I'm not familiar with the code in your examples) then my experience is that you won't receive an auth challenge for every request. (However, you still need to be able to handle an auth challenge on every request - including POSTs - otherwise it may fail intermittently if the session times out just before you send a POST).

Difference between Request.Cookies and Response.Cookies

I use both of these many times in my code and don't really know what the difference is , if a cookie is set shouldn't it be exactly the same in request and response? and is request going to the the most up to date , or response?
EDIT:
ok , I get the difference between a request and a response, but if I type
string a = HttpContext.Current.Request.Cookie["a"].Value;
it is most of the time the same as
string a = HttpContext.Current.Response.Cookie["a"].Value;
but I am wondering what is the difference between using the two.
As everyone says Request.Cookies are supposed to be cookies coming from client (browser) and Response.Cookies are cookies that will be send back to client (browser).
There is black magic well documented* code that copies values from Response cookies to Request.Cookies when you add cookies to Response. As result it looks like you have same cookies in both Request and Response. Note that these copied cookies did not come from the client... so beware of making wrong decisions.
Here is a link to discussion about the code: http://forums.asp.net/t/1279490.aspx. In particular, cookies added in the following way will show up in the Request.Cookies collection:
Response.Cookies.Add(HttpCookie("MyCookie", "MyValue"))
*The behavior of cookies getting copied from Response.Cookies is documented in the HttpResponse.Cookies article:
After you add a cookie by using the HttpResponse.Cookies collection, the cookie is immediately available in the HttpRequest.Cookies collection, even if the response has not been sent to the client.
The request cookie is what is send from the client to the server (thus what the browser provides). The response cookie are the cookies that you want to place in the browser. The next connection from the browser that accepted the cookie from the response object will provide the cookie in the request object.
The word Response is used in Asp.net to send data from the server to the client and the Request is used to get the data from the client ( in the form of cookies, query string ) etc.
Example:
Response.Write("will write the content on the form which will return to the client");
// Response.Cookies will send the cookie to the client browser.
Response.Cookies.Add(HttpCookie("MyCookie", "MyValue"))
//and Request.Cookies is used to get the cookie value which is already present in the clinet browswer
and as you mentioned
string a = HttpContext.Current.Request.Cookie["a"].Value;
// I think this will check the cookie which is present in the client browser [ If client has sent the cookie to the server ]
string a = HttpContext.Current.Response.Cookie["a"].Value;
// and this will see the only Response object. If the cookie present in the response object then it will return you otherwise not.
Depends on what context.
Request is the data that gets sent to the server with every http request. Response is the response after the request by the server to the client.

c# httpwebrequest credential problem

I am trying to login into www.diary.com using a httpwebrequest object. However, it always fail to login, and kept giving me back the login page. Can anyone enlighten me on what is/are wrong?
My code is as follows:
// prepare the web page we will be asking for
HttpWebRequest request = (HttpWebRequest)
WebRequest.Create(#"http://diary.com/events/agenda");
request.ContentType = "text/html";
request.Credentials = new NetworkCredential(#"user#hotmail.com", "password");
request.AllowAutoRedirect = true;
request.Referer = #"http://diary.com/";
// execute the request
HttpWebResponse response = (HttpWebResponse)
request.GetResponse();
// we will read data via the response stream
Stream resStream = response.GetResponseStream();
// set the WebBrowser object documentStream to the response stream
myWB.DocumentStream = resStream;
// simply tell me the title of the webpage
MessageBox.Show(myWB.Document.Title);
You have two problems here:
You are providing credentials at the protocol level, which is not how most websites (including this one) work. The protocol is totally anonymous, and the site uses Forms Authentication to log you in. Your code needs to actually create a POST request that mimics submitting the login form. The response that comes back from the server will include a cookie that has your auth token, which leads into...
You need to persist cookies across requests. After you submit the login request and get the cookie, you'll need to hang on to it and send it along in the request headers of each subsequent request. The easiest way to do this is to use a WebClient for spanning multiple requests, and a CookieContainer to track the cookies for you.
If you're ever unsure about how to mimic the traffic that goes between your browser and a website, a great tool to use is Fiddler. It captures the raw request/response for you to observe.

C# maintaining session over HTTPS on the client

I need to login to a website and perform an action. The website is REST based so I can easily login by doing this (the login info is included as a querystring on the URL, so I dont't need to set the credentials):
CookieContainer cookieJar = new CookieContainer();
HttpWebRequest firstRequest = (HttpWebRequest) WebRequest.Create(loginUrl);
firstRequest.CookieContainer = cookieJar;
firstRequest.KeepAlive = true;
firstRequest.Method = "POST";
HttpWebResponse firstResponse = (HttpWebResponse)firstRequest.GetResponse();
That works and logs me in. I get a cookie back to maintain the session and it's stored in the cookieJar shown above. Then I do a second request such as this:
HttpWebRequest secondRequest = (HttpWebRequest) WebRequest.Create(actionUrl);
secondRequest.Method = "POST";
secondRequest.KeepAlive = true;
secondRequest.CookieContainer = cookieJar;
WebResponse secondResponse = secondRequest.GetResponse();
And I ensure I assign the cookies to the new request. But for some reason this doesn't appear to work. I get back an error telling me "my session has timed out or expired", and this is done one right after the other so its not a timing issue.
I've used Fiddler to examine the HTTP headers but I'm finding that difficult since this is HTTPS. (I know i can decrypt it but doesn't seem to work well.)
I can take my URL's for this rest service and paste them into firefox and it all works fine, so it must be something I'm doing wrong and not the other end of the connection.
I'm not very familiar with HTTPS. Do I need to do something else to maintain my session? I thought the cookie would be it, but perhaps there is something else I need to maintain across the two requests?
Here are the headers returned when I send in the first request (except I changed the cookie to protect the innocent!):
X-DB-Content-length=19
Keep-Alive=timeout=15, max=50
Connection=Keep-Alive
Transfer-Encoding=chunked
Content-Type=text/html; charset=WINDOWS-1252
Date=Mon, 16 Nov 2009 15:26:34 GMT
Set-Cookie:MyCookie stuff goes here
Server=Oracle-Application-Server-10g
Any help would be appreciated, I'm running out of ideas.
I finally got it working after decrypting the HTTP traffic from my program.
The cookie I'm getting back doesn't list the Path variable. So .NET takes the current path and assigns that as the path on the cookie including the current page. ie: If it was at http://mysite/somepath/somepage.htm it would set the cookie path=/somepath/somepage.htm. This is a bug as it should be assigned to "/" which is what all web browsers do. (hope they fix this.)
After noticing this I grabbed the cookie and modified the path property and everything works fine now.
Anyone else with a problem like this check out Fiddler. .NET uses the windows certificate store so to decrypt http traffic from your program you will need to follow the instructions here: http://www.fiddler2.com/Fiddler/help/httpsdecryption.asp . You will also need to turn on decryption under the Options\HTTPS tab of Fiddler.
From MSDN:
When a user moves back and forth between secure and public areas, the ASP.NET-generated session cookie (or URL if you have enabled cookie-less session state) moves with them in plaintext, but the authentication cookie is never passed over unencrypted HTTP connections as long as the Secure cookie property is set.
So basically, the cookie can be passed over both HTTP and HTTPS if the 'Secure' property is set to 'false'.
see also how can I share an asp.net session between http and https

Categories