Как изменить MustUnderstand заголовка сообщения WCF с помощью ClientInspector

Я вызываю службу не-WCF из клиента WCF. Клиент WCF включает атрибут заголовка" MustUnderstand " установите в «1». Вот типичный запрос SOAP:

<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".

Я пытался изменить это в MessageContract для прокси-клиента с помощью атрибута MessageHeader, но это не помогло

Затем я реализовал специальный инспектор сообщений клиента. Я создал классы для каждого 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 или что-то подобное. Мы действительно предпочли бы избежать этого, так как нам нужно вызвать ряд операций над службой.

Кроме того, нам нужно сохранить тело и свойства сообщения без изменений.

Любая помощь будет принята с благодарностью !!

7
задан pelazem 23 August 2010 в 21:11
поделиться

1 ответ

Интересно, зачем существуют стандарты совместимости, если производители не следуют им. Если инспектор клиента не работает, можно попробовать реализовать собственный кодировщик сообщений и модифицировать заголовок в нем.

Edit:

Вопрос в том, зачем вы посылаете учетные данные пользователя для аутентификации, если вы в то же время заявляете, что сервис не обязан понимать заголовок с учетными данными = не обязан их использовать. Действительно ли они вам нужны?

Есть и другие подходы, зависящие от ваших требований. Нужна ли вам временная метка? Проверяется ли временная метка на сервере? У вас один пользователь для всех вызовов или вы должны различать пользователей между вызовами?

Если вам не нужен timestamp или timestamp не проверяется, и у вас только одно имя пользователя и пароль, самый простой способ - не использовать режим безопасности TranportWithMessageCredential. Вместо этого используйте чистый Transport и поместите описание заголовка внутри конфигурации конечной точки клиента, например:

<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. Это можно сделать с помощью инспектора сообщений.

5
ответ дан 7 December 2019 в 12:13
поделиться
Другие вопросы по тегам:

Похожие вопросы: