Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to write code that calls a WCF service and falls back from Kerberos to NTLM if needed?

I need to call a WCF service programmatically. The service may be hosted with either NTLM or Kerberos authentication and needs to work under either. That is, if connecting to the service via Kerberos fails, then it should fall back to NTLM.

Here's the code I'm using for Kerberos auth (if relevant, the service is hosted in SharePoint 2010 and is being called from a web part):

public static SiteMembershipSvc.SiteMembershipServiceClient InitialiseSiteMembershipService(string url)
{
    var binding = new BasicHttpBinding();
    binding.Security.Mode = BasicHttpSecurityMode.TransportCredentialOnly;
    binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Windows;
    url = url.EndsWith("/") ? url + SiteMembershipAddress : url + "/" + SiteMembershipAddress;
    var endpoint = new EndpointAddress(url);
    var proxy = new SiteMembershipSvc.SiteMembershipServiceClient(binding, endpoint);
    proxy.ClientCredentials.Windows.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Impersonation;
    return proxy;
}

Calling a method on the proxy when run in an NTLM environment gives the error:

The HTTP request is unauthorized with client authentication scheme 'Negotiate'. The authentication header received from the server was 'NTLM'.

Note: The URL may be in another web application on another server. I can't check what authentication the web part's web app runs under and assume it is the same as where the WCF service is hosted.

How can I (automatically or manually) ensure authentication falls back from Kerberos back to NTLM on failure?

Update:

As mentioned, the authentication error occurs when a web method is called. However I don't want to wait that long as there are several web methods in the service called from several places. I'd like to test the authentication at the point where the proxy is configured (in the code snippet above).

I've tried using proxy.Open() but that doesn't seem to cause the failure.

like image 304
Alex Angas Avatar asked Sep 09 '10 00:09

Alex Angas


2 Answers

This is a bit off a curveball, but why is it falling back to NTLM. I've had significant difficulty with security in active directory and WCF all related to service principal names (SPNs).

Kerberos will fail if you are running the service as something other than Network Service unless you have an SPN declared in the domain for your service. To set the SPN you need the windows server administrative kit, which has the command setspn.

setspn -A HTTP\machinename domain\service_account

This will then allow Kerberos to share client credentials to your service within the domain.

Please do some reading, as you could break kerberos for any other services running on the same box depending on your setup.

like image 190
Spence Avatar answered Nov 13 '22 06:11

Spence


(I recognize the original post is very old.)

Can you use something other than BasicHttpBinding (like WsHttpBinding)? According to this article, BasicHttpBinding is the one exception to the binding objects, in that it does not automatically negotiate. This is why allowNTLM has no effect.

like image 29
Les Avatar answered Nov 13 '22 06:11

Les