WCF authentication schemes mismatch? - c#

I am using .Net 3.5 and attempting to configure a WCF service and am receiving the exception, The HTTP request is unauthorized with client authentication scheme 'Negotiate'. The authentication header received from the server was 'Negotiate,NTLM'. I have attached my server-side and client-side .config files below.
Just a couple of notes. The application and service are both using impersonation due to network access requirements. The web application resides on a different server than the WCF service. Both also have the following specified in their respective web.config files.
<authentication mode="Windows"/>
<identity impersonate="true" userName="userName" password="password"/>
Web Application (on server1)
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IReports" 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="false" proxyAddress="http://server2/Services/ReportService">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows" proxyCredentialType="None" realm="" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint name="BasicHttpBinding_IReports" address="http://server2/Services/ReportService/Reports.svc"
binding="basicHttpBinding" contract="WCFServiceRef.IReports" bindingConfiguration="BasicHttpBinding_IReports"
behaviorConfiguration="ClientBehavior"/>
</client>
<behaviors>
<endpointBehaviors>
<behavior name="ClientBehavior" >
<clientCredentials supportInteractive="true" >
<windows allowedImpersonationLevel="Impersonation" allowNtlm="true" />
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>
WCF Service (on server2)
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
<bindings>
<basicHttpBinding>
<binding name="default" maxReceivedMessageSize="200000">
<readerQuotas maxStringContentLength="200000" maxArrayLength="200000"/>
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows" proxyCredentialType="None" realm="" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<services>
<service behaviorConfiguration="ReportService.ReportsBehavior" name="ReportService.Reports">
<endpoint address="" binding="basicHttpBinding" contract="ReportService.IReports" bindingConfiguration="default">
<identity>
<dns value="localhost"/>
</identity>
</endpoint>
<endpoint name="mex" address="mex" binding="basicHttpBinding" contract="IMetadataExchange" bindingConfiguration="default"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="ReportService.ReportsBehavior">
<serviceAuthorization impersonateCallerForAllOperations="false"/>
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
I thought that if I were to apply the allowNtlm="true" directive in the application that this would be fixed. It seems to me that the server is expecting Windows authentication but is not receiving it? Due to the application and service residing on different servers do I need to use the proxy values? I feel that I'm not understanding something basic but whether it's on the server-side IIS configuration or simply in my application I don't know.
Thanks for any help!

This sample from MSDN for basicHttpBinding with TransportCredentialOnly shows how to set it up. Your config is very similar except that it is also setting message level security. I'd try removing the message element from the config to see if that is the cause of the problem.
I don't believe the problem is passing the impersonation credentials themselves but the TransportCredentialOnly configuration. Also, make sure IIS is configured to support Windows authentication on the WCF server.

Related

WCF Service Metadata Exchange over TCP

I created a WCF Service hosted on IIS. With HTTP binding everything ist working fine. But when I switch to TCP binding it doesn't work any more. I tried every hint I found on the web, but no success.
Already done:
installed Windows-Feature "WCF-Non-Http-Activation"
activated Windows Service Net.Tcp-Listener Adapter
In WcfTestClient the service can't be added. But maybe this tool doesn't support TCP(?) so I also tested in Visual Studio by trying to add a service reference.
Error Message when trying to add the service in VS:
An error occurred while attempting to find services at 'net.tcp://hostname:19099/Namespace/Company.Service.svc/mex'. No IPEndpoints were found for host hostname. Details: Metadata contains a reference that cannot be resolved: 'net.tcp://hostname:19099/Namespace/Company.Service.svc/mex'.
This is my current web.config (anonymized) - what am I doing wrong?
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.web>
<compilation targetFramework="4.8"/>
<httpRuntime targetFramework="4.8"/>
<customErrors mode="Off"/>
</system.web>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="ServiceBehavior">
<serviceMetadata />
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service name="Company.Namespace.Service" behaviorConfiguration="ServiceBehavior">
<endpoint name="ServiceEndpoint" address="" binding="netTcpBinding"
bindingConfiguration="ServiceNetTcpBinding" contract="Company.Namespace.IService"/>
<endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange"/>
<host>
<baseAddresses>
<add baseAddress="net.tcp://hostname:19099/Namespace/Company.Service/"/>
</baseAddresses>
</host>
</service>
</services>
<bindings>
<basicHttpBinding>
<binding name="ServiceBasicHttpBinding" sendTimeout="00:01:00" receiveTimeout="00:01:00" openTimeout="00:01:00" closeTimeout="00:01:00"/>
</basicHttpBinding>
<netTcpBinding>
<binding name="ServiceNetTcpBinding" sendTimeout="00:01:00" receiveTimeout="00:01:00" openTimeout="00:01:00" closeTimeout="00:01:00"
transferMode="Buffered" transactionFlow="false" hostNameComparisonMode="StrongWildcard" listenBacklog="10" maxBufferPoolSize="524288"
maxBufferSize="65536" maxConnections="10" maxReceivedMessageSize="65536" portSharingEnabled="false" transactionProtocol="OleTransactions">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384"/>
<reliableSession ordered="true" inactivityTimeout="00:10:00" enabled="false"/>
<security mode="Transport">
<message clientCredentialType="None"/>
<transport clientCredentialType="Windows" protectionLevel="EncryptAndSign"/>
</security>
</binding>
</netTcpBinding>
<wsHttpBinding>
<binding name="ServiceWsHttpBinding" sendTimeout="01:00:30" receiveTimeout="01:00:30"/>
</wsHttpBinding>
</bindings>
<protocolMapping>
<add binding="basicHttpsBinding" scheme="https"/>
</protocolMapping>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true"/>
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
<directoryBrowse enabled="true"/>
</system.webServer>
</configuration>
When you say that you cancel the maximum number of connections and it works, does that mean that the maximum number of connections limits your network?
As far as I know, IIS 5/6 does not support non-HTTP services. IIS7 supports Net TCP, but you must install WAS first. Refer to the following steps:
Control Panel -- Programs and Features -- Turn Windows features on or off and install WAS.
Check whether non-HTTP support is enabled for WCF. Select the same interface in .NET Framework.
Add the Net TCP binding to the site and enable the Net TCP protocol.
Further details can also be found in this docs.

