WCF configuration/authentication not working in Azure - c#

I'm trying to call an external service that has Windows authentication, it works fine from my Windows development machine running in IIS but once I publish the site to Azure it can't authenticate with the service even if the configuration is the same. The error I get back is,
System.ServiceModel.Security.MessageSecurityException:
The HTTP request is unauthorized with client authentication scheme 'Negotiate'.
The authentication header received from the server was 'Negotiate'. --->
System.Net.WebException: The remote server returned an error: (401) Unauthorized.
It feels like in Azure it's not even trying the authenticate.
The configuration for the service looks like this,
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="Custom_Binding" maxBufferSize="2147483647" maxReceivedMessageSize="2147483647" maxBufferPoolSize="524288" receiveTimeout="00:20:00" sendTimeout="00:20:00">
<readerQuotas maxDepth="32" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://www.otherdomain.com/webServiceRequest" binding="basicHttpBinding" bindingConfiguration="Custom_Binding" contract="webServiceRequest_Port" name="webServiceRequest_Port" />
</client>
</system.serviceModel>
This is the c# code that makes the request,
var client = new webServiceRequest_PortClient();
client.ClientCredentials.UserName.UserName = "domain\Username";
client.ClientCredentials.UserName.Password = "Password";
var response = await client.PerformServiceAsync(method, request);
/Viktor

Does it work if you set the Windows credentials?
var client = new webServiceRequest_PortClient();
client.ClientCredentials.Windows.ClientCredential.UserName = "domain\Username";
client.ClientCredentials.Windows.ClientCredential.Password = "Password";
var response = await client.PerformServiceAsync(method, request);

System.ServiceModel.Security.MessageSecurityException:
The HTTP request is unauthorized with client authentication scheme 'Negotiate'.
The authentication header received from the server was 'Negotiate'. --->
System.Net.WebException: The remote server returned an error: (401) Unauthorized
According to exception I assume that you publish your website to Azure WebApp.
If we want to use the Windows Authenticated, we need to ensure that Windows Authentication is enabled for the web server. We could remote to Azure website to check that there is no Windows Authenticated under the Authentication option, details please refer to the screenshot.
If Azure could service is possible, could use the Azure cloud service as a work around.

Related

Web Service exception : An error occurred while receiving the HTTP response to

