Commit cc274f5f authored by frankiejol's avatar frankiejol
Browse files

Merge branch 'feat/1500_resetpasswd/develop' of...

Merge branch 'feat/1500_resetpasswd/develop' of https://github.com/robertperez-upc/ravada into develop
parents f5504bc2 3dc32241
...@@ -1345,6 +1345,17 @@ sub _set_url_isos($self, $new_url='http://localhost/iso/') { ...@@ -1345,6 +1345,17 @@ sub _set_url_isos($self, $new_url='http://localhost/iso/') {
} }
sub _get_column_info
{
my $self = shift;
my ($table, $field) = @_;
my $dbh = $CONNECTOR->dbh;
my $sth = $dbh->column_info(undef,undef,$table,$field);
my $row = $sth->fetchrow_hashref;
$sth->finish;
return $row;
}
sub _upgrade_table { sub _upgrade_table {
my $self = shift; my $self = shift;
my ($table, $field, $definition) = @_; my ($table, $field, $definition) = @_;
...@@ -1776,6 +1787,18 @@ sub _clean_iso_mini { ...@@ -1776,6 +1787,18 @@ sub _clean_iso_mini {
$sth->finish; $sth->finish;
} }
sub _upgrade_users_table {
my $self = shift;
my $data = $self->_get_column_info('users', 'change_password');
if ($data->{'COLUMN_DEF'} == 1) {
my $sth = $CONNECTOR->dbh->prepare("UPDATE users set change_password=0");
$sth->execute;
$sth = $CONNECTOR->dbh->prepare("ALTER TABLE users ALTER change_password SET DEFAULT 0");
$sth->execute;
}
}
sub _upgrade_tables { sub _upgrade_tables {
my $self = shift; my $self = shift;
# return if $CONNECTOR->dbh->{Driver}{Name} !~ /mysql/i; # return if $CONNECTOR->dbh->{Driver}{Name} !~ /mysql/i;
...@@ -1889,6 +1912,8 @@ sub _upgrade_tables { ...@@ -1889,6 +1912,8 @@ sub _upgrade_tables {
$self->_upgrade_table('messages','date_changed','timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP'); $self->_upgrade_table('messages','date_changed','timestamp DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP');
$self->_upgrade_table('grant_types', 'is_int', 'int DEFAULT 0'); $self->_upgrade_table('grant_types', 'is_int', 'int DEFAULT 0');
$self->_upgrade_users_table();
} }
sub _upgrade_timestamps($self) { sub _upgrade_timestamps($self) {
......
...@@ -501,6 +501,24 @@ sub id { ...@@ -501,6 +501,24 @@ sub id {
return $id; return $id;
} }
=head2 password_will_be_changed
Returns true if user password will be changed
$user->password_will_be_changed();
=cut
sub password_will_be_changed {
my $self = shift;
_init_connector();
my $sth = $$CON->dbh->prepare("SELECT change_password FROM users WHERE name=?");
$sth->execute($self->name);
return $sth->fetchrow();
}
=head2 change_password =head2 change_password
Changes the password of an User Changes the password of an User
...@@ -514,14 +532,22 @@ Arguments: password ...@@ -514,14 +532,22 @@ Arguments: password
sub change_password { sub change_password {
my $self = shift; my $self = shift;
my $password = shift or die "ERROR: password required\n"; my $password = shift or die "ERROR: password required\n";
my ($force_change_password) = @_;
_init_connector(); _init_connector();
die "Password too small" if length($password)<6; die "Password too small" if length($password)<6;
my $sth= $$CON->dbh->prepare("UPDATE users set password=?" my $sth;
." WHERE name=?"); if (defined($force_change_password)) {
$sth->execute(sha1_hex($password), $self->name); $sth= $$CON->dbh->prepare("UPDATE users set password=?, change_password=?"
." WHERE name=?");
$sth->execute(sha1_hex($password), $force_change_password ? 1 : 0, $self->name);
} else {
my $sth= $$CON->dbh->prepare("UPDATE users set password=?"
." WHERE name=?");
$sth->execute(sha1_hex($password), $self->name);
}
} }
=head2 compare_password =head2 compare_password
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
.service("listMess", gtListMess) .service("listMess", gtListMess)
.controller("SupportForm", suppFormCtrl) .controller("SupportForm", suppFormCtrl)
.controller("AddUserForm",addUserFormCrtl) .controller("AddUserForm",addUserFormCrtl)
.controller("ChangePasswordForm",changePasswordFormCrtl)
// .controller("machines", machinesCrtl) // .controller("machines", machinesCrtl)
// .controller("messages", messagesCrtl) // .controller("messages", messagesCrtl)
.controller("users", usersCrtl) .controller("users", usersCrtl)
...@@ -74,6 +75,11 @@ ...@@ -74,6 +75,11 @@
function addUserFormCrtl($scope, $http, request){ function addUserFormCrtl($scope, $http, request){
};
function changePasswordFormCrtl($scope, $http, request){
}; };
function swNewMach() { function swNewMach() {
......
...@@ -156,6 +156,7 @@ hook before_routes => sub { ...@@ -156,6 +156,7 @@ hook before_routes => sub {
,url => undef ,url => undef
,_logged_in => undef ,_logged_in => undef
,_anonymous => undef ,_anonymous => undef
,forcing_change_password => undef
,_user => undef ,_user => undef
,footer=> $CONFIG_FRONT->{footer} ,footer=> $CONFIG_FRONT->{footer}
,monitoring => 0 ,monitoring => 0
...@@ -187,6 +188,10 @@ hook before_routes => sub { ...@@ -187,6 +188,10 @@ hook before_routes => sub {
return if $url =~ m{^/anonymous}; return if $url =~ m{^/anonymous};
if ((defined $USER) && (_logged_in($c)) && (! $USER->is_temporary) && (! $USER->is_external) && ($USER->password_will_be_changed())) {
return change_password($c, 1);
}
if (($url =~ m{^/machine/(clone|display|info|view)/} if (($url =~ m{^/machine/(clone|display|info|view)/}
|| $url =~ m{^/(list_bases_anonymous|request/)}i || $url =~ m{^/(list_bases_anonymous|request/)}i
|| $url =~ m{^/ws/subscribe} || $url =~ m{^/ws/subscribe}
...@@ -1116,10 +1121,18 @@ any '/admin/user/(:id).(:type)' => sub { ...@@ -1116,10 +1121,18 @@ any '/admin/user/(:id).(:type)' => sub {
} }
} }
} }
if ($c->param('set_password')) {
$user->change_password($c->param('password'), $c->param('force_change_password'));
}
$c->stash(user => $user); $c->stash(user => $user);
return $c->render(template => 'main/manage_user'); return $c->render(template => 'main/manage_user');
}; };
any '/user/change_password' => sub {
my $c = shift;
return change_password($c);
};
get '/list_ldap_attributes/(#cn)' => sub { get '/list_ldap_attributes/(#cn)' => sub {
my $c = shift; my $c = shift;
...@@ -2554,6 +2567,39 @@ sub register { ...@@ -2554,6 +2567,39 @@ sub register {
$c->render(template => 'bootstrap/new_user'); $c->render(template => 'bootstrap/new_user');
} }
sub change_password {
my $c = shift;
my ($forcing_change_password) = @_;
return $c->render(text => "User is anonymous")
if (! _logged_in($c));
return $c->render(text => "User is temporary")
if $USER->is_temporary;
return $c->render(text => "User is external")
if $USER->is_external;
my $old_password = $c->param('old_password');
if ($old_password) {
return $c->render(template => 'bootstrap/change_password', error => [ "Old password do not match!" ]) if (! $USER->compare_password($old_password));
my $new_password = $c->param('new_password');
return $c->render(template => 'bootstrap/change_password', error => [ "New password length is less than 6!" ]) if (length($new_password) < 6);
my $repeated_new_password = $c->param('repeated_new_password');
return $c->render(template => 'bootstrap/change_password', error => [ "New password and their repeat do not match!" ]) if ($new_password ne $repeated_new_password);
$USER->change_password($c->param('new_password'), 0);
$c->redirect_to('/');
}
$c->render(template => 'bootstrap/change_password', forcing_change_password => $forcing_change_password);
}
sub manage_machine { sub manage_machine {
my $c = shift; my $c = shift;
my ($domain) = _search_requested_machine($c); my ($domain) = _search_requested_machine($c);
......
...@@ -2,7 +2,7 @@ CREATE TABLE `users` ( ...@@ -2,7 +2,7 @@ CREATE TABLE `users` (
`id` int(11) NOT NULL AUTO_INCREMENT, `id` int(11) NOT NULL AUTO_INCREMENT,
`name` char(255) NOT NULL, `name` char(255) NOT NULL,
`password` char(255) DEFAULT NULL, `password` char(255) DEFAULT NULL,
`change_password` integer DEFAULT 1, `change_password` integer DEFAULT 0,
`is_admin` integer DEFAULT 0, `is_admin` integer DEFAULT 0,
`is_temporary` integer DEFAULT 0, `is_temporary` integer DEFAULT 0,
`is_external` integer DEFAULT 0, `is_external` integer DEFAULT 0,
......
...@@ -2,7 +2,7 @@ CREATE TABLE `users` ( ...@@ -2,7 +2,7 @@ CREATE TABLE `users` (
`id` integer NOT NULL PRIMARY KEY AUTOINCREMENT `id` integer NOT NULL PRIMARY KEY AUTOINCREMENT
, `name` char(255) NOT NULL , `name` char(255) NOT NULL
, `password` char(255) DEFAULT NULL , `password` char(255) DEFAULT NULL
, `change_password` integer DEFAULT 1 , `change_password` integer DEFAULT 0
, `is_admin` integer DEFAULT 0 , `is_admin` integer DEFAULT 0
, `is_temporary` integer DEFAULT 0 , `is_temporary` integer DEFAULT 0
, `is_external` integer DEFAULT 0 , `is_external` integer DEFAULT 0
......
<!DOCTYPE html>
<html ng-app="ravada.app">
%= include 'bootstrap/header'
<body id="page-top" data-spy="scroll" data-target=".navbar-fixed-top" role="document">
<div id="wrapper">
%= include 'bootstrap/navigation'
<div id="page-wrapper">
<!--CHANGE PASSWORD-->
<div ng-controller="ChangePasswordForm">
<div class="page-title">
<div class="card">
<div class="card-header">
<h2><%=l 'Change password' %>
</h2>
</div>
%= include '/ng-templates/change_password'
</div>
</div>
</div>
</div>
</div>
%= include 'bootstrap/scripts'
</body>
</html>
...@@ -13,6 +13,7 @@ navbar-dark bg-dark fixed-top navbar-expand-lg navbar-inverse"> ...@@ -13,6 +13,7 @@ navbar-dark bg-dark fixed-top navbar-expand-lg navbar-inverse">
<div class="collapse navbar-collapse justify-content-end" id="navbarNavDropdown"> <div class="collapse navbar-collapse justify-content-end" id="navbarNavDropdown">
<!-- Top Menu Items --> <!-- Top Menu Items -->
<ul class="navbar-nav"> <ul class="navbar-nav">
% if (! $forcing_change_password) {
% if ($_logged_in) { % if ($_logged_in) {
% if ( !$_anonymous ) { % if ( !$_anonymous ) {
<li class="nav-item active"> <li class="nav-item active">
...@@ -73,6 +74,7 @@ navbar-dark bg-dark fixed-top navbar-expand-lg navbar-inverse"> ...@@ -73,6 +74,7 @@ navbar-dark bg-dark fixed-top navbar-expand-lg navbar-inverse">
</div> </div>
</li> </li>
% } % }
% }
% } % }
</ul> </ul>
</div> </div>
......
<html> <html>
%= include 'bootstrap/header' %= include 'bootstrap/header'
<body id="page-top" data-spy="scroll" data-target=".fixed-top" role="document"> <body id="page-top" data-spy="scroll" data-target=".fixed-top" role="document" ng-app="ravada.app">
<div id="wrapper"> <div id="wrapper">
%= include 'bootstrap/navigation' %= include 'bootstrap/navigation'
<div id="page-wrapper"> <div id="page-wrapper">
...@@ -21,6 +21,11 @@ ...@@ -21,6 +21,11 @@
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" href="#grants" role="tab" data-toggle="tab" aria-controls="grants" aria-selected="true">Grants</a> <a class="nav-link" href="#grants" role="tab" data-toggle="tab" aria-controls="grants" aria-selected="true">Grants</a>
</li> </li>
% }
% if (( $_user->is_admin ) && (! $user->is_external)) {
<li class="nav-item">
<a class="nav-link" href="#password" role="tab" data-toggle="tab" aria-controls="password" aria-selected="true">Password</a>
</li>
% } % }
</ul> </ul>
<div class="tab-content" id="myTabContent"> <div class="tab-content" id="myTabContent">
...@@ -33,6 +38,11 @@ ...@@ -33,6 +38,11 @@
<div class="tab-pane fade" id="grants" role="tabpanel" aria-labelledby="grants-tab"> <div class="tab-pane fade" id="grants" role="tabpanel" aria-labelledby="grants-tab">
%= include '/main/manage_user_grants' %= include '/main/manage_user_grants'
</div> </div>
% }
% if (( $_user->is_admin ) && (! $user->is_external)) {
<div class="tab-pane fade" id="password" role="tabpanel" aria-labelledby="password-tab">
%= include '/main/manage_user_password'
</div>
% } % }
</div> </div>
</div><! --page-header --> </div><! --page-header -->
......
<div class="card">
<div class="card-body">
<form method="post" name="form" action="/admin/user/<%= $user->id %>.json" novalidate>
<input type="hidden" name="set_password" value="1">
<label for="password"><%=l 'New password' %></label><br/>
<input type="text" name="password" ng-model="password" ng-minlength="6">
<br>
<br>
<input type="checkbox" name="force_change_password" value="1" checked>
<label for="force_change_password"><%=l 'Force change password on first access' %></label><br/>
<div ng-show="form.$submitted || (form.password.$touched && form.password.$dirty)">
<div ng-show="form.password.$error.minlength" class="alert alert-warning">
<strong><%=l 'Oops!' %></strong>&nbsp;<%=l 'New Password must be at least 6 characters' %>.
</div>
</div>
<input type="submit" class="btn btn-primary" name="set_password" value="<%=l 'Set New Password' %>">
</form>
</div>
</div>
<div class="card-body">
<form name="form" role="form" method="post" action="/user/change_password" novalidate>
<div class="from-group">
<label for="old_password"><%=l 'Old Password' %></label>
<input class="form-control" ng-model="old_password" ng-model-onblur placeholder="<%=l 'Enter Old Password' %>" type="password" name="old_password" id="old_password" required="true" ng-pattern="/^[a-zA-Z0-9]*$/"><br/>
</div>
<div class="from-group">
<label for="new_password"><%=l 'New Password' %></label>
<input class="form-control" ng-model="new_password" ng-model-onblur placeholder="<%=l 'Enter New Password' %>" type="password" ng-minlength="6" name="new_password" id="new_password" required="true" ng-pattern="/^[a-zA-Z0-9]*$/"><br/>
</div>
<div class="from-group">
<label for="repeated_new_password"><%=l 'Repeat New Password' %></label>
<input class="form-control" ng-model="repeated_new_password" ng-model-onblur placeholder="<%=l 'Re-Enter New Password' %>" type="password" name="repeated_new_password" id="repeated_new_password" required="true" ng-pattern="/^[a-zA-Z0-9]*$/"><br/>
</div>
<div ng-show="form.$submitted || (form.old_password.$touched && form.old_password.$dirty)">
<div ng-show="form.old_password.$error.required" class="alert alert-warning">
<strong><%=l 'Oops!' %></strong>&nbsp;<%=l 'Old Password is required' %>.
</div>
<div ng-show="form.old_password.$error.pattern" class="alert alert-warning">
<strong><%=l 'Oops!' %></strong>&nbsp;<%=l 'Old Password can only contain words and numbers' %>.
</div>
<div ng-show="form.new_password.$error.required" class="alert alert-warning">
<strong><%=l 'Oops!' %></strong>&nbsp;<%=l 'New Password is required' %>.
</div>
<div ng-show="form.new_password.$error.minlength" class="alert alert-warning">
<strong><%=l 'Oops!' %></strong>&nbsp;<%=l 'New Password must be at least 6 characters' %>.
</div>
<div ng-show="form.new_password.$error.pattern" class="alert alert-warning">
<strong><%=l 'Oops!' %></strong>&nbsp;<%=l 'New Password can only contain words and numbers' %>.
</div>
<div ng-show="old_password === new_password" class="alert alert-warning">
<strong><%=l 'Oops!' %></strong>&nbsp;<%=l 'Old and New Passwords match!' %>.
</div>
<div ng-show="form.repeated_new_password.$error.required" class="alert alert-warning">
<strong><%=l 'Oops!' %></strong>&nbsp;<%=l 'Repeated New Password is required' %>.
</div>
<div ng-show="new_password != repeated_new_password" class="alert alert-warning">
<strong><%=l 'Oops!' %></strong>&nbsp;<%=l 'Password and their confirmation do not match!' %>.
</div>
</div>
<button type="submit" ng-disabled="form.$invalid || old_password === new_password || new_password != repeated_new_password" id="submitbutton" class="btn btn-primary"><%=l 'Submit' %></button>
% if (scalar @$error) {
% for my $i (@$error) {
<div class="alert alert-danger">
<%= $i %>
</div>
% }
% }
</form>
</div>
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment