Ws-Security 1.1标题安全性未被理解

时间:2016-08-24 14:12:43

标签: c# web-services soap

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

(更新)这是绑定

<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中我收到此错误:

  

标题&#39;安全&#39;来自命名空间&#39; http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd&#39;此邮件的收件人不理解该邮件,导致邮件无法处理。此错误通常表示此消息的发送方已启用接收方无法处理的通信协议。请确保客户端绑定的配置与服务的绑定一致。

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

2 个答案:

答案 0 :(得分:0)

我找到了解决方案,但我不得不修改。

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);

答案 1 :(得分:0)

如果你有 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>