Initial work for support for different user roles.

This commit is contained in:
Johannes Loher 2017-10-26 20:08:16 +02:00
parent bebb5079c4
commit 4959c67e89
3 changed files with 45 additions and 14 deletions

View file

@ -2,11 +2,14 @@ module calendarwebapp.authenticator;
import poodinis; import poodinis;
import std.typecons : nullable, Nullable;
import vibe.data.bson : Bson, BsonObjectID, deserializeBson;
import vibe.db.mongo.collection : MongoCollection; import vibe.db.mongo.collection : MongoCollection;
interface Authenticator interface Authenticator
{ {
bool checkUser(string username, string password) @safe; Nullable!AuthInfo checkUser(string username, string password) @safe;
} }
class MongoDBAuthenticator(Collection = MongoCollection) : Authenticator class MongoDBAuthenticator(Collection = MongoCollection) : Authenticator
@ -16,21 +19,48 @@ private:
Collection users; Collection users;
public: public:
bool checkUser(string username, string password) @safe Nullable!AuthInfo checkUser(string username, string password) @safe
{ {
import botan.passhash.bcrypt : checkBcrypt; import botan.passhash.bcrypt : checkBcrypt;
import vibe.data.bson : Bson;
auto result = users.findOne(["username" : username]); auto result = users.findOne(["username" : username]);
/* checkBcrypt should be called using vibe.core.concurrency.async to /* checkBcrypt 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 */
return (result != Bson(null)) && (() @trusted => checkBcrypt(password, if (result != Bson(null))
result["password"].get!string))(); {
auto authInfo = result.deserializeBson!AuthInfo;
if ((()@trusted => checkBcrypt(password, authInfo.passwordHash))())
{
return authInfo.nullable;
}
}
return Nullable!AuthInfo();
} }
} }
enum Role
{
User,
Admin
}
struct AuthInfo struct AuthInfo
{ {
string userName; import vibe.data.serialization : name;
@name("_id") BsonObjectID id;
string username;
string passwordHash;
Role role;
bool isUser()
{
return role == Role.User;
}
bool isAdmin()
{
return role == Role.Admin;
}
} }

View file

@ -45,9 +45,9 @@ public:
@noAuth @errorDisplay!getLogin void postLogin(string username, string password) @safe @noAuth @errorDisplay!getLogin void postLogin(string username, string password) @safe
{ {
enforce(authenticator.checkUser(username, password), "Benutzername oder Passwort ungültig"); auto authInfo = authenticator.checkUser(username, password);
immutable AuthInfo authInfo = {username}; enforce(!authInfo.isNull, "Benutzername oder Passwort ungültig");
auth = authInfo; auth = authInfo.get;
redirect("/"); redirect("/");
} }

View file

@ -41,13 +41,14 @@ public:
container.register!(Authenticator, MongoDBAuthenticator!(Collection))( container.register!(Authenticator, MongoDBAuthenticator!(Collection))(
RegistrationOption.doNotAddConcreteTypeRegistration); RegistrationOption.doNotAddConcreteTypeRegistration);
auto userBson = Bson(["_id" : Bson(BsonObjectID.fromString("5988ef4ae6c19089a1a53b79")), "username" : Bson("foo"), auto userBson = Bson(["_id" : Bson(BsonObjectID.fromString("5988ef4ae6c19089a1a53b79")),
"password" : Bson("$2a$10$9LBqOZV99ARiE4Nx.2b7GeYfqk2.0A32PWGu2cRGyW2hRJ0xeDfnO")]); "username" : Bson("foo"), "passwordHash"
: Bson("$2a$10$9LBqOZV99ARiE4Nx.2b7GeYfqk2.0A32PWGu2cRGyW2hRJ0xeDfnO"), "role" : Bson(1)]);
collection.returnValue!"findOne"(Bson(null), userBson, userBson); collection.returnValue!"findOne"(Bson(null), userBson, userBson);
auto authenticator = container.resolve!(Authenticator); auto authenticator = container.resolve!(Authenticator);
authenticator.checkUser("", "").shouldBeFalse; authenticator.checkUser("", "").isNull.shouldBeTrue;
authenticator.checkUser("foo", "bar").shouldBeTrue; authenticator.checkUser("foo", "bar").isNull.shouldBeFalse;
authenticator.checkUser("foo", "baz").shouldBeFalse; authenticator.checkUser("foo", "baz").isNull.shouldBeTrue;
} }