mirror of
https://github.com/cadmium-im/zirconium-sharp.git
synced 2024-12-22 17:01:50 +00:00
Implement DefaultAuthProvider plugin
This commit is contained in:
parent
c6fdd03908
commit
afd43e2553
@ -0,0 +1,14 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="../../Zirconium/Zirconium.csproj">
|
||||
<ExcludeAssets>runtime</ExcludeAssets>
|
||||
</ProjectReference>
|
||||
|
||||
<PackageReference Include="Konscious.Security.Cryptography.Argon2" Version="1.2.1" />
|
||||
</ItemGroup>
|
||||
</Project>
|
51
src/ZirconiumPlugins/DefaultAuthProvider/PasswordHasher.cs
Normal file
51
src/ZirconiumPlugins/DefaultAuthProvider/PasswordHasher.cs
Normal file
@ -0,0 +1,51 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using Konscious.Security.Cryptography;
|
||||
|
||||
namespace DefaultAuthProvider
|
||||
{
|
||||
public static class PasswordHasher
|
||||
{
|
||||
// First item is password hash, and second item is a salt
|
||||
public static Tuple<byte[], byte[]> CreatePasswordHash(string password)
|
||||
{
|
||||
var argon2 = new Argon2id(Encoding.UTF8.GetBytes(password));
|
||||
|
||||
var salt = createSalt();
|
||||
argon2.Salt = salt;
|
||||
argon2.DegreeOfParallelism = 2; // four cores
|
||||
argon2.Iterations = 1;
|
||||
argon2.MemorySize = 64 * 1024; // 1 GB
|
||||
|
||||
return new Tuple<byte[], byte[]>(argon2.GetBytes(32), salt);
|
||||
}
|
||||
|
||||
private static byte[] _createPasswordHashWithCustomSalt(string password, byte[] salt)
|
||||
{
|
||||
var argon2 = new Argon2id(Encoding.UTF8.GetBytes(password));
|
||||
|
||||
argon2.Salt = salt;
|
||||
argon2.DegreeOfParallelism = 2; // four cores
|
||||
argon2.Iterations = 1;
|
||||
argon2.MemorySize = 64 * 1024; // 1 GB
|
||||
|
||||
return argon2.GetBytes(32);
|
||||
}
|
||||
|
||||
private static byte[] createSalt()
|
||||
{
|
||||
var buffer = new byte[16];
|
||||
var rng = new RNGCryptoServiceProvider();
|
||||
rng.GetBytes(buffer);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
public static bool VerifyHash(string password, byte[] salt, byte[] hash)
|
||||
{
|
||||
var newHash = _createPasswordHashWithCustomSalt(password, salt);
|
||||
return hash.SequenceEqual(newHash);
|
||||
}
|
||||
}
|
||||
}
|
87
src/ZirconiumPlugins/DefaultAuthProvider/Plugin.cs
Normal file
87
src/ZirconiumPlugins/DefaultAuthProvider/Plugin.cs
Normal file
@ -0,0 +1,87 @@
|
||||
using MongoDB.Bson;
|
||||
using MongoDB.Bson.Serialization.Attributes;
|
||||
using MongoDB.Driver;
|
||||
using Zirconium.Core;
|
||||
using Zirconium.Core.Plugins.Interfaces;
|
||||
using System.Linq;
|
||||
|
||||
namespace DefaultAuthProvider
|
||||
{
|
||||
public class DefaultAuthProviderPlugin : IPluginAPI
|
||||
{
|
||||
public string GetPluginUniqueName()
|
||||
{
|
||||
return "DefaultAuthProvider";
|
||||
}
|
||||
|
||||
public void Initialize(IPluginHostAPI hostModuleAPI)
|
||||
{
|
||||
var db = hostModuleAPI.GetRawDatabase();
|
||||
hostModuleAPI.ProvideAuth(new DefaultAuthProvider(db));
|
||||
}
|
||||
}
|
||||
|
||||
public class DefaultAuthProvider : IAuthProvider
|
||||
{
|
||||
public class User
|
||||
{
|
||||
[BsonId]
|
||||
public ObjectId Id { get; set; }
|
||||
public string Username { get; set; }
|
||||
public byte[] Password { get; set; }
|
||||
public byte[] Salt { get; set; }
|
||||
}
|
||||
|
||||
private IMongoDatabase _db;
|
||||
private IMongoCollection<User> usersCol;
|
||||
|
||||
public DefaultAuthProvider(IMongoDatabase db)
|
||||
{
|
||||
this._db = db;
|
||||
this.usersCol = db.GetCollection<User>("default_auth_data");
|
||||
_createUsernameUniqueIndex();
|
||||
}
|
||||
|
||||
private void _createUsernameUniqueIndex()
|
||||
{
|
||||
var options = new CreateIndexOptions() { Unique = true };
|
||||
var field = new StringFieldDefinition<User>("Username");
|
||||
var indexDefinition = new IndexKeysDefinitionBuilder<User>().Ascending(field);
|
||||
var createIndexModel = new CreateIndexModel<User>(indexDefinition, options);
|
||||
usersCol.Indexes.CreateOne(createIndexModel);
|
||||
}
|
||||
|
||||
public void CreateUser(string username, string pass)
|
||||
{
|
||||
var user = new User();
|
||||
user.Username = username; // TODO add check on bad chars
|
||||
var hashed = PasswordHasher.CreatePasswordHash(pass);
|
||||
System.GC.Collect();
|
||||
user.Password = hashed.Item1;
|
||||
user.Salt = hashed.Item2;
|
||||
_db.GetCollection<User>("default_auth_data").InsertOne(user);
|
||||
}
|
||||
|
||||
public string GetAuthProviderName()
|
||||
{
|
||||
return "default";
|
||||
}
|
||||
|
||||
public bool TestPassword(string username, string pass)
|
||||
{
|
||||
var filter = Builders<User>.Filter.Eq("Username", username);
|
||||
var user = usersCol.Find(filter).FirstOrDefault();
|
||||
if (user == null) {
|
||||
return false;
|
||||
}
|
||||
var valid = PasswordHasher.VerifyHash(pass, user.Salt, user.Password);
|
||||
System.GC.Collect();
|
||||
return valid;
|
||||
}
|
||||
|
||||
public bool TestToken(string token, JWTPayload payload)
|
||||
{
|
||||
return true; // TODO add enchanced token validation later
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user