本文介绍了在发给WCF Web服务的SOAP消息中,如何将KeyIdentifier直接放在SecurityTokenReference中(内联,不使用参考令牌)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已成功通过SoapUI与WCF服务通信(已获得有关如何配置它的规范),但是在将这些设置复制到.NET应用程序时遇到了麻烦.事实证明,生成的SOAP消息(通过Fiddler窥视)的形状被Web服务拒绝,后者希望信封的布局更严格.

I'm successful in communicating with a WCF service via SoapUI (I was given specification on how to configure it), but I'm having trouble in copying those settings to .NET application. Turns out the shape of generated SOAP message (peeked via Fiddler) is being rejected by the web service, who expects a stricter layout of envelope.

我很近.在这张照片上...

I'm very close. On this picture...

...您可以看到三个SOAP消息:

... you can see three SOAP messages:

1..将X509SecurityTokenParameters.InclusionMode设置为AlwaysToRecipient

2..将X509SecurityTokenParameters.InclusionMode设置为Never

3..预期的安全令牌,已在SoapUI上进行了测试.

3. Expected security token, tested on SoapUI.

如何使用C#代码从第3点开始获得包络?我没有使用app.config文件,整个配置都在C#代码内部(但我并不致力于保持这种状态, 就这样发生了).当前代码:

How do I achieve envelope from point 3 using C# code? I'm not using app.config file, entire config is inside C# code (but I'm not dedicated on keeping it that way, it just happened). Current code:

using System;
using System.Net;
using System.Security.Cryptography.X509Certificates;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Security;
using System.ServiceModel.Security.Tokens;
using System.Text;



public class CustomAlgorithmSuite : SecurityAlgorithmSuite
{
    public override string DefaultAsymmetricKeyWrapAlgorithm    { get { return "http://www.w3.org/2000/09/xmldsig#dsa-sha1"; }}
    public override string DefaultAsymmetricSignatureAlgorithm  { get { return "http://www.w3.org/2000/09/xmldsig#dsa-sha1"; }}
    public override string DefaultCanonicalizationAlgorithm     { get { return "http://www.w3.org/2001/10/xml-exc-c14n#"; }}
    public override string DefaultDigestAlgorithm               { get { return "http://www.w3.org/2000/09/xmldsig#sha1"; }}
    public override string DefaultEncryptionAlgorithm           { get { return "http://www.w3.org/2001/04/xmlenc#aes256-cbc"; }}
    public override int    DefaultEncryptionKeyDerivationLength { get { return SecurityAlgorithmSuite.Default.DefaultEncryptionKeyDerivationLength; }}
    public override int    DefaultSignatureKeyDerivationLength  { get { return SecurityAlgorithmSuite.Default.DefaultSignatureKeyDerivationLength; }}
    public override int    DefaultSymmetricKeyLength            { get { return SecurityAlgorithmSuite.Default.DefaultSymmetricKeyLength; }}
    public override string DefaultSymmetricKeyWrapAlgorithm     { get { return "http://www.w3.org/2000/09/xmldsig#dsa-sha1"; }}
    public override string DefaultSymmetricSignatureAlgorithm   { get { return "http://www.w3.org/2000/09/xmldsig#dsa-sha1"; }}
    public override bool   IsAsymmetricKeyLengthSupported(int length) { return true; }
    public override bool   IsSymmetricKeyLengthSupported(int length)  { return true; }
}



