I have followed numerous msdn articles and the codeplex guidance but cannot get WCF to work with Kerberos authentication and delegation and would appreciate a little help.
Setup
I have the WCF service in an IIS website on a remote machine
I am using Brian Booth's debug site on 8080 and the site passes all requirements for Kerberos delegation. The debug IIS site has anonymous authentication off, and Integrated Windows authentication on.
I have mirrored these settings to the site hosting the WCF service.
Web Service - Web Config (Original)
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="WsHttpBindingConfig">
<security>
<message negotiateServiceCredential="true" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<services>
<service behaviorConfiguration="ServiceBehavior" name="Service">
<endpoint address=""
binding="wsHttpBinding"
bindingConfiguration="WsHttpBindingConfig"
contract="IService">
<identity>
<servicePrincipalName value="http/myserver" />
<dns value="" />
</identity>
</endpoint>
<endpoint address="mex"
binding="mexHttpBinding"
contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="ServiceBehavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
<serviceAuthorization
impersonateCallerForAllOperations="true" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
Web Service - Web Method
[OperationBehavior(Impersonation = ImpersonationOption.Required)]
public string GetCurrentUserName()
{
string name = WindowsIdentity.GetCurrent().Name;
return name;
}
Client App - App Config
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_IService"
... />
...
<security mode="Message">
<transport clientCredentialType="Windows"
proxyCredentialType="None"
realm="" />
<message clientCredentialType="Windows"
negotiateServiceCredential="true"
algorithmSuite="Default"
establishSecurityContext="true" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="http://myserver/Service.svc"
binding="wsHttpBinding"
bindingConfiguration="WSHttpBinding_IService"
contract="KerberosService.IService"
name="WSHttpBinding_IService">
<identity>
<servicePrincipalName value="http/myserver" />
</identity>
</endpoint>
</client>
</system.serviceModel>
Application Error
The following error occurs when my test application, a WinForms app, tries to call the web method:
"The HTTP request is unauthorized with client authentication scheme 'Anonymous'. The authentication header received from the server was 'Negotiate,NTLM'."
Event Log
The following error is in the event log:
Exception: System.ServiceModel.ServiceActivationException: The service '/Service.svc' cannot be activated due to an exception during compilation. The exception message is: Security settings for this service require 'Anonymous' Authentication but it is not enabled for the IIS application that hosts this service.
Which I don't understand. The whole point of this service is to not allow anonymous authentication, every user/request must be authenticated using Kerberos tickets, then passing them through to other machines.
How should I configure this WCF service for Kerberos authentication and delegation?
Revision 1
After reading this SO question I removed the metadata endpoint. This has not resolved the issue.
Revision 2
After more researching I found a few posts suggesting to change wsHttpBinding to basicHttpBinding. The modification to that portion of the web.config has been included below, and the service endpoint has been updated to refer to that binding.
Web Service - Web Config (Revised)
<basicHttpBinding>
<binding name="basicBindingConfig">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows"
proxyCredentialType="Windows"
realm="" />
</security>
</binding>
</basicHttpBinding>
Client App - App Config (Revised)
<!-- ... -->
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows"
proxyCredentialType="Windows"
realm="" />
<message clientCredentialType="UserName"
algorithmSuite="Default" />
</security>
<!-- ... -->
Error (Revised)
The current error looks like it contains a Kerberos authentication header.
The HTTP request is unauthorized with client authentication scheme 'Negotiate'. The authentication header received from the server was 'Negotiate SOMEHUGESCARYKEYHERE
For me the current setup does work:
On the Server:
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="wsHttpBindingConf" useDefaultWebProxy="true"/>
</wsHttpBinding>
</bindings>
<services>
<service behaviorConfiguration="returnFaults" name="Epze.BusinessLayer.ZeitManager">
<endpoint binding="wsHttpBinding" bindingConfiguration="wsHttpBindingConf" contract="Epze.Contract.IZeitManager"/>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="returnFaults">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
<serviceAuthorization impersonateCallerForAllOperations="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
Set the following attribute on all methods for the WCF:
[OperationBehavior(Impersonation = ImpersonationOption.Required)]
On the Client:
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_IZeitManager" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard" maxBufferPoolSize="524288" maxReceivedMessageSize="65536" messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true" allowCookies="false">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384"/>
<reliableSession ordered="true" inactivityTimeout="00:10:00" enabled="false"/>
<security mode="Message">
<transport clientCredentialType="Windows" proxyCredentialType="None" realm=""/>
<message clientCredentialType="Windows" negotiateServiceCredential="true" algorithmSuite="Default" establishSecurityContext="true"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
<behaviors>
<endpointBehaviors>
<behavior name="Delegation">
<clientCredentials>
<windows allowedImpersonationLevel="Delegation" />
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
<client>
<endpoint address="http://server.mydomain.net/ePZEsvc/ZeitManager.svc" binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IZeitManager"
contract="External.Epze.IZeitManager" name="WSHttpBinding_IZeitManager" behaviorConfiguration="Delegation">
<identity>
<servicePrincipalName value="HOST/localhost"/>
</identity>
</endpoint>
</client>
</system.serviceModel>
HTH, Sven