We are working with a third-party company and we are using their webservice. all of the methods work fine except one method whiche requires a byte[] (File) as input.
when we call the method we get this exception:
An error occurred while receiving the HTTP response to https://someaddress/Services/DefineMerchant.
This could be due to the service endpoint binding not using the HTTP protocol.
This could also be due to an HTTP request context being aborted by the server (possibly due to the service shutting down). See server logs for more details.
The underlying connection was closed: An unexpected error occurred on a receive.
Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host.
An existing connection was forcibly closed by the remote host
this is the line that throws the exception:
using (var client = new SomeService.DefineMerchantsClient())
{
client.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.None;
client.ClientCredentials.UserName.UserName = "*****";
client.ClientCredentials.UserName.Password = "****";
var response = await client.AddRequestDocumentAsync(new MarketerDocEntity { File = requestData.File, DocumentType = requestData.DocumentType, DocumentTrackingCode = requestData.DocumentTrackingCode });
}
and this is my App.config (console application - .Net Framework 4.7.2):
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IDefineMerchants"
maxBufferSize="2147483647" maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647">
<security mode="TransportWithMessageCredential" />
<readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647"
maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="https://someaddress/Services/DefineMerchant" binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IDefineMerchants" contract="SomeService.IDefineMerchants" name="BasicHttpBinding_IDefineMerchants"/>
</client>
</system.serviceModel>
<system.web>
<httpRuntime maxRequestLength="2147483647" executionTimeout="103600"/>
</system.web>
I have also tried this line of code but it didn't work:
System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
Is this exception a server side error(which I don't have access to)? or should I change something in my program?
thanks!
As far as I know, there may be the following solutions:
The firewall. Sometimes this goes wrong because the firewall is turned on, turn it off and try again.
Add the following code to the wcf server config.
<dataContractSerializer maxItemsInObjectGraph="2147483647" />
Check whether the binding BasicHttpBinding_IDefineMerchants is defined in the client configuration file. Also if you want to better tracking problem, includeExceptionDetailInFaults value can be set to true.
Feel free to contact me if have any issues.

client HTTP request is unauthorized on server 2012 but works on 2008

I am calling a WCF service from console app, I do not have any control on WCF service.
this console app works fine on my development system and one 2008 server, When I move it to server running windows 2012 it gives error The HTTP request is unauthorized with client authentication scheme 'Negotiate'. The authentication header received from the server was 'Negotiate,NTLM'
app config file contains
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="ServiceNameSoap" maxBufferSize="5242880" maxReceivedMessageSize="5242880">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows"/>
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://someCompanyurl.com/ServiceName" binding="basicHttpBinding" bindingConfiguration="ServiceNameSoap" contract="ServiceName.ServiceNameSoap" name="ServiceNameSoap"/>
</client>
actual code is
ServiceNameSoapClient proxy = new ServiceNameSoapSoapClient();
proxy.ClientCredentials.Windows.ClientCredential.Domain = connStringParts[DOMAIN];
proxy.ClientCredentials.Windows.ClientCredential.UserName = connStringParts[USER_NAME];
proxy.ClientCredentials.Windows.ClientCredential.Password = connStringParts[PASSWORD];
proxy.ClientCredentials.Windows.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Delegation;
RequestHeader soapHeader = new RequestHeader();
soapHeader.clientApplicationName = ConfigurationManager.AppSettings["clientApplicationName"];
ServiceNameRequestCollection request = new ServiceNameRequestCollection();
adding some flags to request
Response = proxy.Method(soapHeader, request, out Response);
I have searched extensively, haven't fond any solution .
any setting missing or configuration missing on 2012 server?
have tried changing Ntlm to Windows and Vice versa . same error, negotiate changes to ntlm in error message.
Thanks

Can/Should a web application connect to a secure web service on the same server?

I have a web application and web service on the same server. Both are .NET. For the web service I setup 2 versions. One is secure and uses https. The other is not. Applications not on the server use the secure instance and it works fine. I can use the unsecure instance (http) for the web application that is on the same server and it works fine.
My question: Can or should you use a secure version of a web service when you are connecting to it from the same server?
Thanks.
UPDATE
Web service binding:
<wsHttpBinding>
<binding name="WSHttpBinding_IPaging" maxReceivedMessageSize="20000000" maxBufferPoolSize="20000000" sendTimeout="00:25:00">
<readerQuotas maxDepth="32" maxArrayLength="200000000" maxStringContentLength="200000000" />
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="None"></transport>
<message clientCredentialType="Windows"/>
</security>
</binding>
</wsHttpBinding>
The endpoint defined:
<endpoint address="https://<server_name>/PagingServiceSecure/PagingService.Paging.svc" binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IPaging" contract="PagingService.IPaging" name="WSHttpBinding_IPaging">
When trying to connect to the secure web service that is on a server from my local machine, I get the error:
Security Support Provider Interface (SSPI) authentication failed.
The server may not be running in an account with identity 'host/'.
If the server is running in a service account (Network Service for example),
specify the account's ServicePrincipalName as the identity in the EndpointAddress for the server.
I don't understand the error. I have a certificate on the server. Shouldn't the check be that the connection is using the correct domain and then allow access to the web service?

WCF service with WsHttpBinding & windows authentication failing with anonymous access error

Good day. I've written a service in WCF that uses message-level security, which is set to use Windows authentication. The relevant configuration is shown below:
<wsHttpBinding>
<binding name="WsHttpBinding" closeTimeout="00:30:00" openTimeout="00:30:00"
receiveTimeout="00:30:00" sendTimeout="00:30:00" maxBufferPoolSize="2147483647"
maxReceivedMessageSize="2147483647">
<readerQuotas maxStringContentLength="2147483647" maxArrayLength="2147483647"
maxBytesPerRead="2147483647" />
<security mode="Message">
<message clientCredentialType="Windows" establishSecurityContext="true" />
</security>
</binding>
</wsHttpBinding>
The developer of the calling client requested that my service is configured using these details. I also do not have access to the configuration of the client binding unfortunately, but I can only assume it is configured properly, since other services that are consumed by it is working.
The service is hosted through IIS, as an application under the default website. The Authentication for the service application is set to Windows, with Anonymous authentication turned off. It also doesn't have a SSL certificate bound to it.
When the service gets called from the client, the following error is reported in the logs:
The HTTP request is unauthorized with client authentication scheme 'Anonymous'. The authentication header received from the server was 'Negotiate,NTLM'.
Any help resolving this issue will be greatly appreciated.
Additional Info
In an effort to find a solution, I had thrown together a WinForms test client to call the service. The client binding is configured as follows:
<wsHttpBinding>
<binding name="WSHttpBinding_IEAIEndpointService" closeTimeout="00:10:00"
openTimeout="00:10:00" receiveTimeout="00:10:00" sendTimeout="00:10:00"
maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647">
<security mode="Message">
<message clientCredentialType="Windows" establishSecurityContext="true" />
</security>
</binding>
</wsHttpBinding>
Before making calls using the client proxy, I have the following code to set the Windows user account I want the service to authenticate with:
client.ClientCredentials.Windows.ClientCredential = new System.Net.NetworkCredential("Username", "Password", "DOMAIN");
Even with this configuration, I am still receiving the above-mentioned error.
IIS authentication is transport security. Your client requested message security, so you need to disable it. Message security will be handled by WCF, not IIS.

The HTTP request is unauthorized with client authentication scheme 'Ntlm' The authentication header received from the server was 'NTLM'

I know there's a lot of questions on SO similar to this, but I couldn't find one for this particular issue.
A couple of points, first:
I have no control over our Sharepoint server. I cannot tweak any IIS settings.
I believe our IIS server version is IIS 7.0.
Our Sharepoint Server is anticipating requests via NTLM.
Our Sharepoint Server is on the same domain as my client computer.
I am using .NET Framework 3.5, Visual Studio 2008
I am trying to write a simple console app to manipulate Sharepoint data using Sharepoint Web Services. I have added the Service Reference, and the following is my app.config:
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="ListsSoap" closeTimeout="00:01:00" openTimeout="00:01:00"
receiveTimeout="00:10:00" sendTimeout="00:01:00" allowCookies="false"
bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
useDefaultWebProxy="true">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<security mode="Transport">
<transport clientCredentialType="Ntlm" proxyCredentialType="Ntlm" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="https://subdomain.companysite.com/subsite/_vti_bin/Lists.asmx"
binding="basicHttpBinding" bindingConfiguration="ListsSoap"
contract="ServiceReference1.ListsSoap" name="ListsSoap" />
</client>
</system.serviceModel>
This is my code:
static void Main(string[] args)
{
using (var client = new ListsSoapClient())
{
client.ClientCredentials.Windows.ClientCredential = new NetworkCredential("username", "password", "domain");
client.GetListCollection();
}
}
When I call GetListCollection(), the following MessageSecurityException gets thrown:
The HTTP request is unauthorized with client authentication scheme 'Ntlm'.
The authentication header received from the server was 'NTLM'.
With an inner WebException:
"The remote server returned an error: (401) Unauthorized."
I've tried various bindings and various code tweaks to try to authenticate properly, but to no avail. I'll list those below.
I've tried the following steps:
Using a native Win32 Impersonator before creating the client
using (new Impersonator.Impersonator("username", "password", "domain"))
using (var client = new ListsSoapClient())
{
client.ClientCredentials.Windows.ClientCredential = new NetworkCredential("dpincas", "password", "domain");
client.GetListCollection();
}
This produced the same error message.
Setting TokenImpersonationLevel for my client credentials
using (var client = new ListsSoapClient())
{
client.ClientCredentials.Windows.AllowedImpersonationLevel = TokenImpersonationLevel.Impersonation;
client.GetListCollection();
}
This produced the same error message.
Using security mode=TransportCredentialOnly
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Ntlm" />
</security>
This resulted in a different error message:
The provided URI scheme 'https' is invalid; expected 'http'.
Parameter name: via
However, I need to use https, so I cannot change my URI scheme.
I've tried some other combinations that I can't remember, but I'll post them when I do. I'm really at wits end here. I see a lot of links on Google that say "switch to Kerberos", but my server seems to only be accepting NTLM, not "Negotiate" (as it would say if it was looking for Kerberos), so that is unfortunately not an option.
Any help out there, folks?
Visual Studio 2005
Create a new console application project in Visual Studio
Add a "Web Reference" to the Lists.asmx web service.
Your URL will probably look like: http://servername/sites/SiteCollection/SubSite/_vti_bin/Lists.asmx
I named my web reference: ListsWebService
Write the code in program.cs (I have an Issues list here)
Here is the code.
using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
namespace WebServicesConsoleApp
{
class Program
{
static void Main(string[] args)
{
try
{
ListsWebService.Lists listsWebSvc = new WebServicesConsoleApp.ListsWebService.Lists();
listsWebSvc.Credentials = System.Net.CredentialCache.DefaultNetworkCredentials;
listsWebSvc.Url = "http://servername/sites/SiteCollection/SubSite/_vti_bin/Lists.asmx";
XmlNode node = listsWebSvc.GetList("Issues");
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
}
}
Visual Studio 2008
Create a new console application project in Visual Studio
Right click on References and Add Service Reference
Put in the URL to the Lists.asmx service on your server
Ex: http://servername/sites/SiteCollection/SubSite/_vti_bin/Lists.asmx
Click Go
Click OK
Make the following code changes:
Change your app.config file from:
<security mode="None">
<transport clientCredentialType="None" proxyCredentialType="None"
realm="" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
To:
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Ntlm"/>
</security>
Change your program.cs file and add the following code to your Main function:
ListsSoapClient client = new ListsSoapClient();
client.ClientCredentials.Windows.ClientCredential = System.Net.CredentialCache.DefaultNetworkCredentials;
client.ClientCredentials.Windows.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Impersonation;
XmlElement listCollection = client.GetListCollection();
Add the using statements:
using [your app name].ServiceReference1;
using System.Xml;
Reference: http://sharepointmagazine.net/technical/development/writing-caml-queries-for-retrieving-list-items-from-a-sharepoint-list
After a lot of trial and error, followed by a stagnant period while I waited for an opportunity to speak with our server guys, I finally had a chance to discuss the problem with them and asked them if they wouldn't mind switching our Sharepoint authentication over to Kerberos.
To my surprise, they said this wouldn't be a problem and was in fact easy to do. They enabled Kerberos and I modified my app.config as follows:
<security mode="Transport">
<transport clientCredentialType="Windows" />
</security>
For reference, my full serviceModel entry in my app.config looks like this:
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="TestServerReference" closeTimeout="00:01:00" openTimeout="00:01:00"
receiveTimeout="00:10:00" sendTimeout="00:01:00" allowCookies="false"
bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
maxBufferSize="2000000" maxBufferPoolSize="2000000" maxReceivedMessageSize="2000000"
messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
useDefaultWebProxy="true">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<security mode="Transport">
<transport clientCredentialType="Windows" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="https://path/to/site/_vti_bin/Lists.asmx"
binding="basicHttpBinding" bindingConfiguration="TestServerReference"
contract="TestServerReference.ListsSoap" name="TestServerReference" />
</client>
</system.serviceModel>
After this, everything worked like a charm. I can now (finally!) utilize Sharepoint Web Services. So, if anyone else out there can't get their Sharepoint Web Services to work with NTLM, see if you can convince the sysadmins to switch over to Kerberos.
After many answers that did not work, I finally found a solution when Anonymous access is Disabled on the IIS server. Our server is using Windows authentication, not Kerberos. This is thanks to this blog posting.
No changes were made to web.config.
On the server side, the .SVC file in the ISAPI folder uses MultipleBaseAddressBasicHttpBindingServiceHostFactory
The class attributes of the service are:
[BasicHttpBindingServiceMetadataExchangeEndpointAttribute]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
public class InvoiceServices : IInvoiceServices
{
...
}
On the client side, the key that made it work was the http binding security attributes:
EndpointAddress endpoint =
new EndpointAddress(new Uri("http://SharePointserver/_vti_bin/InvoiceServices.svc"));
BasicHttpBinding httpBinding = new BasicHttpBinding();
httpBinding.Security.Mode = BasicHttpSecurityMode.TransportCredentialOnly;
httpBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Ntlm;
InvoiceServicesClient myClient = new InvoiceServicesClient(httpBinding, endpoint);
myClient.ClientCredentials.Windows.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Impersonation;
(call service)
I hope this works for you!
If I recall correctly, there are some issues with adding SharePoint web services as a VS2K8 "Service Reference". You need to add it as an old-style "Web Reference" to work properly.
I have the same setup that you do, and this works fine for me. I think that maybe the problem lies somewhere on your moss configuration or on your network.
You said that moss resides on the same domain as your application. If you have access to the site with your user (that is logged into your machine)... have you tried:
client.ClientCredentials.Windows.ClientCredential = System.Net.CredentialCache.DefaultNetworkCredentials;
I had exactly the same issue last week - WCF program behaves strangely on one server - why?
For me the solution was rather simple. Sharepoint has its own set of permissions. My client tried to log on as a user that wasn't explicitly given access to the webservice through Sharepoint's administration panel.
I added the user to Sharepoint's whitelist and bang - it just worked.
Even if that isn't the issue, please note that
The HTTP request is unauthorized with client authentication scheme ‘Ntlm’. The authentication header received from the server was ‘NTLM’.
Means (in English) that you simply don't have permission. Your protocol is probably right - your user just doesn't have permissions.
I would try to connect to your Sharepoint site with this tool here. If that works you can be sure that the problem is in your code / configuration. That maybe does not solve your problem immediately but it rules out that there is something wrong with the server. Assuming that it does not work I would investigate the following:
Does your user really have enough rights on the site?
Is there a proxy that interferes? (Your configuration looks a bit like there is a proxy. Can you bypass it?)
I think there is nothing wrong with using security mode Transport, but I am not so sure about the proxyCredentialType="Ntlm", maybe this should be set to None.
I have had this issue before.
client.ClientCredentials.Windows.AllowedImpersonationLevel = TokenImpersonationLevel.Impersonation;
do this against your wcf proxy before making the call.
Try this
<client>
<endpoint>
<identity>
<servicePrincipalName value="" />
</identity>
</endpoint>
</client>
I've encountered this error before when working in a webfarm and this fixed it for me.
This issue was even more strange for us. Everything worked if you had previously visited the sharepoint site from the browser, before you made the SOAP call. However, if you did the SOAP call first we'd throw the above error.
We were able to resolve this issue by installing the sharepoint certificate on the client and adding the domain to the local intranet sites.

Categories

Resources