Laden...

WCF: The server has rejected the client credentials.

Erstellt von matthias@friehe.eu vor 16 Jahren Letzter Beitrag vor 16 Jahren 9.278 Views
M
matthias@friehe.eu Themenstarter:in
9 Beiträge seit 2007
vor 16 Jahren
WCF: The server has rejected the client credentials.

Guten Morgen,

habe gerade ein großes Problem mit der WCF. Ich habe eine kleine Test-Applikation geschrieben, die einen WCF-Dientst in einer WinForms-Anwendung hostet.

Ich benutzer NetTcpBinding. Solange ich alles auf dem localhost probiert habe, hat das auch alles wunderbar funktioniert. Dann habe ich das auch zwischen zwei Vista-PCs, meinem Laptop und meinem Desktop, ausprobiert. Auch hier lief alles ohne Probleme.

Dann habe ich versucht, auch eine Verbindung mit meinem alten WinXP-Laptop aufzunehmen. Das schlug fehl. Der XP-Client hat die folgende Fehlermeldung ausgegeben:

The server has rejected the client credentials.

Habe das dann auch noch mal mit einem anderen XP-Laptop ausprobiert, da kam dann wohl die deutsche Übersetzung: Clientanmeldeinformation zurückgewiesen.

Unter "Clientanmeldeinformation" habe ich bei Google gar nichts gefunden. Die englische Fehlermeldung lässt sich zuweilen finden, allerdings ohne ordentliches Lösungskonzept.

Ich muss das jetzt noch mal zwischen XP und XP ausprobieren.

Was ist hier zu tun und woran genau liegt das? Liegt es an WinXP?

Das kann ja aber wohl überhaupt nicht sein. Denn angeblich ist die WCF doch (mehr oder weniger) eine plattformübergreifende Technologie - da sollte sie doch zumindest zwischen zwei Windows-Systemen laufen können, oder?

Matthias Friehe

3.728 Beiträge seit 2005
vor 16 Jahren
Privillegien

Der Client-Benutzer benötigt das Privilleg "Auf diesen Computer vom Netzwerk aus zugreifen" auf dem Server-Computer (Einzustellen über Lokale-Gruppenrichtlinie bzw. Active Directory).

Probleme gibt es auch, wenn die betroffenen Computer nicht Teil der selben Active Directory-Domäne sind. Ist der Server z.B. in einer Domäne, das Notebook aber nicht, kann der Server die Identität des Clients nicht überprüfen (da Active Directory ja nur Computer kennt, die Teil der Domäne sind). In diesem Fall muss die Bindung so angepasst werden, dass NTLM2 statt Kerberos als Athentifizierungsprotokoll verwendet wird. NTLM2 prüft nur Benutzername und Passwort, aber nicht das Konto des Clients.

M
matthias@friehe.eu Themenstarter:in
9 Beiträge seit 2007
vor 16 Jahren

Ist es möglich, dass der Server anonyme Anmeldungen akzeptiert? Ich möchte nämlich nicht unbedingt unter einer Domäne arbeiten. Die Authentifizierung via Zertifikaten lohnt sich in meinem Fall auch nicht.

Die Authentifizierung übernehme ich selbst, so dass ich mir diese ganzen Protokolle gerne ersparen würde.

Tatsächlich funktioniert das ganze auch, wenn ich den SecurityMode auf "None" setze. Das gefällt mir wiederum nicht, weil die Nachrichten dann auch nicht mehr verschlüsselt werden (wenn die WCF-Runtime mir das abnimmt, finde ich das eigentlich sehr praktisch).

Also: Ist es möglich, sich anonym, ohne Windows-Anmeldeinformationen, CardSpace oder sonst solchen Dingen anzumelden und die WCF trotzdem die Kommunikation verschlüsseln zu lassen?

Wie muss ich da denn die app.config konfigurieren? Ich hatte schon den SecurityMode auf "Message" gestellt und als algorithmSuite "Basic128" eingestellt. Wenn ich dann aber im message-Tag noch den clientCredentialType auf "None" stelle, erhalte ich die Fehlermeldung "Der ChannelDispatcher bei [Endpoint] mit den Verträgen [Contract] kann seinen IChannelListener nicht öffnen.

???

