Unanswered Kerberos Delegation Fails

  • Thursday, April 05, 2012 8:46 AM
     
     

    Hi,

    We've deployed a WCF DataService to our IIS6/Win2003 box.  When the service tries to connect to the SqlServer backend  (using Integrated Security=True) it seems to lose the Windows Credentials of the calling user and throws a "Login failed for user 'NT AUTHORITY\\ANONYMOUS LOGON".

    I'm pretty sure this just actually means that the delegation is failing. The question is why, we have set up Kerberos for the box, we have confirmed it works for a test aspx page connecting to the same database, and the wcf service config file and client has been set up to.

    So in more detail:

    Client (IE6 and IE8)

    WebServer (IIS6/Win2003). Wcf service running under domain service account in the app pool with SPNs set up (Anonymous Authentication is also checked when I turn on Windows Authentication)

    Database - Win 2003/SqlServer 2005 with SPNs set up

    The exception we get is on a sqlconnection.Open() line and is:

    System.Data.SqlClient.SqlException was caught

      Message="Login failed for user 'NT AUTHORITY\\ANONYMOUS LOGON'."

      Source=".Net SqlClient Data Provider"

      ErrorCode=-2146232060

    Our Wcf WebService web.config file is, and we have tried every variation on it, but to no avail so far:

    <?xml version="1.0" encoding="utf-8" ?>

    <configuration>

      <configSections/>

      <appSettings>

        <add key="LimitStoreServer" value="AMS1-S-06692.europe.shell.com\DEV01"/>

        <add key="LimitStoreDatabase" value="LimitStoreV6_2"/>

      </appSettings>

      <system.diagnostics>

        <trace autoflush="true" />

        <sources>

          <source name="System.ServiceModel"

                  switchValue="Information, ActivityTracing"

                  propagateActivity="true">

            <listeners>

              <add name="sdt"

                  type="System.Diagnostics.XmlWriterTraceListener"

                  initializeData= "SdrConfigExample.e2e" />

            </listeners>

          </source>

        </sources>

      </system.diagnostics>

      <system.net>

        <defaultProxy>

          <proxy autoDetect="false" />

        </defaultProxy>

      </system.net>

      <system.serviceModel>

    <diagnostics wmiProviderEnabled="false" performanceCounters="Off">

            <messageLogging logEntireMessage="true" logMalformedMessages="false"

               logMessagesAtServiceLevel="false" logMessagesAtTransportLevel="false" />

         </diagnostics>

        <bindings>

          <basicHttpBinding>

    <binding name="BasicEndpoint" closeTimeout="00:03:00" openTimeout="00:03:00"

                receiveTimeout="00:10:00" sendTimeout="00:03:00" allowCookies="false"

                bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"

                maxBufferSize="1000000" maxBufferPoolSize="524288" maxReceivedMessageSize="1000000"

                messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"

                useDefaultWebProxy="true">

              <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"

                  maxBytesPerRead="4096" maxNameTableCharCount="16384" />

              <security mode="TransportCredentialOnly">

                <transport clientCredentialType="Windows"  proxyCredentialType="Windows"

                        realm="" />

              </security>

            </binding>

          </basicHttpBinding>

        </bindings>

        <services>

          <service name="WcfKerberosTest.Service1" behaviorConfiguration="DefaultBehavior">

            <endpoint address=""

              binding="basicHttpBinding" bindingConfiguration="BasicEndpoint" name="BasicEndpoint"

            contract="WcfKerberosTest.IService1" >

             

            </endpoint>

            <endpoint address="mex" binding="basicHttpBinding" name="MexEndpoint"

                     contract="IMetadataExchange" />

          </service>

        </services>

        <behaviors>

          <serviceBehaviors>

            <behavior name="DefaultBehavior">

              <serviceDebug includeExceptionDetailInFaults="true"/>

              <serviceMetadata httpGetEnabled="true"/>

             <serviceCredentials>

                <windowsAuthentication includeWindowsGroups="true" allowAnonymousLogons="true" />

                <issuedTokenAuthentication allowUntrustedRsaIssuers="true" />

              </serviceCredentials>

              <serviceAuthorization principalPermissionMode="UseWindowsGroups"

                impersonateCallerForAllOperations="true" />

              <serviceSecurityAudit auditLogLocation="Default" serviceAuthorizationAuditLevel="SuccessOrFailure"

                messageAuthenticationAuditLevel="SuccessOrFailure" />

            </behavior>

          </serviceBehaviors>

        </behaviors>

      </system.serviceModel>

    </configuration>

    The event log I think is indicating that the problem is simply that the wcf service is not using kerberos. Below the first image is from our test aspx page, which does successfully connect to the database. The second is the wcf service trying to do exactly the same thing but failing. Both are hosted on the same urls so there should be no SPNs differences here.

    1.       Using http://websvc1-int-wrm32-01.sharing.shell.comTestKerberos/Default.aspx

    2.       Using http://websvc1-int-wrm32-01.sharing.shell.com/WcfTestKerberos/Service1.svc

    This has been stumping us for days now. Any ideas appreciated

    G

