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