Commit 00b57bf4 authored by Kirk Webb's avatar Kirk Webb

Add global permissions support for leases.

Two types of global permissions are supported:

* Anonymous read-only (to support users without local accounts).
* Read-only for users with local accounts.

Global permissions are added to leases by way of entries of type "global"
in the lease_permissions table.  The lease mod tool still needs to be
updated to make use of the updated library support here.

The new GetAllowedLeases() method in Lease.pm was reworked - it became
clear that this was needed as I did the global RO permissions stuff.
parent b162d8de
...@@ -93,6 +93,9 @@ use vars qw(@ISA @EXPORT); ...@@ -93,6 +93,9 @@ use vars qw(@ISA @EXPORT);
LEASE_ERROR_NONE LEASE_ERROR_FAILED LEASE_ERROR_BUSY LEASE_ERROR_NONE LEASE_ERROR_FAILED LEASE_ERROR_BUSY
LEASE_ERROR_GONE LEASE_ERROR_GONE
GLOBAL_PERM_ANON_RO GLOBAL_PERM_USER_RO
GLOBAL_PERM_ANON_RO_IDX GLOBAL_PERM_USER_RO_IDX
DBLIMIT_NSFILESIZE NODERELOADPENDING_EID DBLIMIT_NSFILESIZE NODERELOADPENDING_EID
NODEREPOSITIONING_PID NODEREPOSITIONING_EID NODEREPOSPENDING_EID NODEREPOSITIONING_PID NODEREPOSITIONING_EID NODEREPOSPENDING_EID
...@@ -425,6 +428,12 @@ sub LEASE_ERROR_FAILED() { -1; } ...@@ -425,6 +428,12 @@ sub LEASE_ERROR_FAILED() { -1; }
sub LEASE_ERROR_BUSY() { -2; } sub LEASE_ERROR_BUSY() { -2; }
sub LEASE_ERROR_GONE() { -3; } sub LEASE_ERROR_GONE() { -3; }
# Global permissions identifiers and indexes for *_permissions tables.
sub GLOBAL_PERM_ANON_RO { "GLOBAL_ANON_RO"; }
sub GLOBAL_PERM_USER_RO { "GLOBAL_USER_RO"; }
sub GLOBAL_PERM_ANON_RO_IDX { 1; }
sub GLOBAL_PERM_USER_RO_IDX { 2; }
# Node Log Types # Node Log Types
sub TB_NODELOGTYPE_MISC { "misc"; } sub TB_NODELOGTYPE_MISC { "misc"; }
sub TB_NODELOGTYPES() { ( TB_NODELOGTYPE_MISC() ) ; } sub TB_NODELOGTYPES() { ( TB_NODELOGTYPE_MISC() ) ; }
......
...@@ -906,6 +906,13 @@ sub AllUserLeases($$;$) ...@@ -906,6 +906,13 @@ sub AllUserLeases($$;$)
# access to leases associated with that project. # access to leases associated with that project.
# * Explicitly granted per-user and per-project permissions are extracted # * Explicitly granted per-user and per-project permissions are extracted
# from the lease_permissions tables. # from the lease_permissions tables.
# * Global permissions (only RO).
#
# Note: Greatest privilege is returned when a principle matches more than
# one lease permissions condition.
#
# Note: Non-local users will only be allowed access to leases that have
# global "anonymous read-only" permissions enabled on them.
# #
# Arguments: # Arguments:
# * upid - User OR Project object to lookup lease access for. # * upid - User OR Project object to lookup lease access for.
...@@ -918,20 +925,18 @@ sub AllUserLeases($$;$) ...@@ -918,20 +925,18 @@ sub AllUserLeases($$;$)
# #
sub GetAllowedLeases($$;$) { sub GetAllowedLeases($$;$) {
my ($class, $upid, $type) = @_; my ($class, $upid, $type) = @_;
my $uid = "";
my %admin_pids = ();
my %leases = ();
# Determine appropriate "where" clause for DB lookup based on the
# type of object passed in (User or Project). Also stash away some
# info to process the query results with in the case of a User access
# query.
my $wclause = ""; my $wclause = "";
my %lease_indexes = ();
my @leases = ();
# Gather up lease permissions for Users and Projects. The logic for users
# is much more complicated...
if (ref($upid) == "User") { if (ref($upid) == "User") {
$uid = $upid->uid(); $uid = $upid->uid();
my $uid_idx = $upid->uid_idx(); my $uid_idx = $upid->uid_idx();
my @ugroups = (); my @ugroups = ();
my $gid_idx_list = ""; my $gid_idx_list = "";
my %admin_pids = ();
my $admin_pid_list = ""; my $admin_pid_list = "";
# Get group information for input User. # Get group information for input User.
...@@ -945,8 +950,6 @@ sub GetAllowedLeases($$;$) { ...@@ -945,8 +950,6 @@ sub GetAllowedLeases($$;$) {
$admin_pids{$group->pid()} = 1; $admin_pids{$group->pid()} = 1;
} }
} }
# Create admin and overall membership list strings for groups the
# user is in. Used in the SQL query below.
$gid_idx_list = join ",", map {$_->gid_idx()} @ugroups; $gid_idx_list = join ",", map {$_->gid_idx()} @ugroups;
$admin_pid_list = join ",", keys %admin_pids; $admin_pid_list = join ",", keys %admin_pids;
} else { } else {
...@@ -955,25 +958,53 @@ sub GetAllowedLeases($$;$) { ...@@ -955,25 +958,53 @@ sub GetAllowedLeases($$;$) {
return undef; return undef;
} }
# Construct the "where" clause for this user based on the information # Users have full access to leases they own, and for leases in
# collected above. # projects that they have group_root (or above) trust in.
$wclause = "where (pl.owner_uid='$uid'"; # Note: Skip if user is not local to site.
if ($admin_pid_list) { if ($upid->IsLocal()) {
$wclause .= " or (pl.pid in ($admin_pid_list))"; $wclause = "where owner_uid='$uid'";
if ($admin_pid_list) {
$wclause .= " or pid in ($admin_pid_list)";
}
my $query_result =
DBQueryWarn("select lease_idx from project_leases".
" $wclause order by lease_idx");
if ($query_result) {
while (my ($lease_idx) = $query_result->fetchrow_array()) {
$lease_indexes{$lease_idx} = 1; # "modify rights" == 1
}
}
} }
$wclause .= " or (lp.permission_type='user'".
" and lp.permission_idx='$uid_idx')"; # Conjure "where" clause for lease_permissions table query below.
if ($gid_idx_list) { if ($upid->IsLocal()) {
$wclause .= " or (lp.permission_type='group'". # User is local to site - look for several conditions:
" and lp.permission_idx in ($gid_idx_list))"; # * Any global permissions.
# * Leases with user permissions matching input user.
# * Leases with group permissions matching any group user is in.
$wclause = "where (permission_type='global'".
" or (permission_type='user' and".
" permission_idx='$uid_idx')";
if ($gid_idx_list) {
$wclause .=
" or (permission_type='group' and".
" permission_idx in ($gid_idx_list))";
}
$wclause .= ")";
} else {
# User is non-local - only look for anonymous RO permissions.
$idxstr = GLOBAL_PERM_ANON_RO_IDX();
$wclause = "where (permission_type='global' and".
" permission_idx='$idxstr')";
} }
$wclause .= ")";
} }
# Construct "where" clause for a Project principal. # The case for Project principals is easy: just construct a "where"
# clause for the lease_permissions table query below.
elsif (ref($upid) == "Project") { elsif (ref($upid) == "Project") {
my $pid_idx = $upid->pid_idx(); my $pid_idx = $upid->pid_idx();
$wclause = "where lp.permissions_type='group'". $wclause = "where (permission_type='global'".
" and lp.permission_idx='$pid_idx'"; " or (permission_type='group' and".
" permission_idx='$pid_idx'))";
} }
# Input principal argument must be either a User or Project argument. # Input principal argument must be either a User or Project argument.
else { else {
...@@ -982,7 +1013,7 @@ sub GetAllowedLeases($$;$) { ...@@ -982,7 +1013,7 @@ sub GetAllowedLeases($$;$) {
return undef; return undef;
} }
# Build up type selector clause to add to where clause, if requested. # Build up type selector clause, if requested.
my $tclause = ""; my $tclause = "";
if (defined($type)) { if (defined($type)) {
if (_validLeaseType($type)) { if (_validLeaseType($type)) {
...@@ -993,52 +1024,42 @@ sub GetAllowedLeases($$;$) { ...@@ -993,52 +1024,42 @@ sub GetAllowedLeases($$;$) {
} }
} }
# Now perform the constructed query. # Grab all lease permissions entries that pertain to the user or project
my $query_result = my $query_result =
DBQueryWarn("select distinct pl.lease_idx,lp.allow_modify". DBQueryWarn("select lease_idx, modify".
" from project_leases as pl". " from lease_permissions".
" left join lease_permissions as lp". " $wclause $tclause order by lease_idx");
" on pl.lease_idx = lp.lease_idx".
" $wclause $tclause order by pl.lease_idx");
return ()
if (!$query_result || !$query_result->numrows);
# Loop through result set and process. Augment permissions for # Loop through result set and process. Augment permissions for
# lease owners and users with group_root in lease's owning project. # lease owners and users with group_root in lease's owning project.
# There will be duplicate lease_idx values in the results if there # There will be duplicate lease_idx values in the results if there
# are multiple entries for the lease in the lease_permissions table. # are multiple entries for the lease in the lease_permissions table.
# Handle this by storing the result set in a hash table. # Handle this by storing the result set in a hash table.
while (my ($lease_idx, $modify) = $query_result->fetchrow_array()) { if ($query_result) {
my $lease; while (my ($lease_idx, $modify) = $query_result->fetchrow_array()) {
if (!exists($leases{$lease_idx})) { if (!exists($lease_indexes{$lease_idx})) {
$lease = $leases{$lease_idx} = Lookup($class, $lease_idx); $lease_indexes{$lease_idx} = 0;
# Failing to get a Lease object for a lease we just found }
# with the above DB query is both odd and fatal. # If _any_ permissions found for a lease allow for
return () # modification, then it is allowed (greatest privilege for
if !$lease; # the same lease wins out).
# Initialize modify setting - defaults to read-only (0). $modify = ($modify || $lease_indexes{$lease_idx}) ? 1 : 0;
$lease->allow_modify(0); $lease_indexes{$lease_idx} = $modify;
} else {
$lease = $leases{$lease_idx};
} }
}
# The lease's owner, and admins in the project that the lease # Fetch all of the leases and send them back to caller.
# belongs to _always_ have full rights. while (my ($lease_idx, $modify) = each %lease_indexes) {
if ($uid && ($uid eq $lease->owner_uid() || my $lease = Lookup($class, $lease_idx);
exists($admin_pids{$lease->pid()}))) if (!$lease) {
{ print STDERR "Lease::GetAllowedLeases(): unable to lookup lease with index $lease_idx!\n";
$modify = 1; next;
} }
# If _any_ permissions found for a lease allow for
# modification, then it is allowed (greatest privilege for
# the same lease wins out).
$modify = ($modify || $lease->allow_modify()) ? 1 : 0;
$lease->allow_modify($modify); $lease->allow_modify($modify);
push (@leases, $lease);
} }
return values %leases; return @leases;
} }
# #
...@@ -1333,7 +1354,24 @@ sub AccessCheck($$$) { ...@@ -1333,7 +1354,24 @@ sub AccessCheck($$$) {
if !defined($qres); if !defined($qres);
while (my ($perm_type, $perm_idx, $modify) = $qres->fetchrow_array()) { while (my ($perm_type, $perm_idx, $modify) = $qres->fetchrow_array()) {
if ($perm_type eq "group") { if ($perm_type eq "global") {
# A lease with anonymous global read-only access is available
# to everyone. Force entry to be read-only.
if ($perm_idx == GLOBAL_PERM_ANON_RO_IDX()) {
$modify = 0; # Force!
}
# A lease with global read-only access for registered users
# requires that the incoming user be a "real" user. I.e.,
# not the geni user. Force entry to be read-only.
elsif ($perm_idx == GLOBAL_PERM_USER_RO_IDX()) {
next unless $user->IsLocal();
$modify = 0; # Force!
}
else {
# Unknown global permissions entry - skip!
next;
}
} elsif ($perm_type eq "group") {
# If the user is a member of this group and has a minimum of # If the user is a member of this group and has a minimum of
# trust, then give them the access listed in the db. # trust, then give them the access listed in the db.
my $dbgroup = Group->Lookup($perm_idx); my $dbgroup = Group->Lookup($perm_idx);
...@@ -1382,6 +1420,18 @@ sub GrantAccess($$$) ...@@ -1382,6 +1420,18 @@ sub GrantAccess($$$)
$perm_id = $target->pid() . "/" . $target->gid(); $perm_id = $target->pid() . "/" . $target->gid();
$perm_type = "group"; $perm_type = "group";
} }
elsif ($target eq GLOBAL_PERM_ANON_RO()) {
$perm_idx = GLOBAL_PERM_ANON_RO_IDX();
$perm_id = GLOBAL_PERM_ANON_RO();
$perm_type = "global";
$modify = 0; # Force
}
elsif ($target eq GLOBAL_PERM_USER_RO()) {
$perm_idx = GLOBAL_PERM_USER_RO_IDX();
$perm_id = GLOBAL_PERM_USER_RO();
$perm_type = "global";
$modify = 0; # Force
}
else { else {
print STDERR "Lease->GrantAccess: Bad target: $target\n"; print STDERR "Lease->GrantAccess: Bad target: $target\n";
return LEASE_ERROR_FAILED(); return LEASE_ERROR_FAILED();
...@@ -1416,6 +1466,14 @@ sub RevokeAccess($$) ...@@ -1416,6 +1466,14 @@ sub RevokeAccess($$)
$perm_idx = $target->gid_idx(); $perm_idx = $target->gid_idx();
$perm_type = "group"; $perm_type = "group";
} }
elsif ($target eq GLOBAL_PERM_ANON_RO()) {
$perm_idx = GLOBAL_PERM_ANON_RO_IDX();
$perm_type = "global";
}
elsif ($target eq GLOBAL_PERM_USER_RO()) {
$perm_idx = GLOBAL_PERM_USER_RO_IDX();
$perm_type = "global";
}
else { else {
print STDERR "Lease->RevokeAccess: Bad target: $target\n"; print STDERR "Lease->RevokeAccess: Bad target: $target\n";
return LEASE_ERROR_FAILED(); return LEASE_ERROR_FAILED();
......
#
# Update lease_permissions to take global permissions entries.
#
use strict;
use libdb;
sub DoUpdate($$$)
{
my ($dbhandle, $dbname, $version) = @_;
if (DBSlotExists("lease_permissions", "permission_type")) {
DBQueryFatal("alter table lease_permissions change permission_type ".
"permission_type enum('user','group','global') ".
"NOT NULL default 'user'");
}
return 0;
}
# Local Variables:
# mode:perl
# End:
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment