accounts + argon2 migration

This commit is contained in:
2025-05-16 09:04:03 -04:00
parent 12a28f00b1
commit 3ac1fbcd8e
6 changed files with 104 additions and 3 deletions

View File

@@ -0,0 +1,63 @@
using AobaCore.Models;
using Isopoh.Cryptography.Argon2;
using MongoDB.Bson;
using MongoDB.Driver;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
namespace AobaCore;
public class AccountsService(IMongoDatabase db)
{
public readonly IMongoCollection<User> _users = db.GetCollection<User>("users");
public async Task<User?> GetUserAsync(ObjectId id, CancellationToken cancellationToken = default)
{
return await _users.Find(u => u.Id == id).FirstOrDefaultAsync(cancellationToken);
}
public async Task<bool> VerifyLoginAsync(string username, string password, CancellationToken cancellationToken = default)
{
var user = await _users.Find(u => u.Username == username).FirstOrDefaultAsync(cancellationToken);
if(user.IsArgon)
return Argon2.Verify(user.PasswordHash, password);
if(LegacyVerifyPassword( password, user.PasswordHash))
{
var argon2Hash = Argon2.Hash(password);
var update = Builders<User>.Update.Set(u => u.PasswordHash, argon2Hash).Set(u => u.IsArgon, true);
await _users.UpdateOneAsync(u => u.Id == user.Id, update, cancellationToken: cancellationToken);
return true;
}
return false;
}
public bool LegacyVerifyPassword(string password, string passwordHash)
{
if (string.IsNullOrWhiteSpace(password) || string.IsNullOrWhiteSpace(passwordHash))
return false;
/* Extract the bytes */
byte[] hashBytes = Convert.FromBase64String(passwordHash);
/* Get the salt */
byte[] salt = new byte[16];
Array.Copy(hashBytes, 0, salt, 0, 16);
/* Compute the hash on the password the user entered */
var pbkdf2 = new Rfc2898DeriveBytes(password, salt, 10000, HashAlgorithmName.SHA1);
byte[] hash = pbkdf2.GetBytes(20);
/* Compare the results */
for (int i = 0; i < 20; i++)
if (hashBytes[i + 16] != hash[i])
return false;
return true;
}
}

View File

@@ -7,12 +7,14 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Isopoh.Cryptography.Argon2" Version="2.0.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="9.0.4" /> <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="9.0.4" />
<PackageReference Include="MaybeError" Version="1.1.0" /> <PackageReference Include="MaybeError" Version="1.1.0" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="9.0.4" /> <PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="9.0.4" />
<PackageReference Include="MongoDB.Analyzer" Version="1.5.0" /> <PackageReference Include="MongoDB.Analyzer" Version="1.5.0" />
<PackageReference Include="MongoDB.Driver" Version="3.3.0" /> <PackageReference Include="MongoDB.Driver" Version="3.3.0" />
<PackageReference Include="MongoDB.Driver.Core.Extensions.DiagnosticSources" Version="2.0.0" /> <PackageReference Include="MongoDB.Driver.Core.Extensions.DiagnosticSources" Version="2.0.0" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.10.0" />
</ItemGroup> </ItemGroup>
</Project> </Project>

35
AobaCore/Models/User.cs Normal file
View File

@@ -0,0 +1,35 @@
using Microsoft.IdentityModel.Tokens;
using MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes;
using System;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
namespace AobaCore.Models;
public class User
{
[BsonId]
public ObjectId Id { get; set; }
public required string Username { get; set; }
public required string PasswordHash { get; set; }
public required string Role { get; set; }
public bool IsArgon { get; set; }
public ObjectId[] ApiKeys { get; set; } = [];
public List<ObjectId> RegTokens { get; set; } = [];
public ClaimsIdentity GetIdentity()
{
var id = new ClaimsIdentity(new[]
{
new Claim(ClaimTypes.NameIdentifier, Id.ToString()),
new Claim(ClaimTypes.Name, Username),
});
if (Role != null)
id.AddClaim(new Claim(ClaimTypes.Role, Role));
return id;
}
}

View File

@@ -1,4 +1,6 @@
using Microsoft.IdentityModel.Tokens; using AobaServer.Models;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt; using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims; using System.Security.Claims;

View File

@@ -3,7 +3,7 @@
using System.Security.Cryptography; using System.Security.Cryptography;
using System.Text.Json; using System.Text.Json;
namespace AobaServer; namespace AobaServer.Models;
public class AuthInfo public class AuthInfo
{ {

View File

@@ -1,6 +1,5 @@
using AobaCore; using AobaCore;
using AobaServer;
using AobaServer.Auth; using AobaServer.Auth;
using AobaServer.Middleware; using AobaServer.Middleware;
using AobaServer.Models; using AobaServer.Models;