web-dev-qa-db-fra.com

Point de terminaison du client WCF: SecurityNegotiationException sans <dns>

Je vais avoir une situation étrange ici. Je l'ai fait fonctionner, mais je ne comprends pas pourquoi. La situation est la suivante: 

Il existe un service WCF que mon application (un site Web) doit appeler. Le service WCF expose une transaction netTcpBinding et requiert la sécurité du transport (Windows). Le client et le serveur se trouvent dans le même domaine, mais sur des serveurs différents.
Donc, générer un client a pour résultat la config suivante (principalement par défaut)

<system.serviceModel>
    <bindings>
      <netTcpBinding>
         <binding name="MyTcpEndpoint" ...>          
              <reliableSession ordered="true" inactivityTimeout="00:10:00"
                              enabled="false" />
             <security mode="Transport">
                <transport clientCredentialType="Windows" protectionLevel="EncryptAndSign"/>
                <message clientCredentialType="Windows" />
            </security>
        </binding>
      </netTcpBinding>
    </bindings>
    <client> 
        <endpoint address="net.tcp://localhost:xxxxx/xxxx/xxx/1.0" 
                   binding="netTcpBinding" bindingConfiguration="MyTcpEndpoint" 
                   contract="Service.IMyService" name="TcpEndpoint"/>
    </client>
</system.serviceModel>

Lorsque j'exécute le site Web et passe l'appel au service, le message d'erreur suivant s'affiche: 

System.ServiceModel.Security.SecurityNegotiationException: Either the target name is incorrect or the server has rejected the client credentials. ---> System.Security.Authentication.InvalidCredentialException: Either the target name is incorrect or the server has rejected the client credentials. ---> System.ComponentModel.Win32Exception: The logon attempt failed
    --- End of inner exception stack trace ---
    at System.Net.Security.NegoState.EndProcessAuthentication(IAsyncResult result)
    at System.Net.Security.NegotiateStream.EndAuthenticateAsClient(IAsyncResult asyncResult)
    at System.ServiceModel.Channels.WindowsStreamSecurityUpgradeProvider.WindowsStreamSecurityUpgradeInitiator.InitiateUpgradeAsyncResult.OnCompleteAuthenticateAsClient(IAsyncResult result)
    at System.ServiceModel.Channels.StreamSecurityUpgradeInitiatorAsyncResult.CompleteAuthenticateAsClient(IAsyncResult result)
    --- End of inner exception stack trace ---

Server stack trace: 
    at System.ServiceModel.AsyncResult.End[TAsyncResult](IAsyncResult result)
    at System.ServiceModel.Channels.ServiceChannel.SendAsyncResult.End(SendAsyncResult result)
    at System.ServiceModel.Channels.ServiceChannel.EndCall(String action, Object[] outs, IAsyncResult result)
....

Maintenant, si je modifie simplement la configuration du client de la manière suivante:

    <endpoint address="net.tcp://localhost:xxxxx/xxxx/xxx/1.0" 
               binding="netTcpBinding" bindingConfiguration="MyTcpEndpoint" 
               contract="Service.IMyService" name="TcpEndpoint">
        <identity>
            <dns />
        </identity> 
  </endpoint>

tout fonctionne et mon serveur indique avec joie qu'il a été appelé par le compte de service qui héberge l'AppPool pour mon site Web. Tout bon.

Ma question est la suivante: pourquoi cela fonctionne-t-il? Qu'est-ce que cela fait? Je suis arrivé à cette solution par simple essai et erreur. Il me semble que tout ce que la balise <dns /> indique au client d'utiliser le DNS par défaut pour l'authentification, mais ne le fait-il pas de toute façon?

METTRE &AGRAVE; JOUR
Donc, après quelques recherches et essais et erreurs, je n'ai toujours pas trouvé de réponse à ce problème. Dans certains cas, si je ne fournis pas le <dns />, je reçois le Erreur Credentials rejected, mais si je fournis le <dns value="whatever"/>config, cela fonctionne. Pourquoi?

18
RoelF

La balise <dns/> permet au client de vérifier l'identité du serveur. Par exemple, si vous avez dit <dns value="google.com"/>, cela vérifierait que le serveur WCF fournit l'identité de google.com. Puisque vous dites <dns/>, cela permet probablement à tout le monde de vous servir.

Plus d'infos sur Identité de service et authentification

14
Vitalik

MSDN's "Identité de service et authentification" explique que la section relative à l'identité du noeud final permet une précaution de sécurité côté client contre les schémas de phishing.

De MSDN: 

Une fois que le client a initié une communication avec un noeud final et que le service S’authentifie auprès du client, le client compare la valeur d’identité du noeud final À la valeur réelle renvoyée par le processus d’authentification par le noeud final . S'ils correspondent, le client est assuré Qu'il a contacté le point de terminaison du service attendu. Ceci constitue une protection Contre le phishing en empêchant un client d'être redirigé vers vers un point de terminaison hébergé par un service malveillant.

Voir également MSDN's "Exemple d'identité de service" .

6
Rana Ian

Pas une réponse, mais le même "truc" fonctionne si vous créez le EndpointAddress via le code:

// does fail on some machines for some users 
// (I have no explanation here - just crazy)
var address = new EndpointAddress(new Uri(url));

// will work and the dns entry doesn't matter
address = new EndpointAddress(new Uri(url), UpnEndpointIdentity.CreateDnsIdentity(""));

C'est étrange et je ne sais pas pourquoi cela fonctionne, mais cela semble aider.

0
Robert Muehsig