C# maintaining session over HTTPS on the client - c#

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

Related

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).

c# HttpClient does not store some cookies

I'm using the HttpClient (System.Net.Http.HttpCient) to send some requests and I'm also using a CookieContainer to hande Cookies. For some Webpages everything works fine, but on some other pages no cookies are stored, although my browser saves the Cookies when I visit the webpage.
Can someone here explain what's the problem.
ceddy
Maybe these pages redirect to an other url? Cookies are stored per url and hence it's possible you "loose" a cookie.
To verify the behavior you may set
request.AllowAutoRedirect = false;
and look at the response object about what's going on. If this is really the issue in your case, you can copy the cookies from one url to the other via the CookieContainer.

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# Sending an HttpWebRequest without the servername

Basically what I've been trying to do is download a file off a server. The server sends a redirect automatically which is fine, but through packet sniffing a program that does successfully download the file I've found that the Headers (for the second request) are:
GET /path/to/file.txt
...
Host: server.com
Rather than the current response being generated (what I thought was standard):
GET www.server.com/path/to/file.txt
Using the normal HttpWebRequest method results in a 500 server error, and I get exceptions thrown when trying to use just the relative path as one would expect.
Using AllowAutoRedirect does not work for this scenario as the cookies are not handled properly, but even if I handle it manually the same error occurs.
How does one go about doing this (preferably without sockets :D)?
To be honest, I'm really not sure what you are asking, but you mentioned cookie troubles. As a total shot in the dark guess, are you setting the CookieContainer on your WebRequest?
request.CookieContainer = new CookieContainer();
request.AllowAutoRedirect = true;

Cookies in ASP.Net

I set a cookie like this in one page:
Request.Cookies["lang"].Value = "en-US";
Request.Cookies["lang"].Expires = DateTime.Now.AddDays(50);
On another page I try and read the cookie:
string lang = Server.HtmlEncode(Request.Cookies["lang"].Value);
The cookie is not null but the value is an empty string. What am I doing wrong?
You should be using Response.Cookies to set the cookie, and Request.Cookies to read any cookies sent back from the client.
The code in your question is setting the cookie in the Request object, not the Response.
Are cookies enabled on the client? The fact that you set a cookie doesn't mean that the client supports them and will send them back.
Remember, you're dealing with two disconnected systems; your server doesn't keep state and you know little about the client.
If I remember correctly I think you should be using response instead of request as request is what is being sent to you. Response is when you want to set something back to the client browser.
EDIT: What you are doing is modifying the cookies in that particular request which would make sense why you are not seeing on subsequent pages. That is not saving them back to the client.

Categories