WebAPI Certificates and Authentication - ELI5

I'm sure I'm missing some key facts, but I can get those for you. I'm really confused on how this all needs to work:
Server 1 – IIS 8, Hosting a Vendor’s WebAPI, Anonymous and Windows Authentication. Providers are Negotiate, NTLM. Https and a signed certificate (Cert1).
Server 2 – IIS8, New WebAPI connecting to Server1’s WebAPI. I’m assuming I need to store Cert1 on Server 2. We will have another Certificate, https (Cert2)
Server 3 – IIS 8, Website connecting to server 2’s webAPI.
User – Browser connecting to Server 3, Windows Authentication Only.
Every server and the user’s browser connects to the same Active Directory.
I have access to Server1’s web.config to change bindings, but not the code. In Visual Studio 2013, when I add the service reference for Server 2, the web.config is added like this:
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_ICoreWebService">
<security mode="Transport">
<transport clientCredentialType="Windows" proxyCredentialType="None" realm="" />
<message clientCredentialType="Certificate" negotiateServiceCredential="true" algorithmSuite="Default" establishSecurityContext="true" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="https://dave.domain.com/webService/CoreWebService.svc" binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_ICoreWebService" contract="Dave.ICoreWebService" name="WSHttpBinding_ICoreWebService">
<identity>
<userPrincipalName value="Server1ServiceAccount#dave.domain.com" />
</identity>
</endpoint>
</client>
This is Server1's WebAPI web.config
<system.serviceModel>
<bindings>
<wsHttpBinding>
<!-- The following block is used for secure connection (HTTPS)-->
<binding name="DaveServiceBinding" maxReceivedMessageSize="2147483647" maxBufferPoolSize="2147483647" receiveTimeout="00:05:00" sendTimeout="00:05:00">
<readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="None" />
<message clientCredentialType="UserName" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<services>
<service name="Dave.WebService.CoreWebService" behaviorConfiguration="DaveWebServiceBehavior">
<endpoint address="" binding="wsHttpBinding" bindingConfiguration="DaveWebServiceBinding" contract="Dave.WebService.ICoreWebService" />
<endpoint address="wauth" binding="wsHttpBinding" bindingConfiguration="DaveWebServiceBindingWauth" contract="Dave.WebService.ICoreWebService" />
<endpoint address="mex" binding="mexHttpsBinding" contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="DaveWebServiceBehavior">
<dataContractSerializer maxItemsInObjectGraph="2147483647" />
<serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="Dave.WebService.WebServiceAuthValidator,Dave.WebService" />
</serviceCredentials>
<serviceMetadata httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
I’m having trouble with how the certificates work between Server 1 and Server 2. I just need to download Cert1 and store it on Server2? Then refer to that certificate when I make the call. This code isn't finding the certificate:
svc.ClientCredentials.ServiceCertificate.SetDefaultCertificate(StoreLocation.LocalMachine,
StoreName.TrustedPublisher,
X509FindType.FindBySubjectName, "CN = dave.domain.com, OU = ZZ123, O = Dave, Inc., L = Chicago, S = Illinois, C = US");
How can I bubble up the windows authentication from the user to server1? The vendor’s API will Authenticate through that message.
Right now, I’m able to browse to the service locally, but I’ve been stuck on Server 2 and getting the certificate. I want to make sure I’m storing and referencing it correctly.
Thanks in Advance.
The Subject Name needed to be the domain, and I used the MMC to make sure the certificate was where it should be.
MMC -> certificates (you may need to add them in your snap-in)
Trusted People -> Certificates.
Hope that helps someone.

