gpt4 book ai didi

c# - 如何为 WS-Security 生成 UsernameToken?

转载 作者:行者123 更新时间:2023-11-30 17:26:40 25 4
gpt4 key购买 nike

我有一些 Web 服务(用 Java 编写),我需要在 .NET 中为它创建客户端。 WebService 具有 WS-Security 并且需要 PasswordDigest。首先,我已经在 SoapUI 中对其进行了测试,它适用于:

POST http://192.168.100.101:8181/services/ws/SomeService HTTP/1.1
Accept-Encoding: gzip,deflate
Content-Type: application/soap+xml;charset=UTF-8;action="someMethod"
Content-Length: 971
Host: 192.168.100.101:8181
Connection: Keep-Alive
User-Agent: Apache-HttpClient/4.1.1 (java 1.5)

<soap:Envelope xmlns:not="http://existing-domain.com/op/integration/services" xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
<soap:Header>
<wsse:Security 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">
<wsse:UsernameToken wsu:Id="UsernameToken-2C1E2DE2B61EBB94E115572099598331">
<wsse:Username>SOME_LOGIN</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">rcSb6Hd8btcI9g6JvO7dGdiTBTI=</wsse:Password>
<wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">PCoVwJm9oEXtusx6gkMb7w==</wsse:Nonce>
<wsu:Created>2019-05-07T06:19:19.824Z</wsu:Created>
</wsse:UsernameToken>
</wsse:Security>
</soap:Header>
<soap:Body>
<not:someMethod/>
</soap:Body>
</soap:Envelope>

在下一步中,我在 .NET 中准备了简单的客户端,并使用 Wireshark 检查它发送的内容:

POST /services/ws/SomeService HTTP/1.1
Accept-Encoding: gzip,deflate
Content-Type: application/soap+xml;charset=UTF-8;action="someMethod"
User-Agent: Apache-HttpClient/4.1.1 (java 1.5)
Host: 192.168.100.101:8181
Content-Length: 1124
Expect: 100-continue
Connection: Keep-Alive

<soap:Envelope xmlns:not="http://existing-domain.com/op/integration/services" xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
<soap:Header>
<wsse:Security 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">
<wsse:UsernameToken xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="SecurityToken-85707168-b5c6-47dc-93e9-45afa466fa2a" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:Username>SOME_LOGIN</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">g112a9eHPR1hXD4UH+Lh3o8JV/o=</wsse:Password>
<wsse:Nonce>EiUbo2DbXMGhM26fT+ZkJQ==</wsse:Nonce>
<wsu:Created>2019-05-07T06:27:59Z</wsu:Created>
</wsse:UsernameToken>
</wsse:Security>
</soap:Header>
<soap:Body>
<not:someMethod />
</soap:Body>
</soap:Envelope>

不幸的是,我总是得到 500 状态码和响应:

<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
<soap:Body>
<soap:Fault>
<soap:Code>
<soap:Value>soap:Sender</soap:Value>
<soap:Subcode>
<soap:Value xmlns:ns1="http://ws.apache.org/wss4j">ns1:SecurityError</soap:Value>
</soap:Subcode>
</soap:Code>
<soap:Reason>
<soap:Text xml:lang="en">A security error was encountered when verifying the message</soap:Text>
</soap:Reason>
</soap:Fault>
</soap:Body>
</soap:Envelope>

我很确定它是由于授权问题而出现的(如果提供了错误的凭据,我在 SoapUI 中会收到相同的消息)。

我的客户端中的部分是用以下内容创建的:

UsernameToken t = new UsernameToken("SOME_LOGIN", "SOME_PASSWORD", PasswordOption.SendHashed);
string usernameTokenSection = t.GetXml(new XmlDocument()).OuterXml.ToString();

有几篇文章如何创建密码数字(Base64(SHA1(密码+随机数+创建))),随机数(Base64(RandomString))或创建日期但我找不到什么是 wsu:Id="UsernameToken-2C1E2DE2B61EBB94E115572099598331" 以及如何创建它。上面我从 UsernameToken 获取 xml 的代码返回了完整的部分,所以我决定使用它,但我注意到它附加了 wsu:Id="SecurityToken-85707168-b5c6-47dc-93e9-45afa466fa2a"(而不是wsu:Id="UsernameToken-2C1E2DE2B61EBB94E115572099598331")。我可以更改名称并删除 - 字符,但没有任何改变,我仍然收到 500 内部服务器错误消息“验证消息时遇到安全错误”。

所以,我的问题是如何使用正确的 wsu:Id="UsernameToken-XXXXXXXXXXXXXXX" 数据生成 UsernameToken 部分?它是什么 - 只是随机字符串或一些基于用户名和密码创建的散列?

最佳答案

明白了!我注意到从 .NET 客户端发送的 SOAP 在 Nonce 节点中没有属性 EncodingType。代码稍作修改后:

UsernameToken t = new UsernameToken("SOME_LOGIN", "SOME_PASSWORD", PasswordOption.SendHashed);
string usernameTokenSection = t.GetXml(new XmlDocument()).OuterXml.ToString().Replace("<wsse:Nonce", "<wsse:Nonce EncodingType=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary\"");

一切正常!

.NET 客户端的完整代码:

public static void Execute()
{
UsernameToken usernameTokenSection = new UsernameToken("SOME_LOGIN", "SOME_PASSWORD", PasswordOption.SendHashed);

HttpWebRequest request = CreateWebRequest();
XmlDocument soapEnvelopeXml = new XmlDocument();
soapEnvelopeXml.LoadXml(@"<soap:Envelope xmlns:not=""http://existing-domain.com/op/integration/services"" xmlns:soap=""http://www.w3.org/2003/05/soap-envelope"">" +
"<soap:Header>" +
@"<wsse:Security 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"">"+
usernameTokenSection.GetXml(new XmlDocument()).OuterXml.ToString().Replace("<wsse:Nonce", "<wsse:Nonce EncodingType=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary\"") +
"</wsse:Security>" +
"</soap:Header>"+
"<soap:Body>"+
"<not:someMethod/>"+
"</soap:Body>"+
"</soap:Envelope>");

using (Stream stream = request.GetRequestStream())
{
soapEnvelopeXml.Save(stream);
}

using (WebResponse response = request.GetResponse())
{
using (StreamReader rd = new StreamReader(response.GetResponseStream()))
{
string soapResult = rd.ReadToEnd();
Console.WriteLine(soapResult);
}
}
}

public static HttpWebRequest CreateWebRequest()
{
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(@"http://192.168.100.101:8181/services/ws/SomeService");

webRequest.Method = "POST";
webRequest.Headers.Add("Accept-Encoding:gzip,deflate");
webRequest.ContentType = "application/soap+xml;charset=UTF-8;action=\"someMethod\"";
//NOTE: below it's not necessary
//webRequest.Host = "192.168.100.101:8181";
//webRequest.KeepAlive = true;
//webRequest.UserAgent = "Apache-HttpClient/4.1.1 (java 1.5)";

return webRequest;
}

static void Main(string[] args)
{
try
{
Execute();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
Console.ReadLine();
}

}

附言。要使用 UsernameToken 类,您必须使用 Microsoft.Web.Services2 引用,您可以从此处通过 Nuget 添加它:Microsoft.Web.Services2

PPS。我知道 Add Service Reference... 有更简单的方法,但它需要额外的类和修改才能在 Header 中创建 Security 节点,所以我决定发送原始 xml 并直接对其进行操作。

关于c# - 如何为 WS-Security 生成 UsernameToken?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56017114/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com