“Required impersonation level was not provided…” exception on opening an SPSite when using WCF

If you have ever tried open to a SharePoint Site from a WCF web service, you might got the “An error occurred loading a configuration file: Either a required impersonation level was not provided, or the provided impersonation level is invalid.” exception.

You need to set your binding to basicHttpBinding, and security to TransportCredentialOnly and transport to clientCredentialType=”Ntlm”.

On the client side, when initializing the service proxy, you must set the ClientCredential to DefaultNetworkCredential, and set the AllowedImpersonationLevel to “Impersonation”.

The whole configuration and initialization on server and client side looks like:

Server side – service configuration:

...
<system.web>
  ...
  <identity impersonate="true" />
</system.web>
...
<system.serviceModel>
  <serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
  <bindings>
    <basicHttpBinding>
      <binding name="custombasicHttpBinding">
        <security mode="TransportCredentialOnly">
          <transport clientCredentialType="Ntlm" />
        </security>
      </binding>
    </basicHttpBinding>
  </bindings>
  <behaviors>
    <serviceBehaviors>
      <behavior name="PlanB.ShareDove.ConferenceOrganization.ServiceLayer.WcfService.WcfServiceBehavior">
        <serviceMetadata httpGetEnabled="true" />
        <serviceDebug includeExceptionDetailInFaults="true" />
      </behavior>
    </serviceBehaviors>
  </behaviors>
  <services>
    <service behaviorConfiguration="PlanB.ShareDove.ConferenceOrganization.ServiceLayer.WcfService.WcfServiceBehavior" name="PlanB.ShareDove.ConferenceOrganization.ServiceLayer.WcfService.WcfService">
      <endpoint address="http://server/SharedoveWcfService/WcfService.svc" binding="basicHttpBinding" name="BasicHttpEndpoint" bindingConfiguration="custombasicHttpBinding" contract="PlanB.ShareDove.ConferenceOrganization.ServiceLayer.WcfService.IWcfService">
      </endpoint>
    </service>
  </services>
</system.serviceModel>

On the client side, you invoke the service methods like…

SdService.WcfServiceClient client = new SdService.WcfServiceClient();
client.ClientCredentials.Windows.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Impersonation;
client.ChannelFactory.Credentials.Windows.ClientCredential = System.Net.CredentialCache.DefaultNetworkCredentials;

// call the service method...
ConferenceSessionLite[] sessions = client.GetAgendaForDay(new DateTime(2012, 06, 20));

This way, your credentials will be transported on the correct way, and you’ll be able to open the SPSite in the right context.