enable Bcrypt password storage

This commit is contained in:
Oliver Gorwits
2014-02-08 19:10:03 +00:00
parent f8cf6aad73
commit 545f878cb7
11 changed files with 114 additions and 66 deletions

View File

@@ -34,6 +34,7 @@ requires:
Dancer: 1.3112
Dancer::Plugin::Auth::Extensible: 0.3
Dancer::Plugin::DBIC: 0.1803
Dancer::Plugin::Passphrase: 2
File::ShareDir: 1.03
Guard: 1.022
HTML::Parser: 3.7

View File

@@ -18,6 +18,7 @@ requires 'Daemon::Control' => 0.001000;
requires 'Dancer' => 1.3112;
requires 'Dancer::Plugin::DBIC' => 0.1803;
requires 'Dancer::Plugin::Auth::Extensible' => 0.30;
requires 'Dancer::Plugin::Passphrase' => 2.00;
requires 'File::ShareDir' => 1.03;
requires 'Guard' => 1.022;
requires 'HTML::Parser' => 3.70;

View File

@@ -99,9 +99,9 @@ $bool = $term->ask_yn(
);
deploy_db() if $bool;
say '';
my $users = schema('netdisco')->resultset('User');
if ($users->count == 0) {
say '';
$bool = $term->ask_yn(
prompt => 'Would you like a default web user with Admin rights (discover, etc)?',
default => 'n',
@@ -136,6 +136,10 @@ if ($users->count == 0) {
}
}
}
elsif (!setting('safe_password_store')) {
say '*** WARNING: Weak password hashes are being stored in the database! ***';
say '*** WARNING: Please add "safe_password_store: true" to your ~/environments/deployment.yml file. ***';
}
say '';
$bool = $term->ask_yn(

View File

@@ -210,7 +210,8 @@ C<name>, C<host>, C<user> and C<pass>).
In the same file uncomment and edit the C<domain_suffix> setting to be
appropriate for your local site. If this is a fresh install, uncomment and set
the C<no_auth> value to true (temporarily disables user authentication).
the C<no_auth> value to true (temporarily disables user authentication). Have
a quick read of the other settings to make sure you're happy, then move on.
=head1 Bootstrap
@@ -243,7 +244,7 @@ daemon at the same time. Similarly, if you use the device discovery with
Netdisco 2, disable your system's cron jobs for the Netdisco 1.x poller.
At this point you can revisit the C<~/environments/deployment.yml> file to
uncomment more configuration. Check out the community string settings, and
uncomment more configuration. Enable the C<community> string settings, and
C<housekeeping> which enables the automatic periodic device discovery. See
L<Configuration|App::Netdisco::Manual::Configuration> for further details.

View File

@@ -223,6 +223,13 @@ Value: List of Modules. Default: Empty List.
List of additional L<App::Netdisco::Web::Plugin> names to load. See also the
C<web_plugins> setting.
=head3 C<safe_password_store>
Value: Boolean. Default: true.
Set to "C<false>" if you MUST maintain backwards compatibility with the Netdisco
1.x web interface. Strongly recommended that you leave this set to "C<true>".
=head2 Netdisco Core
=head3 C<mibhome>

View File