All Replies

  • Friday, April 06, 2012 1:54 AM
    Moderator
     
     
    Hello, are you using WCF Data Services? If so, the basicHttpBinding in your web.config will not be applied to your service. You need to configure a global webHttpBinding (a binding without name). However, you also have a custom service endpoint in your config file. So do you mean you're using a SOAP service that works with data, instead of a Data Service? In this case, make sure you have the correct code to impersonate the user (for example, set Impersonation = ImpersonationOption.Required). Refer to http://msdn.microsoft.com/en-us/library/ms730088.aspx for more details.

    Lante, shanaolanxing This posting is provided "AS IS" with no warranties, and confers no rights.
    If you have feedback about forum business, please contact msdnmg@microsoft.com. But please do not ask technical questions in the email.

  • Friday, April 06, 2012 4:59 PM
     
     

    Hi

    Thx, we are using WCF as a SOAP service. We have the correct code in for impersonation, at least we think we do, including decorating methods with Impersonation = ImpersonationOption.Required. It makes no difference, we still get the same error.

    I have referred to the Url you supplied, thx, however as far as I can see we are complying with the described setup.

    Can you advise further ?

    Gordon

    
  • Friday, April 06, 2012 5:33 PM
     
      Has Code

    Hi, when calling out to network service you need to use the delegation impersonation level

    Apply the following to the client config:

            <endpointBehaviors>
              <behavior name="NewBehavior">
                <clientCredentials>
                  <windows allowedImpersonationLevel="Delegation" />
                </clientCredentials>
              </behavior>
            </endpointBehaviors>

    This will allow the client to make calls out into the network with its own credentials
  • Monday, April 09, 2012 4:14 PM
     
      Has Code

    Hi

    Thx for the suggestion, but we already have this in the configuration. Again it makes no difference.

    I've pasted in our client app.config. It has two configurations which we've tested out (changing the server web.config as appropriate to match the client). Both configs "refuse" to use kerberos.

    <?xml version="1.0" encoding="utf-8" ?>
    
    <configuration>
    
     
    
    <system.serviceModel>
    
     <bindings>
    
     <basicHttpBinding>
    
     <binding name="BasicEndpoint" closeTimeout="00:01:00" openTimeout="00:01:00"
    
     receiveTimeout="00:10:00" sendTimeout="00:01:00" allowCookies="false"
    
     bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
    
     maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
    
     messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
    
     useDefaultWebProxy="true">
    
     <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
    
     maxBytesPerRead="4096" maxNameTableCharCount="16384" />
    
     <security mode="TransportCredentialOnly">
    
     <transport clientCredentialType="Windows" proxyCredentialType="None"
    
     realm="" />
    
     <message clientCredentialType="UserName" />
    
     </security>
    
     </binding>
    
     </basicHttpBinding>
    
     <wsHttpBinding>
    
     <binding name="WSHttpBinding_IService1" closeTimeout="00:01:00"
    
     openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
    
     bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard"
    
     maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
    
     messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true"
    
     allowCookies="false">
    
     <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
    
     maxBytesPerRead="4096" maxNameTableCharCount="16384" />
    
     <reliableSession ordered="true" inactivityTimeout="00:10:00"
    
     enabled="false" />
    
     <security mode="Message">
    
     <transport clientCredentialType="Windows" proxyCredentialType="None"
    
     realm="" />
    
     <message clientCredentialType="Windows" negotiateServiceCredential="true"
    
     algorithmSuite="Default" establishSecurityContext="true" />
    
     </security>
    
     </binding>
    
     </wsHttpBinding>
    
     </bindings>
    
     <client>
    
     <endpoint address="" behaviorConfiguration="FRB.AllowImpersonate"
    
     binding="basicHttpBinding" bindingConfiguration="BasicEndpoint"
    
     contract="KerberosTest.IService1" name="BasicEndpoint" />
    
     <endpoint address=""
    
     binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IService1" behaviorConfiguration="FRB.AllowImpersonate"
    
     contract="Kerberos8421wsHttp.IService1" name="WSHttpBinding_IService1">
    
     <identity>
    
     <servicePrincipalName value="" />
    
     </identity>
    
     </endpoint>
    
     </client>
    
     <behaviors>
    
     <endpointBehaviors>
    
     <behavior name='FRB.AllowImpersonate'>
    
     <clientCredentials> 
    
    <windows allowedImpersonationLevel="Delegation" />
    
     <httpDigest impersonationLevel="Delegation" />
    
     </clientCredentials>
    
     </behavior>
    
     </endpointBehaviors>
    
     </behaviors>
    
     
    
    </system.serviceModel>
    
    </configuration>
    

    
    
    
  • Monday, April 09, 2012 5:44 PM
     
     

    I just realised, did you say you created a WCF Data Service or when you say WCF DataService you me a normal WCF Service that makes data avaliable?

    If it is a WCF Data Service then any configuration you put in the config file will be disregarded as ASP.NET is doing the authentication.

    In IIS Manager, Create and Application Pool and use the Classic Pipeline. That is the only way I can get ASP.NET impersonation to work on my PC. Intergrated Mode always throws an error.

    Assign the new Application Pool to your WCF Data Service Web Application
  • Monday, April 16, 2012 9:59 AM
     
     

    Hi

    A normal WCF Service that makes data available, (and the config file definitely does make a difference.)

    We are using IIS6.0, so we can't implement the classic pipeline configuration.

    Gordon