I have been all over the net for this. I\'ve just been having a devil of a time doing it, and the vendor whose web service I\'m trying to consume refuses to officially suppo
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:
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.
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:
download cub and make yourself familiar with it (not the internals, just how to use it according to the blog post)
add reference to System.Runtime.Serialization.dll to the project ClearUsernameBinding
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);
}
}
}
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));
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!