2010-06-23 15 views
13

Mam klienta WCF łączącego się z usługą sieciową Axis2 opartą na języku Java (poza kontrolą). Niedługo zostanie zastosowany WS-Security i muszę naprawić klienta .NET. Jednak staram się zapewnić prawidłowe uwierzytelnianie. Jestem świadomy, że GPW 3.0 może to ułatwić, ale wolałbym nie powracać do przestarzałej technologii.Błąd klienta WCF zużywającego usługę WWW osi 2 z WS-Security UsernameToken PasswordDigest schemat uwierzytelniania

Podobne problemy (nierozwiązane) obejmują: this, this i this.

Komunikat SOAP powinny wyglądać następująco:

<wsse:UsernameToken> 
    <wsse:Username><!-- Removed--></wsse:Username> 
    <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest"><!-- Removed--></wsse:Password> 
    <wsse:Nonce><!-- Removed--></wsse:Nonce> 
    <wssu:Created>2010-05-28T12:50:33.675+01:00</wssu:Created> 
</wsse:UsernameToken> 

jednak kopalnia wygląda następująco:

<s:Header> 
<h:Security xmlns:h="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"></h:Security> 
<o:Security s:mustUnderstand="1" xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"> 
<u:Timestamp u:Id="_0"> 
<u:Created>2010-06-23T10:31:23.441Z</u:Created> 
<u:Expires>2010-06-23T10:36:23.441Z</u:Expires> 
</u:Timestamp> 
<o:UsernameToken u:Id="uuid-d329b3b2-6a1f-4882-aea6-ec6b8a492de7-1"> 
<o:Username> 
<!-- Removed--> 
</o:Username> 
<o:Password> 
<!-- Removed--> 
</o:Password> 
</o:UsernameToken> 
</o:Security> 
</s:Header> 

Mój klient wygląda następująco: PS: Zauważ, że wymagany jest parametr SecurityHeaderType. Co to jest?

public MyAck SendRequest(MyRequest request) 
{ 
RemoteServicePortTypeClient client = new RemoteServicePortTypeClient(); 

client.ClientCredentials.UserName.UserName = "JAY"; 
client.ClientCredentials.UserName.Password = "AND"; 

    // what is the difference between the two different Credential types?? 
    //client.ClientCredentials.HttpDigest.ClientCredential.UserName = "SILENT"; 
    //client.ClientCredentials.HttpDigest.ClientCredential.Password = "BOB"; 

SecurityHeaderType sht = new SecurityHeaderType(); 
//sht.Any = ???; // How do I use this??? 
//sht.AnyAttr = ???; // How do I use this ??? 

// SecurityHeaderType is a required parameter 
return client.RemoteServiceOperation_Provider(sht, request); 
} 

Aktualny wiązania jest następujący:

<basicHttpBinding> 
    <binding name="CustomBinding"> 
     <security mode="TransportWithMessageCredential"> 
      <transport clientCredentialType="None"></transport> 
      <message clientCredentialType="UserName" /> 
     </security> 
    </binding> 
</basicHttpBinding> 

Próbowałem zostały również niestandardowe wiążąca i ma podobny błąd:

<customBinding> 
    <binding name="myCustomBindingConfig"> 
    <security authenticationMode="UserNameOverTransport" 
     messageSecurityVersion="WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11" 
     securityHeaderLayout="Strict" 
     includeTimestamp="false"></security> 
    <textMessageEncoding messageVersion="Soap11"></textMessageEncoding> 
    <httpsTransport /> 
    </binding> 
</customBinding> 

I punkt końcowy (adres oczywiście zmieniło ...):

<endpoint address="https://www.somecompany.com/uat/axis/services/RemoteServiceOperation_Provider" 
     binding="basicHttpBinding" bindingConfiguration="CustomBinding" 
     contract="RemoteService.RemoteServicePortType" 
     name="RemoteService_UAT" /> 

C ustom błędu, który jest zwracany jest następujący:

<ErrorID>0</ErrorID> 
<ErrorType>UNEXPECTED</ErrorType> 
<ErrorDescription><![CDATA[Array index out of range: 0]]></ErrorDescription> 
<TimeStamp>2010-06-23T13:28:54Z</TimeStamp> 

Czytałem wiele o niestandardowych nagłówków, żetonów, wiązań i mój mózg jest całkowicie zdezorientowany. Czy ktokolwiek może zaproponować krok po kroku proces wysyłania wiadomości we właściwym formacie?

