In default configurations web applications and web services are running under the credentials of a predefined user account. For ASP.NET webapplications this is the ASPNET (or similar) account and for WCF services this is the user that started the servicehost or the user associated as logon account for the windows service hosting the services.
This means access to resources is restricted by this account. This is most often a dedicated account and not related to a real user. In a good secure environment the decision should have been made to give those accounts minimal rights, just enough to allow the hosting. So this account will not have the rights to access resources (files, databases) like normal users do.
Impersonation is the way to allow that the code in services (or in webapplications) can run under the credentials of the user accessing this webservice (or webapplication).
In an architecture where the services with the logic are separated from the webapplication with the UI we can have 3 accounts executing code or needing access to resources.

It makes sense that the user behind the browser is the one that must have the rights to allow the code in the WCF service to access the resources.
A WCF service can easily be configured to do impersonation:
1. Add the OperationBehavior attribute to the method that is called and needs to run under the impersonated user credentials and set Impersonation to allowed. The OperationBehavior attribute must be placed in implementation class, not on the interface !
[OperationBehavior(Impersonation = ImpersonationOption.Allowed)]
public string DoSomething(string data)
{
…
//Access to the resource
…
}
2. In the WCF configuration write a servicebehavior for the service which sets the impersonateCallerForAllOperations attribute of the serviceAuthorization element to “true”
<behaviors>
<serviceBehaviors>
<behavior name="Service1Behave">
<serviceAuthorization impersonateCallerForAllOperations="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service name="ServiceImplementation.ServiceImplementation"
behaviorConfiguration="Service1Behave">
<endpoint
address="http://localhost:9876/TestService"
binding="wsHttpBinding"
bindingConfiguration=""
contract="ServiceInterface.IServiceInterface" />
</service>
</services>
On the client side (which is the ASP.NET website) set the AllowedImpersonationLevel to Impersonation on the ChannelFactory<T> or ClientBase<T> before calling the method.
a. when using ChannelFactory<T>:
System.ServiceModel.ChannelFactory<MyChannelClass> channelFactory;
channelFactory = new System.ServiceModel.ChannelFactory<MyChannelClass>("EP");
channelFactory.Credentials.Windows.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Impersonation;
ServiceInterface.IServiceInterface channel;
channel = channelFactory.CreateChannel();
string s;
s = channel.DoSomething("devitect");
b. when using a ClientBase<T> proxy.
MyClient myClient;
myClient = new MyClient("EP");
myClient.ClientCredentials.Windows.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Impersonation;
string s;
s = myClient.DoSomething("devitect");
This results in running the code in the serviceoperation (the DoSomething method) under the credentials of the user running the process on the client. This is the ASPNET account and still not the user behind the browser.
So we have to make sure that the calling code in the webapplication can now impersonate in its turn the user behind the browser. Again this can be done very easy by specifying the identity tag in the system.web part of the configuration file for the webbapplication.
<system.web>
…
<identity impersonate="true"/>
…
</system.web>
But now we created a potential pitfall. By setting this suddenly all the code in the webapplication is now running under the account of the user behind the browser. Which could not always be desired.
We need a way to impersonate the user just before calling the WCF service and stop impersonating just after we received the answer.
You can use the WindowsImpersonationContext class for this. This class has to be set to the result of the static method WindowsIdentity.Impersonate() which needs the usertoken of the user you want to impersonate as parameter. This usertoken can be found on a property of the WindowsIdentity class which is set to the identity of the current user in the Httpcontext. This is the identity of the user using the browser. After the call you can undo the impersonation with the Undo method on this WindowsImpersonationContext class and the code will be running under the ASPNET account again. We are just temporarily impersonating the user.
Code to do this:
WindowsIdentity windowsIdentity = (WindowsIdentity)HttpContext.Current.User.Identity;
WindowsImpersonationContext windowsImpersonationContext;
windowsImpersonationContext = WindowsIdentity.Impersonate(windowsIdentity.Token);
//… call the service
windowsImpersonationContext.Undo();