From 4523f6e30b4818b8f03c4e7be6dc6950743745ba Mon Sep 17 00:00:00 2001 From: Noremac Skich Date: Tue, 8 Oct 2024 23:28:04 -0500 Subject: [PATCH] Fix expired token (#158) Needed to implement a password provider for the postgres database connection Serilog can no longer dump stuff into the database, only can do that locally where the token won't expire Also implemented Application Insights, as a way to debug the application --- .github/workflows/DeployAPI.yml | 2 +- .../ExpressedRealms.Server.csproj | 3 + api/ExpressedRealms.Server/Program.cs | 91 +++++++++++++------ 3 files changed, 68 insertions(+), 28 deletions(-) diff --git a/.github/workflows/DeployAPI.yml b/.github/workflows/DeployAPI.yml index c8af2df..3555fb2 100644 --- a/.github/workflows/DeployAPI.yml +++ b/.github/workflows/DeployAPI.yml @@ -79,4 +79,4 @@ jobs: imageToDeploy: ${{ vars.EXPRESSEDREALMSFRONTEND_REGISTRY_URL }}/noremacskich/expressedrealms-api:${{ github.sha }} containerAppName: ca-expressedrealms-api resourceGroup: RG_ExpressedRealms - environmentVariables: ASPNETCORE_ENVIRONMENT=secretref:aspnetcore-environment POSTMARK_API_KEY=secretref:postmark-api-key NO_REPLY_EMAIL=secretref:no-reply-email TEST_EMAIL_ADDRESS=secretref:test-email-address AZURE_POSTGRESSQL_CONNECTIONSTRING=secretref:azure-postgresql-connectionstring-6f940 FRONT_END_BASE_URL=secretref:front-end-base-url CLIENT_COOKIE_DOMAIN=secretref:client-cookie-domain AZURE_STORAGEBLOB_RESOURCEENDPOINT=secretref:azure-storageblob-resourceendpoint-08dee + environmentVariables: ASPNETCORE_ENVIRONMENT=secretref:aspnetcore-environment POSTMARK_API_KEY=secretref:postmark-api-key NO_REPLY_EMAIL=secretref:no-reply-email TEST_EMAIL_ADDRESS=secretref:test-email-address AZURE_POSTGRESSQL_CONNECTIONSTRING=secretref:azure-postgresql-connectionstring-6f940 FRONT_END_BASE_URL=secretref:front-end-base-url CLIENT_COOKIE_DOMAIN=secretref:client-cookie-domain AZURE_STORAGEBLOB_RESOURCEENDPOINT=secretref:azure-storageblob-resourceendpoint-08dee APPLICATION_INSIGHTS_CONNECTION_STRING=secretref:application-insights-connection-string diff --git a/api/ExpressedRealms.Server/ExpressedRealms.Server.csproj b/api/ExpressedRealms.Server/ExpressedRealms.Server.csproj index 62175f9..a3e5856 100644 --- a/api/ExpressedRealms.Server/ExpressedRealms.Server.csproj +++ b/api/ExpressedRealms.Server/ExpressedRealms.Server.csproj @@ -19,6 +19,8 @@ + + @@ -27,6 +29,7 @@ + diff --git a/api/ExpressedRealms.Server/Program.cs b/api/ExpressedRealms.Server/Program.cs index 786e672..6e6a085 100644 --- a/api/ExpressedRealms.Server/Program.cs +++ b/api/ExpressedRealms.Server/Program.cs @@ -22,42 +22,43 @@ using Unchase.Swashbuckle.AspNetCore.Extensions.Extensions; using Azure.Identity; using Azure.Storage.Blobs; -using Azure.Extensions.AspNetCore.DataProtection.Blobs; using Microsoft.AspNetCore.DataProtection; using Microsoft.AspNetCore.HttpOverrides; +using Npgsql; try { Log.Information("Setting Up Web App"); var builder = WebApplication.CreateBuilder(args); - - // For system-assigned identity. + string connectionString = builder.Configuration.GetConnectionString("DefaultConnection") ?? ""; - if (string.IsNullOrEmpty(connectionString)) - { - var sqlServerTokenProvider = new DefaultAzureCredential(); - AccessToken accessToken = await sqlServerTokenProvider.GetTokenAsync( - new TokenRequestContext(scopes: new string[] - { - "https://ossrdbms-aad.database.windows.net/.default" - })); - - connectionString = - $"{Environment.GetEnvironmentVariable("AZURE_POSTGRESSQL_CONNECTIONSTRING")};Password={accessToken.Token}"; - } Log.Information("Setting Up Loggers"); - Log.Logger = new LoggerConfiguration() + var logger = new LoggerConfiguration() .MinimumLevel.Information() - .WriteTo.Console() - .WriteTo.PostgreSQL( + .WriteTo.Console(); + + if (!string.IsNullOrEmpty(connectionString)) + { + logger.WriteTo.PostgreSQL( connectionString, "Logs", needAutoCreateTable: true - ) - .CreateLogger(); + ); + } + else + { + logger.WriteTo.ApplicationInsights(Environment.GetEnvironmentVariable("APPLICATION_INSIGHTS_CONNECTION_STRING"), TelemetryConverter.Traces); + } + + Log.Logger = logger.CreateLogger(); builder.Host.UseSerilog(); + + builder.Services.AddApplicationInsightsTelemetry((options) => + { + options.ConnectionString = Environment.GetEnvironmentVariable("APPLICATION_INSIGHTS_CONNECTION_STRING"); + }); // Since we are in a container, we need to keep track of the data keys manually var blobStorageEndpoint = Environment.GetEnvironmentVariable("AZURE_STORAGEBLOB_RESOURCEENDPOINT") ?? ""; @@ -70,18 +71,54 @@ builder.Services.AddDataProtection() .PersistKeysToAzureBlobStorage(blobClient); } - + Log.Information("Add in Healthchecks"); builder.Services.AddHealthChecks(); - + Log.Information("Adding DB Context"); - builder.Services.AddDbContext(options => - options.UseNpgsql(connectionString, - x => x.MigrationsHistoryTable("_EfMigrations", "efcore") - ) - ); + builder.Services.AddDbContext(async (serviceProvider, options) => + { + if (string.IsNullOrEmpty(connectionString)) + { + var dataSourceBuilder = new NpgsqlDataSourceBuilder(Environment.GetEnvironmentVariable("AZURE_POSTGRESSQL_CONNECTIONSTRING")); + dataSourceBuilder.UsePasswordProvider( + passwordProvider: _ => + { + var sqlServerTokenProvider = new DefaultAzureCredential(); + AccessToken accessToken = sqlServerTokenProvider.GetToken( + new TokenRequestContext(new string[] { "https://ossrdbms-aad.database.windows.net/.default" }) + ); + + return accessToken.Token; + }, + passwordProviderAsync: async (passwordBuilder, token) => + { + var sqlServerTokenProvider = new DefaultAzureCredential(); + AccessToken accessToken = await sqlServerTokenProvider.GetTokenAsync( + new TokenRequestContext(new string[] { "https://ossrdbms-aad.database.windows.net/.default" }), + token // Pass the cancellation token along if needed + ); + + return accessToken.Token; + }); + var dataSource = dataSourceBuilder.Build(); + + options.UseNpgsql(dataSource, postgresOptions => + { + postgresOptions.MigrationsHistoryTable("_EfMigrations", "efcore"); + }); + } + else + { + options.UseNpgsql(connectionString, postgresOptions => + { + postgresOptions.MigrationsHistoryTable("_EfMigrations", "efcore"); + }); + } + + }); Log.Information("Setting Up Authentication and Identity"); builder