Matthias Friehe

M
matthias@friehe.eu Themenstarter:in
9 Beiträge seit 2007
vor 16 Jahren

Also so langsam wird das ganze hier immer komischer.
Wenn ich im Bereich <bindings><security>...
nur ein klein wenig von den Standard-Werten abweiche, zeigt der mir diese Exception von wegen Der ChannelDispatcher kann seinen ChannelListener nicht öffnen an. Wenn ich danach bei Google suche, bekomme ich dies als Fehlermeldung bei irgendwelchen BizTalk-Adaptern in der Alpha 2.

Ich benutze aber weder BizTalk noch eine Alpha sonder .NET Framework 3.0 RTM und ich bin der Meinung, dass Microsoft gefälligst dafür zu sorgen hat, dass seine Produkte laufen und nicht irgendwelchen Blödsinn fabrizieren. Und selbst wenn ich da irgendwo einen Tipp-Fehler habe möchte ich doch anmerken, dass diese Fehlermeldung wirklich alles andere als brauchbar ist.

Ich habe mir jetzt sogar in der MSDN ein Beispiel angeschaut, mit dem eine benutzerdefinierte Authentifizierung möglich sein soll: http://msdn2.microsoft.com/en-us/library/aa702565.aspx

Das habe ich 1:1 so umgesetzt und die Fehlermeldung kommt immer noch. Ich kann beim ClientCredentialType nichts anderes mehr als "Windows" angeben, sonst macht er gar nichts mehr.

Weiß irgendjemand Rat?

Matthias Friehe

3.728 Beiträge seit 2005
vor 16 Jahren
Sicherheit

Das Beispiel ist für HTTP-Protokoll ohne Windows-Authentifizierung geschrieben und nicht für TCP mit Windows-Authentifizierung.

Microsoft kann nichts dafür, dass Du eine Lösung haben willst, ohne dich mit dem Thema Security auseinanderzusetzen. Wenn Du Ausnahmen bekommst, liegt es daran, dass Du was falsch gemacht hast und nicht Microsoft. Durch ausprobieren kommst Du nicht zu einer soliden Sicherheitskonfiguration. WCF ist komplex, da es eben mit einer vielzahl von Protokollen und Standards umgehen und diese auch noch kombinieren kann. Am besten verwendest Du den Service Configuration Editor aus dem SDK.

Im folgenden Artikel findest Du detailierte Informationen zum Thema Sicherheit mit WCF:
http://www.microsoft.com/germany/msdn/library/net/wcf/SicherheitInWindowsCommunicationFoundation.mspx

Zwar nicht WCF-spezifisch aber für das generelle Verständnis von Windows-Sicherheits-Integration in .NET sehr nützlich:
http://www.microsoft.com/germany/msdn/library/security/IntegrationInWindowsSecurityMitNET20Teil1.mspx
http://www.microsoft.com/germany/msdn/library/security/IntegrationInWindowsSecurityMitNET20Teil2.mspx
http://www.microsoft.com/germany/msdn/library/security/IntegrationInWindowsSecurityMitNET20Teil3.mspx

Du kannst auch Anonymes Anmelden zulassen (Siehe Screenshot).

M
matthias@friehe.eu Themenstarter:in
9 Beiträge seit 2007
vor 16 Jahren

Herzlichen Dank erstmal, Rainbird, dass Du Dich um mein Problem kümmerst.

Leider funktioniert aber das Beispiel so nicht. Ich habe jetzt also wie beschrieben die entsprechende Konfiguration ausgeführt (mit dem Tool), hier der Code, der app.config, der so erzeugt wurde:


<configuration>
  <system.serviceModel>
    <behaviors>
      <serviceBehaviors>
        <behavior name="NewBehavior">
          <serviceCredentials>
            <windowsAuthentication allowAnonymousLogons="true" />
          </serviceCredentials>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <services>
      <service behaviorConfiguration="NewBehavior" name="WCF03.Service">
        <endpoint address="net.tcp://localhost:1234/Volectra/WCF03" binding="netTcpBinding"
          name="Service" contract="WCF03.IService" />
      </service>
    </services>
  </system.serviceModel>
</configuration>

Trotzdem bleibt es beim Client-Laptop bei einer Fehlermeldung, diesmal: "The server has rejected the client credentials."

