问题描述
我正在使用 C# 调用 Web 服务,使用 HttpClient 模拟使用 spnego.sourceforge.net 对现有的 java WebLogic Web 服务进行调用。我们将 Windows 机器称为“machinename.forest.company.com”,并将 url 称为“https://weblogicnode.forest.company.com:7772/form/index.jsp”。 WebLogic 服务正在使用用户“serviceid@forest.company.com”的密钥表文件 krb5.keytab。
当 spengo 尝试解码 Kerberos 令牌时,我收到错误“在 GSS-API 级别未指定失败(机制级别:校验和失败)”。
我知道将 UseDefaultCredentials 与 HttpClient 结合使用会在幕后生成 Kerberos 令牌,但我不知道它使用的是什么 SPN。
我已经设置了 SPN:
setspn -S HTTP/machinename.forest.company.com FOREST\SERVICEID
setspn -S HTTPS/machinename.forest.company.com FOREST\SERVICEID
我应该使用不同的 SPN 吗? (“HOST”?端口号?)
客户端需要知道keytab文件吗?如果我使用 Kerberos.NET 和 keytab 文件生成令牌,我还能进行模拟吗?
客户端代码为:
var identity = (WindowsIdentity)System.Security.Principal.WindowsPrincipal.Current.Identity; //asp.net
//var identity = WindowsIdentity.GetCurrent(); //console
using (identity.Impersonate())
{
using (System.Threading.ExecutionContext.SuppressFlow())
{
AppContext.SetSwitch("System.Net.Http.UseSocketsHttpHandler",false);
HttpClientHandler httpClientHandler = new HttpClientHandler
{
UseDefaultCredentials = true,AllowAutoRedirect = true,};
var cred = CredentialCache.DefaultCredentials.GetCredential(uri,"Negotiate");
using (var client = new HttpClient(httpClientHandler))
{
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls12;
var message = new HttpRequestMessage(HttpMethod.Get,uri);
foreach (var headerItem in headerItems)
{
message.Headers.Add(headerItem.Key,headerItem.Value);
}
var response = client.SendAsync(message).Result;
解决方法
我想通了。我需要在客户端上显式设置 SPN。
if (!System.Net.AuthenticationManager.CustomTargetNameDictionary.ContainsKey(uri.AbsoluteUri))
{
System.Net.AuthenticationManager.CustomTargetNameDictionary.Add(uri.AbsoluteUri,"HTTPS/weblogicnode.forest.company.com");
}
这里我使用的是 WebLogic 节点而不是机器名称,因此我将其设置为:
setspn -S HTTP/weblogicnode.forest.company.com FOREST\SERVICEID