* the endpoint will receive "type" (expires|onetime)
and "expires" (positive integer representing seconds)
* type will define the expiray method for the token;
onetime: the token expires as soon as it's used, or
after "expires" seconds if not used
expires: the token can be used multiple times until
it expires according to the "expires" param value
* login_jwt endpoint for generating the JWT token for
subscribers has been enhanced to accept the "token"
param, containing the token generated using the
/api/authtokens endpoint
* admin_login_jwt endpoint for generating the JWT token
for admins has been enhanced to accept the "token"
param, containing the token generated using the
/api/authtokens endpoint
* login_jwt and amin_login_jwt will respond with 403
"Forbidden" if the token role stored in Redis does
not match the role of the user that generated it
* /api/authtokens is hidden from documentation for now
Change-Id: I4eb76c2b08f2e24774fa84ba0ccf7412ce8670e8
(cherry picked from commit 9b422ddabf
)
mr9.5.4
parent
944823b780
commit
db8f0feff6
@ -0,0 +1,74 @@
|
|||||||
|
package NGCP::Panel::Controller::API::AuthTokens;
|
||||||
|
|
||||||
|
use Sipwise::Base;
|
||||||
|
|
||||||
|
use Data::HAL qw();
|
||||||
|
use Data::HAL::Link qw();
|
||||||
|
use File::Basename;
|
||||||
|
use File::Find::Rule;
|
||||||
|
use HTTP::Headers qw();
|
||||||
|
use HTTP::Status qw(:constants);
|
||||||
|
|
||||||
|
|
||||||
|
sub allowed_methods{
|
||||||
|
return [qw/POST OPTIONS/];
|
||||||
|
}
|
||||||
|
|
||||||
|
use parent qw/NGCP::Panel::Role::Entities NGCP::Panel::Role::API::AuthTokens/;
|
||||||
|
|
||||||
|
sub api_description {
|
||||||
|
return '';
|
||||||
|
};
|
||||||
|
|
||||||
|
sub query_params {
|
||||||
|
return [
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
sub resource_name{
|
||||||
|
return 'authtokens';
|
||||||
|
}
|
||||||
|
|
||||||
|
sub dispatch_path{
|
||||||
|
return '/api/authtokens/';
|
||||||
|
}
|
||||||
|
|
||||||
|
sub relation{
|
||||||
|
return 'http://purl.org/sipwise/ngcp-api/#rel-authtokens';
|
||||||
|
}
|
||||||
|
|
||||||
|
__PACKAGE__->set_config({
|
||||||
|
allowed_roles => [qw/admin reseller ccare ccareadmin subscriber subscriberadmin/],
|
||||||
|
});
|
||||||
|
|
||||||
|
sub POST :Allow {
|
||||||
|
my ($self, $c) = @_;
|
||||||
|
|
||||||
|
my $resource = $self->get_valid_post_data(
|
||||||
|
c => $c,
|
||||||
|
media_type => 'application/json',
|
||||||
|
);
|
||||||
|
return unless $resource;
|
||||||
|
|
||||||
|
my $form = $self->get_form($c);
|
||||||
|
return unless $self->validate_form(
|
||||||
|
c => $c,
|
||||||
|
resource => $resource,
|
||||||
|
form => $form,
|
||||||
|
);
|
||||||
|
if($c->user->roles eq "reseller") {
|
||||||
|
$resource->{reseller_id} = $c->user->reseller_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
my $res = {};
|
||||||
|
|
||||||
|
$res->{token} = $self->generate_auth_token($c, $resource);
|
||||||
|
|
||||||
|
$c->response->status(HTTP_CREATED);
|
||||||
|
$c->response->body(JSON::to_json($res));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
||||||
|
|
||||||
|
# vim: set tabstop=4 expandtab:
|
@ -0,0 +1,29 @@
|
|||||||
|
package NGCP::Panel::Form::AuthToken;
|
||||||
|
|
||||||
|
use HTML::FormHandler::Moose;
|
||||||
|
use NGCP::Panel::Utils::Form;
|
||||||
|
extends 'HTML::FormHandler';
|
||||||
|
|
||||||
|
has_field 'type' => (
|
||||||
|
type => 'Select',
|
||||||
|
options => [
|
||||||
|
{ label => 'Onetime', value => 'onetime' },
|
||||||
|
{ label => 'Expires', value => 'expires' },
|
||||||
|
],
|
||||||
|
label => 'Type',
|
||||||
|
required => 1,
|
||||||
|
);
|
||||||
|
|
||||||
|
has_field 'expires' => (
|
||||||
|
type => '+NGCP::Panel::Field::PosInteger',
|
||||||
|
required => 1,
|
||||||
|
label => 'Expires',
|
||||||
|
);
|
||||||
|
|
||||||
|
has_block 'fields' => (
|
||||||
|
tag => 'div',
|
||||||
|
class => [qw/modal-body/],
|
||||||
|
render_list => [qw/type expires/],
|
||||||
|
);
|
||||||
|
|
||||||
|
1;
|
@ -0,0 +1,35 @@
|
|||||||
|
package NGCP::Panel::Role::API::AuthTokens;
|
||||||
|
|
||||||
|
use Sipwise::Base;
|
||||||
|
use NGCP::Panel::Utils::Redis;
|
||||||
|
|
||||||
|
use parent 'NGCP::Panel::Role::API';
|
||||||
|
|
||||||
|
use Redis;
|
||||||
|
use UUID;
|
||||||
|
|
||||||
|
sub get_form {
|
||||||
|
my ($self, $c) = @_;
|
||||||
|
return NGCP::Panel::Form::get("NGCP::Panel::Form::AuthToken", $c);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub generate_auth_token {
|
||||||
|
my ($self, $c, $resource) = @_;
|
||||||
|
|
||||||
|
my ($uuid_bin, $uuid_string);
|
||||||
|
UUID::generate($uuid_bin);
|
||||||
|
UUID::unparse($uuid_bin, $uuid_string);
|
||||||
|
#remove '-' from the token
|
||||||
|
$uuid_string =~ s/\-//g;
|
||||||
|
my $redis = NGCP::Panel::Utils::Redis::get_redis_connection($c, {database => $c->config->{'Plugin::Session'}->{redis_db}});
|
||||||
|
return unless $redis;
|
||||||
|
$redis->hset("auth_token:$uuid_string", 'type', $resource->{type});
|
||||||
|
$redis->hset("auth_token:$uuid_string", 'role', $c->user->roles);
|
||||||
|
$redis->hset("auth_token:$uuid_string", 'user_id', $c->user->id);
|
||||||
|
$redis->expire("auth_token:$uuid_string", $resource->{expires});
|
||||||
|
|
||||||
|
return $uuid_string;
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
||||||
|
# vim: set tabstop=4 expandtab:
|
@ -0,0 +1,23 @@
|
|||||||
|
package NGCP::Panel::Utils::Redis;
|
||||||
|
|
||||||
|
use warnings;
|
||||||
|
use strict;
|
||||||
|
|
||||||
|
use Redis;
|
||||||
|
|
||||||
|
sub get_redis_connection {
|
||||||
|
my ($c, $params) = @_;
|
||||||
|
my $redis = Redis->new(
|
||||||
|
server => $c->config->{redis}->{central_url},
|
||||||
|
reconnect => 10, every => 500000, # 500ms
|
||||||
|
cnx_timeout => 3,
|
||||||
|
);
|
||||||
|
unless ($redis) {
|
||||||
|
$c->log->error("Failed to connect to central redis url " . $c->config->{redis}->{central_url});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$redis->select($params->{database});
|
||||||
|
return $redis;
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
Loading…
Reference in new issue