2014-06-07 9 views
11

Ich habe ein Problem bei der Verbindung mit meinem WCF-Dienst mit clientCredentialType="UserName".WCF-Authentifizierung - Beim Überprüfen der Sicherheit für die Nachricht ist ein Fehler aufgetreten

Wenn ich den Code ausführen unten ich einen Fehler

FaultException erhalten: Ein Fehler trat auf, wenn für die Nachrichtensicherheit zu überprüfen.

Beim Herumspielen mit einigen der Bindungswerte bekomme ich auch Access is denied..

Fiddler sagt, es gibt keine Autorisierung Header und ich kann nicht den Benutzernamen oder das Passwort in der Anfrage auch nicht finden.

Hier sind Auszüge aus meiner config:

<system.webServer> 
    <modules runAllManagedModulesForAllRequests="true"/> 
    </system.webServer> 
    <services> 
     <service name="InventoryServices.MobileAPI" behaviorConfiguration="customBehaviour"> 
     <endpoint address="" 
        binding="basicHttpBinding" 
        bindingConfiguration="secureHttpBinding" 
        contract="InventoryServices.IMobileAPI"/> 

     <endpoint address="mex" 
        binding="mexHttpsBinding" 
        contract="IMetadataExchange" /> 
     </service> 
    </services> 
    <behaviors> 
     <serviceBehaviors> 
     <behavior name="customBehaviour"> 
      <serviceSecurityAudit auditLogLocation="Application" serviceAuthorizationAuditLevel="Failure" messageAuthenticationAuditLevel="Failure" suppressAuditFailure="true" /> 
      <!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment --> 
      <serviceMetadata httpsGetEnabled="true"/> 
      <!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information --> 
      <serviceDebug includeExceptionDetailInFaults="true"/> 
      <serviceCredentials> 
      <userNameAuthentication userNamePasswordValidationMode="Custom" 
       customUserNamePasswordValidatorType="InventoryLibrary.Helpers.UserAuthentication,InventoryLibrary"/> 
      </serviceCredentials> 
     </behavior> 
     </serviceBehaviors> 
    </behaviors> 
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" /> 
    <bindings> 
     <basicHttpBinding> 
     <binding name="secureHttpBinding"> 
      <security mode="TransportWithMessageCredential"> 
      <transport clientCredentialType="Basic" proxyCredentialType="Basic" realm="MyRealm"/> 
      <message clientCredentialType="UserName" algorithmSuite="Default" /> 
      </security> 
     </binding> 
     </basicHttpBinding> 
    </bindings> 

Mein Benutzername/Passwort-Validator sieht so aus:

public class UserAuthentication : UserNamePasswordValidator { 
     public override void Validate(string userName, string password) { 

      EntitiesContext db = new EntitiesContext(); 
      db.Logs.Add(new DomainModels.Log() { 
       DateLogged = DateTime.Now, 
       Message = "hit auth", 
       Type = DomainModels.LogType.Info 
      }); 
      db.SaveChanges(); 

      try { 

       if (userName == "test" && password == "test123") { 
        Console.WriteLine("Authentic User"); 
       } 
      } 
      catch (Exception ex) { 
       throw new FaultException("Unknown Username or Incorrect Password"); 
      } 
     } 
    } 

ich dies als einen einfachen Test auf meinem Service haben:

[OperationContract] 
[XmlSerializerFormat] 
void Test(); 

[PrincipalPermission(SecurityAction.Demand, Name = "test")] 
public void Test() { 

} 

Ich habe ein selbstsigniertes SSL-Zertifikat auf meinem Server und kann auf meine Dienste/Metadaten zugreifen.

Dann auf den Dienst mit diesem Code habe ich einen Dienstverweis in einer Konsolenanwendung, hinzugefügt und versuchen, unten zu verbinden:

