valorl
valorl

Reputation: 1569

No credentials in security package when requesting a Kerberos ticket while impersonating another user

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:

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

Answers (1)

valorl
valorl

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

Related Questions