Authenticated HttpWebRequest with redirection, persisting credentials? - asp.net

My ASP.NET 2.0 app creates a HTTPWebRequest to a site within a company's intranet, which uses NTLM authentication. The credentials passed are for a service account, which is authenticated on the domain successfully (the security log confirms this)
Some abbreviated code follows..
HttpWebRequest req = WebRequest.Create(queryUrl) as HttpWebRequest;
NetworkCredential cred = new NetworkCredential(username,
pwd, domain);
req.Credentials = cred;
HttpWebResponse response = req.GetResponse() as HttpWebResponse;
As part of the request, there are a couple of redirections (within the same domain) to the final response - which is handled OK on my dev machine (Windows 2k)
When this request is created from my deployment environment (Windows 2k3), I get a 401 Unauthorized error returned from the site, seemingly after the first redirect code is returned (301 Moved), and my request object attempts to follow the redirect.
So basically, does anyone know of any issues surrounding authenticated HttpWebRequests that follow redirections?
PS - The obvious workaround is to simply request the page redirected to - but I the admins in charge of the intranet site want to monitor my app's usage by redirecting me through a specific page.

For HttpWebRequest to reuse credentials across redirects you need to use a credential cache.
If you just assign a NetworkCredentials object it will only be used on the first request.
Here is an example:
HttpWebRequest req = WebRequest.Create(queryUrl) as HttpWebRequest;
NetworkCredential cred = new NetworkCredential(username, pwd, domain);
var cache = new CredentialCache {{queryUrl, "Ntlm", cred}};
req.Credentials = cache;
HttpWebResponse response = req.GetResponse() as HttpWebResponse;

It's going to depend on how your auth. scheme works. The Network credentials is only going to help for the NTLM part of if. I suspect that the site you are trying to access is using forms authentication also. If this is the case, when you log in you should get an auth cookie, you will need to include that in subsequent requests, e.g. after a redirect. I think the WebRequest object has a headers collection that you can use to hold the cookie. Might be a good idea to use fiddler or firebug to see what is coming across when you normally browse.

