1

上下文:在 IIS 和 IIS 重写规则之上用 C# 构建的自定义反向代理/API 网关,利用 OWIN 中间件。

目标:我希望代理首先对传入请求进行身份验证(这在 IIS 中很容易配置)。有了可用的身份,OWIN 中间件应该根据经过身份验证的用户声明一些事情。然而,之后,请求应该被发送到后端 API,这也是 windows 认证的。

我尝试的解决方案:在进一步发送请求之前,OWIN 中间件应该模拟经过身份验证的身份,请求 Kerberos 票证并将其放入 Authorization 标头(as Negotiate XXXXX.....)。

这是使用 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 错误:

安全包中没有可用的凭据

重要信息:

  • 代理托管在 IIS 中,在服务帐户下运行(假设srv_ApiGateway
  • useAppPoolCredentials在 IIS 中设置为True(否则 IIS 甚至无法使用 Kerberos 对初始请求进行身份验证)
  • 服务帐户 ( srv_ApiGateway) 在 AD 中设置为委派给Trust this user for delegation to any service (Kerberos only)
  • 在这两种实现中,删除模拟并在服务帐户工作时简单地请求票证(仅供参考)
  • 代理和后端 API 都有适当的 SPN(直接请求使用 Kerberos 正确验证)。
  • WindowsIdentity.GetCurrent().ImpersonationLevelusing回报内ImpersonationLevel.Impersonation(这应该是可能的Delegation

是否有人对可能导致此问题的原因以及如何解决此双跳反向代理用例有任何建议?任何帮助表示赞赏:)

4

1 回答 1

1

未设置模拟级别的原因Delegation是票证无效。出于某种原因,即使域被列入白名单(根据这些文档),谷歌浏览器也不会为用户请求委托票。尝试使用 IE,然后使用 Chrome,即使不是真正的解决方案。

于 2018-09-10T09:41:41.617 回答