netTCP binding Soap Security Negotiation Failed
Asked Answered
H

2

17

I am writing a WCF service requires impersonate and session.

It is ok when I tried to call it on my local machine, but on the remote machine it always failed with such error:

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.

If I provided a upn, it throws an identity failed exception.

Here is my config:

Server Config(APP):

<system.serviceModel>    
    <behaviors>
      <serviceBehaviors>
        <behavior name="default">
          <serviceMetadata httpGetEnabled="true" />
          <serviceDebug includeExceptionDetailInFaults="true" />
          <serviceAuthorization impersonateCallerForAllOperations="true" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <bindings>
      <netTcpBinding>
        <binding name="DataService.netTcpBinding">
          <readerQuotas maxArrayLength="65535" maxBytesPerRead="2147483647" maxStringContentLength="2147483647"/>
          <reliableSession enabled="true" inactivityTimeout="24:00:00" ordered="true"/>          
          <security mode="TransportWithMessageCredential">
            <message clientCredentialType="Windows" />
            <transport clientCredentialType="Windows"/>          
          </security>
        </binding>
      </netTcpBinding>
    </bindings>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true"/>
    <services>
      <service behaviorConfiguration="default" name="DataService.DataService">
        <endpoint address="" binding="netTcpBinding" bindingConfiguration="DataService.netTcpBinding" 
          name="DataService.DataService" contract="DataService.IDataService"/>
        <endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange" />
        <host>
          <baseAddresses>
            <add baseAddress="http://address:4504/"/>
            <add baseAddress="net.tcp://address:4503/"/>
          </baseAddresses>
        </host>
      </service>
    </services>
</system.serviceModel>

Client Config:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <system.serviceModel>     
        <bindings>
            <netTcpBinding>
                <binding name="DataService.DataService" closeTimeout="00:01:00"
                    openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
                    transactionFlow="false" transferMode="Buffered" transactionProtocol="OleTransactions"
                    hostNameComparisonMode="StrongWildcard" listenBacklog="10"
                    maxBufferPoolSize="524288" maxBufferSize="65536" maxConnections="10"
                    maxReceivedMessageSize="65536">
                    <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
                        maxBytesPerRead="4096" maxNameTableCharCount="16384" />
                    <reliableSession ordered="true" inactivityTimeout="24.00:00:00"
                        enabled="true" />
                    <security mode="TransportWithMessageCredential">
                        <transport clientCredentialType="Windows" protectionLevel="EncryptAndSign" />
                        <message clientCredentialType="Windows" algorithmSuite="Default" />
                    </security>
                </binding>
            </netTcpBinding>
        </bindings>
        <client>
            <endpoint address="net.tcp://address:4503/" binding="netTcpBinding"
                bindingConfiguration="DataService.DataService"
                contract="ataService.IDataService" name="DataService.DataService">
              <identity>
                <dns value="DOMAIN"/>                                                  
              </identity>
            </endpoint>
        </client>
    </system.serviceModel>
</configuration>

Any help would be greatly appreciated.

Hutchinson answered 13/3, 2012 at 11:34 Comment(0)
A
24

Windows services register themselves with either a User Principal Name or a Service Principal Name (documentation). To quote from that link: "If the service is running under the LocalSystem, LocalService, or NetworkService account, a service principal name (SPN) is generated by default in the form of host/ because those accounts have access to the computer's SPN data. If the service is running under a different account, Windows Communication Foundation (WCF) generates a UPN in the form of @." In fact, this quote is rather similar to what your error message is stating. So it seems that...

a) if the service is running under the Local Service account or similar standard account, then you need to adjust your client configuration file to have this, where the actual server's name is "address" and the endpoint is running on port 4503:

<identity>
     <servicePrincipalName value="host/address:4503" />
</identity>

b) alternately, if you are running under a dedicated service account (let's call it "ServiceAccount" on the domain "MyDomain"), then you want

<identity>
     <userPrincipalName value="ServiceAccount@MyDomain" />
</identity>

Please note that you may need to use the fully-qualified domain name in both cases, including the Forest and Tree levels. For a simple domain inside of your private LAN/WAN, that will mean address.MyDomain.local and [email protected]. If your domain is in a tree called MyTree then it will be [email protected]; if that is in a forest called MyForest then it will be [email protected] (and similar for ServicePrincipalName). The fully-qualified name is needed when you are using Kerberos for authentication.

Armipotent answered 31/5, 2013 at 2:12 Comment(3)
This is correct. I'll also add that when consuming web services hosted by IIS, the identity should match the app pool identity that the service lives under. This was changed in some version of IIS (maybe 7?) from NetworkService (where you would use a user principle of NetworkService@MACHINE-NAME) to AppPoolIdentity (where you would use a service principle of host/MACHINE-NAME).Mongeau
Is there a way to do the above in an ASP.NET Core v6 WebAPI in the ConnectedService.json file?Effluent
Sorry, can't help you @Effluent - I'm not familiar with that ConnectedService.json file and haven't used WCF since 2014.Armipotent
R
9

There is also a dirty hack, as posted here, here, and here, and analysed here.

You can supply a dummy Service Principal Name (SPN). In that case, WCF will not fail, but fall back to NTLM for authentication which doesn't verify the principal.

So, configuration:

    <identity>
      <servicePrincipalName value="dummy" >
    </identity>

and programmatically

    EndpointIdentity identity = EndpointIdentity.CreateSpnIdentity("dummy");

using ChannelFactory:

    Uri uri = new Uri("net.tcp://<myServer>:<myPort>/myServiceAddress");
    ChannelFactory channelFactory = new ChannelFactory<IMyContract>(new NetTcpBinding());
    channelFactory.CreateChannel(new EndpointAddress(uri, identity)

will also work.

Resurrectionist answered 8/11, 2013 at 1:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.