ma.citi

A Coder's Blog

Add wsse security header to soap request in WCF

It could happen that you have to interface your WCF client to a web service that uses WS-Security/WSE protocol. Web Services Security (WS-Security, WSS) is an extension to SOAP to apply security to Web services.

Unfortunately WS-Security/WSE protocol is not natively supported in .NET WCF 4.

WSS incorporates security features in the header of a SOAP message. Inside the header of a SOAP message, WSS has a security element (one or more than one) used to verify the end-user identity. Example:

<soap:Envelope>
 <soap:Header>	     
  <wsse:Security>
   <wsse:UsernameToken>
    <wsse:Username>user</wsse:Username>
    <wsse:Password>password</wsse:Password>
   </wsse:UsernameToken>
  </wsse:Security>

In order to allow your WCF client application to communicate with a WSS service a possible solution could be the following:

  1. Capture the raw soap message before it gets submitted: capture raw soap messages

  2. Implement BeforeSendRequest method in CapturingMessageInspector class (the following code is going to modify the soap message injecting the wss security header):

public object BeforeSendRequest(ref System.ServiceModel.Channels.Message request, IClientChannel channel)
{
    var soapModified = InjectWsseHeader(request.ToString());

    var ms = new MemoryStream();
    var writer = new StreamWriter(ms);
    writer.Write(soapModified);
    writer.Flush();
    ms.Position = 0;

    var reader = XmlReader.Create(ms);
    request = System.ServiceModel.Channels.Message.CreateMessage(reader, int.MaxValue, request.Version);

    this.SoapMessages.Request = soapModified;
    return null;
}
private string InjectWsseHeader(string request)
{
    XmlDocument xmlDoc = new XmlDocument();

    xmlDoc.LoadXml(request);

    XmlNode root = xmlDoc.DocumentElement;

    var sseNamespace = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";

    XmlElement sseSecurityHeader = xmlDoc.CreateElement("wsse", "Security", sseNamespace);

    XmlElement usernameToken = xmlDoc.CreateElement("wsse", "UsernameToken", sseNamespace);

    XmlElement username = xmlDoc.CreateElement("wsse", "Username", sseNamespace);

    username.InnerText = "your username ..";

    XmlElement password = xmlDoc.CreateElement("wsse", "Password", sseNamespace);

    password.InnerText = "your password ..";

    usernameToken.AppendChild(username);

    usernameToken.AppendChild(password);

    sseSecurityHeader.AppendChild(usernameToken);

    root.FirstChild.AppendChild(sseSecurityHeader);

    using (var stringWriter = new StringWriter())
    using (var xmlTextWriter = XmlWriter.Create(stringWriter))
    {
        xmlDoc.WriteTo(xmlTextWriter);
        xmlTextWriter.Flush();
        return stringWriter.GetStringBuilder().ToString();
    }
}