我設計了一個向供應商發送SOAP請求的WCF.net客戶端。爲了滿足供應商的WS安全要求,我必須創建一個自定義SOAP頭,並將自定義頭的請求發送到供應商方的Web服務。所以,我通過實現從的MessageHeader derieved一個新的類創建一個自定義標題(見下文)簽名失敗核心驗證錯誤
public class SignOnlyMessageHeader : MessageHeader
{
private const string PREFIX_CP = "wsse";
public string m_Username { get; set; }
public string m_Envelope { get; set; }
public SignOnlyMessageHeader(string Username, string Envelope)
{
m_Username = Username;
m_Envelope = Envelope;
}
public override string Name
{
get { return "wsse:Security"; }
}
public override string Namespace
{
get { return null; }
}
public override bool MustUnderstand
{
get
{
return false;
}
}
protected override void OnWriteStartHeader(XmlDictionaryWriter writer, MessageVersion messageVersion)
{
base.OnWriteStartHeader(writer, messageVersion);
writer.WriteXmlnsAttribute(PREFIX_CP, "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
}
protected override void OnWriteHeaderContents(XmlDictionaryWriter writer, MessageVersion messageVersion)
{
writer.WriteStartElement(PREFIX_CP, "UsernameToken", null);
writer.WriteAttributeString("wsu:Id", "UsernameToken-20");
writer.WriteXmlnsAttribute("wsu", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd");
writer.WriteElementString(PREFIX_CP, "Username", null, m_Username);
writer.WriteEndElement();
SignXmlFile(writer);
}
public void SignXmlFile(XmlDictionaryWriter writer)
{
string certificatePath = "C:\\Users\\22428-cert.p12";
System.Security.Cryptography.X509Certificates.X509Certificate2 cert = new X509Certificate2(certificatePath, "changeit");
// Create a new XML document.
XmlDocument doc = new XmlDocument();
// Format the document to ignore white spaces.
doc.PreserveWhitespace = false;
doc.LoadXml(m_Envelope);
// Create a SignedXml object.
SignedXml signedXml = new SignedXml(doc);
// Add the key to the SignedXml document.
//signedXml.SigningKey = Key;
signedXml.SigningKey = cert.PrivateKey;
// Create a new KeyInfo object.
KeyInfo keyInfo = new KeyInfo();
keyInfo.Id = "";
// Load the certificate into a KeyInfoX509Data object
// and add it to the KeyInfo object.
KeyInfoX509Data keyInfoData = new KeyInfoX509Data();
keyInfoData.AddCertificate(cert);
keyInfo.AddClause(keyInfoData);
// Add the KeyInfo object to the SignedXml object.
signedXml.KeyInfo = keyInfo;
signedXml.SignedInfo.CanonicalizationMethod = "http://www.w3.org/2001/10/xml-exc-c14n#";
// Create a reference to be signed.
Reference reference = new Reference();
reference.Uri = "";
// Add an enveloped transformation to the reference.
XmlDsigEnvelopedSignatureTransform env = new XmlDsigEnvelopedSignatureTransform();
reference.AddTransform(env);
reference.DigestMethod = "http://www.w3.org/2001/04/xmlenc#sha256";
// Add the reference to the SignedXml object.
signedXml.AddReference(reference);
signedXml.Signature.Id = "";
// Compute the signature.
signedXml.ComputeSignature();
// Get the XML representation of the signature and save
// it to an XmlElement object.
XmlElement xmlDigitalSignature = signedXml.GetXml();
// Check the signature and return the result.
if (!signedXml.CheckSignature(new X509Certificate2(certificatePath, "changeit"), true))
{
Console.WriteLine("invalid signature");
}
xmlDigitalSignature.WriteTo(writer);
}
所以創建自定義標題下課後,我推翻了IClientMessageInspector.BeforeSendRequest方法來攔截傳出請求,並添加我的自定義標題肥皂請求。請參閱下面的代碼,
object IClientMessageInspector.BeforeSendRequest(ref System.ServiceModel.Channels.Message request, IClientChannel channel)
{
request.Headers.RemoveAt(0);
SignOnlyMessageHeader header = new SignOnlyMessageHeader("x509user", env);
request.Headers.Add(header);
return null;
}
最終結果是我攔截SOAP請求並正確使用自定義標頭替換當前標頭。在發送請求之前,我檢查了更新後的SOAP請求(放置了一個斷點),該結構完全匹配供應商請求的內容。但是,在供應商端處理請求後,我收到一個錯誤。它只說「簽名失敗的核心驗證」。我認爲我正確地在「SignXmlFile」方法中籤署了整個信封。我甚至檢查了方法中的有效性(if(!signedXml.CheckSignature(new X509Certificate2(certificatePath,「changeit」),true))),該語句返回一個假,表示簽名有效。
我在做什麼錯?
你可以使用Fiddler或Wireshark來查看*完全*你的應用程序發送的線路是什麼? – Amy
你確定你必須忽略空白嗎?有或沒有空格的 –
,我得到相同的錯誤。 – wcfvemi