Commit 8c6bae5a authored by Leigh Stoller's avatar Leigh Stoller

Checkpoint

parent 3aa90d6b
......@@ -24,6 +24,7 @@ use GeniResponse;
use User;
use GeniUser;
use GeniSlice;
use GeniComponent;
use libtestbed;
use emutil;
use English;
......@@ -84,7 +85,8 @@ sub LookupSlice($)
# Return a blob.
my $blob = { "hrn" => $slice->hrn(),
"uuid" => $slice->uuid(),
"creator_uuid" => $slice->creator_uuid() };
"creator_uuid" => $slice->creator_uuid(),
"cert" => $slice->cert() };
return GeniResponse->Create(GENIRESPONSE_SUCCESS, $blob);
}
......@@ -197,6 +199,7 @@ sub RegisterSlice($)
my $hrn = $argref->{'hrn'};
my $uuid = $argref->{'uuid'};
my $creator_uuid = $argref->{'creator_uuid'};
my $cert = $argref->{'cert'};
if (! (defined($hrn) && defined($uuid) && defined($creator_uuid))) {
return Protogeni::MalformedArgsResponse();
......@@ -210,11 +213,14 @@ sub RegisterSlice($)
return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
"uuid: Invalid characters");
}
if (! ($creator_uuid =~ /^[-\w]*$/)) {
return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
"creator_uuid: Invalid characters");
}
if (! ($cert =~ /^[\012\015\040-\176]*$/)) {
return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
"cert: Invalid characters");
}
#
# Make sure the geni user exists.
......@@ -261,7 +267,8 @@ sub RegisterSlice($)
"Improper format for uuid");
}
my $newslice = GeniSlice->Create($hrn, $uuid, $creator_uuid, $sa_idx);
my $newslice = GeniSlice->Create($hrn, $uuid, $creator_uuid, $cert,
$sa_idx);
if (!defined($newslice)) {
return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
"$hrn/$uuid could not be registered");
......@@ -278,28 +285,30 @@ sub RegisterSlice($)
sub DiscoverResources($)
{
my ($argref) = @_;
my $slice_uuid = $argref->{'slice_uuid'};
my $slice = $argref->{'slice'};
if (!defined($slice_uuid)) {
# This is a certificate. Ignored for now.
if (!defined($slice)) {
return Protogeni::MalformedArgsResponse();
}
if (! ($slice_uuid =~ /^[-\w]*$/)) {
return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
"uuid: Invalid characters");
}
#
# Return simple list of components (hashes).
#
my @results = ();
my $query_result = DBQueryWarn("select uuid,hrn,url from geni_components");
my $query_result = DBQueryWarn("select uuid from geni_components");
return GeniResponse->Create(GENIRESPONSE_DBERROR)
if (!defined($query_result));
while (my ($component_uuid,$hrn,$url) = $query_result->fetchrow_array()) {
while (my ($component_uuid) = $query_result->fetchrow_array()) {
my $component = GeniComponent->Lookup($component_uuid);
return GeniResponse->Create(GENIRESPONSE_DBERROR)
if (!defined($component));
push(@results, { "uuid" => $component_uuid,
"hrn" => $hrn,
"url" => $url});
"hrn" => $component->hrn(),
"url" => $component->url(),
"cert" => $component->cert() });
}
return GeniResponse->Create(GENIRESPONSE_SUCCESS, \@results);
}
......
......@@ -24,7 +24,6 @@ use GeniDB;
use Genixmlrpc;
use GeniResponse;
use User;
use GeniUser;
use libtestbed;
use English;
use Data::Dumper;
......@@ -37,21 +36,21 @@ my $TBAUDIT = "@TBAUDITEMAIL@";
my $BOSSNODE = "@BOSSNODE@";
my $OURDOMAIN = "@OURDOMAIN@";
my $GENICENTRAL = "myboss.little-emulab-bsd61.testbed.emulab.net";
my $GENICENTRALURL = "https://$GENICENTRAL/protogeni/xmlrpc";
my $GENICENTRALURL = "https://$GENICENTRAL/protogeni/xmlrpc/ch";
#
# Lookup a user at the clearing house.
#
sub LookupUser($$)
{
my ($user, $pref) = @_;
my ($uuid, $pref) = @_;
$$pref = undef;
my $response =
Genixmlrpc::CallMethodHTTP($GENICENTRALURL, undef,
"CH::LookupUser",
{ "uuid" => $user->uuid()});
{ "uuid" => $uuid });
return -1
if (!defined($response) || $response->code() != GENIRESPONSE_SUCCESS);
......@@ -64,14 +63,14 @@ sub LookupUser($$)
#
sub LookupSlice($$)
{
my ($experiment, $pref) = @_;
my ($uuid, $pref) = @_;
$$pref = undef;
my $response =
Genixmlrpc::CallMethodHTTP($GENICENTRALURL, undef,
"CH::LookupSlice",
{ "uuid" => $experiment->uuid()});
{ "uuid" => $uuid });
return -1
if (!defined($response) || $response->code() != GENIRESPONSE_SUCCESS);
......@@ -83,29 +82,17 @@ sub LookupSlice($$)
# Register a local Emulab user at the Geni ClearingHouse (which in the
# prototype is Utah Emulab).
#
sub RegisterUser($)
sub RegisterUser($$$$$)
{
my ($user) = @_;
my $cert;
if ($user->SSLCert(1, \$cert)) {
print STDERR
"Geni::RegisterUser - No encrypted certificate found for $user\n";
return -1;
}
# XXX Form hrn from the uid and domain. This is backwards.
my $hrn = $OURDOMAIN . "." . $user->uid();
my ($hrn, $uuid, $name, $email, $cert) = @_;
my $response =
Genixmlrpc::CallMethodHTTP($GENICENTRALURL, undef,
"CH::RegisterUser",
{ "hrn" => $hrn,
# Optional, prefered local login id.
"uid" => $user->uid(),
"uuid" => $user->uuid(),
"name" => $user->name(),
"email" => $user->email(),
"uuid" => $uuid,
"name" => $name,
"email" => $email,
"cert" => $cert});
return -1
......@@ -117,20 +104,17 @@ sub RegisterUser($)
#
# Register a local Emulab experiment at the Clearinghouse, as a slice.
#
sub RegisterSlice($)
sub RegisterSlice($$$$)
{
my ($experiment) = @_;
my $user = $experiment->GetCreator();
# XXX Form hrn from the uid and domain. This is backwards.
my $hrn = $OURDOMAIN . "." . $experiment->pid() . "." . $experiment->eid();
my ($hrn, $uuid, $creator_uuid, $cert) = @_;
my $response =
Genixmlrpc::CallMethodHTTP($GENICENTRALURL, undef,
"CH::CreateSliceName",
{ "hrn" => $hrn,
"uuid" => $experiment->uuid(),
"creator_uuid" => $user->uuid()});
"uuid" => $uuid,
"creator_uuid" => $creator_uuid,
"cert" => $cert });
return -1
if (!defined($response) || $response->code() != GENIRESPONSE_SUCCESS);
......@@ -143,12 +127,12 @@ sub RegisterSlice($)
#
sub DeleteSlice($)
{
my ($experiment) = @_;
my ($uuid) = @_;
my $response =
Genixmlrpc::CallMethodHTTP($GENICENTRALURL, undef,
"CH::FreeSliceName",
{ "uuid" => $experiment->uuid()});
{ "uuid" => $uuid });
return -1
if (!defined($response) || $response->code() != GENIRESPONSE_SUCCESS);
......@@ -165,21 +149,12 @@ sub DeleteSlice($)
#
sub DiscoverResources($$)
{
my ($experiment, $pref) = @_;
my ($slice, $pref) = @_;
#
# XXX
#
my $this_user = User->LookupByUnixId($UID);
if (! defined($this_user)) {
print STDERR "You ($UID) do not exist!\n";
return -1;
}
my $response =
Genixmlrpc::CallMethodHTTP($GENICENTRALURL, undef,
"CH::DiscoverResources",
{ "slice_uuid" => $experiment->uuid() });
{ "slice" => $slice->cert() });
return -1
if (!defined($response));
......@@ -188,7 +163,7 @@ sub DiscoverResources($$)
if ($response->code() != GENIRESPONSE_SUCCESS);
#
# We get back a list of components right now, whic we cache locally.
# We get back a list of components right now, which we cache locally.
#
my @result = ();
......@@ -196,10 +171,11 @@ sub DiscoverResources($$)
my $uuid = $ref->{'uuid'};
my $url = $ref->{'url'};
my $hrn = $ref->{'hrn'};
my $cert = $ref->{'cert'};
my $component = GeniComponent->Lookup($uuid);
if (!defined($component)) {
$component = GeniComponent->Create($uuid, $hrn, $url);
$component = GeniComponent->Create($uuid, $hrn, $url, $cert);
if (!defined($component)) {
return GeniResponse->Create(GENIRESPONSE_DBERROR);
}
......
......@@ -24,6 +24,7 @@ use Genixmlrpc;
use GeniResponse;
use GeniTicket;
use GeniCredential;
use GeniSlice;
use GeniSliver;
use GeniUser;
use libtestbed;
......@@ -33,6 +34,7 @@ use User;
use Node;
use English;
use Data::Dumper;
use XML::Simple;
use Experiment;
# Configure variables
......@@ -52,11 +54,12 @@ my $AVAIL = "$TB/sbin/avail";
sub DiscoverResources($)
{
my ($argref) = @_;
my $slice_uuid = $argref->{'slice_uuid'};
my $slice = $argref->{'slice'};
my $credential = $argref->{'credential'};
my $user_uuid = $ENV{'GENIUSER'};
my $slice_uuid;
if (! (defined($slice_uuid) && ($slice_uuid =~ /^[-\w]+$/))) {
if (! defined($slice)) {
return GeniResponse->MalformedArgsResponse();
}
......@@ -65,6 +68,10 @@ sub DiscoverResources($)
return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
"Could not create GeniCredential object");
}
GeniCredential->CertificateInfo($slice, \$slice_uuid) == 0 or
return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
"Could not get uuid from Certificate");
# The credential owner/slice has to match what was provided.
if (! ($user_uuid eq $credential->owner_uuid() &&
$slice_uuid eq $credential->this_uuid())) {
......@@ -90,7 +97,7 @@ sub DiscoverResources($)
}
close(AVAIL);
my $xml = "<rspec xmlns:\"http://protogeni.net/resources/rspec/0.1\">\n";
my $xml = "<rspec xmlns=\"http://protogeni.net/resources/rspec/0.1\">\n";
foreach my $node (@nodelist) {
my $uuid = $node->uuid();
my $nodeid = $node->node_id();
......@@ -104,9 +111,7 @@ sub DiscoverResources($)
}
#
# Respond to a GetTicket request. No worries about credentials yet; we
# trust the caller cause it got past the SSL client verify checks in the
# web server.
# Respond to a GetTicket request.
#
sub GetTicket($)
{
......@@ -118,11 +123,16 @@ sub GetTicket($)
my $owner_uuid = $ENV{'GENIUSER'};
if (! (defined($slice_uuid) && ($slice_uuid =~ /^[-\w]+$/))) {
return GeniResponse->MalformedArgsResponse();
GeniResponse->Create(GENIRESPONSE_BADARGS, undef,
"Improper slice uuid");
}
if (! defined($rspec)) {
return GeniResponse->MalformedArgsResponse();
if (! (defined($rspec) && ($rspec =~ /^[-\w]+$/))) {
GeniResponse->Create(GENIRESPONSE_BADARGS, undef,
"Improper rspec");
}
# Convert the rspec back to a structure.
$rspec = XMLin($rspec, ForceArray => ["node"]);
$impotent = 0
if (!defined($impotent));
......@@ -138,6 +148,18 @@ sub GetTicket($)
"Invalid credentials for operation");
}
#
# See if we have a record of this slice in the DB. If not, then we have
# to go to the ClearingHouse to find its record, so that we can find out
# who the SA for it is.
#
my $slice = GeniSlice->Lookup($slice_uuid);
if (!defined($slice)) {
}
#
# XXX Should we create a local geni_slices record in the DB?
#
......@@ -164,20 +186,23 @@ sub GetTicket($)
}
#
# An rspec is a structure that requests a specific node. If that node
# is available, then reserve it. Otherwise the ticket cannot be
# granted.
# An rspec is a structure that requests specific nodes. If those
# nodes are available, then reserve it. Otherwise the ticket
# cannot be granted.
#
my $node_id = $rspec->{'node_id'};
my @nodeids = ();
my $pid = $experiment->pid();
my $eid = $experiment->eid();
if (defined($node_id) && $node_id =~ /^(\w*)$/) {
$node_id = $1;
}
else {
return GeniResponse->Create(GENIRESPONSE_BADARGS, undef,
"Improper node id");
foreach my $node_id (keys(%{$rspec->{'node'}})) {
if ($node_id =~ /^(\w*)$/) {
$node_id = $1;
}
else {
return GeniResponse->Create(GENIRESPONSE_BADARGS, undef,
"Improper node id: $node_id");
}
push(@nodeids, $node_id);
}
#
......@@ -190,7 +215,7 @@ sub GetTicket($)
}
# Nalloc might fail if the node gets picked up by someone else.
if (!$impotent) {
system("$NALLOC $pid $eid $node_id");
system("$NALLOC $pid $eid @nodeids");
if (($? >> 8) < 0) {
$ticket->Delete();
return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
......@@ -203,7 +228,7 @@ sub GetTicket($)
}
}
if ($ticket->Sign() != 0) {
# Release will free the node.
# Release will free the nodes.
$ticket->Release();
return GeniResponse->Create(GENIRESPONSE_ERROR, undef,
"Could not sign Ticket");
......@@ -215,8 +240,6 @@ sub GetTicket($)
#
# Create a sliver.
#
# XXX Credentials stuff.
#
sub CreateSliver($)
{
my ($argref) = @_;
......
......@@ -41,46 +41,6 @@ my $OURDOMAIN = "@OURDOMAIN@";
my $GENICENTRAL = "myboss.little-emulab-bsd61.testbed.emulab.net";
my $GENICENTRALURL = "https://$GENICENTRAL/protogeni/xmlrpc";
#
# Discover resources on components, for this experiment.
#
sub DiscoverResources($@)
{
my ($experiment, @resources) = @_;
my $rspec;
#
# XXX
#
my $this_user = User->LookupByUnixId($UID);
if (! defined($this_user)) {
print STDERR "You ($UID) do not exist!\n";
return -1;
}
# Need to construct a credential.
my $credential = GeniCredential->Create($experiment->uuid(),
$this_user->uuid());
if (!defined($credential)) {
print STDERR "Could not create a slice credential for $experiment!\n";
return -1;
}
if ($credential->AddCapability("createslice", 0)) {
print STDERR "Could not add capability to slice credential!\n";
return -1;
}
if ($credential->Sign()) {
print STDERR "Could not sign slice credential!\n";
return -1;
}
foreach my $component (@resources) {
$component->DiscoverResources($this_user, $credential,
$experiment->uuid(), \$rspec);
}
return 0;
}
#
# Ask for a ticket. We provide an rspec. Neither of these are defined yet
# so lets be simpleminded; send a count of nodes we want and get back a
......@@ -110,10 +70,6 @@ sub GetTicket($$$$)
print STDERR "Could not create a slice credential for $experiment!\n";
return -1;
}
if ($credential->AddCapability("createslice", 0)) {
print STDERR "Could not add capability to slice credential!\n";
return -1;
}
if ($credential->Sign()) {
print STDERR "Could not sign slice credential!\n";
return -1;
......
......@@ -28,6 +28,7 @@ use Experiment;
use libdb qw(TBGetUniqueIndex);
use English;
use overload ('""' => 'Stringify');
use XML::Simple;
# Configure variables
my $TB = "@prefix@";
......@@ -79,6 +80,19 @@ sub Lookup($$)
my $self = {};
$self->{'COMPONENT'} = $query_result->fetchrow_hashref();
bless($self, $class);
#
# Grab the certificate, since we will probably want it.
#
my $uuid = $self->{'COMPONENT'}->{'uuid'};
$query_result = DBQueryWarn("select cert from geni_certificates ".
"where uuid='$uuid'");
if (!$query_result || !$query_result->numrows) {
print STDERR "Could not find certificate for component $idx\n";
return undef;
}
my ($cert) = $query_result->fetchrow_array();
$self->{'COMPONENT'}->{'cert'} = $cert;
# Add to cache.
$components{$self->{'COMPONENT'}->{'idx'}} = $self;
......@@ -104,7 +118,7 @@ sub Stringify($)
#
sub Create($$$$;$$)
{
my ($class, $uuid, $hrn, $url) = @_;
my ($class, $uuid, $hrn, $url, $cert) = @_;
my @insert_data = ();
my $idx = TBGetUniqueIndex('next_component', 1);
......@@ -112,6 +126,7 @@ sub Create($$$$;$$)
my $safe_hrn = DBQuoteSpecial($hrn);
my $safe_url = DBQuoteSpecial($url);
my $safe_uuid = DBQuoteSpecial($uuid);
my $safe_cert = DBQuoteSpecial($cert);
# Now tack on other stuff we need.
push(@insert_data, "created=now()");
......@@ -121,9 +136,16 @@ sub Create($$$$;$$)
push(@insert_data, "uuid=$safe_uuid");
# Insert into DB.
DBQueryWarn("insert into geni_components set " . join(",", @insert_data))
DBQueryWarn("replace into geni_components set " . join(",", @insert_data))
or return undef;
# Insert the certificate.
if (!DBQueryWarn("replace into geni_certificates set ".
" uuid=$safe_uuid, cert=$safe_cert")) {
DBQueryWarn("delete from geni_components where idx='$idx'");
return undef;
}
return GeniComponent->Lookup($idx);
}
# accessors
......@@ -132,6 +154,7 @@ sub idx($) { return field($_[0], "idx"); }
sub uuid($) { return field($_[0], "uuid"); }
sub url($) { return field($_[0], "url"); }
sub hrn($) { return field($_[0], "hrn"); }
sub cert($) { return field($_[0], "cert"); }
#
# Refresh a class instance by reloading from the DB.
......@@ -143,7 +166,8 @@ sub Refresh($)
return -1
if (! ref($self));
my $idx = $self->idx();
my $idx = $self->idx();
my $uuid = $self->uuid();
my $query_result =
DBQueryWarn("select * from geni_components where idx=$idx");
......@@ -152,6 +176,19 @@ sub Refresh($)
if (!$query_result || !$query_result->numrows);
$self->{'COMPONENT'} = $query_result->fetchrow_hashref();
#
# Grab the certificate, since we will probably want it.
#
$query_result = DBQueryWarn("select cert from geni_certificates ".
"where uuid='$uuid'");
if (!$query_result || !$query_result->numrows) {
print STDERR "Could not find certificate for component $idx\n";
return undef;
}
my ($cert) = $query_result->fetchrow_array();
$self->{'COMPONENT'}->{'cert'} = $cert;
return 0;
}
......@@ -185,23 +222,26 @@ sub Update($$)
#
sub DiscoverResources($$$$$)
{
my ($self, $user, $credential, $slice_uuid, $pref) = @_;
my ($self, $slice, $user, $credential, $pref) = @_;
# Must be a real reference.
return -1
if (! ref($self));
if (! (ref($self) && ref($slice) && ref($user) && ref($credential)));
my $response =
Genixmlrpc::CallMethodHTTP($self->url(),
$user,
"CM::DiscoverResources",
{ "slice_uuid" => $slice_uuid,
"credential" => $credential->asString()
{ "slice" => $slice->cert(),
"credential" => $credential->asString()
});
return undef
return -1
if (!defined($response) || $response->code() != GENIRESPONSE_SUCCESS);
my $rspec = XMLin($response->value(), ForceArray => ["node"]);
$$pref = $rspec;
return 0;
}
......@@ -211,11 +251,17 @@ sub DiscoverResources($$$$$)
sub GetTicket($$$$$)
{
my ($self, $user, $credential, $slice_uuid, $rspec) = @_;
my $rspec_xml = $rspec;
# Must be a real reference.
return -1
if (! ref($self));
# The rspec is passed as XML. If we get a ref, convert it.
if (ref($rspec_xml)) {
$rspec_xml = XMLout($rspec_xml, RootName => "rspec");
}
my $response =
Genixmlrpc::CallMethodHTTP($self->url(),
$user,
......@@ -223,7 +269,7 @@ sub GetTicket($$$$$)
{ "slice_uuid" => $slice_uuid,
"credential" => $credential->asString(),
"impotent" => 0,
"rspec" => $rspec });
"rspec" => $rspec_xml });
return undef
if (!defined($response));
......
......@@ -28,6 +28,9 @@ use XML::LibXML;
use Data::Dumper;
use File::Temp qw(tempfile);
# Exported variables
use vars qw(@EXPORT_OK $LOCALSA_FLAG $LOCALCM_FLAG);
# Configure variables
my $TB = "@prefix@";
my $TBOPS = "@TBOPSEMAIL@";
......@@ -38,17 +41,30 @@ my $OURDOMAIN = "@OURDOMAIN@";
my $SIGNCRED = "$TB/sbin/signgenicred";
my $VERIFYCRED = "$TB/sbin/verifygenicred";
my $NFREE = "$TB/bin/nfree";
my $OPENSSL = "/usr/bin/openssl";
# Signing flags
$LOCALSA_FLAG = 1;
$LOCALCM_FLAG = 2;
@EXPORT_OK = qw(LOCALSA_FLAG LOCALCM_FLAG);
#
# Create an empty credential object.
#
sub Create($$$$)
{
my ($class, $this_uuid, $owner_uuid) = @_;
my ($class, $this, $owner) = @_;
return undef
if (! (ref($this) && ref($owner)));
my $self = {};
$self->{'this_uuid'} = $this_uuid;
$self->{'owner_uuid'} = $owner_uuid;
$self->{'this'} = $this;
$self->{'owner'} = $owner;
$self->{'this_uuid'} = $this->uuid();
$self->{'owner_uuid'} = $owner->uuid();
$self->{'this_cert'} = $this->cert();
$self->{'owner_cert'} = $owner->cert();
$self->{'string'} = undef;
$self->{'capabilities'} = undef;
$self->{'idx'} = undef; # Only set when stored to DB.
......@@ -59,8 +75,12 @@ sub Create($$$$)
# accessors
sub field($$) { return ($_[0]->{$_[1]}); }
sub idx($) { return field($_[0], "idx"); }
sub this($) { return field($_[0], "this"); }
sub owner($) { return field($_[0], "owner"); }
sub this_uuid($) { return field($_[0], "this_uuid"); }
sub owner_uuid($) { return field($_[0], "owner_uuid"); }
sub this_cert($) { return field($_[0], "this_cert"); }
sub owner_cert($) { return field($_[0], "owner_cert"); }
sub asString($) { return field($_[0], "string"); }
sub capabilities($) { return field($_[0], "capabilities"); }
......@@ -116,7 +136,10 @@ sub CreateFromSigned($$)
my ($uuid_node) = $doc->getElementsByTagName("this_uuid");
return undef
if (!defined($uuid_node));
my $this_uuid = $uuid_node->to_literal();
my $this_cert = $uuid_node->to_literal();
my $this_uuid;
GeniCredential->CertificateInfo($this_cert, \$this_uuid) == 0
or return undef;
if (! ($this_uuid =~ /^\w+\-\w+\-\w+\-\w+\-\w+$/)) {
print STDERR "Invalid this_uuid in credential\n";
......@@ -128,7 +151,10 @@ sub CreateFromSigned($$)
($uuid_node) = $doc->getElementsByTagName("owner_uuid");
return undef
if (!defined($uuid_node));
my $owner_uuid = $uuid_node->to_literal();
my $owner_cert = $uuid_node->to_literal();
my $owner_uuid;
GeniCredential->CertificateInfo($owner_cert, \$owner_uuid) == 0
or return undef;
if (! ($owner_uuid =~ /^\w+\-\w+\-\w+\-\w+\-\w+$/)) {
print STDERR "Invalid owner_uuid in credential\n";
......@@ -139,6 +165,8 @@ sub CreateFromSigned($$)
$self->{'capabilities'} = $capabilities;
$self->{'this_uuid'} = $this_uuid;
$self->{'owner_uuid'} = $owner_uuid;
$self->{'this_cert'} = $this_cert;
$self->{'owner_cert'} = $owner_cert;
$self->{'string'} = $string;
$self->{'xmlref'} = $doc;
$self->{'idx'} = undef; # Only set when stored to DB.
......@@ -169,9 +197,9 @@ sub Delete($)
#
# Sign the credential.
#
sub Sign($)
sub Sign($$)
{
my ($self) = @_;