Tempo limite do AcquireTokenAsync do Active Directory do KeyVault do Azure quando chamado de forma assíncrona
Eu configurei o Azure Keyvault no meu aplicativo Web ASP.Net MVC, seguindo o exemplo no MicrosoftHello Key Vault aplicativo de amostra.
O KeyVault do Azure (Active Directory) AuthenticationResult, por padrão, tem uma hora de validade. Portanto, após uma hora, você deve obter um novo token de autenticação. O KeyVault está funcionando conforme o esperado na primeira hora após a obtenção do meu primeiro token AuthenticationResult, mas após a expiração de 1 hora, ele falha ao obter um novo token.
Infelizmente, tive uma falha no meu ambiente de produção para que eu percebesse isso, pois nunca testei a última hora em desenvolvimento.
De qualquer forma, depois de mais de dois dias tentando descobrir o que havia de errado com o código do meu keyvault, encontrei uma solução que corrige todos os meus problemas - remova o código assíncrono -, mas parece muito hacky. Quero descobrir por que não estava funcionando em primeiro lugar.
Meu código fica assim:
public AzureEncryptionProvider() //class constructor
{
_keyVaultClient = new KeyVaultClient(GetAccessToken);
_keyBundle = _keyVaultClient
.GetKeyAsync(_keyVaultUrl, _keyVaultEncryptionKeyName)
.GetAwaiter().GetResult();
}
private static readonly string _keyVaultAuthClientId =
ConfigurationManager.AppSettings["KeyVaultAuthClientId"];
private static readonly string _keyVaultAuthClientSecret =
ConfigurationManager.AppSettings["KeyVaultAuthClientSecret"];
private static readonly string _keyVaultEncryptionKeyName =
ConfigurationManager.AppSettings["KeyVaultEncryptionKeyName"];
private static readonly string _keyVaultUrl =
ConfigurationManager.AppSettings["KeyVaultUrl"];
private readonly KeyBundle _keyBundle;
private readonly KeyVaultClient _keyVaultClient;
private static async Task<string> GetAccessToken(
string authority, string resource, string scope)
{
var clientCredential = new ClientCredential(
_keyVaultAuthClientId,
_keyVaultAuthClientSecret);
var context = new AuthenticationContext(
authority,
TokenCache.DefaultShared);
var result = context.AcquireToken(resource, clientCredential);
return result.AccessToken;
}
A assinatura do método GetAccessToken deve ser assíncrona para passar para o novo construtor KeyVaultClient; portanto, deixei a assinatura como assíncrona, mas removi a palavra-chave wait.
Com a palavra-chave wait lá, (do jeito que deveria ser e está na amostra):
private static async Task<string> GetAccessToken(string authority, string resource, string scope)
{
var clientCredential = new ClientCredential(_keyVaultAuthClientId, _keyVaultAuthClientSecret);
var context = new AuthenticationContext(authority, null);
var result = await context.AcquireTokenAsync(resource, clientCredential);
return result.AccessToken;
}
O programa funciona bem na primeira vez em que o executo. E por uma hora, o AcquireTokenAsync retorna o mesmo token de autenticação original, o que é ótimo. Porém, quando o token expirar, o AcquiteTokenAsync deverá obter um novo token com uma nova data de validade. E não - o aplicativo simplesmente trava. Nenhum erro retornado, nada.
Assim, chamar AcquireToken em vez de AcquireTokenAsync resolve o problema, mas não faço ideia do porquê. Você também notará que estou passando 'null' em vez de 'TokenCache.DefaultShared' para o construtor AuthenticationContext no meu código de exemplo com async. Isso é forçar o toke a expirar imediatamente em vez de após uma hora. Caso contrário, você terá que esperar uma hora para reproduzir o comportamento.
Consegui reproduzir isso novamente em um novo projeto MVC, então não acho que tenha algo a ver com o meu projeto específico. Qualquer insight seria apreciado. Mas, por enquanto, apenas não estou usando assíncrono.