IssuedTokenOverTransport响应中出现意外的SignatureConfirmation
本文关键字:意外 SignatureConfirmation 响应 IssuedTokenOverTransport | 更新日期: 2023-09-27 17:58:01
我正在构建一个WCF客户端来访问供应商web服务。该服务使用IssuedTokenOverTransport、SymmetricKey,并且需要SAML。我已经处理了请求,但从服务返回的响应在WS-Security头中包含SignatureConfirmation元素。我的C#客户端被这个"安全头中不需要签名确认"卡住了,我看不出有什么方法可以忽略或处理这个元素。在WCF中处理SignatureConfirmation的唯一方法似乎是放弃IssuedTokenOverTransport绑定并使用其他方法,但这似乎不是一个选项,因为服务需要这种绑定类型。这是WCF中的一个错误吗?
我使用自定义消息编码器解决了这个问题。参见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;
}
}
}