Freigeben über


Orcas SP1 Released

The first service pack for .NET Framework 3.5 came out
yesterday, primarily focusing on fixing bugs and performance issues.  There are some new features, notably around
improving the support for REST based services and around serialization.

Here are some known issues related to WCF in this release.

Authentication
failure when Windows authentication is used over certain transports

WCF now specifies a default domain target name in Windows
authentication scenarios. When upgrading, the client may see an authentication
failure when the following conditions exist:

- The scenario uses ClientCredentialType.Windows, which specifies the Negotiate authentication scheme.

The scenario uses http, https, or net.tcp.
  • The service runs under a non-domain account.

An example of the authentication failure is
"System.ComponentModel.Win32Exception The target principal name is
incorrect"

To resolve this issue:

The client must override the default domain target name by
specifying the Service Principal Name of the server in the SpnEndpointIdentity
class, or User Principal Name in the UpnEndpointIdentity class, and then
passing the identity to the EndpointAddress. If the client uses Https and
requires X509CertificateEndpointIdentity, the client must still specify the
SpnEndpointIdentity or UpnEndpointIdentity. The X509CertificateEndpointIdentity
enables validation of thumbprints. The client can work around the loss of
validation by registering for the System.Net.ServicePointManager.ServerCertificateValidationCallback
and performing thumbprint validation manually.

Breaking changes in
the SspiNegotiatedOverTransport authentication mode

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
snippets show how to do this and provide 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;
   }
}

Comments