GeniCredential.pm.in 15.8 KB
Newer Older
Leigh Stoller's avatar
Leigh Stoller committed
1 2
#!/usr/bin/perl -wT
#
3
# GENIPUBLIC-COPYRIGHT
4
# Copyright (c) 2008-2010 University of Utah and the Flux Group.
Leigh Stoller's avatar
Leigh Stoller committed
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
# All rights reserved.
#
package GeniCredential;

#
# Some simple credential stuff.
#
use strict;
use Exporter;
use vars qw(@ISA @EXPORT);

@ISA    = "Exporter";
@EXPORT = qw ( );

use GeniDB;
20
use GeniCertificate;
21
use GeniUtil;
22
use GeniXML;
23
use emutil qw(TBGetUniqueIndex);
Leigh Stoller's avatar
Leigh Stoller committed
24 25 26 27 28
use English;
use XML::Simple;
use XML::LibXML;
use Data::Dumper;
use File::Temp qw(tempfile);
29 30 31
use Date::Parse;
use POSIX qw(strftime);
use Time::Local;
Leigh Stoller's avatar
Leigh Stoller committed
32
use overload ('""' => 'Stringify');
Leigh Stoller's avatar
Leigh Stoller committed
33

Leigh Stoller's avatar
Leigh Stoller committed
34
# Exported variables
35
use vars qw(@EXPORT_OK $LOCALSA_FLAG $LOCALCM_FLAG $LOCALMA_FLAG);
Leigh Stoller's avatar
Leigh Stoller committed
36

Leigh Stoller's avatar
Leigh Stoller committed
37 38 39 40 41 42 43 44 45 46
# Configure variables
my $TB		   = "@prefix@";
my $TBOPS          = "@TBOPSEMAIL@";
my $TBAPPROVAL     = "@TBAPPROVALEMAIL@";
my $TBAUDIT   	   = "@TBAUDITEMAIL@";
my $BOSSNODE       = "@BOSSNODE@";
my $OURDOMAIN      = "@OURDOMAIN@";
my $SIGNCRED	   = "$TB/sbin/signgenicred";
my $VERIFYCRED	   = "$TB/sbin/verifygenicred";
my $NFREE	   = "$TB/bin/nfree";
Leigh Stoller's avatar
Leigh Stoller committed
47 48 49 50 51
my $OPENSSL	   = "/usr/bin/openssl";

# Signing flags
$LOCALSA_FLAG	   = 1;
$LOCALCM_FLAG	   = 2;
52
$LOCALMA_FLAG	   = 3;
53
@EXPORT_OK	   = qw($LOCALSA_FLAG $LOCALCM_FLAG $LOCALMA_FLAG);
Leigh Stoller's avatar
Leigh Stoller committed
54

Leigh Stoller's avatar
Leigh Stoller committed
55 56
# Capability Flags.

Leigh Stoller's avatar
Leigh Stoller committed
57 58 59 60 61 62
#
# Look for a signed credential in the DB. At present, we store a credential
# by user/object (uuid/uuid), not worrying about different flavors of creds
# with different permissions. This is basically a cache on the client side of
# credentials in use so that they do not need to be regenerated.
#
63
sub Lookup($$;$)
Leigh Stoller's avatar
Leigh Stoller committed
64
{
65 66
    my ($class, $arg1, $arg2) = @_;
    my $query_result;
Leigh Stoller's avatar
Leigh Stoller committed
67

68 69 70 71 72 73 74 75 76 77 78 79 80
    if (!defined($arg2)) {
	if ($arg1 =~ /^(\d*)$/) {
	    $query_result =
		DBQueryWarn("select * from geni_credentials ".
			    "where idx='$arg1'");
	}
	else {
	    return undef;
	}
    }
    elsif (ref($arg1) && ref($arg2)) {
	my $target_uuid  = $arg1->uuid();
	my $owner_uuid   = $arg2->uuid();
Leigh Stoller's avatar
Leigh Stoller committed
81

82 83 84 85 86 87 88 89
	$query_result =
	    DBQueryWarn("select * from geni_credentials ".
			"where owner_uuid='$owner_uuid' and ".
			"      this_uuid='$target_uuid'");
    }
    else {
	return undef;
    }
Leigh Stoller's avatar
Leigh Stoller committed
90
    return undef
91 92
	if (!$query_result || !$query_result->numrows);

Leigh Stoller's avatar
Leigh Stoller committed
93 94 95 96
    my $row = $query_result->fetchrow_hashref();
    
    my $credential =
	GeniCredential->CreateFromSigned($row->{'credential_string'}, 1);
Leigh Stoller's avatar
Leigh Stoller committed
97 98 99 100

    return undef
	if (!defined($credential));

Leigh Stoller's avatar
Leigh Stoller committed
101
    # Mark as coming from the DB.
102
    $credential->{'idx'}          = $row->{'idx'};
Leigh Stoller's avatar
Leigh Stoller committed
103 104
    return $credential;
}
Leigh Stoller's avatar
Leigh Stoller committed
105
  
Leigh Stoller's avatar
Leigh Stoller committed
106
#
107
# Create an unsigned credential object.
Leigh Stoller's avatar
Leigh Stoller committed
108
#
109
sub Create($$$)
Leigh Stoller's avatar
Leigh Stoller committed
110
{
Leigh Stoller's avatar
Leigh Stoller committed
111
    my ($class, $target, $owner) = @_;
Leigh Stoller's avatar
Leigh Stoller committed
112 113

    return undef
Leigh Stoller's avatar
Leigh Stoller committed
114
	if (! (ref($target) && ref($owner)));
Leigh Stoller's avatar
Leigh Stoller committed
115 116

    my $self = {};
117
    $self->{'uuid'}          = undef;
118
    $self->{'valid_until'}   = $target->expires();
Leigh Stoller's avatar
Leigh Stoller committed
119
    $self->{'target_uuid'}   = $target->uuid();
Leigh Stoller's avatar
Leigh Stoller committed
120
    $self->{'owner_uuid'}    = $owner->uuid();
121 122 123
    # Convenience stuff.
    $self->{'target_cert'}   = $target->GetCertificate();
    $self->{'owner_cert'}    = $owner->GetCertificate();
Leigh Stoller's avatar
Leigh Stoller committed
124 125
    $self->{'string'}        = undef;
    $self->{'capabilities'}  = undef;
126
    $self->{'extensions'}    = XML::LibXML::NodeList->new();
Leigh Stoller's avatar
Leigh Stoller committed
127
    $self->{'idx'}	     = undef;	# Only set when stored to DB.
Leigh Stoller's avatar
Leigh Stoller committed
128 129 130 131 132 133
    bless($self, $class);

    return $self;
}
# accessors
sub field($$)           { return ($_[0]->{$_[1]}); }
Leigh Stoller's avatar
Leigh Stoller committed
134
sub idx($)		{ return field($_[0], "idx"); }
135
sub uuid($)		{ return field($_[0], "uuid"); }
136
sub expires($)		{ return field($_[0], "valid_until"); }
Leigh Stoller's avatar
Leigh Stoller committed
137
sub target_uuid($)	{ return field($_[0], "target_uuid"); }
138
sub slice_uuid($)	{ return field($_[0], "target_uuid"); }
Leigh Stoller's avatar
Leigh Stoller committed
139 140 141
sub owner_uuid($)	{ return field($_[0], "owner_uuid"); }
sub asString($)		{ return field($_[0], "string"); }
sub capabilities($)	{ return field($_[0], "capabilities"); }
142 143 144 145
sub extensions($)	{ return field($_[0], "extensions"); }
sub owner_cert($)	{ return $_[0]->{"owner_cert"}; }
sub target_cert($)	{ return $_[0]->{"target_cert"}; }
sub hrn($)		{ return $_[0]->{"target_cert"}->hrn(); }
146 147
sub target_urn($)       { return $_[0]->{"target_cert"}->urn(); }
sub owner_urn($)        { return $_[0]->{"owner_cert"}->urn(); }
Leigh Stoller's avatar
Leigh Stoller committed
148

Leigh Stoller's avatar
Leigh Stoller committed
149 150 151 152 153 154 155 156 157 158 159 160 161
#
# Stringify for output.
#
sub Stringify($)
{
    my ($self) = @_;
    
    my $target_uuid = $self->target_uuid();
    my $owner_uuid  = $self->owner_uuid();

    return "[GeniCredential: $target_uuid, $owner_uuid]";
}

Leigh Stoller's avatar
Leigh Stoller committed
162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178
#
# Add a capability to the array.
#
sub AddCapability($$$)
{
    my ($self, $name, $delegate) = @_;

    return -1
	if (!ref($self));

    if (!defined($self->capabilities())) {
	$self->{'capabilities'} = {};
    }
    $self->{'capabilities'}->{$name} = {"can_delegate" => $delegate};
    return 0;
}

179 180 181 182 183 184 185 186 187
#
# Add an entension. Key/Value pairs
#
sub AddExtension($$$)
{
    my ($self, $key, $value) = @_;

    return -1
	if (!ref($self));
188 189
    my $newNode = XML::LibXML::Element->new($key);
    $newNode->appendText($value);
190 191 192
    return 0;
}

193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219
#
# Convenience function; create a signed credential for the target,
# issued to the provided user.
#
sub CreateSigned($$$;$)
{
    my ($class, $target, $owner, $signer) = @_;

    return undef
	if (! (ref($target) && ref($owner)));

    $signer = $target->GetCertificate()
	if (!defined($signer));

    my $credential = GeniCredential->Create($target, $owner);
    if (!defined($credential)) {
	print STDERR "Could not create credential for $target, $owner\n";
	return undef;
    }
    if ($credential->Sign($signer) != 0) {
	$credential->Delete();
	print STDERR "Could not sign credential for $target, $owner\n";
	return undef;
    }
    return $credential;
}

