簡體   English   中英

如何為WS-Security生成UsernameToken?

[英]How to generate UsernameToken for WS-Security?

我有一些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();

有一些關於如何創建PasswordDigits( Base64(SHA1(密碼+ nonce +創建)) ),Nonce( 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();
        }

}

PS。 要使用UsernameToken類,您必須使用Microsoft.Web.Services2引用,您可以從這里添加Nuget: Microsoft.Web.Services2

PPS。 我知道Add Service Reference...有更簡單的方法Add Service Reference...但它需要額外的類和修改來在Header創建Security節點,所以我決定發送原始xml並直接操作它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM