Update CredentialCache at runtime

41 Views Asked by At

I'm using DI for an HttpClient that uses a CredentialCache as it's a linux host that needs to authenticate to a Windows API. I'm setting the credentials as shown below, which works great.

My issue is that the service account's password is automatically rotated monthly. I can query that new password at runtime using the IAAM service that I call below, but I don't know how to replace the credential.

My thought was that when the HttpClient's get/send methods return a 401, then I could grab the new password and update.

But how do I update that credential cache at runtime?

public static Func<IServiceProvider, SocketsHttpHandler> CreateWindowsAuthHandler(string username, string domain) {
    return x => {
        var pwd = x.GetRequiredService<IAAM>().GetPasswordAsync(username).GetAwaiter().GetResult();

        return new SocketsHttpHandler {
            Credentials = new CredentialCache {
                { new(BaseAddress), "Negotiate", new(username, pwd, domain) }
            },
            PreAuthenticate = true,
            UseProxy = false
        };
    };
}

services.AddHttpClient<IMyClient, MyClient>()
    .ConfigurePrimaryHttpMessageHandler(x => CreateWindowAuthHandler("..", ".."));
1

There are 1 best solutions below

1
gorillapower On

Note See this bug preventing Credential updates when PreAuthenticate = true https://github.com/dotnet/runtime/issues/93340

One possible way is to use DelegatingHandler to override the CredentialsCache from the base.InnerHandler property which seems a bit dirty (assumes that innerHandler will always be SocketsHttpHandler).

public class OverridingHandler : DelegatingHandler
{
    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        if (base.InnerHandler is SocketsHttpHandler socketsHttpHandler)
        {
            CredentialCache newCredentials = GetCredentials();
            socketsHttpHandler.Credentials = newCredentials;
        }
        
        return await base.SendAsync(request, cancellationToken);
    }
}

and then do

 services.AddHttpClient<IMyClient, MyClient>()
    .AddHttpMessageHandler(new OverridingHandler());
    

Perhaps a better way is to create your own implementation of the ICredentials interface that can handle credential updates.

I saw an example implementation in this bug report https://github.com/dotnet/runtime/issues/93340 called CredentialPlugin.

Hopefully .NET team will provide a extensability point or add async methods on ICredentials to for updating credentials dynamically