Leigh Stoller's avatar
Leigh Stoller committed
220 221 222
#
# Create a credential object from a signed credential string.
#
Leigh Stoller's avatar
Leigh Stoller committed
223
sub CreateFromSigned($$;$)
Leigh Stoller's avatar
Leigh Stoller committed
224
{
Leigh Stoller's avatar
Leigh Stoller committed
225 226 227 228 229 230 231 232 233
    my ($class, $string, $nosig) = @_;

    #
    # This flag is used to avoid verifying the signature since I do not
    # really care if the component gives me a bad ticket; I am not using
    # it locally, just passing it back to the component at some point.
    #
    $nosig = 0
	if (!defined($nosig));
Leigh Stoller's avatar
Leigh Stoller committed
234 235

    # First verify the credential
Leigh Stoller's avatar
Leigh Stoller committed
236 237 238 239 240 241 242 243 244 245 246 247
    if (! $nosig) {
	my ($fh, $filename) = tempfile(UNLINK => 0);
	return undef
	    if (!defined($fh));
	print $fh $string;
	close($fh);
	system("$VERIFYCRED $filename");
	if ($?) {
	    print STDERR "Credential in $filename did not verify\n";
	    return undef;
	}
	unlink($filename);
Leigh Stoller's avatar
Leigh Stoller committed
248 249
    }

250
    # Use XML::LibXML to convert to something we can mess with.
Leigh Stoller's avatar
Leigh Stoller committed
251
    my $parser = XML::LibXML->new;
252 253 254 255 256 257 258 259
    my $doc;
    eval {
	$doc = $parser->parse_string($string);
    };
    if ($@) {
	print STDERR "Failed to parse credential string: $@\n";
	return undef;
    }
260
    my $root = $doc->documentElement();
Leigh Stoller's avatar
Leigh Stoller committed
261

262
    # Dig out the extensions
263
    my $extensions = GeniXML::FindNodes('//n:extensions/*', $root);
264

265 266
    # UUID of the credential.
    my ($uuid_node) = $doc->getElementsByTagName("uuid");
Leigh Stoller's avatar
Leigh Stoller committed
267 268
    return undef
	if (!defined($uuid_node));
269
    my $this_uuid = $uuid_node->to_literal();
Leigh Stoller's avatar
Leigh Stoller committed
270 271 272 273 274 275

    if (! ($this_uuid =~ /^\w+\-\w+\-\w+\-\w+\-\w+$/)) {
	print STDERR "Invalid this_uuid in credential\n";
	return undef;
    }

276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295
    # Expiration
    my ($expires_node) = $doc->getElementsByTagName("expires");
    if (!defined($expires_node)) {
	print STDERR "Credential is missing expires node\n";
	return undef;
    }
    my $expires = $expires_node->to_literal();

    if (! ($expires =~ /^[-\w:.\/]+/)) {
	print STDERR "Invalid expires date in credential\n";
	return undef;
    }
    # Convert to a localtime.
    my $when = timegm(strptime($expires));
    if (!defined($when)) {
	print STDERR "Could not parse expires: '$expires'\n";
	return undef;
    }
    $expires = POSIX::strftime("20%y-%m-%dT%H:%M:%S", localtime($when));

296 297
    # Dig out the target certificate.
    my ($cert_node) = $doc->getElementsByTagName("target_gid");
298
    return undef
299 300 301 302 303
	if (!defined($cert_node));
    my $target_certificate =
	GeniCertificate->LoadFromString($cert_node->to_literal());
    return undef
	if (!defined($target_certificate));
304

305
    if (!($target_certificate->uuid() =~ /^\w+\-\w+\-\w+\-\w+\-\w+$/)) {
306 307 308
	print STDERR "Invalid target_uuid in credential\n";
	return undef;
    }
309
    if (!($target_certificate->hrn() =~ /^[-\w\.]+$/)) {
310 311 312
	print STDERR "Invalid hrn in credential\n";
	return undef;
    }
313

314 315
    # Dig out the owner certificate.
    ($cert_node) = $doc->getElementsByTagName("owner_gid");
316
    return undef
317
	if (!defined($cert_node));
318

319 320
    my $owner_certificate =
	GeniCertificate->LoadFromString($cert_node->to_literal());
Leigh Stoller's avatar
Leigh Stoller committed
321
    return undef
322
	if (!defined($owner_certificate));
Leigh Stoller's avatar
Leigh Stoller committed
323

324 325 326 327
    if (!($owner_certificate->uuid() =~ /^\w+\-\w+\-\w+\-\w+\-\w+$/)) {
	print STDERR "Invalid target_uuid in credential\n";
	return undef;
    }
328
    if (!($owner_certificate->hrn() =~ /^[-\w\.]+$/)) {
329
	print STDERR "Invalid hrn in credential\n";
Leigh Stoller's avatar
Leigh Stoller committed
330 331 332 333
	return undef;
    }

    my $self = {};
334
    $self->{'capabilities'}  = undef;
335
    $self->{'extensions'}    = $extensions;
336
    $self->{'uuid'}          = $this_uuid;
337
    $self->{'valid_until'}   = $expires;
338 339 340 341
    $self->{'target_uuid'}   = $target_certificate->uuid();
    $self->{'target_cert'}   = $target_certificate;
    $self->{'owner_uuid'}    = $owner_certificate->uuid();
    $self->{'owner_cert'}    = $owner_certificate;
Leigh Stoller's avatar
Leigh Stoller committed
342
    $self->{'string'}        = $string;
Leigh Stoller's avatar
Leigh Stoller committed
343
    $self->{'idx'}	     = undef;	# Only set when stored to DB.
Leigh Stoller's avatar
Leigh Stoller committed
344 345
    bless($self, $class);

346 347 348
    # Dig out the capabilities
    foreach my $cap (GeniXML::FindNodes('.//n:privileges/n:privilege',
					 $root)->get_nodelist()) {
349 350
	my $name = GeniXML::FindElement('n:name', $cap);
	my $delegate = GeniXML::FindElement('n:can_delegate', $cap);
351 352 353 354 355 356
	if (defined($name) && defined($delegate)) {
	    $self->AddCapability($name->textContent(),
				 $delegate->textContent());
	}
    }

Leigh Stoller's avatar
Leigh Stoller committed
357 358 359
    return $self;
}

