WCF-为oasis-200401-wss-username-token-profile-1.0创建带有时间戳和密码摘要
本文关键字:时间戳 密码 oasis-200401-wss-username-token-profile-1 创建 WCF- | 更新日期: 2023-09-27 18:21:30
目标是,通过使用WCF,连接到一个需要UserNameToken ws安全性的Web服务,该安全性由标准"oasis-200401-wss-soap-message-security-1.0"指定
完整规格可在此处找到http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0.pdf
关于如何创建令牌的例子很少,没有一个对我有用。当我发布这篇文章时,我已经找到了答案,但由于这并不容易,我把我找到的解决方案放在这里,希望它能得到改进。所以我马上回答。
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens;
using System.Security.Cryptography;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.ServiceModel.Security;
using System.ServiceModel.Channels;
using System.Text;
using System.Threading.Tasks;
namespace WSClient
{
//Create this custom credentials class to implement UserNameToken autentication
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.WSSecurity10);
}
}
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");
string phrase = Guid.NewGuid().ToString();
var nonce = Convert.ToBase64String(Encoding.UTF8.GetBytes(phrase));
SHA1CryptoServiceProvider sha1Hasher = new SHA1CryptoServiceProvider();
//Password_Digest = Base64 ( SHA-1 ( nonce + created + password ) )
string Password_Digest = Convert.ToBase64String(sha1Hasher.ComputeHash(Encoding.UTF8.GetBytes(phrase + createdStr + userToken.Password))); // pxLqPLCXU1EiUS+NnpRuCw==
var stringToWrite = string.Format(
"<{0}:UsernameToken u:Id='"" + token.Id +
"'" 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#PasswordDigest'">" +
Password_Digest + "</{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);
writer.WriteRaw(stringToWrite);
}
}
class Program
{
static void Main(string[] args)
{
try
{
//for invalid ssl server certificate
System.Net.ServicePointManager.ServerCertificateValidationCallback +=
(se, cert, chain, sslerror) =>
{
return true;
};
CustomBinding binding = new CustomBinding();
var security = TransportSecurityBindingElement.CreateUserNameOverTransportBindingElement();
security.IncludeTimestamp = true;
security.DefaultAlgorithmSuite = SecurityAlgorithmSuite.Basic256;
security.MessageSecurityVersion = MessageSecurityVersion.WSSecurity10WSTrust13WSSecureConversation13WSSecurityPolicy12BasicSecurityProfile10;
security.EnableUnsecuredResponse = true;
var encoding = new TextMessageEncodingBindingElement();
encoding.MessageVersion = MessageVersion.Soap11;
var transport = new HttpsTransportBindingElement();
transport.MaxReceivedMessageSize = 2000000;
binding.Elements.Add(security);
binding.Elements.Add(encoding);
binding.Elements.Add(transport);
WSClient.Proxy.TargetWS client = new Proxy.TargetWS(binding,
new EndpointAddress(Properties.Settings.Default.Url));
//change credential for the custom credentials instance
client.ChannelFactory.Endpoint.Behaviors.Remove<System.ServiceModel.Description.ClientCredentials>();
client.ChannelFactory.Endpoint.Behaviors.Add(new CustomCredentials());
client.ClientCredentials.UserName.UserName = Properties.Settings.Default.username;
client.ClientCredentials.UserName.Password = Properties.Settings.Default.password;
Proxy.Message message = new WSClient.Proxy.Message();
message.id = "whatever";
client.foo(message);
System.Console.Write("Success");
}
catch (Exception ex)
{
System.Console.Write(ex.Message);
}
}
}
}
有点粗放!
本质上,需要根据Oasys规范对令牌进行序列化。要做到这一点,需要以所提供的方式派生ClientCredentials、ClientCredentialsSecurityTokenManager和WSSecurityTokenSerializer。
关于绑定,不确定是否适用于所有情况,或者规范是否允许更改。