Commit c85367b4 authored by Leigh B. Stoller's avatar Leigh B. Stoller

Checkpoint

parent 3e2702be
...@@ -24,6 +24,8 @@ CREATE TABLE `geni_users` ( ...@@ -24,6 +24,8 @@ CREATE TABLE `geni_users` (
`idx` mediumint(8) unsigned NOT NULL default '0', `idx` mediumint(8) unsigned NOT NULL default '0',
`uuid` varchar(40) NOT NULL default '', `uuid` varchar(40) NOT NULL default '',
`created` datetime default NULL, `created` datetime default NULL,
`expires` datetime default NULL,
`locked` datetime default NULL,
`archived` datetime default NULL, `archived` datetime default NULL,
`status` enum('active','archived','frozen') NOT NULL default 'frozen', `status` enum('active','archived','frozen') NOT NULL default 'frozen',
`name` tinytext, `name` tinytext,
...@@ -100,6 +102,8 @@ CREATE TABLE `geni_slices` ( ...@@ -100,6 +102,8 @@ CREATE TABLE `geni_slices` (
`uuid` varchar(40) NOT NULL default '', `uuid` varchar(40) NOT NULL default '',
`exptidx` int(11) default NULL, `exptidx` int(11) default NULL,
`created` datetime default NULL, `created` datetime default NULL,
`expires` datetime default NULL,
`locked` datetime default NULL,
`creator_uuid` varchar(40) NOT NULL default '', `creator_uuid` varchar(40) NOT NULL default '',
`name` tinytext, `name` tinytext,
`sa_uuid` varchar(40) NOT NULL default '', `sa_uuid` varchar(40) NOT NULL default '',
...@@ -123,6 +127,8 @@ CREATE TABLE `geni_slivers` ( ...@@ -123,6 +127,8 @@ CREATE TABLE `geni_slivers` (
`resource_uuid` varchar(40) NOT NULL default '', `resource_uuid` varchar(40) NOT NULL default '',
`resource_type` varchar(40) NOT NULL default '', `resource_type` varchar(40) NOT NULL default '',
`created` datetime default NULL, `created` datetime default NULL,
`expires` datetime default NULL,
`locked` datetime default NULL,
`credential_idx` int(10) unsigned default NULL, `credential_idx` int(10) unsigned default NULL,
`component_uuid` varchar(40) default NULL, `component_uuid` varchar(40) default NULL,
`aggregate_uuid` varchar(40) default NULL, `aggregate_uuid` varchar(40) default NULL,
...@@ -146,6 +152,8 @@ CREATE TABLE `geni_aggregates` ( ...@@ -146,6 +152,8 @@ CREATE TABLE `geni_aggregates` (
`slice_uuid` varchar(40) NOT NULL default '', `slice_uuid` varchar(40) NOT NULL default '',
`creator_uuid` varchar(40) NOT NULL default '', `creator_uuid` varchar(40) NOT NULL default '',
`created` datetime default NULL, `created` datetime default NULL,
`expires` datetime default NULL,
`locked` datetime default NULL,
`credential_idx` int(10) unsigned default NULL, `credential_idx` int(10) unsigned default NULL,
`component_idx` int(10) unsigned NOT NULL default '0', `component_idx` int(10) unsigned NOT NULL default '0',
`aggregate_idx` int(10) unsigned default NULL, `aggregate_idx` int(10) unsigned default NULL,
...@@ -166,6 +174,7 @@ CREATE TABLE `geni_tickets` ( ...@@ -166,6 +174,7 @@ CREATE TABLE `geni_tickets` (
`slice_uuid` varchar(40) NOT NULL default '', `slice_uuid` varchar(40) NOT NULL default '',
`created` datetime default NULL, `created` datetime default NULL,
`redeem_before` datetime default NULL, `redeem_before` datetime default NULL,
`locked` datetime default NULL,
`valid_until` datetime default NULL, `valid_until` datetime default NULL,
`component_uuid` varchar(40) NOT NULL default '', `component_uuid` varchar(40) NOT NULL default '',
`seqno` int(10) unsigned NOT NULL default '0', `seqno` int(10) unsigned NOT NULL default '0',
......
...@@ -19,7 +19,7 @@ LIB_SCRIPTS = GeniDB.pm GeniUser.pm GeniSAClient.pm \ ...@@ -19,7 +19,7 @@ LIB_SCRIPTS = GeniDB.pm GeniUser.pm GeniSAClient.pm \
GeniUtil.pm GeniRegistry.pm GeniUtil.pm GeniRegistry.pm
SBIN_SCRIPTS = plabnodewrapper plabslicewrapper SBIN_SCRIPTS = plabnodewrapper plabslicewrapper
SCRIPTS = test.pl addnode.pl test.pl addauthority SCRIPTS = test.pl addnode.pl
#OPS_LIBS = GeniCMClient.pm GeniSAClient.pm #OPS_LIBS = GeniCMClient.pm GeniSAClient.pm
# These scripts installed setuid, with sudo. # These scripts installed setuid, with sudo.
......
This diff is collapsed.
...@@ -230,6 +230,7 @@ sub LoadFromString($$) ...@@ -230,6 +230,7 @@ sub LoadFromString($$)
my $certificate = GeniCertificate->LoadFromFile($filename); my $certificate = GeniCertificate->LoadFromFile($filename);
unlink($filename); unlink($filename);
$certificate->{'CERT'}->{'certfile'} = undef;
return $certificate; return $certificate;
} }
......
...@@ -399,7 +399,7 @@ sub Sign($$) ...@@ -399,7 +399,7 @@ sub Sign($$)
if (ref($how)) { if (ref($how)) {
# This will auto delete too. # This will auto delete too.
my $certfile = $how->certfile() || $how->WriteToFile(); my $certfile = $how->certfile() || $how->WriteToFile(1);
if (!defined($certfile)) { if (!defined($certfile)) {
print STDERR "Could not write $how to temp file\n"; print STDERR "Could not write $how to temp file\n";
return -1; return -1;
......
...@@ -133,7 +133,8 @@ sub GetCredential($) ...@@ -133,7 +133,8 @@ sub GetCredential($)
if (!defined($slice)); if (!defined($slice));
return GeniResponse->Create(GENIRESPONSE_FORBIDDEN, undef, return GeniResponse->Create(GENIRESPONSE_FORBIDDEN, undef,
"Not your slice!") "Not your slice!")
if ($slice->creator_uuid() ne $this_user->uuid()); if ($slice->creator_uuid() ne $this_user->uuid() &&
!$slice->IsBound($this_user));
# #
# Return a credential for the slice. # Return a credential for the slice.
...@@ -250,7 +251,7 @@ sub Resolve($) ...@@ -250,7 +251,7 @@ sub Resolve($)
"hrn" => $geniuser->hrn(), "hrn" => $geniuser->hrn(),
"uuid" => $geniuser->uuid(), "uuid" => $geniuser->uuid(),
"email" => $geniuser->email(), "email" => $geniuser->email(),
"cert" => $geniuser->cert(), "gid" => $geniuser->cert(),
"name" => $geniuser->name(), "name" => $geniuser->name(),
}; };
#$blob->{'sliverkeys'} = \@sliverkeys #$blob->{'sliverkeys'} = \@sliverkeys
...@@ -620,5 +621,111 @@ sub DiscoverResources($) ...@@ -620,5 +621,111 @@ sub DiscoverResources($)
return GeniResponse->Create(GENIRESPONSE_SUCCESS, 0); return GeniResponse->Create(GENIRESPONSE_SUCCESS, 0);
} }
#
# Return ssh keys.
#
sub GetKeys($)
{
my ($argref) = @_;
my $cred = $argref->{'credential'};
if (! defined($cred)) {
return GeniResponse->MalformedArgsResponse();
}
my $credential = GeniCredential->CreateFromSigned($cred);
if (!defined($credential)) {
return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
"Could not create GeniCredential object");
}
#
# Make sure the credential was issued to the caller.
#
if ($credential->owner_uuid() ne $ENV{'GENIUUID'}) {
return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
"This is not your credential!");
}
#
# And that the target of the credential is this registry.
#
my $authority = GeniAuthority->Lookup($ENV{'MYUUID'});
if (!defined($authority)) {
print STDERR "Could not find local authority object\n";
return GeniResponse->Create(GENIRESPONSE_ERROR);
}
if ($credential->target_uuid() ne $authority->uuid()) {
return GeniResponse->Create(GENIRESPONSE_FORBIDDEN,
undef, "This is not your registry!");
}
my $this_user = GeniUser->Lookup($credential->owner_uuid(), 1);
if (!defined($this_user)) {
return GeniResponse->Create(GENIRESPONSE_FORBIDDEN,
undef, "Who are you?");
}
my @keys;
if ($this_user->GetKeys(\@keys) != 0) {
print STDERR "Could not get keys for $this_user\n";
return GeniResponse->Create(GENIRESPONSE_ERROR);
}
return GeniResponse->Create(GENIRESPONSE_SUCCESS, @keys);
}
#
# Bind a user to a slice. The slice creator does this so that the target
# user can request his own credential to manipulate the slice. This is in
# leu of delegation.
#
sub BindToSlice($)
{
my ($argref) = @_;
my $cred = $argref->{'credential'};
my $uuid = $argref->{'uuid'};
if (!defined($uuid) || !defined($cred)) {
return GeniResponse->MalformedArgsResponse();
}
if (!($uuid =~ /^[-\w]*$/)) {
return GeniResponse->MalformedArgsResponse();
}
my $credential = GeniCredential->CreateFromSigned($cred);
if (!defined($credential)) {
return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
"Could not create GeniCredential object");
}
#
# Make sure the credential was issued to the caller.
#
if ($credential->owner_uuid() ne $ENV{'GENIUUID'}) {
return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
"This is not your credential!");
}
my $this_user = GeniUser->Lookup($credential->owner_uuid(), 1);
if (!defined($this_user)) {
return GeniResponse->Create(GENIRESPONSE_FORBIDDEN,
undef, "Who are you?");
}
my $slice = GeniSlice->Lookup($credential->target_uuid());
if (!defined($slice)) {
return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
"Unknown slice for this credential");
}
#
# Locate the target user; must exist locally.
#
my $target_user = GeniUser->Lookup($uuid, 1);
if (!defined($target_user)) {
return GeniResponse->Create(GENIRESPONSE_SEARCHFAILED,
undef, "No such user here");
}
if ($slice->BindUser($target_user) != 0) {
print STDERR "Could not bind $target_user to $slice\n";
return GeniResponse->Create(GENIRESPONSE_ERROR);
}
return GeniResponse->Create(GENIRESPONSE_SUCCESS);
}
# _Always_ make sure that this 1 is at the end of the file... # _Always_ make sure that this 1 is at the end of the file...
1; 1;
...@@ -111,6 +111,7 @@ sub Lookup($$) ...@@ -111,6 +111,7 @@ sub Lookup($$)
} }
$self->{'CERT'} = $certificate; $self->{'CERT'} = $certificate;
$self->{'BINDINGS'} = undef; $self->{'BINDINGS'} = undef;
$self->{'LOCKED'} = 0;
# Add to cache. # Add to cache.
$slices{$self->{'SLICE'}->{'idx'}} = $self; $slices{$self->{'SLICE'}->{'idx'}} = $self;
...@@ -124,10 +125,12 @@ sub hrn($) { return field($_[0], "hrn"); } ...@@ -124,10 +125,12 @@ sub hrn($) { return field($_[0], "hrn"); }
sub uuid($) { return field($_[0], "uuid"); } sub uuid($) { return field($_[0], "uuid"); }
sub creator_uuid($) { return field($_[0], "creator_uuid"); } sub creator_uuid($) { return field($_[0], "creator_uuid"); }
sub created($) { return field($_[0], "created"); } sub created($) { return field($_[0], "created"); }
sub expires($) { return field($_[0], "expires"); }
sub sa_uuid($) { return field($_[0], "sa_uuid"); } sub sa_uuid($) { return field($_[0], "sa_uuid"); }
sub exptidx($) { return field($_[0], "exptidx"); } sub exptidx($) { return field($_[0], "exptidx"); }
sub cert($) { return $_[0]->{'CERT'}->cert(); } sub cert($) { return $_[0]->{'CERT'}->cert(); }
sub GetCertificate($) { return $_[0]->{'CERT'}; } sub GetCertificate($) { return $_[0]->{'CERT'}; }
sub LOCKED($) { return $_[0]->{'LOCKED'}; }
# #
# Stringify for output. # Stringify for output.
...@@ -212,6 +215,7 @@ sub Create($$$$;$) ...@@ -212,6 +215,7 @@ sub Create($$$$;$)
# Now tack on other stuff we need. # Now tack on other stuff we need.
push(@insert_data, "created=now()"); push(@insert_data, "created=now()");
push(@insert_data, "expires=DATE_ADD(now(), INTERVAL 1 HOUR)");
push(@insert_data, "idx='$idx'"); push(@insert_data, "idx='$idx'");
push(@insert_data, "sa_uuid='$sa_uuid'"); push(@insert_data, "sa_uuid='$sa_uuid'");
push(@insert_data, "exptidx=$exptidx") push(@insert_data, "exptidx=$exptidx")
...@@ -237,6 +241,53 @@ sub Create($$$$;$) ...@@ -237,6 +241,53 @@ sub Create($$$$;$)
return GeniSlice->Lookup($idx); return GeniSlice->Lookup($idx);
} }
#
# We lock at a very coarse grain, mostly in the CM. When a slice is busy
# we cannot expire things from it.
#
sub Lock($)
{
my ($self) = @_;
my $idx = $self->idx();
# We already have it locked.
return 0
if ($self->LOCKED());
DBQueryWarn("lock tables geni_slices write")
or return -1;
my $query_result =
DBQueryWarn("select locked from geni_slices ".
"where idx='$idx' and locked is null");
if (!$query_result || !$query_result->numrows) {
DBQueryWarn("unlock tables");
return 1;
}
$query_result =
DBQueryWarn("update geni_slices set locked=now() where idx='$idx'");
DBQueryWarn("unlock tables");
return 1
if (!$query_result);
$self->{'LOCKED'} = $$;
return 0;
}
sub UnLock($)
{
my ($self) = @_;
my $idx = $self->idx();
return 1
if (!$self->LOCKED());
DBQueryWarn("update geni_slices set locked=NULL where idx='$idx'")
or return -1;
$self->{'LOCKED'} = 0;
return 0;
}
# #
# Class function to create new Geni slice from a local experiment. # Class function to create new Geni slice from a local experiment.
# We want to create the key pair so that we can sign credentials. # We want to create the key pair so that we can sign credentials.
...@@ -344,6 +395,16 @@ sub Delete($) ...@@ -344,6 +395,16 @@ sub Delete($)
return 0; return 0;
} }
#
# Flush from our little cache, as for the expire daemon.
#
sub Flush($)
{
my ($self) = @_;
delete($slices{$self->idx()});
}
# #
# Return the emulab experiment for this slice. # Return the emulab experiment for this slice.
# #
...@@ -462,5 +523,52 @@ sub UserBindings($$) ...@@ -462,5 +523,52 @@ sub UserBindings($$)
return 0; return 0;
} }
#
# Is the user bound to a slice.
#
sub IsBound($$)
{
my ($self, $user) = @_;
return -1
if (! (ref($self) && ref($user)));
my $slice_uuid = $self->uuid();
my $user_uuid = $user->uuid();
my $query_result =
DBQueryWarn("select user_uuid from geni_bindings ".
"where slice_uuid='$slice_uuid' and ".
" user_uuid='$user_uuid'");
return 0
if (!$query_result);
return $query_result->numrows();
}
#
# Set the expiration time for a slice.
#
sub SetExpiration($$)
{
my ($self, $expires) = @_;
my $uuid = $self->uuid();
if ($expires =~ /^\d+$/) {
$expires = "FROM_UNIXTIME($expires)";
}
else {
$expires = "'$expires'";
}
my $query_result =
DBQueryWarn("update geni_slices set expires=$expires " .
"where uuid='$uuid'");
return -1
if (!$query_result);
$self->{'SLICE'}->{'expires'} = $expires;
return 0;
}
# _Always_ make sure that this 1 is at the end of the file... # _Always_ make sure that this 1 is at the end of the file...
1; 1;
...@@ -28,6 +28,9 @@ use English; ...@@ -28,6 +28,9 @@ use English;
use XML::Simple; use XML::Simple;
use XML::LibXML; use XML::LibXML;
use Data::Dumper; use Data::Dumper;
use Date::Parse;
use POSIX qw(strftime);
use Time::Local;
use File::Temp qw(tempfile); use File::Temp qw(tempfile);
use overload ('""' => 'Stringify'); use overload ('""' => 'Stringify');
...@@ -78,6 +81,10 @@ sub Lookup($$) ...@@ -78,6 +81,10 @@ sub Lookup($$)
return undef return undef
if (!defined($ticket)); if (!defined($ticket));
# We ignore this in the ticket. In fact, we need to change how we bring
# tickets back into the system.
$ticket->{'redeem_before'} = $row->{'redeem_before'};
# Mark as coming from the DB. # Mark as coming from the DB.
$ticket->{'idx'} = $idx; $ticket->{'idx'} = $idx;
$ticket->{'stored'} = 1; $ticket->{'stored'} = 1;
...@@ -109,6 +116,12 @@ sub Create($$$$) ...@@ -109,6 +116,12 @@ sub Create($$$$)
$self->{'component'} = undef; $self->{'component'} = undef;
$self->{'stored'} = 0; # Stored to the DB. $self->{'stored'} = 0; # Stored to the DB.
#
# For now, all tickets expire very quickly ...
#
$self->{'redeem_before'} =
POSIX::strftime("20%y-%m-%dT%H:%M:%S", localtime(time() + (2*60)));
# #
# Locally generated tickets need a local DB index, which can be the # Locally generated tickets need a local DB index, which can be the
# same as the sequence number. A ticket from a remote component will # same as the sequence number. A ticket from a remote component will
...@@ -136,6 +149,7 @@ sub ticket_uuid($) { return field($_[0], "ticket_uuid"); } ...@@ -136,6 +149,7 @@ sub ticket_uuid($) { return field($_[0], "ticket_uuid"); }
sub ticket($) { return field($_[0], "ticket"); } sub ticket($) { return field($_[0], "ticket"); }
sub asString($) { return field($_[0], "ticket_string"); } sub asString($) { return field($_[0], "ticket_string"); }
sub ticket_string($) { return field($_[0], "ticket_string"); } sub ticket_string($) { return field($_[0], "ticket_string"); }
sub redeem_before($) { return field($_[0], "redeem_before"); }
sub component_uuid($) { return field($_[0], "component_uuid"); } sub component_uuid($) { return field($_[0], "component_uuid"); }
sub component($) { return field($_[0], "component"); } sub component($) { return field($_[0], "component"); }
sub stored($) { return field($_[0], "stored"); } sub stored($) { return field($_[0], "stored"); }
...@@ -157,6 +171,16 @@ sub Stringify($) ...@@ -157,6 +171,16 @@ sub Stringify($)
return "[GeniTicket: $idx, slice:$slice_uuid]"; return "[GeniTicket: $idx, slice:$slice_uuid]";
} }
#
# Flush from our little cache, as for the expire daemon.
#
sub Flush($)
{
my ($self) = @_;
delete($tickets{$self->idx()});
}
# #
# Create a ticket object from a signed ticket string. # Create a ticket object from a signed ticket string.
# #
...@@ -288,6 +312,8 @@ sub CreateFromSignedTicket($$;$$) ...@@ -288,6 +312,8 @@ sub CreateFromSignedTicket($$;$$)
print STDERR "Could not find the ticket $seqno in the DB\n"; print STDERR "Could not find the ticket $seqno in the DB\n";
return undef; return undef;
} }
my $row = $query_result->fetchrow_hashref();
$self->{'redeem_before'} = $row->{'redeem_before'};
$self->{'idx'} = $seqno; $self->{'idx'} = $seqno;
$self->{'stored'} = 1; $self->{'stored'} = 1;
} }
...@@ -349,6 +375,7 @@ sub Store($) ...@@ -349,6 +375,7 @@ sub Store($)
my $slice_uuid = $self->slice_uuid(); my $slice_uuid = $self->slice_uuid();
my $owner_uuid = $self->owner_uuid(); my $owner_uuid = $self->owner_uuid();
my $ticket_uuid= $self->ticket_uuid(); my $ticket_uuid= $self->ticket_uuid();
my $expires = $self->redeem_before();
# #
# For a locally created/signed ticket, seqno=idx. For a ticket from # For a locally created/signed ticket, seqno=idx. For a ticket from
...@@ -370,6 +397,7 @@ sub Store($) ...@@ -370,6 +397,7 @@ sub Store($)
push(@insert_data, "ticket_uuid='$ticket_uuid'"); push(@insert_data, "ticket_uuid='$ticket_uuid'");
push(@insert_data, "slice_uuid='$slice_uuid'"); push(@insert_data, "slice_uuid='$slice_uuid'");
push(@insert_data, "owner_uuid='$owner_uuid'"); push(@insert_data, "owner_uuid='$owner_uuid'");
push(@insert_data, "redeem_before='$expires'");
my $safe_ticket = DBQuoteSpecial($self->ticket_string()); my $safe_ticket = DBQuoteSpecial($self->ticket_string());
push(@insert_data, "ticket_string=$safe_ticket"); push(@insert_data, "ticket_string=$safe_ticket");
...@@ -395,6 +423,7 @@ sub Sign($) ...@@ -395,6 +423,7 @@ sub Sign($)
if (!ref($self)); if (!ref($self));
my $idx = $self->seqno(); my $idx = $self->seqno();
my $expires = $self->redeem_before();
my $slice_cert = $self->slice_cert()->cert(); my $slice_cert = $self->slice_cert()->cert();
my $owner_cert = $self->owner_cert()->cert(); my $owner_cert = $self->owner_cert()->cert();
my $rspec_xml = XMLout($self->rspec(), "NoAttr" => 1); my $rspec_xml = XMLout($self->rspec(), "NoAttr" => 1);
...@@ -406,6 +435,10 @@ sub Sign($) ...@@ -406,6 +435,10 @@ sub Sign($)
my $ticket_uuid = NewUUID(); my $ticket_uuid = NewUUID();
$self->{'ticket_uuid'} = $ticket_uuid; $self->{'ticket_uuid'} = $ticket_uuid;
# Convert to GMT.
$expires = POSIX::strftime("20%y-%m-%dT%H:%M:%S",
gmtime(str2time($expires)));
# #
# Create a template xml file to sign. # Create a template xml file to sign.
# #
...@@ -417,10 +450,10 @@ sub Sign($) ...@@ -417,10 +450,10 @@ sub Sign($)
" <owner_gid>$owner_cert</owner_gid>\n". " <owner_gid>$owner_cert</owner_gid>\n".
" <target_gid>$slice_cert</target_gid>\n". " <target_gid>$slice_cert</target_gid>\n".
" <uuid>$ticket_uuid</uuid>\n". " <uuid>$ticket_uuid</uuid>\n".
" <expires>2008-05-10T09:00:00</expires>\n". " <expires>$expires</expires>\n".
" <ticket>\n". " <ticket>\n".
" <can_delegate>1</can_delegate>\n". " <can_delegate>1</can_delegate>\n".
" <redeem_before>2008-05-10T09:00:00</redeem_before>\n". " <redeem_before>$expires</redeem_before>\n".
" $rspec_xml\n". " $rspec_xml\n".
" </ticket>\n". " </ticket>\n".
"</credential>\n"; "</credential>\n";
...@@ -553,5 +586,22 @@ sub SameTicket($$) ...@@ -553,5 +586,22 @@ sub SameTicket($$)
return $self->idx() == $other->idx(); return $self->idx() == $other->idx();
} }
#
# Check if ticket has expired. Use the DB directly.
#
sub Expired($)
{
my ($self) = @_;
my $idx = $self->idx();
my $query_result =
DBQueryWarn("select idx from geni_tickets ".
"where idx='$idx' and ".
" (UNIX_TIMESTAMP(now()) > ".
" UNIX_TIMESTAMP(redeem_before))");
return $query_result->numrows;
}
# _Always_ make sure that this 1 is at the end of the file... # _Always_ make sure that this 1 is at the end of the file...