(Attempting to) migrate from WSE 3.0 to WCF for client code

What you need is to send a username token over http transport which is not supported in wcf ootb. in addition your token uses nonce/created which is also not ootb. you have 2 options:

  1. this oss project adds nonce/created to the username token. this oss project adds the ability to send username over http. you would need to combine both projects together.

  2. ws-security is usually considered complex, but you use it in its simplest form (username). the easiest would be to dismiss any wcf security setting all together and create the whole security header by yourself in a message inspector! As you can see most headers are just static xml nodes, and most values are pretty clear (you know the username). the only tricky two are the nonce and the timestamps which you could look how to do in this oss project (one line each). There is a variant of this option which may be easier - use CUB after all and implement a custom encoder which pushes the timestmpa/nonce. I would go for the latter but I'm biased since I developed CUB...

There's also the ws-addressing headers which you can configure on your custom encoding "messageVersion" property. I can't tell the exact value since you omitted the envelope header with the wsa prefix definition.

If you want help privately (since you seem to have security restrictions) by all means send me an email from my blog.

EDIT: I've implemented it for you. follow these steps:

  1. download cub and make yourself familiar with it (not the internals, just how to use it according to the blog post)

  2. add reference to System.Runtime.Serialization.dll to the project ClearUsernameBinding

  3. add a new file to that project: UsernameExEncoder.cs. Paste this content:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.ServiceModel.Channels;
    using System.IO;
    using System.Xml;
    using System.Security.Cryptography;
    
    namespace Webservices20.BindingExtensions
       {
        class UsernameExEncoderBindingElement : MessageEncodingBindingElement
        {
        MessageEncodingBindingElement inner;        
    
        public UsernameExEncoderBindingElement(MessageEncodingBindingElement inner)
        {
            this.inner = inner;            
        }
    
        public override IChannelFactory<TChannel> BuildChannelFactory<TChannel>(BindingContext context)
        {
            context.BindingParameters.Add(this);
            var res = base.BuildChannelFactory<TChannel>(context);
            return res;
        }
    
        public override bool CanBuildChannelFactory<TChannel>(BindingContext context)
        {
            var res = base.CanBuildChannelFactory<TChannel>(context);
            return res;
        }
    
        public override MessageEncoderFactory CreateMessageEncoderFactory()
        {
            return new UsernameExEncoderFactory(this.inner.CreateMessageEncoderFactory());
        }      
    
        public override MessageVersion MessageVersion
        {
            get
            {
                return this.inner.MessageVersion;
            }
            set
            {
                this.inner.MessageVersion = value;
            }
        }
    
        public override BindingElement Clone()
        {
            var c = (MessageEncodingBindingElement)this.inner.Clone();
            var res = new UsernameExEncoderBindingElement(c);
            return res;
        }
    
        public override T GetProperty<T>(BindingContext context)
        {
            var res = this.inner.GetProperty<T>(context);
            return res;
        }
    }
    
    class UsernameExEncoderFactory : MessageEncoderFactory
    {
        MessageEncoderFactory inner;        
    
        public UsernameExEncoderFactory(MessageEncoderFactory inner)
        {
            this.inner = inner;            
        }
    
        public override MessageEncoder Encoder
        {
            get { return new UsernameExEncoder(inner.Encoder); }
        }
    
        public override MessageVersion MessageVersion
        {
            get { return this.inner.MessageVersion; }
        }
    
    }
    
    class UsernameExEncoder : MessageEncoder
    {
        MessageEncoder inner;
    
        public override T GetProperty<T>()
        {
            return inner.GetProperty<T>();
        }
    
        public UsernameExEncoder(MessageEncoder inner)
        {
            this.inner = inner;
        }
    
        public override string ContentType
        {
            get { return this.inner.ContentType; }
        }
    
        public override string MediaType
        {
            get { return this.inner.MediaType; }
        }
    
        public override MessageVersion MessageVersion
        {
            get { return this.inner.MessageVersion; }
        }
    
        public override bool IsContentTypeSupported(string contentType)
        {
            return this.inner.IsContentTypeSupported(contentType);
        } 
    
        public override Message ReadMessage(ArraySegment<byte> buffer, BufferManager bufferManager, string contentType)
        {
            return this.inner.ReadMessage(buffer, bufferManager, contentType);
        }
    
        public override Message ReadMessage(System.IO.Stream stream, int maxSizeOfHeaders, string contentType)
        {
            return this.inner.ReadMessage(stream, maxSizeOfHeaders, contentType);
        }
    
        public override ArraySegment<byte> WriteMessage(Message message, int maxMessageSize, BufferManager bufferManager, int messageOffset)
        {   
            //load the message to dom
            var mem = new MemoryStream();
            var x = XmlWriter.Create(mem);
            message.WriteMessage(x);
            x.Flush();
            mem.Flush();
            mem.Position = 0;
            XmlDocument doc = new XmlDocument();
            doc.Load(mem);
    
            //add the missing elements
            var token = doc.SelectSingleNode("//*[local-name(.)='UsernameToken']");
            var created = doc.CreateElement("Created", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
            var nonce = doc.CreateElement("Nonce", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
            token.AppendChild(created);
            token.AppendChild(nonce);
    
            //set nonce value
            byte[] nonce_bytes = new byte[16];
            RandomNumberGenerator rndGenerator = new RNGCryptoServiceProvider();
            rndGenerator.GetBytes(nonce_bytes);
            nonce.InnerText = Convert.ToBase64String(nonce_bytes);
    
            //set create value
            created.InnerText = XmlConvert.ToString(DateTime.Now.ToUniversalTime(), "yyyy-MM-ddTHH:mm:ssZ");
    
            //create a new message
            var r = XmlReader.Create(new StringReader(doc.OuterXml));
            var newMsg = Message.CreateMessage(message.Version, message.Headers.Action, r);
    
            return this.inner.WriteMessage(newMsg, maxMessageSize, bufferManager, messageOffset);
        }
    
    
    
    
        public override void WriteMessage(Message message, System.IO.Stream stream)
        {
            this.inner.WriteMessage(message, stream);
        }
    }
    }
    
  4. In the file ClearUsernameBinding.cs replace this:

    res.Add(new TextMessageEncodingBindingElement() { MessageVersion = this.messageVersion});

    with this:

    var textEncoder = new TextMessageEncodingBindingElement() { MessageVersion = this.messageVersion }; res.Add(new UsernameExEncoderBindingElement(textEncoder));

  5. In the project TestClient in app.config there is a messageVersion property on the binding element. You have not published the root of your envelope so I cannot know for sure, but probably you need to set it to Soap11WSAddressingAugust2004 or Soap11WSAddressing10 (or one of these with Soap12 instead).

Good luck!


Comments

  1. Bernard

    • 2018/3/29

    What you need is to send a username token over http transport which is not supported in wcf ootb. in addition your token uses nonce/created which is also 

  2. Gregory

    • 2021/3/31

    WCF has a built-in message tracing feature but you could also use Fiddler for capturing traffic from both the WSE and the WCF clients. To expand on my previous comment, you should approach creating your new WCF client from the point of view of interfacing with an Apache Axis service instead of porting from a legacy WSE client.

  3. Ricky

    • 2018/9/20

    That client however contains interfaces and classes that can be used as a starting point for a WCF service too. The interfaces that are 

  4. Damien

    • 2021/4/29

    Hi I'm struggling with migrating some WSE 3.0 code to WCF. It is client-side code which is calling a 3rd Party Java web service. I have no control over this web service and the owners do not know how to consume it using VS2008 and WCF, so are unable to advise me.

  5. Long

    • 2019/4/25

    Hi I'm struggling with migrating some WSE 3.0 code to WCF. It is client-side code which is calling a 3rd Party Java web service.

  6. Riley

    • 2017/12/26

    This means WCF clients can interoperate with WSE 3.0 services and vice versa, removing the need for continued migration. Migrating Projects from WSE 2.0 to WSE 3.0. When it comes to moving existing code forward to WSE 3.0, integration with the .NET Framework 2.0 and Visual Studio 2005 is most important.

  7. Roberts

    • 2018/6/16

    Hi! I have a website that consume a webservice using WSE 3.0. Now I want to convert my WSE code, to WCF. In Visual Studio, and using WSE, 

  8. Misael

    • 2017/8/12

    To access a WSE 3.0 Web service with a WCF client. Run the ServiceModel Metadata Utility Tool (Svcutil.exe) to create a WCF client for the WSE 3.0 Web service. For a WSE 3.0 Web service, a WCF client is created. Because WSE 3.0 does not support the MEX protocol, you cannot use the tool to retrieve the security requirements for the Web service.

  9. Victor

    • 2018/2/7

    could you please tell, how will look this code if to use WCF instead of WSE3.0? #How to Migrating WSE 3.0 Web Services to WCF:

  10. Uriel

    • 2021/6/25

    Hi! I have a website that consume a webservice using WSE 3.0. Now I want to convert my WSE code, to WCF. In Visual Studio, and using WSE, I goto Website>Add WebReference, to add the refence to the webservice to my website. And, I use this code, to connect to webservice: Dim myRUProxyWS As New RU.ConsultaUtenteWse. myRUProxyWS.Timeout = 30000.

  11. Enoch

    • 2016/7/23

    Attempting to migrate from WSE 3.0 to WCF for client code I have been all over the net for.. created with Apache Axis 1.2. The code My legacy code uses WSE 

  12. Ross

    • 2019/6/12

    To configure a WCF client to interoperate with a WSE 3.0 Web service. Run the ServiceModel Metadata Utility Tool (Svcutil.exe) to create a WCF client for the WSE 3.0 Web service. For a WSE Web service, a WCF client class is created. For details about creating a WCF client, see the How to: Create a Client.

  13. Nehemiah

    • 2020/4/30

    The reason is that Microsoft wants you to migrate your code to WCF. See below to enable Web Services Enhancements (WSE) 3.0 in VS2012, 

  14. King

    • 2020/5/7

    Web Services Performance, Interoperability And Testing Blog - WCF, Axis2, WSIT. (Attempting to) migrate from WSE 3.0 to WCF for client code.

Comments are closed.

Recent Posts