![](/img/trans.png)
[英]How to configure a wcf service client to use both certificate and username credentials at the message level?
[英]Can't get certificate message credentials to work in my WCF service
我制作了一個承載WCF服務的控制台應用程序。 我現在正在嘗試對其進行修改。 這是目前有效的...
Program.cs :
namespace FileRetrievalPoC
{
class Program
{
static void Main(string[] args)
{
var address = "https://localhost:8000/FileRetrievalPoC";
Console.WriteLine("Starting a service at {0}...", address);
FileRetrievalService.Start(address, StoreLocation.LocalMachine, StoreName.TrustedPeople, "b7ba8f6e4c33ba55053f2e85898b383e40bf8ac9");
Console.WriteLine("Service started.");
Console.WriteLine("Press Enter to create a new proxy client and call the Get method.");
Console.WriteLine("Press Escape to end the application.");
while (true)
{
var key = Console.ReadKey();
if (key.Key == ConsoleKey.Enter)
{
var proxy = FileRetrievalService.Connect(address, "localhost", "username", "password");
Console.WriteLine("Read the following from the server: {0}", proxy.Get(@"C:\Users\User\Desktop\Document.txt"));
FileRetrievalService.CloseClients();
}
else if (key.Key == ConsoleKey.Escape)
break;
}
FileRetrievalService.CloseServer();
}
}
}
FileRetrievalService.cs :
class FileRetrievalService : IFileRetrieval
{
private static BasicHttpsBinding _binding = new BasicHttpsBinding()
{
HostNameComparisonMode = HostNameComparisonMode.Exact,
Security = new BasicHttpsSecurity()
{
Message = new BasicHttpMessageSecurity()
{
AlgorithmSuite = SecurityAlgorithmSuite.Basic256Sha256Rsa15,
ClientCredentialType = BasicHttpMessageCredentialType.UserName
},
Mode = BasicHttpsSecurityMode.TransportWithMessageCredential,
Transport = new HttpTransportSecurity()
{
ClientCredentialType = HttpClientCredentialType.Windows,
}
}
};
private static ChannelFactory<IFileRetrieval> _channelFactory;
private static ServiceHost _host;
public static void Start(string address, StoreLocation location, StoreName name, string thumbprint)
{
_host = new ServiceHost(typeof(FileRetrievalService));
_host.Credentials.ServiceCertificate.SetCertificate(location, name, X509FindType.FindByThumbprint, thumbprint);
_host.AddServiceEndpoint(typeof(IFileRetrieval), _binding, address);
_host.Open();
}
public static void CloseClients()
{
if (_channelFactory != null)
_channelFactory.Close();
_channelFactory = null;
}
public static void CloseServer()
{
if (_host != null)
_host.Close();
_host = null;
}
public static void CloseServerAndClients()
{
CloseServer();
CloseClients();
}
public static IFileRetrieval Connect(string address, string domain, string username, string password)
{
if (_channelFactory == null)
{
_channelFactory = new ChannelFactory<IFileRetrieval>(_binding, address);
_channelFactory.Credentials.UserName.UserName = domain + '\\' + username;
_channelFactory.Credentials.UserName.Password = password;
_channelFactory.Credentials.Windows.ClientCredential = new NetworkCredential(username, password, domain);
}
return _channelFactory.CreateChannel();
}
public string Get(string path)
{
return File.ReadAllText(path);
}
public void Set(string path, string contents)
{
File.WriteAllText(path, contents);
}
}
IFileRetrieval.cs :
[ServiceContract]
public interface IFileRetrieval
{
[OperationContract]
string Get(string path);
[OperationContract]
void Set(string path, string contents);
}
以上所有代碼均有效,因為:
ClientCredentialType = BasicHttpMessageCredentialType.UserName
。 _channelFactory.Credentials.UserName
對象上設置用戶名憑據。 我想增加安全性,並讓客戶端在連接到服務器時也提供SSL證書。 為了嘗試執行此操作,我在代碼中用以下邏輯替換了點1和2:
ClientCredentialType = BasicHttpMessageCredentialType.Certificate
而不是ClientCredentialType = BasicHttpMessageCredentialType.UserName
。 Connect
方法中,我現在設置了客戶端的證書( _channelFactory.Credentials.ClientCertificate.SetCertificate(location, name, X509FindType.FindByThumbprint, thumbprint);
),並修改了該方法以采用適當的證書信息( StoreLocation location, StoreName name, string thumbprint
)傳遞完全相同的參數,以從客戶端引用從服務器端提供的相同證書。 我已經刪除了設置_channelFactory.Credentials.UserName
對象的先前邏輯。 這不起作用,並且出現以下異常:
接收到來自另一方的不安全或不正確安全的故障。 有關錯誤代碼和詳細信息,請參見內部FaultException。
其內部異常表示:
驗證消息的安全性時發生錯誤。
一個人從這里去哪里? 我沒有使用IIS,那么如何進一步跟蹤此錯誤? 我有點茫然。 我希望有人可以解釋什么地方出了問題,以及如何解決該錯誤或進一步對其進行調試。
編輯 :我想出了一種進一步調試它的方法,但是它並沒有比我想象的有用得多。 在我的App.config
,添加了以下跟蹤:
<system.diagnostics>
<sources>
<source name="System.ServiceModel" switchValue="Verbose, ActivityTracing" propagateActivity="true">
<listeners>
<add name="listener" type="System.Diagnostics.XmlWriterTraceListener" initializeData= "C:\Users\YourAccountUsername\Desktop\WCFTraces.svclog" />
</listeners>
</source>
<source name="System.ServiceModel.MessageLogging" switchValue="Verbose, ActivityTracing" propagateActivity="true">
<listeners>
<add name="listener" type="System.Diagnostics.XmlWriterTraceListener" initializeData= "C:\Users\YourAccountUsername\Desktop\WCFTraces.svclog" />
</listeners>
</source>
</sources>
</system.diagnostics>
現在在WCFTraces.svclog
內部,我也從服務器端看到了很多異常。 第一個是:
安全處理器無法在消息中找到安全標頭。 這可能是因為該消息是不安全的故障,或者是由於通信雙方之間存在綁定不匹配。 如果將服務配置為具有安全性,並且客戶端未使用安全性,則會發生這種情況。
考慮到我已經指定了客戶端證書,我不確定為什么該消息沒有安全標頭。 客戶端代碼丟失了什么?
編輯 :啊,我也看到此錯誤:
密鑰大小為'8192'的'System.IdentityModel.Tokens.X509SecurityToken'令牌不滿足'Basic256Sha256Rsa15'算法套件的密鑰大小要求。
它的接收字節不足。 我的證書具有8192字節的私鑰和公鑰,但這不能與我選擇的AlgorithmSuite = SecurityAlgorithmSuite.Basic256Sha256Rsa15
很好地匹配。 有人知道我在這里應該怎么允許這個證書嗎? 我可以嘗試為此使用256位密鑰...還是我的證書上的簽名算法是512位的問題?
我終於知道了。 錯誤使我誤入了一條黑暗的道路,但現在我明白了。
問題
這似乎是一條未成文的規則。 當您指定Mode = BasicHttpsSecurityMode.TransportWithMessageCredential
告訴它同時使用消息和傳輸憑據時,然后使用證書作為消息憑據,
Message = new BasicHttpMessageSecurity()
{
AlgorithmSuite = SecurityAlgorithmSuite.Basic256Sha256Rsa15,
ClientCredentialType = BasicHttpMessageCredentialType.Certificate
}
如果證書的密鑰超過4096位,則不能使用證書作為消息憑據。
解決方案
我使用SHA 512作為簽名算法,使用4096位RSA密鑰對制作了一個新的自簽名證書。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.