locked
WS Security element missing in the soap header RRS feed

  • Question

  • Hello All,

    I would like to have your assistance and guidance in some of the issues (listed below) I'm facing while building a wcf client to a java based web service.

    Background:

    - the service is authenticated via ws security (so it expects wsse:Security element in the soap header)

    - for development purpose, the service endpoint will be http but for test and prod, its going to be https

    - I am building a middle tier dll (to isolate it from DB layer), so I prefer to setup the binding configuration parameters completely in code (without any .config dependency)

    Expected soap packet: (non relevant attributes and elements omitted):

    <soapenv:Envelope ...>
        <soapenv:Header>
            <wsse:Security....>
                 <wsse:UsernameToken ...   >
                    <wsse:Username>XX</wsse:Username>
                    <wsse:Password ..></wsse:Password>
                    <wsse:Nonce...> .. </wsse:Nonce>
                    <wsu:Created> ..  </wsu:Created>
                </wsse:UsernameToken>
            </wsse:Security>
        </soapenv:Header>
        <soapenv:Body>
        .
        .
        .
        </soapenv:Body>
    </soapenv:Envelope>

     

    Currently generated soap packet:

    <s:Envelope ...>
        <s:Header>
            <a:Action s:mustUnderstand="1"></a:Action>
            <a:ReplyTo>
                <a:Address></a:Address>
                </a:ReplyTo>
        </s:Header>
        <s:Body>
        .
        .
        .
        </s:Body>
    </s:Envelope>

     

    my current code (no config settings):

               //tried with WSHttpBinding as well

                EndpointAddress address = new EndpointAddress(httpsORhttpAddress);
                BasicHttpBinding soapHTTPBinding = new BasicHttpBinding(BasicHttpSecurityMode.TransportWithMessageCredential);
                soapHTTPBinding.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.UserName;
                ServicePointManager.CertificatePolicy = new AcceptAllCertificatePolicy();           
                myClient = new  TestTypeClient(soapHTTPBinding, address);
                myClient.ClientCredentials.UserName.UserName = "XXX";
                myClient.ClientCredentials.UserName.Password = "XXXXXXX";
                myClient.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode = System.ServiceModel.Security.X509CertificateValidationMode.None;
                ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(delegate { return true; });
                myClient.testMethod("blah");

     

    These are the issues/questions I have:

    1. After googling across many blogs and suggestions, I tried various configuration parameters for the binding as well as for the client proxy itself. But non of them makes an effect in the soap packet creation. For some reason, its not generating the ws security header elements. I do understand that we can intercept the raw message with a messageInspector and modify the headers, but  I am looking for a more robust/standard approach. In my opinion, this is kinda common header elements and there could be a straighforward way to generate it. I appreciate your support here.

    2. I was not able to turn off the ws-addressing header elements (action, ReplyTo) with WSHttpBinding/BasicHttpBinding. Do I need to go for CustomBinding to do this? Even if I want to preserve them, what would be the best approach to either remove or set the  mustUnderstand attribute to false?

    3.  For some reason, I am getting an empty soap action for request.Headers.Action in IClientMessageInspector.BeforeSendRequest. Is there any property I should specifically set in my client or server to receive the soap action in the messageInspectors?

     

    I truly appreciate your suggestions and support...

    Thank you very much...

     




    • Edited by cool.dev Thursday, January 26, 2012 10:22 PM
    Wednesday, January 25, 2012 8:18 PM

Answers

  • hi cool.dev,

    What you see is as expected :)

    What passes the messageInspector is indeed NOT the final message that is put on the wire. Between the messageInspector and the wire there is still a channelstack with security components, reliable messaging component (if applied) and an encoder. Those things are executed after your messageInspector. That is why Fiddler shows a different result.

    To trace WCF I never use Fiddler :) I use WCF tracing (under diagnostics in the config file). WCF has a very usefull trace viewer to analyze the trace files.

    You can trace on two levels, transport and service. Trasport traces messages as they are put on the wire (one exception though: transport security as it is done on the transport layer and as a consequence is never visible during tracing), service tracing traces message as they are presented to the dispatcher.
    Next to message tracing also events are traced. This  gives a very detailed view about where something goes wrong in the communication between client and service.


    If this post answers your quenstion, please mark it as such. If this post is helpful, click 'Vote as helpful'.
    • Proposed as answer by Peter Borremans Monday, January 30, 2012 12:02 PM
    • Marked as answer by Yi-Lun Luo Wednesday, February 1, 2012 11:41 AM
    Friday, January 27, 2012 9:55 PM

