Regarding to my previous post on breaking changes in SP1 for Visual Studio 2008 and the .NET Framework 3.5 I found another breaking change in the in the SspiNegotiatedOverTransport authentication mode (WCF).
When WSHttpBinding, WS2007HttpBinding, or NetTcpBinding is used with SecurityMode = TransportWithMessageCredential and a client credential type of Windows, clients that previously authenticated to a service by using NTLM will now fail to authenticate, with the following error:
"System.ComponentModel.Win32Exception: Security Support Provider Interface (SSPI) authentication failed. The server may not be running in an account with identity 'host/<hostname>'. If the server is running in a service account (Network Service for example), specify the account's ServicePrincipalName as the identity in the EndpointAddress for the server. If the server is running in a user account, specify the account's UserPrincipalName as the identity in the EndpointAddress for the server."
The error appears when the service is running on an account that has an identity other than 'host/<hostname>'. This issue also applies to CustomBindings, which specify the SspiNegotiatedOverTransport authentication mode.
To resolve this issue:
If possible, clients should be updated by using a UPN or SPN endpoint identity that specifies the identity of the service so that Kerberos authentication occurs. The following configuration snippet shows how to do this in the UPN case; the SPN case is similar, but the <servicePrincipalName> element is used instead.
<system.serviceModel>
<client>
<endpoint>
<identity>
<userPrincipalName value="user@domain" />
</identity>
</endpoint>
</client>
</system.serviceModel>
Additionally, clients that use NetTcpBinding or CustomBindings, with SspiNegotiatedOverTransport specified in the stack over SslStreamSecurityBindingElement, must specify a custom IdentityVerifier in the code to perform the CN check of the service's certificate. The following code snippet shows how to do this and provides a starting point for IdentityVerifier implementations.
{
NetTcpBinding tcpBinding = new NetTcpBinding(SecurityMode.TransportWithMessageCredential);
CustomBinding customBinding = new CustomBinding(tcpBinding.CreateBindingElements());
SslStreamSecurityBindingElement ssl = customBinding.Elements.Find<SslStreamSecurityBindingElement>();
ssl.IdentityVerifier = new DnsIdentityVerifier(new DnsEndpointIdentity("DNS.name.of.service.certificate"));
}
public class DnsIdentityVerifier : IdentityVerifier
{
DnsEndpointIdentity _expectedIdentity;
public DnsIdentityVerifier(DnsEndpointIdentity expectedIdentity)
{
_expectedIdentity = expectedIdentity;
}
public override bool CheckAccess(EndpointIdentity identity, AuthorizationContext authContext)
{
List<Claim> dnsClaims = new List<Claim>();
foreach (ClaimSet claimSet in authContext.ClaimSets)
{
foreach (Claim claim in claimSet)
{
if (ClaimTypes.Dns == claim.ClaimType)
{
dnsClaims.Add(claim);
}
}
}
if (1 != dnsClaims.Count)
{
throw new InvalidOperationException(String.Format("Found {0} DNS claims in authorization context.", dnsClaims.Count));
}
return String.Equals((string)_expectedIdentity.IdentityClaim.Resource, (string)dnsClaims[0].Resource, StringComparison.OrdinalIgnoreCase);
}
public override bool TryGetIdentity(EndpointAddress reference, out EndpointIdentity identity)
{
identity = _expectedIdentity;
return true;
}
}
You can find this information in the Microsoft .NET Framework 3.5 Service Pack 1 (SP1) Readme:
http://download.microsoft.com/download/A/2/8/A2807F78-C861-4B66-9B31-9205C3F22252/dotNet35SP1Readme.htm
Posted
Aug 13 2008, 10:28 AM
by
alehmann