Übrigens habe ich auch das MS-Beipiel mit Http gemacht. Http-Bindungen funktionieren allerdings bei mir grundsätzlich nicht, mit der Begründung, dort würde eine entsprechende Berechtigung fehlen. Für mein Programm ist mir außerdem die NetTcpBinding wichtig, weil sich hier Callback-Verträge leichter implementieren lassen.

Eigentlich dachte ich, man könnte die Authentifizierung ausschalten:


<bindings>
      <netTcpBinding>
        <binding name="ServiceConfig">
          <security mode="Message">
            <message clientCredentialType="None" algorithmSuite="Basic256"/>
          </security>
        </binding>
      </netTcpBinding>
    </bindings>

Entsprechend müsste dann beim Endpoint natürlich das Attribute "bindingConfiguration" gesetzt sein. Bei diesem Code beschwert er sich aber schon beim Starten des Servers:

Der ChannelDispatcher bei net.tcp://localhost:1234/Volectra/WCF03 mit den Verträgen WCF03.IService kann seinen IChannelListener nicht öffnen.

Das ist übrigens unabhängig davon, welchen Wert ich bei clientCredentialType setze, ob nun None oder UserName etc. Nur Windows funktioniert.

Gruß Matthias

Matthias Friehe

3.728 Beiträge seit 2005
vor 16 Jahren
Windows-Authentifizierung mit WCF

Hallo Matthias,

ich habe ein kleines Beispiel mit NetTcpBinding und Windows-Authentifizierung geschrieben. Das hat auf Anhieb funktioniert. Die Projektmappe findest Du im Anhang als ZIP-Archiv.

Meine Testumgebung:

Ich habe zwei physikalische Computer (also keine VMs etc.) verwendet (ein Standard-PC und ein Notebook) die über Ethernet verbunden sind. Serverseitig ist Windows Vista Ultimate und auf dem Notebook (Client) Windows XP SP2 mit .NET Framework 3.0 installiert. Die Computer sind nicht in einer Domäne und werden im Arbeitsgruppen-Modus betrieben. Auf den Client wurden nur die Binaries von Rainbird.Examples.WCF.Client kopiert und in der App.Config der Client-Windows-Anwendung wurde die Dienstadresse von "net.tcp://localhost:14000/HelloWorldService" in "net.tcp://MAMMOTH:14000/HelloWorldService" (MAMMOTH ist der Server-Computer) geändert.

Ergebnis:

Die Windows-Authentifizierung funktioniert einwandfrei. Wenn ich mich am Client mit einem Benutzer anmelde, der auf dem Server-Computer nicht mit dem selben Namen und identischem Passwort angelegt ist, erhalte ich eine Ausnahme, dass die Anmeldung fehlgeschlagen ist. Verwende ich aber am Client einen Benutzer, der auf dem Server auch vorhanden ist und dessen Passwort identisch ist, klappt die Authentifizierung.
Genau so soll sich die Windows-Authentifizierung ja uch verhalten. Unbekannte Benutzer abweisen und bekannte Benutzer authentifizieren.

Wenn mein kleines Beispiel bei Dir nicht funktioniert, liegt es nahe, dass die verwenden Benutzer auf Client- und Server-Computer nicht identisch angelegt sind.

M
matthias@friehe.eu Themenstarter:in
9 Beiträge seit 2007
vor 16 Jahren

Hallo Rainbird,

herzlichen Dank erstmal für das Beispielprojekt. Funktioniert auch ganz gut. Ein Problem, was bei mir wohl immer wieder aufgetreten ist, ist, dass die Authentifizierung offenbar grundsätzlich nicht mit Benutzerkonten ohne Passwort umgehen kann. Dann wird die Authentifizierung offenbar grundsätzlich verweigert. Nun gut, damit kann ich aber eigentlich leben.