All replies

  • You are not using the correct WCF binding. Instead of the basicHttpBinding go for the wsHttpBinding. That binding support WS-Security. Configure the binding's security mode to 'Message'. Set the clientCredentialType to 'Username'.

     


    If this post answers your quenstion, please mark it as such. If this post is helpful, click 'Vote as helpful'.
    Wednesday, January 25, 2012 9:34 PM
  • Thanks Peter for your Reply.

     

    made this change with http url:

    WSHttpBinding soapHTTPBinding = new WSHttpBinding(SecurityMode.Message);

     

    also this with https url:

    WSHttpBinding soapHTTPBinding = new WSHttpBinding(SecurityMode.TransportWithMessageCredential);

    Both these changes did not make any visible effect in the generated soap message (except for MessageID element). Its still the same :(

    This is the header now:

    <s:Header>
        <a:Action s:mustUnderstand="1"></a:Action>
        <a:MessageID>urn:uuid:04000b95-9eb8-42d7-b006a9297dc05f9a</a:MessageID>
        <a:ReplyTo>
        <a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address></a:ReplyTo>
    </s:Header>




    • Edited by cool.dev Wednesday, January 25, 2012 11:43 PM
    Wednesday, January 25, 2012 10:04 PM
  • Something must be missing in your config; maybe posting your config file and if possible the service's metadate can help.
    If this post answers your quenstion, please mark it as such. If this post is helpful, click 'Vote as helpful'.
    Thursday, January 26, 2012 7:00 AM
  • I am pasting the client definition generated out of svcutil.exe.  As I mentioned earlier, My proxy is going to make the call from a middle tier dll - so there is no config parameters. I am setting up the binding and other parameters in code itself.

     

    [System.ServiceModel.ServiceContractAttribute(Namespace = "http://test.com/test")]
    public interface TestPortType
    {
        [System.ServiceModel.OperationContractAttribute()]
        [SoapLogger]//Custom message logger
        EchoResponse1 Echo(EchoRequest1 request);
    }

    [System.ServiceModel.MessageContractAttribute(IsWrapped = false)]
    public partial class EchoRequest1
    {
        [System.ServiceModel.MessageBodyMemberAttribute(Namespace = "http://test.com/testTypes", Order = 0)]
        public EchoRequest EchoRequest;
    }

    [System.ServiceModel.MessageContractAttribute(IsWrapped = false)]
    public partial class EchoResponse1
    {
        [System.ServiceModel.MessageBodyMemberAttribute(Namespace = "http://test.com/testTypes", Order = 0)]
        public EchoResponse EchoResponse;
    }

    [System.SerializableAttribute()]
    [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://test.com/testTypes")]
    public partial class EchoRequest
    {
        public string data { get; set; }
    }

    [System.SerializableAttribute()]
    [System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://test.com/testTypes")]
    public partial class EchoResponse
    {
        public string data { get; set; }
    }

    public interface TestPortTypeChannel : TestPortType, System.ServiceModel.IClientChannel
    {
    }

    public partial class TestTypeClient : System.ServiceModel.ClientBase<TestPortType>, TestPortType
    {
        public TestTypeClient()
        {
        }
        public TestTypeClient(string endpointConfigurationName)
            : base(endpointConfigurationName)
        {
        }
        public TestTypeClient(string endpointConfigurationName, string remoteAddress)
            : base(endpointConfigurationName, remoteAddress)
        {
        }

        public TestTypeClient(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress)
            : base(endpointConfigurationName, remoteAddress)
        {
        }
        public TestTypeClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress)
            : base(binding, remoteAddress)
        {
        }

        EchoResponse1 TestPortType.Echo(EchoRequest1 request)
        {
            return base.Channel.Echo(request);
        }

        public EchoResponse Echo(EchoRequest EchoRequest)
        {
            EchoRequest1 inValue = new EchoRequest1();
            inValue.EchoRequest = EchoRequest;
            EchoResponse1 retVal = ((TestPortType)(this)).Echo(inValue);
            return retVal.EchoResponse;
        }
    }

    Thursday, January 26, 2012 10:21 PM
  • Can you show the code that configures the binding?


    If this post answers your quenstion, please mark it as such. If this post is helpful, click 'Vote as helpful'.
    Friday, January 27, 2012 6:25 AM
  • Thank you Peter.

    My first post has all the code with which I am making the call.  But its kinda working now!!

    All the time, I was tracing the message logged by (custom) messageInspector. And I was under the impression that, thats the final message send out over the wire. But looks like I am wrong. When I traced it with Fiddler, I see that appropriate ws-security tags are generated. So its working :)

    But, what could be the reason for  getting a different message in messageInspector?  So is it not the right place in the pipeline, to log the final messages in wcf, Is there a better approach to log the final message send out?

    Friday, January 27, 2012 6:56 PM
  • hi cool.dev,

    What you see is as expected :)

    What passes the messageInspector is indeed NOT the final message that is put on the wire. Between the messageInspector and the wire there is still a channelstack with security components, reliable messaging component (if applied) and an encoder. Those things are executed after your messageInspector. That is why Fiddler shows a different result.

    To trace WCF I never use Fiddler :) I use WCF tracing (under diagnostics in the config file). WCF has a very usefull trace viewer to analyze the trace files.

    You can trace on two levels, transport and service. Trasport traces messages as they are put on the wire (one exception though: transport security as it is done on the transport layer and as a consequence is never visible during tracing), service tracing traces message as they are presented to the dispatcher.
    Next to message tracing also events are traced. This  gives a very detailed view about where something goes wrong in the communication between client and service.


    If this post answers your quenstion, please mark it as such. If this post is helpful, click 'Vote as helpful'.
    • Proposed as answer by Peter Borremans Monday, January 30, 2012 12:02 PM
    • Marked as answer by Yi-Lun Luo Wednesday, February 1, 2012 11:41 AM
    Friday, January 27, 2012 9:55 PM
  • It is UserName. case sensitive.

    A tested snippet:

        <bindings>
          <wsHttpBinding>
            <binding name="BindingName">
              <security mode="Message">
                <message clientCredentialType = "UserName" />
              </security>
            </binding>        
          </wsHttpBinding>
        </bindings>
    

    Wednesday, November 18, 2020 2:29 PM