This commit is contained in:
Wieland, Marc
2026-06-26 14:49:30 +02:00
parent f4512a807c
commit 7d9eac498a
3 changed files with 89 additions and 1 deletions
+56
View File
@@ -1,4 +1,6 @@
using System.Security.Claims;
using System.Security.Cryptography;
using System.Text;
using System.Threading.RateLimiting;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
@@ -11,6 +13,8 @@ using timetracker.Data;
using timetracker.Shared;
var builder = WebApplication.CreateBuilder(args);
const string SuperAdminUsername = "marc";
const string SuperAdminPassword = "123456";
// Add Authentication
builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
@@ -277,6 +281,32 @@ using (var scope = app.Services.CreateScope())
Console.WriteLine($"Fehler beim Konvertieren der PostgreSQL-Spaltentypen (IsTenantAdmin/IsApproved/CreatedAt): {ex.Message}");
}
}
var superAdmin = await db.Users
.IgnoreQueryFilters()
.FirstOrDefaultAsync(u => u.TenantId == null && u.Username == SuperAdminUsername);
if (superAdmin == null)
{
var (passwordHash, passwordSalt) = HashPassword(SuperAdminPassword);
db.Users.Add(new User
{
Username = SuperAdminUsername,
PasswordHash = passwordHash,
PasswordSalt = passwordSalt,
TenantId = null,
IsTenantAdmin = true
});
await db.SaveChangesAsync();
}
else if (IsLegacySeedPassword(superAdmin.PasswordHash, superAdmin.PasswordSalt, SuperAdminPassword))
{
var (passwordHash, passwordSalt) = HashPassword(SuperAdminPassword);
superAdmin.PasswordHash = passwordHash;
superAdmin.PasswordSalt = passwordSalt;
superAdmin.IsTenantAdmin = true;
await db.SaveChangesAsync();
}
}
var forwardedHeadersOptions = new ForwardedHeadersOptions
@@ -821,6 +851,32 @@ superAdminApi.MapDelete("/tenants/{id:int}", async (int id, TimetrackerDbContext
app.Run();
static (string Hash, string Salt) HashPassword(string password)
{
var saltBytes = RandomNumberGenerator.GetBytes(32);
var salt = Convert.ToBase64String(saltBytes);
var hash = ComputePasswordHash(password, salt);
return (hash, salt);
}
static bool IsLegacySeedPassword(string hash, string salt, string password)
{
var passwordBytes = Encoding.UTF8.GetBytes(password + salt);
var legacyHash = Convert.ToBase64String(SHA256.HashData(passwordBytes));
return hash == legacyHash;
}
static string ComputePasswordHash(string password, string salt)
{
var hash = Rfc2898DeriveBytes.Pbkdf2(
Encoding.UTF8.GetBytes(password),
Convert.FromBase64String(salt),
iterations: 200_000,
HashAlgorithmName.SHA256,
outputLength: 32);
return Convert.ToBase64String(hash);
}
// ── Models for Request Bodies ──────────────────────────────────────────────────
public record LoginRequest(string Username, string Password);
public record RegisterRequest(string Username, string Password, string? Honeypot = null);