From 12b8b74506d4b15c75379dd959d66b3428a79aa4 Mon Sep 17 00:00:00 2001 From: gledis69 Date: Tue, 29 Nov 2022 10:26:06 +0300 Subject: [PATCH 1/5] AD Support for Pg --- src/Service.Tests/SqlTests/SqlTestBase.cs | 6 +- .../PostgreSqlQueryExecutorUnitTests.cs | 88 +++++++++++++ src/Service/Resolvers/PostgreSqlExecutor.cs | 120 ++++++++++++++++++ src/Service/Startup.cs | 3 +- 4 files changed, 212 insertions(+), 5 deletions(-) create mode 100644 src/Service.Tests/Unittests/PostgreSqlQueryExecutorUnitTests.cs create mode 100644 src/Service/Resolvers/PostgreSqlExecutor.cs diff --git a/src/Service.Tests/SqlTests/SqlTestBase.cs b/src/Service.Tests/SqlTests/SqlTestBase.cs index d066b22d3b..d0893166cf 100644 --- a/src/Service.Tests/SqlTests/SqlTestBase.cs +++ b/src/Service.Tests/SqlTests/SqlTestBase.cs @@ -84,7 +84,7 @@ protected static async Task InitializeTestFixture(TestContext context, List>> pgQueryExecutorLogger = new(); + Mock> pgQueryExecutorLogger = new(); _queryBuilder = new PostgresQueryBuilder(); _defaultSchemaName = "public"; _dbExceptionParser = new PostgreSqlDbExceptionParser(_runtimeConfigProvider); - _queryExecutor = new QueryExecutor( + _queryExecutor = new PostgreSqlQueryExecutor( _runtimeConfigProvider, _dbExceptionParser, pgQueryExecutorLogger.Object); diff --git a/src/Service.Tests/Unittests/PostgreSqlQueryExecutorUnitTests.cs b/src/Service.Tests/Unittests/PostgreSqlQueryExecutorUnitTests.cs new file mode 100644 index 0000000000..2b9193fbad --- /dev/null +++ b/src/Service.Tests/Unittests/PostgreSqlQueryExecutorUnitTests.cs @@ -0,0 +1,88 @@ +using System; +using System.Collections.Generic; +using System.Text.Json; +using System.Threading.Tasks; +using Azure.Core; +using Azure.DataApiBuilder.Service.Configurations; +using Azure.DataApiBuilder.Service.Resolvers; +using Azure.Identity; +using Microsoft.Extensions.Logging; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; +using Npgsql; + +namespace Azure.DataApiBuilder.Service.Tests.UnitTests +{ + [TestClass, TestCategory(TestCategory.POSTGRESQL)] + public class PostgreSqlQueryExecutorUnitTests + { + /// + /// Validates managed identity token issued ONLY when ManagedIdentityAccessToken is "USE DEFAULT" + /// + [DataTestMethod] + [DataRow("Server =<>;Database=<>;username=<>;password=<>", null, false, false, + DisplayName = "Managed identity is not used")] + [DataRow("Server =<>;Database=<>;", "xxx", true, false, + DisplayName = "Managed identity access token from config used " + + "when ManagedIdentityAccessToken is not null and not \"USE DEFAULT\".")] + [DataRow("Server =<>;Database=<>;", "USE DEFAULT", true, true, + DisplayName = "Default managed identity access token used " + + "when ManagedIdentityAccessToken is \"USE DEFAULT\".")] + public async Task TestHandleManagedIdentityAccess( + string connectionString, + string managedIdentityAccessToken, + bool expectManagedIdentityAccessToken, + bool isDefaultAzureCredential) + { + RuntimeConfigProvider runtimeConfigProvider = TestHelper.GetRuntimeConfigProvider(TestCategory.POSTGRESQL); + runtimeConfigProvider.Initialize( + JsonSerializer.Serialize(runtimeConfigProvider.GetRuntimeConfiguration()), + schema: null, + connectionString: connectionString, + accessToken: managedIdentityAccessToken); + + Mock dbExceptionParser = new(runtimeConfigProvider, new HashSet()); + Mock> queryExecutorLogger = new(); + PostgreSqlQueryExecutor postgreSqlQueryExecutor = new(runtimeConfigProvider, dbExceptionParser.Object, queryExecutorLogger.Object); + + const string DEFAULT_TOKEN = "Default access token"; + AccessToken testValidToken = new(accessToken: DEFAULT_TOKEN, expiresOn: DateTimeOffset.MaxValue); + if (expectManagedIdentityAccessToken) + { + if (isDefaultAzureCredential) + { + Mock dacMock = new(); + dacMock + .Setup(m => m.GetTokenAsync(It.IsAny(), + It.IsAny())) + .Returns(ValueTask.FromResult(testValidToken)); + postgreSqlQueryExecutor.AzureCredential = dacMock.Object; + } + else + { + postgreSqlQueryExecutor = new(runtimeConfigProvider, dbExceptionParser.Object, queryExecutorLogger.Object); + } + } + + using NpgsqlConnection conn = new(connectionString); + await postgreSqlQueryExecutor.SetManagedIdentityAccessTokenIfAnyAsync(conn); + + if (expectManagedIdentityAccessToken) + { + if (isDefaultAzureCredential) + { + Assert.IsTrue(conn.ConnectionString.Contains(DEFAULT_TOKEN), "Password not set to default access token"); + } + else + { + Assert.IsTrue(conn.ConnectionString.Contains(managedIdentityAccessToken), $"Password not set to the config access token"); + } + } + else + { + // password is not changed to the access token + Assert.AreEqual(connectionString, conn.ConnectionString); + } + } + } +} diff --git a/src/Service/Resolvers/PostgreSqlExecutor.cs b/src/Service/Resolvers/PostgreSqlExecutor.cs new file mode 100644 index 0000000000..134da0e573 --- /dev/null +++ b/src/Service/Resolvers/PostgreSqlExecutor.cs @@ -0,0 +1,120 @@ +using System.Data.Common; +using System.Threading.Tasks; +using Azure.Core; +using Azure.DataApiBuilder.Service.Configurations; +using Azure.Identity; +using Microsoft.Extensions.Logging; +using Npgsql; + +namespace Azure.DataApiBuilder.Service.Resolvers +{ + /// + /// Specialized QueryExecutor for PostgreSql mainly providing methods to + /// handle connecting to the database with a managed identity. + /// for more info: https://learn.microsoft.com/EN-us/azure/postgresql/single-server/how-to-connect-with-managed-identity + /// /// + public class PostgreSqlQueryExecutor : QueryExecutor + { + // This is the same scope for any Azure SQL database that is + // required to request a default azure credential access token + // for a managed identity. + public const string DATABASE_SCOPE = @"https://ossrdbms-aad.database.windows.net/.default"; + + /// + /// The managed identity Access Token string obtained + /// from the configuration controller. + /// + private readonly string? _accessTokenFromController; + + public DefaultAzureCredential AzureCredential { get; set; } = new(); + + /// + /// The saved cached access token obtained from DefaultAzureCredentials + /// representing a managed identity. + /// + private AccessToken? _defaultAccessToken; + + private bool _attemptToSetAccessToken; + + public PostgreSqlQueryExecutor( + RuntimeConfigProvider runtimeConfigProvider, + DbExceptionParser dbExceptionParser, + ILogger> logger) + : base(runtimeConfigProvider, dbExceptionParser, logger) + { + // Postgres connection string does not have a good way to determine + // if the authentication should be done through Azure AD + // so as a workaround the user can specify "ManagedIdentityAccessToken": "USE DEFAULT" + // to instruct DAB to use the default access token + string? configAccessToken = runtimeConfigProvider.ManagedIdentityAccessToken; + _attemptToSetAccessToken = configAccessToken is not null; + _accessTokenFromController = configAccessToken is "USE DEFAULT" ? null : configAccessToken; + } + + /// + /// Modifies the properties of the supplied connection string to support managed identity access. + /// In the case of Postgres, if a default managed identity needs to be used, the password in the + /// connection needs to be replaced with the default access token. + /// + /// The supplied connection to modify for managed identity access. + public override async Task SetManagedIdentityAccessTokenIfAnyAsync(DbConnection conn) + { + // Only attempt to get the access token if the connection string is in the appropriate format + if (_attemptToSetAccessToken) + { + NpgsqlConnection sqlConn = (NpgsqlConnection)conn; + + // If the configuration controller provided a managed identity access token use that, + // else use the default saved access token if still valid. + // Get a new token only if the saved token is null or expired. + string? accessToken = _accessTokenFromController ?? + (IsDefaultAccessTokenValid() ? + ((AccessToken)_defaultAccessToken!).Token : + await GetAccessTokenAsync()); + + if (accessToken is not null) + { + NpgsqlConnectionStringBuilder newConnectionString = new(sqlConn.ConnectionString) + { + Password = accessToken + }; + sqlConn.ConnectionString = newConnectionString.ToString(); + } + } + } + + /// + /// Determines if the saved default azure credential's access token is valid and not expired. + /// + /// True if valid, false otherwise. + private bool IsDefaultAccessTokenValid() + { + return _defaultAccessToken is not null && + ((AccessToken)_defaultAccessToken).ExpiresOn.CompareTo(System.DateTimeOffset.Now) > 0; + } + + /// + /// Tries to get an access token using DefaultAzureCredentials. + /// Catches any CredentialUnavailableException and logs only a warning + /// since since this is best effort. + /// + /// The string representation of the access token if found, + /// null otherwise. + private async Task GetAccessTokenAsync() + { + try + { + _defaultAccessToken = + await AzureCredential.GetTokenAsync( + new TokenRequestContext(new[] { DATABASE_SCOPE })); + } + catch (CredentialUnavailableException ex) + { + QueryExecutorLogger.LogWarning($"Attempt to retrieve a managed identity access token using DefaultAzureCredential" + + $" failed due to: \n{ex}"); + } + + return _defaultAccessToken?.Token; + } + } +} diff --git a/src/Service/Startup.cs b/src/Service/Startup.cs index b084252883..d91c3e499a 100644 --- a/src/Service/Startup.cs +++ b/src/Service/Startup.cs @@ -27,7 +27,6 @@ using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using MySqlConnector; -using Npgsql; namespace Azure.DataApiBuilder.Service { @@ -108,7 +107,7 @@ public void ConfigureServices(IServiceCollection services) case DatabaseType.mssql: return ActivatorUtilities.GetServiceOrCreateInstance(serviceProvider); case DatabaseType.postgresql: - return ActivatorUtilities.GetServiceOrCreateInstance>(serviceProvider); + return ActivatorUtilities.GetServiceOrCreateInstance(serviceProvider); case DatabaseType.mysql: return ActivatorUtilities.GetServiceOrCreateInstance>(serviceProvider); default: From 15bb791f44eaa16fe1fc42df231b6800af9aea26 Mon Sep 17 00:00:00 2001 From: gledis69 Date: Fri, 9 Dec 2022 15:10:51 +0300 Subject: [PATCH 2/5] Change how default identity is inferred --- .../PostgreSqlQueryExecutorUnitTests.cs | 40 ++++++++++--------- src/Service/Resolvers/PostgreSqlExecutor.cs | 26 ++++++++---- 2 files changed, 39 insertions(+), 27 deletions(-) diff --git a/src/Service.Tests/Unittests/PostgreSqlQueryExecutorUnitTests.cs b/src/Service.Tests/Unittests/PostgreSqlQueryExecutorUnitTests.cs index 2b9193fbad..ec50061d7d 100644 --- a/src/Service.Tests/Unittests/PostgreSqlQueryExecutorUnitTests.cs +++ b/src/Service.Tests/Unittests/PostgreSqlQueryExecutorUnitTests.cs @@ -17,35 +17,32 @@ namespace Azure.DataApiBuilder.Service.Tests.UnitTests public class PostgreSqlQueryExecutorUnitTests { /// - /// Validates managed identity token issued ONLY when ManagedIdentityAccessToken is "USE DEFAULT" + /// Validates managed identity token issued ONLY when connection string does not specify password /// [DataTestMethod] - [DataRow("Server =<>;Database=<>;username=<>;password=<>", null, false, false, - DisplayName = "Managed identity is not used")] - [DataRow("Server =<>;Database=<>;", "xxx", true, false, - DisplayName = "Managed identity access token from config used " + - "when ManagedIdentityAccessToken is not null and not \"USE DEFAULT\".")] - [DataRow("Server =<>;Database=<>;", "USE DEFAULT", true, true, - DisplayName = "Default managed identity access token used " + - "when ManagedIdentityAccessToken is \"USE DEFAULT\".")] + [DataRow("Server =<>;Database=<>;Username=xyz;", false, false, + DisplayName = "No managed identity access token when connection string specifies Username only.")] + [DataRow("Server =<>;Database=<>;Username=xyz;", true, false, + DisplayName = "Managed identity access token from config used when connection string specifies Username only.")] + [DataRow("Server =<>;Database=<>;Username=xyz;", true, true, + DisplayName = "Default managed identity access token used when connection string specifies Username only.")] + [DataRow("Server =<>;Database=<>;Password=xyz;", false, false, + DisplayName = "No managed identity access token when connection string specifies Password only.")] + [DataRow("Server =<>;Database=<>;Username=xyz;Password=xxx", false, false, + DisplayName = "No managed identity access token when connection string specifies both Username and Password.")] public async Task TestHandleManagedIdentityAccess( string connectionString, - string managedIdentityAccessToken, bool expectManagedIdentityAccessToken, bool isDefaultAzureCredential) { RuntimeConfigProvider runtimeConfigProvider = TestHelper.GetRuntimeConfigProvider(TestCategory.POSTGRESQL); - runtimeConfigProvider.Initialize( - JsonSerializer.Serialize(runtimeConfigProvider.GetRuntimeConfiguration()), - schema: null, - connectionString: connectionString, - accessToken: managedIdentityAccessToken); - + runtimeConfigProvider.GetRuntimeConfiguration().ConnectionString = connectionString; Mock dbExceptionParser = new(runtimeConfigProvider, new HashSet()); Mock> queryExecutorLogger = new(); PostgreSqlQueryExecutor postgreSqlQueryExecutor = new(runtimeConfigProvider, dbExceptionParser.Object, queryExecutorLogger.Object); const string DEFAULT_TOKEN = "Default access token"; + const string CONFIG_TOKEN = "Configuration controller access token"; AccessToken testValidToken = new(accessToken: DEFAULT_TOKEN, expiresOn: DateTimeOffset.MaxValue); if (expectManagedIdentityAccessToken) { @@ -60,27 +57,32 @@ public async Task TestHandleManagedIdentityAccess( } else { + runtimeConfigProvider.Initialize( + JsonSerializer.Serialize(runtimeConfigProvider.GetRuntimeConfiguration()), + schema: null, + connectionString: connectionString, + accessToken: CONFIG_TOKEN); postgreSqlQueryExecutor = new(runtimeConfigProvider, dbExceptionParser.Object, queryExecutorLogger.Object); } } using NpgsqlConnection conn = new(connectionString); await postgreSqlQueryExecutor.SetManagedIdentityAccessTokenIfAnyAsync(conn); + NpgsqlConnectionStringBuilder connStringBuilder = new(conn.ConnectionString); if (expectManagedIdentityAccessToken) { if (isDefaultAzureCredential) { - Assert.IsTrue(conn.ConnectionString.Contains(DEFAULT_TOKEN), "Password not set to default access token"); + Assert.AreEqual(expected: DEFAULT_TOKEN, actual: connStringBuilder.Password); } else { - Assert.IsTrue(conn.ConnectionString.Contains(managedIdentityAccessToken), $"Password not set to the config access token"); + Assert.AreEqual(expected: CONFIG_TOKEN, actual: connStringBuilder.Password); } } else { - // password is not changed to the access token Assert.AreEqual(connectionString, conn.ConnectionString); } } diff --git a/src/Service/Resolvers/PostgreSqlExecutor.cs b/src/Service/Resolvers/PostgreSqlExecutor.cs index 134da0e573..5bd1d417f1 100644 --- a/src/Service/Resolvers/PostgreSqlExecutor.cs +++ b/src/Service/Resolvers/PostgreSqlExecutor.cs @@ -1,3 +1,4 @@ +using System; using System.Data.Common; using System.Threading.Tasks; using Azure.Core; @@ -42,13 +43,9 @@ public PostgreSqlQueryExecutor( ILogger> logger) : base(runtimeConfigProvider, dbExceptionParser, logger) { - // Postgres connection string does not have a good way to determine - // if the authentication should be done through Azure AD - // so as a workaround the user can specify "ManagedIdentityAccessToken": "USE DEFAULT" - // to instruct DAB to use the default access token - string? configAccessToken = runtimeConfigProvider.ManagedIdentityAccessToken; - _attemptToSetAccessToken = configAccessToken is not null; - _accessTokenFromController = configAccessToken is "USE DEFAULT" ? null : configAccessToken; + _accessTokenFromController = runtimeConfigProvider.ManagedIdentityAccessToken; + _attemptToSetAccessToken = + ShouldManagedIdentityAccessBeAttempted(runtimeConfigProvider.GetRuntimeConfiguration().ConnectionString); } /// @@ -83,6 +80,16 @@ public override async Task SetManagedIdentityAccessTokenIfAnyAsync(DbConnection } } + /// + /// Determines if managed identity access should be attempted or not. + /// It should only be attempted if the password is not provided + /// + private static bool ShouldManagedIdentityAccessBeAttempted(string connString) + { + NpgsqlConnectionStringBuilder connStringBuilder = new(connString); + return string.IsNullOrEmpty(connStringBuilder.Password); + } + /// /// Determines if the saved default azure credential's access token is valid and not expired. /// @@ -108,7 +115,10 @@ private bool IsDefaultAccessTokenValid() await AzureCredential.GetTokenAsync( new TokenRequestContext(new[] { DATABASE_SCOPE })); } - catch (CredentialUnavailableException ex) + // because there can be scenarios where password is not specified but + // default managed identity is not the intended method of authentication + // so a bunch of different exceptions could occur in that scenario + catch (Exception ex) { QueryExecutorLogger.LogWarning($"Attempt to retrieve a managed identity access token using DefaultAzureCredential" + $" failed due to: \n{ex}"); From c7e498bb83111f2a290d618515dd36a4475c4b67 Mon Sep 17 00:00:00 2001 From: gledis69 Date: Fri, 9 Dec 2022 15:50:07 +0300 Subject: [PATCH 3/5] Address reivews --- src/Service.Tests/SqlTests/SqlTestBase.cs | 2 +- src/Service/Resolvers/PostgreSqlExecutor.cs | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/Service.Tests/SqlTests/SqlTestBase.cs b/src/Service.Tests/SqlTests/SqlTestBase.cs index d0893166cf..b276f5accd 100644 --- a/src/Service.Tests/SqlTests/SqlTestBase.cs +++ b/src/Service.Tests/SqlTests/SqlTestBase.cs @@ -84,7 +84,7 @@ protected static async Task InitializeTestFixture(TestContext context, List public class PostgreSqlQueryExecutor : QueryExecutor { - // This is the same scope for any Azure SQL database that is + // This is the same scope for any Azure Database for PostgreSQL that is // required to request a default azure credential access token // for a managed identity. public const string DATABASE_SCOPE = @"https://ossrdbms-aad.database.windows.net/.default"; @@ -120,8 +120,9 @@ await AzureCredential.GetTokenAsync( // so a bunch of different exceptions could occur in that scenario catch (Exception ex) { - QueryExecutorLogger.LogWarning($"Attempt to retrieve a managed identity access token using DefaultAzureCredential" + - $" failed due to: \n{ex}"); + QueryExecutorLogger.LogWarning($"No password detected in the connection string. Attempt to retrieve " + + $"a managed identity access token using DefaultAzureCredential failed due to: \n{ex}\n" + + $"If authentication with DefaultAzureCrendential is not intended, this warning can be safely ignored."); } return _defaultAccessToken?.Token; From 474671b2022b1f531b3a14838ce5dc472ad63c09 Mon Sep 17 00:00:00 2001 From: gledis69 Date: Fri, 9 Dec 2022 21:05:53 +0300 Subject: [PATCH 4/5] Optimise connection string without password scenario --- .../Unittests/PostgreSqlQueryExecutorUnitTests.cs | 2 +- src/Service/Resolvers/PostgreSqlExecutor.cs | 12 ++++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/Service.Tests/Unittests/PostgreSqlQueryExecutorUnitTests.cs b/src/Service.Tests/Unittests/PostgreSqlQueryExecutorUnitTests.cs index ec50061d7d..aacafc0fbf 100644 --- a/src/Service.Tests/Unittests/PostgreSqlQueryExecutorUnitTests.cs +++ b/src/Service.Tests/Unittests/PostgreSqlQueryExecutorUnitTests.cs @@ -21,7 +21,7 @@ public class PostgreSqlQueryExecutorUnitTests /// [DataTestMethod] [DataRow("Server =<>;Database=<>;Username=xyz;", false, false, - DisplayName = "No managed identity access token when connection string specifies Username only.")] + DisplayName = "No managed identity access token even when connection string specifies Username only.")] [DataRow("Server =<>;Database=<>;Username=xyz;", true, false, DisplayName = "Managed identity access token from config used when connection string specifies Username only.")] [DataRow("Server =<>;Database=<>;Username=xyz;", true, true, diff --git a/src/Service/Resolvers/PostgreSqlExecutor.cs b/src/Service/Resolvers/PostgreSqlExecutor.cs index f0eb383766..05b14f605b 100644 --- a/src/Service/Resolvers/PostgreSqlExecutor.cs +++ b/src/Service/Resolvers/PostgreSqlExecutor.cs @@ -13,7 +13,7 @@ namespace Azure.DataApiBuilder.Service.Resolvers /// Specialized QueryExecutor for PostgreSql mainly providing methods to /// handle connecting to the database with a managed identity. /// for more info: https://learn.microsoft.com/EN-us/azure/postgresql/single-server/how-to-connect-with-managed-identity - /// /// + /// public class PostgreSqlQueryExecutor : QueryExecutor { // This is the same scope for any Azure Database for PostgreSQL that is @@ -103,7 +103,7 @@ private bool IsDefaultAccessTokenValid() /// /// Tries to get an access token using DefaultAzureCredentials. /// Catches any CredentialUnavailableException and logs only a warning - /// since since this is best effort. + /// since this is best effort. /// /// The string representation of the access token if found, /// null otherwise. @@ -123,6 +123,14 @@ await AzureCredential.GetTokenAsync( QueryExecutorLogger.LogWarning($"No password detected in the connection string. Attempt to retrieve " + $"a managed identity access token using DefaultAzureCredential failed due to: \n{ex}\n" + $"If authentication with DefaultAzureCrendential is not intended, this warning can be safely ignored."); + + // the config doesn't contain an identity token + // and a default identity token cannot be obtained + // so the application should not attempt to set the token + // for future conntions + // this would happen in scenarios where the user has a + // valid connection string without a password in it + _attemptToSetAccessToken = false; } return _defaultAccessToken?.Token; From 453d6485ec98812eb0ff7514b92e3d88cb3cc00b Mon Sep 17 00:00:00 2001 From: gledis69 Date: Fri, 9 Dec 2022 21:21:50 +0300 Subject: [PATCH 5/5] Improve default access token scenario logic --- src/Service/Resolvers/PostgreSqlExecutor.cs | 20 ++++++++++++++++---- src/Service/Startup.cs | 2 -- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/Service/Resolvers/PostgreSqlExecutor.cs b/src/Service/Resolvers/PostgreSqlExecutor.cs index 05b14f605b..870ba6e3e3 100644 --- a/src/Service/Resolvers/PostgreSqlExecutor.cs +++ b/src/Service/Resolvers/PostgreSqlExecutor.cs @@ -109,6 +109,8 @@ private bool IsDefaultAccessTokenValid() /// null otherwise. private async Task GetAccessTokenAsync() { + bool firstAttemptAtDefaultAccessToken = _defaultAccessToken is null; + try { _defaultAccessToken = @@ -122,15 +124,25 @@ await AzureCredential.GetTokenAsync( { QueryExecutorLogger.LogWarning($"No password detected in the connection string. Attempt to retrieve " + $"a managed identity access token using DefaultAzureCredential failed due to: \n{ex}\n" + - $"If authentication with DefaultAzureCrendential is not intended, this warning can be safely ignored."); + (firstAttemptAtDefaultAccessToken ? + $"If authentication with DefaultAzureCrendential is not intended, this warning can be safely ignored." : + string.Empty)); // the config doesn't contain an identity token // and a default identity token cannot be obtained // so the application should not attempt to set the token // for future conntions - // this would happen in scenarios where the user has a - // valid connection string without a password in it - _attemptToSetAccessToken = false; + // note though that if a default access token has been previously + // obtained successfully (firstAttemptAtDefaultAccessToken == false) + // this might be a transitory failure don't disable attempts to set + // the token + // + // disabling the attempts is useful in scenarios where the user + // has a valid connection string without a password in it + if (firstAttemptAtDefaultAccessToken) + { + _attemptToSetAccessToken = false; + } } return _defaultAccessToken?.Token; diff --git a/src/Service/Startup.cs b/src/Service/Startup.cs index a35d8bc7cc..bc0f6fc4cc 100644 --- a/src/Service/Startup.cs +++ b/src/Service/Startup.cs @@ -26,8 +26,6 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; -using MySqlConnector; -using Npgsql; namespace Azure.DataApiBuilder.Service {