【问题标题】:.NET Core ChannelFactory - Set a X509Certificate2 as Client Certificate.NET Core ChannelFactory - 将 X509Certificate2 设置为客户端证书
【发布时间】:2018-03-04 16:53:42
【问题描述】:

我需要将客户端证书(作为实例,而不是来自 Windows 证书存储)设置到我的 wcf 通道,但我总是得到异常:

System.InvalidOperationException: "对象是只读的。"

这很奇怪,因为这些属性有一个 setter 但如果我分配了 X509Certificate2 就会崩溃。

堆栈跟踪

System.InvalidOperationException
  HResult=0x80131509
  Nachricht = Object is read-only.
  Quelle = System.Private.ServiceModel
  Stapelüberwachung:
   at System.ServiceModel.Security.X509CertificateRecipientClientCredential.ThrowIfImmutable()
   at System.ServiceModel.Security.X509CertificateRecipientClientCredential.set_DefaultCertificate(X509Certificate2 value)

代码

var binding = new BasicHttpsBinding();
var endpoint = new EndpointAddress(new Uri("https://myservice.com"));
var channelFactory = new ChannelFactory<MyService>(binding, endpoint);
var serviceClient = channelFactory.CreateChannel();
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;

var token = GetToken(); // Just an method that reads a pfx from disk
channelFactory.Credentials.
    ServiceCertificate.DefaultCertificate = token.Certificate; // throws exception
channelFactory.Credentials.
    ClientCertificate.Certificate = token.Certificate; // throws exception too

更新 1

方法SetCertificate 抛出同样的System.InvalidOperationException: "Object is read-only." 异常。

using (X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser)) 
{
    store.Open(OpenFlags.ReadWrite);
    var x509Certificate2Collection = store.Certificates.Find(X509FindType.FindByThumbprint, token.Certificate.Thumbprint, false);
    if(x509Certificate2Collection.Count == 0)
        store.Add(token.Certificate);
}

channelFactory.Credentials.ClientCertificate.SetCertificate(StoreLocation.CurrentUser, StoreName.My,X509FindType.FindByThumbprint, token.Certificate.Thumbprint);

更新 2

X509CertificateRecipientClientCredential.cs 的实现很有趣。

public X509Certificate2 DefaultCertificate
{
    get
    {
        return _defaultCertificate;
    }
    set
    {
        ThrowIfImmutable();
        _defaultCertificate = value;
    }
}

internal void MakeReadOnly()
{
    _isReadOnly = true;
    this.Authentication.MakeReadOnly();
    if (_sslCertificateAuthentication != null)
    {
        _sslCertificateAuthentication.MakeReadOnly();
    }
}

private void ThrowIfImmutable()
{
    if (_isReadOnly)
    {
        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.Format(SR.ObjectIsReadOnly)));
    }
}

某事打电话给internal void MakeReadOnly(),让我的生活变得更加艰难。

【问题讨论】:

  • GetToken() 是什么?请阅读How to Askedit 您的问题以包含minimal reproducible example
  • @CamiloTerevinto 我将问题编辑得更清楚。
  • 如果您将var 替换为GetToken() 行中的实际类型,这将有所帮助。
  • 我记得有一个 ClientCertificate.SetCertificate(...) 方法,你在这里看到了吗?列出您尝试过的所有死胡同。
  • 你不知道是谁打电话的吗?因为原因也将指向解决它的方法。有很多方法可以设置这些证书和凭证类型。

标签: c# wcf asp.net-core client-certificates


【解决方案1】:

在阅读github上的ClientCredentials.cs时,我发现了MakeReadOnly()的方法。

channelFactory.CreateChannel() 的调用使 ClientCertificate 实例为只读,因此在更改语句的顺序后它可以工作!

使用 WCF 进行 ClientCertificate 身份验证:

var binding = new BasicHttpsBinding();
var endpoint = new EndpointAddress(new Uri("https://myservice.com"));
var channelFactory = new ChannelFactory<MyService>(binding, endpoint);
// Must set before CreateChannel()
channelFactory.Credentials.
    ClientCertificate.Certificate = token.Certificate;

var serviceClient = channelFactory.CreateChannel();
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-05-27
    • 1970-01-01
    • 2016-04-02
    • 2015-04-17
    • 2011-09-28
    • 2023-03-24
    相关资源
    最近更新 更多