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);
Related
I'm trying to send HttpWebRequest to a secure website using a client certificate through ASP.NET web app. The app is hosted on IIS under Windows Server 2016.
Whenever I try to send a request I'm receiving the following exception:
System.Net.WebException: The request was aborted: Could not create SSL/TLS secure channel.
The tricky part is that it works on my Windows 7 machine. I've managed to simulate at 100% the production environment and I've received the expected response.
Here is the code I'm using to send the request:
ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12;
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
request.ClientCertificates.Add(this.Certificate);
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
var stream = response.GetResponseStream();
using (StreamReader reader = new StreamReader(stream))
{
string responseData = reader.ReadToEnd();
return responseData;
}
I am trying to add functionality to my C# app, to test a connection to an OData service which is secured with only Windows Authentication. The following block of code is what I am using to perform this test:
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(new Uri(SERVICE_NAME));
CredentialCache myCache = new CredentialCache();
myCache.Add(new Uri(SERVICE_NAME), "Negotiate", new NetworkCredential(user, password));
resolver.Credentials = myCache;
// Do a simple request
request.Credentials = myCache;
request.PreAuthenticate = true;
request.KeepAlive = true;
request.AllowAutoRedirect = true;
request.CookieContainer = new CookieContainer();
object response = request.GetResponse(); // This is where the exception is thrown
When I run the above code, I receive the 401 - Unauthorized error as previously stated. However, when I have Fiddler2 running, the code works fine. So I am using Wireshark instead. In addition, the service works perfect within my browser (Chrome), and if I use Wireshark to compare the HTTP requests/responses for the Authentication, I see that they are nearly identical, except that in Chrome I have: Accept, User-Agent, Accept-Encoding, and Accept-Language headers, while my C# app does not have these. The only other difference is that my C# app sets the "Negotiate Seal" flag in the NTLM header, while Chrome does not set this flag.
Despite these differences, the authentication phase seems to work fine in the C# app, up until the service returns a 302 - Redirection, at which point the app tries a GET on the newly redirected URI, which returns a 401 again (when Chrome does the analogous GET, it receives HTTP 200 - OK, and proceeds on its merry way).
So, any ideas what could cause this? Problem with the service? or my code?
Thanks a lot!
-Erik
Ok, two whole days of research and I found the answer. Line 3 in the code above was using the full URI of the service (".../Northwind/Northwind.svc"), when the request was redirected, the credentials no longer applied to the new URI. The solution was to pass in only the beginning part ("...") of the URI. Stupid mistake on my part.
I have some basic questions on HTTP authentication
1) How does client know about Server's authentication type (Basic/Digest/NTLM) of HTTP ? is this configurable at HTTP Server side?
My Answer: Server will be set with which authentication type it has to perform with the client.
So our client API(in C# HttpWebRequest API) will automatically take care of it.
Best use of Wireshrk with applying HTTP filter; you will get source and Destination IP at Internet Protocol layer. And src and dest port at Transmission control protocol and athentication type at http layer.
2) If i place squid linux proxy in between client and Server; is there any need from my client code should know about authentication type of proxy also? or authentication type is only related to the end HTTP server?
My Answer: If squid proxy is placed in between Client and Server; it wont use HTTP authentication. It may use a) DB: Uses a SQL database b) LDAP: Uses the Lightweight Directory Access Protocol. c) RADIUS: Uses a RADIUS server for login validation. and etc..
So we have to mention proxy authentication credentials in HTTP Headers.
3) Using WireShark found that there are three request from Browser to Server to fulfill single request.
a) Browser sends a request without any authentication credentials; So server responded with 401 along with relam and nonce.
WWW-Authenticate: Digest realm="realm", qop="auth", nonce="MTM1OTYyMzkyNDU4MzpiOWM0OWY0NmMzMzZlMThkMDJhMzRhYmU5NjgwNjkxYQ=="\r\n <BR>
b) The second time Browser sends request with credentials, relam, nonce, cnonce; but still server responded with 401;
WWW-Authenticate: Digest realm="realm", qop="auth", nonce="MTM1OTYyMzk0OTAyMTo3Njk3MDNhZTllZDQyYzQ5MGUxYzI5MWY2MGU5ZDg0Yw==", stale="true"\r\n
c) The third time Browser send the same request with same credentials, relam, nonce, cnonce. This time Server sends 200 ok.
My Question is in the second and third time Browser send the same request; why Server failed at second time and success at the third time. Is this because of my server implementation ? (I am having REST Java server with SPRING Security filter).
I have C# HTTP client;
where in the first time HttpWebRequest is sent without credentials though the System.Net.NetworkCredentials is set; so clinet got 407 with relam, and nonce. The second time HttpWebRequest is scuccess. There is no third request from this client like browser.
Why this difference between the browser and C# client?
My Answer: I am still don't know what is happening here: Q3.
4) Now the real issue i am facing is When SQUID LINUX PROXY came in between our Client and HTTP Server, Browser did the same three request authentication and succeeded. However C# HttpWebRequest is failed (401) at the second request and reached the cache(exception){} block and not tried for the third time.
Could you please anyone clarify me how to resolve this issue in C# client when PROXY SERVER is in between?
Below code is doing the GET Request.
HttpWebRequest request = WebRequest.Create("url") as HttpWebRequest;
request.Credentials = new NetworkCredential(loginUserName, password);
WebResponse response = request.GetResponse();
Note that our request to proxy is send via TCP protocol not with HTTP protocol. Then from PROXY to SERVER is communicated with HTTP protocol.
But HTTP request from Proxy has the info about our client ip in the HTTP header X-Forwarded-For.
Below are the possible solutions
These solutions only required if your proxy requires any authentication else ignore it.
Solution 1: working for me
request.Proxy.Credentials = System.Net.CredentialCache.DefaultNetworkCredentials;
Solution 2:
IWebProxy proxy = WebRequest.GetSystemWebProxy();
proxy.Credentials = new NetworkCredential(UserName, UserPassword, UserDomain);
request.Proxy = proxy;
Solution 3 given by Martin:
var proxy = new WebProxy ("http://localhost:3128/");
proxy.Credentials = new NetworkCredential (UserName, UserPassword, UserDomain);
request.Proxy = proxy;
Learn more about proxy authentication at
http://wiki.squid-cache.org/Features/Authentication
It's a challenge/response protocol. Usually, the client makes an initial request without any authentication headers (you may set request.PreAuthenticate = true to send the credentials with the first request).
Then, the server responds with a list of authentication methods that it supports.
If the user did not explicitly specify an authentication method using CredentialsCache, the runtime will try them all, from strongest to weakest. Some protocols (NTLM, for instance) require multiple requests from client to server. In theory, Digest should work with a single one, no idea why it's sending the request twice.
Regarding your proxy question, there are two different kinds of authentication:
The target web server's authentication, a proxy simply passes this though and you don't need any special code in your client.
In addition to that, the proxy itself may also require authentication - which may be different from the one of target web server.
You specify these using
var proxy = new WebProxy ("http://localhost:3128/");
proxy.Credentials = new NetworkCredential ("username", "password");
and then
WebRequest.DefaultWebProxy = proxy;
or
request.Proxy = proxy;
Don't set any credentials on the WebProxy if your proxy server doesn't use any authentication.
If you can't get authentication working while using a proxy server, look at the actual requests that are being sent between the three parties (web server, proxy, client) with Wireshark.
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.
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.