Ws-Security 1.1报头安全性无法理解

本文关键字:安全性 报头 Ws-Security | 更新日期: 2023-09-27 18:03:58

我正在尝试编写一个客户机来调用使用WS-Security 1.1的web服务。他们提供了WSDL,我通过Visual Studio生成代码。

(UPDATE)这是绑定

<basicHttpBinding>
    <binding name="BasicHttpBinding_IConnectService">
      <security mode="TransportWithMessageCredential" />
    </binding>
</basicHttpBinding>

这是我的请求

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
    <s:Header>
     ...
        <Security s:mustUnderstand="1" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
            <u:Timestamp u:Id="7c10648f-984d-4920-849e-b0afb586f871">
                <u:Created>2016-08-24T13:08:06.118Z</u:Created>
                <u:Expires>2016-08-24T14:08:06.118Z</u:Expires>
            </u:Timestamp>
            <o:UsernameToken>
                <o:Username>actualUsername</o:Username>
                <o:Password>realPassword</o:Password>
            </o:UsernameToken>
        </Security>
    </s:Header>
    <s:Body xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

通过Fiddler,我可以看到我想要的数据正在返回。

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
    <s:Header>
        <o:Security s:mustUnderstand="1" xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
            <u:Timestamp u:Id="_0">
                <u:Created>2014-05-02T14:02:46.988Z</u:Created>
                <u:Expires>2014-05-02T14:07:46.988Z</u:Expires>
            </u:Timestamp>
        </o:Security>
    </s:Header>
    <s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    ....
    The data I really want

然而,在Visual Studio中,我得到这个错误:

消息的接收者无法理解来自命名空间'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd'的标头'Security',导致消息不被处理。此错误通常表示此消息的发送方启用了接收方无法处理的通信协议。请确保客户端绑定的配置与服务的绑定一致。

如何纠正这个错误?鉴于我看到数据返回,这似乎是一个配置问题。

Ws-Security 1.1报头安全性无法理解

我找到了解决方案,但我必须修改。

public class CustomCredentials : ClientCredentials
{
    public CustomCredentials()
    { }
    protected CustomCredentials(CustomCredentials cc)
        : base(cc)
    { }
    public override System.IdentityModel.Selectors.SecurityTokenManager CreateSecurityTokenManager()
    {
        return new CustomSecurityTokenManager(this);
    }
    protected override ClientCredentials CloneCore()
    {
        return new CustomCredentials(this);
    }
}
public class CustomSecurityTokenManager : ClientCredentialsSecurityTokenManager
{
    public CustomSecurityTokenManager(CustomCredentials cred)
        : base(cred)
    { }
    public override System.IdentityModel.Selectors.SecurityTokenSerializer CreateSecurityTokenSerializer(System.IdentityModel.Selectors.SecurityTokenVersion version)
    {
        return new CustomTokenSerializer(System.ServiceModel.Security.SecurityVersion.WSSecurity11);
    }
}
public class CustomTokenSerializer : WSSecurityTokenSerializer
{
    public CustomTokenSerializer(SecurityVersion sv)
        : base(sv)
    { }
    protected override void WriteTokenCore(System.Xml.XmlWriter writer, System.IdentityModel.Tokens.SecurityToken token)
    {
        UserNameSecurityToken userToken = token as UserNameSecurityToken;
        string tokennamespace = "o";
        DateTime created = DateTime.UtcNow;
        string createdStr = created.ToString("yyyy-MM-ddThh:mm:ss.fffZ");
        Random r = new Random();
        var nonce = Convert.ToBase64String(Encoding.ASCII.GetBytes(GetSHA1String(created + r.Next().ToString())));

       // string password = GetSHA1String(nonce + createdStr + userToken.Password);
        writer.WriteRaw(string.Format(
        "<{0}:UsernameToken u:Id='"" + "UsernameToken-ABCD" +
        "'" xmlns:u='"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd'">" +
        "<{0}:Username>" + userToken.UserName + "</{0}:Username>" +
        "<{0}:Password Type='"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText'">" +
        userToken.Password + "</{0}:Password>" +
        "<{0}:Nonce EncodingType='"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary'">" +
        nonce + "</{0}:Nonce>" +
        "<u:Created>" + createdStr + "</u:Created></{0}:UsernameToken>", tokennamespace));
    }
    protected string GetSHA1String(string phrase)
    {
        UTF8Encoding encoder = new UTF8Encoding();
        SHA1CryptoServiceProvider sha1Hasher = new SHA1CryptoServiceProvider();
        byte[] hashedDataBytes = sha1Hasher.ComputeHash(encoder.GetBytes(phrase));
        return ByteArrayToString(hashedDataBytes);
    }
    protected String ByteArrayToString(byte[] inputArray)
    {
        StringBuilder output = new StringBuilder("");
        for (int i = 0; i < inputArray.Length; i++)
        {
            output.Append(inputArray[i].ToString("X2"));
        }
        return output.ToString();
    }
}
 public static YOURContractClient CreateRealTimeOnlineProxy(string url, string username, string password)
    {
        CustomBinding binding = new CustomBinding();
        var security = TransportSecurityBindingElement.CreateUserNameOverTransportBindingElement();
        security.IncludeTimestamp = false;
        security.DefaultAlgorithmSuite = SecurityAlgorithmSuite.Basic256;
        security.AllowInsecureTransport = true;
        security.MessageSecurityVersion = MessageSecurityVersion.WSSecurity10WSTrust13WSSecureConversation13WSSecurityPolicy12BasicSecurityProfile10;
        var encoding = new TextMessageEncodingBindingElement();
        encoding.MessageVersion = MessageVersion.Soap11;
        var transport = new HttpTransportBindingElement();
        transport.MaxReceivedMessageSize = 20000000; // 20 megs
        binding.Elements.Add(security);
        binding.Elements.Add(encoding);
        binding.Elements.Add(transport);
        YOURContractClient client = new YOURContractClient(binding, new EndpointAddress(url));
        client.ChannelFactory.Endpoint.Behaviors.Remove<System.ServiceModel.Description.ClientCredentials>();
        client.ChannelFactory.Endpoint.Behaviors.Add(new CustomCredentials());
        client.ClientCredentials.UserName.UserName = username;
        client.ClientCredentials.UserName.Password = password;
        return client;
    }

使用它:

 var cl = CreateRealTimeOnlineProxy(URL, USER_NAME, PASSWORD);

如果你有customBinding,你的配置必须是:

  <customBinding>
            <binding name="ImportsTaxPaySoap12Binding">
            <security includeTimestamp="true" 
                      authenticationMode="UserNameOverTransport" 
                      defaultAlgorithmSuite="Basic256" 
                      requireDerivedKeys="true"
                      messageSecurityVersion="WSSecurity10WSTrustFebruary2005WSSecu
                      reConversationFebruary2005WSSecurityPolicy11
                      BasicSecurityProfile10">
            </security>
            <textMessageEncoding messageVersion="Soap12"></textMessageEncoding>
            <httpsTransport maxReceivedMessageSize="2000000000" />
            </binding>
 </customBinding>