Merge branch 'dauth' into 'master'

Use DAuth instead of botan for password hashing. Fixes #7

Closes #7

See merge request fsimphy/calendar-webapp!15
This commit is contained in:
Johannes Loher 2017-11-20 22:46:30 +01:00
commit c918e8e574
6 changed files with 31 additions and 56 deletions

View file

@ -4,15 +4,11 @@
"Johannes Loher" "Johannes Loher"
], ],
"dependencies": { "dependencies": {
"dauth": "~>0.6.3",
"mysql-native": "~>1.1.2", "mysql-native": "~>1.1.2",
"botan": "~>1.12.9",
"vibe-d": "~>0.8.1", "vibe-d": "~>0.8.1",
"vibe-d:tls": "~>0.8.1",
"poodinis": "~>8.0.1" "poodinis": "~>8.0.1"
}, },
"subConfigurations": {
"vibe-d:tls": "botan"
},
"description": "A simple webapplication to edit and view calendar entries", "description": "A simple webapplication to edit and view calendar entries",
"copyright": "Copyright © 2017, Johannes Loher", "copyright": "Copyright © 2017, Johannes Loher",
"license": "MIT", "license": "MIT",

View file

@ -4,7 +4,7 @@ USE CalendarWebapp;
CREATE TABLE users ( CREATE TABLE users (
id MEDIUMINT UNSIGNED NOT NULL AUTO_INCREMENT, id MEDIUMINT UNSIGNED NOT NULL AUTO_INCREMENT,
username CHAR(30) NOT NULL UNIQUE, username CHAR(30) NOT NULL UNIQUE,
passwordHash CHAR(60) NOT NULL, passwordHash CHAR(92) NOT NULL,
privilege TINYINT UNSIGNED NOT NULL, privilege TINYINT UNSIGNED NOT NULL,
PRIMARY KEY (id) PRIMARY KEY (id)
); );
@ -21,4 +21,4 @@ CREATE TABLE events (
); );
INSERT INTO users (username, passwordHash, privilege) VALUES ('foo', INSERT INTO users (username, passwordHash, privilege) VALUES ('foo',
'$2a$10$9LBqOZV99ARiE4Nx.2b7GeYfqk2.0A32PWGu2cRGyW2hRJ0xeDfnO', 2); '$5$eGohWUmw9yyiTqG7kti1MmT/jR52raEVlYuHQJa/sYk=$ucI+vTQq38Rr5RUAatd4Om0Dy9fuF0oKgkuVCuXSnxc=', 2);

View file

