public void AfterReceiveReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
public object BeforeSendRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel)
{
// Add the ws-Security header
request.Headers.Add(new WsSecurityHeader(_certificate, TimeStampId, SecurityTokenId));
LastRequestXML = request.ToString();
// Get the entire message as an xml doc, so we can sign the body.
var signable = GetMessageAsString(request);
XmlDocument doc = new XmlDocument();
doc.PreserveWhitespace = true;
doc.LoadXml(signable);
Log.Information(doc.OuterXml);
XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable);
nsmgr.AddNamespace("s", WsSecurityHeader.SoapEnvelopeNamespace);
nsmgr.AddNamespace("wsse", WsSecurityHeader.WsseNamespace);
// The BinarySecrityToken is the element we want to sign.
var _binarySecToken = doc.SelectSingleNode("//wsse:BinarySecurityToken", nsmgr) as XmlElement;
var _binarySecToken_id = doc.CreateAttribute("wsu", "Id", WsSecurityHeader.WsseUtilityNamespaceUrl);
_binarySecToken_id.Value = SecurityTokenId;
_binarySecToken.Attributes.Append(_binarySecToken_id);
// The Body is the element we want to sign.
var body = doc.SelectSingleNode("//s:Body", nsmgr) as XmlElement;
var body_id = doc.CreateAttribute("wsu", "Id", WsSecurityHeader.WsseUtilityNamespaceUrl);
body_id.Value = BodyId;
body.Attributes.Append(body_id);
var signedXml = new SignedXmlWithUriFix(doc);
var key = _certificate.GetRSAPrivateKey(); //Private key from client certificate
signedXml.SigningKey = key;
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;
//TIMESTamop Ref
Reference ref_TimeStamp = new Reference();
ref_TimeStamp.Uri = "#" + TimeStampId;
var t0 = new XmlDsigExcC14NTransform();
ref_TimeStamp.AddTransform(t0);
ref_TimeStamp.DigestMethod = SignedXml.XmlDsigSHA1Url;
signedXml.AddReference(ref_TimeStamp);
//Binary Security token Ref
Reference ref_BinarySecurityToken = new Reference();
ref_BinarySecurityToken.Uri = "#" + SecurityTokenId;
ref_BinarySecurityToken.AddTransform(t0);
ref_BinarySecurityToken.DigestMethod = SignedXml.XmlDsigSHA1Url;
signedXml.AddReference(ref_BinarySecurityToken);
//BODY Ref
Reference ref_Body = new Reference();
ref_Body.Uri = "#" + BodyId;
ref_Body.AddTransform(t0);
ref_Body.DigestMethod = SignedXml.XmlDsigSHA1Url;
signedXml.AddReference(ref_Body);
signedXml.ComputeSignature();
XmlElement xmlDigitalSignature = signedXml.GetXml();
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();
//Append security Token Reference
XmlElement securityTokenReference = doc.CreateElement("wsse", "SecurityTokenReference", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
XmlElement reference = doc.CreateElement("wsse", "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");
reference.SetAttribute("URI", "#" + SecurityTokenId);
securityTokenReference.AppendChild(reference);
info.AppendChild(securityTokenReference);
//Append xmlDigitalSignature
var nsmgr2 = new XmlNamespaceManager(doc.NameTable);
nsmgr2.AddNamespace("wsse", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
nsmgr2.AddNamespace("s", "http://schemas.xmlsoap.org/soap/envelope/");
var security_node = doc.SelectSingleNode("/s:Envelope/s:Header/wsse:Security", nsmgr2);
security_node.AppendChild(xmlDigitalSignature);
var newMessage = CreateMessageFromXmlDocument(request, doc);
// Log.Information(GetMessageAsString(newMessage));
request = newMessage;
return null;
}
private string GetMessageAsString(Message msg)
{
using (var sw = new StringWriter())
using (var xw = new XmlTextWriter(sw))
{
msg.WriteMessage(xw);
xw.Close();
return sw.ToString();
}
}
private Message CreateMessageFromXmlDocument(Message message, XmlDocument doc)
{
MemoryStream ms = new MemoryStream();
using (XmlWriter xmlWriter = XmlWriter.Create(ms, new XmlWriterSettings { OmitXmlDeclaration = true, Indent = false }))
{
doc.WriteTo(xmlWriter);
xmlWriter.Flush();
xmlWriter.Close();
ms.Position = 0;
}
XmlDictionaryReader xdr = XmlDictionaryReader.CreateTextReader(ms, new XmlDictionaryReaderQuotas());
var newMessage = Message.CreateMessage(xdr, int.MaxValue, message.Version);
newMessage.Properties.CopyProperties(message.Properties);
return newMessage;
}
}
----------------------------------------------------------------------------------------------------------
/// <summary>
/// The SignedXml class chokes on a URI prefixed with "#", so we override the GetIdElement here. The #
/// is allowed by the XML Signature rfc (rfc3075), so this is really a bug fix for SignedXml.
/// </summary>
public class SignedXmlWithUriFix : SignedXml
{
public SignedXmlWithUriFix(XmlDocument xml) : base(xml)
{
}
public SignedXmlWithUriFix(XmlElement xmlElement)
: base(xmlElement)
{
}
public override XmlElement GetIdElement(XmlDocument document, string idValue)
{
// check to see if it's a standard ID reference
XmlElement idElem = base.GetIdElement(document, idValue);
if (idElem == null)
{
XmlNamespaceManager nsManager = new XmlNamespaceManager(document.NameTable);
nsManager.AddNamespace("wsu", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd");
idElem = document.SelectSingleNode("//*[@wsu:Id=\"" + idValue + "\"]", nsManager) as XmlElement;
}
return idElem;
}
}
}
Sample Request
_______________________________________
<s:Envelope xmlns:s=http://schemas.xmlsoap.org/soap/envelope/>
<s:Header>
<wsse:Security soap:mustUnderstand="1" xmlns:wsse=http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd xmlns:soap=http://schemas.xmlsoap.org/soap/envelope/ xmlns:wsu=http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd>
<wsu:Timestamp wsu:Id="TimeStamp-462b7720-6c40-467c-a1b7-3c8cf97bc9cb-1">
<wsu:Created>2023-12-26T17:17:59.283Z</wsu:Created>
<wsu:Expires>2023-12-26T17:22:59.283Z</wsu:Expires>
</wsu:Timestamp>
<saml:Assertion wsu:Id="SAML-91cada9b-e05f-4506-abd7-e0e45caedd23-1" Version="2.0" IssueInstant="2023-12-26T17:17:59.283Z" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">
<saml:Subject>
<saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">SOAB-TASKScheduler</saml:NameID>
<saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"/>
</saml:Subject>
<saml:AuthnStatement AuthnInstant="2023-12-26T17:17:59.283Z">
<saml:AuthnContext>
<saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified</saml:AuthnContextClassRef>
</saml:AuthnContext>
</saml:AuthnStatement>
<saml:AttributeStatement>
<saml:Attribute Name="organization">
<saml:AttributeValue>SOAB</saml:AttributeValue>
</saml:Attribute>
</saml:AttributeStatement>
</saml:Assertion>
<wsse:BinarySecurityToken wsu:Id="SecurityToken-47cdbd10-7285-4895-95f3-c0c495612a0a-1" ValueType=http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3 EncodingType=http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary>MIIF2DCCBMCgAwIBAgIQA3I+4IMONzX2</wsse:BinarySecurityToken>
<Signature xmlns=http://www.w3.org/2000/09/xmldsig#>
<SignedInfo>
<CanonicalizationMethod Algorithm=http://www.w3.org/2001/10/xml-exc-c14n#/>
<SignatureMethod Algorithm=http://www.w3.org/2000/09/xmldsig#rsa-sha1/>
<Reference URI="#TimeStamp-462b7720-6c40-467c-a1b7-3c8cf97bc9cb-1">
<Transforms>
<Transform Algorithm=http://www.w3.org/2001/10/xml-exc-c14n#/>
</Transforms>
<DigestMethod Algorithm=http://www.w3.org/2000/09/xmldsig#sha1/>
<DigestValue>nOn0gosvtJ8MpWiPe2qd0vHTvmM=</DigestValue>
</Reference>
<Reference URI="#SAML-91cada9b-e05f-4506-abd7-e0e45caedd23-1">
<Transforms>
<Transform Algorithm=http://www.w3.org/2001/10/xml-exc-c14n#/>
</Transforms>
<DigestMethod Algorithm=http://www.w3.org/2000/09/xmldsig#sha1/>
<DigestValue>J0fNSLnxmSMRKNdo0eqDOO+2w4s=</DigestValue>
</Reference>
<Reference URI="#SecurityToken-47cdbd10-7285-4895-95f3-c0c495612a0a-1">
<Transforms>
<Transform Algorithm=http://www.w3.org/2001/10/xml-exc-c14n#/>
</Transforms>
<DigestMethod Algorithm=http://www.w3.org/2000/09/xmldsig#sha1/>
<DigestValue>tm9NaZ01T/drvdpjgH5dnDLGHtU=</DigestValue>
</Reference>
<Reference URI="#Body-f4c9b7d8-7b0b-4068-aa67-bd565382da28-1">
<Transforms>
<Transform Algorithm=http://www.w3.org/2001/10/xml-exc-c14n#/>
</Transforms>
<DigestMethod Algorithm=http://www.w3.org/2000/09/xmldsig#sha1/>
<DigestValue>4d4WI+8V40abciJCd1ZqKkQNHvY=</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>ikL2RgqWUbX7WEe6TNygawcQFq7qO/zCJnqybNloBAT48Nf7kTlIfLo1jVTxRxZyEffkb8dEbtjv4D3fZcuar9wQsBeFLEA==</SignatureValue>
<KeyInfo>
<wsse:SecurityTokenReference>
<wsse:Reference ValueType=http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3 URI="#SecurityToken-47cdbd10-7285-4895-95f3-c0c495612a0a-1"/>
</wsse:SecurityTokenReference>
</KeyInfo>
</Signature>
</wsse:Security>
</s:Header>
<s:Body wsu:Id="Body-f4c9b7d8-7b0b-4068-aa67-bd565382da28-1" xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance xmlns:xsd=http://www.w3.org/2001/XMLSchema xmlns:wsu=http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd>
<GetOffenderInformation xmlns=http://xyx/OffenderInquiry/1>
<RequestMetadata xmlns=http://www.xyz/metadata/1>
<UserDefinedTrackingID>UDTID-d175cfe0-779c-4acb-a744-72f644002e08</UserDefinedTrackingID>
<RequestDataSourceID>ER</RequestDataSourceID>
<RequestAuthenticatedUserID>TEstUser</RequestAuthenticatedUserID>
</RequestMetadata>
<OffenderSearchCriteria xmlns=http://www.jnet.state.pa.us/niem/JNET/jnet-core/2>
<PersonOtherIdentification xmlns=http://release.niem.gov/niem/niem-core/3.0/>
<IdentificationID>DOCINmateNumABCDEF12345</IdentificationID>
<IdentificationCategoryText>INMATEID</IdentificationCategoryText>
</PersonOtherIdentification>
</OffenderSearchCriteria>
</GetOffenderInformation>
</s:Body>
</s:Envelope>