내가 우리 자신의 비누 봉투를 압연하여이를 해결 : 우리는 인증서를 사용할 수와 같이 서명하고 싶습니다
<?xml version="1.0" encoding="UTF8"?>
<SOAP-ENV:Envelope xmlns:SOAPENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header>
<wsse:Security xmlns:ds="http://www.w3.org/2000/09/xmldsig#"
xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" SOAP-ENV:mustUnderstand="1">
<wsse:BinarySecurityToken
EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary"
ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509"
wsu:Id="x509cert00">BASE64_CERT</wsse:BinarySecurityToken>
</wsse:Security>
</SOAP-ENV:Header>
<SOAP-ENV:Body xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="TheBody">
<getVersion xmlns="http://msgsec.wssecfvt.ws.ibm.com"/>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
:
같은 요청을 감안할 때 그들에게 서명하고 HttpClient를 통해 파이핑합니다. .NET Core의 WCF는 제 3 자 서비스의 다양한 단점을 다루는 결과를 얻지 못했습니다.
여기 코드는, 당신의 요구 사항을 변경할 정도로 쉬워야한다이다 :
// ...
private static HttpClient Client = new HttpClient(); // https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/
// ...
Uri uri = new Uri("https://thirdparty.com/service.svc");
X509Certificate2 cert = // from some store etc
var envelope = BuildEnvelope(cert);
using (HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, uri))
{
request.Content = new StringContent(envelope, Encoding.UTF8, "application/soap+xml");
using (HttpResponseMessage response = Client.SendAsync(request).Result)
{
if (response.IsSuccessStatusCode)
{
response.Content.ReadAsStringAsync().ContinueWith(task =>
{
string thirdparty_envelope = task.Result;
XElement thirdparty_root = XElement.Parse(thirdparty_envelope);
// etc
}, TaskContinuationOptions.ExecuteSynchronously);
}
}
}
private string BuildEnvelope(X509Certificate2 certificate)
{
string envelope = null;
// note - lots of bits here specific to my thirdparty
string cert_id = string.Format("uuid-{0}-1", Guid.NewGuid().ToString());
using (var stream = new MemoryStream())
{
Encoding utf8 = new UTF8Encoding(false); // omit BOM
using (var writer = new XmlTextWriter(stream, utf8))
{
// timestamp
DateTime dt = DateTime.UtcNow;
string now = dt.ToString("o").Substring(0, 23) + "Z";
string plus5 = dt.AddMinutes(5).ToString("o").Substring(0, 23) + "Z";
// soap envelope
// <s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
writer.WriteStartDocument();
writer.WriteStartElement("s", "Envelope", "http://www.w3.org/2003/05/soap-envelope");
writer.WriteAttributeString("xmlns", "a", null, "http://www.w3.org/2005/08/addressing");
writer.WriteAttributeString("xmlns", "u", null, "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd");
writer.WriteStartElement("s", "Header", null);
/////////////////
// saml guts //
/////////////////
//<a:Action s:mustUnderstand="1">http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Issue</a:Action>
writer.WriteStartElement("a", "Action", null);
writer.WriteAttributeString("s", "mustUnderstand", null, "1");
writer.WriteString("http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Issue");
writer.WriteEndElement(); //Action
//<a:MessageID>urn:uuid:0cc426dd-35bf-4c8b-a737-7e2ae94bd44d</a:MessageID>
string msg_id = string.Format("urn:uuid:{0}", Guid.NewGuid().ToString());
writer.WriteStartElement("a", "MessageID", null);
writer.WriteString(msg_id);
writer.WriteEndElement(); //MessageID
//<a:ReplyTo><a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address></a:ReplyTo>
writer.WriteStartElement("a", "ReplyTo", null);
writer.WriteStartElement("a", "Address", null);
writer.WriteString("http://www.w3.org/2005/08/addressing/anonymous");
writer.WriteEndElement(); //Address
writer.WriteEndElement(); //ReplyTo
writer.WriteStartElement("a", "To", "http://www.w3.org/2005/08/addressing");
writer.WriteAttributeString("s", "mustUnderstand", null, "1");
writer.WriteAttributeString("u", "Id", null, "_1");
writer.WriteString("https://thirdparty.com/service.svc");
writer.WriteEndElement(); //To
//<o:Security xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" s:mustUnderstand="1">
writer.WriteStartElement("o", "Security", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
writer.WriteAttributeString("s", "mustUnderstand", null, "1");
//<u:Timestamp u:Id="_0">
writer.WriteStartElement("u", "Timestamp", null);
writer.WriteAttributeString("u", "Id", null, "_0");
//<u:Created>2018-02-08T15:03:13.115Z</u:Created>
writer.WriteElementString("u", "Created", null, now);
//<u:Expires>2018-02-08T15:08:13.115Z</u:Expires>
writer.WriteElementString("u", "Expires", null, plus5);
writer.WriteEndElement(); //Timestamp
writer.WriteStartElement("o", "BinarySecurityToken", null);
writer.WriteAttributeString("u", "Id", null, cert_id);
writer.WriteAttributeString("ValueType", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3");
writer.WriteAttributeString("EncodingType", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary");
byte[] rawData = certificate.GetRawCertData();
writer.WriteBase64(rawData, 0, rawData.Length);
writer.WriteEndElement(); //BinarySecurityToken
writer.WriteEndElement(); //Security
writer.WriteEndElement(); //Header
//<s:Body xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
writer.WriteStartElement("s", "Body", "http://www.w3.org/2003/05/soap-envelope");
writer.WriteAttributeString("xmlns", "xsd", null, "http://www.w3.org/2001/XMLSchema");
writer.WriteAttributeString("xmlns", "xsi", null, "http://www.w3.org/2001/XMLSchema-instance");
// your 3rd-party soap payload goes here
writer.WriteStartElement("???", "http://docs.oasis-open.org/ws-sx/ws-trust/200512");
// ...
writer.WriteEndElement(); //
writer.WriteEndElement(); // Body
writer.WriteEndElement(); //Envelope
}
// signing pass
var signable = Encoding.UTF8.GetString(stream.ToArray());
XmlDocument doc = new XmlDocument();
doc.LoadXml(signable);
// see https://stackoverflow.com/a/6467877
var signedXml = new SignedXmlWithId(doc);
var key = certificate.GetRSAPrivateKey();
signedXml.SigningKey = key;
// these values may not be supported by your 3rd party - they may use e.g. SHA256 miniumum
signedXml.SignedInfo.CanonicalizationMethod = SignedXml.XmlDsigExcC14NTransformUrl;
signedXml.SignedInfo.SignatureMethod = SignedXml.XmlDsigRSASHA1Url;
//
KeyInfo keyInfo = new KeyInfo();
KeyInfoX509Data x509data = new KeyInfoX509Data(certificate);
keyInfo.AddClause(x509data);
signedXml.KeyInfo = keyInfo;
// 3rd party wants us to only sign the timestamp fragment- ymmv
Reference reference0 = new Reference();
reference0.Uri = "#_0";
var t0 = new XmlDsigExcC14NTransform();
reference0.AddTransform(t0);
reference0.DigestMethod = SignedXml.XmlDsigSHA1Url;
signedXml.AddReference(reference0);
// etc
// get the sig fragment
signedXml.ComputeSignature();
XmlElement xmlDigitalSignature = signedXml.GetXml();
// modify the fragment so it points at BinarySecurityToken instead
XmlNode info = null;
for (int i = 0; i < xmlDigitalSignature.ChildNodes.Count; i++)
{
var node = xmlDigitalSignature.ChildNodes[i];
if (node.Name == "KeyInfo")
{
info = node;
break;
}
}
info.RemoveAll();
//
XmlElement securityTokenReference = doc.CreateElement("o", "SecurityTokenReference", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
XmlElement reference = doc.CreateElement("o", "Reference", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
reference.SetAttribute("ValueType", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3");
// cert id
reference.SetAttribute("URI", "#" + cert_id);
securityTokenReference.AppendChild(reference);
info.AppendChild(securityTokenReference);
var nsmgr = new XmlNamespaceManager(doc.NameTable);
nsmgr.AddNamespace("o", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
nsmgr.AddNamespace("s", "http://www.w3.org/2003/05/soap-envelope");
var security_node = doc.SelectSingleNode("/s:Envelope/s:Header/o:Security", nsmgr);
security_node.AppendChild(xmlDigitalSignature);
envelope = doc.OuterXml;
}
return envelope;
}
는 .NET Framework의 닷넷 표준 구현을하고 그것을 호출과 같은 일을 할 수 있나요? 그것은 또 다른 프로젝트 일 것이지만 일어 나고 시작하는 것이 더 쉬울 수도 있습니다. 나는 그것이 당신의 질문에 대답하지 않는다는 것을 압니다. 그러나 그것은 가능한 실행 가능한 일이 될 것입니다. – thinklarge
나는 비슷한 요청으로 몇 주 전에 누군가를 도운다. 도움이 더 필요하면 알려주세요. 참조 : https://stackoverflow.com/questions/46722997/saml-assertion-in-a-xml-using-c-sharp/46724392#comment80642919_46724392 – jdweng