IssuedTokenOverTransport响应中出现意外的SignatureConfirmation

本文关键字:意外 SignatureConfirmation 响应 IssuedTokenOverTransport | 更新日期: 2023-09-27 17:58:01

我正在构建一个WCF客户端来访问供应商web服务。该服务使用IssuedTokenOverTransport、SymmetricKey,并且需要SAML。我已经处理了请求,但从服务返回的响应在WS-Security头中包含SignatureConfirmation元素。我的C#客户端被这个"安全头中不需要签名确认"卡住了,我看不出有什么方法可以忽略或处理这个元素。在WCF中处理SignatureConfirmation的唯一方法似乎是放弃IssuedTokenOverTransport绑定并使用其他方法,但这似乎不是一个选项,因为服务需要这种绑定类型。这是WCF中的一个错误吗?

IssuedTokenOverTransport响应中出现意外的SignatureConfirmation

我使用自定义消息编码器解决了这个问题。参见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;
        }
    }
}