@@ -90,61 +90,6 @@ hook 'after' => sub {
}
};
get qr{^/(?:login(?:/denied)?)?} => sub {
template 'index';
};
# Override default login_handler so that we can log access in the
# database
post '/login' => sub {
my ($success, $realm) = authenticate_user(
params->{username}, params->{password}
);
if ($success) {
session logged_in_user => params->{username};
session logged_in_user_realm => $realm;
schema('netdisco')->resultset('UserLog')->create({
username => session('logged_in_user'),
userip => request->remote_address,
event => "Login",
details => params->{return_url},
});
redirect params->{return_url} || uri_for('/');
} else {
schema('netdisco')->resultset('UserLog')->create({
username => params->{username},
userip => request->remote_address,
event => "Login Failure",
details => params->{return_url},
});
vars->{login_failed}++;
forward uri_for('/login'), { login_failed => 1 }, { method => 'GET' };
}
};
# Since we override the default login_handler, logout has to be handled as
# well
any ['get','post'] => '/logout' => sub {
schema('netdisco')->resultset('UserLog')->create({
username => session('logged_in_user'),
userip => request->remote_address,
event => "Logout",
details => '',
});
session->destroy;
if (params->{return_url}) {
redirect params->{return_url};
} else {
return "OK, logged out successfully.";
}
};
any qr{.*} => sub {
var('notfound' => true);
status 'not_found';

View File

@@ -10,7 +10,7 @@ use base 'Dancer::Plugin::Auth::Extensible::Provider::Base';
use Dancer ':syntax';
use Dancer::Plugin::DBIC;
use Dancer::Plugin::Passphrase;
use Digest::MD5;
sub authenticate_user {
@@ -77,8 +77,25 @@ sub match_with_local_pass {
return unless $password and $user->$password_column;
if ($user->$password_column !~ m/^{[A-Z]+}/) {
debug 'authN: using legacy MD5';
my $sum = Digest::MD5::md5_hex($password);
return ($sum eq $user->$password_column ? 1 : 0);
if ($sum eq $user->$password_column) {
if (setting('safe_password_store')) {
# upgrade password if successful, and permitted
$user->update({password => passphrase($password)->generate});
}
return 1;
}
else {
return 0;
}
}
else {
debug 'authN: using Passphrase';
return passphrase($password)->matches($user->$password_column);
}
}
sub match_with_ldap {

View File

@@ -27,4 +27,59 @@ hook 'before' => sub {
}
};
get qr{^/(?:login(?:/denied)?)?} => sub {
template 'index';
};
# override default login_handler so we can log access in the database
post '/login' => sub {
my ($success, $realm) = authenticate_user(
params->{username}, params->{password}
);
if ($success) {
session logged_in_user => params->{username};
session logged_in_user_realm => $realm;
schema('netdisco')->resultset('UserLog')->create({
username => session('logged_in_user'),
userip => request->remote_address,
event => "Login",
details => params->{return_url},
});
redirect params->{return_url} || uri_for('/');
}
else {
schema('netdisco')->resultset('UserLog')->create({
username => params->{username},
userip => request->remote_address,
event => "Login Failure",
details => params->{return_url},
});
vars->{login_failed}++;
forward uri_for('/login'), { login_failed => 1 }, { method => 'GET' };
}
};
# we override the default login_handler, so logout has to be handled as well
any ['get','post'] => '/logout' => sub {
schema('netdisco')->resultset('UserLog')->create({
username => session('logged_in_user'),
userip => request->remote_address,
event => "Logout",
details => '',
});
session->destroy;
if (params->{return_url}) {
redirect params->{return_url};
}
else {
return "OK, logged out successfully.";
}
};
true;

View File

@@ -4,6 +4,7 @@ use Dancer ':syntax';
use Dancer::Plugin::Ajax;
use Dancer::Plugin::DBIC;
use Dancer::Plugin::Auth::Extensible;
use Dancer::Plugin::Passphrase;
use App::Netdisco::Web::Plugin;
use Digest::MD5 ();
@@ -21,6 +22,16 @@ sub _sanity_ok {
return 1;
}
sub _make_password {
my $pass = (shift || passphrase->generate_random);
if (setting('safe_password_store')) {
return passphrase($pass)->generate;
}
else {
return Digest::MD5::md5_hex($pass),
}
}
ajax '/ajax/control/admin/users/add' => require_role admin => sub {
send_error('Bad Request', 400) unless _sanity_ok();
@@ -28,7 +39,7 @@ ajax '/ajax/control/admin/users/add' => require_role admin => sub {
my $user = schema('netdisco')->resultset('User')
->create({
username => param('username'),
password => Digest::MD5::md5_hex(param('password')),
password => _make_password(param('password')),
fullname => param('fullname'),
ldap => (param('ldap') ? \'true' : \'false'),
port_control => (param('port_control') ? \'true' : \'false'),
@@ -56,7 +67,7 @@ ajax '/ajax/control/admin/users/update' => require_role admin => sub {
$user->update({
((param('password') ne '********')
? (password => Digest::MD5::md5_hex(param('password')))
? (password => _make_password(param('password')))
: ()),
fullname => param('fullname'),
ldap => (param('ldap') ? \'true' : \'false'),

View File

@@ -72,6 +72,7 @@ web_plugins:
- Device::Neighbors
- Device::Addresses
extra_web_plugins: []
safe_password_store: true
# -------------
# NETDISCO CORE

View File

@@ -18,6 +18,11 @@ database:
# RECOMMENDED SETTINGS
# --------------------
# set to "false" if you MUST maintain backwards compatibility
# with Netdisco 1.x web frontend.
# ```````````````````````````````````````````````````````````
safe_password_store: true
# will be stripped from fqdn when displayed in the web UI
# also, do not forget the leading dot.
# ```````````````````````````````````````````````````````
@@ -48,8 +53,8 @@ database:
# expiry:
# when: '20 23 * * *'
# increase the performance of parallel DNS resolution for node names
# (the default is max_outstanding: 10)
# increase the performance of parallel DNS resolution for node
# names (the default is max_outstanding: 10)
# ````````````````````````````````````````````````````````````
#dns:
# max_outstanding: 100