This is the fifth post in the WCF 4.5 series. This time we will demonstrate one of the new cool features of WCF 4.5 and IIS hosting – creating an endpoint that supports multiple authentication types.
Note: The authentication mechanism in the following post refers to client authentication used in the HTTP transport (the Authorization HTTP header), either when using a secured transport (HTTPS) or a non-secured transport (HTTP).
When hosting WCF services in IIS, a lot of developers struggle with the problem of declaring authentication types, since there are two places where you need to set the authentication type – in the service’s configuration and in the IIS configuration.
If you don’t set the two properly, meaning if there is a mismatch between the endpoint’s authentication types and IIS’s authentication types, you might end up getting an error message like this:
The authentication schemes configured on the host (‘Basic, Anonymous’) do not allow those configured on the binding ‘WSHttpBinding’ (‘Negotiate’). Please ensure that the SecurityMode is set to Transport or TransportCredentialOnly. Additionally, this may be resolved by changing the authentication schemes for this application through the IIS management tool, through the ServiceHost.Authentication.AuthenticationSchemes property, in the application configuration file at the <serviceAuthenticationManager> element, by updating the ClientCredentialType property on the binding, or by adjusting the AuthenticationScheme property on the HttpTransportBindingElement.
The message informs you that you’ve declared basic and anonymous authentication in IIS, but you are trying to use Negotiate (Windows authentication using Kerberos) in your service configuration which isn’t supported by the host (IIS).
Since this is very annoying, WCF 4.5 enabled you to inherit the authentication types from IIS, so you only need to declare them once.
So how do we do that? It took me some time to understand how to set it up, since this is one of the new features which is not so documented; To save you the trouble, here is a set of instructions you’ll need to follow:
1. Create a service and host it in IIS.
2. Define the service’s endpoint to use any of the HTTP bindings (basicHttp, wsHttp…).
3. Create a binding configuration for the endpoint, and set the security to either Transport, or TransportCredentialsOnly (in basicHttp).
4. In the transport’s configuration, set the clientCredentialType attribute to InheritedFromHost – this is a new value that was added in WCF 4.5. This value is currently not documented in MSDN.
At this point, your service configuration might look like so:
<endpoint address=”” binding=”basicHttpBinding” contract=”Mycontract” bindingConfiguration=”secured”/>
Note: if you use basicHttpBinding, you can use either transport security or transportCredentialsOnly security (use the last option only when not using basic authentication). For wsHttpBinding, you need to use transport security to get the InheritedFromHost credential type option.
5. Open IIS, and set the authentication types to the ones you require – anonymous, basic, digest, NTLM, windows, or certificate. Of course you can set several of these options.
6. After setting the authentication types in IIS, try browsing to the service’s WSDL file and check the reported authentication types:
Note: Anonymous authentication is not shown as an authentication type in the WSDL. For the list of authentication types that can appear in the WSDL file, check this MSDN article.
7. On the client-side, add a service reference to your service. The generated configuration will be set according to the authentication types you set in IIS:
a. If you set a single authentication type, then the configuration will be set to it. For example basic, if you set basic authentication, then the configuration will be set to basic credentials:<basicHttpBinding>
<transport clientCredentialType=”Basic“ />
b. If you set multiple authentication types in IIS, then things get a bit trickier. The client-side doesn’t have a matching “InheritedFromHost” attribute, and it can’t include more than one transport element, so the credential type is usually set to the first credential type specified in the WSDL. For example if you only use basic and digest, then it’s likely you will see digest authentication in the client’s credential type:<wsHttpBinding>
<transport clientCredentialType=”Digest“ />
If you only set IIS to support anonymous authentication, then the client binding configuration will look like so:<wsHttpBinding>
<transport clientCredentialType=”None“ />
One small thing to note regarding the default configuration – basicHttp and wsHttp have different default values for client credential type; if the authentication type in IIS is the binding’s default credential type, then you will see the following client binding configuration (this example is for the wsHttp binding):
The default client credential for basicHttp is none, and the default for wsHttp is Windows. So for the above example, the binding configuration was generated because the IIS was set to Windows.
I think that Microsoft should have invested a bit more on managing the configuration on the client side for this feature – it’s not clear to the client-side which authentication types are supported, and the generated configuration is only set to one of them. Another thing is that if you use anonymous authentication in IIS, it doesn’t show in the client configuration unless it is the only available authentication type.
To conclude, without this feature, we need to declare several endpoints, one for each credential type, but our clients will able to see exactly which credentials the service expects; With the new feature, we only need one endpoint, and the rest is configured in IIS, but our clients will have more trouble understanding what is available to them.
My score for this feature: Server-side +1, Client-side –1.
Stay tuned for more posts about the new features of WCF 4.5. You can also follow me on Twitter (@IdoFlatow) to get updates as soon as new posts are published.
The RTM of .NET 4.5 is still to come, and I assume many of you are still adjusting to WCF 4. If you want to learn more about the new features of WCF 4, come to my session at Visual Studio Live! 2011 in Redmond (October 17-21).
Also, if you are an MCT and reside in the US, come hear my session about WCF 4 at the MCT 2011 North-America Summit that will be held in San-Francisco (October 19-21).