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

Bug Fix: a bunch of fixes to make sure that holders of SFA credentials

can create slices, and be notified of expiring slices and slivers. The
problem is the PL credentials do not inclide an email address, so we
have to get it from the user's registry. This required a bunch of goo
top find the proper place to do a resolve, since PL credentials do not
include a URL either.
parent 00d563f3
......@@ -26,6 +26,7 @@ use emutil;
use Compress::Zlib;
use MIME::Base64;
use XML::LibXML;
use URI;
use Data::Dumper;
use Frontier::RPC2;
......@@ -249,12 +250,11 @@ sub auto_add_sa($)
}
my $url = $certificate->URL();
if (!defined($url)) {
print STDERR "auto_add_sa: certificate does not have a URI extension";
return;
print STDERR "auto_add_sa: certificate does not have a URL extension\n";
}
my $urn = $certificate->urn();
if (!defined($urn)) {
print STDERR "auto_add_sa: certificate does not have a URN extension";
print STDERR "auto_add_sa: certificate does not have a URN extension\n";
return;
}
# Look to see if already registered.
......@@ -267,20 +267,62 @@ sub auto_add_sa($)
if ($certificate->SameCert($authority->GetCertificate()));
#
# Do nothing; needs more thought. The problem is that the caller
# could be from a conforming PG authority, and so setting the url
# to undef in the code below is wrong. We should probably probe the
# SA here, to see if it is conforming. Or maybe set the URL and not
# worry of the sliver registration throws an error.
# Not sure what is the right thing yet ...
#
return;
}
#
# We want the URL!
#
# First get the list of registries from PLC.
my $registry = GeniRegistry::PLC->Create();
if (!defined($registry)) {
print STDERR "Cannot create a PLC registry object\n";
return;
}
my $blob;
if ($registry->GetRegistries(\$blob)) {
print STDERR "Cannot get PLC registry listing\n";
return;
}
print STDERR Dumper($blob);
#
# Now look at the last signer certificate; this is the actual authority.
#
my $authcertstr = @$signers[scalar(@$signers) - 1];
my $authcert = GeniCertificate->LoadFromString($authcertstr);
if (!defined($authcert)) {
print STDERR "auto_add_sa: could not get certificate from $authcertstr\n";
return;
}
my $authurn = $authcert->urn();
if (!defined($authurn)) {
print STDERR "auto_add_sa: $authcert does not have a URN extension\n";
return;
}
# if we're auto adding an authority, set the url to null
# so the PG/Emulab machinery does not try to contact the
# dynamic sa. It probably won't respond to the PG/Emulab
# protocols.
$url = undef;
#
# Now search ...
#
foreach my $ref (@$blob) {
if ($ref->{'urn'} eq $authurn) {
$url = $ref->{'url'};
last;
}
}
if (!defined($url)) {
print STDERR "auto_add_sa: could not get a URL for $authcert\n";
return;
}
#
# Gack. Replace the URL with a modified URL which says https.
# Why does PLC set the scheme to http?
#
my $uri = URI->new($url);
$uri->scheme("https");
$url = "$uri";
if (!GeniAuthority->Create($certificate, $url, "sa")) {
print STDERR "auto_add_sa: unable to add authority\n";
return;
......
......@@ -518,6 +518,23 @@ sub Resolve($$)
print STDERR "Need an RPC context to generate a self credential\n";
return undef;
}
#
# Gack, if this is an SFA, hand off to the registry module, since it
# knows how to get to the registry.
#
if ($self->IsSFA()) {
my $registry = GeniRegistry::PLC->CreateFromAuthority($self);
if (!defined($registry)) {
print "Could not create an SFA registry from $self\n";
return undef;
}
return $registry->Resolve($urn);
}
#
# Otherwise we assume a PG authority, and all PG servers do Resolve.
#
my $context = Genixmlrpc->GetContext();
my $me = GeniAuthority->Lookup($context->certificate()->uuid());
if (!defined($me)) {
......
......@@ -492,7 +492,8 @@ sub GetTicketAuxAux($$$$$$$$$)
# ticket is redeemed, it will expire according to the rspec request.
# If nothing specified in the rspec, then it will expire when the
# slice record expires, which was given by the expiration time of the
# slice credential.
# slice credential, or the local policy max_sliver_lifetime. See
# CreateSliceFromCertificate() in this file.
#
my $expires = GeniXML::GetExpires($rspec);
if (defined($expires)) {
......@@ -655,7 +656,7 @@ sub GetTicketAuxAux($$$$$$$$$)
}
# Turn off fixnode; we will control this on the commandline.
$virtexperiment->allowfixnode(0);
$virtexperiment->multiplex_factor(3);
$virtexperiment->multiplex_factor(1);
#
# An rspec is a structure that requests specific nodes. If those
......@@ -2692,6 +2693,14 @@ sub SliverWorkAux($$$$$$$)
$message = "$linkname: Missing nodes for tunnels";
goto bad;
}
print STDERR Dumper([$node1sliver,
$node2sliver,
Serialize($linkref, 1),
Serialize($node1rspec, 1),
Serialize($node2rspec, 1)])
if (0);
my $tunnel = GeniAggregate::Tunnel->Create($slice,
$owner,
$node1sliver,
......@@ -4328,6 +4337,7 @@ sub CreateUserFromCertificate($)
"a new encrypted SSL certificate.\n",
$TBOPS, "BCC: protogeni-errors\@flux.utah.edu");
}
my $urn = $certificate->urn();
# Local users always exist.
my $user = GeniUser->Lookup($certificate->urn(), 1);
......@@ -4354,7 +4364,7 @@ sub CreateUserFromCertificate($)
#
# Check urn. Must be a "user" urn. The uid is checked in Create().
#
my (undef,$type,$uid) = GeniHRN::Parse($certificate->urn());
my (undef,$type,$uid) = GeniHRN::Parse($urn);
if (!defined($uid) || $type ne "user") {
return GeniResponse->Create(GENIRESPONSE_BADARGS, undef,
"Malformed user URN");
......@@ -4373,39 +4383,40 @@ sub CreateUserFromCertificate($)
my $email = $certificate->email();
my $username;
if (!defined($email) || $email eq "" || $email eq "unknown") {
if (! $authority->IsSFA()) {
if (! defined($authority->url()) || !$authority->IsSFA()) {
return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
"Your certificate does not include ".
"an email address");
}
#
# XXX: The SFA stores all records in the central registry, not at
# the SA like we do.
#
my $registry = GeniRegistry->Create($certificate->urn());
print STDERR "No email address in certificate for $urn\n";
print STDERR "Trying to get email from $authority\n";
my $registry = GeniRegistry::PLC->CreateFromAuthority($authority);
if (!defined($registry)) {
return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
"Could not connect to PLC registry ".
"Could not get registry at $authority ".
"to get your email address");
}
my $blob;
if ($registry->Resolve($certificate->urn(), "User", \$blob) != 0) {
my $blob = $registry->Resolve($urn);
if (!defined($blob)) {
return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
"Could not resolve you at the PLC ".
"registry to get your email address");
"Could not resolve you at $registry ".
"to get your email address");
}
# Why does PLC resolve return an array of length one?
$email = $blob->[0]->{'email'};
# Why does PLC return an array?
$blob = $blob->[0];
$email = $blob->{'email'};
if (!defined($email) || $email eq "") {
return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
"Your PLC registry record did ".
"Your authority record did ".
"not include your email address");
}
$username = $blob->[0]->{'first_name'}
if (exists($blob->[0]->{'first_name'}));
$username = ($username ? "$username " : "") . $blob->[0]->{'last_name'}
if (exists($blob->[0]->{'last_name'}));
# This is very PLC specific.
$username = $blob->{'first_name'}
if (exists($blob->{'first_name'}));
$username = ($username ? "$username " : "") . $blob->{'last_name'}
if (exists($blob->{'last_name'}));
$modify = 1;
}
$user = GeniUser->Create($certificate, $authority);
......@@ -4431,18 +4442,15 @@ sub CreateAuthorityFromRegistry($)
my ($certificate) = @_;
my $authority;
if (defined($certificate->urn()) &&
GeniHRN::IsValid($certificate->urn())) {
my ($auth,$type,$id) = GeniHRN::Parse($certificate->urn());
my $sa_urn = GeniHRN::Generate($auth, "authority", "sa");
$authority = GeniAuthority->CreateFromRegistry("SA", $sa_urn);
if (! (defined($certificate->urn()) &&
GeniHRN::IsValid($certificate->urn()))) {
print STDERR "Cannot create authority: No URN in $certificate\n";
return undef;
}
else {
# This prefix stuff will go away when fully converted to urns.
my ($prefix) = ($certificate->uuid() =~ /^\w+\-\w+\-\w+\-\w+\-(\w+)$/);
my ($auth,$type,$id) = GeniHRN::Parse($certificate->urn());
my $sa_urn = GeniHRN::Generate($auth, "authority", "sa");
$authority = GeniAuthority->CreateFromRegistry("SA", $sa_urn);
$authority = GeniAuthority->CreateFromRegistry("SA", "P${prefix}");
}
if (!defined($authority)) {
print STDERR "Could not create authority from registry\n";
return undef;
......
......@@ -675,6 +675,11 @@ sub URL($)
print STDERR "Could not find url in $self\n";
return undef;
}
# Make sure its really a URL!
if (! ($url =~ /^http/)) {
print STDERR "Not a valid url in $self: $url\n";
return undef;
}
$self->{'CERT'}->{'uri'} = $url;
$self->{'URL'} = $url;
return $url;
......
......@@ -441,12 +441,20 @@ sub Resolve($)
return undef
if (!defined($manager_version));
#
# Need a credential to make this call. Seems kinda silly.
#
if (!defined(Genixmlrpc->GetContext())) {
print STDERR "Need an RPC context to generate a self credential\n";
return undef;
}
#
# XXX: The SFA stores all records in the central registry, not at
# the CM like we do.
#
if ($authority->IsSFA()) {
my $registry = GeniRegistry->Create($self->urn());
my $registry = GeniRegistry::PLC->CreateFromAuthority($authority);
return undef
if (!defined($registry));
......@@ -458,13 +466,6 @@ sub Resolve($)
return $blob->[0];
}
#
# Need a credential to make this call. Seems kinda silly.
#
if (!defined(Genixmlrpc->GetContext())) {
print STDERR "Need an RPC context to generate a self credential\n";
return undef;
}
my $context = Genixmlrpc->GetContext();
my $me = GeniAuthority->Lookup($context->certificate()->uuid());
if (!defined($me)) {
......
......@@ -34,8 +34,8 @@ sub Create($$;$$)
return undef
if (!defined($auth));
if ($auth =~ /^plc:/ || $auth eq "ple" || $auth eq "plc") {
return GeniRegistry::PLC->Create($auth, $context);
if ($auth =~ /^plc/) {
return GeniRegistry::PLC->Create($context, $credential);
}
else {
return GeniRegistry::ClearingHouse->Create($context, $credential);
......@@ -588,7 +588,7 @@ use overload ('""' => 'Stringify');
#
sub Create($;$$)
{
my ($class, $aggregate, $context) = @_;
my ($class, $context, $credential) = @_;
$context = Genixmlrpc->GetContext()
if (!defined($context));
......@@ -603,43 +603,31 @@ sub Create($;$$)
print STDERR "Could not find my own authority for $context\n";
return undef;
}
my $credential = GeniCredential->GetSelfCredential($me);
if (!defined($credential)) {
print STDERR "Could not create self credential for $me\n";
return undef;
$credential = GeniCredential->GetSelfCredential($me);
if (!defined($credential)) {
print STDERR "Could not create self credential for $me\n";
return undef;
}
}
#
# At the moment, we hardwire all this.
# XXX Hardwired to PLC.
#
my $url;
if ($aggregate =~ /maxpl/) {
$url = "https://max-myplc.dragon.maxgigapop.net:12345";
}
elsif ($aggregate =~ /ple/) {
$url = "https://www.planet-lab.eu:12345";
}
elsif ($aggregate =~ /plc/) {
$url = "https://www.planet-lab.org:12345";
}
else {
print STDERR "Do not know anything about $aggregate\n";
return undef;
}
my $self = {};
$self->{'url'} = $url;
$self->{'url'} = "https://www.planet-lab.org:12345";
$self->{'urn'} = "";
$self->{'context'} = $context;
$self->{'credential'} = $credential;
$self->{'aggregate'} = $aggregate;
bless($self, $class);
return $self;
}
sub authority($) { return undef; }
sub url($) { return $_[0]->{"url"}; }
sub urn($) { return $_[0]->{"urn"}; }
sub context($) { return $_[0]->{"context"}; }
sub credential($) { return $_[0]->{"credential"}; }
sub aggregate($) { return $_[0]->{"aggregate"}; }
#
# Stringify for output.
......@@ -647,24 +635,57 @@ sub aggregate($) { return $_[0]->{"aggregate"}; }
sub Stringify($)
{
my ($self) = @_;
my $aggregate = $self->aggregate();
my $urn = $self->urn();
return "[GeniRegistry: $aggregate]";
return "[GeniRegistry: $urn]";
}
#
# Lookup a record.
#
sub Resolve($$$$)
sub Resolve($$;$$)
{
my ($self, $urn, $type, $pref) = @_;
$$pref = undef;
$$pref = undef
if (defined($pref));
my $response =
Genixmlrpc::CallMethod($self->url(), $self->context(), "Resolve",
$urn, $self->credential()->asString());
goto bad
if (!defined($response));
if ($response->IsError()) {
print STDERR "Resolve: " . $response->Dump() . "\n"
if ($response->code() != GENIRESPONSE_SEARCHFAILED());
goto bad;
}
return $response->value()
if (!defined($pref));
$$pref = $response->value();
return 0;
bad:
return undef
if (!defined($pref));
return -1;
}
#
# Get the registry list
#
sub GetRegistries($$)
{
my ($self, $pref) = @_;
$$pref = undef;
my $response =
Genixmlrpc::CallMethod($self->url(), $self->context(), "get_registries",
$self->credential()->asString(), "");
return -1
if (!defined($response));
......@@ -678,5 +699,32 @@ sub Resolve($$$$)
return 0;
}
#
# PLC exports three different interfaces, differentiated by port
# number, but all with the same URN. This is really a pain since only
# one of them supports Resolve(), and everything must by resolved
# there.
#
sub CreateFromAuthority($$;$$)
{
my ($class, $authority, $context, $credential) = @_;
require URI;
my $registry = GeniRegistry::PLC->Create($context, $credential);
return undef
if (!defined($registry));
#
# Gack. Replace the URL with a modified URL for the registry we are
# really trying to resolve at. Also change to the proper port number.
#
my $uri = URI->new($authority->url());
$uri->port(12345);
$registry->{'url'} = "$uri";
$registry->{'urn'} = $authority->urn();
return $registry;
}
# _Always_ make sure that this 1 is at the end of the file...
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