tenantutils - becoming stateless
Project: http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/commit/16eb2597 Tree: http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/tree/16eb2597 Diff: http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/diff/16eb2597 Branch: refs/heads/master Commit: 16eb2597759ca265fba984f8caf1f0b0d8d1bd50 Parents: f5ca600 Author: nir-sopher <nirsop...@gmail.com> Authored: Fri Jun 2 16:45:54 2017 +0300 Committer: Jeremy Mitchell <mitchell...@gmail.com> Committed: Tue Jul 18 12:12:31 2017 -0600 ---------------------------------------------------------------------- traffic_ops/app/lib/API/Tenant.pm | 44 +++++--- traffic_ops/app/lib/UI/TenantUtils.pm | 171 +++++++++++++++-------------- 2 files changed, 119 insertions(+), 96 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/16eb2597/traffic_ops/app/lib/API/Tenant.pm ---------------------------------------------------------------------- diff --git a/traffic_ops/app/lib/API/Tenant.pm b/traffic_ops/app/lib/API/Tenant.pm index 4812439..e9b9cb5 100644 --- a/traffic_ops/app/lib/API/Tenant.pm +++ b/traffic_ops/app/lib/API/Tenant.pm @@ -36,18 +36,20 @@ sub index { my $self = shift; my $orderby = $self->param('orderby') || "name"; + my $tenant_utils = UI::TenantUtils->new($self); + my $tenants_data = $tenant_utils->create_tenants_data_from_db($orderby); + my @data = (); - my $tenantUtils = UI::TenantUtils->new($self); - my @tenants_list = $tenantUtils->get_hierarchic_tenants_list(undef, $orderby); + my @tenants_list = $tenant_utils->get_hierarchic_tenants_list($tenants_data, undef, $orderby); foreach my $row (@tenants_list) { - if ($tenantUtils->is_tenant_resource_readable($row->id)) { + if ($tenant_utils->is_tenant_resource_readable($tenants_data, $row->id)) { push( @data, { "id" => $row->id, "name" => $row->name, "active" => \$row->active, "parentId" => $row->parent_id, - "parentName" => ( defined $row->parent_id ) ? $tenantUtils->get_tenant($row->parent_id)->name : undef, + "parentName" => ( defined $row->parent_id ) ? $tenant_utils->get_tenant($tenants_data, $row->parent_id)->name : undef, } ); } @@ -60,18 +62,20 @@ sub show { my $self = shift; my $id = $self->param('id'); + my $tenant_utils = UI::TenantUtils->new($self); + my $tenants_data = $tenant_utils->create_tenants_data_from_db(undef); + my @data = (); - my $tenantUtils = UI::TenantUtils->new($self); my $rs_data = $self->db->resultset("Tenant")->search( { 'me.id' => $id }); while ( my $row = $rs_data->next ) { - if ($tenantUtils->is_tenant_resource_readable($row->id)) { + if ($tenant_utils->is_tenant_resource_readable($tenants_data, $row->id)) { push( @data, { "id" => $row->id, "name" => $row->name, "active" => \$row->active, "parentId" => $row->parent_id, - "parentName" => ( defined $row->parent_id ) ? $tenantUtils->get_tenant($row->parent_id)->name : undef, + "parentName" => ( defined $row->parent_id ) ? $tenant_utils->get_tenant($tenants_data, $row->parent_id)->name : undef, } ); } @@ -109,9 +113,10 @@ sub update { } } - my $tenantUtils = UI::TenantUtils->new($self); + my $tenant_utils = UI::TenantUtils->new($self); + my $tenants_data = $tenant_utils->create_tenants_data_from_db(undef); - if ( !defined( $params->{parentId}) && !$tenantUtils->is_root_tenant($id) ) { + if ( !defined( $params->{parentId}) && !$tenant_utils->is_root_tenant($tenants_data, $id) ) { # Cannot turn a simple tenant to a root tenant. # Practically there is no problem with doing so, but it is to risky to be done by mistake. return $self->alert("Parent Id is required."); @@ -123,7 +128,7 @@ sub update { my $is_active = $params->{active}; - if ( !$params->{active} && $tenantUtils->is_root_tenant($id)) { + if ( !$params->{active} && $tenant_utils->is_root_tenant($tenants_data, $id)) { return $self->alert("Root tenant cannot be in-active."); } @@ -134,11 +139,11 @@ sub update { $current_resource_tenancy = $id; } - if (!$tenantUtils->is_tenant_resource_writeable($current_resource_tenancy)) { + if (!$tenant_utils->is_tenant_resource_writeable($tenants_data, $current_resource_tenancy)) { return $self->alert("Current owning tenant is not under user's tenancy."); } - if (!$tenantUtils->is_tenant_resource_writeable($params->{parentId})) { + if (!$tenant_utils->is_tenant_resource_writeable($tenants_data, $params->{parentId})) { return $self->alert("Parent tenant to be set is not under user's tenancy."); } @@ -150,6 +155,7 @@ sub update { parent_id => $params->{parentId} }; + #$tenants_data is about to become outdated my $rs = $tenant->update($values); if ($rs) { my %idnames; @@ -196,8 +202,10 @@ sub create { return $self->alert("Parent Id is required."); } - my $tenantUtils = UI::TenantUtils->new($self); - if (!$tenantUtils->is_tenant_resource_writeable($params->{parentId})) { + my $tenant_utils = UI::TenantUtils->new($self); + my $tenants_data = $tenant_utils->create_tenants_data_from_db(undef); + + if (!$tenant_utils->is_tenant_resource_writeable($tenants_data, $params->{parentId})) { return $self->alert("Parent tenant to be set is not under user's tenancy."); } @@ -218,6 +226,7 @@ sub create { parent_id => $params->{parentId} }; + #$tenants_data is about to become outdated my $insert = $self->db->resultset('Tenant')->create($values); my $rs = $insert->insert(); if ($rs) { @@ -262,8 +271,10 @@ sub delete { my $parent_tenant = $tenant->parent_id; - my $tenantUtils = UI::TenantUtils->new($self); - if (!$tenantUtils->is_tenant_resource_writeable($parent_tenant)) { + my $tenant_utils = UI::TenantUtils->new($self); + my $tenants_data = $tenant_utils->create_tenants_data_from_db(undef); + + if (!$tenant_utils->is_tenant_resource_writeable($tenants_data, $parent_tenant)) { return $self->alert("Parent tenant is not under user's tenancy."); } @@ -285,6 +296,7 @@ sub delete { return $self->alert("Tenant '$name' is assign with user(s): e.g. '$existing_user'. Please update these users and retry."); } + #$tenants_data is about to become outdated my $rs = $tenant->delete(); if ($rs) { return $self->success_message("Tenant deleted."); http://git-wip-us.apache.org/repos/asf/incubator-trafficcontrol/blob/16eb2597/traffic_ops/app/lib/UI/TenantUtils.pm ---------------------------------------------------------------------- diff --git a/traffic_ops/app/lib/UI/TenantUtils.pm b/traffic_ops/app/lib/UI/TenantUtils.pm index d2b1ea5..6b02f8e 100644 --- a/traffic_ops/app/lib/UI/TenantUtils.pm +++ b/traffic_ops/app/lib/UI/TenantUtils.pm @@ -15,53 +15,101 @@ package UI::TenantUtils; # # # -use NetAddr::IP; + + +# +# This class provide utilities to examine different tenancy aspects, +# and specifically tenancy based access restrictions. +# +# The class itself is almost* stateless. However in order to reduce calls to DB, its +# API allows the user to create the "DATA" object (using "create_tenants_data_from_db") +# and run utility functions over it. +# +# For now, until the current user tenant ID will come from the jwt, the current user tenant is taken from the DB. +# In order to reduce the number of calls from the DB, the current user tenant is taken in the class creation +# + use Data::Dumper; -use Switch; use UI::Utils; sub new { my $class = shift; - my $self = { - context => shift, - user_tenant_id => -1, + my $context = shift; + # For now, until the current user tenant ID will come from the jwt, the current user tenant is taken from the DB. + my $current_user_tenant = $context->db->resultset('TmUser')->search( { username => $context->current_user()->{username} } )->get_column('tenant_id')->single(); + my $dbh = $context->db; + my $self = { + dbh => $dbh, + # In order to reduce the number of calls from the DB, the current user tenant is taken in the class creation. + # the below parameters are held temporarily until the info is taken from the jwt + current_user_tenant => $current_user_tenant, + is_ldap => $context->is_ldap(), + }; + bless $self, $class; + return $self; +} + +sub create_tenants_data_from_db { + my $self = shift; + my $tenants_data = { tenants_dict => undef, root_tenants => undef, order_by => -1, ordered_by => undef, }; - return bless $self, $class; + $tenants_data->{order_by} = shift || "name";#some default + + my $tenants_table = $self->{dbh}->resultset("Tenant")->search( undef, { order_by => $tenants_data->{order_by} }); + + $tenants_data->{ordered_by} = (); + $tenants_data->{tenants_dict} = {}; + while ( my $row = $tenants_table->next ) { + push (@{ $tenants_data->{ordered_by} }, $row->id); + $tenants_data->{tenants_dict}->{$row->id} = { + row => $row, + parent => $row->parent_id, + children => (), + } + } + + $tenants_data->{root_tenants} = (); + foreach my $key (@{ $tenants_data->{ordered_by} }) { + my $value = $tenants_data->{tenants_dict}->{$key}; + my $parent = $value->{parent}; + if (!defined($parent)) + { + push @{ $tenants_data->{root_tenants} }, $key; + } + else{ + push @{ $tenants_data->{tenants_dict}->{$parent}{children} }, $key; + } + } + + return $tenants_data; } - sub current_user_tenant { my $self = shift; - if ($self->{user_tenant_id} == -1) - { - $self->{user_tenant_id} = $self->{context}->db->resultset('TmUser')->search( { username => $self->{context}->current_user()->{username} } )->get_column('tenant_id')->single(); - } - return $self->{user_tenant_id}; + return $self->{current_user_tenant}; } sub get_tenant { my $self = shift; + my $tenants_data = shift; my $tenant_id = shift; - $self->_init_tenants_if_needed(undef); - - return $self->{tenants_dict}->{$tenant_id}{row}; + return $tenants_data->{tenants_dict}->{$tenant_id}{row}; } sub get_tenants_list { my $self = shift; + my $tenants_data = shift; my $order_by = shift; - $self->_init_tenants_if_needed($order_by); - my @result = (); - foreach my $tenant_id (@{ $self->{ordered_by} }) { - push @result, $self->{tenants_dict}->{$tenant_id}{row}; + foreach my $tenant_id (@{ $tenants_data->{ordered_by} }) { + push @result, $tenants_data->{tenants_dict}->{$tenant_id}{row}; } return @result; @@ -69,24 +117,23 @@ sub get_tenants_list { sub get_hierarchic_tenants_list { my $self = shift; + my $tenants_data = shift; my $tree_root = shift; my $order_by = shift; - $self->_init_tenants_if_needed($order_by); - my @stack = (); if (defined($tree_root)){ push (@stack, $tree_root); } else { - push (@stack, reverse(@{$self->{root_tenants}})); + push (@stack, reverse(@{$tenants_data->{root_tenants}})); } my @result = (); while (@stack) { my $tenant_id = pop @stack; - push (@result, $self->{tenants_dict}->{$tenant_id}{row}); - push (@stack, reverse(@{$self->{tenants_dict}->{$tenant_id}{children}})); + push (@result, $tenants_data->{tenants_dict}->{$tenant_id}{row}); + push (@stack, reverse(@{$tenants_data->{tenants_dict}->{$tenant_id}{children}})); } return @result; @@ -94,82 +141,47 @@ sub get_hierarchic_tenants_list { sub is_root_tenant { my $self = shift; + my $tenants_data = shift; my $tenant_id = shift; if (!defined($tenant_id)) { return 0; } - if (defined($self->{tenants_dict})) { - return !(defined($self->{tenants_dict}{$tenant_id}{parent})); + if (defined($tenants_data->{tenants_dict})) { + return !(defined($tenants_data->{tenants_dict}{$tenant_id}{parent})); } - return !defined($self->{context}->db->resultset('Tenant')->search( { id => $tenant_id } )->get_column('parent_id')->single()); + return !defined($self->{dbh}->resultset('Tenant')->search( { id => $tenant_id } )->get_column('parent_id')->single()); } sub is_tenant_resource_readable { - my $self = shift; - my $resource_tenancy = shift; + my $self = shift; + my $tenants_data = shift; + my $resource_tenancy = shift; - return _is_resource_accessable ($self, $resource_tenancy, "r"); + return $self->_is_resource_accessable ($tenants_data, $resource_tenancy, "r"); } sub is_tenant_resource_writeable { - my $self = shift; - my $resource_tenancy = shift; + my $self = shift; + my $tenants_data = shift; + my $resource_tenancy = shift; - return _is_resource_accessable ($self, $resource_tenancy, "w"); + return $self->_is_resource_accessable ($tenants_data, $resource_tenancy, "w"); } ############################################################## -sub _init_tenants { - my $self = shift; - $self->{order_by} = shift || "name";#some default - my $tenants_table = $self->{context}->db->resultset("Tenant")->search( undef, { order_by => $self->{order_by} }); - - $self->{ordered_by} = (); - $self->{tenants_dict} = {}; - while ( my $row = $tenants_table->next ) { - push (@{ $self->{ordered_by} }, $row->id); - $self->{tenants_dict}->{$row->id} = { - row => $row, - parent => $row->parent_id, - children => (), - } - } - - $self->{root_tenants} = (); - foreach my $key (@{ $self->{ordered_by} }) { - my $value = $self->{tenants_dict}->{$key}; - my $parent = $value->{parent}; - if (!defined($parent)) - { - push @{ $self->{root_tenants} }, $key; - } - else{ - push @{ $self->{tenants_dict}->{$parent}{children} }, $key; - } - } -} - -sub _init_tenants_if_needed { - my $self = shift; - my $order_by = shift; - if (($self->{order_by} == -1) || (defined($order_by) && $order_by != $self->{order_by})) { - ## first run to build the list OR (the order is important AND is not the current order) - $self->_init_tenants($order_by); - } -} - -sub _max_tenancy_heirarchy { +sub _tenancy_heirarchy_limit { my $self = shift; return 100; } sub _is_resource_accessable { my $self = shift; + my $tenants_data = shift; my $resource_tenant = shift; my $operation = shift; @@ -178,7 +190,7 @@ sub _is_resource_accessable { return 1; } - if (&is_ldap($self->{context})) { + if ($self->{is_ldap}) { if ($operation eq "r") { #ldap user, can read all tenants - temporary for now as an LDAP user as no tenant and is part of the TC operator. # should be removed when LDAP is gone @@ -188,14 +200,13 @@ sub _is_resource_accessable { return 0; } - my $user_tenant = current_user_tenant($self); + my $user_tenant = $self->current_user_tenant(); if (!defined($user_tenant)) { #the user has no tenancy, - cannot approach items with tenancy return 0; } - $self->_init_tenants_if_needed(undef); - my $tenant_record = $self->{tenants_dict}->{$user_tenant}; + my $tenant_record = $tenants_data->{tenants_dict}->{$user_tenant}; my $is_active_tenant = $tenant_record->{row}->active; if (! $is_active_tenant) { #user tenant is in-active - cannot do any operation @@ -208,7 +219,7 @@ sub _is_resource_accessable { } #checking if the user tenant is an ancestor of the resource tenant - for (my $depth = 0; $depth < $self->_max_tenancy_heirarchy(); $depth++) { + for (my $depth = 0; $depth < $self->_tenancy_heirarchy_limit(); $depth++) { if (!defined($resource_tenant)){ #reached top tenant, resource is not under the user tenancy @@ -220,11 +231,11 @@ sub _is_resource_accessable { return 1; } - $resource_tenant = $self->{tenants_dict}->{$resource_tenant}->{parent}; + $resource_tenant = $tenants_data->{tenants_dict}->{$resource_tenant}->{parent}; }; #not found - recursion limit, give only access to root tenant - return $self->is_root_tenant(current_user_tenant($self)); + return $self->is_root_tenant($tenants_data, $user_tenant); } 1;