diff --git a/Netdisco/Changes b/Netdisco/Changes index 1ded84c4..3315bfc1 100644 --- a/Netdisco/Changes +++ b/Netdisco/Changes @@ -5,6 +5,7 @@ * [#75] Device module inventory report / search * [#70] SSID Search (port) * [#72] Search on Vendor / OUI + * Password Change form for all users [ENHANCEMENTS] diff --git a/Netdisco/lib/App/Netdisco/Web.pm b/Netdisco/lib/App/Netdisco/Web.pm index c6721da2..80ab7a63 100644 --- a/Netdisco/lib/App/Netdisco/Web.pm +++ b/Netdisco/lib/App/Netdisco/Web.pm @@ -21,6 +21,7 @@ use App::Netdisco::Web::AdminTask; use App::Netdisco::Web::TypeAhead; use App::Netdisco::Web::PortControl; use App::Netdisco::Web::Statistics; +use App::Netdisco::Web::Password; sub _load_web_plugins { my $plugin_list = shift; diff --git a/Netdisco/lib/App/Netdisco/Web/AuthN.pm b/Netdisco/lib/App/Netdisco/Web/AuthN.pm index caadb7e5..d52ee121 100644 --- a/Netdisco/lib/App/Netdisco/Web/AuthN.pm +++ b/Netdisco/lib/App/Netdisco/Web/AuthN.pm @@ -29,38 +29,38 @@ hook 'before' => sub { }; get qr{^/(?:login(?:/denied)?)?} => sub { - template 'index', { return_url => params->{return_url} }; + template 'index', { return_url => param('return_url') }; }; # override default login_handler so we can log access in the database post '/login' => sub { my $mode = (request->is_ajax ? 'API' : 'Web'); my ($success, $realm) = authenticate_user( - params->{username}, params->{password} + param('username'), param('password') ); if ($success) { - session logged_in_user => params->{username}; + session logged_in_user => param('username'); session logged_in_user_realm => $realm; schema('netdisco')->resultset('UserLog')->create({ username => session('logged_in_user'), userip => request->remote_address, event => "Login ($mode)", - details => params->{return_url}, + details => param('return_url'), }); return if request->is_ajax; - redirect params->{return_url}; + redirect param('return_url'); } else { session->destroy; schema('netdisco')->resultset('UserLog')->create({ - username => params->{username}, + username => param('username'), userip => request->remote_address, event => "Login Failure ($mode)", - details => params->{return_url}, + details => param('return_url'), }); if (request->is_ajax) { @@ -69,7 +69,7 @@ post '/login' => sub { else { vars->{login_failed}++; forward uri_for('/login'), - { login_failed => 1, return_url => params->{return_url} }, + { login_failed => 1, return_url => param('return_url') }, { method => 'GET' }; } } diff --git a/Netdisco/lib/App/Netdisco/Web/Password.pm b/Netdisco/lib/App/Netdisco/Web/Password.pm new file mode 100644 index 00000000..8992e6e8 --- /dev/null +++ b/Netdisco/lib/App/Netdisco/Web/Password.pm @@ -0,0 +1,51 @@ +package App::Netdisco::Web::Password; + +use Dancer ':syntax'; +use Dancer::Plugin::DBIC; +use Dancer::Plugin::Auth::Extensible; +use Dancer::Plugin::Passphrase; + +use Digest::MD5 (); + +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), + } +} + +sub _bail { + var('passchange_failed' => 1); + return template 'password.tt'; +} + +any ['get', 'post'] => '/password' => require_login sub { + my $old = param('old'); + my $new = param('new'); + my $confirm = param('confirm'); + + if (request->is_post) { + unless ($old and $new and $confirm and ($new eq $confirm)) { + return _bail(); + } + + my ($success, $realm) = authenticate_user( + session('logged_in_user'), $old + ); + return _bail() if not $success; + + my $user = schema('netdisco')->resultset('User') + ->find({username => session('logged_in_user')}); + return _bail() if not $user; + + $user->update({password => _make_password($new)}); + var('passchange_ok' => 1); + } + + template 'password.tt'; +}; + +true; diff --git a/Netdisco/share/views/index.tt b/Netdisco/share/views/index.tt index a58e3ae5..c90d9e32 100644 --- a/Netdisco/share/views/index.tt +++ b/Netdisco/share/views/index.tt @@ -38,8 +38,8 @@ [% IF NOT session.logged_in_user %]