If you are using NTLM, This is the classic 2 hop problem. It works on your dev machine because the client and the server are on the same box and the credentials are passed at most once (to the redirect final target machine i'm guessing)
When you deploy to your prod environment, there are 3 machines involved. Client browser passes credentials to server1, then server1 tries to pass the credentials to server2 which is not allowed. One work around is to implement Kerberos authentication (a stricter protocol) which will allow server1 to pass credentials to server2

Related

HttpWebRequest 401 error

I am developing an intranet application (Windows Authentication) which download report stream from reporting server then save it as a file. When I ran it in debuging mode it works fine。 The code is as below:
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
req.UseDefaultCredentials = true;
HttpWebResponse response = (HttpWebResponse)req.GetResponse();
Stream fStream = response.GetResponseStream();
However after I deployed it to the server, it won't get response rather than getting 401 unauthorized error.
Even I change the code to:
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
string domain = ConfigurationManager.AppSettings["SchedulerDomain"];
string userName = ConfigurationManager.AppSettings["SchedulerUser"];
string passWord = ConfigurationManager.AppSettings["SchedulerPassword"];
NetworkCredential credential = new System.Net.NetworkCredential(userName, passWord, domain);
req.Credentials = credential;
HttpWebResponse response = (HttpWebResponse)req.GetResponse();
Stream fStream = response.GetResponseStream();
Get the same error. The user setup in the code has the permission to view/run the report.
The IIS7 is using Negotiate and NTLM. (Due to complicated reason, can't change Kerberos), run under ApplicationPoolIdentity
My question is, when I run it under debug mode, the user is my windows account, but why it fails when I tried to send the credential to the reporting server?
Anyone can help?
I capture all the request from the application server to the reporting server, find that all the requests' header's credential username and domain, password are null. Finally I think it is the NTLM causes the issue as here requires two credential hops which NTLM can't handle it, need use Kerberos.
There is another solution if you can't use Kerberos authentication: disable the asp.net impersonation, so from the app server to reporting server will use the applicationpoolidentity, which is a local machine account with account as such: domain/machinename$. So if you grant this account with browse permission on the reporting server, it should work.
I'm not sure how your IIS is configured but it seems like the Identity in your Application Pools setting for your app is overriding any supplied credential. Most obviously, the user that it is trying to authenticate with does not have access. That being said go to your IIS Manager and check the Identity settings for the site's Application Pool.
Change it to a user that has access to the report viewer and that should fix it. I've had a similar issue I posted here in case anyone is interested.

how change Username And Password to proxy

I have username and password to login a web site but i need login with proxy
how can change username and pass to proxy
i can login to web site with this url www.mydomain.com?user=1&pass=2 or insert user and pass to login page
how i can login web site with HttpWebRequest in asp.net C#?
<code>
Encoding encode = System.Text.Encoding.GetEncoding("utf-8");
HttpWebRequest Request = (HttpWebRequest)HttpWebRequest.Create(Url);
HttpWebResponse Response = (HttpWebResponse)Request.GetResponse();
</code>
It is well documented on MSDN, see HttpWebRequest.Proxy Property.
The local computer or application config file may specify that a
default proxy be used. If the Proxy property is specified, then the
proxy settings from the Proxy property override the local computer or
application config file and the HttpWebRequest instance will use the
proxy settings specified. If no proxy is specified in a config
file and the Proxy property is unspecified, the HttpWebRequest
class uses the proxy settings inherited from Internet Explorer on the
local computer. If there are no proxy settings in Internet Explorer,
the request is sent directly to the server.
There is also longer sample code, the most important part is:
WebProxy myProxy = new WebProxy();
myProxy.Address = "your proxy url";
myProxy.Credentials = new NetworkCredential("login", "password");
Request.Proxy = myProxy;

ASP.NET: cannot impersonate the caller (2-hop?)

I have an MVC3 webapplication which runs as a DOMAIN\USER1 account. This user has SPN in AD set and is trusted for delegation.
I want this application to access sharepoint server on behalf of the caller and upload the file for her/him. I use the following code
Dim request = HttpWebRequest.Create(http://sharepoint.domain.com)
request.Method = WebRequestMethods.Http.Head
request.PreAuthenticate = True
Dim identity = New WindowsIdentity(callerName & "#domain.com")
Dim impContext = identity.Impersonate()
'###### At this point identity.ImpersonationLevel is `Impersonate` not `Delegate`
request.Credentials = CredentialCache.DefaultNetworkCredentials
'###### DefaultNetworkCredentials is empty (Username, domain and password are all empty strings)
Dim response As HttpWebResponse
Try
response = request.GetResponse()
Return JsonSuccess()
Catch ex As WebException
'###### I get 401 Unauthorized exception
Return JsonError(ex.Message)
Finally
impContext.Undo()
End Try
My question is. Should the impersonation level at this point be Impersonate or Delegate (Sharepoint runs on a different machine than IIS server)?
In AD I also configured protocol transition for the sharepoint and HTTP, so maybe Impersonate should change to Delegate after it makes the request? I have no idea, guidance will be appreciated.
Another question is - shouldn't CredentialCache.DefaultNetworkCredentials contain at least the username of the impersonated user?
I found the answer here:
http://support.microsoft.com/kb/810572
"Kerberos does not work in a load-balanced architecture and IIS drops back to NTLM authentication. Because you cannot use NTLM for delegation, any applications or services that require delegation do not work. For more information, click the following article number to view the article in the Microsoft"
And that was exactly the case. I tried now with another machine that is not load-balanced and it works.
The only thing that still surprises me is that ImpersonationLevel of the identity is still Impersonate not Delegate...

Can I code HTTP requests to work around SSL warnings?

I have code that makes a server side call to another web service. In many situations this is over SSL. We have problems where this fails when the stars are not completely aligned. I realize that the certificate must be trusted and the internal certificate authorities (CAs) likely have to be manually imported into the trusted root certificate store on the servers. However, there are other cases as well. Today I ran into a problem where if I use a browser to hit the URL I get a warning stating that:
The name on the security certificate is invalid or does not match the name of the site
This is just a warning that you can acknowledge with the browser and tell it to continue to the site.
However, it seems to prevent my code from working. Here is a condensed version of my code:
HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
request.Credentials = new NetworkCredential(user, password);
HttpWebResponse response = request.GetResponse() as HttpWebResponse;
In looking at HttpWebRequest I don't see anything obvious that would help me out and I don't currently have the luxury of trying things out in my developer environment. Is there a simple change I can make to fix this? Are there other similar gotchas I can prevent this way as well?
Kirk, have you looked into using ServerCertificateValidationCallback and simply returning true (as a test) and then augmenting the error checking for the special cases? You can also check out What is the best way of handling non-validating SSL certificates in C# for some other info on checking cer
Working solution:
HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
request.Credentials = new NetworkCredential(user, password);
ServicePointManager.ServerCertificateValidationCallback = delegate(object certsender, X509Certificate cert, X509Chain chain, System.Net.Security.SslPolicyErrors error)
{
return true;
}
HttpWebResponse response = request.GetResponse() as HttpWebResponse;
See also SSLPolicyErrors for the enumeration to review in the delegate.

Get current request's credentials for using in WebRequest

When accessing my site, the user has to enter his credentials. They are basically plain directory access credentials.
At a certain point I check if a certain file they want to download exists by calling
WebRequest req = HttpWebRequest.Create(checkUri.AbsoluteUri);
WebResponse res = req.GetResponse();
Although I can access the checkUri from the browser, I get a 401 when doing the above check. I think I have to set the
req.Credentials
But I don't know where the current credentials are stored...
Any ideas?
--Update--
Integrated Windows Authentication: No
Allow Anonymous: Off
Caler: Link on page of same site (GET)
Impersonation: default is off (don't even know how to enable it in asp.net mvc)
I was having a similar problem on a site where I'm using forms authentication, I was able to solve this problem by using the code provided here as the second reply in the thread.
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(uri);
// Add the current authentication cookie to the request
HttpCookie cookie = HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName];
Cookie authenticationCookie = new Cookie(
FormsAuthentication.FormsCookieName,
cookie.Value,
cookie.Path,
HttpContext.Current.Request.Url.Authority);
req.CookieContainer = new CookieContainer();
req.CookieContainer.Add(authenticationCookie);
WebResponse res = req.GetResponse();
I think you want this:
req.Credentials = CredentialCache.DefaultCredentials;
You're going to need to enable Integrated Windows Authentication.
I don't know what happens in ASP.NET MVC, but in ASP.NET Web Forms impersonation is turned on by:
<identity impersonate="true">
in web.config.

Resources