2010-08-23 35 views
6

我正在從WCF客戶端調用非WCF服務。 WCF客戶端包含設置爲「1」的「MustUnderstand」標頭屬性。下面是一個典型的SOAP請求:如何使用ClientInspector修改WCF消息頭的MustUnderstand

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"> 
<s:Header> 
    <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-08-23T20:48:52.680Z</u:Created> 
      <u:Expires>2010-08-23T20:53:52.680Z</u:Expires> 
     </u:Timestamp> 
     <o:UsernameToken u:Id="uuid-72ea0c0a-43aa-43b2-bed7-c2da13624105-1"> 
      <o:Username>blablabla</o:Username> 
      <o:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">blablabla</o:Password> 
     </o:UsernameToken> 
    </o:Security> 
</s:Header> 
<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
    <HeartbeatRequest xmlns="http://removed"> 
     <DateTime xmlns="">8/23/2010 4:48:51 PM</DateTime> 
     <Message xmlns="">123</Message> 
    </HeartbeatRequest> 
</s:Body> 

現在,這裏是我回來這個響應。

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 
<soapenv:Header> 
    <Misunderstood qname="o:Security" xmlns="http://www.w3.org/2002/06/soap-faults" xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" /> 
</soapenv:Header> 
<soapenv:Body> 
    <soapenv:Fault xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"> 
     <faultcode>soapenv:MustUnderstand</faultcode> 
     <faultstring>WSWS3173E: Error: Did not understand &quot;MustUnderstand&quot; header(s):{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd}Security</faultstring> 
    </soapenv:Fault> 
</soapenv:Body> 

備註的mustUnderstand不被人理解的部分。

此服務的所有者已經表明它們允許具有WSSE命名空間前綴但實際上不在XSD中的元素,並執行一些其他處理來阻止它們接受MustUnderstand =「1」,因此我必須找到一種方法來發送MustUnderstand =「0」的消息。

我試圖在使用MessageHeader屬性的代理客戶端的MessageContract中對此進行更改,但這並沒有幫助。

接下來,我實現了一個自定義的客戶端消息檢查器。我創建了每MSDN類的自定義行爲擴展元素和IEndpointBehavior,這些都是微不足道的,但這裏的完整性:

public class ExClientBehavior : IEndpointBehavior 
{ 
    #region IEndpointBehavior Members 

    public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters) 
    { 
     // no op 
    } 

    public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime) 
    { 
     ExInspector inspector = new ExInspector(); 
     clientRuntime.MessageInspectors.Add(inspector); 
    } 

    public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) 
    { 
     // no op 
    } 

    public void Validate(ServiceEndpoint endpoint) 
    { 
     // no op 
    } 

    #endregion 
} 


    public class ExClientBehaviorExtensionElement : BehaviorExtensionElement 
{ 
    public override Type BehaviorType 
    { 
     get { return typeof(ExClientBehavior); } 
    } 

    protected override object CreateBehavior() 
    { 
     return new ExClientBehavior(); 
    } 
} 

現在的實際檢查:

public class ExInspector : IClientMessageInspector 
{ 

    #region IClientMessageInspector Members 

    public void AfterReceiveReply(ref Message reply, object correlationState) 
    { 
     // no op 
     return; 
    } 

    public object BeforeSendRequest(ref Message request, IClientChannel channel) 
    { 
     MessageBuffer buffer = request.CreateBufferedCopy(int.MaxValue); 

     Message newMessage = buffer.CreateMessage(); 

     newMessage.Headers.RemoveAt(0); 

     newMessage.Headers.Add(MessageHeader.CreateHeader 
      (
       request.Headers[0].Name, 
       request.Headers[0].Namespace, 
       string.Empty, 
       false, 
       string.Empty, 
       request.Headers[0].Relay 
      ) 
     ); 

     request = newMessage; 

     return null; 
    } 

    #endregion 
} 

正如你看到的,我創建通過緩衝副本創建一個新請求,然後刪除安全頭(只有一個頭),並添加一個MustUnderstand設置爲false的新頭(爲什麼要這麼做?MessageHeader.MustUnderstand是隻讀的)。我在這個方法中設置了一個斷點,事實上,新的頭文件被添加,newMessage被寫回請求,並且newMessage.Headers [0] .MustUnderstand以及request.Headers [0] .MustUnderstand在此方法結束。

但是,發送到服務的消息仍然包含標頭上的MustUnderstand =「1」!!!!!

下面是包括上述行爲的app.config:

