Debugging Windows Authentication Errors
When using Windows authentication as a security mechanism, the Security Support Provider Interface (SSPI) handles security processes. When security errors occur at the SSPI layer, they are surfaced by Windows Communication Foundation (WCF). This topic provides a framework and set of questions to help diagnose the errors.
For Windows authentication, WCF typically uses the Negotiate Security Support Provider (SSP), which performs Kerberos mutual authentication between the client and service. If the Kerberos protocol is not available, by default WCF falls back to NT LAN Manager (NTLM). However, you can configure WCF to use only the Kerberos protocol (and to throw an exception if Kerberos is not available). You can also configure WCF to use restricted forms of the Kerberos protocol.
The basic method is as follows:
Determine whether you are using Windows authentication. If you are using any other scheme, this topic does not apply.
If you are sure you are using Windows authentication, determine whether your WCF configuration uses Kerberos direct or Negotiate.
Once you have determined whether your configuration is using the Kerberos protocol or NTLM, you can understand error messages in the correct context.
The Kerberos SSP requires a domain controller to act as the Kerberos Key Distribution Center (KDC). The Kerberos protocol is available only when both the client and service are using domain identities. In other account combinations, NTLM is used, as summarized in the following table.
The table headers show possible account types used by the server. The left column shows possible account types used by the client.
Specifically, the four account types include:
Local User: Machine-only user profile. For example: MachineName\Administrator or MachineName\ProfileName.
Local System: The built-in account SYSTEM on a machine that is not joined to a domain.
Domain User: A user account on a Windows domain. For example: DomainName\ProfileName.
Domain Machine: A process with machine identity running on a machine joined to a Windows domain. For example: MachineName\Network Service.
This section discusses some common Windows authentication problems and possible remedies.
When using Windows authentication, and the Kerberos protocol is used or negotiated by SSPI, the URL the client endpoint uses must include the fully qualified domain name of the service's host inside the service URL. This assumes that the account under which the service is running has access to the machine (default) service principal name (SPN) key that is created when the computer is added to the Active Directory domain, which is most commonly done by running the service under the Network Service account. If the service does not have access to the machine SPN key, you must supply the correct SPN or user principal name (UPN) of the account under which the service is running in the client's endpoint identity. For more information about how WCF works with SPN and UPN, see Service Identity and Authentication.
In load-balancing scenarios, such as Web farms or Web gardens, a common practice is to define a unique account for each application, assign an SPN to that account, and ensure that all of the application's services run in that account.
To obtain an SPN for your service's account, you need to be an Active Directory domain administrator. For more information, see Kerberos Technical Supplement for Windows.
This occurs when the ClientCredentialType property is set to Windows and the NegotiateServiceCredential property is set to false, as shown in the following code.
WSHttpBinding b = new WSHttpBinding(); // By default, the WSHttpBinding uses Windows authentication // and Message mode. b.Security.Message.NegotiateServiceCredential = false;
To remedy, run the service using a Domain Machine account, such as Network Service, on a domain joined machine.
To use the Kerberos authentication protocol with delegation, you must implement the Kerberos protocol with credential negotiation (sometimes called "multi-leg" or "multi-step" Kerberos). If you implement Kerberos authentication without credential negotiation (sometimes called "one-shot" or "single-leg" Kerberos), an exception will be thrown.
To implement Kerberos with credential negotiation, do the following steps:
Require SSPI negotiation:
If you are using standard bindings, set the NegotiateServiceCredential property to true.
If you are using custom bindings, set the AuthenticationMode attribute of the Security element to SspiNegotiated.
Require the SSPI negotiation to use Kerberos by disallowing the use of NTLM:
Do this in code, with the following statement: ChannelFactory.Credentials.Windows.AllowNtlm = false
Or you can do this in the configuration file by setting the allowNtlm attribute to false. This attribute is contained in the <windows> of <clientCredentials> Element.
The AllowNtlm property is set to false, which causes Windows Communication Foundation (WCF) to make a best-effort to throw an exception if NTLM is used. Note that setting this property to false may not prevent NTLM credentials from being sent over the wire.
The following shows how to disable fallback to NTLM.
The client credentials are not valid on the service. Check that the user name and password are correctly set and correspond to an account that is known to the computer where the service is running. NTLM uses the specified credentials to log on to the service's computer. While the credentials may be valid on the computer where the client is running, this logon will fail if the credentials are not valid on the service's computer.
When creating a client, the AllowedImpersonationLevel property is set to Anonymous, as shown in the following example, but by default the server disallows anonymous logons. This occurs because the default value of the AllowAnonymousLogons property of the WindowsServiceCredential class is false.
The following client code attempts to enable anonymous logons (note that the default property is Identification).
CalculatorClient cc = new CalculatorClient("WSHttpBinding_ICalculator"); cc.ClientCredentials.Windows.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Anonymous;
The following service code changes the default to enable anonymous logons by the server.
Uri httpUri = new Uri("http://localhost:8000/"); ServiceHost sh = new ServiceHost(typeof(Calculator), httpUri); sh.Credentials.WindowsAuthentication.AllowAnonymousLogons = true;
For more information about impersonation, see Delegation and Impersonation with WCF.
Alternatively, the client is running as a Windows service, using the built-in account SYSTEM.
Windows authentication uses the WindowsClientCredential instance returned by the ClientCredentials property of the ClientBase<TChannel> class, not the UserNamePasswordClientCredential. The following shows an incorrect example.
CalculatorClient cc = new CalculatorClient("WSHttpBinding_ICalculator"); cc.ClientCredentials.UserName.UserName = GetUserName(); // wrong! cc.ClientCredentials.UserName.Password = GetPassword(); // wrong!
The following shows the correct example.
The following operating systems do not support Windows authentication when used as a server: Windows XP Home Edition, Windows XP Media Center Edition, and Windows Vista Home editions.
If you develop your application on one machine, and deploy on another, and use different account types to authenticate on each machine, you may experience different behavior. For example, suppose you develop your application on a Windows XP Pro machine using the SSPI Negotiated authentication mode. If you use a local user account to authenticate with, then NTLM protocol will be used. Once the application is developed, you deploy the service to a Windows Server 2003 machine where it runs under a domain account. At this point the client will not be able to authenticate the service because it will be using Kerberos and a domain controller.