parent
c58d1702e0
commit
cb7e0fb63c
@ -0,0 +1,175 @@
|
||||
package NGCP::Panel::Controller::Security;
|
||||
use Sipwise::Base;
|
||||
|
||||
BEGIN { extends 'Catalyst::Controller'; }
|
||||
|
||||
use XML::Mini::Document;
|
||||
use NGCP::Panel::Utils::Navigation;
|
||||
use NGCP::Panel::Utils::XMLDispatcher;
|
||||
|
||||
sub auto :Does(ACL) :ACLDetachTo('/denied_page') :AllowedRole(admin) {
|
||||
my ($self, $c) = @_;
|
||||
$c->log->debug(__PACKAGE__ . '::auto');
|
||||
NGCP::Panel::Utils::Navigation::check_redirect_chain(c => $c);
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub root :PathPart('/') :CaptureArgs(0) {
|
||||
my ( $self, $c ) = @_;
|
||||
}
|
||||
|
||||
sub index :Chained('/') :PathPart('security') :Args(0) {
|
||||
my ( $self, $c ) = @_;
|
||||
my $dispatcher = NGCP::Panel::Utils::XMLDispatcher->new;
|
||||
|
||||
my $ip_xml = <<'EOF';
|
||||
<?xml version="1.0" ?>
|
||||
<methodCall>
|
||||
<methodName>htable.dump</methodName>
|
||||
<params>
|
||||
<param><value><string>ipban</string></value></param>
|
||||
</params>
|
||||
</methodCall>
|
||||
EOF
|
||||
|
||||
my $ip_res = $dispatcher->dispatch("loadbalancer", 1, 1, $ip_xml);
|
||||
|
||||
my @ips = ();
|
||||
for my $host (grep {$$_[1]} @$ip_res) {
|
||||
my $xmlDoc = XML::Mini::Document->new();
|
||||
$xmlDoc->parse($host->[2]);
|
||||
my $xmlHash = $xmlDoc->toHash();
|
||||
|
||||
# non empty response
|
||||
if(defined $xmlHash->{methodResponse}->{params}->{param}->{value} and
|
||||
'' ne $xmlHash->{methodResponse}->{params}->{param}->{value} ) {
|
||||
|
||||
# single IP
|
||||
if(ref $xmlHash->{methodResponse}->{params}->{param}->{value}->{struct} eq 'HASH') {
|
||||
push @ips, { ip => $xmlHash->{methodResponse}->{params}->{param}->{value}->{struct}->{member}->[2]->{value}->{struct}->{member}->{value}->{struct}->{member}->[0]->{value}->{string} };
|
||||
}
|
||||
# multiple IPs
|
||||
else {
|
||||
for my $struct ( @{ $xmlHash->{methodResponse}->{params}->{param}->{value}->{struct} } ) {
|
||||
push @ips, { ip => $struct->{member}->[2]->{value}->{struct}->{member}->{value}->{struct}->{member}->[0]->{value}->{string} };
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
my $user_xml = <<'EOF';
|
||||
<?xml version="1.0" ?>
|
||||
<methodCall>
|
||||
<methodName>htable.dump</methodName>
|
||||
<params>
|
||||
<param><value><string>auth</string></value></param>
|
||||
</params>
|
||||
</methodCall>
|
||||
EOF
|
||||
|
||||
my $user_res = $dispatcher->dispatch("loadbalancer", 1, 1, $user_xml);
|
||||
my @users = ();
|
||||
my $usr = {};
|
||||
for my $host (grep {$$_[1]} @$user_res) {
|
||||
my $xmlDoc = XML::Mini::Document->new();
|
||||
$xmlDoc->parse($host->[2]);
|
||||
my $xmlHash = $xmlDoc->toHash();
|
||||
|
||||
# non empty response
|
||||
if(defined $xmlHash->{methodResponse}->{params}->{param}->{value} and
|
||||
'' ne $xmlHash->{methodResponse}->{params}->{param}->{value} ) {
|
||||
|
||||
for my $struct_ar ( @{ $xmlHash->{methodResponse}->{params}->{param}->{value}->{struct} } ) {
|
||||
# possibly buggy behaviour of kamailio to return mutliple entries as one member
|
||||
# (array of hashes) instead of seperate members (hashes)
|
||||
my $member = ref $struct_ar->{member}->[2]->{value}->{struct}->{member} eq 'HASH'
|
||||
? [ $struct_ar->{member}->[2]->{value}->{struct}->{member} ]
|
||||
: $struct_ar->{member}->[2]->{value}->{struct}->{member};
|
||||
|
||||
foreach my $m (@$member) {
|
||||
$m->{value}->{struct}->{member}->[0]->{value}->{string} =~ m/(?<user>.*)::(?<key>.*)/;
|
||||
my $username = $+{user};
|
||||
my $key = $+{key};
|
||||
my $value = $m->{value}->{struct}->{member}->[1]->{value}->{int};
|
||||
|
||||
# there souldn't be any other keys
|
||||
$key eq 'auth_count' and $usr->{$username}->{auth_count} = $value;
|
||||
$key eq 'last_auth' and $usr->{$username}->{last_auth} = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for my $key (keys %{ $usr }) {
|
||||
push @users, {
|
||||
username => $key,
|
||||
auth_count => $usr->{$key}->{auth_count},
|
||||
last_auth => $usr->{$key}->{last_auth},
|
||||
} if($usr->{$key}->{auth_count} >= $c->config->{security}->{failed_auth_attempts});
|
||||
}
|
||||
}
|
||||
|
||||
$c->stash(
|
||||
template => 'security/list.tt',
|
||||
banned_ips => \@ips,
|
||||
banned_users => \@users,
|
||||
);
|
||||
}
|
||||
|
||||
sub ip_base :Chained('/') :PathPart('security/ip') :CaptureArgs(1) {
|
||||
my ( $self, $c, $ip ) = @_;
|
||||
$c->stash->{ip} = $ip;
|
||||
}
|
||||
|
||||
sub ip_unban :Chained('ip_base') :PathPart('unban') :Args(0) {
|
||||
my ( $self, $c ) = @_;
|
||||
my $dispatcher = NGCP::Panel::Utils::XMLDispatcher->new;
|
||||
my $ip = $c->stash->{ip};
|
||||
|
||||
my $xml = <<"EOF";
|
||||
<?xml version="1.0" ?>
|
||||
<methodCall>
|
||||
<methodName>htable.delete</methodName>
|
||||
<params>
|
||||
<param><value><string>ipban</string></value></param>
|
||||
<param><value><string>$ip</string></value></param>
|
||||
</params>
|
||||
</methodCall>
|
||||
EOF
|
||||
|
||||
$dispatcher->dispatch("loadbalancer", 1, 1, $xml);
|
||||
|
||||
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for('/security'));
|
||||
}
|
||||
|
||||
sub user_base :Chained('/') :PathPart('security/user') :CaptureArgs(1) {
|
||||
my ( $self, $c, $user ) = @_;
|
||||
$c->stash->{user} = $user;
|
||||
}
|
||||
|
||||
sub user_unban :Chained('user_base') :PathPart('unban') :Args(0) {
|
||||
my ( $self, $c ) = @_;
|
||||
my $dispatcher = NGCP::Panel::Utils::XMLDispatcher->new;
|
||||
my $user = $c->stash->{user};
|
||||
|
||||
my $xml = <<"EOF";
|
||||
<?xml version="1.0" ?>
|
||||
<methodCall>
|
||||
<methodName>htable.delete</methodName>
|
||||
<params>
|
||||
<param><value><string>auth</string></value></param>
|
||||
<param><value><string>$user</string></value></param>
|
||||
</params>
|
||||
</methodCall>
|
||||
EOF
|
||||
|
||||
$dispatcher->dispatch("loadbalancer", 1, 1, $xml);
|
||||
|
||||
NGCP::Panel::Utils::Navigation::back_or($c, $c->uri_for('/security'));
|
||||
}
|
||||
|
||||
__PACKAGE__->meta->make_immutable;
|
||||
|
||||
1;
|
||||
|
||||
# vim: set tabstop=4 expandtab:
|
||||
@ -0,0 +1,94 @@
|
||||
[% site_config.title = 'Security Bans' -%]
|
||||
|
||||
<div class="row">
|
||||
<span class="pull-left" style="margin:0 5px 0 5px;">
|
||||
<a class="btn btn-primary btn-large" href="[% c.uri_for('/back') %]"><i class="icon-arrow-left"></i> Back</a>
|
||||
</span>
|
||||
</div>
|
||||
[% back_created = 1 -%]
|
||||
|
||||
<div class="row">
|
||||
[% FOREACH m IN messages -%]
|
||||
<div class="alert alert-[% m.type %]">[% m.text %]</div>
|
||||
[% END -%]
|
||||
</div>
|
||||
|
||||
<div class="ngcp-separator"></div>
|
||||
|
||||
<div class="accordion" id="security_data">
|
||||
|
||||
<div class="accordion-group">
|
||||
<div class="accordion-heading">
|
||||
<a class="accordion-toggle" data-toggle="collapse" data-parent="#security_data" href="#collapse_ips">Banned IPs</a>
|
||||
</div>
|
||||
<div class="accordion-body collapse" id="collapse_ips">
|
||||
<div class="accordion-inner">
|
||||
|
||||
<table class="table table-bordered table-striped table-highlight table-hover" id="subscribers_table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>IP</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
[% FOR ip IN banned_ips -%]
|
||||
<tr class="sw_action_row">
|
||||
<td>[% ip.ip %]</td>
|
||||
<td class="ngcp-actions-column">
|
||||
<div class="sw_actions pull-right">
|
||||
<a class="btn btn-small btn-primary"
|
||||
href="[% c.uri_for_action("/security/ip_unban", [ip.ip]) %]">
|
||||
<i class="icon-remove"></i> Unban
|
||||
</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
[% END -%]
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="accordion-group">
|
||||
<div class="accordion-heading">
|
||||
<a class="accordion-toggle" data-toggle="collapse" data-parent="#security_data" href="#collapse_users">Banned Users</a>
|
||||
</div>
|
||||
<div class="accordion-body collapse" id="collapse_users">
|
||||
<div class="accordion-inner">
|
||||
|
||||
<table class="table table-bordered table-striped table-highlight table-hover" id="subscribers_table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>User</th>
|
||||
<th>Fail Count</th>
|
||||
<th>Last Attempt</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
[% FOR user IN banned_users -%]
|
||||
<tr class="sw_action_row">
|
||||
<td>[% user.username %]</td>
|
||||
<td>[% user.auth_count %]</td>
|
||||
<td>[% user.last_auth %]</td>
|
||||
<td class="ngcp-actions-column">
|
||||
<div class="sw_actions pull-right">
|
||||
<a class="btn btn-small btn-primary"
|
||||
href="[% c.uri_for_action("/security/user_unban", [ip.ip]) %]">
|
||||
<i class="icon-remove"></i> Unban
|
||||
</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
[% END -%]
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
[% # vim: set tabstop=4 syntax=html expandtab: -%]
|
||||
Loading…
Reference in new issue