2017-09-17 17:52:41 +02:00
|
|
|
module calendarwebapp.authenticator;
|
|
|
|
|
|
|
|
import poodinis;
|
|
|
|
|
2017-10-26 20:08:16 +02:00
|
|
|
import std.typecons : nullable, Nullable;
|
|
|
|
|
|
|
|
import vibe.data.bson : Bson, BsonObjectID, deserializeBson;
|
2017-09-17 17:52:41 +02:00
|
|
|
import vibe.db.mongo.collection : MongoCollection;
|
|
|
|
|
|
|
|
interface Authenticator
|
|
|
|
{
|
2017-10-26 20:08:16 +02:00
|
|
|
Nullable!AuthInfo checkUser(string username, string password) @safe;
|
2017-09-17 17:52:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
class MongoDBAuthenticator(Collection = MongoCollection) : Authenticator
|
|
|
|
{
|
|
|
|
private:
|
|
|
|
@Value("users")
|
|
|
|
Collection users;
|
|
|
|
|
|
|
|
public:
|
2017-10-26 20:08:16 +02:00
|
|
|
Nullable!AuthInfo checkUser(string username, string password) @safe
|
2017-09-17 17:52:41 +02:00
|
|
|
{
|
2017-10-15 16:43:39 +02:00
|
|
|
import botan.passhash.bcrypt : checkBcrypt;
|
|
|
|
|
|
|
|
auto result = users.findOne(["username" : username]);
|
|
|
|
/* checkBcrypt should be called using vibe.core.concurrency.async to
|
|
|
|
avoid blocking, but https://github.com/vibe-d/vibe.d/issues/1521 is
|
|
|
|
blocking this */
|
2017-10-26 20:08:16 +02:00
|
|
|
if (result != Bson(null))
|
|
|
|
{
|
|
|
|
auto authInfo = result.deserializeBson!AuthInfo;
|
|
|
|
if ((()@trusted => checkBcrypt(password, authInfo.passwordHash))())
|
|
|
|
{
|
|
|
|
return authInfo.nullable;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return Nullable!AuthInfo();
|
2017-09-17 17:52:41 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-26 20:08:16 +02:00
|
|
|
enum Role
|
|
|
|
{
|
|
|
|
User,
|
|
|
|
Admin
|
|
|
|
}
|
|
|
|
|
2017-09-17 17:52:41 +02:00
|
|
|
struct AuthInfo
|
|
|
|
{
|
2017-10-26 20:08:16 +02:00
|
|
|
import vibe.data.serialization : name;
|
|
|
|
|
|
|
|
@name("_id") BsonObjectID id;
|
|
|
|
string username;
|
|
|
|
string passwordHash;
|
|
|
|
Role role;
|
|
|
|
|
2017-10-27 15:13:02 +02:00
|
|
|
mixin(generateAuthMethods);
|
2017-10-26 20:08:16 +02:00
|
|
|
|
2017-10-27 15:13:02 +02:00
|
|
|
private:
|
|
|
|
static string generateAuthMethods() pure @safe
|
2017-10-26 20:08:16 +02:00
|
|
|
{
|
2017-10-27 15:13:02 +02:00
|
|
|
import std.conv : to;
|
|
|
|
import std.format : format;
|
|
|
|
import std.traits : EnumMembers;
|
|
|
|
|
|
|
|
string ret;
|
|
|
|
foreach (member; EnumMembers!Role)
|
|
|
|
{
|
|
|
|
ret ~= q{
|
|
|
|
bool is%s() const pure @safe nothrow
|
|
|
|
{
|
|
|
|
return role == Role.%s;
|
|
|
|
}
|
|
|
|
}.format(member.to!string, member.to!string);
|
|
|
|
}
|
|
|
|
return ret;
|
2017-10-26 20:08:16 +02:00
|
|
|
}
|
2017-10-27 15:13:02 +02:00
|
|
|
|
2017-09-17 17:52:41 +02:00
|
|
|
}
|