TT#149461 Enhance /api/admins to accept the role data property

- Optional "role" parameter is added for POST PUT PATCH.
If "role" is provided then the passed flags are ignored and are applied internally by the server according to the provided role.
If "role" is not provided then the former flags based approach is applied.

Change-Id: Ib6e591ff6dc50122e0ec49a348153ca820fc2e03
mr10.3
Oleksandr Duts 4 years ago
parent aac3a16e5e
commit 9855b6ab45

@ -37,6 +37,7 @@ sub query_params {
sub create_item {
my ($self, $c, $resource, $form, $process_extras) = @_;
if ($c->user->roles eq 'lintercept') {
$self->error($c, HTTP_FORBIDDEN, "Cannot create admin users");
return;
@ -45,18 +46,39 @@ sub create_item {
$self->error($c, HTTP_FORBIDDEN, "Cannot create admin without master permissions");
return;
}
$resource = NGCP::Panel::Utils::UserRole::resolve_resource_role($c, $resource);
my $item;
try {
$resource->{role_id} = NGCP::Panel::Utils::UserRole::resolve_role_id($c, $resource);
$item = $c->model('DB')->resultset('admins')->create($resource);
} catch($e) {
$c->log->error("failed to create admin: $e");
$self->error($c, HTTP_INTERNAL_SERVER_ERROR, "Failed to create admin.");
return;
}
return $item;
}
sub resource_from_item{
my($self, $c, $item) = @_;
my $res;
if ('HASH' eq ref $item) {
$res = $item;
} else {
$res = { $item->get_inflated_columns };
}
my $role_id = delete $res->{role_id};
if ($role_id) {
$res->{role} = NGCP::Panel::Utils::UserRole::find_row_by_id($c, $role_id)->role;
}
return $res;
}
1;
# vim: set tabstop=4 expandtab:

@ -51,6 +51,10 @@ sub PATCH :Allow {
#we later check in update_item and if the password field is still
#the same with saltedpass we don't update the password
$old_resource->{password} = $old_resource->{salted_pass};
# This trick allows to call apply_patch below without "role" reference error.
$old_resource->{role} = undef;
my $resource = $self->apply_patch($c, $old_resource, $json);
last unless $resource;
@ -97,6 +101,24 @@ sub delete_item {
return 1;
}
sub resource_from_item{
my($self, $c, $item) = @_;
my $res;
if ('HASH' eq ref $item) {
$res = $item;
} else {
$res = { $item->get_inflated_columns };
}
my $role_id = delete $res->{role_id};
if ($role_id) {
$res->{role} = NGCP::Panel::Utils::UserRole::find_row_by_id($c, $role_id)->role;
}
return $res;
}
1;
# vim: set tabstop=4 expandtab:

@ -0,0 +1,29 @@
package NGCP::Panel::Form::Administrator::AdminAPI;
use HTML::FormHandler::Moose;
extends 'NGCP::Panel::Form::Administrator::Admin';
use Storable qw();
has_field 'role' => (
type => 'Text'
);
sub validate {
my $self = shift;
my $c = $self->ctx;
return unless $c;
my $resource = Storable::dclone($self->values);
if (defined $resource->{role} && ! ref $resource->{role}) {
if (!defined NGCP::Panel::Utils::UserRole::name_to_flags($resource->{role})) {
my $err = 'Unknown role: ' . $resource->{role};
$c->log->error($err);
$self->field('role')->add_error($err);
}
}
}
1;

@ -0,0 +1,29 @@
package NGCP::Panel::Form::Administrator::LInterceptAPI;
use HTML::FormHandler::Moose;
extends 'NGCP::Panel::Form::Administrator::LIntercept';
use Storable qw();
has_field 'role' => (
type => 'Text'
);
sub validate {
my $self = shift;
my $c = $self->ctx;
return unless $c;
my $resource = Storable::dclone($self->values);
if (defined $resource->{role} && ! ref $resource->{role}) {
if (!defined NGCP::Panel::Utils::UserRole::name_to_flags($resource->{role})) {
my $err = 'Unknown role: ' . $resource->{role};
$c->log->error($err);
$self->field('role')->add_error($err);
}
}
}
1;

@ -0,0 +1,29 @@
package NGCP::Panel::Form::Administrator::ResellerAPI;
use HTML::FormHandler::Moose;
extends 'NGCP::Panel::Form::Administrator::Reseller';
use Storable qw();
has_field 'role' => (
type => 'Text'
);
sub validate {
my $self = shift;
my $c = $self->ctx;
return unless $c;
my $resource = Storable::dclone($self->values);
if (defined $resource->{role} && ! ref $resource->{role}) {
if (!defined NGCP::Panel::Utils::UserRole::name_to_flags($resource->{role})) {
my $err = 'Unknown role: ' . $resource->{role};
$c->log->error($err);
$self->field('role')->add_error($err);
}
}
}
1;

@ -0,0 +1,31 @@
package NGCP::Panel::Form::Administrator::SystemAPI;
use HTML::FormHandler::Moose;
extends 'NGCP::Panel::Form::Administrator::System';
use Storable qw();
has_field 'role' => (
type => 'Text'
);
sub validate {
my $self = shift;
$self->SUPER::validate(@_);
my $c = $self->ctx;
return unless $c;
my $resource = Storable::dclone($self->values);
if (defined $resource->{role} && ! ref $resource->{role}) {
if (!defined NGCP::Panel::Utils::UserRole::name_to_flags($resource->{role})) {
my $err = 'Unknown role: ' . $resource->{role};
$c->log->error($err);
$self->field('role')->add_error($err);
}
}
}
1;

@ -63,13 +63,13 @@ sub get_form {
my ($self, $c) = @_;
my $form;
if ($c->user->is_system) {
$form = NGCP::Panel::Form::get("NGCP::Panel::Form::Administrator::System", $c);
$form = NGCP::Panel::Form::get("NGCP::Panel::Form::Administrator::SystemAPI", $c);
} elsif ($c->user->roles eq "lintercept") {
$form = NGCP::Panel::Form::get("NGCP::Panel::Form::Administrator::LIntercept", $c);
$form = NGCP::Panel::Form::get("NGCP::Panel::Form::Administrator::LInterceptAPI", $c);
} elsif ($c->user->roles eq "admin") {
$form = NGCP::Panel::Form::get("NGCP::Panel::Form::Administrator::Admin", $c);
$form = NGCP::Panel::Form::get("NGCP::Panel::Form::Administrator::AdminAPI", $c);
} else {
$form = NGCP::Panel::Form::get("NGCP::Panel::Form::Administrator::Reseller", $c);
$form = NGCP::Panel::Form::get("NGCP::Panel::Form::Administrator::ResellerAPI", $c);
}
return $form;
}
@ -168,7 +168,7 @@ sub update_item {
$resource->{is_active} = $active;
}
$resource->{role_id} = NGCP::Panel::Utils::UserRole::resolve_role_id($c, $resource);
$resource = NGCP::Panel::Utils::UserRole::resolve_resource_role($c, $resource);
$item->update($resource);

@ -44,7 +44,7 @@ sub _flags_to_name {
return 'reseller';
}
sub _name_to_flags {
sub name_to_flags {
my $name = shift;
my @flag_names = qw/ is_system is_superuser is_ccare lawful_intercept /;
@ -59,14 +59,14 @@ sub _name_to_flags {
return $map{$name} ?
( map { $flag_names[$_] => $map{$name}->[$_] } 0..$#flag_names ) :
undef;
();
}
sub resolve_role_id {
my ($c, $params) = @_;
my $role_name = _flags_to_name($params) // return;
my $role = $c->model('DB')->resultset('acl_roles')->find({role => $role_name});
my $role = &find_row_by_name($c, $role_name);
return $role ? $role->id : undef;
}
@ -77,7 +77,33 @@ sub resolve_flags {
my $role_name = $c->model('DB')->resultset('acl_roles')->search({id => $role_id})->first->role
|| return ();
return &_name_to_flags($role_name);
return &name_to_flags($role_name);
}
sub find_row_by_name {
my ($c, $name) = @_;
return $c->model('DB')->resultset('acl_roles')->find({role => $name});
}
sub find_row_by_id {
my ($c, $id) = @_;
return $c->model('DB')->resultset('acl_roles')->find($id);
}
sub resolve_resource_role {
my ($c, $resource) = @_;
my $role_name = delete $resource->{role};
if ($role_name) {
$resource = { %$resource, &name_to_flags($role_name) };
$resource->{role_id} = &find_row_by_name($c, $role_name)->id;
} else {
$resource->{role_id} = &resolve_role_id($c, $resource);
}
return $resource;
}
1;

@ -0,0 +1,228 @@
---
-
name: check OPTIONS for admins
type: item
method: OPTIONS
path: /api/admins/
conditions:
is:
code: 200
header:
Accept-Post: application/hal+json; profile=http://purl.org/sipwise/ngcp-api/#rel-admins
ok:
options:
- GET
- POST
- OPTIONS
- HEAD
-
name: create admin - role admin
type: item
thread: 1
method: POST
path: /api/admins/
header:
Content-Type: application/json
Prefer: return=representation
content:
login: test_login_${unique_id}
password: password
role: admin
reseller_id: 1
conditions:
is:
code: 201
retain:
admin_path: header.location
admin_id: header.location
-
name: get admin - role admin
type: item
method: GET
path: '/${admin_path}'
retain:
admin: body
conditions:
is:
code: 200
'${admin}.is_system': 0
'${admin}.is_superuser': 1
'${admin}.is_ccare': 0
'${admin}.lawful_intercept': 0
'${admin}.role': admin
ok:
'${admin}.login': defined
'${admin}.role_id': undefined
-
name: put admin - to role system
type: item
thread: 1
method: PUT
path: '/${admin_path}'
header:
Content-Type: application/json
Prefer: return=representation
content:
login: test_login_${unique_id}
role: system
reseller_id: 1
retain:
admin: body
conditions:
is:
code: 200
'${admin}.is_system': 1
'${admin}.is_superuser': 0
'${admin}.is_ccare': 0
'${admin}.lawful_intercept': 0
-
name: put admin - to role ccareadmin
type: item
thread: 1
method: PUT
path: '/${admin_path}'
header:
Content-Type: application/json
Prefer: return=representation
content:
login: test_login_${unique_id}
role: ccareadmin
reseller_id: 1
retain:
admin: body
conditions:
is:
code: 200
'${admin}.is_system': 0
'${admin}.is_superuser': 1
'${admin}.is_ccare': 1
'${admin}.lawful_intercept': 0
-
name: put admin - to role ccare
type: item
thread: 1
method: PUT
path: '/${admin_path}'
header:
Content-Type: application/json
Prefer: return=representation
content:
login: test_login_${unique_id}
role: ccare
reseller_id: 1
retain:
admin: body
conditions:
is:
code: 200
'${admin}.is_system': 0
'${admin}.is_superuser': 0
'${admin}.is_ccare': 1
'${admin}.lawful_intercept': 0
-
name: put admin - to role lintercept
type: item
thread: 1
method: PUT
path: '/${admin_path}'
header:
Content-Type: application/json
Prefer: return=representation
content:
login: test_login_${unique_id}
role: lintercept
reseller_id: 1
retain:
admin: body
conditions:
is:
code: 200
'${admin}.is_system': 0
'${admin}.is_superuser': 0
'${admin}.is_ccare': 0
'${admin}.lawful_intercept': 1
-
name: put admin - to role reseller
type: item
thread: 1
method: PUT
path: '/${admin_path}'
header:
Content-Type: application/json
Prefer: return=representation
content:
login: test_login_${unique_id}
role: reseller
reseller_id: 1
retain:
admin: body
conditions:
is:
code: 200
'${admin}.is_system': 0
'${admin}.is_superuser': 0
'${admin}.is_ccare': 0
'${admin}.lawful_intercept': 0
-
name: put admin - no role, is_system flag
type: item
thread: 1
method: PUT
path: '/${admin_path}'
header:
Content-Type: application/json
Prefer: return=representation
content:
login: test_login_${unique_id}
reseller_id: 1
is_system: 1
retain:
admin: body
conditions:
is:
code: 200
'${admin}.is_system': 1
'${admin}.is_superuser': 0
'${admin}.is_ccare': 0
'${admin}.lawful_intercept': 0
-
name: patch admin - to role admin
type: item
method: PATCH
path: '/${admin_path}'
header:
Content-Type: application/json-patch+json
Prefer: return=representation
content:
-
op: replace
path: /role
value: admin
retain:
admin: body
conditions:
is:
code: 200
'${admin}.is_system': 0
'${admin}.is_superuser': 1
'${admin}.is_ccare': 0
'${admin}.lawful_intercept': 0
-
name: delete admin
type: item
method: DELETE
path: '/${admin_path}'
conditions:
is:
code: 204
Loading…
Cancel
Save