@ -30,8 +30,6 @@ private:
public: public:
Nullable!AuthInfo checkUser(string username, string password) @safe Nullable!AuthInfo checkUser(string username, string password) @safe
{ {
import botan.passhash.bcrypt : checkBcrypt;
auto result = users.findOne(["username" : username]); auto result = users.findOne(["username" : username]);
/* checkHash 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

View file

@ -1,13 +1,10 @@
module calendarwebapp.configuration; module calendarwebapp.configuration;
import botan.rng.auto_rng : AutoSeededRNG;
import botan.rng.rng : RandomNumberGenerator;
import calendarwebapp.authenticator : Authenticator, MongoDBAuthenticator, import calendarwebapp.authenticator : Authenticator, MongoDBAuthenticator,
MySQLAuthenticator; MySQLAuthenticator;
import calendarwebapp.calendarwebapp : CalendarWebapp; import calendarwebapp.calendarwebapp : CalendarWebapp;
import calendarwebapp.event : EventStore, MongoDBEventStore, MySQLEventStore; import calendarwebapp.event : EventStore, MongoDBEventStore, MySQLEventStore;
import calendarwebapp.passhash : BcryptPasswordHasher, PasswordHasher; import calendarwebapp.passhash : PasswordHasher, SHA256PasswordHasher;
import mysql : MySQLPool; import mysql : MySQLPool;
@ -28,9 +25,7 @@ public:
container.register!MongoClient.existingInstance(mongoClient); container.register!MongoClient.existingInstance(mongoClient);
container.register!(EventStore, MySQLEventStore); container.register!(EventStore, MySQLEventStore);
container.register!(Authenticator, MySQLAuthenticator); container.register!(Authenticator, MySQLAuthenticator);
container.register!(PasswordHasher, SHA256PasswordHasher);
container.register!(PasswordHasher, BcryptPasswordHasher);
container.register!(RandomNumberGenerator, AutoSeededRNG);
container.register!CalendarWebapp; container.register!CalendarWebapp;
container.register!(ValueInjector!string, StringInjector); container.register!(ValueInjector!string, StringInjector);
container.register!(ValueInjector!MongoCollection, MongoCollectionInjector); container.register!(ValueInjector!MongoCollection, MongoCollectionInjector);

View file

@ -1,33 +1,11 @@
module calendarwebapp.passhash; module calendarwebapp.passhash;
import poodinis;
interface PasswordHasher interface PasswordHasher
{ {
string generateHash(in string password) @safe; string generateHash(in string password) const @safe;
bool checkHash(in string password, in string hash) const @safe; bool checkHash(in string password, in string hash) const @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) const @safe
{
return (()@trusted => checkBcrypt(password, hash))();
}
private:
@Autowire RandomNumberGenerator rng;
enum cost = 10;
}
class StubPasswordHasher : PasswordHasher class StubPasswordHasher : PasswordHasher
{ {
string generateHash(in string password) const @safe pure nothrow string generateHash(in string password) const @safe pure nothrow
@ -40,3 +18,19 @@ class StubPasswordHasher : PasswordHasher
return password == hash; return password == hash;
} }
} }
class SHA256PasswordHasher : PasswordHasher
{
import dauth : dupPassword, isSameHash, makeHash, parseHash;
import std.digest.sha : SHA256;
string generateHash(in string password) const @safe
{
return (() @trusted => password.dupPassword.makeHash!SHA256.toCryptString)();
}
bool checkHash(in string password, in string hash) const @safe
{
return (() @trusted => isSameHash(password.dupPassword, parseHash(hash)))();
}
}

View file

@ -2,25 +2,8 @@ module test.calendarwebapp.testpasshash;
import calendarwebapp.passhash; import calendarwebapp.passhash;
import poodinis;
import unit_threaded; import unit_threaded;
@("BcryptPasswordHasher")
@Values("", "test", "langesKompliziertesPasswort")
@system unittest
{
import botan.rng.rng : RandomNumberGenerator;
import botan.rng.auto_rng : AutoSeededRNG;
auto container = new shared DependencyContainer;
container.register!(RandomNumberGenerator, AutoSeededRNG);
container.register!(PasswordHasher, BcryptPasswordHasher);
auto hasher = container.resolve!PasswordHasher;
immutable testPassword = getValue!string;
hasher.checkHash(testPassword, hasher.generateHash(testPassword)).shouldBeTrue;
}
@("StubPasswordHasher") @("StubPasswordHasher")
@Values("", "test", "langesKompliziertesPasswort") @Values("", "test", "langesKompliziertesPasswort")
@safe unittest @safe unittest
@ -29,3 +12,12 @@ import unit_threaded;
immutable testPassword = getValue!string; immutable testPassword = getValue!string;
hasher.checkHash(testPassword, hasher.generateHash(testPassword)).shouldBeTrue; hasher.checkHash(testPassword, hasher.generateHash(testPassword)).shouldBeTrue;
} }
@("SHA256PasswordHasher")
@Values("", "test", "langesKompliziertesPasswort")
@safe unittest
{
immutable hasher = new SHA256PasswordHasher;
immutable testPassword = getValue!string;
hasher.checkHash(testPassword, hasher.generateHash(testPassword)).shouldBeTrue;
}