mirror of
https://github.com/cadmium-im/zirconium-sharp.git
synced 2024-11-22 10:22:23 +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