Password Change form for all users

This commit is contained in:
Oliver Gorwits
2014-02-22 18:39:39 +00:00
parent ae535a63d9
commit db24e4af27
7 changed files with 95 additions and 11 deletions

View File

@@ -5,6 +5,7 @@
* [#75] Device module inventory report / search * [#75] Device module inventory report / search
* [#70] SSID Search (port) * [#70] SSID Search (port)
* [#72] Search on Vendor / OUI * [#72] Search on Vendor / OUI
* Password Change form for all users
[ENHANCEMENTS] [ENHANCEMENTS]

View File

@@ -21,6 +21,7 @@ use App::Netdisco::Web::AdminTask;
use App::Netdisco::Web::TypeAhead; use App::Netdisco::Web::TypeAhead;
use App::Netdisco::Web::PortControl; use App::Netdisco::Web::PortControl;
use App::Netdisco::Web::Statistics; use App::Netdisco::Web::Statistics;
use App::Netdisco::Web::Password;
sub _load_web_plugins { sub _load_web_plugins {
my $plugin_list = shift; my $plugin_list = shift;

View File

@@ -29,38 +29,38 @@ hook 'before' => sub {
}; };
get qr{^/(?:login(?:/denied)?)?} => 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 # override default login_handler so we can log access in the database
post '/login' => sub { post '/login' => sub {
my $mode = (request->is_ajax ? 'API' : 'Web'); my $mode = (request->is_ajax ? 'API' : 'Web');
my ($success, $realm) = authenticate_user( my ($success, $realm) = authenticate_user(
params->{username}, params->{password} param('username'), param('password')
); );
if ($success) { if ($success) {
session logged_in_user => params->{username}; session logged_in_user => param('username');
session logged_in_user_realm => $realm; session logged_in_user_realm => $realm;
schema('netdisco')->resultset('UserLog')->create({ schema('netdisco')->resultset('UserLog')->create({
username => session('logged_in_user'), username => session('logged_in_user'),
userip => request->remote_address, userip => request->remote_address,
event => "Login ($mode)", event => "Login ($mode)",
details => params->{return_url}, details => param('return_url'),
}); });
return if request->is_ajax; return if request->is_ajax;
redirect params->{return_url}; redirect param('return_url');
} }
else { else {
session->destroy; session->destroy;
schema('netdisco')->resultset('UserLog')->create({ schema('netdisco')->resultset('UserLog')->create({
username => params->{username}, username => param('username'),
userip => request->remote_address, userip => request->remote_address,
event => "Login Failure ($mode)", event => "Login Failure ($mode)",
details => params->{return_url}, details => param('return_url'),
}); });
if (request->is_ajax) { if (request->is_ajax) {
@@ -69,7 +69,7 @@ post '/login' => sub {
else { else {
vars->{login_failed}++; vars->{login_failed}++;
forward uri_for('/login'), forward uri_for('/login'),
{ login_failed => 1, return_url => params->{return_url} }, { login_failed => 1, return_url => param('return_url') },
{ method => 'GET' }; { method => 'GET' };
} }
} }

View File

@@ -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;

View File

@@ -38,8 +38,8 @@
[% IF NOT session.logged_in_user %] [% IF NOT session.logged_in_user %]
<form class="nd_login-form" method="post" action="[% uri_for('/login') %]"> <form class="nd_login-form" method="post" action="[% uri_for('/login') %]">
<div class="form-horizontal"> <div class="form-horizontal">
<input placeholder="Username" class="span2" name="username" type="text"/> <input placeholder="Username" class="span2" name="username" type="text" required="required"/>
<input placeholder="Password" class="span2" name="password" type="password"/> <input placeholder="Password" class="span2" name="password" type="password" required="required"/>
<button type="submit" class="btn btn-info">Log In</button> <button type="submit" class="btn btn-info">Log In</button>
</div> </div>
[% IF params.return_url %] [% IF params.return_url %]

View File

@@ -157,7 +157,9 @@
[% session.logged_in_user | html_entity %] <b class="caret"></b> [% session.logged_in_user | html_entity %] <b class="caret"></b>
</a> </a>
<ul class="dropdown-menu"> <ul class="dropdown-menu">
<li><a href="[% uri_for('/about') %]">About</a></li> [% IF NOT user_has_role('ldap') %]
<li><a href="[% uri_for('/password') %]">Change Password</a></li>
[% END %]
[% IF NOT settings.no_auth %] [% IF NOT settings.no_auth %]
<li><a href="[% uri_for('/logout') %]">Log Out</a></li> <li><a href="[% uri_for('/logout') %]">Log Out</a></li>
[% END %] [% END %]

View File

@@ -0,0 +1,29 @@
<div class="container">
<div class="row nd_hero-row">
<div class="span8 offset2">
[% IF vars.passchange_ok %]
<div class="alert alert-success fade in">
<a class="close" data-dismiss="alert">×</a>
Password successfully updated.
</div>
[% END %]
[% IF vars.passchange_failed %]
<div class="alert alert-error fade in">
<a class="close" data-dismiss="alert">×</a>
Incorrect current password, or new passwords did not match. Please try again.
</div>
[% END %]
<div class="hero-unit">
<h2>Change Password</h2>
<form class="nd_login-form" method="post" action="[% uri_for('/password') %]">
<div class="form-horizontal">
<input placeholder="Current Password" class="span2" name="old" type="password" required="required"/><br/>
<input placeholder="New Password" class="span2" name="new" type="password" required="required"/>
<input placeholder="Confirm New Password" class="span2" name="confirm" type="password" required="required"/>
<button type="submit" class="btn btn-info">Save</button>
</div>
</form>
</div>
</div>
</div>
</div> <!-- /container -->