TT#43351 Check subscriberadmin access to profile and profile_set

Unify UI and API code to make subscriberadmin behavior with profile_set and profile common
Change alias_numbers input field to embedded RepeatableJS so it pass form validation

Change-Id: I1b3dc6f88cc6c1f43d76acc8e339dbb664c166a3
changes/54/23354/7
Irina Peshinskaya 7 years ago
parent 42730fb359
commit b1e4733d00

@ -353,6 +353,7 @@ sub POST :Allow {
my $groups = $r->{groups};
my $groupmembers = $r->{groupmembers};
$resource = $r->{resource};
my $error_info = { extended => {} };
try {
my ($uuid_bin, $uuid_string);
@ -362,13 +363,14 @@ sub POST :Allow {
my @events_to_create = ();
my $event_context = { events_to_create => \@events_to_create };
$subscriber = NGCP::Panel::Utils::Subscriber::create_subscriber(
c => $c,
schema => $schema,
contract => $r->{customer},
params => $resource,
preferences => $preferences,
c => $c,
schema => $schema,
contract => $r->{customer},
params => $resource,
preferences => $preferences,
admin_default => 0,
event_context => $event_context,
error => $error_info,
);
if($resource->{status} eq 'locked') {
NGCP::Panel::Utils::Subscriber::lock_provisoning_voip_subscriber(
@ -405,9 +407,15 @@ sub POST :Allow {
$self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Number '$1' already exists.");
last;
} catch($e) {
$c->log->error("failed to create subscriber: $e"); # TODO: user, message, trace, ...
$self->error($c, HTTP_INTERNAL_SERVER_ERROR, "Failed to create subscriber: $e");
last;
if (ref $error_info->{extended} eq 'HASH' && $error_info->{extended}->{response_code}) {
$c->log->error($error_info->{extended}->{error}); # TODO: user, message, trace, ...
$self->error($c, $error_info->{extended}->{response_code}, $error_info->{extended}->{description});
last;
} else {
$c->log->error("failed to create subscriber: $e"); # TODO: user, message, trace, ...
$self->error($c, HTTP_INTERNAL_SERVER_ERROR, "Failed to create subscriber: $e");
last;
}
}
last unless $self->add_create_journal_item_hal($c,sub {

@ -2834,42 +2834,16 @@ sub edit_master :Chained('master') :PathPart('edit') :Args(0) :Does(ACL) :ACLDet
}
);
my $old_profile = $prov_subscriber->profile_id;
my ($profile_set, $profile);
if($form->values->{profile_set}{id}) {
my $profile_set_rs = $c->model('DB')->resultset('voip_subscriber_profile_sets');
if($c->user->roles eq "admin") {
} elsif($c->user->roles eq "reseller") {
$profile_set_rs = $profile_set_rs->search({
reseller_id => $c->user->reseller_id,
});
}
$profile_set = $profile_set_rs->find($form->values->{profile_set}{id});
unless($profile_set) {
NGCP::Panel::Utils::Message::error(
c => $c,
error => 'invalid subscriber profile set id ' . $form->values->{profile_set}{id},
desc => $c->loc('Invalid subscriber profile set id'),
);
return;
}
delete $form->values->{profile_set};
} elsif(exists $form->params->{profile_set}{id}) {
# if the param has been passed and is empty, clear it (by doing nothing)
} else {
$profile_set = $prov_subscriber->voip_subscriber_profile_set;
}
if($profile_set && $form->values->{profile}{id}) {
$profile = $profile_set->voip_subscriber_profiles->find({
id => $form->values->{profile}{id},
});
}
if($profile_set && !$profile) {
$profile = $profile_set->voip_subscriber_profiles->find({
set_default => 1,
});
#$old_profile_id is necessary for events
my $old_profile_id = $prov_subscriber->profile_id;
my($error,$profile_set,$profile) = NGCP::Panel::Utils::Subscriber::check_profile_set_and_profile($c, $form->values, $subscriber);
if ($error) {
NGCP::Panel::Utils::Message::error(
c => $c,
error => $error->{error},
desc => $error->{description}
);
return;
}
if($c->user->roles eq "admin" || $c->user->roles eq "reseller") {
$prov_params->{profile_set_id} = $profile_set ? $profile_set->id : undef;
@ -2882,30 +2856,6 @@ sub edit_master :Chained('master') :PathPart('edit') :Args(0) :Does(ACL) :ACLDet
}
}
# if the profile changed, clear any preferences which are not in the new profile
if($prov_subscriber->voip_subscriber_profile) {
my %old_profile_attributes = map { $_ => 1 }
$prov_subscriber->voip_subscriber_profile
->profile_attributes->get_column('attribute_id')->all;
if($profile) {
foreach my $attr_id($profile->profile_attributes->get_column('attribute_id')->all) {
delete $old_profile_attributes{$attr_id};
}
}
if(keys %old_profile_attributes) {
my $cfs = $c->model('DB')->resultset('voip_preferences')->search({
id => { -in => [ keys %old_profile_attributes ] },
attribute => { -in => [qw/cfu cfb cft cfna cfs cfr/] },
});
$prov_subscriber->voip_usr_preferences->search({
attribute_id => { -in => [ keys %old_profile_attributes ] },
})->delete;
$prov_subscriber->voip_cf_mappings->search({
type => { -in => [ map { $_->attribute } $cfs->all ] },
})->delete;
}
}
$prov_subscriber->update($prov_params);
my $new_group_ids = defined $form->value->{group_select} ?
@ -3064,7 +3014,7 @@ sub edit_master :Chained('master') :PathPart('edit') :Args(0) :Does(ACL) :ACLDet
NGCP::Panel::Utils::Events::insert_profile_events(
c => $c, schema => $schema, subscriber_id => $subscriber->id,
old => $old_profile, new => $prov_subscriber->profile_id,
old => $old_profile_id, new => $prov_subscriber->profile_id,
%$aliases_before,
);

@ -143,6 +143,15 @@ has_field 'customer_id' => (
},
);
has_field 'profile' => (
type => '+NGCP::Panel::Field::SubscriberProfile',
label => 'Subscriber Profile',
validate_when_empty => 0,
element_attr => {
rel => ['tooltip'],
title => ['The profile defining the actual feature set for this subscriber.'],
},
);
has_field 'display_name' => (
type => 'Text',

@ -410,11 +410,12 @@ sub prepare_resource {
$c->log->error("failed to create subscriber, contract_id " . $customer->id . " already has pbx pilot subscriber");
$self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Customer already has a pbx pilot subscriber.");
return;
}
elsif(!$pilot && !is_true($resource->{is_pbx_pilot})) {
} elsif (!$pilot && !is_true($resource->{is_pbx_pilot})) {
$c->log->error("failed to create subscriber, contract_id " . $customer->id . " has no pbx pilot subscriber and is_pbx_pilot is set");
$self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Customer has no pbx pilot subscriber yet and is_pbx_pilot is not set.");
return;
} else {
$c->stash->{pilot} = $pilot;
}
}
@ -645,68 +646,11 @@ sub update_item {
return;
};
my ($profile_set, $profile);
#as we don't allow to change customer (l. 624), so we shouldn't allow profile_set that belongs to other reseller
my $profile_set_rs = $schema->resultset('voip_subscriber_profile_sets')->search({
reseller_id => $subscriber->contract->contact->reseller_id,
});
if($c->user->roles eq "admin") {
} elsif($c->user->roles eq "reseller") {
$profile_set_rs = $profile_set_rs->search({
reseller_id => $c->user->reseller_id,
});
} elsif($c->user->roles eq "subscriberadmin") {
$profile_set_rs = $profile_set_rs->search({
reseller_id => $c->user->contract->contact->reseller_id,
});
}
if ($resource->{profile_set}{id}) {
$profile_set = $profile_set_rs->find($resource->{profile_set}{id});
unless($profile_set) {
$c->log->error("invalid subscriber profile set id '" . $resource->{profile_set}{id} . "'");
$self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Invalid profile_set_id parameter");
return;
}
}
if($resource->{profile}{id}) {
$profile = $profile_set_rs->search_related_rs('voip_subscriber_profiles')->find({
id => $resource->{profile}{id},
});
if (!$profile) {
$c->log->error("invalid subscriber profile id '" . $resource->{profile}{id} . "'");
$self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Invalid profile_id parameter");
return;
}
}
if($profile_set && !$profile) {
$profile = $profile_set->voip_subscriber_profiles->find({
set_default => 1,
});
}
# if the profile changed, clear any preferences which are not in the new profile
if($prov_subscriber->voip_subscriber_profile) {
my %old_profile_attributes = map { $_ => 1 }
$prov_subscriber->voip_subscriber_profile
->profile_attributes->get_column('attribute_id')->all;
if($profile) {
foreach my $attr_id($profile->profile_attributes->get_column('attribute_id')->all) {
delete $old_profile_attributes{$attr_id};
}
}
if(keys %old_profile_attributes) {
my $cfs = $schema->resultset('voip_preferences')->search({
id => { -in => [ keys %old_profile_attributes ] },
attribute => { -in => [qw/cfu cfb cft cfna cfs cfr/] },
});
$prov_subscriber->voip_usr_preferences->search({
attribute_id => { -in => [ keys %old_profile_attributes ] },
})->delete;
$prov_subscriber->voip_cf_mappings->search({
type => { -in => [ map { $_->attribute } $cfs->all ] },
})->delete;
}
my ($error,$profile_set,$profile) = NGCP::Panel::Utils::Subscriber::check_profile_set_and_profile($c, $resource, $subscriber);
if ($error) {
$c->log->error($error->{error});
$self->error($c, $error->{response_code}, $error->{description});
return;
}
if($resource->{email} || $resource->{timezone}) {

@ -18,6 +18,7 @@ use NGCP::Panel::Utils::Generic;
use NGCP::Panel::Utils::RedisLocationResultSet;
use UUID qw/generate unparse/;
use JSON qw/decode_json encode_json/;
use HTTP::Status qw(:constants);
use IPC::System::Simple qw/capturex/;
use File::Slurp qw/read_file/;
use Redis;
@ -229,38 +230,10 @@ sub create_subscriber {
}
}
my ($profile_set, $profile);
#as we don't allow to change customer (l. 624), so we shouldn't allow profile_set that belongs to other reseller
my $profile_set_rs = $schema->resultset('voip_subscriber_profile_sets');
if($c->user->roles eq "admin") {
} elsif($c->user->roles eq "reseller") {
$profile_set_rs = $profile_set_rs->search({
reseller_id => $c->user->reseller_id,
});
} elsif($c->user->roles eq "subscriberadmin") {
$profile_set_rs = $profile_set_rs->search({
reseller_id => $c->user->contract->contact->reseller_id,
});
}
if ($params->{profile_set}{id}) {
$profile_set = $profile_set_rs->find($params->{profile_set}{id});
unless($profile_set) {
die("invalid subscriber profile set id '".$params->{profile_set}{id}."' detected");
}
}
if($params->{profile}{id}) {
$profile = $profile_set_rs->search_related_rs('voip_subscriber_profiles')->find({
id => $params->{profile}{id},
});
if (!$profile) {
die("invalid subscriber profile id '".$params->{profile}{id}."' detected");
}
}
if($profile_set && !$profile) {
$profile = $profile_set->voip_subscriber_profiles->find({
set_default => 1,
});
my($error,$profile_set,$profile) = check_profile_set_and_profile($c, $params);
if ($error) {
$params{error}->{extended} = $error if ref $params{error} eq 'HASH';
die($error->{error});
}
$params->{timezone} = $params->{timezone}->{name} if 'HASH' eq ref $params->{timezone};
@ -483,6 +456,159 @@ sub create_subscriber {
});
}
sub check_profile_set_and_profile {
my ($c, $resource, $subscriber) = @_;
my ($profile_set, $profile, $profile_set_rs);
my $schema = $c->model('DB');
my $prov_subscriber;
if ($subscriber) { #edit
$prov_subscriber = $subscriber->provisioning_voip_subscriber;
#as we don't allow to change customer (l. 624), so we shouldn't allow profile_set that belongs to other reseller
#this restriction also is related to admin, so we don't allow to make data uncoordinated
$profile_set_rs = $schema->resultset('voip_subscriber_profile_sets')->search({
'me.reseller_id' => $subscriber->contract->contact->reseller_id,
});
} else {
$profile_set_rs = $schema->resultset('voip_subscriber_profile_sets');
}
if($c->user->roles eq "admin") {
#we allow to admins (both superadmin and reseller admin roles)
#to pick any profile_set, even not linked to pilot.
#it may lead to situation when subscriberadmin will not see profile options, as profile ajax call is based on pilot profile_set setting
#this was old behavior and I left untouched this administrator privilege
} elsif($c->user->roles eq "reseller") {
$profile_set_rs = $profile_set_rs->search({
'me.reseller_id' => $c->user->reseller_id,
});
} elsif($c->user->roles eq "subscriberadmin") {
if ($c->stash->{pilot} && $c->stash->{pilot}->provisioning_voip_subscriber->profile_set_id) {
#$c->user->voip_subscriber->provisioning_voip_subscriber->profile_set_id
#this is new condition, as now we allow subscriberadmin to edit subscribers using API
#(and previousely we allowed to add)
#and subscriberadmin should operate in boundaries of his own profile_set
$profile_set_rs = $profile_set_rs->search({
'me.id' => $c->stash->{pilot}->provisioning_voip_subscriber->profile_set_id
});
} else {
#subscriberadmin is not supposed to add a pilot,
#pilot will be created first by force, if not exists
#but this situation still is possible if pilot doesn't have profile_set setting
#then we will check at least reseller
$profile_set_rs = $profile_set_rs->search({
'me.reseller_id' => $c->user->contract->contact->reseller_id
});
}
}
if (defined $resource->{profile_set}{id} && $resource->{profile_set}{id}) {
$profile_set = $profile_set_rs->find($resource->{profile_set}{id});
unless($profile_set) {
return {
error => "invalid subscriber profile set id '" . $resource->{profile_set}{id} . "'",
description => "Invalid profile_set_id parameter",
response_code => HTTP_UNPROCESSABLE_ENTITY,
};
}
} elsif (!exists $resource->{profile_set}{id}) {
if ($c->user->roles eq "subscriberadmin") { #we are in subscriberadmin web UI
#this is for subscriberadmin web ui to edit subscriber.
#Edit subscriber form for subscriberadmin doesn't contain profile_set control
#API form doesn't suppose profile_set field.
# => subscriberadmin can't manage profile_set via web ui and API
#here we will provide profile_set so below we can check profile id
#please note, that we don't allow to subscriberadmin unset profile_set_id and profile_set at all, . Later we will take default profile for profile_set
if ($c->stash->{pilot} && $c->stash->{pilot}->provisioning_voip_subscriber->voip_subscriber_profile_set) {
$profile_set = $c->stash->{pilot}->provisioning_voip_subscriber->voip_subscriber_profile_set;
} elsif ($prov_subscriber && $resource->{profile}{id}) { #edit
#not pbx account or pilot doesn't have any profile set
$profile_set = $prov_subscriber->voip_subscriber_profile_set;
}
}
}
if ($profile_set) {
#inverted condition to don't repeate taking default for empty input and input mismatch in web admin ui
if ($resource->{profile}{id}) {
$profile = $profile_set->voip_subscriber_profiles->find({
id => $resource->{profile}{id},
});
}
if (!$profile
&& (
#we force default profile instead of empty for all roles those can't unset profile_set
(!$resource->{profile}{id})
#to admin roles we forgive incorrect profile_id (no error)
#this is due web ui, when not dynamic profile field can't reflect profile_set change
#and user need to edit twice to 1) change profile_set + incorrect profile_id) and 2) select not-default profile
|| ($c->user->roles eq "admin" || $c->user->roles eq "reseller")
)
) {
$profile = $profile_set->voip_subscriber_profiles->find({
set_default => 1,
});
}
} elsif ($resource->{profile}{id}) {#so - user requested profile, but we didn't find proper profile_set
return {
error => "empty subscriber profile_set id for profile id '" . $resource->{profile}{id} . "'",
description => "Empty profile_set_id parameter",
response_code => HTTP_UNPROCESSABLE_ENTITY,
};
}
if (!$profile && (
$profile_set
|| ( $c->user->roles eq "subscriberadmin"
&& $resource->{profile}{id} )
)
) {
#it does not matter how we get here - it is incorrect.
#subscriberadmin can get there if he will try to set profile not from pilot or existing profile_set
if ($resource->{profile}{id}) {
return {
error => "invalid subscriber profile id '" . $resource->{profile}{id} . "'",
description => "Invalid profile_id parameter",
response_code => HTTP_UNPROCESSABLE_ENTITY,
};
} else {
#TODO: maybe we should allow it? Can it be so that subscribers are linked to the profile_set without default profile?
#in that case we will fail with this error on every subscriber update attempt
return {
error => "can not determine allowed profile for subscribers profile_set",
description => "Can not determine allowed profile for subscribers profile_set",
response_code => HTTP_UNPROCESSABLE_ENTITY,
};
}
}
# if the profile changed, clear any preferences which are not in the new profile
#in create use case we don't have prov_subscriber
if($prov_subscriber
&& $prov_subscriber->voip_subscriber_profile
&& ( !$profile || $prov_subscriber->voip_subscriber_profile->id != $profile->id )
) {
my %old_profile_attributes = map { $_ => 1 }
$prov_subscriber->voip_subscriber_profile
->profile_attributes->get_column('attribute_id')->all;
if($profile) {
foreach my $attr_id($profile->profile_attributes->get_column('attribute_id')->all) {
delete $old_profile_attributes{$attr_id};
}
}
if(keys %old_profile_attributes) {
my $cfs = $schema->resultset('voip_preferences')->search({
id => { -in => [ keys %old_profile_attributes ] },
attribute => { -in => [qw/cfu cfb cft cfna cfs cfr/] },
});
$prov_subscriber->voip_usr_preferences->search({
attribute_id => { -in => [ keys %old_profile_attributes ] },
})->delete;
$prov_subscriber->voip_cf_mappings->search({
type => { -in => [ map { $_->attribute } $cfs->all ] },
})->delete;
}
}
return 0, $profile_set, $profile;
}
sub update_preferences {
my (%params) = @_;
my $c = $params{c};

@ -8,6 +8,7 @@ use Data::Dumper;
use Clone qw/clone/;
use feature 'state';
#use NGCP::Panel::Utils::Subscriber;
use Data::Compare qw//;
my $test_machine = Test::Collection->new(
name => 'subscribers',
@ -78,7 +79,7 @@ $fake_data->set_data_from_script({
my $fake_data_processed = $fake_data->process('subscribers');
my $pilot = $test_machine->get_item_hal('subscribers','/api/subscribers/?customer_id='.$fake_data_processed->{customer_id}.'&'.'is_pbx_pilot=1');
if((exists $pilot->{total_count} && $pilot->{total_count}) || $pilot->{content}->{total_count} > 0){
if((exists $pilot->{total_count} && $pilot->{total_count}) || (exists $pilot->{content}->{total_count} && $pilot->{content}->{total_count} > 0) ){
$fake_data_processed->{is_pbx_pilot} = 0;
#remove pilot aliases to don't intersect with them. On subscriber termination admin adopt numbers, see ticket#4967
$test_machine->request_patch( [ { op => 'replace', path => '/alias_numbers', value => [] } ], $pilot->{location} );
@ -419,6 +420,316 @@ if($remote_config->{config}->{features}->{cloudpbx}){
$test_machine->http_code_msg(403, "Check display_name patch for subscriberadmin", $res, $content, "Read-only resource for authenticated role");
}
}
{#TT#43350
diag("TT#43350 Test subscriberadmin access");
diag("#------------------------ create subscribers of other customer of other reseller\n");
my $test_machine_other_reseller = Test::Collection->new(
name => 'subscribers',
QUIET_DELETION => 1,
);
my $fake_data_other_reseller = Test::FakeData->new(
keep_db_data => 1,
test_machine => $test_machine_other_reseller,
);
$fake_data_other_reseller->load_collection_data('subscribers');
$fake_data_other_reseller->apply_data({
'customers' => {
'external_id' => 'other_reseller',
'type' => 'pbxaccount',
},
'customercontacts' => {
'email' => 'other_reseller@email.com',
},
'contracts' => {
'external_id' => 'other_reseller',
},
'resellers' => {
'name' => 'other_reseller',
},
'subscribers' => {
'is_pbx_pilot' => 0,
'is_pbx_group' => 0,
'webpassword' => 'api_test_webpassword',
},
'subscriberprofilesets' => {
'name' => 'other_reseller_subscriberprofileset',
},
'subscriberprofiles' => {
'name' => 'other_reseller_subscriberprofile',
},
});
my($subscribers_other_reseller, $subscriberadmins_other_reseller)
= create_subs_and_subadmin($fake_data_other_reseller, $test_machine_other_reseller);
diag("#------------------------ create subscriber of other customer\n");
my $test_machine_other_customer = Test::Collection->new(
name => 'subscribers',
QUIET_DELETION => 1,
);
my $fake_data_other_customer = Test::FakeData->new(
keep_db_data => 1,
test_machine => $test_machine_other_customer,
);
$fake_data_other_customer->load_collection_data('subscribers');
$fake_data_other_customer->apply_data({
'customers' => {
'external_id' => 'other_customer',
'type' => 'pbxaccount',
},
'customercontacts' => {
'email' => 'other_customer@email.com',
},
'contracts' => {
'external_id' => 'other_customer',
},
'subscribers' => {
'is_pbx_pilot' => 0,
'is_pbx_group' => 0,
'webpassword' => 'api_test_webpassword',
},
'subscriberprofilesets' => {
'name' => 'other_customer_subscriberprofileset',
},
'subscriberprofiles' => {
'name' => 'other_customer_subscriberprofile',
},
});
my($subscribers_other_customer, $subscriberadmins_other_customer)
= create_subs_and_subadmin($fake_data_other_customer, $test_machine_other_customer);
diag("#------------------------ create usual subscriber of default test customer and reseller\n");
my $fake_data_processed_old = $test_machine->DATA_ITEM_STORE;
$fake_data->apply_data({
'subscribers' => {
'is_pbx_pilot' => 0,
'is_pbx_group' => 0,
'webpassword' => 'api_test_webpassword',
},
});
$fake_data_processed = $fake_data->process('subscribers');
$test_machine->DATA_ITEM($fake_data_processed);
#print Dumper $test_machine->DATA_ITEM;
my($subscribers, $subscriberadmins)
= create_subs_and_subadmin($fake_data, $test_machine);
$test_machine->set_subscriber_credentials($subscriberadmins->[0]->{content});
$test_machine->runas('subscriber');
diag("\n\n\nSUBSCRIBERADMIN ".$subscriberadmins->[0]->{content}->{id}.":");
diag("#------------------------ subscriberadmin: attempt to create subscriber using other customer-reseller:\n");
my($res,$content,$sub_create_attempt);
$sub_create_attempt = $test_machine->check_create_correct(1,sub {
my $num = $_[1]->{i};
my $uniq = Test::FakeData::seq;
$_[0]->{webusername} = '43350_'.$uniq;
$_[0]->{username} = '43350_'.$uniq;
$_[0]->{pbx_extension} = '43350'.$uniq;
$_[0]->{primary_number}->{ac} = '43350'.$uniq;
$_[0]->{is_pbx_pilot} = 0;
$_[0]->{administrative} = 1;
#delete $_[0]->{profile_id};
delete $_[0]->{alias_numbers};
$_[0]->{profile_id} = $subscribers->[0]->{content}->{profile_id};
}, $subscribers_other_reseller->[0]->{content})->[0];
#print Dumper [
# $sub_create_attempt->{content},
# $subscribers_other_reseller->[0]->{content}->{customer_id},
# $subscriberadmins->[0]->{content}->{customer_id}];
#print Dumper [$sub_create_attempt->{content}, $sub_create_attempt->{content_post}];
ok(($sub_create_attempt->{content}->{customer_id} != $subscribers_other_reseller->[0]->{content}->{customer_id})
&& ($sub_create_attempt->{content}->{customer_id} == $subscriberadmins->[0]->{content}->{customer_id})
&& ($sub_create_attempt->{content_post}->{customer_id} == $subscribers_other_reseller->[0]->{content}->{customer_id}),
"check that subscriberadminadmin customer_id ".$subscriberadmins->[0]->{content}->{customer_id}
." was applied instead of ".$sub_create_attempt->{content_post}->{customer_id});
ok( ($sub_create_attempt->{content}->{administrative} == 0)
&& ($sub_create_attempt->{content_post}->{administrative} == 1),
"check that subscriberadminadmin can't create subscriberadmin: "
.$sub_create_attempt->{content_post}->{administrative}
."=>".$sub_create_attempt->{content}->{administrative}.";");
#here we have unexpected error:
#Sep 9 22:37:02 sp1 ngcp-panel: DEBUG: username:43350_8_; resource.domain_id:101;item.domain_id:535;
#Sep 9 22:37:02 sp1 ngcp-panel: ERROR: error 422 - Subscriber with this username does not exist in the domain.
diag("#-------------------------- 1. Check customer_id management ----------");
my ($content_get,$content_put, $content_patch);
$test_machine->request_patch( [ {
op => 'replace',
path => '/customer_id',
value => $subscribers_other_customer->[0]->{content}->{customer_id}
} ], $subscribers->[0]->{location});
(undef,$content_get) = $test_machine->check_item_get($subscribers->[0]->{location});
ok($content_get->{customer_id} == $fake_data->get_id('customers')
&& $content_get->{customer_id} != $subscribers_other_customer->[0]->{content}->{customer_id},
"check that subscribersadmin can't apply foreign customer_id to own subscribers: "
.$subscribers_other_customer->[0]->{content}->{customer_id}."=>".$content_get->{customer_id});
$content_get->{customer_id} = $subscribers_other_customer->[0]->{content}->{customer_id};
$test_machine->request_put( $content_get, $subscribers->[0]->{location});
(undef,$content_get) = $test_machine->check_item_get($subscribers->[0]->{location});
ok($content_get->{customer_id} == $fake_data->get_id('customers')
&& $content_get->{customer_id} != $subscribers_other_customer->[0]->{content}->{customer_id},
"check that subscribersadmin can't apply foreign customer_id to own subscribers: "
.$subscribers_other_customer->[0]->{content}->{customer_id}."=>".$content_get->{customer_id});
diag("#-------------------------- 2. Check NUMBER management ----------");
diag("#-------------------------- 2. 1. NUMBER: use other customer's primary number for create ----------");
($res,$sub_create_attempt) = $test_machine->check_item_post(sub {
my $num = $_[1]->{i};
my $uniq = Test::FakeData::seq;
$_[0]->{webusername} = '43350_'.$uniq;
$_[0]->{username} = '43350_'.$uniq;
$_[0]->{pbx_extension} = '43350'.$uniq;
$_[0]->{primary_number}->{ac} = '43350'.$uniq;
my $foreign_number = clone $subscribers_other_customer->[0]->{content}->{primary_number};
delete $foreign_number->{number_id};
delete $_[0]->{profile_id};
$_[0]->{alias_numbers} = [$foreign_number];
#print Dumper $_[0]->{alias_numbers};
}, $subscribers_other_reseller->[0]->{content});
$test_machine->http_code_msg(422, "Check subscriberadmin create subscriber using foreign primary_number", $res, $sub_create_attempt);
#print Dumper $res;
diag("#-------------------------- 2. 2. NUMBER: use other customer's primary number for edit (PUT) ----------");
$content_put = clone $content_get;
$content_put->{alias_numbers} = [clone $subscribers_other_customer->[0]->{content}->{primary_number}];
delete $content_put->{_links};
delete $content_put->{alias_numbers}->[0]->{number_id};
#print Dumper $content_put;
($res,$content_put) = $test_machine->request_put( $content_put, $subscribers->[0]->{location});
$test_machine->http_code_msg(422, "check that subscribersadmin can't manage others customers numbers", $res, $content_put);
(undef,$content_get) = $test_machine->check_item_get($subscribers->[0]->{location});
delete $content_get->{alias_numbers}->[0]->{number_id};
delete $subscribers_other_customer->[0]->{content}->{primary_number}->{number_id};
# 0 if different, 1 if equal
ok(!Data::Compare::Compare($content_get->{alias_numbers}->[0], $subscribers_other_customer->[0]->{content}->{primary_number}),
"check that subscribersadmin can't manage others customers numbers. Other subscriber primary_number:\n"
.Dumper($subscribers_other_customer->[0]->{content}->{primary_number})."\n=>\n".Dumper($content_get->{alias_numbers}->[0])
);
diag("#--------------------------3. Check PROFILE management ");
diag("#--------------------------3. 1. PROFILE: Check attempt to apply other cutsomer's profile_id ------------ ");
$content_put = clone $subscribers->[0]->{content};
delete $content_put->{_links};
$content_put->{profile_id} = $subscribers_other_customer->[0]->{content}->{profile_id};
($res, $content_put) = $test_machine->request_put( $content_put, $subscribers->[0]->{location});
$test_machine->http_code_msg(422, "check that subscribersadmin can't manage others customers profile_id", $res, $content_put);
($res,$content_get) = $test_machine->check_item_get($subscribers->[0]->{location});
$content_get->{profile_id} //= '';
ok($content_get->{profile_id} != $subscribers_other_customer->[0]->{content}->{profile_id},
"check that subscribersadmin can't apply others customers profile_id. "
.$subscribers_other_customer->[0]->{content}->{profile_id}." => ".$content_get->{profile_id});
diag("#--------------------------3. 2. PROFILE: Check attempt to apply other profile_set profile_id ------------ ");
my $test_machine_other_profile_set = Test::Collection->new(
name => 'subscriberprofiles',
QUIET_DELETION => 1,
);
my $fake_data_other_profile_set = Test::FakeData->new(
keep_db_data => 1,
test_machine => $test_machine_other_profile_set,
);
$fake_data_other_profile_set->load_collection_data('subscriberprofiles');
$fake_data_other_profile_set->apply_data({
'subscriberprofilesets' => {
'name' => 'other_subscriberprofileset'.Test::FakeData::seq,
},
'subscriberprofiles' => {
'name' => 'other_subscriberprofile'.Test::FakeData::seq,
},
});
my $fake_data_other_profile_set_processed = $fake_data_other_profile_set->process('subscriberprofiles');
#print Dumper ['create_subs_and_subadmin','fake_data_l_processed',$fake_data_l_processed];
$test_machine_other_profile_set->DATA_ITEM($fake_data_other_profile_set_processed);
$test_machine_other_profile_set->DATA_ITEM_STORE($fake_data_other_profile_set_processed);
#just note - test_machine_other_profile_set is logged in as administrator, so we can create profileset and profile
my $subscriberprofile_other_profile_set = $test_machine_other_profile_set->check_create_correct(1)->[0];
$content_put = clone $subscribers->[0]->{content};
delete $content_put->{_links};
$content_put->{profile_id} = $subscriberprofile_other_profile_set->{content}->{id};
$content_put->{display_name} = 'test_other_profileset_profile';
($res, $content_put) = $test_machine->request_put( $content_put, $subscribers->[0]->{location});
$test_machine->http_code_msg(422, "check that subscribersadmin can't assign other profileset profile_id", $res, $content_put);
($res,$content_get) = $test_machine->check_item_get($subscribers->[0]->{location});
$content_get->{profile_id} //= '';
ok($content_get->{profile_id} != $subscriberprofile_other_profile_set->{content}->{id},
"check that subscribersadmin can't apply other profileset profile_id. "
.$subscriberprofile_other_profile_set->{content}->{id}." => ".$content_get->{profile_id});
diag("#--------------------------3. 3. PROFILE: Check attempt to apply correct profile_id ------------ ");
my $test_machine_other_profile = Test::Collection->new(
name => 'subscriberprofiles',
QUIET_DELETION => 1,
);
my $fake_data_other_profile = Test::FakeData->new(
keep_db_data => 1,
test_machine => $test_machine_other_profile,
);
$fake_data_other_profile->load_collection_data('subscriberprofiles');
$fake_data_other_profile->apply_data({
'subscriberprofiles' => {
'name' => 'other_subscriberprofile'.Test::FakeData::seq,
},
});
my $fake_data_other_profile_processed = $fake_data_other_profile->process('subscriberprofiles');
#print Dumper ['create_subs_and_subadmin','fake_data_l_processed',$fake_data_l_processed];
$test_machine_other_profile->DATA_ITEM($fake_data_other_profile_processed);
$test_machine_other_profile->DATA_ITEM_STORE($fake_data_other_profile_processed);
#just note - test_machine_other_profile is logged in as administrator, so we can create profileset and profile
my $subscriberprofile_other = $test_machine_other_profile->check_create_correct(1)->[0];
$content_put = clone $subscribers->[0]->{content};
delete $content_put->{_links};
$content_put->{profile_id} = $subscriberprofile_other->{content}->{id};
$content_put->{display_name} = 'test_other_profileset_profile';
($res, $content_put) = $test_machine->request_put( $content_put, $subscribers->[0]->{location});
$test_machine->http_code_msg(200, "check that subscribersadmin can assign other profile from correct profile_set", $res, $content_put);
($res,$content_get) = $test_machine->check_item_get($subscribers->[0]->{location});
$content_get->{profile_id} //= '';
ok($content_get->{profile_id} eq $subscriberprofile_other->{content}->{id},
"check that subscribersadmin can't apply other profileset profile_id. "
.$subscriberprofile_other->{content}->{id}." => ".$content_get->{profile_id});
diag("#--------------------------4. MISC: Check that subscriberadmin can manage something ------------ ");
($res,$content_patch) = $test_machine->request_patch( [ { op => 'replace', path => '/display_name', value => 'patched_43350' } ], $subscribers->[0]->{location});
$test_machine->http_code_msg(200, "check that subscribersadmin can manage available fields", $res, $content_patch);
($res,$content_get) = $test_machine->check_item_get($subscribers->[0]->{location});
ok($content_get->{display_name} eq 'patched_43350',
"check that subscribersadmin can manage display_name");
diag("#-------------------------- 5. ACCESS other's customer subscribers ----------");
foreach my $restricted_subscriber ($subscribers_other_reseller, $subscribers_other_customer) {
my $location = $restricted_subscriber->[0]->{location};
($res,$content) = $test_machine->request_get($location);
$test_machine->http_code_msg(404, "subscriberadmin: view subscriber of other customer:",$res,$content,
"Entity 'subscriber' not found");
($res,$content) = $test_machine->request_put($sub_create_attempt->{content}, $location);
$test_machine->http_code_msg(404, "subscriberadmin: put subscriber of other customer:",$res,$content,
"Entity 'subscriber' not found");
($res,$content) = $test_machine->request_patch( [ { op => 'replace', path => '/display_name', value => 'patched 433050' } ], $location);
$test_machine->http_code_msg(404, "subscriberadmin: patch subscriber of other customer:",$res,$content,
"Entity 'subscriber' not found");
}
#$test_machine_other->set_subscriber_credentials($subscriber_other->{content});
#$test_machine_other->runas('subscriber');
#diag("\n\n\nSUBSCRIBER ".$subscriber_other->{content}->{id}.":");
$test_machine->DATA_ITEM($fake_data_processed_old);
$test_machine->clear_test_data_all();
#if we failed with create checking (we s)
#$test_machine->check_item_delete();
}
}
#TT#21818 variant 2 - pbx feature off, subscriberadmin is read-only. No subscriber exists
@ -464,6 +775,8 @@ $test_machine->runas('admin');
($res,$content) = $test_machine->request_post( $data);
$test_machine->http_code_msg(422, "Alias numbers should be the hashs", $res, $content);
}
$test_machine->init_ssl_cert();
$fake_data->clear_test_data_all();
$test_machine->clear_test_data_all();#fake data aren't registered in this test machine, so they will stay.
$fake_data->clear_test_data_all();
@ -602,6 +915,69 @@ sub test_password_validation {
}
}
sub create_subs_and_subadmin {
my ($fake_data_l, $test_machine_l, $prefix, $no_pilot) = @_;
$prefix //= '';
my $fake_data_l_processed = $fake_data_l->process('subscribers');
#print Dumper ['create_subs_and_subadmin','fake_data_l_processed',$fake_data_l_processed];
$test_machine_l->DATA_ITEM($fake_data_l_processed);
$test_machine_l->DATA_ITEM_STORE($fake_data_l_processed);
my $pilot_l = $test_machine_l->get_item_hal('subscribers','/api/subscribers/?customer_id='.$fake_data_l_processed->{customer_id}.'&'.'is_pbx_pilot=1');
if((exists $pilot_l->{total_count} && $pilot_l->{total_count}) || (exists $pilot_l->{content}->{total_count} && $pilot_l->{content}->{total_count} > 0)){
#remove existing pilot aliases to don't intersect with them. On subscriber termination admin adopt numbers, see ticket#4967
my($res, $mod_pilot) = $test_machine_l->request_patch([
{ op => 'replace', path => '/alias_numbers', value => [] },
#to don't intersect with manual testing on the web
{ op => 'replace', path => '/profile_set_id', value => $fake_data_l->get_id('subscriberprofilesets') },
{ op => 'replace', path => '/profile_id', value => undef },#we will take default profile for profile_set
#we can't change domain
#and we can create subscriber in domain out of reseller
#{ op => 'replace', path => '/domain_id', value => $fake_data_l->get_id('domains') },
],
$pilot_l->{location} );
#print Dumper $pilot_l->{content};
}else{
undef $pilot_l;
}
my $subscribers = $test_machine_l->check_create_correct(3, sub {
my $num = $_[1]->{i};
my $uniq = Test::FakeData::seq;
$_[0]->{webusername} = '43350_'.$uniq.'_'.$prefix;
$_[0]->{username} = '43350_'.$uniq.'_'.$prefix ;
$_[0]->{pbx_extension} = '43350'.$uniq;
$_[0]->{primary_number}->{ac} = '43350'.$uniq;
$_[0]->{is_pbx_pilot} = ($pilot_l || $num > 1 )? 0 : 1;
$_[0]->{administrative} = 0;
$_[0]->{alias_numbers} = [{
ac => '43350'.$uniq,
cc => $uniq,
sn => '43350'.$uniq,
}];
#$_[0]->{domain} = $pilot_l->{domain};
$pilot_l and $_[0]->{domain_id} = $pilot_l->{content}->{domain_id};
});
#$fake_data_l->get_id('resellers',@_);
diag("#------------------------ create subscriberadmin\n");
my $subscriberadmins = $test_machine_l->check_create_correct(1, sub {
my $num = $_[1]->{i};
my $uniq = Test::FakeData::seq;
$_[0]->{webusername} = '43350_'.$uniq.'_'.$prefix.'_adm';
$_[0]->{username} = '43350_'.$uniq.'_'.$prefix.'_adm';
$_[0]->{pbx_extension} = '43350'.$uniq;
$_[0]->{primary_number}->{ac} = '43350'.$uniq;
$_[0]->{administrative} = 1;
$_[0]->{is_pbx_pilot} = 0;
delete $_[0]->{alias_numbers};
});
diag("#------------------------ /create subscriberadmin\n");
return $subscribers, $subscriberadmins;
}
sub number_as_string{
my ($number_row, %params) = @_;
return 'HASH' eq ref $number_row

@ -1294,12 +1294,13 @@ sub process_data{
}
sub check_item_post{
my($self, $data_cb, $data_in, $data_cb_data) = @_;
my($self, $data_cb, $data_in, $data_cb_data, $uri) = @_;
my $data = $self->process_data($data_cb, $data_in, $data_cb_data);
#print Dumper $data;
my ($res,$rescontent,$req) = $self->request_post($data);#,$uri,$req
my ($res,$rescontent,$req) = $self->request_post($data, $uri);#,$uri,$req
return wantarray ? ($res,$rescontent,$req,$data) : $res;
};
}
sub check_item_delete{
my($self, $uri, $msg) = @_;
my $name = $self->name // '';
@ -1307,7 +1308,8 @@ sub check_item_delete{
my ($req,$res,$content) = $self->request_delete($uri);#,$uri,$req
$self->http_code_msg(204, "$name: check delete item $uri",$res,$content);
return ($req,$res,$content);
};
}
sub check_create_correct{
my($self, $number, $uniquizer_cb, $data_in) = @_;
if(!$self->KEEP_CREATED){

@ -479,6 +479,15 @@ sub process_data{
#incorrect place, leave it for the next timeframe to work on it
#$self->load_db($data);
}
sub apply_data {
my($self, $alternative_data) = @_;
foreach my $collection (keys %$alternative_data) {
my @keys = keys %{$alternative_data->{$collection}};
@{$self->{data}->{$collection}->{data}}{@keys} = @{$alternative_data->{$collection}}{@keys};
}
}
sub load_db{
my($self,$data,$collections_slice) = @_;
$data //= $self->data;

Loading…
Cancel
Save