Fix format and update the method of pulling connection string from kv with dac
This commit is contained in:
@@ -11,7 +11,6 @@ public static class Dependencies
|
|||||||
public static void ConfigureServices(IConfiguration configuration, IServiceCollection services)
|
public static void ConfigureServices(IConfiguration configuration, IServiceCollection services)
|
||||||
{
|
{
|
||||||
var useOnlyInMemoryDatabase = false;
|
var useOnlyInMemoryDatabase = false;
|
||||||
|
|
||||||
if (configuration["UseOnlyInMemoryDatabase"] != null)
|
if (configuration["UseOnlyInMemoryDatabase"] != null)
|
||||||
{
|
{
|
||||||
useOnlyInMemoryDatabase = bool.Parse(configuration["UseOnlyInMemoryDatabase"]);
|
useOnlyInMemoryDatabase = bool.Parse(configuration["UseOnlyInMemoryDatabase"]);
|
||||||
|
|||||||
148
src/Web/AzureDeveloperCliCredential.cs
Normal file
148
src/Web/AzureDeveloperCliCredential.cs
Normal file
@@ -0,0 +1,148 @@
|
|||||||
|
using Azure.Core;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
|
namespace Azure.Identity
|
||||||
|
{
|
||||||
|
public class AzureDeveloperCliCredential : TokenCredential
|
||||||
|
{
|
||||||
|
internal const string AzdCliNotInstalled = $"Azure Developer CLI could not be found. {Troubleshoot}";
|
||||||
|
internal const string AzdNotLogIn = "Please run 'azd login' from a command prompt to authenticate before using this credential.";
|
||||||
|
internal const string WinAzdCliError = "'azd is not recognized";
|
||||||
|
internal const string AzdCliTimeoutError = "Azure Developer CLI authentication timed out.";
|
||||||
|
internal const string AzdCliFailedError = "Azure Developer CLI authentication failed due to an unknown error.";
|
||||||
|
internal const string Troubleshoot = "Please visit https://aka.ms/azure-dev for installation instructions and then, once installed, authenticate to your Azure account using 'azd login'.";
|
||||||
|
internal const string InteractiveLoginRequired = "Azure Developer CLI could not login. Interactive login is required.";
|
||||||
|
private const string RefreshTokeExpired = "The provided authorization code or refresh token has expired due to inactivity. Send a new interactive authorization request for this user and resource.";
|
||||||
|
|
||||||
|
private static readonly string DefaultWorkingDirWindows = Environment.GetFolderPath(Environment.SpecialFolder.System);
|
||||||
|
private const string DefaultWorkingDirNonWindows = "/bin/";
|
||||||
|
private static readonly string DefaultWorkingDir = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? DefaultWorkingDirWindows : DefaultWorkingDirNonWindows;
|
||||||
|
|
||||||
|
private static readonly Regex AzdNotFoundPattern = new Regex("azd:(.*)not found");
|
||||||
|
|
||||||
|
public override AccessToken GetToken(TokenRequestContext requestContext, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
return RequestCliAccessTokenAsync(requestContext, cancellationToken)
|
||||||
|
.GetAwaiter()
|
||||||
|
.GetResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async ValueTask<AccessToken> GetTokenAsync(TokenRequestContext requestContext, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
return await RequestCliAccessTokenAsync(requestContext, cancellationToken).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async ValueTask<AccessToken> RequestCliAccessTokenAsync(TokenRequestContext context, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ProcessStartInfo processStartInfo = GetAzdCliProcessStartInfo(context.Scopes);
|
||||||
|
string output = await RunProcessAsync(processStartInfo);
|
||||||
|
|
||||||
|
return DeserializeOutput(output);
|
||||||
|
}
|
||||||
|
catch (OperationCanceledException) when (!cancellationToken.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
throw new AuthenticationFailedException(AzdCliTimeoutError);
|
||||||
|
}
|
||||||
|
catch (InvalidOperationException exception)
|
||||||
|
{
|
||||||
|
bool isWinError = exception.Message.StartsWith(WinAzdCliError, StringComparison.CurrentCultureIgnoreCase);
|
||||||
|
bool isOtherOsError = AzdNotFoundPattern.IsMatch(exception.Message);
|
||||||
|
|
||||||
|
if (isWinError || isOtherOsError)
|
||||||
|
{
|
||||||
|
throw new CredentialUnavailableException(AzdCliNotInstalled);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isAADSTSError = exception.Message.Contains("AADSTS");
|
||||||
|
bool isLoginError = exception.Message.IndexOf("azd login", StringComparison.OrdinalIgnoreCase) != -1;
|
||||||
|
|
||||||
|
if (isLoginError && !isAADSTSError)
|
||||||
|
{
|
||||||
|
throw new CredentialUnavailableException(AzdNotLogIn);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isRefreshTokenFailedError = exception.Message.IndexOf(AzdCliFailedError, StringComparison.OrdinalIgnoreCase) != -1 &&
|
||||||
|
exception.Message.IndexOf(RefreshTokeExpired, StringComparison.OrdinalIgnoreCase) != -1 ||
|
||||||
|
exception.Message.IndexOf("CLIInternalError", StringComparison.OrdinalIgnoreCase) != -1;
|
||||||
|
|
||||||
|
if (isRefreshTokenFailedError)
|
||||||
|
{
|
||||||
|
throw new CredentialUnavailableException(InteractiveLoginRequired);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new AuthenticationFailedException($"{AzdCliFailedError} {Troubleshoot} {exception.Message}");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
throw new CredentialUnavailableException($"{AzdCliFailedError} {Troubleshoot} {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async ValueTask<string> RunProcessAsync(ProcessStartInfo processStartInfo, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
var process = Process.Start(processStartInfo);
|
||||||
|
if (process == null)
|
||||||
|
{
|
||||||
|
throw new CredentialUnavailableException(AzdCliFailedError);
|
||||||
|
}
|
||||||
|
|
||||||
|
await process.WaitForExitAsync(cancellationToken);
|
||||||
|
|
||||||
|
if (process.ExitCode != 0)
|
||||||
|
{
|
||||||
|
var errorMessage = process.StandardError.ReadToEnd();
|
||||||
|
throw new InvalidOperationException(errorMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
return process.StandardOutput.ReadToEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
private ProcessStartInfo GetAzdCliProcessStartInfo(string[] scopes)
|
||||||
|
{
|
||||||
|
string scopeArgs = string.Join(" ", scopes.Select(scope => string.Format($"--scope {scope}")));
|
||||||
|
string command = $"azd auth token --output json {scopeArgs}";
|
||||||
|
|
||||||
|
string fileName;
|
||||||
|
string argument;
|
||||||
|
|
||||||
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||||
|
{
|
||||||
|
fileName = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.System), "cmd.exe");
|
||||||
|
argument = $"/c \"{command}\"";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fileName = "/bin/sh";
|
||||||
|
argument = $"-c \"{command}\"";
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ProcessStartInfo
|
||||||
|
{
|
||||||
|
FileName = fileName,
|
||||||
|
Arguments = argument,
|
||||||
|
UseShellExecute = false,
|
||||||
|
RedirectStandardOutput = true,
|
||||||
|
RedirectStandardError = true,
|
||||||
|
ErrorDialog = false,
|
||||||
|
CreateNoWindow = true,
|
||||||
|
WorkingDirectory = DefaultWorkingDir,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static AccessToken DeserializeOutput(string output)
|
||||||
|
{
|
||||||
|
using JsonDocument document = JsonDocument.Parse(output);
|
||||||
|
|
||||||
|
JsonElement root = document.RootElement;
|
||||||
|
string accessToken = root.GetProperty("token").GetString();
|
||||||
|
DateTimeOffset expiresOn = root.GetProperty("expiresOn").GetDateTimeOffset();
|
||||||
|
|
||||||
|
return new AccessToken(accessToken, expiresOn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
using System.Net.Mime;
|
using System.Net.Mime;
|
||||||
using Ardalis.ListStartupServices;
|
using Ardalis.ListStartupServices;
|
||||||
|
using Azure.Identity;
|
||||||
using BlazorAdmin;
|
using BlazorAdmin;
|
||||||
using BlazorAdmin.Services;
|
using BlazorAdmin.Services;
|
||||||
using Blazored.LocalStorage;
|
using Blazored.LocalStorage;
|
||||||
@@ -8,6 +9,7 @@ using Microsoft.AspNetCore.Authentication.Cookies;
|
|||||||
using Microsoft.AspNetCore.Diagnostics.HealthChecks;
|
using Microsoft.AspNetCore.Diagnostics.HealthChecks;
|
||||||
using Microsoft.AspNetCore.Identity;
|
using Microsoft.AspNetCore.Identity;
|
||||||
using Microsoft.AspNetCore.Mvc.ApplicationModels;
|
using Microsoft.AspNetCore.Mvc.ApplicationModels;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.eShopWeb;
|
using Microsoft.eShopWeb;
|
||||||
using Microsoft.eShopWeb.ApplicationCore.Interfaces;
|
using Microsoft.eShopWeb.ApplicationCore.Interfaces;
|
||||||
using Microsoft.eShopWeb.Infrastructure.Data;
|
using Microsoft.eShopWeb.Infrastructure.Data;
|
||||||
@@ -21,7 +23,19 @@ var builder = WebApplication.CreateBuilder(args);
|
|||||||
|
|
||||||
builder.Logging.AddConsole();
|
builder.Logging.AddConsole();
|
||||||
|
|
||||||
Microsoft.eShopWeb.Infrastructure.Dependencies.ConfigureServices(builder.Configuration, builder.Services);
|
// Configure SQL Server
|
||||||
|
var credential = new ChainedTokenCredential(new AzureDeveloperCliCredential(), new DefaultAzureCredential());
|
||||||
|
builder.Configuration.AddAzureKeyVault(new Uri(builder.Configuration["AZURE_KEY_VAULT_ENDPOINT"]), credential);
|
||||||
|
builder.Services.AddDbContext<CatalogContext>(c =>
|
||||||
|
{
|
||||||
|
var connectionString = builder.Configuration[builder.Configuration["AZURE_SQL_CATALOG_CONNECTION_STRING_KEY"]];
|
||||||
|
c.UseSqlServer(connectionString, sqlOptions => sqlOptions.EnableRetryOnFailure());
|
||||||
|
});
|
||||||
|
builder.Services.AddDbContext<AppIdentityDbContext>(options =>
|
||||||
|
{
|
||||||
|
var connectionString = builder.Configuration[builder.Configuration["AZURE_SQL_IDENTITY_CONNECTION_STRING_KEY"]];
|
||||||
|
options.UseSqlServer(connectionString, sqlOptions => sqlOptions.EnableRetryOnFailure());
|
||||||
|
});
|
||||||
|
|
||||||
builder.Services.AddCookieSettings();
|
builder.Services.AddCookieSettings();
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,8 @@
|
|||||||
<PackageReference Include="Ardalis.ListStartupServices" Version="1.1.4" />
|
<PackageReference Include="Ardalis.ListStartupServices" Version="1.1.4" />
|
||||||
<PackageReference Include="Ardalis.Specification" Version="6.1.0" />
|
<PackageReference Include="Ardalis.Specification" Version="6.1.0" />
|
||||||
<PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="11.0.0" />
|
<PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="11.0.0" />
|
||||||
|
<PackageReference Include="Azure.Extensions.AspNetCore.Configuration.Secrets" Version="1.2.1" />
|
||||||
|
<PackageReference Include="Azure.Identity" Version="1.5.0" />
|
||||||
<PackageReference Include="MediatR" Version="10.0.1" />
|
<PackageReference Include="MediatR" Version="10.0.1" />
|
||||||
<PackageReference Include="MediatR.Extensions.Microsoft.DependencyInjection" Version="10.0.1" />
|
<PackageReference Include="MediatR.Extensions.Microsoft.DependencyInjection" Version="10.0.1" />
|
||||||
<PackageReference Include="BuildBundlerMinifier" Version="3.2.449" Condition="'$(Configuration)'=='Release'" PrivateAssets="All" />
|
<PackageReference Include="BuildBundlerMinifier" Version="3.2.449" Condition="'$(Configuration)'=='Release'" PrivateAssets="All" />
|
||||||
|
|||||||
Reference in New Issue
Block a user