99using System . Text . RegularExpressions ;
1010using System . Threading . Tasks ;
1111
12- using Microsoft . Azure . KeyVault ;
13- using Microsoft . Azure . KeyVault . Models ;
14- using Microsoft . Azure . Services . AppAuthentication ;
12+ using Azure ;
13+ using Azure . Identity ;
14+ using Azure . Security . KeyVault . Secrets ;
1515
1616namespace Microsoft . Configuration . ConfigurationBuilders
1717{
@@ -35,7 +35,7 @@ public class AzureKeyVaultConfigBuilder : KeyValueConfigBuilder
3535 private bool _preload ;
3636 private bool _preloadFailed ;
3737
38- private KeyVaultClient _kvClient ;
38+ private SecretClient _kvClient ;
3939 private List < string > _allKeys ;
4040
4141 /// <summary>
@@ -58,6 +58,8 @@ protected override void LazyInitialize(string name, NameValueCollection config)
5858 _uri = UpdateConfigSettingWithAppSettings ( uriTag ) ;
5959 _vaultName = UpdateConfigSettingWithAppSettings ( vaultNameTag ) ;
6060 _version = UpdateConfigSettingWithAppSettings ( versionTag ) ;
61+ if ( String . IsNullOrWhiteSpace ( _version ) )
62+ _version = null ;
6163
6264 if ( String . IsNullOrWhiteSpace ( _uri ) )
6365 {
@@ -83,8 +85,7 @@ protected override void LazyInitialize(string name, NameValueCollection config)
8385 // Connect to KeyVault
8486 try
8587 {
86- AzureServiceTokenProvider tokenProvider = new AzureServiceTokenProvider ( _connectionString ) ;
87- _kvClient = new KeyVaultClient ( new KeyVaultClient . AuthenticationCallback ( tokenProvider . KeyVaultTokenCallback ) ) ;
88+ _kvClient = new SecretClient ( new Uri ( _uri ) , new DefaultAzureCredential ( ) ) ;
8889 }
8990 catch ( Exception )
9091 {
@@ -130,10 +131,10 @@ public override ICollection<KeyValuePair<string, string>> GetAllValues(string pr
130131 {
131132 // Azure Key Vault keys are case-insensitive, so there shouldn't be any races here.
132133 // Include version information. It will get filtered out later before updating config.
133- SecretBundle secret = t . Result ;
134+ KeyVaultSecret secret = t . Result ;
134135 if ( secret != null )
135136 {
136- string versionedKey = key + "/" + ( secret . SecretIdentifier . Version ?? "0" ) ;
137+ string versionedKey = key + "/" + ( secret . Properties ? . Version ?? "0" ) ;
137138 d [ versionedKey ] = secret . Value ;
138139 }
139140 } ) ) ) ;
@@ -184,31 +185,36 @@ public override string UpdateKey(string rawKey)
184185 return new VersionedKey ( rawKey ) . Key ;
185186 }
186187
187- private async Task < SecretBundle > GetValueAsync ( string key )
188+ private async Task < KeyVaultSecret > GetValueAsync ( string key )
188189 {
189190 if ( _kvClient == null )
190191 return null ;
191192
192193 VersionedKey vKey = new VersionedKey ( key ) ;
193194
195+ // If we successfully preloaded key names, see if the requested key is valid before making network request.
194196 if ( ! _preload || _preloadFailed || _allKeys . Contains ( vKey . Key , StringComparer . OrdinalIgnoreCase ) )
195197 {
196198 try
197199 {
198- string version = ! String . IsNullOrWhiteSpace ( _version ) ? _version : vKey . Version ;
200+ string version = _version ?? vKey . Version ;
199201 if ( version != null )
200202 {
201- SecretBundle versionedSecret = await _kvClient . GetSecretAsync ( _uri , vKey . Key , version ) ;
203+ KeyVaultSecret versionedSecret = await _kvClient . GetSecretAsync ( vKey . Key , version ) ;
202204 return versionedSecret ;
203205 }
204206
205- SecretBundle secret = await _kvClient . GetSecretAsync ( _uri , vKey . Key ) ;
207+ KeyVaultSecret secret = await _kvClient . GetSecretAsync ( vKey . Key ) ;
206208 return secret ;
207209 }
208- catch ( KeyVaultErrorException kve )
210+ catch ( RequestFailedException rfex )
209211 {
210212 // Simply return null if the secret wasn't found
211- if ( kve . Body . Error . Code == "SecretNotFound" || kve . Body . Error . Code == "BadParameter" )
213+ //if (rfex.ErrorCode == "SecretNotFound" || rfex.ErrorCode == "BadParameter")
214+ // .ErrorCode doesn't get populated. :/
215+ // "SecretNotFound" == 404
216+ // "BadParameter" = 400
217+ if ( rfex . Status == 404 || rfex . Status == 400 )
212218 return null ;
213219
214220 // If there was a permission issue or some other error, let the exception bubble
@@ -230,35 +236,25 @@ private List<string> GetAllKeys()
230236
231237 try
232238 {
233- // Get first page of secret keys
234- var allSecrets = Task . Run ( async ( ) => { return await _kvClient . GetSecretsAsync ( _uri ) ; } ) . Result ;
235- foreach ( var secretItem in allSecrets )
236- keys . Add ( secretItem . Identifier . Name ) ;
237-
238- // If there more more pages, get those too
239- string nextPage = allSecrets . NextPageLink ;
240- while ( ! String . IsNullOrWhiteSpace ( nextPage ) )
239+ foreach ( SecretProperties secretProps in _kvClient . GetPropertiesOfSecrets ( ) )
241240 {
242- var moreSecrets = Task . Run ( async ( ) => { return await _kvClient . GetSecretsNextAsync ( nextPage ) ; } ) . Result ;
243- foreach ( var secretItem in moreSecrets )
244- keys . Add ( secretItem . Identifier . Name ) ;
245- nextPage = moreSecrets . NextPageLink ;
241+ // Don't include disabled secrets
242+ if ( ! secretProps . Enabled . GetValueOrDefault ( ) )
243+ continue ;
244+
245+ keys . Add ( secretProps . Name ) ;
246246 }
247247 }
248- catch ( AggregateException ae )
248+ catch ( RequestFailedException rfex )
249249 {
250- ae . Handle ( ex =>
251- {
252- var exAsKve = ex as KeyVaultErrorException ;
253- // If List Permission on Secrets in not available return empty list of keys
254- if ( exAsKve != null && exAsKve . Body . Error . Code == "Forbidden" )
255- {
256- _preloadFailed = true ;
257- return true ;
258- }
259- else
260- return Optional ; // False == throw.
261- } ) ;
250+ _preloadFailed = true ;
251+
252+ // If List Permission on Secrets in not available return empty list of keys
253+ if ( rfex . ErrorCode == "Forbidden" )
254+ return keys ;
255+
256+ if ( ! Optional )
257+ throw ;
262258 }
263259
264260 return keys ;
0 commit comments