class Program
{
    static void Main()
    {
        X509SecurityTokenParameters x509Params = new X509SecurityTokenParameters()
        {
            X509ReferenceStyle = X509KeyIdentifierClauseType.RawDataKeyIdentifier,
            InclusionMode      = SecurityTokenInclusionMode.AlwaysToRecipient,
            ReferenceStyle     = SecurityTokenReferenceStyle.External,
            RequireDerivedKeys = false
        };

        SecurityBindingElement security = new TransportSecurityBindingElement()
        {
            MessageSecurityVersion = MessageSecurityVersion.WSSecurity10WSTrust13WSSecureConversation13WSSecurityPolicy12BasicSecurityProfile10,
            DefaultAlgorithmSuite  = new CustomAlgorithmSuite()
        };
        security.EndpointSupportingTokenParameters.Endorsing.Add(x509Params);
        security.SetKeyDerivation(false);
        //security.IncludeTimestamp = false;

        TextMessageEncodingBindingElement encoding = new TextMessageEncodingBindingElement(MessageVersion.Soap11, Encoding.UTF8);
        HttpsTransportBindingElement transport = new HttpsTransportBindingElement();
        //transport.RequireClientCertificate = true;
        CustomBinding customBinding = new CustomBinding(security, encoding, transport);

        ServicePointManager.ServerCertificateValidationCallback = (a, b, c, d) => true;

        var twoCertificatesInOneFile = new X509Certificate2Collection();
        twoCertificatesInOneFile.Import("foo path", "foo cert pass", X509KeyStorageFlags.Exportable);
        someGeneratedServiceClass client = new someGeneratedServiceClass(customBinding, new EndpointAddress(new Uri("foo webservice address"), EndpointIdentity.CreateDnsIdentity(twoCertificatesInOneFile[0].FriendlyName)));
        client.ClientCredentials.ServiceCertificate.DefaultCertificate = twoCertificatesInOneFile[0];
        client.ClientCredentials.ClientCertificate.Certificate = twoCertificatesInOneFile[1];
        //client.Endpoint.Contract.ProtectionLevel = System.Net.Security.ProtectionLevel.None;
        client.ClientCredentials.UserName.UserName = "foo user";
        client.ClientCredentials.UserName.Password = "foo pass";

        client.someServiceCall("foo", "foo", false, out i1, out i2);
    }
}

推荐答案

我最终使用了InclusionMode = SecurityTokenInclusionMode.Never,然后劫持了邮件并手动替换了不正确的标签.

I ended up using InclusionMode = SecurityTokenInclusionMode.Never, then hijacked the message and replaced incorrect tags manually.

public class CustomProxy_portClient : GeneratedProxy_portClient
{
    public CustomProxy_portClient() : base()
    {
        Endpoint.Behaviors.Remove(typeof(ClientCredentials));
        Endpoint.Behaviors.Add(new CustomClientCredentials());
    }
}



class CustomClientCredentials : ClientCredentials
{
    public CustomClientCredentials() : base() { }
    public CustomClientCredentials(ClientCredentials ClientCredentials) : base(ClientCredentials) { }

    public override SecurityTokenManager CreateSecurityTokenManager()
    {
        return new CustomSecurityTokenManager(this);
    }

    protected override ClientCredentials CloneCore()
    {
        return new CustomClientCredentials(this);
    }
}



class CustomSecurityTokenManager : ClientCredentialsSecurityTokenManager
{
    public CustomSecurityTokenManager(ClientCredentials clientCredentials) : base(clientCredentials) { }

    public override SecurityTokenSerializer CreateSecurityTokenSerializer(SecurityTokenVersion version)
    {
        return new CustomWSSecurityTokenSerializer();
    }
}



class CustomWSSecurityTokenSerializer : WSSecurityTokenSerializer
{
    protected override void WriteKeyIdentifierClauseCore(XmlWriter writer, SecurityKeyIdentifierClause keyIdentifierClause)
    {
        string xml;
        using(MemoryStream ms = new MemoryStream())
        {
            XmlTextWriter tempWriter = new XmlTextWriter(ms, new UTF8Encoding(false));
            base.WriteKeyIdentifierClauseCore(tempWriter, keyIdentifierClause);
            xml = Encoding.UTF8.GetString(ms.ToArray());
        }
        XmlDocument originalKeyIdentifierClause = new XmlDocument();
        originalKeyIdentifierClause.LoadXml(xml);

        writer.WriteStartElement("SecurityTokenReference");
        writer.WriteElementString("KeyIdentifier", originalKeyIdentifierClause.InnerText);
        writer.WriteEndElement();
    }
}

这篇关于在发给WCF Web服务的SOAP消息中,如何将KeyIdentifier直接放在SecurityTokenReference中(内联,不使用参考令牌)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-15 23:40