This wydaje się być krokiem naprzód dla WCF, używając tokenów niestandardowych, ale w jaki sposób należy zastosować skrót i wymaganie w razie potrzeby?

Każda pomoc mile widziane.

AKTUALIZACJA

Odniosłem ograniczony sukces. Użyłem biblioteki Microsoft.Web.Services3 do utworzenia UsernameToken z poprawnym podsumowaniem.I już wtedy stworzył własną niestandardową zachowanie iw BeforeSendRequest metody Zrobiłem następujące wstrzyknąć nagłówka:

object IClientMessageInspector.BeforeSendRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel) 
{ 
    UsernameToken ut = new UsernameToken("USERNAME", "PASSWORD", PasswordOption.SendHashed); 

    XmlElement securityElement = ut.GetXml(new XmlDocument()); 

    MessageHeader myHeader = MessageHeader.CreateHeader("Security", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", securityElement, false); 
    request.Headers.Add(myHeader); 

    return Convert.DBNull; 
} 

dodam zachowanie tak:

CustomBehavior behavior = new CustomBehavior("USERNAME", "PASSWORD"); 
client.Endpoint.Behaviors.Add(behavior); 

mogę teraz zobaczyć nagłówki dzieje po drugiej stronie:

<s:Header> 
<Security xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"> 
<wsse:UsernameToken wsu:Id="SecurityToken-c6aeb72d-4d36-4650-abd3-33cc66caac6d" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"> 
<wsse:Username> 
<!-- Removed--> 
</wsse:Username> 
<wsse:Password> 
<!-- Removed--> 
</wsse:Password> 
<wsse:Nonce> 
<!-- Removed--> 
</wsse:Nonce> 
<wsu:Created>2010-06-24T16:23:58Z</wsu:Created> 
</wsse:UsernameToken> 
</Security> 
</s:Header> 

Ale ja dostaję błąd:

<soapenv:Fault> 
<faultcode xmlns="">soapenv:Server</faultcode> 
<faultstring xmlns="">WSDoAllReceiver: security processing failed; nested exception is: 
    org.apache.ws.security.WSSecurityException: General security error (WSSecurityEngine: Callback supplied no password for: USERNAME)</faultstring> 
<faultactor xmlns="">urn:Remote_Provider</faultactor> 
<detail xmlns=""> 
<CUSTOMError xmlns="urn:customerror:v01"> 
<ErrorID>0</ErrorID> 
<ErrorType>UNEXPECTED</ErrorType> 
<ErrorDescription><![CDATA[WSDoAllReceiver: security processing failed; nested exception is: 
    org.apache.ws.security.WSSecurityException: General security error (WSSecurityEngine: Callback supplied no password for: USERNAME)]]></ErrorDescription> 
<TimeStamp>2010-06-24T17:23:59Z</TimeStamp> 
</CUSTOMError> 
</detail> 
</soapenv:Fault> 

Nie wydaje się być brakuje Rodzaj atrybut na węźle hasłem:

Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest" 

Jednak nie jestem pewien, czy śledzenie bezpieczeństwo i ustawienia logowania są koc usuwanie atrybutów i treści tych węzłów. Próbowałem użyć ustawienia logKnownPii w dzienniku diagnostycznym, ale informacje o zabezpieczeniach pozostają zasłonięte. Jakieś pomysły na ten temat?

Odpowiedz

5

Mogę potwierdzić, że aktualizacja z moim pytaniu faktycznie działa:

object IClientMessageInspector.BeforeSendRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel) 
{ 
    UsernameToken ut = new UsernameToken("USERNAME", "PASSWORD", PasswordOption.SendHashed); 

    XmlElement securityElement = ut.GetXml(new XmlDocument()); 

