Commit be190ada authored by Leigh B Stoller's avatar Leigh B Stoller

Clean up and refactor credential handling in the dataset code.

Watch for and adapt if the user certificate/speaksfor is expired,
need to use an SA auth credential.
parent 6879d0f0
......@@ -104,7 +104,7 @@ sub DoExtend();
sub DoSnapshot();
sub DoSnapShotInternal($$$$$);
sub PollDatasetStatus($$$);
sub DoImageTrackerStuff($$$$);
sub DoImageTrackerStuff($$$$$);
#
# Parse command arguments. Once we return from getopts, all that should be
......@@ -309,6 +309,13 @@ sub DoCreate()
fatal("Dataset already exists!");
}
# Check for expired certs and speaksfor.
if (my $retval = APT_Geni::VerifyCredentials($geniuser, \$errmsg)) {
if ($retval) {
($retval < 0 ? fatal($errmsg) : uerror($errmsg));
}
}
my $blob = {
"dataset_id" => $name,
"pid" => $project->pid(),
......@@ -514,6 +521,8 @@ sub DoRefreshInternal($$)
$dataset->Update({"last_used" => TBDateStringLocal($blob->{"lastused"}),
"expires" => TBDateStringLocal($blob->{"expires"})});
$dataset->Update({"updated" => TBDateStringLocal($blob->{"updated"})})
if ($blob->{"updated"});
if ($blob->{"busy"}) {
$dataset->Update({"state" => "busy"});
......@@ -705,7 +714,8 @@ sub DoSnapshot()
fatal("Could not find aggregate for $nodeid");
}
if (GetSiteVar("protogeni/use_imagetracker")) {
if (DoImageTrackerStuff($dataset,\$copyback_uuid,\$sha1hash,\$errmsg)) {
if (DoImageTrackerStuff($dataset, $aggregate,
\$copyback_uuid,\$sha1hash,\$errmsg)) {
fatal("Could not get info from image tracker");
}
}
......@@ -968,9 +978,15 @@ sub DoGetCredential()
$dataset->Unlock();
uerror("dataset was busy at the remote cluster, try again later");
}
if ($response->code() == GENIRESPONSE_SEARCHFAILED) {
$dataset->Unlock();
uerror("dataset could not be found at the remote cluster");
}
$credential = GeniCredential->CreateFromSigned($response->value());
if (!defined($credential)) {
$dataset->Unlock();
fatal("Could not parse new credential")
if (!defined($credential));
}
$dataset->Update({"credential_string" => $response->value()});
haveit:
if (defined($authority)) {
......@@ -988,12 +1004,20 @@ sub DoGetCredential()
fatal($errmsg);
}
sub DoImageTrackerStuff($$$$)
sub DoImageTrackerStuff($$$$$)
{
my ($dataset, $puuid, $phash, $perrmsg) = @_;
my $remote_urn = $dataset->remote_urn();
my ($dataset, $aggregate, $puuid, $phash, $perrmsg) = @_;
my $remote_urn = GeniHRN->new($dataset->remote_urn());
my $aggregate_urn = GeniHRN->new($aggregate->aggregate_urn());
my $errmsg;
#
# If the dataset is being used on the cluster where it lives, then
# there is no need for any of this.
#
return 0
if (lc($remote_urn->domain()) eq lc($aggregate_urn->domain()));
Genixmlrpc->SetContext(APT_Geni::GeniContext());
my $blob = GeniImage::GetImageData($remote_urn, \$errmsg);
Genixmlrpc->SetContext(undef);
......@@ -1003,6 +1027,7 @@ sub DoImageTrackerStuff($$$$)
"$remote_urn:\n" . $errmsg;
return 1;
}
$$puuid = $blob->{'version_uuid'} if (defined($puuid));
$$phash = $blob->{'sha1hash'} if (defined($phash));
return 0;
......@@ -1021,7 +1046,8 @@ sub PollImageStatus($$$)
if ($dataset->_copying()) {
my $sha1hash;
if (DoImageTrackerStuff($dataset, undef, \$sha1hash, $perrmsg)) {
if (DoImageTrackerStuff($dataset, $aggregate,
undef, \$sha1hash, $perrmsg)) {
print STDERR $perrmsg . "\n";
# Give up.
$dataset->Update({"state" => "valid"});
......
......@@ -458,6 +458,32 @@ sub LookupByOriginURN($$)
return Image->Lookup($imageid, $version);
}
#
# Lookup by Authority URN. Only for datasets right now.
#
sub LookupByAuthorityURN($$)
{
my ($class, $urn) = @_;
return undef
if (! $PGENISUPPORT);
require GeniHRN;
return undef
if (!GeniHRN::IsValid($urn));
my $safe_urn = DBQuoteSpecial($urn);
my $query_result =
DBQueryWarn("select distinct imageid from image_versions ".
"where authority_urn=$safe_urn and deleted is null");
return undef
if (!$query_result || !$query_result->numrows);
my ($imageid) = $query_result->fetchrow_array();
return Image->Lookup($imageid);
}
#
# Get a list of all running frisbee images.
# XXX if this is actually used, it will have to be fixed; DB no longer
......
......@@ -2120,7 +2120,7 @@ sub GetProject($)
#
# Lookup by origin, as for portal created leases.
#
sub LookupByOriginURN($$)
sub LookupByAuthorityURN($$)
{
my ($class, $urn) = @_;
......@@ -2134,8 +2134,8 @@ sub LookupByOriginURN($$)
my $safe_urn = DBQuoteSpecial($urn);
my $query_result =
DBQueryWarn("select lease_idx from project_leases ".
"where origin_urn=$safe_urn");
DBQueryWarn("select lease_idx from lease_attributes ".
"where attrkey='authority_urn' and attrval=$safe_urn");
return undef
if (!$query_result || !$query_result->numrows);
......
This diff is collapsed.
#
# Copyright (c) 2008-2015 University of Utah and the Flux Group.
# Copyright (c) 2008-2016 University of Utah and the Flux Group.
#
# {{{GENIPUBLIC-LICENSE
#
......@@ -52,7 +52,7 @@ PSBIN_STUFF = register_resources expire_daemon gencrl postcrl \
mondbd parsecert creategeniuser webcreategeniuser \
updategeniuser webupdategeniuser verifycert webverifycert \
postimagedata getimagedata triggerimageupdate \
deleteimagedata
deleteimagedata secureimageget
ifeq ($(ISCLEARINGHOUSE),1)
PSBIN_STUFF += ch_daemon
......
#!/usr/bin/perl -w
#
# Copyright (c) 2008-2016 University of Utah and the Flux Group.
#
# {{{GENIPUBLIC-LICENSE
#
# GENI Public License
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and/or hardware specification (the "Work") to
# deal in the Work without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Work, and to permit persons to whom the Work
# is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Work.
#
# THE WORK IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE WORK OR THE USE OR OTHER DEALINGS
# IN THE WORK.
#
# }}}
#
use strict;
use English;
use Getopt::Std;
use Date::Parse;
use Data::Dumper;
#
# Upload image data to the image server.
#
sub usage()
{
print "Usage: secureimageget [-n] [-d] [-u user] ".
"[-c credfile] -o outfile imageid\n";
exit(1);
}
my $optlist = "ndvc:u:o:";
my $impotent = 0;
my $debug = 0;
my $verbose = 0;
my $credfile;
my $outfile;
my $outfp;
my $user;
my $credential;
#
# Configure variables
#
my $TB = "@prefix@";
my $TBOPS = "@TBOPSEMAIL@";
my $TBLOGS = "@TBLOGSEMAIL@";
my $PGENIDOMAIN = "@PROTOGENI_DOMAIN@";
my $PGENISUPPORT = @PROTOGENI_SUPPORT@;
my $PGENILOCALUSER= @PROTOGENI_LOCALUSER@;
my $CMCERT = "$TB/etc/genicm.pem";
my $OURDOMAIN = "@OURDOMAIN@";
# un-taint path
$ENV{'PATH'} = '/bin:/usr/bin:/usr/local/bin:/usr/site/bin';
delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
# Protos
sub fatal($);
sub GetServerCredential();
sub PostImageInfo($);
#
# Turn off line buffering on output
#
$| = 1;
# Now we can load the libraries after setting the proper DB.
use lib '@prefix@/lib';
use emutil;
use GeniDB;
use EmulabConstants;
use GeniCertificate;
use GeniAuthority;
use GeniUser;
use GeniHRN;
use Genixmlrpc;
use libEmulab;
use Image;
use User;
use Group;
use OSinfo;
if (!$PGENISUPPORT) {
print STDERR "You are not a protogeni site\n";
exit(0);
}
#
# Check args.
#
my %options = ();
if (! getopts($optlist, \%options)) {
usage();
}
if (defined($options{"n"})) {
$impotent = 1;
}
if (defined($options{"d"})) {
$debug = 1;
}
if (defined($options{"v"})) {
$verbose = 1;
}
if (defined($options{"c"})) {
$credfile = $options{"c"};
}
if (defined($options{"o"})) {
$outfile = $options{"o"};
}
if (defined($options{"u"})) {
$user = $options{"u"};
}
usage()
if (! (@ARGV && $outfile));
my $image = Image->Lookup($ARGV[0]);
fatal("No such image")
if (!defined($image));
if (defined($user)) {
my $local_user = User->Lookup($user);
fatal("No such user")
if (!defined($local_user));
$local_user = GeniUser->CreateFromLocal($local_user);
my $context = Genixmlrpc->UserContext($local_user);
if (!defined($context)) {
fatal("Could not create context to talk to image server");
}
Genixmlrpc->SetContext($context);
}
else {
#
# Load the CM cert to act as caller context.
#
my $certificate = GeniCertificate->LoadFromFile($CMCERT);
if (!defined($certificate)) {
fatal("Could not load certificate from $CMCERT\n");
}
my $context = Genixmlrpc->Context($certificate);
if (!defined($context)) {
fatal("Could not create context to talk to image server");
}
Genixmlrpc->SetContext($context);
}
if (defined($credfile)) {
$credential = GeniCredential->LoadFromFile($credfile);
}
else {
$credential = $image->GetCredential();
}
fatal("Could not load credential")
if (!defined($credential));
fatal("Not allowed to write to output file")
if (-e $outfile && !-w $outfile);
open(FD, ">$outfile")
or fatal("Could not open output file for writing: $!");
$outfp = *FD;
#
# Derive the authority where the image lives, from the credential.
#
my ($signer_cert) = @{ $credential->signer_certs() };
fatal("Could not find signer certificate for credential")
if (!defined($signer_cert));
my $signer = GeniCertificate->LoadFromString($signer_cert);
fatal("Could not load signer certificate for credential")
if (!defined($signer));
my $authority = GeniAuthority->CreateFromRegistry("cm", $signer->urn());
fatal("Could not lookup authority: " . $signer->urn())
if (!defined($authority));
my $cmurl = $authority->url();
$cmurl =~ s/protogeni/protogeni\/stoller/;
#
# Suck over some bits.
#
my $response =
Genixmlrpc::CallMethodStream($cmurl, undef, $outfp, "SecureImageDownload",
{"credentials" => [$credential->asString()]});
if (!defined($response) || $response->code()) {
my $msg = "SecureImageDownload failed for image " . $image->versname() . " :";
if (!defined($response)) {
# Bail, we will try again later.
print STDERR "$msg RPC error\n";
exit(-1);
}
elsif (defined($response->output())) {
print STDERR "$msg " . $response->output() . "\n";
exit(-1);
}
else {
print STDERR "$msg " . $response->code() . "\n";
exit(-1);
}
}
close($outfp);
exit(0);
sub fatal($)
{
my ($msg) = @_;
print STDERR "*** $0:\n".
" $msg\n";
# exit value important.
exit(-1);
}
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