IssuedTokenOverTransport响应中出现意外的SignatureConfirmation

时间:2014-04-11 18:02:21

标签: c# wcf interop

我正在构建一个WCF客户端来访问供应商Web服务。该服务使用IssuedTokenOverTransport,SymmetricKey,并期望SAML。我有请求工作,但从服务返回的响应包括WS-Security标头中的SignatureConfirmation元素。我的C#客户端在此安全标头中不会出现#34;签名确认#34;而且我没有看到忽略或处理这个元素的方法。似乎在WCF中接近处理SignatureConfirmation的唯一方法是放弃IssuedTokenOverTransport绑定并使用其他东西,但这似乎不是一个选项,因为该服务需要这种绑定类型。这是WCF中的错误吗?

1 个答案:

答案 0 :(得分:1)

我通过使用自定义消息编码器解决了这个问题。请参阅Carlos Figueroa的这篇​​文章了解背景信息:

http://blogs.msdn.com/b/carlosfigueira/archive/2011/11/09/wcf-extensibility-message-encoders.aspx

实际上,编码器可以在传入消息中查找SignatureConfirmation元素并将其从头中删除。关键代码是从ReadMessage覆盖调用的私有方法:

    private MemoryStream ProcessMemoryStream(Stream inputStream, bool dispose)
    {
        StreamWriter xmlStream = null;
        var outputStream = new MemoryStream();
        bool continueFilter = false;
        try
        {
            xmlStream = new StreamWriter(outputStream);
            using (var reader = XmlReader.Create(inputStream))
            {
                using (
                    var writer = XmlWriter.Create(xmlStream,
                        new XmlWriterSettings() {ConformanceLevel = ConformanceLevel.Auto}))
                {
                    while (reader.Read())
                    {
                        if (reader.LocalName.Equals("SignatureConfirmation") &&
                            reader.NamespaceURI.Equals(
                                "http://docs.oasis-open.org/wss/oasis-wss-wssecurity-secext-1.1.xsd"))
                        {
                            if (!reader.IsEmptyElement) continueFilter = reader.IsStartElement();
                        }
                        else if (reader.LocalName.Equals("Signature") &&
                                 reader.NamespaceURI.Equals("http://www.w3.org/2000/09/xmldsig#"))
                        {
                            if (!reader.IsEmptyElement) continueFilter = reader.IsStartElement();
                        }
                        else if (continueFilter)
                        {
                           // continue to next node
                        }
                        else
                            XmlHelper.WriteShallowNode(reader, writer);
                    }
                    writer.Flush();
                }
                reader.Close();
            }
            outputStream.Position = 0;
            return outputStream;
        }
        catch (Exception ex)
        {
            // handle error
            throw;
        }
        finally
        {
            if (xmlStream != null && dispose) xmlStream.Dispose();
        }
    }

Xml助手:

internal static class XmlHelper
{
    internal static void WriteShallowNode(XmlReader reader, XmlWriter writer)
    {
        if (reader == null)
        {
            throw new ArgumentNullException("reader");
        }
        if (writer == null)
        {
            throw new ArgumentNullException("writer");
        }

        switch (reader.NodeType)
        {
            case XmlNodeType.Element:
                writer.WriteStartElement(reader.Prefix, reader.LocalName, reader.NamespaceURI);
                writer.WriteAttributes(reader, true);
                if (reader.IsEmptyElement)
                {
                    writer.WriteEndElement();
                }
                break;
            case XmlNodeType.Text:
                writer.WriteString(reader.Value);
                break;
            case XmlNodeType.Whitespace:
            case XmlNodeType.SignificantWhitespace:
                writer.WriteWhitespace(reader.Value);
                break;
            case XmlNodeType.CDATA:
                writer.WriteCData(reader.Value);
                break;
            case XmlNodeType.EntityReference:
                writer.WriteEntityRef(reader.Name);
                break;
            case XmlNodeType.XmlDeclaration:
            case XmlNodeType.ProcessingInstruction:
                writer.WriteProcessingInstruction(reader.Name, reader.Value);
                break;
            case XmlNodeType.DocumentType:
                writer.WriteDocType(reader.Name, reader.GetAttribute("PUBLIC"), reader.GetAttribute("SYSTEM"),
                    reader.Value);
                break;
            case XmlNodeType.Comment:
                writer.WriteComment(reader.Value);
                break;
            case XmlNodeType.EndElement:
                writer.WriteFullEndElement();
                break;
        }
    }
}