diff --git a/source/calendarwebapp/authenticator.d b/source/calendarwebapp/authenticator.d index b48d83b..d5450ca 100644 --- a/source/calendarwebapp/authenticator.d +++ b/source/calendarwebapp/authenticator.d @@ -2,11 +2,14 @@ module calendarwebapp.authenticator; import poodinis; +import std.typecons : nullable, Nullable; + +import vibe.data.bson : Bson, BsonObjectID, deserializeBson; import vibe.db.mongo.collection : MongoCollection; interface Authenticator { - bool checkUser(string username, string password) @safe; + Nullable!AuthInfo checkUser(string username, string password) @safe; } class MongoDBAuthenticator(Collection = MongoCollection) : Authenticator @@ -16,21 +19,48 @@ private: Collection users; public: - bool checkUser(string username, string password) @safe + Nullable!AuthInfo checkUser(string username, string password) @safe { import botan.passhash.bcrypt : checkBcrypt; - import vibe.data.bson : Bson; 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 */ - return (result != Bson(null)) && (() @trusted => checkBcrypt(password, - result["password"].get!string))(); + if (result != Bson(null)) + { + auto authInfo = result.deserializeBson!AuthInfo; + if ((()@trusted => checkBcrypt(password, authInfo.passwordHash))()) + { + return authInfo.nullable; + } + } + return Nullable!AuthInfo(); } } +enum Role +{ + User, + Admin +} + 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; + } } diff --git a/source/calendarwebapp/calendarwebapp.d b/source/calendarwebapp/calendarwebapp.d index 21a652e..8427942 100644 --- a/source/calendarwebapp/calendarwebapp.d +++ b/source/calendarwebapp/calendarwebapp.d @@ -45,9 +45,9 @@ public: @noAuth @errorDisplay!getLogin void postLogin(string username, string password) @safe { - enforce(authenticator.checkUser(username, password), "Benutzername oder Passwort ungültig"); - immutable AuthInfo authInfo = {username}; - auth = authInfo; + auto authInfo = authenticator.checkUser(username, password); + enforce(!authInfo.isNull, "Benutzername oder Passwort ungültig"); + auth = authInfo.get; redirect("/"); } diff --git a/test/calendarwebapp/testauthenticator.d b/test/calendarwebapp/testauthenticator.d index 4e744c2..6a11273 100644 --- a/test/calendarwebapp/testauthenticator.d +++ b/test/calendarwebapp/testauthenticator.d @@ -41,13 +41,14 @@ public: container.register!(Authenticator, MongoDBAuthenticator!(Collection))( RegistrationOption.doNotAddConcreteTypeRegistration); - auto userBson = Bson(["_id" : Bson(BsonObjectID.fromString("5988ef4ae6c19089a1a53b79")), "username" : Bson("foo"), - "password" : Bson("$2a$10$9LBqOZV99ARiE4Nx.2b7GeYfqk2.0A32PWGu2cRGyW2hRJ0xeDfnO")]); + auto userBson = Bson(["_id" : Bson(BsonObjectID.fromString("5988ef4ae6c19089a1a53b79")), + "username" : Bson("foo"), "passwordHash" + : Bson("$2a$10$9LBqOZV99ARiE4Nx.2b7GeYfqk2.0A32PWGu2cRGyW2hRJ0xeDfnO"), "role" : Bson(1)]); collection.returnValue!"findOne"(Bson(null), userBson, userBson); auto authenticator = container.resolve!(Authenticator); - authenticator.checkUser("", "").shouldBeFalse; - authenticator.checkUser("foo", "bar").shouldBeTrue; - authenticator.checkUser("foo", "baz").shouldBeFalse; + authenticator.checkUser("", "").isNull.shouldBeTrue; + authenticator.checkUser("foo", "bar").isNull.shouldBeFalse; + authenticator.checkUser("foo", "baz").isNull.shouldBeTrue; }