    MessageHeader myHeader = MessageHeader.CreateHeader("Security", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", securityElement, false); 
    request.Headers.Add(myHeader); 

    return Convert.DBNull; 
} 

a klient:

CustomBehavior behavior = new CustomBehavior("USERNAME", "PASSWORD"); 
client.Endpoint.Behaviors.Add(behavior); 

Komunikat o błędzie niepowiązane. Nagłówek bezpieczeństwa działa z bardzo prostego basicHttpBinding:

<basicHttpBinding> 
    <binding name="BasicSOAPBinding"> 
     <security mode="Transport" /> 
    </binding> 
</basicHttpBinding> 

przykładowy kod w akcji można znaleźć na moim blogu: http://benpowell.org/supporting-the-ws-i-basic-profile-password-digest-in-a-wcf-client-proxy/

+0

Niestety, to wygląda jak coś, co może zniknąć w przyszłości. Specyfikacja ONVIF mówi teraz: "Usługi zdefiniowane w tym standardzie są chronione przy użyciu uwierzytelniania skrótu zgodnego z do [RFC 2617], z wyjątkiem starszych urządzeń obsługujących [WS-UsernameToken]." źródło: https://www.onvif.org/specs/core/ONVIF-Core-Specification-v1706.pdf 5.12.1 – cube45

1

Ostatnio miałem podobny problem i zrezygnowałem z poszukiwania rozwiązania innego niż na GPW. Po kilku dniach wyciągania włosów skończyłem pobieranie pakietu SDK WSE 3.0, generowanie klasy proxy za pomocą narzędzia WseWsdl3.exe i tworzenie nowej polityki dla UsernameToken. Byłem uruchomiony przez 15 minut. Następujące obecnie działa dla mnie.

RemoteService service = new RemoteService(); //generated class 

UsernameToken token = new UsernameToken(username, password, PasswordOption.SendPlainText); 
Policy policy = new Policy(); 
policy.Assertions.Add(new UsernameOverTransportAssertion()); 

service.SetClientCredential(token); 
service.SetPolicy(policy); 

var result = service.MethodCall(); 
2

To pytanie jest dobrze napisany - wielkie dzięki. W odniesieniu do komentarza "Jak używać tego" @ Junto okazuje się, że do dodania nagłówka można użyć parametru SecurityHeader w metodzie serwisowej. Podam przykład poniżej. Wierzę, że to, co się dzieje, to, że narzędzie SvcUtil.exe blokuje się przy próbie odczytu WSD * DTD. Nie jest to oczywiste, gdy używasz kreatora "Dodaj usługę odniesienia". Ale jest to bardzo oczywiste, gdy uruchamiasz svcutil.exe z wiersza poleceń. Ponieważ svcutil.exe nie odczytuje WSD * DTD, obiekt SecurityHeader nie jest dobrze rozwinięty. Ale Microsoft daje ci dostęp do własności. Any. Możesz serializować klasę UsernameToken bezpośrednio do właściwości .Any, a twój nagłówek zostanie dodany do wiadomości. Jeszcze raz dziękuję za to doskonałe pytanie.

Jak używać parametru SecurityHeader aby dodać nagłówek UsernameToken zabezpieczeń:

Wymagane narzędzia:

Fiddler2 (or similar) -- you really can't figure any of this out without inspecting the http headers.

wymaganego odniesienia: wywołanie usługi

Microsoft.Web.Services3.dll -- you can reference this 2.0 framework assembly from your 4.0 assembly 

WCF:

// Initialization of the service... 
_service = new MyService("MyEndpoint", RemoteUri); 

// etc.  

// Calling the service -- note call to GetSecurityHeader() 
_service.ServiceAction(GetSecurityHeader(), "myParam1"); 

// etc. 

/// <summary> 
/// Construct the WSE 3.0 Security Header 
/// </summary> 
private SecurityHeader GetSecurityHeader() 
{ 
    SecurityHeader h = new SecurityHeader(); 
    UsernameToken t = new UsernameToken(RemoteLogin, RemotePassword, PasswordOption.SendPlainText); 
    h.Any = new XmlElement[1]; 
    h.Any[0] = t.GetXml(new XmlDocument()); 
    return h; 
} 

App.config:

<system.serviceModel> 
    <bindings> 
     <basicHttpBinding> 
     <binding name="MyBinding" closeTimeout="00:01:00" openTimeout="00:01:00" 
      receiveTimeout="00:10:00" sendTimeout="00:10:00" allowCookies="false" 
      bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard" 
      maxBufferSize="1048576" maxBufferPoolSize="524288" maxReceivedMessageSize="1048576" 
      messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered" 
      useDefaultWebProxy="true"> 
      <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" 
       maxBytesPerRead="4096" maxNameTableCharCount="16384" /> 
      <security mode="Transport"> 
      <transport clientCredentialType="None" proxyCredentialType="None" 
       realm="" /> 
      <message clientCredentialType="UserName" algorithmSuite="Default" /> 
      </security> 
     </binding> 
     </basicHttpBinding> 
    </bindings> 
    <client> 
     <endpoint address="http://myservice.com/service.asmx" 
      binding="basicHttpBinding" bindingConfiguration="MyBinding"    contract="MyContract" 
      name="MyEndpoint" /> 
    </client> 
    </system.serviceModel> 
+0

GetSecurityHeader() zrobił to dla mnie, dzięki! – Robotron