Search code examples
c#kerberoswindows-authenticationasp.net-core-3.0

ASP.NET Core 3.0: How to forward an existing authentication to another request - double hop problem?


I've got the following scenario (all applications and services are using asp.net core 3.0 on Windows):

I have a client application that runs in the context of AppUser. It uses an HttpClient to send a request to WebServiceA that runs in the context of WebUser. The request uses Windows authentication.

    var credentialsCache = new CredentialCache { { uri, "Negotiate", CredentialCache.DefaultNetworkCredentials } };
    var handler = new HttpClientHandler { Credentials = credentialsCache };
    var httpClient = new HttpClient(handler);

In WebServiceA, the call is recieved correctly and it's authenticated: HttpContext.User.Identity.IsAuthenticated is true and HttpContext.User.Identity.Name is AppUser.

To be able to process the request, WebServiceA must send another request to WebServiceB. This request must also be authenticated as AppUser.

Currently I'm using the following code to create the HttpClient that makes the request to WebServiceB:

    var credentialsCache = new CredentialCache { { uri, "Negotiate", CredentialCache.DefaultNetworkCredentials } };
    HttpClientHandler handler = new HttpClientHandler
    {
        Credentials = credentialsCache,
        UseDefaultCredentials = true
    };
    HttpClient httpClient = new HttpClient(handler);

The problem is, the call is always authenticated as WebUser (who runs the service), NOT AppUser (who sent the request).

I thought the DefaultNetworkCredentials were always those of the authenticated user.

How can I send (from within a WebRequest) another WebRequest to another WebService that is authenticated with the same user who submitted the original request? Is there a way to pass the authentication from one WebService to another?

Regarding Kerberos and AD: WebServiceA and WebServiceB are running on different servers in the same domain. They are not hosted in IIS, but in a Windows Service.

I tried to set the SPN as described here: https://learn.microsoft.com/en-us/aspnet/core/security/authentication/windowsauth?view=aspnetcore-3.0&tabs=visual-studio

setspn -S HTTP/ServerA.domain domain\WebUser

Also tried: setspn -a WebServiceA/WebUser domain\WebUser

But without success.

After three days of web research and trying around, my head is spinning ... How do I get the UserCredentials into the second request? Or is it because of (a possibly wrong?) AD configuration (SPN) that the WebService always silently takes the credentials of the user who started the service?

I am grateful for every hint!

Steffi


Solution

  • An answer accepted by the OP in the comment involves impersonation. According to this blog entry it's possible in .Net Core using the WindowsIdentity.RunImpersonated:

    // The user to be impersonated
    var userToImpersonate = (WindowsIdentity)HttpContext.User.Identity;
    
    // Impersonating the current Windows user [HttpContext.User.Identity]...
    var result = await WindowsIdentity.RunImpersonated(
                                     userToImpersonate.AccessToken, async () =>
    {
        // This time WindowsIdentity.GetCurrent() will retrieve the impersonated
        // user with its claims...
        var impersonatedUser = WindowsIdentity.GetCurrent().Name;
    
        // Your business logic code here...  
    });