4
votes

I've successfully managed to list all of the secrets in an Azure KeyVault - however I need to make a call to get a token each time I want to get the next secret.

How do I store the credentials so I only have to login once during the loop?

    public async Task<List<string>> getsecretslist(string url)
    {

        var kv = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(GetToken));

        List<string> secretlist = new List<string>(); 
        var all = kv.GetSecretsAsync(url);
        var myId = "";
        foreach (Microsoft.Azure.KeyVault.Models.SecretItem someItem in all.Result)
        {
            myId = someItem.Id;
            var mOtherThing = someItem.Identifier;
            var yep = await kv.GetSecretAsync(mOtherThing.ToString());
            secretlist.Add(yep.Value);
        }

        return secretlist;
    }
3

3 Answers

8
votes

In your GetToken callback method you need to cache the access token as long as it is valid and not expired. Then your callback will return the cached access token instead of doing the authentication again. The following code snippet will use the ADAL default token cache (e.g. TokenCache.DefaultShared).

public static async Task<string> GetToken(string authority, string resource, string scope)
{
    var assertionCert = new ClientAssertionCertificate(clientId, certificate);
    var context = new AuthenticationContext(authority, TokenCache.DefaultShared);
    var result = await context.AcquireTokenAsync(resource, assertionCert).ConfigureAwait(false);

    return result.AccessToken;
}
1
votes

The best way that i found is to save the token you obtained in your GetToken function, for example:

var authenticationContext = new AuthenticationContext(authority, TokenCache.DefaultShared);

var authenticationResult = await authenticationContext.AcquireTokenAsync(resource, KeyVaultUserClientId, new Uri(KeyVaultRedirectUri), new PlatformParameters(PromptBehavior.SelectAccount)).ConfigureAwait(false);

return authenticationResult.AccessToken;

Then i simply altered the getter for the client so it will check for the expiry, if its still valid (should have expiration of 60 minutes) it will return a simpler client which returns the lastAuthenticationResult

private static KeyVaultClient KeyVaultClient
{
    get
    {
        if (lastAuthenticationResult != null && DateTime.UtcNow.AddSeconds(5) < lastAuthenticationResult.ExpiresOn)
        {
            if (m_cachedKeyVaultClient != null)
            {
                return m_cachedKeyVaultClient;
            }
            else
            {
                return new KeyVaultClient(getCachedToken);
            }
        }

        if (m_keyVaultClient == null)
            m_keyVaultClient = new KeyVaultClient(GetAccessTokenAsync);

        return m_keyVaultClient;
    }
}


private static async Task<string> getCachedToken(string authority, string resource, string scope)
{
    return lastAuthenticationResult.AccessToken;
}
0
votes

You don't need to call GetSecretAsync inside your loop. The secrets are already included in your Result set from calling GetSecretsAsync. This is why you are being authenticated repeatedly.

Here is a simple change to your loop to do what you are looking for.

var all = kv.GetSecretsAsync(url).GetAwaiter().GetResult();
foreach (var secret in all.Value)
{
    secretlist.Add(secret.Id);
}