Delegate IIS Application Pool account to WCF service calls

I have developed a WCF service which is running in IIS (IIS 7.5 to be exact). This service runs under its own app pool, under a specific domain identity. This service references & calls other WCF services hosted elsewhere in the network, which in turn access various resources (Event Log, SQL Servers etc).
Calls to my service are authenticated using username & password, through a custom UserNamePasswordValidator. The username(s) used are not domain credentials.
What I'm trying to do, is that when my service is called & it in turn calls the referenced services using the generated proxy classes, that it delegates the application pool identity as the calling identity, since this domain account has been granted rights to access the background resources like SQL Server.
My current implementation is as follows:
Service Configuration
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="RemoteServiceBinding" closeTimeout="00:10:00"
openTimeout="00:10:00" receiveTimeout="00:10:00" sendTimeout="00:10:00"
maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647">
<readerQuotas maxStringContentLength="2147483647" maxArrayLength="2147483647"
maxBytesPerRead="2147483647" />
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows" />
</security>
</binding>
</basicHttpBinding>
<wsHttpBinding>
<binding name="MyServiceBinding" closeTimeout="00:10:00" openTimeout="00:10:00"
receiveTimeout="00:10:00" sendTimeout="00:10:00" maxBufferPoolSize="2147483647"
maxReceivedMessageSize="2147483647">
<readerQuotas maxStringContentLength="2147483647" maxArrayLength="2147483647"
maxBytesPerRead="2147483647" />
<security mode="Message">
<message clientCredentialType="UserName" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="http://remote.service.address/Service.svc"
binding="basicHttpBinding" bindingConfiguration="RemoteServiceBinding"
contract="RemoteService.IRemoteService" name="RemoteServiceBinding" />
</client>
<services>
<service name="MyService.MyService" behaviorConfiguration="MyServiceBehavior">
<endpoint address="" binding="wsHttpBinding" bindingConfiguration="MyServiceBinding" contract="MyService.IMyService">
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:8733/MyService/" />
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="MyServiceBehavior">
<serviceMetadata httpGetEnabled="True" httpsGetEnabled="True"/>
<serviceDebug includeExceptionDetailInFaults="True" />
<serviceCredentials>
<clientCertificate>
<authentication certificateValidationMode="None" />
</clientCertificate>
<serviceCertificate findValue="AuthCert" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName" />
<userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="MyService.CredentialValidator, MyService" />
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
Service behavior code
using (var client = new Proxy.RemoteServiceClient()) {
client.ClientCredentials.Windows.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Delegation;
return client.PerformAction();
}
Using this code, whenever a client makes a call to my service, the following is thrown:
The HTTP request is unauthorized with client authentication scheme 'Negotiate'. The authentication header received from the server was 'Negotiate,NTLM'.
Could someone please assist me, or point me in the right direction on how to implement this authentication configuration?
I've managed to find a working solution. It is implemented as such:
The client proxy credentials need to be set to those of the IIS Application Pool, since these don't get picked up automatically:
client.ClientCredentials.Windows.ClientCredential = System.Net.CredentialCache.DefaultNetworkCredentials;
Also, the remote service I was connecting to had a service principal that needed to be included in the endpoint configuration. So I modified the config that was generated by the VS tooling to the following:
<client>
<endpoint address="http://remote.service.address/Service.svc"
binding="basicHttpBinding" bindingConfiguration="RemoteServiceBinding"
contract="RemoteService.IRemoteService" name="RemoteServiceBinding">
<identity>
<servicePrincipalName value="spn_name" />
</identity>
</endpoint>
</client>
With this configuration, I was able to authenticate to my service by username & password, then have my service access a SQL Server instance using the domain credentials that the application pool was running under in IIS.

The remote server returned an error: (413) Request Entity Too Large

