views:

73

answers:

2

In short my scenario is like so:
alt text

  1. The user triggers an action in the web browser, which causes an Ajax call to a web service in the web server (server A).
  2. The web server issues a call to a WCF service, hosted in IIS (server B)
  3. The WCF service issues a call to another WCF service, hosted in IIS (server C)

All web sites are exposed over http, not https.

Now, server C needs to know who the user is in the other end. I got it working so far so that the WCF service call to server B is performed under impersonation, so server B has a WindowsIdentity object representing the user. However, when I try to invoke the service call from server B to server C under impersonation, I get the following back:

System.ComponentModel.Win32Exception: No credentials are available in the security package

Server stack trace: 
   at System.IdentityModel.SspiWrapper.AcquireCredentialsHandle(String package, CredentialUse intent, AuthIdentityEx& authdata)
   at System.ServiceModel.Security.SecurityUtils.GetCredentialsHandle(String package, NetworkCredential credential, Boolean isServer, String[] additionalPackages)
   at System.ServiceModel.Security.SpnegoTokenProvider.OnOpening()
   at System.ServiceModel.Security.WrapperSecurityCommunicationObject.OnOpening()
   at System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout)
   at System.ServiceModel.Security.CommunicationObjectSecurityTokenProvider.Open(TimeSpan timeout)
   at System.ServiceModel.Security.SecurityUtils.OpenTokenProviderIfRequired(SecurityTokenProvider tokenProvider, TimeSpan timeout)
   at System.ServiceModel.Security.SymmetricSecurityProtocol.OnOpen(TimeSpan timeout)
   at System.ServiceModel.Security.WrapperSecurityCommunicationObject.OnOpen(TimeSpan timeout)
   at System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout)
   at System.ServiceModel.Channels.SecurityChannelFactory`1.ClientSecurityChannel`1.OnOpen(TimeSpan timeout)
   at System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout)
   at System.ServiceModel.Channels.ServiceChannel.OnOpen(TimeSpan timeout)
   at System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout)
   at System.ServiceModel.Channels.ServiceChannel.CallOpenOnce.System.ServiceModel.Channels.ServiceChannel.ICallOnce.Call(ServiceChannel channel, TimeSpan timeout)
   at System.ServiceModel.Channels.ServiceChannel.CallOnceManager.CallOnce(TimeSpan timeout, CallOnceManager cascade)
   at System.ServiceModel.Channels.ServiceChannel.EnsureOpened(TimeSpan timeout)
   at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
   at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs)
   at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
   at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)

Tweaking service binding feels for me like walking on ice so thin that I am almost walking on water, so let's disregard from what I have failed with so far, and start with a clean sheet.

How should I configure the services to play nicely with each other (and me)?

+3  A: 

According to Microsoft, you need to use something called "Delegation", which if I understand correctly, is specifying that Server C trusts Server B to properly authenticate the user from Server A.

Without Delegation, your service on Server B can only access local resources as the impersonated user from Server A.

From the horse's mouth: http://msdn.microsoft.com/en-us/library/cc949014.aspx

Rice Flour Cookies
That looks quite promising. Will see if I can try it out tomorrow in the office.
Fredrik Mörk
+1  A: 

Because you are making more than one hop, you need to use delegation. Take a look here for more information.

MattK