diff --git a/src/service/API/Microsoft.FeatureFlighting.API.csproj b/src/service/API/Microsoft.FeatureFlighting.API.csproj index b92b30f..3d5b7a9 100644 --- a/src/service/API/Microsoft.FeatureFlighting.API.csproj +++ b/src/service/API/Microsoft.FeatureFlighting.API.csproj @@ -30,9 +30,11 @@ - - - + + + + + diff --git a/src/service/API/Program.cs b/src/service/API/Program.cs index 84cded3..bab153a 100644 --- a/src/service/API/Program.cs +++ b/src/service/API/Program.cs @@ -9,6 +9,7 @@ using Autofac.Extensions.DependencyInjection; using Azure.Extensions.AspNetCore.Configuration.Secrets; using Microsoft.Extensions.Configuration.AzureAppConfiguration; +using Azure.Core; namespace Microsoft.PS.Services.FlightingService.Api { @@ -16,7 +17,7 @@ namespace Microsoft.PS.Services.FlightingService.Api public static class Program { public static void Main(string[] args) - { + { CreateHostBuilder(args).Build().Run(); } @@ -37,12 +38,19 @@ public static IHostBuilder CreateHostBuilder(string[] args) private static void AddKeyVault(IConfigurationBuilder config) { - var builtConfig = config.Build(); + var builtConfig = config.Build(); + TokenCredential credential; + #if DEBUG + credential = new VisualStudioCredential(); + #else + credential = new ManagedIdentityCredential( + ManagedIdentityId.FromUserAssignedClientId(builtConfig["UserAssignedClientId"])); + #endif config.AddAzureKeyVault( new SecretClient( new Uri(builtConfig["KeyVault:EndpointUrl"]), - credential: new DefaultAzureCredential() + credential ), new AzureKeyVaultConfigurationOptions() { @@ -58,12 +66,19 @@ private static void AddAzureAppConfiguration(IConfigurationBuilder config) string appConfigurationUri = builtConfig["AzureAppConfigurationUri"]; string flightingAppConfigLabel = builtConfig["AppConfiguration:FeatureFlightsLabel"]; string configurationCommonLabel = builtConfig["AppConfiguration:ConfigurationCommonLabel"]; - string configurationEnvLabel = builtConfig["AppConfiguration:ConfigurationEnvLabel"]; + string configurationEnvLabel = builtConfig["AppConfiguration:ConfigurationEnvLabel"]; + TokenCredential credential; + #if DEBUG + credential = new VisualStudioCredential(); + #else + credential = new ManagedIdentityCredential( + ManagedIdentityId.FromUserAssignedClientId(builtConfig["UserAssignedClientId"])); + #endif config.AddAzureAppConfiguration(options => { options - .Connect(new Uri(appConfigurationUri),new DefaultAzureCredential()) + .Connect(new Uri(appConfigurationUri), credential) .UseFeatureFlags(configure => { configure.Label = flightingAppConfigLabel; diff --git a/src/service/API/appsettings.fxp-preprod.json b/src/service/API/appsettings.fxp-preprod.json index 4fbc948..1c54228 100644 --- a/src/service/API/appsettings.fxp-preprod.json +++ b/src/service/API/appsettings.fxp-preprod.json @@ -12,5 +12,6 @@ "Name": "kv-exp-ppe-eus", "EndpointUrl": "https://kv-exp-ppe-eus.vault.azure.net/", "PollingIntervalInHours": 1 - } + }, + "UserAssignedClientId": "493d2364-979a-49e8-a67a-6db0446d079b" } diff --git a/src/service/API/appsettings.fxp-prod.json b/src/service/API/appsettings.fxp-prod.json index 52501c7..acd0283 100644 --- a/src/service/API/appsettings.fxp-prod.json +++ b/src/service/API/appsettings.fxp-prod.json @@ -12,5 +12,6 @@ "Name": "kv-exp-ppe-eus", "EndpointUrl": "https://kv-exp-prod-eus.vault.azure.net/", "PollingIntervalInHours": 1 - } + }, + "UserAssignedClientId": "78d78b7f-4c24-44d7-96f2-b1b73852068f" } diff --git a/src/service/Common/Authentication/ITokenGenerator.cs b/src/service/Common/Authentication/ITokenGenerator.cs index c262690..4e47a89 100644 --- a/src/service/Common/Authentication/ITokenGenerator.cs +++ b/src/service/Common/Authentication/ITokenGenerator.cs @@ -13,7 +13,8 @@ public interface ITokenGenerator /// Authority to generate the token /// ID of the application for generating the token /// Resource ID for which the token is generated + /// user Assigned Client Id /// Bearer token - Task GenerateToken(string authority, string clientId, string resourceId); + Task GenerateToken(string authority, string clientId, string resourceId, string userAssignedClientId); } } diff --git a/src/service/Common/Authorization/IAuthorizationService.cs b/src/service/Common/Authorization/IAuthorizationService.cs index 89921f0..30995ba 100644 --- a/src/service/Common/Authorization/IAuthorizationService.cs +++ b/src/service/Common/Authorization/IAuthorizationService.cs @@ -23,15 +23,16 @@ public interface IAuthorizationService /// Tenant name /// True if the required claims are present bool IsAuthorized(string appName); - + /// /// Creates the bearer token /// /// IDP authority /// AAD Client ID /// AAD Client ID against which the token is acquired + /// user Assigned Client Id /// Bearer token - Task GetAuthenticationToken(string authority, string clientId, string resourceId); + Task GetAuthenticationToken(string authority, string clientId, string resourceId,string userAssignedClientId); /// /// Augments the user identity with the required claims diff --git a/src/service/Domain/Microsoft.FeatureFlighting.Core.csproj b/src/service/Domain/Microsoft.FeatureFlighting.Core.csproj index b45eba5..428de78 100644 --- a/src/service/Domain/Microsoft.FeatureFlighting.Core.csproj +++ b/src/service/Domain/Microsoft.FeatureFlighting.Core.csproj @@ -15,7 +15,7 @@ - + diff --git a/src/service/Infrastructure/AppConfig/AzureConfigurationClientProvider.cs b/src/service/Infrastructure/AppConfig/AzureConfigurationClientProvider.cs index 538e4e9..25f2726 100644 --- a/src/service/Infrastructure/AppConfig/AzureConfigurationClientProvider.cs +++ b/src/service/Infrastructure/AppConfig/AzureConfigurationClientProvider.cs @@ -3,9 +3,10 @@ using Azure.Data.AppConfiguration; using Azure.Identity; using Microsoft.Extensions.Configuration; +using static Microsoft.AspNetCore.Hosting.Internal.HostingApplication; namespace Microsoft.FeatureFlighting.Infrastructure.AppConfig -{ +{ // internal class AzureConfigurationClientProvider : IAzureConfigurationClientProvider { @@ -31,9 +32,15 @@ public ConfigurationClient GetConfigurationClient() options.Retry.Mode = RetryMode.Exponential; options.Retry.MaxRetries = 10; options.Retry.Delay = TimeSpan.FromSeconds(1); - + TokenCredential credential; + #if DEBUG + credential = new VisualStudioCredential(); + #else + credential = new ManagedIdentityCredential( + ManagedIdentityId.FromUserAssignedClientId(_configuration["UserAssignedClientId"])); + #endif string appConfigUri = _configuration["AzureAppConfigurationUri"]; - _configurationClient = new ConfigurationClient(new Uri(appConfigUri), new DefaultAzureCredential(), options); + _configurationClient = new ConfigurationClient(new Uri(appConfigUri), credential, options); return _configurationClient; } diff --git a/src/service/Infrastructure/Authentication/AadTokenGenerator.cs b/src/service/Infrastructure/Authentication/AadTokenGenerator.cs index c5b4320..4af72e3 100644 --- a/src/service/Infrastructure/Authentication/AadTokenGenerator.cs +++ b/src/service/Infrastructure/Authentication/AadTokenGenerator.cs @@ -26,9 +26,9 @@ public AadTokenGenerator() } // - public async Task GenerateToken(string authority, string clientId, string resourceId) + public async Task GenerateToken(string authority, string clientId, string resourceId, string userAssignedClientId) { - IConfidentialClientApplication client = GetOrCreateConfidentialApp(authority, clientId); + IConfidentialClientApplication client = GetOrCreateConfidentialApp(authority, clientId, userAssignedClientId); var scopes = new string[] { resourceId }; AuthenticationResult authenticationResult = await client .AcquireTokenForClient(scopes) @@ -36,7 +36,7 @@ public async Task GenerateToken(string authority, string clientId, strin return authenticationResult.AccessToken; } - private IConfidentialClientApplication GetOrCreateConfidentialApp(string authority, string clientId) + private IConfidentialClientApplication GetOrCreateConfidentialApp(string authority, string clientId, string userAssignedClientId) { string confidentialAppCacheKey = CreateConfidentialAppCacheKey(authority, clientId); if (_cache.ContainsKey(confidentialAppCacheKey)) @@ -58,13 +58,15 @@ private IConfidentialClientApplication GetOrCreateConfidentialApp(string authori return client; #else + var credential = new ManagedIdentityCredential(userAssignedClientId); + IConfidentialClientApplication client = ConfidentialClientApplicationBuilder .Create(clientId) .WithAuthority(new Uri(authority)) .WithClientAssertion((AssertionRequestOptions options) => { - var accessToken = new DefaultAzureCredential().GetToken(new TokenRequestContext(new string[] { $"api://AzureADTokenExchange/.default" }), CancellationToken.None); + var accessToken = credential.GetToken(new TokenRequestContext(new string[] { $"api://AzureADTokenExchange/.default" }), CancellationToken.None); return Task.FromResult(accessToken.Token); }) .Build(); diff --git a/src/service/Infrastructure/Authorization/AuthorizationService.cs b/src/service/Infrastructure/Authorization/AuthorizationService.cs index 64dfb69..2b88426 100644 --- a/src/service/Infrastructure/Authorization/AuthorizationService.cs +++ b/src/service/Infrastructure/Authorization/AuthorizationService.cs @@ -75,14 +75,14 @@ public bool IsAuthorized(string appName) return false; } - public async Task GetAuthenticationToken(string authority, string clientId, string resourceId) + public async Task GetAuthenticationToken(string authority, string clientId, string resourceId,string userAssignedClientId) { AuthenticationResult authenticationResult; const string MsalScopeSuffix = "/.default"; string bearerToken = null; try { - IConfidentialClientApplication app = GetOrCreateConfidentialApp(authority, clientId); + IConfidentialClientApplication app = GetOrCreateConfidentialApp(authority, clientId, userAssignedClientId); if (app != null) { var scopes = new[] { resourceId + MsalScopeSuffix }; @@ -97,7 +97,7 @@ public async Task GetAuthenticationToken(string authority, string client return bearerToken; } - private IConfidentialClientApplication GetOrCreateConfidentialApp(string authority, string clientId) + private IConfidentialClientApplication GetOrCreateConfidentialApp(string authority, string clientId,string userAssignedClientId) { string confidentialAppCacheKey = $"{authority}-{clientId}"; if (_confidentialApps.ContainsKey(confidentialAppCacheKey)) @@ -115,13 +115,14 @@ private IConfidentialClientApplication GetOrCreateConfidentialApp(string authori _confidentialApps.TryAdd(confidentialAppCacheKey, app); return app; #else + var credential = new ManagedIdentityCredential(userAssignedClientId); IConfidentialClientApplication app = ConfidentialClientApplicationBuilder .Create(clientId) .WithAuthority(new Uri(authority)) .WithClientAssertion((AssertionRequestOptions options) => { - var accessToken = new DefaultAzureCredential().GetToken(new TokenRequestContext(new string[] { $"api://AzureADTokenExchange/.default" }), CancellationToken.None); + var accessToken = credential.GetToken(new TokenRequestContext(new string[] { $"api://AzureADTokenExchange/.default" }), CancellationToken.None); return Task.FromResult(accessToken.Token); }) .Build(); diff --git a/src/service/Infrastructure/Graph/GraphGroupVerificationService.cs b/src/service/Infrastructure/Graph/GraphGroupVerificationService.cs index c1f9737..e13e9e2 100644 --- a/src/service/Infrastructure/Graph/GraphGroupVerificationService.cs +++ b/src/service/Infrastructure/Graph/GraphGroupVerificationService.cs @@ -147,13 +147,14 @@ private IGraphServiceClient CreateGraphClient(IConfiguration configuration) _cache.Add(confidentialAppCacheKey, client); #else - IConfidentialClientApplication client = + var credential = new ManagedIdentityCredential(configuration["UserAssignedClientId"]); + IConfidentialClientApplication client = ConfidentialClientApplicationBuilder .Create(configuration["Graph:ClientId"]) .WithAuthority(new Uri(authority)) .WithClientAssertion((AssertionRequestOptions options) => { - var accessToken = new DefaultAzureCredential().GetToken(new TokenRequestContext(new string[] { $"api://AzureADTokenExchange/.default" }), CancellationToken.None); + var accessToken = credential.GetToken(new TokenRequestContext(new string[] { $"api://AzureADTokenExchange/.default" }), CancellationToken.None); return Task.FromResult(accessToken.Token); }) .Build(); diff --git a/src/service/Infrastructure/Microsoft.FeatureFlighting.Infrastructure.csproj b/src/service/Infrastructure/Microsoft.FeatureFlighting.Infrastructure.csproj index 9c7f96e..8d63f16 100644 --- a/src/service/Infrastructure/Microsoft.FeatureFlighting.Infrastructure.csproj +++ b/src/service/Infrastructure/Microsoft.FeatureFlighting.Infrastructure.csproj @@ -13,7 +13,7 @@ - + diff --git a/src/service/Infrastructure/Storage/BlobProviderFactory.cs b/src/service/Infrastructure/Storage/BlobProviderFactory.cs index 1b7dc34..6ec0d1b 100644 --- a/src/service/Infrastructure/Storage/BlobProviderFactory.cs +++ b/src/service/Infrastructure/Storage/BlobProviderFactory.cs @@ -8,6 +8,9 @@ using Microsoft.FeatureFlighting.Common.Storage; using Azure.Identity; using Microsoft.FeatureFlighting.Common; +using Azure.Core; +using Microsoft.Extensions.Configuration; +using System.Reflection.PortableExecutable; namespace Microsoft.FeatureFlighting.Infrastructure.Storage { @@ -17,16 +20,23 @@ internal class BlobProviderFactory : IBlobProviderFactory private readonly ITenantConfigurationProvider _tenantConfigurationProvider; private readonly ILogger _logger; private readonly IDictionary _blobProviderCache; - private readonly DefaultAzureCredential _defaultAzureCredential; - - public BlobProviderFactory(ITenantConfigurationProvider tenantConfigurationProvider, ILogger logger) + private readonly TokenCredential _defaultAzureCredential; + private readonly IConfiguration _configuration; + public BlobProviderFactory(ITenantConfigurationProvider tenantConfigurationProvider, ILogger logger, IConfiguration configuration) { _tenantConfigurationProvider = tenantConfigurationProvider ?? throw new ArgumentNullException(nameof(tenantConfigurationProvider)); _blobProviderCache = new ConcurrentDictionary(StringComparer.InvariantCultureIgnoreCase); _logger = logger; + _configuration = configuration; if (_defaultAzureCredential == null) - _defaultAzureCredential = new DefaultAzureCredential(); - + { + #if DEBUG + _defaultAzureCredential = new VisualStudioCredential(); + #else + _defaultAzureCredential = new ManagedIdentityCredential( + ManagedIdentityId.FromUserAssignedClientId(_configuration["UserAssignedClientId"])); + #endif + } } /// diff --git a/src/service/Infrastructure/Storage/CosmosDbRepository.cs b/src/service/Infrastructure/Storage/CosmosDbRepository.cs index 001e2f6..9b6c1d8 100644 --- a/src/service/Infrastructure/Storage/CosmosDbRepository.cs +++ b/src/service/Infrastructure/Storage/CosmosDbRepository.cs @@ -13,13 +13,14 @@ using Microsoft.FeatureFlighting.Common.AppExceptions; using Microsoft.FeatureFlighting.Common.Config; using Azure.Identity; +using Azure.Core; namespace Microsoft.FeatureFlighting.Infrastructure.Storage { /// /// Azure Cosmos DB Document repository /// - internal class CosmosDbRepository: IDocumentRepository where TDoc : class, new() + internal class CosmosDbRepository : IDocumentRepository where TDoc : class, new() { private readonly IConfiguration _configuration; private readonly ILogger _logger; @@ -40,7 +41,15 @@ public CosmosDbRepository(CosmosDbConfiguration cosmosConfiguration, IConfigurat MaxRetryWaitTimeOnRateLimitedRequests = TimeSpan.FromSeconds(int.Parse(_configuration["CosmosDb:MaxRetryWaitTimeOnRateLimitedRequests"])), MaxRetryAttemptsOnRateLimitedRequests = int.Parse(_configuration["CosmosDb:MaxRetryAttemptsOnRateLimitedRequests"]) }; - CosmosClient client = new(cosmosConfiguration.Endpoint, new DefaultAzureCredential(), options); + TokenCredential credential; + #if DEBUG + credential = new VisualStudioCredential(); + #else + credential = new ManagedIdentityCredential( + ManagedIdentityId.FromUserAssignedClientId(_configuration["UserAssignedClientId"])); + #endif + + CosmosClient client = new(cosmosConfiguration.Endpoint, credential, options); Database database = client.GetDatabase(cosmosConfiguration.DatabaseId); _container = database.GetContainer(cosmosConfiguration.ContainerId); _logger = logger; diff --git a/src/service/Infrastructure/Webhook/WebhookTriggerManager.cs b/src/service/Infrastructure/Webhook/WebhookTriggerManager.cs index 030333d..85d5aec 100644 --- a/src/service/Infrastructure/Webhook/WebhookTriggerManager.cs +++ b/src/service/Infrastructure/Webhook/WebhookTriggerManager.cs @@ -13,6 +13,7 @@ using System.Collections.Generic; using Microsoft.Graph; using System.Linq; +using Microsoft.Extensions.Configuration; namespace Microsoft.FeatureFlighting.Infrastructure.Webhook { @@ -22,13 +23,14 @@ internal class WebhookTriggerManager: IWebhookTriggerManager private readonly IHttpClientFactory _httpClientFactory; private readonly ITokenGenerator _tokenGenerator; private readonly ILogger _logger; + public IConfiguration _configuration { get; } - public WebhookTriggerManager(IHttpClientFactory httpClientFactory, ITokenGenerator tokenGenerator, ILogger logger) - { - + public WebhookTriggerManager(IHttpClientFactory httpClientFactory, ITokenGenerator tokenGenerator, ILogger logger, IConfiguration configuration) + { _httpClientFactory = httpClientFactory; _tokenGenerator = tokenGenerator; _logger= logger; + _configuration = configuration; } // @@ -47,7 +49,7 @@ public async Task Trigger(WebhookConfiguration webhook, string payload, DependencyContext dependency = CreateDependencyContext(webhook, trackingIds); HttpRequestMessage request = new(new HttpMethod(webhook.HttpMethod), webhook.Uri ?? ""); - string bearerToken = await _tokenGenerator.GenerateToken(webhook.AuthenticationAuthority, webhook.ClientId, webhook.ResourceId); + string bearerToken = await _tokenGenerator.GenerateToken(webhook.AuthenticationAuthority, webhook.ClientId, webhook.ResourceId, _configuration["UserAssignedClientId"]); request.Headers.Add("Authorization", $"Bearer {bearerToken}"); request.Headers.Add("x-correlationId", trackingIds.CorrelationId); request.Headers.Add("x-messageId", trackingIds.TransactionId); diff --git a/src/service/Tests/Api.Tests/Microsoft.FeatureFlighting.API.Tests.csproj b/src/service/Tests/Api.Tests/Microsoft.FeatureFlighting.API.Tests.csproj index 61ddf58..85b819e 100644 --- a/src/service/Tests/Api.Tests/Microsoft.FeatureFlighting.API.Tests.csproj +++ b/src/service/Tests/Api.Tests/Microsoft.FeatureFlighting.API.Tests.csproj @@ -7,8 +7,11 @@ - - + + + + + diff --git a/src/service/Tests/Domain.Tests/Microsoft.PS.FlightingService.Core.Tests.csproj b/src/service/Tests/Domain.Tests/Microsoft.PS.FlightingService.Core.Tests.csproj index bf19a76..cda8a01 100644 --- a/src/service/Tests/Domain.Tests/Microsoft.PS.FlightingService.Core.Tests.csproj +++ b/src/service/Tests/Domain.Tests/Microsoft.PS.FlightingService.Core.Tests.csproj @@ -13,6 +13,7 @@ + diff --git a/src/service/Tests/Services.Tests/Microsoft.FeatureFlighting.Infrastructure.Tests.csproj b/src/service/Tests/Services.Tests/Microsoft.FeatureFlighting.Infrastructure.Tests.csproj index 562a3e7..dc7782a 100644 --- a/src/service/Tests/Services.Tests/Microsoft.FeatureFlighting.Infrastructure.Tests.csproj +++ b/src/service/Tests/Services.Tests/Microsoft.FeatureFlighting.Infrastructure.Tests.csproj @@ -21,6 +21,7 @@ + diff --git a/tests/functional/Tests/FeatureFlagClient.cs b/tests/functional/Tests/FeatureFlagClient.cs index 55e99d2..7a11869 100644 --- a/tests/functional/Tests/FeatureFlagClient.cs +++ b/tests/functional/Tests/FeatureFlagClient.cs @@ -9,6 +9,7 @@ using Microsoft.FeatureFlighting.Tests.Functional.Utilities; using Azure.Core; using Azure.Identity; +using System.Threading; namespace Microsoft.FeatureFlighting.Tests.Functional { @@ -217,7 +218,7 @@ private static async Task GetClientSecretForAuthentication() { return _testContext.Properties["FunctionalTest:AAD:ClientSecret"].ToString(); } - return await KeyVaultHelper.Instance.GetSecret(_testContext.Properties["FunctionalTest:KeyVault:Endpoint"].ToString(), _testContext.Properties["FunctionalTest:AAD:ClientSecret"].ToString()); + return await KeyVaultHelper.Instance.GetSecret(_testContext.Properties["FunctionalTest:KeyVault:Endpoint"].ToString(), _testContext.Properties["FunctionalTest:AAD:ClientSecret"].ToString(), _testContext.Properties["FunctionalTest:UserAssignedClientId"].ToString()); } private static async Task GetAlternateClientSecretForAuthentication() @@ -226,7 +227,7 @@ private static async Task GetAlternateClientSecretForAuthentication() { return _testContext.Properties["FunctionalTest:InvalidAAD:ClientSecret"].ToString(); } - return await KeyVaultHelper.Instance.GetSecret(_testContext.Properties["FunctionalTest:KeyVault:Endpoint"].ToString(), _testContext.Properties["FunctionalTest:InvalidAAD:ClientSecret"].ToString()); + return await KeyVaultHelper.Instance.GetSecret(_testContext.Properties["FunctionalTest:KeyVault:Endpoint"].ToString(), _testContext.Properties["FunctionalTest:InvalidAAD:ClientSecret"].ToString(), _testContext.Properties["FunctionalTest:UserAssignedClientId"].ToString()); } private static async Task GetAccessTokenAsync() @@ -239,10 +240,17 @@ private static async Task GetAccessTokenAsync() string cachedToken = _tokenCache.GetValueOrDefault(clientId, null); if (!string.IsNullOrWhiteSpace(cachedToken)) return cachedToken; - - var tokenCredential = new DefaultAzureCredential(); - var accessToken = await tokenCredential.GetTokenAsync( - new TokenRequestContext(scopes: new string[] { flightingResource + "/.default" }) { }); + string userAssignedClientId = _testContext.Properties["FunctionalTest:UserAssignedClientId"].ToString(); + TokenCredential credential; + #if DEBUG + credential = new VisualStudioCredential(); + #else + credential = new ManagedIdentityCredential( + ManagedIdentityId.FromUserAssignedClientId(userAssignedClientId)); + #endif + + var accessToken = await credential.GetTokenAsync( + new TokenRequestContext(scopes: new string[] { flightingResource + "/.default" }), CancellationToken.None); return accessToken.Token; } @@ -252,10 +260,17 @@ private static async Task GetAccessTokenAsyncFromAlternateAccount() string flightingKey = await GetAlternateClientSecretForAuthentication(); string flightingResource = _testContext.Properties["FunctionalTest:FxpFlighting:AAD:ResourceId"].ToString(); string authority = _testContext.Properties["FunctionalTest:AAD:Authority"].ToString(); - - var tokenCredential = new DefaultAzureCredential(); - var accessToken = await tokenCredential.GetTokenAsync( - new TokenRequestContext(scopes: new string[] { flightingResource + "/.default" }) { }); + string userAssignedClientId = _testContext.Properties["FunctionalTest:UserAssignedClientId"].ToString(); + TokenCredential credential; + #if DEBUG + credential = new VisualStudioCredential(); + #else + credential = new ManagedIdentityCredential( + ManagedIdentityId.FromUserAssignedClientId(userAssignedClientId)); + #endif + + var accessToken = await credential.GetTokenAsync( + new TokenRequestContext(scopes: new string[] { flightingResource + "/.default" }), CancellationToken.None ); return accessToken.Token; } } diff --git a/tests/functional/Tests/Helper/KeyVaultHelper.cs b/tests/functional/Tests/Helper/KeyVaultHelper.cs index 263db5f..657c6b1 100644 --- a/tests/functional/Tests/Helper/KeyVaultHelper.cs +++ b/tests/functional/Tests/Helper/KeyVaultHelper.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Collections.Concurrent; using Azure.Security.KeyVault.Secrets; +using Azure.Core; namespace Microsoft.FeatureFlighting.Tests.Functional.Helper { @@ -28,12 +29,20 @@ public static KeyVaultHelper Instance } } - public async Task GetSecret(string keyVaultEndpoint, string secretName) + public async Task GetSecret(string keyVaultEndpoint, string secretName,string userAssignedClientId) { if (SecretsCache.ContainsKey(secretName)) return SecretsCache[secretName]; + TokenCredential credential; - SecretClient client = new(new System.Uri(keyVaultEndpoint), new DefaultAzureCredential()); + #if DEBUG + credential = new VisualStudioCredential(); + #else + credential = new ManagedIdentityCredential( + ManagedIdentityId.FromUserAssignedClientId(userAssignedClientId)); + #endif + + SecretClient client = new(new System.Uri(keyVaultEndpoint), credential); KeyVaultSecret secret = await client.GetSecretAsync(secretName); return secret.Value; } diff --git a/tests/functional/Tests/Local.runsettings b/tests/functional/Tests/Local.runsettings index 3612968..9c83e2c 100644 --- a/tests/functional/Tests/Local.runsettings +++ b/tests/functional/Tests/Local.runsettings @@ -32,6 +32,7 @@ + diff --git a/tests/functional/Tests/PreProduction.runsettings b/tests/functional/Tests/PreProduction.runsettings index 9482dad..9bb2830 100644 --- a/tests/functional/Tests/PreProduction.runsettings +++ b/tests/functional/Tests/PreProduction.runsettings @@ -32,6 +32,7 @@ + diff --git a/tests/functional/Tests/Production.runsettings b/tests/functional/Tests/Production.runsettings index 3d798f7..29131ad 100644 --- a/tests/functional/Tests/Production.runsettings +++ b/tests/functional/Tests/Production.runsettings @@ -32,6 +32,7 @@ +