Please do NOT delete this message as a duplicate!!
I am writing a WCF service that allows for XML files to be uploaded so that they can be imported into the database. However I am receiving the above error when I upload a file above the 64k default.
I have read through all the questions already posted on here about this problem and implemented them but still am facing the same issue.
I have increased all the binding values in my config file (for both the client and server) to accept the maximum size of 2GB.
<binding name="BasicHttpBinding_BailiffServices"
maxBufferSize="2147483647"
maxBufferPoolSize="2147483647"
maxReceivedMessageSize="2147483647">
<readerQuotas maxDepth="2147483647"
maxStringContentLength="2147483647"
maxArrayLength="2147483647"
maxBytesPerRead="2147483647"
maxNameTableCharCount="2147483647" />
&ltsecurity mode="None" />
Here are the WCF services that use this binding.
<services>
<service name="ClientService.ClientService">
<endpoint address="http://subversion/BusinessTier.Services.ClientService.svc"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_BailiffServices"
name="BasicHttpBinding_IClient" contract="ClientService.IClient" />
</service>
<service name="DebtorService.DebtorService">
<endpoint address="http://subversion/BusinessTier.Services.DebtorService.svc"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_BailiffServices"
name="BasicHttpBinding_IDebtor" contract="DebtorService.IDebtor" />
</service>
</services>
I have also added settings to the config to ensure that IIS is also able to handle large files.
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
<security>
<requestFiltering allowDoubleEscaping="true">
<requestLimits maxAllowedContentLength="2147483647"/>
<fileExtensions allowUnlisted="true"/>
<verbs allowUnlisted="true"/>
</requestFiltering>
</security>
</system.webServer>
As far as I can see I have amended all the necessary settings to allow my WCF service to accept large files, but none of them have so far worked.
Any suggestions would be greatly appreciated.
I found solution to avoid error like 'The remote server returned an unexpected response: (413) Request Entity Too Large.'
When using basicHttpBinding in WCF Service Configuration You just need to increase the maximum message length in the Web.config.following way you can update you server web.config and client app.config file for sending large byte array via wcf.
Include following bindings and behaviors parameters in Web.config
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding maxReceivedMessageSize="2147483647" sendTimeout="00:10:00" receiveTimeout="00:10:00">
<readerQuotas maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647"/>
</binding>
</basicHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<protocolMapping>
<add binding="basicHttpsBinding" scheme="https" />
</protocolMapping>
<serviceHostingEnvironment aspNetCompatibilityEnabled="false">
<serviceActivations>
<add factory ="WebService.NInjectServiceHostFactory" relativeAddress="TestServic.svc" service="WebService.Services.ServiceManager"/>
</serviceActivations>
</serviceHostingEnvironment>
I have also added binding configuration in client app.config file.
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IServiceManager" maxBufferSize="2147483647" maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647">
<security mode="None"/>
<readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647"/>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:49359/ServiceManager.svc"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IPackageManager"
contract="PackageManager.IPackageManager" name="BasicHttpBinding_IPackageManager" />
</client>
</system.serviceModel>
this will also handle timeout error as well.
I've eventually managed to get this working after several hours of head scratching. I removed the binding name "BasicHttpBinding_BailiffServices" from both the <binding /> element and the <endpoint /> elements. I stumbled across this solution on the MSDN site. Hope this helps someone else.

IMetadataExchange WCF Configuration Error

I am getting the below error message in my WCF service. Below is my web,config. I have tried a few things and nothing has resolved the error. Any help is appreciated.
The contract 'IMetadataExchange' in client configuration does not
match the name in the service contract
<?xml version="1.0"?>
<configuration>
<connectionStrings/>
<system.web>
<compilation strict="false" explicit="true" targetFramework="4.0" debug="true"/>
</system.web>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<basicHttpBinding>
<binding name="SNCBinding" closeTimeout="00:10:00" openTimeout="00:10:00"
receiveTimeout="00:10:00" sendTimeout="00:10:00" maxBufferSize="2147483647"
maxReceivedMessageSize="2147483647" textEncoding="utf-8">
<readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647"
maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows" proxyCredentialType="Windows" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"
multipleSiteBindingsEnabled="true" />
<services>
<service name="SNC.MaterialRequest.WCF.MaterialRequest">
<endpoint address="" binding="basicHttpBinding" bindingConfiguration="SNCBinding"
contract="SNC.MaterialRequest.WCF.MaterialRequest" />
</service>
</services>
</system.serviceModel>
</configuration>
Have you installed the .Net Services SDK by any chance?
See: http://azure.snagy.name/blog/?tag=imetadataexchange
It sounds like it adds a client endpoint for IMetaDataExchange in your machine.config. So you can either delete it out of your machine.config, or add
<client>
<remove contract=”IMetadataExchange” name=”sb” />
</client>
to every app.config/web.config from now on.
EDIT: Note that this shouldn't affect your actual application, it's just a warning that you can ignore. It's mentioned here, also: http://blogs.msdn.com/b/wcftoolsteamblog/archive/2008/08/28/tips-for-wcf-tools-in-vs2008-sp1.aspx
Here is the issue :
contract="SNC.MaterialRequest.WCF.MaterialRequest"
It's not same as IMetadataExchange in error. So it's either wrong in server side config, or in client side config. Altough I would say in server side, since this should be interface.

Categories

Resources