1
votes

I am trying to write a client to call a web service that uses WS-Security 1.1 . They provided a WSDL and I generated the code through Visual Studio.

(UPDATE) Here is the binding

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

Here is my request

<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">

Through Fiddler, I can see that the data I want is getting returned.

<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

However, in Visual Studio I get this error:

The header 'Security' from the namespace 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd' was not understood by the recipient of this message, causing the message to not be processed. This error typically indicates that the sender of this message has enabled a communication protocol that the receiver cannot process. Please ensure that the configuration of the client's binding is consistent with the service's binding.

How do I correct this error? Given that I see the data coming back, it seems like a configuration problem.

2
What does your client binding look like? Are you using basicHttpBinding or wsHttpBinding?Michael
I'm using basicHttpBinding. I just added the details to the question.beans
I have same problem with same error.Musketyr

2 Answers

0
votes

I found solutions, but I had to modified.

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

Use it:

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

If you have customBinding, your config have to be:

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