class Program { 
    static void Main(string[] args) { 

     Stuff.InitiateSSLTrust(); 

     BasicHttpBinding binding = new BasicHttpBinding(); 
     binding.Security.Mode = BasicHttpSecurityMode.Transport; 
     binding.Security.Transport.Realm = "MyRealm"; 

     ServiceReference1.MobileAPIClient serviceProxy = new ServiceReference1.MobileAPIClient(binding, new EndpointAddress("https://xx.xx.xx.xx/InventoryServices.MobileApi.svc")); 

     serviceProxy.ClientCredentials.UserName.UserName = "test"; 
     serviceProxy.ClientCredentials.UserName.Password = "test123"; 

     try { 

      var a = serviceProxy.Login("a", "b"); 
     } 
     catch (Exception ex) { 
      var ex2 = ex; 
     } 
    } 
} 

public class Stuff { 
    public static void InitiateSSLTrust() { 
     try { 
      //Change SSL checks so that all checks pass 
      ServicePointManager.ServerCertificateValidationCallback = 
       new RemoteCertificateValidationCallback(
        delegate { return true; } 
       ); 
     } 
     catch (Exception ex) { 
     } 
    } 
} 

ich die Ereignisanzeige auf dem Server überprüft haben und dieser Fehler wird mit Jede Anforderung:

MessageSecurityException: Der Sicherheitsprozessor konnte in der Nachricht keinen Sicherheitsheader finden. Dies kann daran liegen, dass es sich bei der Nachricht um einen ungesicherten Fehler handelt oder weil zwischen den kommunizierenden Parteien eine Bindungsabweichung besteht. Dies kann auftreten, wenn der Dienst für die Sicherheit konfiguriert ist und der Client keine Sicherheit verwendet.

+0

Was macht Ihr Client-Web/app.config aussehen? Es sollte einige Werte für das darin enthaltene Cert für die Nachrichtensicherheitsbindung geben. Haben Sie auch Berechtigungen für den Zertifikatsspeicher auf dem Server-Setup korrekt? (Ich denke, es ist in der Regel das "My" cert-Geschäft.Das hört sich sehr ähnlich zu Problemen an, die ich in der Vergangenheit hatte. Ich versuche mich daran zu erinnern, während ich tippe. Es könnte sich in den nächsten 10 bilden, während ich darüber nachdenke. – brumScouse

+0

Leider konnte ich nicht sehen, dass die Serverbindung TransportWithMessage war. Ich habe jedoch bemerkt, dass Ihr Client nur eine Transportbindung verwendet hat, die nicht die gleiche Bindung wie der Server hat? – brumScouse

Antwort

8

Sie sind unter Angabe der Client-Seite BasicHttpSecurityMode.Transport zu verwenden, während der Service BasicHttpSecurityMode.TransportWithMessageCredential erwartet wird. Dies ist ein Problem, da der Dienst im SOAP-Nachrichtenheader nach den Clientanmeldeinformationen sucht und der Client sie nicht mit der auf diese Weise konfigurierten Bindung sendet.

Aus diesem Grund ist das Benutzername/Passwort-Paar nicht im Nachrichtenkopf vorhanden, wie Sie gerade erleben. Der Event Viewer war also richtig, dass zwischen den kommunizierenden Parteien eine verbindliche Inkongruenz bestand.

Setzen Sie auch die ClientCredentialType auf dem Client BasicHttpMessageCredentialType.UserName für Message Level-Sicherheit. Standardmäßig verwendet BasicHttpBindingNone, die anonyme Clients sind.

Hier ist ein Code-Snippet die obigen Änderungen beschreibt:

var basicHttpBinding = new BasicHttpBinding(
           BasicHttpSecurityMode.TransportWithMessageCredential); 
basicHttpBinding.Security.Message.ClientCredentialType = 
            BasicHttpMessageCredentialType.UserName; 
+0

Technisch hast du recht, also gebe ich die Antwort. Ich verwende Xamarin und die zugrunde liegenden Klassen unterstützen leider nicht TransportWithMessageCredential. – Smithy

Verwandte Themen