上下文:使用OWIN中间件,在IIS和IIS Rewrite-rules之上以C#内置的自定义反向代理/ API网关。
目标:我希望代理首先对传入的请求进行身份验证(这很容易在IIS中配置)。有了身份可用,OWIN中间件应基于经过身份验证的用户声明某些内容。但是,此后,该请求应发送到后端API,也是经过Windows验证的。
我尝试的解决方案::在进一步发送请求之前,OWIN中间件应模拟经过身份验证的身份,请求Kerberos票证并将其放入Authorization标头(如Negotiate XXXXX.....
)。 / p>
以下是使用C#标准库的代码:
var identity = (WindowsIdentity) context.Request.User.Identity;
using (var impersonation = identity.Impersonate())
{
var spn = "HTTP/" + backendHostname; // e.g. HTTP/myapi.mydomain.com
var tokenProvider = new KerberosSecurityTokenProvider(spn, TokenImpersonationLevel.Impersonation);
var token = tokenProvider.GetToken(TimeSpan.FromMinutes(1)) as KerberosRequestorSecurityToken;
var ticketBytes = token.GetRequest();
var ticket = Convert.ToBase64String(ticketBytes);
context.Request.Headers.Append("Negotiate", ticket);
}
这是我尝试使用NSSPI的另一种实现方式:
var identity = (WindowsIdentity) context.Request.User.Identity;
using (var impersonation = identity.Impersonate())
{
var clientCredentials = new ClientCurrentCredential(PackageNames.Kerberos);
var client = new ClientContext(
clientCredentials,
"HTTP/" + backendHostname, // e.g. HTTP/myapi.mydomain.com
ContextAttrib.MutualAuth |
ContextAttrib.InitIdentify |
ContextAttrib.Confidentiality |
ContextAttrib.ReplayDetect |
ContextAttrib.SequenceDetect |
ContextAttrib.Connection |
ContextAttrib.Delegate
);
var clientStatus = client.Init(null, out var tokenBytes);
var token = Convert.ToBase64String(tokenBytes);
context.Request.Headers.Append("Negotiate", token);
}
两个实现都引发异常,归结为以下Win32错误:
安全软件包中没有可用的凭据
重要信息:
srv_ApiGateway
useAppPoolCredentials
设置为True
(否则IIS甚至无法使用Kerberos验证初始请求)srv_ApiGateway
),以便在AD中委派给Trust this user for delegation to any service (Kerberos only)
WindowsIdentity.GetCurrent().ImpersonationLevel
中的using
返回ImpersonationLevel.Impersonation
(可能应该是Delegation
)有人对导致此问题的原因有任何建议吗?如何解决这个双重跃点的反向代理用例?任何帮助表示赞赏:)
答案 0 :(得分:1)
未将模拟级别设置为Delegation
的原因是无效的票证。出于某些原因,即使该域已列入白名单(根据these docs),Google Chrome仍不会为该用户请求委派票证。尝试使用IE,然后再使用Chrome,即使不是真正的解决方案,也可以。