Skip to content

Commit

Permalink
disable external auth if not configured in-dev, reformat auth setup
Browse files Browse the repository at this point in the history
  • Loading branch information
NielsPilgaard committed Apr 28, 2024
1 parent 40d91af commit c2cd8ce
Show file tree
Hide file tree
Showing 2 changed files with 141 additions and 72 deletions.
127 changes: 127 additions & 0 deletions src/web/Jordnaer/Extensions/AuthenticationExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
using Jordnaer.Components.Account;
using Jordnaer.Database;
using Jordnaer.Features.Authentication;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Facebook;
using Microsoft.AspNetCore.Authentication.Google;
using Microsoft.AspNetCore.Authentication.MicrosoftAccount;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Identity;
using Serilog;

namespace Jordnaer.Extensions;

public static class AuthenticationExtensions
{
public static WebApplicationBuilder AddAuthentication(this WebApplicationBuilder builder)
{
builder.Services.AddCascadingAuthenticationState();
builder.Services.AddScoped<IdentityUserAccessor>();
builder.Services.AddScoped<IdentityRedirectManager>();
builder.Services.AddScoped<AuthenticationStateProvider, IdentityRevalidatingAuthenticationStateProvider>();
builder.Services.AddCurrentUser();

builder.Services
.AddAuthentication(options =>
{
options.DefaultScheme = IdentityConstants.ApplicationScheme;
options.DefaultSignInScheme = IdentityConstants.ExternalScheme;
})
.AddFacebookAuthentication(builder.Configuration, builder.Environment.IsDevelopment())
.AddMicrosoftAuthentication(builder.Configuration, builder.Environment.IsDevelopment())
.AddGoogleAuthentication(builder.Configuration, builder.Environment.IsDevelopment())
.AddIdentityCookies();

builder.Services
.AddIdentityCore<ApplicationUser>(options =>
{
options.SignIn.RequireConfirmedAccount = true;
options.User.RequireUniqueEmail = true;
})
.AddEntityFrameworkStores<JordnaerDbContext>()
.AddSignInManager()
.AddDefaultTokenProviders();

return builder;
}

private static AuthenticationBuilder AddGoogleAuthentication(
this AuthenticationBuilder builder,
ConfigurationManager configuration, bool isDevelopment)
{
var googleOptions = new GoogleOptions();
configuration.GetSection("Authentication:Schemes:Google").Bind(googleOptions);

if ((string.IsNullOrEmpty(googleOptions.ClientId) || string.IsNullOrEmpty(googleOptions.ClientSecret))
&& isDevelopment)
{
Log.Warning("Google Authentication is not enabled, " +
"because it's configuration section was not set. " +
"SectionName {SectionName}", "Authentication:Schemes:Google");
return builder;
}

builder.AddGoogle(options =>
{
options.ClientId = googleOptions.ClientId;
options.ClientSecret = googleOptions.ClientSecret;
options.SaveTokens = true;
});

return builder;
}

private static AuthenticationBuilder AddFacebookAuthentication(
this AuthenticationBuilder builder,
ConfigurationManager configuration,
bool isDevelopment)
{
var facebookOptions = new FacebookOptions();
configuration.GetSection("Authentication:Schemes:Facebook").Bind(facebookOptions);

if ((string.IsNullOrEmpty(facebookOptions.AppId) || string.IsNullOrEmpty(facebookOptions.AppSecret))
&& isDevelopment)
{
Log.Warning("Google Authentication is not enabled, " +
"because it's configuration section was not set. " +
"SectionName {SectionName}", "Authentication:Schemes:Google");
return builder;
}

builder.AddFacebook(options =>
{
options.AppId = facebookOptions.AppId;
options.AppSecret = facebookOptions.AppSecret;
options.SaveTokens = true;
});

return builder;
}

private static AuthenticationBuilder AddMicrosoftAuthentication(
this AuthenticationBuilder builder,
ConfigurationManager configuration,
bool isDevelopment)
{
var microsoftOptions = new MicrosoftAccountOptions();
configuration.GetSection("Authentication:Schemes:Microsoft").Bind(microsoftOptions);

if ((string.IsNullOrEmpty(microsoftOptions.ClientId) || string.IsNullOrEmpty(microsoftOptions.ClientSecret))
&& isDevelopment)
{
Log.Warning("Google Authentication is not enabled, " +
"because it's configuration section was not set. " +
"SectionName {SectionName}", "Authentication:Schemes:Google");
return builder;
}

builder.AddMicrosoftAccount(options =>
{
options.ClientId = microsoftOptions.ClientId;
options.ClientSecret = microsoftOptions.ClientSecret;
options.SaveTokens = true;
});

return builder;
}
}
86 changes: 14 additions & 72 deletions src/web/Jordnaer/Extensions/WebApplicationBuilderExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
using Grafana.OpenTelemetry;
using Jordnaer.Components.Account;
using Jordnaer.Database;
using Jordnaer.Features.Authentication;
using MassTransit;
using MassTransit.Logging;
using MassTransit.Monitoring;
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.ResponseCompression;
using Microsoft.EntityFrameworkCore;
using MudBlazor;
Expand Down Expand Up @@ -135,12 +131,13 @@ public static WebApplicationBuilder AddOpenTelemetry(this WebApplicationBuilder
return builder;
}

