Commit d1516912 authored by Leigh Stoller's avatar Leigh Stoller

Deal with user privs (issue #309):

* Make user privs work across remote clusters (including stitching). I
  took a severe shortcut on this; I do not expect the Cloudlab portal
  will ever talk to anything but an Emulab based aggregate, so I just
  added the priv indicator to the user keys array we send over. If I am
  ever proved wrong on this, I will come out of retirement and fix
  it (for a nominal fee of course).

* Do not show the root password for the console to users with user
  privs.

* Make sure users with user privs cannot start experiments.

* Do show the user trust values on the user dashboard membership tab.

* Update tmcd to use the new privs slot in the nonlocal_user_accounts
  table.

This closes issue #309.
parent b8a86a6a
...@@ -708,6 +708,14 @@ sub GetProject($) ...@@ -708,6 +708,14 @@ sub GetProject($)
return Project->Lookup($self->pid_idx()); return Project->Lookup($self->pid_idx());
} }
sub GetGroup($)
{
my ($self) = @_;
require Group;
return Group->Lookup($self->gid_idx());
}
# #
# Warn creator that the experiment is going to expire. This is hooked # Warn creator that the experiment is going to expire. This is hooked
# in from the sa_daemon, so we can send a message that is less geni like # in from the sa_daemon, so we can send a message that is less geni like
...@@ -980,6 +988,9 @@ sub GetSSHKeys($$;$) ...@@ -980,6 +988,9 @@ sub GetSSHKeys($$;$)
my $project = $self->GetProject(); my $project = $self->GetProject();
return -1 return -1
if (!defined($project)); if (!defined($project));
my $group = $self->GetGroup();
return -1
if (!defined($group));
if ($geniuser->GetKeyBundle(\@keys, 1) < 0 || !@keys) { if ($geniuser->GetKeyBundle(\@keys, 1) < 0 || !@keys) {
print STDERR "No ssh keys for $geniuser\n"; print STDERR "No ssh keys for $geniuser\n";
...@@ -991,6 +1002,8 @@ sub GetSSHKeys($$;$) ...@@ -991,6 +1002,8 @@ sub GetSSHKeys($$;$)
# #
$rval = [{'urn' => $geniuser->urn(), $rval = [{'urn' => $geniuser->urn(),
'login' => $geniuser->uid(), 'login' => $geniuser->uid(),
# Creator clearly has root privs!
'privs' => 'root',
'keys' => [ @keys ] 'keys' => [ @keys ]
}]; }];
...@@ -1017,6 +1030,20 @@ sub GetSSHKeys($$;$) ...@@ -1017,6 +1030,20 @@ sub GetSSHKeys($$;$)
next next
if (!defined($guser)); if (!defined($guser));
#
# Watch for local Emulab users with user privs.
# Only Emulab based CMs will do anything with this,
# but that is all we talk to.
#
my $privs = "root";
if ($guser->IsLocal()) {
my $trust = $group->Trust($guser->emulab_user());
if (! TBMinTrust($trust, PROJMEMBERTRUST_LOCALROOT())) {
$privs = "user";
}
}
# #
# So, users coming in from the trusted signer have their keys # So, users coming in from the trusted signer have their keys
# at their home portal. We download those keys whenever they # at their home portal. We download those keys whenever they
...@@ -1034,6 +1061,7 @@ sub GetSSHKeys($$;$) ...@@ -1034,6 +1061,7 @@ sub GetSSHKeys($$;$)
} }
push(@{$rval}, {'urn' => $guser->urn(), push(@{$rval}, {'urn' => $guser->urn(),
'login' => $guser->uid(), 'login' => $guser->uid(),
'privs' => $privs,
'keys' => [ @keys ] 'keys' => [ @keys ]
}); });
} }
......
...@@ -4777,9 +4777,9 @@ sub UnBindNonLocalUsers($) ...@@ -4777,9 +4777,9 @@ sub UnBindNonLocalUsers($)
# #
# Bind nonlocal user to experiment (slice, in Geni). # Bind nonlocal user to experiment (slice, in Geni).
# #
sub BindNonLocalUser($$$$$$) sub BindNonLocalUser($$$$$$;$)
{ {
my ($self, $keys, $uid, $urn, $name, $email) = @_; my ($self, $keys, $uid, $urn, $name, $email, $privs) = @_;
return -1 return -1
if (! ref($self)); if (! ref($self));
...@@ -4824,6 +4824,10 @@ sub BindNonLocalUser($$$$$$) ...@@ -4824,6 +4824,10 @@ sub BindNonLocalUser($$$$$$)
push(@insert_data, "name=$safe_name"); push(@insert_data, "name=$safe_name");
push(@insert_data, "email=$safe_email"); push(@insert_data, "email=$safe_email");
push(@insert_data, "uid_uuid=uuid()"); push(@insert_data, "uid_uuid=uuid()");
if (defined($privs)) {
my $safe_privs = DBQuoteSpecial($privs);
push(@insert_data, "privs=$safe_privs");
}
# Insert into DB. # Insert into DB.
my $insert_result = my $insert_result =
......
#!/usr/bin/perl -wT #!/usr/bin/perl -wT
# #
# Copyright (c) 2008-2016 University of Utah and the Flux Group. # Copyright (c) 2008-2017 University of Utah and the Flux Group.
# #
# {{{GENIPUBLIC-LICENSE # {{{GENIPUBLIC-LICENSE
# #
...@@ -393,8 +393,12 @@ sub CreateSliver() ...@@ -393,8 +393,12 @@ sub CreateSliver()
chomp($key); chomp($key);
push(@user_keys, {'type' => 'ssh', 'key' => $key}); push(@user_keys, {'type' => 'ssh', 'key' => $key});
} }
push(@{$sliver_keys}, {'urn' => $user_urn, my $blob = {'urn' => $user_urn,
'keys' => \@user_keys}); 'keys' => \@user_keys};
if (exists($user->{'privs'})) {
$blob->{'privs'} = $user->{'privs'};
}
push(@{$sliver_keys}, $blob);
} }
} }
# Invoke CreateSliver # Invoke CreateSliver
...@@ -1104,8 +1108,12 @@ sub Provision ...@@ -1104,8 +1108,12 @@ sub Provision
chomp($key); chomp($key);
push(@user_keys, {'type' => 'ssh', 'key' => $key}); push(@user_keys, {'type' => 'ssh', 'key' => $key});
} }
push(@{$sliver_keys}, {'urn' => $user_urn, my $blob = {'urn' => $user_urn,
'keys' => \@user_keys}); 'keys' => \@user_keys};
if (exists($user->{'privs'})) {
$blob->{'privs'} = $user->{'privs'};
}
push(@{$sliver_keys}, $blob);
} }
} }
......
...@@ -7322,6 +7322,7 @@ sub AddKeys($$$) ...@@ -7322,6 +7322,7 @@ sub AddKeys($$$)
my $uid; my $uid;
my $name; my $name;
my $email; my $email;
my $privs = "local_root";
if (exists($ref->{'urn'})) { if (exists($ref->{'urn'})) {
$urn = $ref->{'urn'}; $urn = $ref->{'urn'};
...@@ -7344,6 +7345,10 @@ sub AddKeys($$$) ...@@ -7344,6 +7345,10 @@ sub AddKeys($$$)
} }
# Allow user to override urn token. # Allow user to override urn token.
$uid = $ref->{'login'} if (exists($ref->{'login'})); $uid = $ref->{'login'} if (exists($ref->{'login'}));
# Optional specification of privs.
if (exists($ref->{'privs'}) && $ref->{'privs'} eq "user") {
$privs = "user";
}
# The slice owner is easy. # The slice owner is easy.
if (defined($urn) && $urn eq $owner->urn()) { if (defined($urn) && $urn eq $owner->urn()) {
...@@ -7382,7 +7387,7 @@ sub AddKeys($$$) ...@@ -7382,7 +7387,7 @@ sub AddKeys($$$)
} }
$slice_experiment->BindNonLocalUser(\@keylist, $slice_experiment->BindNonLocalUser(\@keylist,
$uid, $urn, $uid, $urn,
$name, $email) $name, $email, $privs)
== 0 or goto error; == 0 or goto error;
} }
} }
......
...@@ -3523,7 +3523,7 @@ COMMAND_PROTOTYPE(doaccounts) ...@@ -3523,7 +3523,7 @@ COMMAND_PROTOTYPE(doaccounts)
" u.uid,'*', " " u.uid,'*', "
" u.unix_uid+20000," " u.unix_uid+20000,"
" u.name, " " u.name, "
" 'local_root',g.pid,g.gid,g.unix_gid,0, " " u.privs,g.pid,g.gid,g.unix_gid,0, "
" NULL,NULL, " " NULL,NULL, "
" UNIX_TIMESTAMP(u.updated), " " UNIX_TIMESTAMP(u.updated), "
" u.email,'bash', " " u.email,'bash', "
......
...@@ -260,6 +260,10 @@ class Instance ...@@ -260,6 +260,10 @@ class Instance
function Project() { function Project() {
return Project::Lookup($this->pid_idx()); return Project::Lookup($this->pid_idx());
} }
# Group of instance.
function Group() {
return Group::Lookup($this->gid_idx());
}
# #
# Class function to create a new Instance # Class function to create a new Instance
......
...@@ -847,7 +847,7 @@ function needAdminApproval($wanted, $granted, $reason, $message) ...@@ -847,7 +847,7 @@ function needAdminApproval($wanted, $granted, $reason, $message)
function Do_ConsoleURL() function Do_ConsoleURL()
{ {
global $instance, $creator, $this_user, $suexec_output; global $instance, $creator, $this_user, $suexec_output;
global $ajax_args; global $ajax_args, $TBDB_TRUST_LOCALROOT;
if (StatusSetupAjax(0)) { if (StatusSetupAjax(0)) {
return; return;
...@@ -876,10 +876,19 @@ function Do_ConsoleURL() ...@@ -876,10 +876,19 @@ function Do_ConsoleURL()
$webtask->Refresh(); $webtask->Refresh();
if ($retval == 0) { if ($retval == 0) {
#
# If the user has 'user' privs in the current project/group
# then we do not return the root password. They can still look
# at the console though.
#
$group = $instance->Group();
$trust = $group->UserTrust($this_user);
$taskdata = $webtask->TaskData(); $taskdata = $webtask->TaskData();
$blob = array(); $blob = array();
$blob["url"] = $taskdata["url"]; $blob["url"] = $taskdata["url"];
if (isset($taskdata["password"])) { if (isset($taskdata["password"]) &&
TBMinTrust($trust, $TBDB_TRUST_LOCALROOT)) {
$blob["password"] = $taskdata["password"]; $blob["password"] = $taskdata["password"];
} }
if (isset($taskdata["logurl"])) { if (isset($taskdata["logurl"])) {
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
<tr> <tr>
<th>Project</th> <th>Project</th>
<th>Group</th> <th>Group</th>
<th>Trust</th>
<th>Leader</th> <th>Leader</th>
<th>Description</th> <th>Description</th>
</tr> </tr>
...@@ -14,6 +15,7 @@ ...@@ -14,6 +15,7 @@
<td><a href='show-project.php?project=<%- value.pid %>'> <td><a href='show-project.php?project=<%- value.pid %>'>
<%= value.pid %></a></td> <%= value.pid %></a></td>
<td><%= value.pid %></td> <td><%= value.pid %></td>
<td><%= value.trust %></td>
<td style='white-space: nowrap;'> <td style='white-space: nowrap;'>
<a href='user-dashboard.php?user=<%- value.leader_idx %>'> <a href='user-dashboard.php?user=<%- value.leader_idx %>'>
<%- value.leader_name %></a></td> <%- value.leader_name %></a></td>
...@@ -26,6 +28,7 @@ ...@@ -26,6 +28,7 @@
<%= value.pid %></a></td> <%= value.pid %></a></td>
<td><a href='show-group.php?group=<%- group.gid_idx %>'> <td><a href='show-group.php?group=<%- group.gid_idx %>'>
<%= group.gid %></a></td> <%= group.gid %></a></td>
<td><%= group.trust %></td>
<td style='white-space: nowrap;'> <td style='white-space: nowrap;'>
<a href='user-dashboard.php?user=<%- group.leader_idx %>'> <a href='user-dashboard.php?user=<%- group.leader_idx %>'>
<%- group.leader_name %></a></td> <%- group.leader_name %></a></td>
......
<?php <?php
# #
# Copyright (c) 2000-2016 University of Utah and the Flux Group. # Copyright (c) 2000-2017 University of Utah and the Flux Group.
# #
# {{{EMULAB-LICENSE # {{{EMULAB-LICENSE
# #
...@@ -139,7 +139,7 @@ function Do_ClassicDatasetList() ...@@ -139,7 +139,7 @@ function Do_ClassicDatasetList()
function Do_ProjectList() function Do_ProjectList()
{ {
global $this_user, $target_user; global $this_user, $target_user;
global $TB_PROJECT_CREATEEXPT; global $TB_PROJECT_READINFO, $newTrustMap;
if (CheckPageArgs()) { if (CheckPageArgs()) {
return; return;
...@@ -147,7 +147,7 @@ function Do_ProjectList() ...@@ -147,7 +147,7 @@ function Do_ProjectList()
$target_idx = $target_user->uid_idx(); $target_idx = $target_user->uid_idx();
$target_uuid = $target_user->uuid(); $target_uuid = $target_user->uuid();
$results = array(); $results = array();
$projlist = $target_user->ProjectAccessList($TB_PROJECT_CREATEEXPT); $projlist = $target_user->ProjectAccessList($TB_PROJECT_READINFO);
# #
# Cull out the nonlocal projects, we do not want to show those # Cull out the nonlocal projects, we do not want to show those
...@@ -163,6 +163,8 @@ function Do_ProjectList() ...@@ -163,6 +163,8 @@ function Do_ProjectList()
$blob["leader"] = $leader->uid(); $blob["leader"] = $leader->uid();
$blob["leader_name"] = $leader->name(); $blob["leader_name"] = $leader->name();
$blob["leader_idx"] = $leader->idx(); $blob["leader_idx"] = $leader->idx();
$membership = $proj->MemberShipInfo($this_user);
$blob["trust"] = $newTrustMap[$membership["trust"]];
# #
# User membership in subgroups # User membership in subgroups
...@@ -181,7 +183,8 @@ function Do_ProjectList() ...@@ -181,7 +183,8 @@ function Do_ProjectList()
$glob["leader"] = $leader->uid(); $glob["leader"] = $leader->uid();
$glob["leader_idx"] = $leader->idx(); $glob["leader_idx"] = $leader->idx();
$glob["leader_name"] = $leader->name(); $glob["leader_name"] = $leader->name();
$membership = $group->MemberShipInfo($this_user);
$glob["trust"] = $newTrustMap[$membership["trust"]];
$blob["subgroups"][] = $glob; $blob["subgroups"][] = $glob;
} }
} }
......
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