You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
444 lines
15 KiB
444 lines
15 KiB
package NGCP::Panel::Controller::Login;
|
|
|
|
use warnings;
|
|
use strict;
|
|
|
|
use parent 'Catalyst::Controller';
|
|
use TryCatch;
|
|
use UUID;
|
|
|
|
use NGCP::Panel::Form;
|
|
|
|
use NGCP::Panel::Utils::Auth;
|
|
use NGCP::Panel::Utils::Form;
|
|
use NGCP::Panel::Utils::Subscriber;
|
|
|
|
sub login_index :Path Form {
|
|
my ( $self, $c, $realm ) = @_;
|
|
|
|
$realm = 'subscriber'
|
|
unless($realm && $realm eq 'admin');
|
|
|
|
my $posted = ($c->req->method eq 'POST');
|
|
my $form = NGCP::Panel::Form::get("NGCP::Panel::Form::Login", $c);
|
|
$form->process(
|
|
posted => $posted,
|
|
params => $c->request->params,
|
|
item => { username => $c->stash->{username} },
|
|
);
|
|
|
|
if($posted && $form->validated) {
|
|
$c->log->debug("login form validated");
|
|
my $user = $form->field('username')->value;
|
|
my $pass = $form->field('password')->value;
|
|
$c->log->debug("Login::index user=$user, pass=****, realm=$realm");
|
|
my $res;
|
|
if($realm eq 'admin') {
|
|
$res = NGCP::Panel::Utils::Auth::perform_auth($c, $user, $pass, 'admin', 'admin_bcrypt');
|
|
} elsif($realm eq 'subscriber') {
|
|
my ($u, $d, $t) = split /\@/, $user;
|
|
if(defined $t) {
|
|
# in case username is an email address
|
|
$u = $u . '@' . $d;
|
|
$d = $t;
|
|
}
|
|
unless(defined $d) {
|
|
$d = $c->req->uri->host;
|
|
}
|
|
$res = NGCP::Panel::Utils::Auth::perform_subscriber_auth($c, $u, $d, $pass);
|
|
}
|
|
|
|
if($res) {
|
|
# auth ok
|
|
|
|
if ($realm eq 'admin') {
|
|
use Crypt::JWT qw/encode_jwt/;
|
|
|
|
my $key = $c->config->{'Plugin::Authentication'}{api_admin_jwt}{credential}{jwt_key};
|
|
my $relative_exp = $c->config->{'Plugin::Authentication'}{api_admin_jwt}{credential}{relative_exp};
|
|
my $alg = $c->config->{'Plugin::Authentication'}{api_admin_jwt}{credential}{alg};
|
|
|
|
unless ($key) {
|
|
NGCP::Panel::Utils::Message::error(
|
|
c => $c,
|
|
desc => $c->loc('No JWT key has been configured.'),
|
|
);
|
|
}
|
|
|
|
my $jwt_data = {
|
|
id => $c->user->id,
|
|
username => $c->user->login,
|
|
};
|
|
my $token = encode_jwt(
|
|
payload => $jwt_data,
|
|
key => $key,
|
|
alg => $alg,
|
|
$relative_exp ? (relative_exp => $relative_exp) : (),
|
|
);
|
|
|
|
$c->session->{aui_adminId} = $c->user->id;
|
|
$c->session->{aui_jwt} = $token;
|
|
}
|
|
|
|
$c->session->{user_tz} = undef; # reset to reload from db
|
|
$c->session->{user_tz_name} = undef; # reset to reload from db
|
|
my $target = $c->session->{'target'} || '/dashboard';
|
|
delete $c->session->{target};
|
|
$target =~ s!^https?://[^/]+/!/!;
|
|
$c->log->debug("Login::index auth ok, redirecting to $target");
|
|
$c->response->redirect($target);
|
|
return;
|
|
} else {
|
|
$c->log->warn("invalid http login from '".$c->qs($c->req->address)."'");
|
|
$c->log->debug("Login::index auth failed");
|
|
$form->add_form_error($c->loc('Invalid username/password'));
|
|
}
|
|
} else {
|
|
# initial get
|
|
}
|
|
|
|
if ($form->has_errors) {
|
|
my $request_ip = $c->request->address;
|
|
$c->log->error("NGCP Panel Login failed realm=$realm ip=" . $c->qs($request_ip));
|
|
}
|
|
|
|
$c->stash(form => $form);
|
|
$c->stash(realm => $realm);
|
|
$c->stash(template => 'login/login.tt');
|
|
}
|
|
|
|
sub reset_password :Chained('/') :PathPart('resetpassword') :Args(0) {
|
|
my ($self, $c) = @_;
|
|
|
|
my $posted = $c->req->method eq "POST";
|
|
my $form = NGCP::Panel::Form::get("NGCP::Panel::Form::Administrator::ResetPassword", $c);
|
|
my $params = {};
|
|
$form->process(
|
|
posted => $posted,
|
|
params => $c->req->params,
|
|
item => $params,
|
|
);
|
|
NGCP::Panel::Utils::Navigation::check_form_buttons(
|
|
c => $c,
|
|
form => $form,
|
|
fields => {},
|
|
back_uri => $c->req->uri,
|
|
);
|
|
|
|
if($posted && $form->validated) {
|
|
try {
|
|
my $schema = $c->model('DB');
|
|
$schema->txn_do(sub {
|
|
my $username = $form->params->{username};
|
|
my $admin = $schema->resultset('admins')->search({
|
|
login => $username,
|
|
})->first;
|
|
|
|
# don't inform about unknown users
|
|
if($admin) {
|
|
if (!$admin->email) {
|
|
NGCP::Panel::Utils::Message::error(
|
|
c => $c,
|
|
desc => $c->loc('Admin does not have an email set'),
|
|
);
|
|
}
|
|
elsif ($admin->can_reset_password) {
|
|
my $result = NGCP::Panel::Utils::Auth::initiate_password_reset($c, $admin);
|
|
if (!$result->{success}) {
|
|
NGCP::Panel::Utils::Message::error(
|
|
c => $c,
|
|
desc => $c->loc($result->{error}),
|
|
);
|
|
}
|
|
else {
|
|
NGCP::Panel::Utils::Message::info(
|
|
c => $c,
|
|
desc => $c->loc('Successfully reset password, please check your email'),
|
|
);
|
|
}
|
|
}
|
|
else {
|
|
NGCP::Panel::Utils::Message::error(
|
|
c => $c,
|
|
desc => $c->loc('This user is not allowed to reset password'),
|
|
);
|
|
}
|
|
}
|
|
});
|
|
} catch($e) {
|
|
NGCP::Panel::Utils::Message::error(
|
|
c => $c,
|
|
error => $e,
|
|
desc => $c->loc('Failed to reset password'),
|
|
);
|
|
}
|
|
$c->res->redirect($c->uri_for('/login/admin'));
|
|
}
|
|
|
|
$c->stash(
|
|
form => $form,
|
|
edit_flag => 1,
|
|
template => 'administrator/reset_password.tt',
|
|
close_target => $c->uri_for('/login/admin'),
|
|
);
|
|
}
|
|
|
|
sub recover_password :Chained('/') :PathPart('recoverpassword') :Args(0) {
|
|
my ($self, $c) = @_;
|
|
|
|
$c->user->logout if($c->user);
|
|
|
|
my $posted = $c->req->method eq "POST";
|
|
my ($uuid_bin, $uuid_string);
|
|
$uuid_string = $c->req->params->{token} // '';
|
|
|
|
unless($uuid_string && UUID::parse($uuid_string, $uuid_bin) != -1) {
|
|
$c->log->warn("invalid password recovery attempt for token '$uuid_string' from '".$c->qs($c->req->address)."'");
|
|
$c->detach('/denied_page')
|
|
}
|
|
|
|
my $redis = $c->redis_get_connection({database => $c->config->{'Plugin::Session'}->{redis_db}});
|
|
unless ($redis) {
|
|
$c->log->error("Failed to connect to central redis url " . $c->config->{redis}->{central_url});
|
|
return;
|
|
}
|
|
my $ip = $redis->hget("password_reset:admin::$uuid_string", "ip");
|
|
if ($ip && $ip ne $c->req->address) {
|
|
$c->log->warn("invalid password recovery attempt for token '$uuid_string' from '".$c->qs($c->req->address)."'");
|
|
$c->detach('/denied_page');
|
|
}
|
|
my $admin = $redis->hget("password_reset:admin::$uuid_string", "user");
|
|
my $administrator;
|
|
if ($admin) {
|
|
$administrator = $c->model('DB')->resultset('admins')->search({login => $admin})->first;
|
|
unless ($administrator) {
|
|
$c->log->warn("invalid password recovery attempt for token '$uuid_string' from '".$c->qs($c->req->address)."'");
|
|
$c->detach('/denied_page');
|
|
}
|
|
}
|
|
else {
|
|
NGCP::Panel::Utils::Message::error(
|
|
c => $c,
|
|
desc => $c->loc('Invalid token'),
|
|
);
|
|
$c->res->redirect($c->uri_for('/login/admin'));
|
|
}
|
|
|
|
my $form = NGCP::Panel::Form::get("NGCP::Panel::Form::Administrator::RecoverPassword", $c);
|
|
my $params = {
|
|
token => $uuid_string,
|
|
};
|
|
$form->process(
|
|
posted => $posted,
|
|
params => $c->req->params,
|
|
item => $params,
|
|
);
|
|
NGCP::Panel::Utils::Navigation::check_form_buttons(
|
|
c => $c,
|
|
form => $form,
|
|
fields => {},
|
|
back_uri => $c->req->uri,
|
|
);
|
|
if($posted && $form->validated) {
|
|
try {
|
|
$administrator->update({
|
|
saltedpass => NGCP::Panel::Utils::Auth::generate_salted_hash($form->params->{password}),
|
|
});
|
|
$redis->del("password_reset:admin::$uuid_string");
|
|
$redis->del("password_reset:admin::$admin");
|
|
} catch($e) {
|
|
NGCP::Panel::Utils::Message::error(
|
|
c => $c,
|
|
error => $e,
|
|
type => 'internal',
|
|
desc => $c->loc('Failed to recover password'),
|
|
);
|
|
$c->detach('/denied_page');
|
|
}
|
|
|
|
NGCP::Panel::Utils::Message::info(
|
|
c => $c,
|
|
data => { username => $administrator->login },
|
|
desc => $c->loc('Password successfully recovered, please re-login.'),
|
|
);
|
|
$c->flash(username => $administrator->login);
|
|
$c->res->redirect($c->uri_for('/login/admin'));
|
|
return;
|
|
|
|
}
|
|
|
|
$c->stash(
|
|
form => $form,
|
|
edit_flag => 1,
|
|
template => 'administrator/reset_password.tt',
|
|
close_target => $c->uri_for('/login/admin'),
|
|
);
|
|
}
|
|
|
|
sub change_password :Chained('/') :PathPart('changepassword') Args(0) {
|
|
my ($self, $c) = @_;
|
|
|
|
my $realm = $c->req->env->{NGCP_REALM} // 'admin';
|
|
|
|
$c->user->logout if $c->user;
|
|
|
|
my $posted = ($c->req->method eq 'POST');
|
|
my $form = NGCP::Panel::Form::get("NGCP::Panel::Form::PasswordChange", $c);
|
|
$form->process(
|
|
posted => $posted,
|
|
params => $c->request->params,
|
|
item => { username => $c->stash->{username} },
|
|
);
|
|
|
|
if($posted && $form->validated) {
|
|
$c->log->debug("login form validated");
|
|
my $user = $form->field('username')->value;
|
|
my $pass = $form->field('password')->value;
|
|
my $new_pass = $form->field('new_password')->value;
|
|
my $new_pass2 = $form->field('new_password2')->value;
|
|
$c->log->debug("Password change user=$user, realm=$realm");
|
|
my $res;
|
|
if($realm eq 'admin') {
|
|
$res = NGCP::Panel::Utils::Auth::perform_auth($c, $user, $pass, 'admin', 'admin_bcrypt');
|
|
} elsif($realm eq 'subscriber') {
|
|
my ($u, $d, $t) = split /\@/, $user;
|
|
if(defined $t) {
|
|
# in case username is an email address
|
|
$u = $u . '@' . $d;
|
|
$d = $t;
|
|
}
|
|
unless(defined $d) {
|
|
$d = $c->req->uri->host;
|
|
}
|
|
$res = NGCP::Panel::Utils::Auth::perform_subscriber_auth($c, $u, $d, $pass);
|
|
}
|
|
|
|
if($res) {
|
|
# auth ok
|
|
|
|
if ($pass eq $new_pass) {
|
|
$form->field('new_password')->add_error($c->loc('Password must not be equal to the old password'));
|
|
} elsif ($new_pass ne $new_pass2) {
|
|
$form->field('new_password2')->add_error($c->loc('New password fields do not match'));
|
|
} else {
|
|
NGCP::Panel::Utils::Form::validate_password(
|
|
c => $c, field => $form->field('new_password'), admin => $realm eq 'admin', password_change => 1
|
|
);
|
|
}
|
|
|
|
if (!$form->has_errors) {
|
|
if ($realm eq 'admin') {
|
|
use Crypt::JWT qw/encode_jwt/;
|
|
|
|
$c->user->update({
|
|
saltedpass => NGCP::Panel::Utils::Auth::generate_salted_hash($new_pass)
|
|
});
|
|
NGCP::Panel::Utils::Admin::insert_password_journal(
|
|
$c, $c->user, $new_pass
|
|
);
|
|
|
|
my $key = $c->config->{'Plugin::Authentication'}{api_admin_jwt}{credential}{jwt_key};
|
|
my $relative_exp = $c->config->{'Plugin::Authentication'}{api_admin_jwt}{credential}{relative_exp};
|
|
my $alg = $c->config->{'Plugin::Authentication'}{api_admin_jwt}{credential}{alg};
|
|
|
|
unless ($key) {
|
|
NGCP::Panel::Utils::Message::error(
|
|
c => $c,
|
|
desc => $c->loc('No JWT key has been configured.'),
|
|
);
|
|
}
|
|
|
|
my $jwt_data = {
|
|
id => $c->user->id,
|
|
username => $c->user->login,
|
|
};
|
|
my $token = encode_jwt(
|
|
payload => $jwt_data,
|
|
key => $key,
|
|
alg => $alg,
|
|
$relative_exp ? (relative_exp => $relative_exp) : (),
|
|
);
|
|
|
|
$c->session->{aui_adminId} = $c->user->id;
|
|
$c->session->{aui_jwt} = $token;
|
|
} else {
|
|
$c->user->provisioning_voip_subscriber->update({
|
|
webpassword =>
|
|
$NGCP::Panel::Utils::Auth::ENCRYPT_SUBSCRIBER_WEBPASSWORDS
|
|
? NGCP::Panel::Utils::Auth::generate_salted_hash($new_pass)
|
|
: $new_pass
|
|
});
|
|
NGCP::Panel::Utils::Subscriber::insert_webpassword_journal(
|
|
$c, $c->user->provisioning_voip_subscriber, $new_pass
|
|
);
|
|
|
|
}
|
|
$c->log->debug("Password successfully changed for user=$user, realm=$realm");
|
|
$c->session->{user_tz} = undef; # reset to reload from db
|
|
$c->session->{user_tz_name} = undef; # reset to reload from db
|
|
my $target = $c->session->{'target'} || '/dashboard';
|
|
delete $c->session->{target};
|
|
$target =~ s!^https?://[^/]+/!/!;
|
|
$c->log->debug("Login::index auth ok, redirecting to $target");
|
|
NGCP::Panel::Utils::Message::info(
|
|
c => $c,
|
|
desc => $c->loc('Password successfully changed'),
|
|
);
|
|
$c->response->redirect($target);
|
|
}
|
|
} else {
|
|
$c->log->warn("invalid http login from '".$c->qs($c->req->address)."'");
|
|
$c->log->debug("Login::index auth failed");
|
|
$form->add_form_error($c->loc('Invalid username/password'));
|
|
}
|
|
} else {
|
|
# initial get
|
|
}
|
|
|
|
if ($form->has_errors) {
|
|
my $request_ip = $c->request->address;
|
|
$c->log->error("NGCP Panel Password Change failed realm=$realm ip=" . $c->qs($request_ip));
|
|
}
|
|
|
|
$c->stash(
|
|
form => $form,
|
|
realm => $realm,
|
|
template => 'login/change_password.tt',
|
|
);
|
|
}
|
|
|
|
1;
|
|
|
|
__END__
|
|
|
|
=encoding UTF-8
|
|
|
|
=head1 NAME
|
|
|
|
NGCP::Panel::Controller::Login - Catalyst Controller
|
|
|
|
=head1 DESCRIPTION
|
|
|
|
Catalyst Controller.
|
|
|
|
=head1 METHODS
|
|
|
|
=cut
|
|
|
|
=head2 index
|
|
|
|
=cut
|
|
|
|
=head1 AUTHOR
|
|
|
|
Andreas Granig,,,
|
|
|
|
=head1 LICENSE
|
|
|
|
This library is free software. You can redistribute it and/or modify
|
|
it under the same terms as Perl itself.
|
|
|
|
=cut
|
|
|
|
# vim: set tabstop=4 expandtab:
|