public AzureAppConfigurationProvider(ConfigurationClient client, AzureAppConfigurationOptions options, bool optional) { _client = client ?? throw new ArgumentNullException(nameof(client)); _options = options ?? throw new ArgumentNullException(nameof(options)); _optional = optional; IEnumerable <KeyValueWatcher> watchers = options.ChangeWatchers.Union(options.MultiKeyWatchers); if (watchers.Any()) { MinCacheExpirationTime = watchers.Min(w => w.CacheExpirationTime); } else { MinCacheExpirationTime = AzureAppConfigurationRefreshOptions.DefaultCacheExpirationTime; } // Enable request tracing if not opt-out string requestTracingDisabled = null; try { requestTracingDisabled = Environment.GetEnvironmentVariable(RequestTracingConstants.RequestTracingDisabledEnvironmentVariable); } catch (SecurityException) { } _requestTracingEnabled = bool.TryParse(requestTracingDisabled, out bool tracingDisabled) ? !tracingDisabled : true; if (_requestTracingEnabled) { _hostType = TracingUtils.GetHostType(); } }
/// <summary> /// An implementation of <see cref="IOfflineCache.Import(AzureAppConfigurationOptions)"/> that retrieves the cached data from the file system. /// </summary> public string Import(AzureAppConfigurationOptions options) { EnsureOptions(options); int retry = 0; while (retry++ <= retryMax) { try { string data = null, dataHash = null, scopeHash = null; byte[] bytes = File.ReadAllBytes(_localCachePath); var reader = new Utf8JsonReader(bytes); while (reader.Read()) { if (reader.TokenType == JsonTokenType.PropertyName) { switch (reader.GetString()) { case dataProp: data = reader.ReadAsString(); break; case hashProp: dataHash = reader.ReadAsString(); break; case scopeProp: scopeHash = reader.ReadAsString(); break; default: return(null); } } } if ((data != null) && (dataHash != null) && (scopeHash != null)) { string newScopeHash = CryptoService.GetHash(Encoding.UTF8.GetBytes(_scopeToken), _options.SignKey); if (string.CompareOrdinal(scopeHash, newScopeHash) == 0) { string newDataHash = CryptoService.GetHash(Convert.FromBase64String(data), _options.SignKey); if (string.CompareOrdinal(dataHash, newDataHash) == 0) { return(CryptoService.AESDecrypt(data, _options.Key, _options.IV)); } } } } catch (IOException ex) when(ex.HResult == ERROR_SHARING_VIOLATION) { Task.Delay(new Random().Next(delayRange)).ConfigureAwait(false).GetAwaiter().GetResult(); } } return(null); }
public AzureAppConfigurationSource(Action <AzureAppConfigurationOptions> optionsInitializer, bool optional = false, IConfigurationClientFactory configurationClientFactory = null) { _optionsProvider = () => { var options = new AzureAppConfigurationOptions(); optionsInitializer(options); return(options); }; _optional = optional; _configurationClientFactory = configurationClientFactory ?? new ConfigurationClientFactory(); }
private void EnsureOptions(AzureAppConfigurationOptions azconfigOptions) { if (azconfigOptions == null) { throw new ArgumentNullException(nameof(azconfigOptions)); } if (azconfigOptions.ConnectionString == null) { throw new InvalidOperationException("An Azure App Configuration connection string is required."); } OfflineFileCacheOptions options = _options ?? new OfflineFileCacheOptions(); if ((options.Key == null) || (options.SignKey == null) || (options.IV == null)) { byte[] secret = Convert.FromBase64String(ConnectionStringParser.Parse(azconfigOptions.ConnectionString, "Secret")); using (SHA256 sha256 = SHA256.Create()) { byte[] hash = sha256.ComputeHash(secret); options.Key = options.Key ?? hash; options.SignKey = options.SignKey ?? hash; options.IV = options.IV ?? hash.Take(16).ToArray(); } } if (string.IsNullOrEmpty(_scopeToken)) { // // The default scope token is the configuration store endpoint combined with all of the key-value filters string endpoint = ConnectionStringParser.Parse(azconfigOptions.ConnectionString, "Endpoint"); if (string.IsNullOrWhiteSpace(endpoint)) { throw new InvalidOperationException("Invalid connection string format."); } var sb = new StringBuilder($"{endpoint}\0"); foreach (var selector in azconfigOptions.KeyValueSelectors) { sb.Append($"{selector.KeyFilter}\0{selector.LabelFilter}\0"); } _scopeToken = sb.ToString(); } _options = options; }
public AzureAppConfigurationProvider(ConfigurationClient client, AzureAppConfigurationOptions options, bool optional) { _client = client ?? throw new ArgumentNullException(nameof(client)); _options = options ?? throw new ArgumentNullException(nameof(options)); _optional = optional; // Enable request tracing if not opt-out string requestTracingDisabled = null; try { requestTracingDisabled = Environment.GetEnvironmentVariable(RequestTracingConstants.RequestTracingDisabledEnvironmentVariable); } catch (SecurityException) { } _requestTracingEnabled = bool.TryParse(requestTracingDisabled, out bool tracingDisabled) ? !tracingDisabled : true; if (_requestTracingEnabled) { _hostType = TracingUtils.GetHostType(); } }
/// <summary> /// An implementation of <see cref="IOfflineCache.Export(AzureAppConfigurationOptions, string)"/> that caches the data in the file system. /// </summary> public void Export(AzureAppConfigurationOptions options, string data) { EnsureOptions(options); if ((DateTime.Now - File.GetLastWriteTime(_localCachePath)) > TimeSpan.FromMilliseconds(1000)) { Task.Run(async() => { string tempFile = Path.Combine(Path.GetDirectoryName(_localCachePath), $"azconfigTemp-{Path.GetRandomFileName()}"); var dataBytes = Encoding.UTF8.GetBytes(data); var encryptedBytes = CryptoService.AESEncrypt(dataBytes, _options.Key, _options.IV); var dataHash = CryptoService.GetHash(encryptedBytes, _options.SignKey); var scopeHash = CryptoService.GetHash(Encoding.UTF8.GetBytes(_scopeToken), _options.SignKey); using (var fileStream = new FileStream(tempFile, FileMode.Create)) { using (var memoryStream = new MemoryStream()) { using (var writer = new Utf8JsonWriter(memoryStream)) { writer.WriteStartObject(); writer.WriteString(dataProp, Convert.ToBase64String(encryptedBytes)); writer.WriteString(hashProp, dataHash); writer.WriteString(scopeProp, scopeHash); writer.WriteEndObject(); } memoryStream.Position = 0; memoryStream.CopyTo(fileStream); fileStream.Flush(); } } await this.DoUpdate(tempFile).ConfigureAwait(false); }); } }
public IConfigurationProvider Build(IConfigurationBuilder builder) { IConfigurationProvider provider = null; try { AzureAppConfigurationOptions options = _optionsProvider(); ConfigurationClient client; if (options.Client != null) { client = options.Client; } else if (!string.IsNullOrWhiteSpace(options.ConnectionString)) { client = _configurationClientFactory.CreateConfigurationClient(options.ConnectionString, options.ClientOptions); } else if (options.Endpoint != null && options.Credential != null) { client = _configurationClientFactory.CreateConfigurationClient(options.Endpoint, options.Credential, options.ClientOptions); } else { throw new ArgumentException($"Please call {nameof(AzureAppConfigurationOptions)}.{nameof(AzureAppConfigurationOptions.Connect)} to specify how to connect to Azure App Configuration."); } provider = new AzureAppConfigurationProvider(client, options, _optional); } catch (InvalidOperationException e) { if (!_optional) { throw new ArgumentException(e.Message, e); } } return(provider ?? new EmptyConfigurationProvider()); }