private static IHostApplicationBuilder AddAspireOpenTelemetryExporters(this IHostApplicationBuilder builder)
private static void AddAspireOpenTelemetryExporters(this IHostApplicationBuilder builder)
{
// The default endpoint is http://localhost:4318, it's automatically set when using Aspire
// If you want to run the Aspire dashboard standalone, set
// the OTEL_EXPORTER_OTLP_ENDPOINT environment variable or appsetting to http://localhost:4318
var useOtlpExporter = !string.IsNullOrWhiteSpace(builder.Configuration["OTEL_EXPORTER_OTLP_ENDPOINT"]);

if (useOtlpExporter)
{
builder.Services.Configure<OpenTelemetryLoggerOptions>(logging => logging.AddOtlpExporter());
Expand All @@ -154,82 +151,27 @@ private static IHostApplicationBuilder AddAspireOpenTelemetryExporters(this IHos
// builder.Services.AddOpenTelemetry()
// .UseAzureMonitor();
//}

return builder;
}

public static WebApplicationBuilder AddAuthentication(this WebApplicationBuilder builder)
{
builder.Services.AddCascadingAuthenticationState();
builder.Services.AddScoped<IdentityUserAccessor>();
builder.Services.AddScoped<IdentityRedirectManager>();
builder.Services.AddScoped<AuthenticationStateProvider, IdentityRevalidatingAuthenticationStateProvider>();
builder.Services.AddCurrentUser();

builder.Services.AddAuthentication(options =>
{
options.DefaultScheme = IdentityConstants.ApplicationScheme;
options.DefaultSignInScheme = IdentityConstants.ExternalScheme;
}).AddFacebook(options =>
{
options.AppId = builder.Configuration.GetValue<string>("Authentication:Schemes:Facebook:AppId")!;
options.AppSecret = builder.Configuration.GetValue<string>("Authentication:Schemes:Facebook:AppSecret")!;
options.SaveTokens = true;
}).AddMicrosoftAccount(options =>
{
options.ClientId = builder.Configuration.GetValue<string>("Authentication:Schemes:Microsoft:ClientId")!;
options.ClientSecret = builder.Configuration.GetValue<string>("Authentication:Schemes:Microsoft:ClientSecret")!;
options.SaveTokens = true;
}).AddGoogle(options =>
{
options.ClientId = builder.Configuration.GetValue<string>("Authentication:Schemes:Google:ClientId")!;
options.ClientSecret = builder.Configuration.GetValue<string>("Authentication:Schemes:Google:ClientSecret")!;
options.SaveTokens = true;
}).AddIdentityCookies();

builder.Services.AddIdentityCore<ApplicationUser>(options =>
{
options.SignIn.RequireConfirmedAccount = true;
options.User.RequireUniqueEmail = true;
})
.AddEntityFrameworkStores<JordnaerDbContext>()
.AddSignInManager()
.AddDefaultTokenProviders();

return builder;
}

public static WebApplicationBuilder AddDatabase(this WebApplicationBuilder builder)
{
var dbConnectionString = GetConnectionString(builder.Configuration);
var connectionString = GetConnectionString(builder.Configuration);

builder.Services.AddDbContextFactory<JordnaerDbContext>(optionsBuilder => optionsBuilder.UseSqlServer(
dbConnectionString,
contextOptionsBuilder =>
contextOptionsBuilder.UseAzureSqlDefaults()),
ServiceLifetime.Scoped);
builder.Services
.AddDbContextFactory<JordnaerDbContext>(
optionsBuilder =>
optionsBuilder.UseSqlServer(connectionString,
contextOptionsBuilder =>
contextOptionsBuilder.UseAzureSqlDefaults()),
ServiceLifetime.Scoped);

builder.Services.AddHealthChecks().AddSqlServer(dbConnectionString);

if (builder.Environment.IsDevelopment())
{
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
}
builder.Services.AddHealthChecks().AddSqlServer(connectionString);

return builder;
}

/// <summary>
/// ConnectionStrings:jordnaer -> Aspire
/// ConnectionStrings:JordnaerDbContext_dev -> local container, created by Visual Studio
/// ConnectionStrings:JordnaerDbContext -> production Azure SQL Database
/// </summary>
/// <param name="configuration"></param>
/// <returns></returns>
/// <exception cref="InvalidOperationException"></exception>
private static string GetConnectionString(IConfiguration configuration) =>
configuration.GetConnectionString("jordnaer") ??
configuration.GetConnectionString($"{nameof(JordnaerDbContext)}_dev") ??
configuration.GetConnectionString(nameof(JordnaerDbContext)) ??
throw new InvalidOperationException($"Connection string '{nameof(JordnaerDbContext)}' not found.");
configuration.GetConnectionString(nameof(JordnaerDbContext))
?? throw new InvalidOperationException(
$"Connection string '{nameof(JordnaerDbContext)}' not found.");
}

0 comments on commit c2cd8ce

Please sign in to comment.