Search code examples
c#asp.net-mvcwcfauthenticationintranet

Intranet - web to remote wcf CredentialCache.DefaultNetworkCredentials not working


I have a ASP.NET MVC intranet application hosted in IIS that added WCF service reference the WCF resides in another computer and also expect windows authentication. In my web this code is working great:

proxy = new MyProxyClient("configurationName", "remoteAddress");
proxy.ClientCredentials.Windows.ClientCredential.UserName = "myUserName";
proxy.ClientCredentials.Windows.ClientCredential.Password = "MyPassword";

proxy.SomeMethod(); //work great

but if I want the credential not to be hardcoded like this I am using: CredentialCache.DefaultNetworkCredentials like this:

 proxy = new MyProxyClient("configurationName", "remoteAddress");
 proxy.ClientCredentials.Windows.ClientCredential = CredentialCache.DefaultNetworkCredentials;

 proxy.SomeMethod(); //not working throw exception

the above code throw SecurityNegotiationException with message: The caller was not authenticated by the service. and the inner exception is: The request for security token could not be satisfied because authentication failed.

How can I pass the credential of the current user to the WCF service without hardcoded user name and password?


Solution

  • If your organization uses regular Windows authentication (NTLM) you can't do what you want due to "one-hop" restriction: credentials passed from user's computer to your server use "one-hop" (from direct login to one external computer) and such credentials can't be used to authenticate other servers from the first one.

    More information can be found using following search term:ntlm one hop,i.e. Why NTLM fails and Kerberos works.

    Standard solution:

    • Kerberos (often requires significant effort to get approval to enable/configure)
    • Use some other form of authentication than Windows. Consider if OAuth is possible. Don't go basic auth.
    • Switch WCF service to claims based authentication.
    • If WCF service can it can trust caller to verify incoming credentials more approaches are possible:
      1. Run code under particular account that signs in locally on server and have permissions to call the service. The easiest approach is what shown in your post, but storing domain passwords (or any passwords) in plain text is not secure. One can also run process account under special credentials that have access to the remote service and temporary revert impersonation after verifying user credentials.
      2. You can also configure WCF service to require client certificate and use such certificate when calling the WCF service. This way WCF service can verify if caller is known.