2014-06-07 13 views
11

Mam problem z połączeniem się z moją usługą WCF pod numerem clientCredentialType="UserName".Uwierzytelnianie WCF - Wystąpił błąd podczas sprawdzania zabezpieczeń wiadomości

Kiedy uruchomić poniższy kod pojawia się błąd

FaultException: Wystąpił błąd podczas weryfikacji bezpieczeństwa dla wiadomości.

Podczas gry z niektórymi wartościami wiążącymi otrzymuję również Access is denied..

Fiddler mówi, że nie ma nagłówka autoryzacji i nie mogę znaleźć nazwy użytkownika lub hasła w żądaniu.

Oto fragmenty z mojego 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> 

Mój login/hasło walidator wygląda tak:

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"); 
      } 
     } 
    } 

mam to za pomocą prostego testu na moją usługę:

[OperationContract] 
[XmlSerializerFormat] 
void Test(); 

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

} 

Posiadam własny podpisany certyfikat SSL na moim serwerze i mogę uzyskać dostęp do mojej usługi/metadanych.

Potem dodałem odniesienie usług w aplikacji konsoli i próbować połączyć się z usługą z tego kodu poniżej:

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) { 
     } 
    } 
} 

Sprawdziłem Podglądu zdarzeń na serwerze i pojawia się ten błąd z każde żądanie:

MessageSecurityException: Procesor zabezpieczeń nie mógł znaleźć nagłówka zabezpieczeń w wiadomości. Może to być spowodowane tym, że wiadomość jest niezabezpieczoną usterką lub z powodu niedopasowania powiązania między komunikującymi się stronami. Może się tak zdarzyć, jeśli usługa jest skonfigurowana pod kątem bezpieczeństwa, a klient nie korzysta z zabezpieczeń.

+0

Co Web klient/app.config wygląda? Powinno być tam kilka wartości dla certyfikatu dla powiązania zabezpieczenia wiadomości. Czy masz poprawnie ustawione uprawnienia do magazynu certyfikatów na serwerze? (Myślę, że jest to zazwyczaj "Mój" sklep z certyfikatami.Brzmi to bardzo podobnie do problemów, które miałem w przeszłości i jest brzydkim gwoździem. Próbuję to przypomnieć, kiedy piszę. Może powstać w ciągu następnych 10, podczas gdy ja o tym myślę. – brumScouse

+0

Niestety nie widziałem, że powiązanie serwera było TransportWithMessage. Zauważyłem jednak, że twój klient korzystał tylko z powiązania transportu, które nie ma takiego samego powiązania jak serwer? – brumScouse

Odpowiedz

8

Podajesz stronę klienta, aby używać BasicHttpSecurityMode.Transport, podczas gdy usługa oczekuje BasicHttpSecurityMode.TransportWithMessageCredential. Jest to problem, ponieważ usługa szuka poświadczeń klienta w nagłówku wiadomości SOAP, a klient nie wysyła ich z powiązaniem skonfigurowanym w ten sposób.

Z tego powodu para nazwa użytkownika/hasło nie jest obecna w nagłówku wiadomości, tak jak jesteś świadkiem. Tak więc przeglądarka zdarzeń była poprawna, ponieważ istniała niedopasowanie między łączącymi się stronami.

Ustaw również ClientCredentialType na kliencie na BasicHttpMessageCredentialType.UserName dla poziomu bezpieczeństwa na poziomie Message. Domyślnie BasicHttpBinding używa None, które są anonimowymi klientami.

Oto fragment kodu opisujące powyższe zmiany:

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

Technicznie masz rację, więc daję odpowiedź. Używam Xamarin, a podstawowe klasy nie obsługują TransportWithMessageCredential niestety. – Smithy

Powiązane problemy