360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383
# Returns a NodeList for a given XPath using a given node as
# context. 'n' is defined to be the prefix for the namespace of the
# node.
#sub findnodes_n($$)
#{
#    my ($path, $node) = @_;
#    my $xc = XML::LibXML::XPathContext->new();
#    my $ns = $node->namespaceURI();
#    if (defined($ns)) {
#	$xc->registerNs('ns', $node->namespaceURI());
#    } else {
#	$path =~ s/\bn://g;
#    }
#    return $xc->findnodes($path, $node);
#}

# Returns the first Node which matches a given XPath against a given
# node. Works like findnodes_n.
#sub findfirst_n($$)
#{
#    my ($path, $node) = @_;
#    return findnodes_n($path, $node)->pop();
#}

Leigh Stoller's avatar
Leigh Stoller committed
384 385 386 387 388 389 390 391 392 393
#
# Might have to delete this from the DB.
#
sub Delete($)
{
    my ($self) = @_;

    return -1
	if (! ref($self));

Leigh Stoller's avatar
Leigh Stoller committed
394
    if (defined($self->idx())) {
395 396
	my $idx  = $self->idx();
	my $uuid = $self->uuid();
Leigh Stoller's avatar
Leigh Stoller committed
397
	
398 399
	DBQueryWarn("delete from geni_certificates where uuid='$uuid'")
	    or return -1;
Leigh Stoller's avatar
Leigh Stoller committed
400 401 402
	DBQueryWarn("delete from geni_credentials where idx='$idx'")
	    or return -1;
    }
Leigh Stoller's avatar
Leigh Stoller committed
403 404 405 406 407 408
    return 0;
}

