我正在尝试编写一个客户端来调用使用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;此邮件的收件人不理解该邮件,导致邮件无法处理。此错误通常表示此消息的发送方已启用接收方无法处理的通信协议。请确保客户端绑定的配置与服务的绑定一致。
如何更正此错误?鉴于我看到数据回来了,这似乎是一个配置问题。
答案 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>