diff --git a/Directory.Build.props b/Directory.Build.props new file mode 100644 index 00000000..051dba7a --- /dev/null +++ b/Directory.Build.props @@ -0,0 +1,5 @@ + + + Yavsc + + diff --git a/Directory.Packages.props b/Directory.Packages.props index 076da407..151e6135 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -59,4 +59,4 @@ - \ No newline at end of file + diff --git a/src/Abstract/Constants.cs b/src/Abstract/Constants.cs index caa0398c..fad2d621 100644 --- a/src/Abstract/Constants.cs +++ b/src/Abstract/Constants.cs @@ -23,6 +23,8 @@ namespace Yavsc public const string LoginPath = "/signin"; public const string LogoutPath = "/signout"; + public const string AccessDeniedPath = "/Account/AccessDenied"; + public const string UserFilesPath = "/files"; public const string AvatarsPath = "/avatars"; public const string GitPath = "/sources"; @@ -38,6 +40,7 @@ namespace Yavsc public const string DefaultAvatar = "/images/Users/icon_user.png"; public const string AnonAvatar = "/images/Users/icon_anon_user.png"; public const string YavscConnectionStringEnvName = "YAVSC_CONNECTION_STRING"; + public const string YavscConnectionStringName = "YavscConnection"; // at the end, let 4*4 bytes in peace public const int WebSocketsMaxBufLen = 4096; diff --git a/src/Org/Controllers/Accounting/AccountController.cs b/src/Org/Controllers/Accounting/AccountController.cs index 156c8010..1b61d9cf 100644 --- a/src/Org/Controllers/Accounting/AccountController.cs +++ b/src/Org/Controllers/Accounting/AccountController.cs @@ -29,6 +29,7 @@ using System.Text.Unicode; using System.Text; using Yavsc.Server.Helpers; using System.Reflection; +using Microsoft.AspNetCore.Authentication.Cookies; namespace Yavsc.Controllers { @@ -485,7 +486,8 @@ namespace Yavsc.Controllers if (result.Succeeded) { - return Redirect(model.ReturnUrl ?? "/"); + // Redirect to returnUrl (ensure it's local to prevent open redirects) + return LocalRedirect(model.ReturnUrl); } if (result.RequiresTwoFactor) @@ -503,8 +505,6 @@ namespace Yavsc.Controllers return this.ViewOk(model); } } - - // If we got this far, something failed, redisplay form ModelState.AddModelError(string.Empty, "Unexpected behavior: something failed ... you could try again, or contact me ..."); } diff --git a/src/Org/Extensions/HostingExtensions.cs b/src/Org/Extensions/HostingExtensions.cs index 6883bf1f..8946ea6f 100644 --- a/src/Org/Extensions/HostingExtensions.cs +++ b/src/Org/Extensions/HostingExtensions.cs @@ -41,6 +41,7 @@ using System.IdentityModel.Tokens.Jwt; using IdentityServer8.EntityFramework.Stores; using IdentityServer8.EntityFramework.Services; using IdentityServer8.EntityFramework.Interfaces; +using Microsoft.AspNetCore.Authentication.Cookies; namespace Yavsc.Extensions; @@ -135,16 +136,15 @@ public static class HostingExtensions IServiceCollection services = builder.Services; services.AddDbContext(options => { - options.UseNpgsql(builder.Configuration.GetConnectionString("DefaultConnection"), - options => options.MigrationsAssembly("Yavsc") - ); - } - ); + options.UseNpgsql(builder.Configuration.GetConnectionString(Constants.YavscConnectionStringName ), + options => options.MigrationsAssembly(typeof(Program).Assembly)); + }); return services.AddIdentity( options => { - options.SignIn.RequireConfirmedAccount = true; + options.SignIn.RequireConfirmedAccount = builder.Environment.IsEnvironment( + builder.Environment.EnvironmentName); options.ClaimsIdentity.UserNameClaimType = JwtClaimTypes.PreferredUserName; options.ClaimsIdentity.RoleClaimType = Constants.RoleClaimType; } @@ -204,7 +204,7 @@ public static class HostingExtensions // OAuth2AppSettings var googleAuthSettings = builder.Configuration.GetSection("Authentication:Google"); - //LoadGoogleConfig(builder.Configuration); + LoadGoogleConfig(builder.Configuration); var services = builder.Services; @@ -245,7 +245,7 @@ public static class HostingExtensions private static IIdentityServerBuilder AddIdentityServer(WebApplicationBuilder builder) { var migrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name; - var connectionString = builder.Configuration.GetConnectionString("DefaultConnection"); + var connectionString = builder.Configuration.GetConnectionString(Constants.YavscConnectionStringName); var identityServerBuilder = builder.Services.AddIdentityServer(options => { @@ -276,6 +276,20 @@ public static class HostingExtensions sql => sql.MigrationsAssembly(migrationsAssembly)); }); + builder.Services.AddAuthentication( + CookieAuthenticationDefaults.AuthenticationScheme) +.AddCookie(options => +{ + options.LoginPath = Constants.LoginPath; // Redirect here if unauthenticated + options.AccessDeniedPath = Constants.AccessDeniedPath; + options.Cookie.SecurePolicy = builder.Environment.IsDevelopment() + ? CookieSecurePolicy.None + : CookieSecurePolicy.Always; // Use HTTPS in production + options.Cookie.SameSite = Microsoft.AspNetCore.Http.SameSiteMode.Lax; // Allows cross-site top-level navigation + options.ExpireTimeSpan = TimeSpan.FromMinutes(30); // Cookie expires in 30 mins + options.SlidingExpiration = true; // Renew cookie if user is active +}); + builder.Services.Configure(options => { options.ClaimsIdentity.UserIdClaimType = JwtClaimTypes.Subject; @@ -290,7 +304,6 @@ public static class HostingExtensions else { var path = builder.Configuration["SigningCert:Path"]; - var pass = builder.Configuration["SigningCert:Password"]; if (path == null) throw new InvalidConfigurationException("No signing cert path"); FileInfo certFileInfo = new FileInfo(path); @@ -312,16 +325,16 @@ public static class HostingExtensions { CultureInfo[] supportedCultures = new[] { - new CultureInfo("en"), - new CultureInfo("fr"), - new CultureInfo("pt") + new CultureInfo("en"), + new CultureInfo("fr"), + new CultureInfo("pt") }; CultureInfo[] supportedUICultures = new[] { - new CultureInfo("fr"), - new CultureInfo("en"), - new CultureInfo("pt") + new CultureInfo("fr"), + new CultureInfo("en"), + new CultureInfo("pt") }; // You must explicitly state which cultures your application supports. @@ -332,11 +345,11 @@ public static class HostingExtensions options.SupportedUICultures = supportedUICultures; options.RequestCultureProviders = new List - { - new QueryStringRequestCultureProvider { Options = options }, - new CookieRequestCultureProvider { Options = options, CookieName="ASPNET_CULTURE" }, - new AcceptLanguageHeaderRequestCultureProvider { Options = options } - }; + { + new QueryStringRequestCultureProvider { Options = options }, + new CookieRequestCultureProvider { Options = options, CookieName="ASPNET_CULTURE" }, + new AcceptLanguageHeaderRequestCultureProvider { Options = options } + }; }); } diff --git a/src/Org/Org.csproj b/src/Org/Org.csproj index 383367b0..0fef8617 100644 --- a/src/Org/Org.csproj +++ b/src/Org/Org.csproj @@ -50,4 +50,4 @@ - \ No newline at end of file + diff --git a/src/Org/appsettings.json b/src/Org/appsettings.json index fd7cdb1f..6d07e28e 100644 --- a/src/Org/appsettings.json +++ b/src/Org/appsettings.json @@ -9,7 +9,7 @@ }, "AllowedHosts": "*", "ConnectionStrings": { - "DefaultConnection": "Server=[YOURSERVERNAME];Port=5432;Database=[YOURDBNAME];Username=[YOURDBUSERNAME];Password=[YOURDBPASSW];" + "YavscConnection": "Server=[YOURSERVERNAME];Port=5432;Database=[YOURDBNAME];Username=[YOURDBUSERNAME];Password=[YOURDBPASSW];" }, "Site": { "Title": "Yavsc", diff --git a/src/Server/Models/ApplicationDbContext.cs b/src/Server/Models/ApplicationDbContext.cs index 74163c52..66043647 100644 --- a/src/Server/Models/ApplicationDbContext.cs +++ b/src/Server/Models/ApplicationDbContext.cs @@ -86,13 +86,6 @@ namespace Yavsc.Models builder.Entity().Property(a => a.ParentCode).IsRequired(false); // builder.Entity>().HasKey(i=> new { i.LoginProvider, i.UserId, i.ProviderKey }); } - protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) - { - string? envCxStr = Environment.GetEnvironmentVariable(Constants.YavscConnectionStringEnvName); - if (envCxStr != null) - optionsBuilder.UseNpgsql(envCxStr); - base.OnConfiguring(optionsBuilder); - } /// /// Activities referenced on this site diff --git a/test/yavscTests/appsettings.json b/test/yavscTests/appsettings.json index 383712b6..e0b05b6e 100644 --- a/test/yavscTests/appsettings.json +++ b/test/yavscTests/appsettings.json @@ -41,7 +41,7 @@ } }, "ConnectionStrings": { - "DefaultConnection": "Server=lame-NpgsqlHostName;Port=5432;Database=lame-DataBase;Username=lame-Username;Password=lame-dbPassword;", + "YavscConnection": "Server=lame-NpgsqlHostName;Port=5432;Database=lame-DataBase;Username=lame-Username;Password=lame-dbPassword;", }, "DataProtection": { "Keys": {