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.
410 lines
14 KiB
410 lines
14 KiB
package NGCP::Panel::Controller::Administrator;
|
|
use NGCP::Panel::Utils::Generic qw(:all);
|
|
use Sipwise::Base;
|
|
use parent 'Catalyst::Controller';
|
|
use HTTP::Headers qw();
|
|
use IO::Compress::Zip qw/zip/;
|
|
use NGCP::Panel::Form::Administrator::Reseller;
|
|
use NGCP::Panel::Form::Administrator::Admin;
|
|
use NGCP::Panel::Form::Administrator::APIGenerate qw();
|
|
use NGCP::Panel::Form::Administrator::APIDownDelete qw();
|
|
use NGCP::Panel::Utils::Message;
|
|
use NGCP::Panel::Utils::Navigation;
|
|
use NGCP::Panel::Utils::Admin;
|
|
|
|
sub auto :Does(ACL) :ACLDetachTo('/denied_page') :AllowedRole(admin) :AllowedRole(reseller) {
|
|
my ($self, $c) = @_;
|
|
$c->log->debug(__PACKAGE__ . '::auto');
|
|
NGCP::Panel::Utils::Navigation::check_redirect_chain(c => $c);
|
|
return 1;
|
|
}
|
|
|
|
sub list_admin :PathPart('administrator') :Chained('/') :CaptureArgs(0) {
|
|
my ($self, $c) = @_;
|
|
|
|
my $dispatch_to = '_admin_resultset_' . $c->user->roles;
|
|
$c->stash(
|
|
admins => $self->$dispatch_to($c),
|
|
template => 'administrator/list.tt',
|
|
);
|
|
my $cols = [
|
|
{ name => "id", search => 1, title => $c->loc("#") },
|
|
];
|
|
if($c->user->is_superuser) {
|
|
@{ $cols } = (@{ $cols }, { name => "reseller.name", search => 1, title => $c->loc("Reseller") });
|
|
}
|
|
@{ $cols } = (@{ $cols },
|
|
{ name => "login", search => 1, title => $c->loc("Login") },
|
|
{ name => "is_master", title => $c->loc("Master") },
|
|
{ name => "is_active", title => $c->loc("Active") },
|
|
{ name => "read_only", title => $c->loc("Read Only") },
|
|
{ name => "show_passwords", title => $c->loc("Show Passwords") },
|
|
{ name => "call_data", title => $c->loc("Show CDRs") },
|
|
{ name => "billing_data", title => $c->loc("Show Billing Info") },
|
|
);
|
|
if($c->user->is_superuser) {
|
|
@{ $cols } = (@{ $cols }, { name => "lawful_intercept", title => $c->loc("Lawful Intercept") });
|
|
}
|
|
$c->stash->{admin_dt_columns} = NGCP::Panel::Utils::Datatables::set_columns($c, $cols);
|
|
return;
|
|
}
|
|
|
|
sub _admin_resultset_admin {
|
|
my ($self, $c) = @_;
|
|
return $c->model('DB')->resultset('admins');
|
|
}
|
|
|
|
sub _admin_resultset_reseller {
|
|
my ($self, $c) = @_;
|
|
return $c->model('DB')->resultset('admins')->search({
|
|
reseller_id => $c->user->reseller_id,
|
|
});
|
|
}
|
|
|
|
sub root :Chained('list_admin') :PathPart('') :Args(0) {
|
|
my ($self, $c) = @_;
|
|
return;
|
|
}
|
|
|
|
sub ajax :Chained('list_admin') :PathPart('ajax') :Args(0) {
|
|
my ($self, $c) = @_;
|
|
my $admins = $c->stash->{admins};
|
|
NGCP::Panel::Utils::Datatables::process($c, $admins, $c->stash->{admin_dt_columns});
|
|
$c->detach($c->view('JSON'));
|
|
return;
|
|
}
|
|
|
|
sub create :Chained('list_admin') :PathPart('create') :Args(0) {
|
|
my ($self, $c) = @_;
|
|
|
|
$c->detach('/denied_page')
|
|
unless($c->user->is_master);
|
|
|
|
my $form;
|
|
my $params = {};
|
|
$params = merge($params, $c->session->{created_objects});
|
|
if($c->user->is_superuser) {
|
|
$form = NGCP::Panel::Form::Administrator::Admin->new(ctx => $c);
|
|
} else {
|
|
$form = NGCP::Panel::Form::Administrator::Reseller->new(ctx => $c);
|
|
}
|
|
$form->process(
|
|
posted => ($c->request->method eq 'POST'),
|
|
params => $c->request->params,
|
|
item => $params,
|
|
);
|
|
NGCP::Panel::Utils::Navigation::check_form_buttons(
|
|
c => $c,
|
|
form => $form,
|
|
fields => {
|
|
'reseller.create' => $c->uri_for('/reseller/create'),
|
|
},
|
|
back_uri => $c->req->uri,
|
|
);
|
|
if ($form->validated) {
|
|
try {
|
|
if($c->user->is_superuser) {
|
|
$form->values->{reseller_id} = $form->values->{reseller}{id};
|
|
delete $form->values->{reseller};
|
|
} else {
|
|
$form->values->{reseller_id} = $c->user->reseller_id;
|
|
}
|
|
$form->values->{md5pass} = undef;
|
|
$form->values->{saltedpass} = NGCP::Panel::Utils::Admin::generate_salted_hash(delete $form->values->{password});
|
|
$c->stash->{admins}->create($form->values);
|
|
delete $c->session->{created_objects}->{reseller};
|
|
NGCP::Panel::Utils::Message::info(
|
|
c => $c,
|
|
desc => $c->loc('Administrator successfully created'),
|
|
);
|
|
} catch($e) {
|
|
NGCP::Panel::Utils::Message::error(
|
|
c => $c,
|
|
error => $e,
|
|
desc => $c->loc('Failed to create administrator'),
|
|
);
|
|
}
|
|
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for('/administrator'));
|
|
}
|
|
|
|
$c->stash(
|
|
create_flag => 1,
|
|
form => $form,
|
|
);
|
|
}
|
|
|
|
sub base :Chained('list_admin') :PathPart('') :CaptureArgs(1) {
|
|
my ($self, $c, $administrator_id) = @_;
|
|
|
|
$c->detach('/denied_page')
|
|
unless($c->user->is_master);
|
|
|
|
unless ($administrator_id && is_int($administrator_id)) {
|
|
NGCP::Panel::Utils::Message::error(
|
|
c => $c,
|
|
data => { id => $administrator_id },
|
|
desc => $c->loc('Invalid administrator id detected'),
|
|
);
|
|
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for('/administrator'));
|
|
}
|
|
$c->stash(administrator => $c->stash->{admins}->find($administrator_id));
|
|
unless($c->stash->{administrator}) {
|
|
NGCP::Panel::Utils::Message::error(
|
|
c => $c,
|
|
desc => $c->loc('Administrator not found'),
|
|
);
|
|
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for('/administrator'));
|
|
}
|
|
}
|
|
|
|
sub edit :Chained('base') :PathPart('edit') :Args(0) {
|
|
my ($self, $c) = @_;
|
|
my $posted = $c->request->method eq 'POST';
|
|
my $form;
|
|
my $params = { $c->stash->{administrator}->get_inflated_columns };
|
|
$params->{reseller}{id} = delete $params->{reseller_id};
|
|
$params = merge($params, $c->session->{created_objects});
|
|
if($c->user->is_superuser) {
|
|
$form = NGCP::Panel::Form::Administrator::Admin->new(ctx => $c);
|
|
} else {
|
|
$form = NGCP::Panel::Form::Administrator::Reseller->new(ctx => $c);
|
|
}
|
|
$form->field('password')->{required} = 0;
|
|
|
|
$form->process(
|
|
posted => $posted,
|
|
params => $c->request->params,
|
|
item => $params,
|
|
);
|
|
NGCP::Panel::Utils::Navigation::check_form_buttons(
|
|
c => $c,
|
|
form => $form,
|
|
fields => {
|
|
'reseller.create' => $c->uri_for('/reseller/create'),
|
|
},
|
|
back_uri => $c->req->uri,
|
|
);
|
|
if ($posted && $form->validated) {
|
|
try {
|
|
# don't allow to take away own master rights/write permission, otherwise he'll not be
|
|
# able to manage any more admins
|
|
if($c->stash->{administrator}->id == $c->user->id) {
|
|
delete $form->values->{$_} for qw(is_master is_active read_only);
|
|
}
|
|
|
|
if($c->user->is_superuser) {
|
|
$form->values->{reseller_id} = $form->values->{reseller}{id};
|
|
delete $form->values->{reseller};
|
|
}
|
|
delete $form->values->{password} unless length $form->values->{password};
|
|
if(exists $form->values->{password}) {
|
|
$form->values->{md5pass} = undef;
|
|
$form->values->{saltedpass} = NGCP::Panel::Utils::Admin::generate_salted_hash(delete $form->values->{password});
|
|
}
|
|
$c->stash->{administrator}->update($form->values);
|
|
delete $c->session->{created_objects}->{reseller};
|
|
NGCP::Panel::Utils::Message::info(
|
|
c => $c,
|
|
data => { $c->stash->{administrator}->get_inflated_columns },
|
|
desc => $c->loc('Administrator successfully updated'),
|
|
);
|
|
} catch($e) {
|
|
NGCP::Panel::Utils::Message::error(
|
|
c => $c,
|
|
error => $e,
|
|
data => { $c->stash->{administrator}->get_inflated_columns },
|
|
desc => $c->loc('Failed to update administrator'),
|
|
);
|
|
};
|
|
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for('/administrator'));
|
|
}
|
|
|
|
$c->stash(
|
|
form => $form,
|
|
edit_flag => 1,
|
|
);
|
|
}
|
|
|
|
sub delete :Chained('base') :PathPart('delete') :Args(0) {
|
|
my ($self, $c) = @_;
|
|
|
|
if($c->stash->{administrator}->id == $c->user->id) {
|
|
NGCP::Panel::Utils::Message::error(
|
|
c => $c,
|
|
data => { $c->stash->{administrator}->get_inflated_columns },
|
|
desc => $c->loc('Cannot delete myself'),
|
|
);
|
|
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for('/administrator'));
|
|
}
|
|
try {
|
|
$c->stash->{administrator}->delete;
|
|
NGCP::Panel::Utils::Message::info(
|
|
c => $c,
|
|
data => { $c->stash->{administrator}->get_inflated_columns },
|
|
desc => $c->loc('Administrator successfully deleted'),
|
|
);
|
|
} catch($e) {
|
|
NGCP::Panel::Utils::Message::error(
|
|
c => $c,
|
|
error => $e,
|
|
data => { $c->stash->{administrator}->get_inflated_columns },
|
|
desc => $c->loc('Failed to delete administrator'),
|
|
);
|
|
};
|
|
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for('/administrator'));
|
|
}
|
|
|
|
sub api_key :Chained('base') :PathPart('api_key') :Args(0) {
|
|
my ($self, $c) = @_;
|
|
my $serial = $c->stash->{administrator}->ssl_client_m_serial;
|
|
my ($pem, $p12);
|
|
if ($c->req->body_parameters->{'gen.generate'}) {
|
|
my $updated;
|
|
while (!$updated) {
|
|
$serial = time;
|
|
try {
|
|
$pem = $c->model('CA')->make_client($c, $serial);
|
|
$p12 = $c->model('CA')->make_pkcs12($c, $serial, $pem, 'sipwise');
|
|
} catch ($e) {
|
|
NGCP::Panel::Utils::Message::error(
|
|
c => $c,
|
|
error => $e,
|
|
data => { $c->stash->{administrator}->get_inflated_columns },
|
|
desc => $c->loc("Failed to generate client certificate."),
|
|
);
|
|
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for('/administrator'));
|
|
}
|
|
try {
|
|
$c->stash->{administrator}->update({
|
|
ssl_client_m_serial => $serial,
|
|
ssl_client_certificate => undef, # not used anymore, clear it just in case
|
|
});
|
|
$updated = 1;
|
|
} catch(DBIx::Class::Exception $e where { "$_" =~ qr'Duplicate entry' }) {
|
|
$serial++;
|
|
}
|
|
}
|
|
|
|
my $input = {
|
|
"NGCP-API-client-certificate-$serial.pem" => $pem,
|
|
"NGCP-API-client-certificate-$serial.p12" => $p12,
|
|
};
|
|
my $zip_opts = {
|
|
AutoClose => 0,
|
|
Append => 0,
|
|
Name => "README.txt",
|
|
CanonicalName => 1,
|
|
Stream => 1,
|
|
};
|
|
my $zipped_file;
|
|
my $zip = IO::Compress::Zip->new(\$zipped_file, %{ $zip_opts });
|
|
$zip->write("Use the PEM file for programmatical clients like java, perl, php or curl, and the P12 file for browsers like Firefox or Chrome. The password for the P12 import is 'sipwise'. Handle this file with care, as it cannot be downloaded for a second time! Only a new certificate can be generated if the certificate is lost.\n");
|
|
foreach my $k(keys %{ $input } ) {
|
|
$zip_opts->{Name} = $k;
|
|
$zip_opts->{Append} = 1;
|
|
$zip->newStream(%{ $zip_opts });
|
|
$zip->write($input->{$k});
|
|
}
|
|
$zip->close();
|
|
|
|
$c->res->headers(HTTP::Headers->new(
|
|
'Content-Type' => 'application/zip',
|
|
'Content-Disposition' => sprintf('attachment; filename=%s', "NGCP-API-client-certificate-$serial.zip")
|
|
));
|
|
$c->res->body($zipped_file);
|
|
return;
|
|
} elsif ($c->req->body_parameters->{'ca.verify'} || $c->req->parameters->{'ca.verify'}) {
|
|
my $result = $c->model('CA')->check_ca_errors($c);
|
|
if($result){
|
|
NGCP::Panel::Utils::Message::error(
|
|
c => $c,
|
|
error => $result,
|
|
data => { $c->stash->{administrator}->get_inflated_columns },
|
|
desc => $c->loc('CA certificate verification failed: '.$result),
|
|
);
|
|
}else{
|
|
NGCP::Panel::Utils::Message::info(
|
|
c => $c,
|
|
desc => $c->loc('CA certificate is OK'),
|
|
);
|
|
}
|
|
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for('/administrator'));
|
|
} elsif ($c->req->body_parameters->{'del.delete'}) {
|
|
$c->stash->{administrator}->update({
|
|
ssl_client_m_serial => undef,
|
|
ssl_client_certificate => undef,
|
|
});
|
|
return;
|
|
} elsif ($c->req->body_parameters->{'ca.download'}) {
|
|
my $ca_cert = $c->model('CA')->get_server_cert($c);
|
|
$c->res->headers(HTTP::Headers->new(
|
|
'Content-Type' => 'application/octet-stream',
|
|
'Content-Disposition' => sprintf('attachment; filename=%s', "NGCP-API-ca-certificate.pem")
|
|
));
|
|
$c->res->body($ca_cert);
|
|
return;
|
|
} elsif ($c->req->body_parameters->{'close'}) {
|
|
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for('/administrator'));
|
|
return;
|
|
}
|
|
my $form;
|
|
if ($serial) {
|
|
$form = NGCP::Panel::Form::Administrator::APIDownDelete->new;
|
|
} else {
|
|
$form = NGCP::Panel::Form::Administrator::APIGenerate->new;
|
|
}
|
|
$c->stash(
|
|
api_modal_flag => 1,
|
|
form => $form,
|
|
);
|
|
}
|
|
|
|
__PACKAGE__->meta->make_immutable;
|
|
1;
|
|
|
|
__END__
|
|
|
|
=encoding UTF-8
|
|
|
|
=head1 NAME
|
|
|
|
NGCP::Panel::Controller::Administrator - manage platform administrators
|
|
|
|
=head1 DESCRIPTION
|
|
|
|
View and edit platform administrators. Administrators have the highest access level and thus can exert the highest
|
|
amount of control over resellers and subscribers.
|
|
|
|
=head1 METHODS
|
|
|
|
=head2 C<list_admin>
|
|
|
|
Stashes administrator data structure. Chains off to L</root>.
|
|
|
|
=head2 C<root>
|
|
|
|
Display administrators through F<administrator/list.tt> template.
|
|
|
|
=head2 C<ajax>
|
|
|
|
JSON emitter for administrator data structure. Implicitly called from F<administrator/list.tt> template.
|
|
|
|
=head2 C<create>
|
|
|
|
Show modal dialog form and save administrator details to database.
|
|
|
|
=head2 C<base>
|
|
|
|
Capture id of existing administrator. Used for L</edit> and L</delete>.
|
|
|
|
=head1 AUTHOR
|
|
|
|
Lars Dieckow C<< <ldieckow@sipwise.com> >>
|
|
|
|
=head1 LICENSE
|
|
|
|
This library is free software. You can redistribute it and/or modify
|
|
it under the same terms as Perl itself.
|
|
|
|
# vim: set tabstop=4 expandtab:
|