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

关于如何创建令牌的例子很少,没有一个对我有用。当我发布这篇文章时,我已经找到了答案,但由于这并不容易,我把我找到的解决方案放在这里,希望它能得到改进。所以我马上回答。

WCF-为oasis-200401-wss-username-token-profile-1.0创建带有时间戳和密码摘要

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。

关于绑定,不确定是否适用于所有情况,或者规范是否允许更改。