I would like to know how can I fix this issue wherein a WebApp running on IIS 7/8 with Windows Authentication is throwing 401 error while executing HttpWebRequest to another site. This WebApp works fine if I run it locally i.e debug mode.
Here is the code snippet
HttpWebRequest webReq;
webReq = (HttpWebRequest)WebRequest.Create("http://sharepoint_site/_vti_bin/listdata.svc/mylist);
webReq.Accept = "application/json";
webReq.UseDefaultCredentials = true;
webReq.Credentials = CredentialCache.DefaultNetworkCredentials;
//webReq.Credentials = new NetworkCredential("user","password","domain");
webReq.Method = "GET";
webReq.KeepAlive = true;
Stream objStream = webReq.GetResponse().GetResponseStream();
StreamReader objReader = new StreamReader(objStream);
HttpWebResponse response = (HttpWebResponse)webReq.GetResponse();
I was also able to make it work by adding BackConnectionHostNames entry in the registry
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0
but I need to pass in the credentials (commented above) which I don't like because I don't want to use my account or any service account.
I want the WebApp to use DefaultNetworkCredentials or DefaultCredentials. I enabled Windows Authentication and NTLM provider on the IIS of the machine hosting this WebApp.
Any help will be greatly appreciated, thanks and more power to this community.
CredentialCache.DefaultNetworkCredentials uses the network credentials that the process is running under. If it's running in IIS, it will be the application pool identity, which the web service won't accept.
You will either have to pass different credentials in code (what you said you didn't want to do) or update the application pool to run with network credentials (right-click the application pool in IIS -> Advanced Settings -> Identity)
Related
We use HttpWebRequest to make web service calls to a remote server. The call requires a certificate to be loaded from the local machine.
The problem we are running into is if the Application Pool identity is set to NetworkService then the call fails with a generic TLS/SSL error on the HttpWebResponse.GetResponse() call. If we change the identity of the app pool user to LocalSystem then it functions normally.
What I'm trying to figure out is why. What does LocalSystem have access to that NetworkService doesn't which is impacting a post call?
The code is pretty simple:
string URL = "https://mywebserver.net";
X509Store store = new X509Store(StoreName.Root, StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly);
var certResults = store.Certificates.Find(X509FindType.FindBySubjectName, "nameofthecertificate", false);
/* I have confirmed that the certificate is found regardless of
* how the application pool is configured.
*/
X509Certificate cert = certResults[0];
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(URL);
req.AllowAutoRedirect = true;
req.ClientCertificates.Add(cert);
req.Method = "POST";
req.ContentType = "application/soap+xml;charset=UTF-8";
StringBuilder postData = new StringBuilder();
postData.Append("some soap info");
byte[] postBytes = Encoding.UTF8.GetBytes(postData.ToString());
using (Stream postStream = req.GetRequestStream())
{
postStream.Write(postBytes, 0, postBytes.Length);
postStream.Flush();
postStream.Close();
}
// dies here when running under NetworkService
HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
String data = String.Empty;
using (StreamReader reader = new StreamReader(resp.GetResponseStream()))
{
data = reader.ReadToEnd();
reader.Close();
}
Generally speaking, an Application Pool needs an Identity to run under. You could configure the identity for it to run as you did, but bear in mind that the different identities have different levels of permission.
Your problem could be as simple as the application pool identity not having permissions
for using the code it's trying to execute. You can check that by viewing the deployed projects folder permissions to see.
Since you mentioned SSL/TLS errors, I would be thinking the identity does not have permission on the installed certificate. Open up mmc and check to see if have the certificate in the Local Computer/Personal/Certificates store. If you do, right click on the certificate and go to All Tasks -> Manage Private Keys.... Add in the Application pool identity by adding it from your computer location as:
IIS AppPool\YourNameOfAppPool.
You should not get another dialog saying it wasn't found it you added it correctly.
Read more about the Application pool identities here.
I'm building a RESTful API using dotnet core 1.1.2.
A big part of this api requires making requests to an external WCF service. These requests are authenticated using windows-based authentication with username, password and domain.
I'm currently in the process of making the api production ready and I wanted to try dockerizing it.
The problem I'm having is that authentication fails towards this third party WCF service as soon as it's called from within the docker container. Running the API using the dotnet runtime works from both windows and mac and the service gets authenticated as it should.
I consume the WCF service using the Connect wcf service feature of Visual studio 2017 and then modifying the endpoint binding with the correct authentication
mode.
public ServiceSoapClient(EndpointConfiguration endpointConfiguration, string username, string password, string domain) :
base(ServiceSoapClient.GetBindingForEndpoint(endpointConfiguration), ServiceSoapClient.GetEndpointAddress(endpointConfiguration))
{
this.ChannelFactory.Credentials.Windows.ClientCredential.UserName = username;
this.ChannelFactory.Credentials.Windows.ClientCredential.Password = password;
this.ChannelFactory.Credentials.Windows.ClientCredential.Domain = domain;
this.Endpoint.Name = endpointConfiguration.ToString();
ConfigureEndpoint(this.Endpoint, this.ClientCredentials);
}
private static System.ServiceModel.Channels.Binding GetBindingForEndpoint(EndpointConfiguration endpointConfiguration)
{
if ((endpointConfiguration == EndpointConfiguration.ServiceSoap))
{
System.ServiceModel.BasicHttpBinding result = new System.ServiceModel.BasicHttpBinding();
result.MaxBufferSize = int.MaxValue;
result.ReaderQuotas = System.Xml.XmlDictionaryReaderQuotas.Max;
result.MaxReceivedMessageSize = int.MaxValue;
result.AllowCookies = true;
result.Security.Mode = System.ServiceModel.BasicHttpSecurityMode.Transport;
result.Security.Transport.ClientCredentialType = HttpClientCredentialType.Windows;
return result;
}
throw new System.InvalidOperationException(string.Format("Could not find endpoint with name \'{0}\'.", endpointConfiguration));
}
I've tried both Ntml and Windows as ClientCredentialType.
I've verified that the authentication credentials don't get messed up when transferring the api to the docker container by hard coding the credentials inside the app, then running it using the normal dotnet runtime to verify that it works. Finally building the docker image with exactly the same published app and running it again. When exactly the same app is running inside docker it fails to authenticate.
The output from the application is:
The HTTP request is unauthorized with client authentication scheme ‘Negotiate’. The authentication header received from the server was ‘Negotiate, NTLM’.
Which is the same output as if when I'm using incorrect credentials.
I'm wondering if this could be somehow related to how networking works with docker and if the api can't negotiate with the WCF service since it's bridging through the docker host.
If anyone more knowledgeable with docker or WCF consumtion inside dotnet core might have some insight it would be very helpful.
Best regards, Linus.
For anyone experiencing the same issue this is due to the way kerberos is configured on non-windows platforms. This has nothing to do with docker per say but rather running as a linux-based container.
The solution is to either switch your platform to windows or correctly configure kerberos authentication on your platform. This is discussed in more detail in the following github issues:
https://github.com/dotnet/wcf/issues/2641
and
https://github.com/dotnet/corefx/issues/9533
I have a problem that I haven't been able to resolve for two days.
In a console app, this code works fine:
url="http://www.reuters.com/finance/currencies/quote?srcAmt=1.00&srcCurr=USD&destAmt=&destCurr=ASD&historicalDate=MMddyyyy"
HttpWebRequest req = WebRequest.Create(url) as HttpWebRequest;
req.Timeout = 3000000;
using (HttpWebResponse resp = req.GetResponse() as HttpWebResponse)
{
// ...
}
But in my Windows service, GetResponse() is throwing the exception, "The remote name could not be resolved: 'www.reuters.com'".
I have no idea what I am doing wrong, maybe I am setting something wrong in ServiceInstaller.
Thanks for showing me the right track, but there is an additional issue.
I am working on virtual machine (I have got admin rights, but I have no experience with administration at all).
If I set account in service installer for the user (and give details of my login) then I have problems with the connection to the database (Odbc). Connection open throws me:
ERROR [08001] [MERANT][ODBC Sybase driver]
Allocation of a Sybase Open Client Context failed.
Sybase normally generates a SYBINIT.ERR file containing more specific reasons for failing.\r\n
ERROR [01S00] [MERANT][ODBC Sybase driver]
Invalid attribute in connection string: Port.
So if set Account User in ServiceInstaller I can't connect to the DB, else if I set Account to LocalSystem I can open connection to DB but I can't use GetResponse().
So the question is, what should I do when everything is placed on Windows Terminal Server?
I suppose that there could be something messed up with admin rights. What could I do to fix this? Thanks again.
Windows Service application run under the LocalSystem account by default, whereas your console app runs under your user account, you may therefore be meeting permission problems (windows firewall?)
You should run the service under the administrator account to see if this resolves your issue.
I have written a WinForms app that uploads addresses from a spreadsheet, and geocodes them using an external geocoding service. This all works fine on my local machine, but the time has come for it to be installed on other peoples computers for testing. The app no longer works now though, generating the below error:
System.Net.WebException: The remote server returned an error: (407) Proxy Authentication Required.
Having read a lot and chatted breifly to our network guys, it seems i need to establish the Security Context for the users account and work with this to correct the error.
Has anyone got any pointers about how I should be going about this?
Thanks in advance!
C
It depends on how your uploading the data. If your using a http request (as it looks like you are) it will look something like;
HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create("https://test.example.com/");
req.Method = "POST";
req.ContentType = "text/xml";
req.Credentials = new NetworkCredential("TESTACCOUNT", "P#ssword");
StreamWriter writer = new StreamWriter(req.GetRequestStream());
writer.Write(input);
writer.Close();
var rsp = req.GetResponse().GetResponseStream();
I'm working on a .NET app that calls 3rd party web services over the internet. The services do not use SOAP, so we manually construct an XML request document, send it to the service via HTTP, and retrieve an XML response.
Our code is a Windows service that is run in the context of a normal Windows domain account, and sits behind a proxy server (Microsoft ISA Server) configured to require NTLM authentication. The account running our service has permission to access the internet through the proxy server.
The code looks like this:
// Create the request object.
HttpWebRequest request = (HttpWebRequest) WebRequest.Create(url);
request.Method = "POST";
// Configure for authenticating proxy server requiring Windows domain credentials.
request.Proxy = New WebProxy(proxyAddress) { UseDefaultCredentials = true };
// Set other required headers.
request.Accept = acceptableMimeType;
request.Headers.Add(HttpRequestHeader.AcceptCharset, acceptableCharset);
request.Headers.Add(HttpRequestHeader.AcceptEncoding, "none");
request.Headers.Add(HttpRequestHeader.AcceptLanguage, "en-gb");
request.Headers.Add(HttpRequestHeader.CacheControl, "no-store");
request.Headers.Add(HttpRequestHeader.ContentEncoding, "none");
request.Headers.Add(HttpRequestHeader.ContentLanguage, "en-gb");
request.ContentType = requestMimeType;
request.ContentLength = requestBytes.Length;
// Make the method call.
using(Stream stream = request.GetRequestStream()) {
stream.Write(requestBytes, 0, requestBytes.Length);
}
HttpWebResponse response = (HttpWebResponse) request.GetResponse();
// Extract the data from the response without relying on the HTTP Content-Length header
// (we cannot trust all providers to set it correctly).
const int bufferSize = 1024 * 64;
List<byte> responseBytes = new List<byte>();
using(Stream stream = new BufferedStream(response.GetResponseStream(), bufferSize)) {
int value;
while((value = stream.ReadByte()) != -1) {
responseBytes.Add((byte) value);
}
}
This works fine if the proxy server is turned off, or the URL has been whitelisted as not requiring authentication, but as soon as authentication is active, it always fails with an HTTP 407 error.
I put the above code in a test harness, and tried every method I could think of for configuring the request.Proxy property, without success.
I then noticed that all the 3rd party web services that we have to call are HTTPS. When I tried accessing them as HTTP instead, the proxy authentication started working. Is there some extra hoop I have to jump through to get proxy authentication and HTTPS to play nicely?
PS: The same problems occur with the open source SmoothWall proxy server, so I can't just write it off as a bug in ISA Server.
PPS: I'm aware that you can configure proxy settings in app.config, but (a) doing it in code shouldn't make any difference, and (b) the application design requires that we read the proxy settings from a database at runtime.
Have you tried setting the proxy in the app.config ?
To disable the proxy, in the App.config file add the following configuration
<system.net>
<defaultProxy enabled="false" useDefaultCredentials="false">
<proxy/>
<bypasslist/>
<module/>
</defaultProxy>
</system.net>
To enable the proxy and to use the default proxy settings(specified in IE) add this configuration in your App.config
<system.net>
<defaultProxy enabled="true" useDefaultCredentials="true">
<proxy/>
<bypasslist/>
<module/>
</defaultProxy>
</system.net>
I did have a similar situation
Did you noticed it worked when you accessed the internet before you ran the code? and if you had not accessed the internet for ages (20mins for me) you got the error.
have you tried to set the proxy credentials directly?
//setup the proxy
request.Proxy = new WebProxy("proxyIp", 8080);
request.Proxy.Credentials = CredentialCache.DefaultCredentials;
I hope this fixes your issue too
I think I will have to write off this question. My original posted code does appear to work sometimes. Our proxy server is extremely unreliable; one minute it will block an internet connection from any software, and the next it will allow it. The IT guys seem powerless to do anything about it, and we (everyone outside the IT department) have no authority to make changes to the network infrastructure.
If anyone has any ideas on how to "harden" my code to compensate for an unreliable proxy server, then I'd be interested to hear them. :-)
Is there something wrong with your proxy server's certificate? If your service can't establish HTTPS then it will throw an error.