Reputation: 1123
I have two WCF services hosted separately in IIS 7. The first service is callable from outside and uses a WebHttpBinding
with windows authentication. The second service is only called by the first one, using a WsDualHttpBinding
.
When the first service is called, I can get the user's windows name from ServiceSecurityContext.Current.WindowsIdentity.Name
. In the second service, that doesn't work and ServiceSecurityContext.Current.WindowsIdentity.Name
is just IIS APPPOOL\DefaultAppPool
.
I configured the WsDualHttpBinding
to use windows authentication, but that didn't help. Here is the server-side configuration:
<wsDualHttpBinding>
<binding name="internalHttpBinding">
<security mode="Message">
<message clientCredentialType="Windows"/>
</security>
</binding>
</wsDualHttpBinding>
And here's the code in the first service to establish communication with the second service:
private WSDualHttpBinding binding = new WSDualHttpBinding();
private ChannelFactory<IMyService> factory;
public IMyService Contract { get; set; }
public MyServiceCallback Callback { get; set; }
public MyService(Uri uri)
{
EndpointAddress address = new EndpointAddress(uri);
Callback = new MyServiceCallback();
var instanceContext = new InstanceContext(Callback);
binding.Security.Mode = WSDualHttpSecurityMode.Message;
binding.Security.Message.ClientCredentialType = MessageCredentialType.Windows;
factory = new DuplexChannelFactory<IMyService>(instanceContext, binding, address);
factory.Credentials.Windows.AllowedImpersonationLevel = TokenImpersonationLevel.Impersonation;
factory.Credentials.Windows.ClientCredential = CredentialCache.DefaultNetworkCredentials;
Contract = factory.CreateChannel();
// Call operations on Contract
}
How can I configure the first service to pass on the user's identity to the second service?
Upvotes: 0
Views: 657
Reputation: 7522
After the server-side enables impersonation and the client-side has set up the windows credential,
ServiceReference1.ServiceClient client = new ServiceReference1.ServiceClient();
client.ClientCredentials.Windows.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Impersonation;
client.ClientCredentials.Windows.ClientCredential.UserName = "Test";
client.ClientCredentials.Windows.ClientCredential.Password = "123456";
We could retrieve the running Windows account by using the below code.
if (ServiceSecurityContext.Current.WindowsIdentity.ImpersonationLevel == TokenImpersonationLevel.Impersonation ||
ServiceSecurityContext.Current.WindowsIdentity.ImpersonationLevel == TokenImpersonationLevel.Delegation)
{
using (ServiceSecurityContext.Current.WindowsIdentity.Impersonate())
{
Console.WriteLine("Impersonating the caller imperatively");
Console.WriteLine("\t\tThread Identity :{0}",
WindowsIdentity.GetCurrent().Name);
Console.WriteLine("\t\tThread Identity level :{0}",
WindowsIdentity.GetCurrent().ImpersonationLevel);
Console.WriteLine("\t\thToken :{0}",
WindowsIdentity.GetCurrent().Token.ToString());
}
}
Please refer to the below example.
https://learn.microsoft.com/en-us/dotnet/framework/wcf/samples/impersonating-the-client
https://learn.microsoft.com/en-us/dotnet/framework/wcf/feature-details/delegation-and-impersonation-with-wcf
Feel free to let me know if there is anything I can help with.
Upvotes: 0
Reputation: 1618
This seems to be a problem with pass-through authentication. First, you need to be in a Active Directory environment. Kerberos must be used for authentication, NTLM will not work. You can use klist to check this: https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/klist
Also see https://blogs.msdn.microsoft.com/besidethepoint/2010/05/08/double-hop-authentication-why-ntlm-fails-and-kerberos-works/ for an explanation.
May be this SO article can help:
Pass Windows credentials to remote https WCF service
Upvotes: 1