added abstraction layer for password hashing
This commit is contained in:
parent
0143b933d5
commit
ec0c7a64b5
4 changed files with 40 additions and 9 deletions
|
@ -1,5 +1,7 @@
|
||||||
module calendarwebapp.authenticator;
|
module calendarwebapp.authenticator;
|
||||||
|
|
||||||
|
import calendarwebapp.passhash : PasswordHasher;
|
||||||
|
|
||||||
import poodinis;
|
import poodinis;
|
||||||
|
|
||||||
import std.range : InputRange;
|
import std.range : InputRange;
|
||||||
|
@ -21,6 +23,7 @@ class MongoDBAuthenticator(Collection = MongoCollection) : Authenticator
|
||||||
private:
|
private:
|
||||||
@Value("users")
|
@Value("users")
|
||||||
Collection users;
|
Collection users;
|
||||||
|
@Autowire PasswordHasher passwordHasher;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Nullable!AuthInfo checkUser(string username, string password) @safe
|
Nullable!AuthInfo checkUser(string username, string password) @safe
|
||||||
|
@ -28,13 +31,13 @@ public:
|
||||||
import botan.passhash.bcrypt : checkBcrypt;
|
import botan.passhash.bcrypt : checkBcrypt;
|
||||||
|
|
||||||
auto result = users.findOne(["username" : username]);
|
auto result = users.findOne(["username" : username]);
|
||||||
/* checkBcrypt should be called using vibe.core.concurrency.async to
|
/* checkHash should be called using vibe.core.concurrency.async to
|
||||||
avoid blocking, but https://github.com/vibe-d/vibe.d/issues/1521 is
|
avoid blocking, but https://github.com/vibe-d/vibe.d/issues/1521 is
|
||||||
blocking this */
|
blocking this */
|
||||||
if (result != Bson(null))
|
if (result != Bson(null))
|
||||||
{
|
{
|
||||||
auto authInfo = result.deserializeBson!AuthInfo;
|
auto authInfo = result.deserializeBson!AuthInfo;
|
||||||
if ((()@trusted => checkBcrypt(password, authInfo.passwordHash))())
|
if (passwordHasher.checkHash(password, authInfo.passwordHash))
|
||||||
{
|
{
|
||||||
return authInfo.nullable;
|
return authInfo.nullable;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
module calendarwebapp.calendarwebapp;
|
module calendarwebapp.calendarwebapp;
|
||||||
|
|
||||||
import botan.rng.rng : RandomNumberGenerator;
|
|
||||||
|
|
||||||
import calendarwebapp.authenticator;
|
import calendarwebapp.authenticator;
|
||||||
import calendarwebapp.event;
|
import calendarwebapp.event;
|
||||||
|
import calendarwebapp.passhash : PasswordHasher;
|
||||||
|
|
||||||
import core.time : days;
|
import core.time : days;
|
||||||
|
|
||||||
|
@ -108,12 +107,10 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
@auth(Role.admin) @errorDisplay!getCreateuser void postCreateuser(string username,
|
@auth(Role.admin) @errorDisplay!getCreateuser void postCreateuser(string username,
|
||||||
string password, Privilege role)
|
string password, Privilege role) @safe
|
||||||
{
|
{
|
||||||
import botan.passhash.bcrypt;
|
|
||||||
|
|
||||||
authenticator.addUser(AuthInfo(BsonObjectID.generate, username,
|
authenticator.addUser(AuthInfo(BsonObjectID.generate, username,
|
||||||
generateBcrypt(password, rng, 10), role));
|
passwordHasher.generateHash(password), role));
|
||||||
redirect("/users");
|
redirect("/users");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,5 +126,5 @@ private:
|
||||||
|
|
||||||
@Autowire EventStore eventStore;
|
@Autowire EventStore eventStore;
|
||||||
@Autowire Authenticator authenticator;
|
@Autowire Authenticator authenticator;
|
||||||
@Autowire RandomNumberGenerator rng;
|
@Autowire PasswordHasher passwordHasher;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import botan.rng.rng : RandomNumberGenerator;
|
||||||
import calendarwebapp.authenticator : Authenticator, MongoDBAuthenticator;
|
import calendarwebapp.authenticator : Authenticator, MongoDBAuthenticator;
|
||||||
import calendarwebapp.calendarwebapp : CalendarWebapp;
|
import calendarwebapp.calendarwebapp : CalendarWebapp;
|
||||||
import calendarwebapp.event : EventStore, MongoDBEventStore;
|
import calendarwebapp.event : EventStore, MongoDBEventStore;
|
||||||
|
import calendarwebapp.passhash : BcryptPasswordHasher, PasswordHasher;
|
||||||
|
|
||||||
import poodinis;
|
import poodinis;
|
||||||
|
|
||||||
|
@ -22,6 +23,7 @@ public:
|
||||||
container.register!MongoClient.existingInstance(mongoClient);
|
container.register!MongoClient.existingInstance(mongoClient);
|
||||||
container.register!(EventStore, MongoDBEventStore!());
|
container.register!(EventStore, MongoDBEventStore!());
|
||||||
container.register!(Authenticator, MongoDBAuthenticator!());
|
container.register!(Authenticator, MongoDBAuthenticator!());
|
||||||
|
container.register!(PasswordHasher, BcryptPasswordHasher);
|
||||||
container.register!(RandomNumberGenerator, AutoSeededRNG);
|
container.register!(RandomNumberGenerator, AutoSeededRNG);
|
||||||
container.register!CalendarWebapp;
|
container.register!CalendarWebapp;
|
||||||
container.register!(ValueInjector!string, StringInjector);
|
container.register!(ValueInjector!string, StringInjector);
|
||||||
|
|
29
source/calendarwebapp/passhash.d
Normal file
29
source/calendarwebapp/passhash.d
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
module calendarwebapp.passhash;
|
||||||
|
|
||||||
|
import poodinis;
|
||||||
|
|
||||||
|
interface PasswordHasher
|
||||||
|
{
|
||||||
|
string generateHash(in string password) @safe;
|
||||||
|
bool checkHash(in string password, in string hash) @safe;
|
||||||
|
}
|
||||||
|
|
||||||
|
class BcryptPasswordHasher : PasswordHasher
|
||||||
|
{
|
||||||
|
import botan.passhash.bcrypt : checkBcrypt, generateBcrypt;
|
||||||
|
import botan.rng.rng : RandomNumberGenerator;
|
||||||
|
|
||||||
|
string generateHash(in string password) @safe
|
||||||
|
{
|
||||||
|
return (() @trusted => generateBcrypt(password, rng, cost))();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool checkHash(in string password, in string hash) @safe
|
||||||
|
{
|
||||||
|
return (()@trusted => checkBcrypt(password, hash))();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
@Autowire RandomNumberGenerator rng;
|
||||||
|
enum cost = 10;
|
||||||
|
}
|
Loading…
Reference in a new issue