I've set up a WCF service, which is intended to run under Kerberos. The issue I'm having is that whenever I throw an exception from the service to the client, it appears to be making a separate request for the exception detail, and failing with 'The requirement for mutual authentication was not met by the remote server.'.
The good news - Requests to service calls that don't throw exceptions work fine.
My current fallback is to allow NTLM, which I'd like to remove. I'd like to understand the heart of the issue, trying overcome the 'Kerberos is always difficult' mindset.
Basic network details:
- SPNs are registered for the service, against the NetBios + FQDN names, and the App Pool's service account. (Falling back to an http machine SPN is not available to us
- Anonymous is disabled
Exception types tried:
- Re-throwing original exception (Client has access to basic Exception types)
FaultException, (though I don't need custom exceptions, which it may be intended for)+ adding the following to each webservice method:
[FaultContract(typeof(FaultException))]
Client-side detail
Setting the ClientCredential: (Client)
credentials.Windows.ClientCredential = CredentialCache.DefaultNetworkCredentials;
credentials.Windows.AllowNtlm = false; // Set to true to allow it to work;
credentials.Windows.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Delegation;
Other fixes from previous issues:
SpnEndpointIdentity set, thanks to this question
SpnEndpointIdentity spnEndpointIdentity = new SpnEndpointIdentity("");
var address = new EndpointAddress(EndpointName, spnEndpointIdentity)
To stop the 407 proxy error:
BasicHttpBinding.UseDefaultWebProxy = false;
The exception received by the client: (Abbreviated stack trace)
(It appears to show that the ProcessGetResponseWebException call is trying to retrieve the exception detail)
System.ServiceModel.CommunicationException was unhandled
Message=An error (The request was canceled) occurred while transmitting data over the HTTP channel.
StackTrace:
at System.ServiceModel.Channels.HttpChannelUtilities.ProcessGetResponseWebException(WebException webException, HttpWebRequest request, HttpAbortReason abortReason)
Exception rethrown at [0]:
at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
at Project.IMetadataManagement.GetMetadata(String identifier)
InnerException: System.Net.WebException
InnerException: System.Net.ProtocolViolationException
Message=The requirement for mutual authentication was not met by the remote server.
Server side detail
In the web config:
includeExceptionDetailInFaults is true
<behavior name="Project.MetadataBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
Bindings:
<bindings>
<basicHttpBinding>
<binding name="BasicHttpEndpointBinding">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows" />
</security>
</binding>
</basicHttpBinding>
</bindings>
Windows auth settings
<system.webServer>
<security>
<authentication>
<windowsAuthentication enabled="true" useKernelMode="true" useAppPoolCredentials="true" >
<providers>
<clear />
<add value="Negotiate" />
<add value="NTLM" />
</providers>
<extendedProtection tokenChecking="None" />
</windowsAuthentication>
<anonymousAuthentication enabled="false" />
</authentication>
</security>
</system.webServer>
Service example
<services>
<service behaviorConfiguration="Project.MetadataBehavior" name="Project.MetadataManagement">
<endpoint address="" binding="basicHttpBinding" bindingConfiguration="BasicHttpEndpointBinding" contract="Project.IMetadataManagement">
</endpoint>
</service>
Any and all help appreciated. I've blanked over the actual project namespaces, so hopefully I haven't left any clumsy mis-alignment.
Thanks.