Как изменить MustUnderstand заголовка сообщения WCF с помощью ClientInspector - PullRequest
7 голосов
/ 24 августа 2010

Я звоню в службу, отличную от 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 на исходящем сообщении, как описано выше, или подобным образом?Или это принудительно изменяется обратно на true позже в конвейере, после того, как инспектор заменит заголовок безопасности?

Примечание: владелец службы говорит, что ему известна только одна другая организация, использующая эту службу в .NET,и что этот потребитель должен был по существу выбросить WCF и WSE и создать сообщения SOAP - и обработать ответы - с нуля, возможно, используя POX POST или что-то подобное.Мы действительно предпочли бы избежать этого, так как нам нужно вызвать ряд операций над службой.

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

Любая помощь будетбыть очень ценным !!

1 Ответ

5 голосов
/ 24 августа 2010

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

Редактировать:

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

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

Если вам не нужна временная метка или временная метка не проверена, и у вас есть только одно имя пользователя и пароль, самый простой способ - это неиспользовать режим безопасности 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.Это можно сделать с помощью инспектора сообщений.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...