#
# Sign the credential.
#
Leigh Stoller's avatar
Leigh Stoller committed
409
sub Sign($$)
Leigh Stoller's avatar
Leigh Stoller committed
410
{
411
    my ($self, $how) = @_;
Leigh Stoller's avatar
Leigh Stoller committed
412 413 414 415

    return -1
	if (!ref($self));

416
    # If no capabilities, then allow all rights, with delegation.
Leigh Stoller's avatar
Leigh Stoller committed
417
    if (!defined($self->capabilities())) {
418
	$self->AddCapability("*", 1);
Leigh Stoller's avatar
Leigh Stoller committed
419 420
    }
    # This little wrapup is for xmlout.
421 422 423 424 425 426 427 428 429
    my $cap_xml = "<privileges>\n";
    foreach my $cap (keys(%{ $self->capabilities() })) {
	my $can_delegate = $self->capabilities()->{$cap}->{'can_delegate'};
	$cap_xml .= "<privilege>";
	$cap_xml .= "<name>$cap</name>";
	$cap_xml .= "<can_delegate>$can_delegate</can_delegate>";
	$cap_xml .= "</privilege>\n";
    }
    $cap_xml .= "</privileges>\n";
Leigh Stoller's avatar
Leigh Stoller committed
430

431
    if ($self->extensions()->size() > 0) {
432
	$cap_xml .= "<extensions>\n";
433
	foreach my $node ($self->extensions()->get_nodelist()) {
434
	    $cap_xml .= $node->toStringC14N();
435 436 437 438
	}
	$cap_xml .= "</extensions>\n";
    }

Leigh Stoller's avatar
Leigh Stoller committed
439 440
    # Every one gets a new unique index, which is used in the xml:id below.
    my $idx = TBGetUniqueIndex('next_ticket', 1);
Leigh Stoller's avatar
Leigh Stoller committed
441

442
    #
443
    # Every ticket/credential its own uuid.
444
    #
445
    my $cred_uuid = GeniUtil::NewUUID();
446

Leigh Stoller's avatar
Leigh Stoller committed
447 448 449
    #
    # Need the certificates for target and owner of the credential.
    #
Leigh Stoller's avatar
Leigh Stoller committed
450 451
    if (!defined($self->target_cert())) {
	print STDERR "No target certificate attached to $self\n";
Leigh Stoller's avatar
Leigh Stoller committed
452 453
	return -1;
    }
Leigh Stoller's avatar
Leigh Stoller committed
454
    my $target_cert = $self->target_cert()->cert();
455
    my $target_urn = $self->target_urn();
456 457 458
    if (! defined($target_urn)) {
	$target_urn = $self->target_uuid();
    }
Leigh Stoller's avatar
Leigh Stoller committed
459

Leigh Stoller's avatar
Leigh Stoller committed
460 461
    if (!defined($self->owner_cert())) {
	print STDERR "No owner certificate attached to $self\n";
Leigh Stoller's avatar
Leigh Stoller committed
462 463
	return -1;
    }
Leigh Stoller's avatar
Leigh Stoller committed
464
    my $owner_cert = $self->owner_cert()->cert();
465
    my $owner_urn = $self->owner_urn();
466 467 468
    if (! defined($owner_urn)) {
	$owner_urn = $self->owner_uuid();
    }
Leigh Stoller's avatar
Leigh Stoller committed
469

470 471 472 473 474 475 476 477 478 479 480
    # Credential expiration: hard-code to 24 hours, if the underlying
    # object does not define an expiration.
    my $expires = $self->expires();
    if (!defined($expires)) {
	$expires = POSIX::strftime("20%y-%m-%dT%H:%M:%S",
				   gmtime(time() + 24 * 60 * 60));
    }
    else {
	$expires = POSIX::strftime("20%y-%m-%dT%H:%M:%S",
				   gmtime(str2time($expires)));
    }
481

Leigh Stoller's avatar
Leigh Stoller committed
482 483 484 485 486 487
    #
    # Create a template xml file to sign.
    #
    my $template =
	"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n".
	"<credential xml:id=\"ref1\">\n".
488
	" <type>privilege</type>\n".
Leigh Stoller's avatar
Leigh Stoller committed
489
	" <serial>$idx</serial>\n".
490
	" <owner_gid>$owner_cert</owner_gid>\n".
491
	" <owner_urn>$owner_urn</owner_urn>\n".
492
	" <target_gid>$target_cert</target_gid>\n".
493
	" <target_urn>$target_urn</target_urn>\n".
494
	" <uuid>$cred_uuid</uuid>\n".
495
	" <expires>$expires</expires>\n".
Leigh Stoller's avatar
Leigh Stoller committed
496 497 498 499 500 501 502 503 504 505
	"  $cap_xml\n".
        "</credential>\n";

    my ($fh, $filename) = tempfile(UNLINK => 0);
    return -1
	if (!defined($fh));

    print $fh $template;
    close($fh);

506 507 508 509
    #
    # Who signs the credential? $how is either a flag (CM or SA) or its
    # a certificate object in the DB. 
    #
510 511 512
    my $certificate;
    
    if (ref($how)) {
513
	# This will auto delete too.
Leigh Stoller's avatar
Leigh Stoller committed
514
	my $certfile = $how->certfile() || $how->WriteToFile(1);
515
	if (!defined($certfile)) {
516
	    print STDERR "Could not write $how to temp file\n";
517 518 519 520 521 522 523 524 525 526
	    return -1;
	}
	$certificate = "-c $certfile";
    }
    elsif ($how == $LOCALSA_FLAG) {
	$certificate = "-c $TB/etc/genisa.pem";
    }
    elsif ($how == $LOCALCM_FLAG) {
	$certificate = "-c $TB/etc/genicm.pem";
    }
527
    elsif ($how == $LOCALMA_FLAG) {
Leigh Stoller's avatar
Leigh Stoller committed
528
	$certificate = "-c $TB/etc/genich.pem";
529
    }
530 531 532 533 534
    else {
	print STDERR "Invalid 'how' argument to Sign()\n";
	return -1;
    }

Leigh Stoller's avatar
Leigh Stoller committed
535 536 537 538
    #
    # Fire up the signer and capture the output. This is the signed credential
    # that is returned. 
    #
539
    if (! open(SIGNER, "$SIGNCRED $certificate $filename |")) {
Leigh Stoller's avatar
Leigh Stoller committed
540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555
	print STDERR "Could not start $SIGNCRED on $filename\n";
	return -1;
    }
    my $credential = "";
    while (<SIGNER>) {
	$credential .= $_;
    }
    if (!close(SIGNER)) {
	print STDERR "Could not sign $filename\n";
	return -1;
    }
    $self->{'string'} = $credential;
    unlink($filename);
    return 0;
}

