Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
565 views
in Technique[技术] by (71.8m points)

wcf security - WCF and Kerberos Authentication

I have followed numerous msdn articles and the codeplex guidance but cannot get WCF to work with Kerberos authentication and delegation and would appreciate a little help.

Setup

I have the WCF service in an IIS website on a remote machine

  • IIS 6.0 on Windows 2003 R2 - SP 2
  • The SPN for the machine has been added (http/myserver && http/myserver:8080)
  • An AD account has been created for the IIS app pool
  • The AD account has the setting, allow delegation (for Kerberos), set to true

I am using Brian Booth's debug site on 8080 and the site passes all requirements for Kerberos delegation. The debug IIS site has anonymous authentication off, and Integrated Windows authentication on.

I have mirrored these settings to the site hosting the WCF service.

Web Service - Web Config (Original)

<system.serviceModel>
    <bindings>
        <wsHttpBinding>
            <binding name="WsHttpBindingConfig">
                <security>
                    <message negotiateServiceCredential="true" />
                </security>
            </binding>
        </wsHttpBinding>
    </bindings> 
    <services>
        <service behaviorConfiguration="ServiceBehavior" name="Service">    
            <endpoint address="" 
                binding="wsHttpBinding" 
                bindingConfiguration="WsHttpBindingConfig" 
                contract="IService">    
                <identity>    
                    <servicePrincipalName value="http/myserver" />    
                    <dns value="" />    
                </identity>    
            </endpoint>    
            <endpoint address="mex" 
                binding="mexHttpBinding" 
                contract="IMetadataExchange" />    
        </service>    
    </services>    
    <behaviors>    
        <serviceBehaviors>    
            <behavior name="ServiceBehavior">    
                <serviceMetadata httpGetEnabled="true"/>    
                <serviceDebug includeExceptionDetailInFaults="true"/>    
                <serviceAuthorization 
                    impersonateCallerForAllOperations="true" />    
            </behavior>    
        </serviceBehaviors>    
    </behaviors>    
</system.serviceModel>

Web Service - Web Method

[OperationBehavior(Impersonation = ImpersonationOption.Required)]
public string GetCurrentUserName()
{
    string name = WindowsIdentity.GetCurrent().Name;
    return name;
}

Client App - App Config

<system.serviceModel>
    <bindings>
        <wsHttpBinding>
            <binding name="WSHttpBinding_IService" 
                ... />
                ...
                <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="http://myserver/Service.svc" 
            binding="wsHttpBinding" 
            bindingConfiguration="WSHttpBinding_IService"
            contract="KerberosService.IService" 
            name="WSHttpBinding_IService">
            <identity>
                <servicePrincipalName value="http/myserver" />
            </identity>
        </endpoint>
     </client>
</system.serviceModel>

Application Error

The following error occurs when my test application, a WinForms app, tries to call the web method:

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

Event Log

The following error is in the event log:

Exception: System.ServiceModel.ServiceActivationException: The service '/Service.svc' cannot be activated due to an exception during compilation. The exception message is: Security settings for this service require 'Anonymous' Authentication but it is not enabled for the IIS application that hosts this service.

Which I don't understand. The whole point of this service is to not allow anonymous authentication, every user/request must be authenticated using Kerberos tickets, then passing them through to other machines.

How should I configure this WCF service for Kerberos authentication and delegation?

Revision 1

After reading this SO question I removed the metadata endpoint. This has not resolved the issue.

Revision 2

After more researching I found a few posts suggesting to change wsHttpBinding to basicHttpBinding. The modification to that portion of the web.config has been included below, and the service endpoint has been updated to refer to that binding.

Web Service - Web Config (Revised)

<basicHttpBinding>
    <binding name="basicBindingConfig">
        <security mode="TransportCredentialOnly">
            <transport clientCredentialType="Windows" 
                proxyCredentialType="Windows" 
                realm="" />
        </security>
    </binding>
</basicHttpBinding>

Client App - App Config (Revised)

<!-- ... -->
<security mode="TransportCredentialOnly">
    <transport clientCredentialType="Windows" 
        proxyCredentialType="Windows"
        realm="" />
    <message clientCredentialType="UserName" 
        algorithmSuite="Default" />
</security>
<!-- ... -->

Error (Revised)

The current error looks like it contains a Kerberos authentication header.

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

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

For me the current setup does work:

On the Server:

<system.serviceModel>
  <bindings>
    <wsHttpBinding>
      <binding name="wsHttpBindingConf" useDefaultWebProxy="true"/>
    </wsHttpBinding>
  </bindings>

  <services>
    <service behaviorConfiguration="returnFaults" name="Epze.BusinessLayer.ZeitManager">
        <endpoint binding="wsHttpBinding" bindingConfiguration="wsHttpBindingConf" contract="Epze.Contract.IZeitManager"/>
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
    </service>
  </services>

  <behaviors>
    <serviceBehaviors>
        <behavior name="returnFaults">
            <serviceMetadata httpGetEnabled="true"/>
            <serviceDebug includeExceptionDetailInFaults="true"/>
            <serviceAuthorization impersonateCallerForAllOperations="true"/>
        </behavior>
    </serviceBehaviors>
  </behaviors>
</system.serviceModel>

Set the following attribute on all methods for the WCF:

[OperationBehavior(Impersonation = ImpersonationOption.Required)]

On the Client:

<system.serviceModel>
  <bindings>
    <wsHttpBinding>
        <binding name="WSHttpBinding_IZeitManager" 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>

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

  <client>
    <endpoint address="http://server.mydomain.net/ePZEsvc/ZeitManager.svc" binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IZeitManager" 
              contract="External.Epze.IZeitManager" name="WSHttpBinding_IZeitManager" behaviorConfiguration="Delegation">
        <identity>
            <servicePrincipalName value="HOST/localhost"/>
        </identity>                      
    </endpoint>
  </client>
</system.serviceModel>

HTH, Sven


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...