Introduction
Configuring WCF to do anything for the first time is very time consuming, frustrating and just generally a hassle. My coworker and I mucked through this wonderful WCF configuration experience last night and now I am going to share our tale of torment and learning.

Useless and Unhelpful Errors
If you have been having trouble setting this up, then chances are you have seen one of two or both of these page errors that are served to you on a steaming hot yellow screen of death:

Useless Error 1
Security settings for this service require Windows Authentication but it is not enabled for the IIS application that hosts this service.

Useless Error 2
Security settings for this service require ‘Anonymous’ Authentication but it is not enabled for the IIS application that hosts this service.
Why is this happening?
Well you may have guessed it already, you didn’t configure something correctly. The short answer is that you have to enable Anonymous and Windows Authentication for your application in IIS for this to begin to work. However there is more configuration that needs to be done which is described further down below.
The Not So Obvious Fix to the Stupid Problem
I can’t promise that what worked for me and my needs will work for you and your needs. I can however promise that this will work if the instructions are followed exactly. There are a lot of moving parts here and unfortunately most of what is happening here is behind the scenes magic (Windows Authentication, Kerberos, NTLM, Negotiate, etc…). Therefore I have to assume that you have IIS7 setup correctly and that you have successfully enabled Windows Authentication for other applications, just not WCF yet.
Configuring IIS
  1. Open IIS manager > Click on your Application > Make sure Features View is selected
  2. In the IIS section of Features View double click on “Authentication” (Figure 1)
  3. Enable Anonymous Authentication (Figure 2)
  4. Enable Windows Authentication (Figure 2)
    1. On the left hand side of the window look at the Actions section.
    2. Click on “Advanced Settings…” make sure Extended Protection is “OFF” and check mark the check box labeled “Enable Kernel-mode authentication” (checked=”True”)**. (Figure 3)
    3. Click on “Providers…” and make sure the Enabled Providers are only “Negotiate” and “NTLM”, do not add anything else here. (Figure 4)
  5. Restart IIS using CMD > iisreset /restart
  6. You are finished with configuring IIS, time to configure WCF.
**Kernel-mode Authentication
You want this check marked especially if you are using a custom UN/PW for your Application Pool Identity.

Figure 1
Figure 2
Figure 3
Figure 4
Configuring WCF
As usual, 99% of the configuration for WCF takes place in the web.config/app.config. In this particular case it is a web.config because I am assuming you are using a Web Application as your WCF host. Therefore there are two main pieces at work here:
  • Enabling Windows Authentication for the Web Application
  • Enabling Windows Authentication for the WCF Service
These two points of interest are actually mutually exclusive. Just because you have Windows Authentication enabled for your Web Application doesn’t mean I can’t still hit your WCF Service. Therefore it must be enabled for both.
Configuring Windows Authentication for the Web Application
Put the following authentication section into the <system.web> section. In this example I am using Active Directory group names to filter out who has access. You can use the user names directly if you want.
<authentication mode="Windows" />
 <authorization>
  <allow roles="ADGroup1,ADGroup2" />
  <deny users="*" />
 </authorization>
<identity impersonate="false" />

Configuring Windows Authentication for the WCF Service
Put the following secruity section into your <binding> section.
<security mode="TransportCredentialOnly">
 <transport clientCredentialType="Windows" />
</security> 

Full Web.Config Example For Reference
<?xml version="1.0"?>
<configuration>
  <system.web>
    <compilation debug="true" targetFramework="4.0">
    </compilation>
    <httpRuntime
      executionTimeout="600"
      maxRequestLength="16384" />
    <authentication mode="Windows" />
    <authorization>
      <allow roles="ADGroup1,ADGroup2" />
      <deny users="*" />
    </authorization>
    <identity impersonate="false" />
  </system.web>
  <system.serviceModel>
    <services>
      <service name="AuthWCFService.AuthService" behaviorConfiguration="AuthWCFService.AuthServiceBehavior">
        <endpoint address=""
                  binding="basicHttpBinding"
                  bindingConfiguration="basicHttpBindingConfig"
                  contract="AuthWCFService.IAuthService" />
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
      </service>
    </services>
    <bindings>
      <basicHttpBinding>
        <binding name="basicHttpBindingConfig"
                 openTimeout="00:10:00"
                 receiveTimeout="00:10:00"
                 sendTimeout="00:10:00"
                 closeTimeout="00:10:00"
                 maxReceivedMessageSize="2147483647"
                 maxBufferSize="2147483647"
                 maxBufferPoolSize="2147483647"
                 messageEncoding="Text"
                 transferMode="Buffered" >
          <security mode="TransportCredentialOnly">
            <transport clientCredentialType="Windows"/>
          </security>
          <readerQuotas maxDepth="32"
                        maxStringContentLength="20000000"
                        maxArrayLength="20000000"
                        maxBytesPerRead="4096"
                        maxNameTableCharCount="16384" />
        </binding>
      </basicHttpBinding>
    </bindings>
    <behaviors>
      <serviceBehaviors>
        <behavior name="AuthWCFService.AuthServiceBehavior">
          <!-- To avoid disclosing metadata information, 
          set the value below to false and remove the metadata endpoint above before deployment -->
          <serviceMetadata httpGetEnabled="True" />
          <!-- To receive exception details in faults for debugging purposes, 
          set the value below to true.  Set to false before deployment 
          to avoid disclosing exception information -->
          <serviceDebug includeExceptionDetailInFaults="true" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
  </system.serviceModel>
</configuration>

Conclusion
I think Microsoft needs to make this easier to figure out… Why the configuration has to be such a mystery that requires countless hours of plug and chug is beyond me. I have tried reading the white papers that are provided, but they are as useful as college books or technical manuals when you aren’t really sure where to begin. As I like to call it FLUFF, lots and lots of FLUFF – no practicality – just lots of meaningless words strung into sentences.

Sources

Leave a Reply

Your email address will not be published. Required fields are marked *