Reputation: 1569
Context: Custom reverse proxy/API Gateway built in C# on top of IIS and IIS Rewrite-rules, making use of OWIN middleware.
Goal: I'd like the proxy to authenticate the incoming request first(this is easily configured in IIS). Having the identity available, an OWIN middleware should assert some things based on the authenticated user. Afterwards, however, the request should be sent to the backend API, which is also windows authenticated.
My attempted solution: Before sending the request further, the OWIN middleware should impersonate the authenticated identity, request a Kerberos ticket and put it to the Authorization header (as Negotiate XXXXX.....
).
Here's the code using C# standard libs:
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);
}
Here's an alternative implementation I tried, using 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);
}
Both implementations throw an exception, which boils down to the following Win32 error:
No credentials are available in the security package
Important info:
srv_ApiGateway
useAppPoolCredentials
in IIS is set to True
(otherwise IIS wouldn't be able to even authenticate the initial request using Kerberos)srv_ApiGateway
) is set up for delegation in AD to Trust this user for delegation to any service (Kerberos only)
WindowsIdentity.GetCurrent().ImpersonationLevel
inside the using
returns ImpersonationLevel.Impersonation
(this should proabably be Delegation
)Does anyone have any suggestions as to what might be causing this and how can I fix this double-hop reverse-proxy use-case? Any help is appreciated :)
Upvotes: 2
Views: 2965
Reputation: 1569
The reason the impersonation level was not set to Delegation
is due to invalid ticket. For some reason, Google Chrome would not request a delegation ticket for the user even though the domain is whitelisted (as per these docs). Trying with IE and then using Chrome worked, even though not really a solution.
Upvotes: 1