Trotzdem würde ich in meinen Programmen gerne wenigstens die Möglichkeit anbieten, dass auf einen WCF-Service zugegriffen wird, ohne dass eine Windows-Authentifizierung erfolgt (selbstverständlich eine Sicherheitslücke, aber das ganze muss auch immer unter dem Aspekt gesehen werden, welche Sicherheit sich wirklich lohnt - bzw. wieviel Aufwand sich für einen Hacker lohnt). Natürlich könnte ich hier einfach den Security-Mode auf "None" setzen. Das hätte aber zur Folge, dass die Daten nicht einmal mehr verschlüsselt gesendet würden.
Ich hätte daher zumindest die Möglichkeit für ein Anonymous-Login. Zwar hast Du in Deiner app.config ein Service-Behavior, dass anonyme Anmeldungen zulässt. Doch habe ich bisher noch nicht ganz herausgefunden, wie man jetzt damit umgehen soll. Muss man am Client irgendetwas ändern, damit er sich anonym anmeldet und der Server das dann auch wirklich akzeptiert?

Oder bleibt mir für anonyme Anmeldungen wirklich nur SecurityMode "None"?

Gruß: Matthias Friehe

Matthias Friehe

3.728 Beiträge seit 2005
vor 16 Jahren
Endpunkt-Konfiguration

Ich habe es auf die schnelle zwar auch nicht hinbekommen, dass anonyme Anmeldungen zulässt, aber ich denke, dass es über ein Endpoint-Behavior machbar sein müsste. Dort lässt sich nämlich Anonym als Impersonierungsart einstellen (Siehe Screenshot im Anhang). Bei meinen Projekten hatte ich bisher immer das Glück, dass es sich um unternehmensweite Anwendungen handelte, auf die auch nur bekannte Mitarbeiter des Unternehmens (also solche, die im Active Directory einen Benutzer haben) zugreifen dürfen.

Irgendwelche Creditials (Benutzername, passwort, etc.) braucht das System auf jede Fall, wenn eine Verschlüsslung stattfinden soll. Bei anonymer Anmeldung gibt es natürlich keine Credentials. Trotzdem sollte es mit Windows-Authentifizierung machbar sein, da Windows einen Standardbenutzer (ANONYMOUS-ANMELDUNG) hat, der automatisch für anonyme Sachen eingesetzt wird. Damit wäre wieder ein Benutzer da und damit auch Credentials die zur Verschlüsselung herangezogen werden könnten. Eine andere Frage ist, ob die Verschlüsslung damit sicher ist, da die Credentials des Benutzers ANONYMOUS-ANMELDUNG vielleicht bei allen Windows-Computern gleich sind.

Alternativ könntest Du natürlich auf die Windows-Authentifizierung verzichten und die Verschlüsselung auf Transport-Ebene mit X509-Zertifikaten realisieren. Das wird von WCF ebenfalls unterstützt. Dir geht es ja nur um die Verschlüsselung der Pakete und nicht um die Identität des Clients. Du könntest ein entsprechendes Zertifikat mit dem Client ausliefern und dieses Zertifikat zur Verschlüssung der WCF-Kommunikation heranziehen.

100 Beiträge seit 2006
vor 16 Jahren

Für den Fall, dass der derselbe Benutzer auf den beiden PCs unterschiedliche Passwörter hat. Dann lasse ich das Passwort am Client einlesen und würde es gerne zur automatischen Windowszertifizierung verwenden.

Nur wie setze ich die Windows-Credentials. Die Eigenschaft ClientCredentials in der Proxy-Klasse bietet ja jede Menge Möglichkeiten zum Setzen von Namen/Passwörtern.

Die offensichtlichste Variante hat zumindest bei mir nicht funktioniert, der Client wurde trotzdem abgewiesen.
Genauergesagt funktioniert es für den angemeldeten Benutzer, wenn dieser ein anderes Passwort besitzt. Möchte man sich jedoch mit einem Benutzer anmelden, der auf dem Klient-PC nicht läuft, dann ist dies nicht möglich.

      

proxyToServer.ClientCredentials.Windows.ClientCredential.UserName = dlg.UserName;
proxyToServer.ClientCredentials.Windows.ClientCredential.Password = dlg.Password ;


Ist dies dann überhaupt prinzipiell richtig oder muß ich dazu unter
Bindings -> MessageClientCredentialType von _Windows _auf UserName wechseln?

3.728 Beiträge seit 2005
vor 16 Jahren
Verschiedene Passwörter

Windows-Authentifizierung solltest Du nur in Verbindung mit Domänen (Active Directory) einsetzen.