Leigh Stoller's avatar
Leigh Stoller committed
556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571
#
# Store the given signed credential in the DB. Client side only for now;
# does the CM need to save all the credentials it hands out?
#
sub Store($)
{
    my ($self) = @_;
    my @insert_data  = ();

    # Do not store again.
    return 0
	if (defined($self->idx()));

    # Every credential store gets a new unique index.
    my $idx = TBGetUniqueIndex('next_ticket', 1);
    
572
    my $this_uuid  = $self->target_uuid();
Leigh Stoller's avatar
Leigh Stoller committed
573
    my $owner_uuid = $self->owner_uuid();
574
    my $uuid       = $self->uuid();
575
    my $expires    = $self->expires();
Leigh Stoller's avatar
Leigh Stoller committed
576 577 578 579 580 581

    # Now tack on other stuff we need.
    push(@insert_data, "created=now()");
    push(@insert_data, "idx='$idx'");
    push(@insert_data, "this_uuid='$this_uuid'");
    push(@insert_data, "owner_uuid='$owner_uuid'");
582
    push(@insert_data, "uuid='$uuid'");
Leigh Stoller's avatar
Leigh Stoller committed
583 584 585 586
    
    my $safe_credential = DBQuoteSpecial($self->asString());
    push(@insert_data, "credential_string=$safe_credential");

587 588
    if (defined($expires)) {
	my $safe_expires = DBQuoteSpecial($expires);
589
	push(@insert_data, "valid_until=$safe_expires");
590 591
    }

Leigh Stoller's avatar
Leigh Stoller committed
592 593 594 595 596 597 598 599 600 601
    # Insert into DB.
    DBQueryWarn("insert into geni_credentials set " . join(",", @insert_data))
	or return -1;

    # If sucessfully stored, set the idx field so we know.
    $self->{'idx'} = $idx;

    return 0;
}

602 603 604 605 606 607 608 609 610 611 612 613 614
sub HasPrivilege($$)
{
    my ( $self, $p ) = @_;

    return 0
	if( !defined( $self->{ 'capabilities' } ) );

    return 1
	if( defined( $self->{ 'capabilities' }->{ "*" } ) );

    return defined( $self->{ 'capabilities' }->{ $p } );
}

Leigh Stoller's avatar
Leigh Stoller committed
615 616
# _Always_ make sure that this 1 is at the end of the file...
1;