<configuration> 
<system.serviceModel> 
    <bindings> 
     <basicHttpBinding> 
      <binding name="WebServiceSOAP" closeTimeout="00:01:00" openTimeout="00:01:00" 
        receiveTimeout="00:10:00" sendTimeout="00:01:00" allowCookies="false" 
        bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard" 
        maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536" 
        messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered" 
        useDefaultWebProxy="true"> 
       <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384" /> 
       <security mode="TransportWithMessageCredential"> 
        <transport clientCredentialType="Basic" proxyCredentialType="None" realm="" /> 
        <message clientCredentialType="UserName" algorithmSuite="Default" /> 
       </security> 
      </binding> 
     </basicHttpBinding> 
    </bindings> 
    <client> 
     <endpoint 
       address="https://removed" 
       behaviorConfiguration="ovrExClientBehavior" 
       binding="basicHttpBinding" 
       bindingConfiguration="WebServiceSOAP" 
       contract="EWebService.EWebService" 
       name="WebServiceSOAP" /> 
    </client> 
    <extensions> 
     <behaviorExtensions> 
      <add name="exClientBehavior" type="ExMessageInspector.ExClientBehaviorExtensionElement, ExMessageInspector, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/> 
     </behaviorExtensions> 
    </extensions> 
    <behaviors> 
     <endpointBehaviors> 
      <behavior name="ovrExClientBehavior"> 
       <exClientBehavior /> 
      </behavior> 
     </endpointBehaviors> 
    </behaviors> 
</system.serviceModel> 

所以我的問題:是否有可能在上方更改的mustUnderstand上發出的消息等,或以類似的方式?或者,在檢查員更換安全標題後,它是否會在管道中強行恢復爲真?

注意:服務所有者表示他們只知道另一個組織在.NET中使用此服務,並且該用戶必須從頭開始從本質上拋出WCF和WSE並創建SOAP消息並處理答覆,可能使用POX POST或其他類似的。我們真的希望避免這種情況,因爲我們需要在服務上調用一些操作。

此外,我們需要保持消息的主體和屬性不變。

任何幫助將非常感謝!

回答

5

我想知道爲什麼標準的互操作性存在,如果供應商不遵循它們。如果客戶端檢查器不工作,您可以嘗試實現自定義消息編碼器並修改其中的標頭。

編輯:

這裏的問題是,爲什麼你,如果你在同一時間宣佈該服務不必瞭解與憑證頭髮送用戶憑據進行身份驗證=不必使用他們。你真的需要他們嗎?

還有其他方法取決於您的要求。你需要時間戳嗎?服務器上檢查了時間戳嗎?您是否有單一用戶接聽所有電話,或者您是否需要在不同電話之間區別用戶?

如果您不需要時間戳或時間戳未選中,並且您只有一個用戶名和密碼,最簡單的方法就是不要使用TranportWithMessageCredential安全模式。改用純運輸和地方標題說明客戶端點配置裏面,如:

<client> 
    <endpoint address="https://removed" binding="basicHttpBinding" bindingConfiguration="WebServiceSOPA" contract="EWebService.EWebService" name="WebServiceSOAP"> 
    <headers> 
    <wsse:Security s:mustUnderstand="0" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"> 
     <wsse:UsernameToken wsu:Id="SecurityToken-3f7f983f-66ce-480d-bce6-170632d33f92" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"> 
     <wsse:Username>User</wsse:Username> 
     <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">Pwd123</wsse:Password> 
     </wsse:UsernameToken> 
    </wsse:Security> 
    </headers> 
    </endpoint> 
    </client> 

如果您有多個用戶名或如果你需要用實際數據真實時間戳,您可以使用相同的方法,但不是靜態的配置,你可以創建自定義代碼中的頭部並避免WCF安全性。這可以使用消息檢查器完成。

+0

不幸的是,這家供應商將MustUnderstand = 0與仍然強制標頭中的(靜態)用戶名/密碼結合起來。如果我們忽略它,我們找回一個缺少的演員(即缺少元素)的錯誤。我不認爲時間戳是必需的。 嗯 - 我會嘗試端點配置方法並回複評論。 – pelazem 2010-08-24 09:30:32

+0

好的,謝謝拉迪斯拉夫!我嘗試了你的方法,並且由於我們「足夠幸運」擁有一個靜態的用戶名/密碼,所以只用於安全性和靜態頭部,因爲你只需要在運行時輸入 - 運行起來!非常感謝你。 – pelazem 2010-08-24 14:17:36

+0

拉迪斯拉夫,感謝您的方法,但我無法使用它。正如我在端點配置中添加了這個頭文件,我得到了編譯錯誤':前綴未定義'。你能否給出一個關於在這個頭文件中應該使用的名字空間的評論。 – 2013-09-02 13:20:36