1
votes

i have created service with such binding configuration:

<bindings>
  <customBinding>
    <binding name="DefaultBinding">
      <textMessageEncoding messageVersion="Soap12" />
      <httpTransport />
    </binding>
  </customBinding>
</bindings>

And when my service receives message starting like this:

<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">
  <s:Header>
    <Security s:mustUnderstand="1" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
      <UsernameToken>
        <Username>
        </Username>
        <Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">...</Password>
        <Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">KWVa4abCrEemOMT55VEZkgIAAAAAAA==</Nonce>
        <Created xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">2013-08-28T13:29:05.966Z</Created>
      </UsernameToken>
    </Security>
    ...

It produces error:

The header 'Security' from the namespace 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd' was not understood ...

I also tried:

<wsHttpBinding>
    <binding name="DefaultBinding">
      <security  mode="Message" />
    </binding>
</wsHttpBinding>

How i can process this header or ignore it ?


Update

As i understood i need username over insecure transport, so i tried:

<customBinding>
    <binding
        name="DefaultBinding">
      <textMessageEncoding messageVersion="Soap12" />
      <security authenticationMode="UserNameOverTransport" allowInsecureTransport="True">
      </security>
      <httpTransport>

      </httpTransport>
    </binding>
</customBinding>

I also tried CUB:

<bindings>
  <clearUsernameBinding>
    <binding name="myClearUsernameBinding" messageVersion="Soap12">
    </binding>
  </clearUsernameBinding>
</bindings>

Both ends with error on client: An error occurred when verifying security for message. But it works with test CUB's client. What could be wrong ?

CUB's envelope's header.

Test client's header.

4

4 Answers

2
votes

Solution was simple:

  1. Create service behavior
  2. Create dispatch message inspector
  3. Add created service behavior to server

And then just parse or just delete unused "mustUnderstand" headers.

Step 1:

public class WSSecurityBehavior : IServiceBehavior {
    public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) {
    }

    public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase,
        Collection<ServiceEndpoint> endpoints,
        BindingParameterCollection bindingParameters) {
    }

    public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) {
        var endpoints = serviceHostBase
            .ChannelDispatchers
            .Cast<ChannelDispatcher>()
            .SelectMany(dispatcher => dispatcher.Endpoints);

        foreach (var endpoint in endpoints)
            endpoint.DispatchRuntime.MessageInspectors.Add(new WSSecurityInspector());
    }
}

Step 2:

public class WSSecurityInspector : IDispatchMessageInspector {
    public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext) {
        var headerPosition = request.Headers.FindHeader("Security",
            "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");

        if (headerPosition > -1)
            request.Headers.RemoveAt(headerPosition);

        return null;
    }

    public void BeforeSendReply(ref Message reply, object correlationState) {
    }
}

Step 3:

Host.Description.Behaviors.Add(new WSSecurityBehavior());
1
votes

You've got a mismatch in the soap structure/contract you're exchanging between the client and host. The structure of the messages exchanged between the client and host (including the namespace) must match exactly. If they don't, you get this error.

What you want to do is get Fiddler running on your host. Then, running Fiddler as an man-in-the-middle proxy, resend the request from your client machine. When the request/response is finished, examine the messages in Fiddler, particularlly the namespace and structure differences between the request and response and there you should find the problem.

0
votes

The client is trying to authenticate to your server using user/pass in the message level. You need to decide if this is expected behavior, in which case you need to configure your service to do username authentication. This is not just a matter of setting a binding, you need to decide how you authenticate users (e.g. via a database, windows credentials etc). Once you know that you should be able to use a binding like this:

        <customBinding>
            <binding name="NewBinding0">
                <textMessageEncoding />
                <security authenticationMode="UserNameOverTransport">
                    <secureConversationBootstrap />
                </security>
                <httpsTransport />
            </binding>
        </customBinding>

I cannot be sure that this is what you need since you did not publish the full soap envelope. You might need to set messageVersion attribute on the text encoding element, or use CUB in case there is no SSL. Then you need to configure how you are going to verify the username. One example is here.

0
votes

you can use basicHttpBinding, download the project and sample code from this post for password digest in wcf PasswordDigest Auth this is my configuration with this implementation (i edited some code for custom needs but this solution works fine).

Create a binding:

 <bindings>
  <basicHttpBinding>
    <binding name="securityBinding">
      <security mode="TransportWithMessageCredential">
        <message clientCredentialType="UserName"/>
      </security>
    </binding>
  </basicHttpBinding>
</bindings>

And after set a behavior

 <behavior name="securityBehavior">
      <DataMessageTracer/>     
      <serviceCredentials type="WCF.SecurityExtensions.ServiceCredentialsEx, WCF.SecurityExtensions, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
        <serviceCertificate findValue="hypori2.zed.pa" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName"/>
        <userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="MyService.Utils.PassValidator, MyService, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
      </serviceCredentials>
      <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
      <serviceDebug includeExceptionDetailInFaults="false"/>
    </behavior>
  </serviceBehaviors>