GeniCredential.pm.in 17 KB
Newer Older
Leigh B. Stoller's avatar
Leigh B. Stoller committed
1
2
#!/usr/bin/perl -wT
#
3
# GENIPUBLIC-COPYRIGHT
4
# Copyright (c) 2008-2010 University of Utah and the Flux Group.
Leigh B. Stoller's avatar
Leigh B. 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 GeniHRN;
24
use emutil qw(TBGetUniqueIndex);
Leigh B. Stoller's avatar
Leigh B. Stoller committed
25
26
27
28
29
use English;
use XML::Simple;
use XML::LibXML;
use Data::Dumper;
use File::Temp qw(tempfile);
30
31
32
use Date::Parse;
use POSIX qw(strftime);
use Time::Local;
Leigh B. Stoller's avatar
Leigh B. Stoller committed
33
use overload ('""' => 'Stringify');
Leigh B. Stoller's avatar
Leigh B. Stoller committed
34

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

Leigh B. Stoller's avatar
Leigh B. Stoller committed
38
39
40
41
42
43
44
45
46
47
# 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 B. Stoller's avatar
Leigh B. Stoller committed
48
49
50
51
52
my $OPENSSL	   = "/usr/bin/openssl";

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

Leigh B. Stoller's avatar
Leigh B. Stoller committed
56
57
# Capability Flags.

Leigh B. Stoller's avatar
Leigh B. Stoller committed
58
59
60
61
62
63
#
# 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.
#
64
sub Lookup($$;$)
Leigh B. Stoller's avatar
Leigh B. Stoller committed
65
{
66
67
    my ($class, $arg1, $arg2) = @_;
    my $query_result;
Leigh B. Stoller's avatar
Leigh B. Stoller committed
68

69
70
71
72
73
74
75
76
77
78
79
80
81
    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 B. Stoller's avatar
Leigh B. Stoller committed
82

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

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

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

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

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

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

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

Leigh B. Stoller's avatar
Leigh B. Stoller committed
150
151
152
153
154
155
156
157
158
159
160
161
162
#
# 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 B. Stoller's avatar
Leigh B. Stoller committed
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
#
# 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;
}

180
#
181
182
183
# Add an extension. Each extension is an xml element.
# If the element is in a different namespace it has to be specified
# during element construction.
184
185
186
187
# It also accepts key/value pairs. When key/value pair is specified
# It converts them to <key>value</key> xml element and 
# adds under extensions.
sub AddExtension
188
{
189
190
    my $self = shift;
    my $elem = undef;
191
    return -1
192
193
194
195
196
197
198
199
200
201
202
203
	      if (!ref($self));
    if (@_ == 1) {
        # it means xml element is specified.
        $elem = shift;
    }
    elsif (@_ == 2) {
        # it means key/value pair is specified.
        $elem = XML::LibXML::Element->new($_[0]);
        $elem->appendText($_[1]);
    }
    else {
        return -1;
204
205
    }
    
206
    my $root = $self->extensions();
207
208
    $root = XML::LibXML::Element->new("extensions")
    if (!defined($root));
209
    $root->appendChild($elem);
210
    $self->{'extensions'} = $root;
211
212
213
    return 0;
}

214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
#
# 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 B. Stoller's avatar
Leigh B. Stoller committed
241
242
243
#
# Create a credential object from a signed credential string.
#
Leigh B. Stoller's avatar
Leigh B. Stoller committed
244
sub CreateFromSigned($$;$)
Leigh B. Stoller's avatar
Leigh B. Stoller committed
245
{
Leigh B. Stoller's avatar
Leigh B. Stoller committed
246
247
248
249
250
251
252
253
254
    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 B. Stoller's avatar
Leigh B. Stoller committed
255
256

    # First verify the credential
Leigh B. Stoller's avatar
Leigh B. Stoller committed
257
258
259
260
261
262
263
264
265
266
267
268
    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 B. Stoller's avatar
Leigh B. Stoller committed
269
270
    }

271
    # Use XML::LibXML to convert to something we can mess with.
Leigh B. Stoller's avatar
Leigh B. Stoller committed
272
    my $parser = XML::LibXML->new;
273
274
275
276
277
278
279
280
    my $doc;
    eval {
	$doc = $parser->parse_string($string);
    };
    if ($@) {
	print STDERR "Failed to parse credential string: $@\n";
	return undef;
    }
281
    my $root = $doc->documentElement();
Leigh B. Stoller's avatar
Leigh B. Stoller committed
282

283
    # Dig out the extensions
284
285
286
    # now extensions is an xml element.
    my ($extensions) = GeniXML::FindNodes('//n:extensions', 
                        $root)->get_nodelist;
287
    
288
289
    # UUID of the credential.
    my ($uuid_node) = $doc->getElementsByTagName("uuid");
Leigh B. Stoller's avatar
Leigh B. Stoller committed
290
291
    return undef
	if (!defined($uuid_node));
292
    my $this_uuid = $uuid_node->to_literal();
Leigh B. Stoller's avatar
Leigh B. Stoller committed
293
294
295
296
297
298

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

299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
    # 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));

319
320
    # Dig out the target certificate.
    my ($cert_node) = $doc->getElementsByTagName("target_gid");
321
    return undef
322
323
324
325
326
	if (!defined($cert_node));
    my $target_certificate =
	GeniCertificate->LoadFromString($cert_node->to_literal());
    return undef
	if (!defined($target_certificate));
327

328
    if (!($target_certificate->uuid() =~ /^\w+\-\w+\-\w+\-\w+\-\w+$/)) {
329
330
331
	print STDERR "Invalid target_uuid in credential\n";
	return undef;
    }
332
    if (!($target_certificate->hrn() =~ /^[-\w\.]+$/)) {
333
334
	my $hrn = $target_certificate->hrn();
	print STDERR "Invalid hrn $hrn in target of credential\n";
335
336
	return undef;
    }
337
338
339
340
    if (!GeniHRN::IsValid($target_certificate->urn())) {
	print STDERR "Invalid urn in target certificate of credential\n";
	return undef;
    }
341

342
343
    # Dig out the owner certificate.
    ($cert_node) = $doc->getElementsByTagName("owner_gid");
344
    return undef
345
	if (!defined($cert_node));
346

347
348
    my $owner_certificate =
	GeniCertificate->LoadFromString($cert_node->to_literal());
Leigh B. Stoller's avatar
Leigh B. Stoller committed
349
    return undef
350
	if (!defined($owner_certificate));
Leigh B. Stoller's avatar
Leigh B. Stoller committed
351

352
353
354
355
    if (!($owner_certificate->uuid() =~ /^\w+\-\w+\-\w+\-\w+\-\w+$/)) {
	print STDERR "Invalid target_uuid in credential\n";
	return undef;
    }
356
    if (!($owner_certificate->hrn() =~ /^[-\w\.]+$/)) {
357
358
	my $hrn = $owner_certificate->hrn();
	print STDERR "Invalid hrn $hrn in owner of credential\n";
Leigh B. Stoller's avatar
Leigh B. Stoller committed
359
360
	return undef;
    }
361
362
363
364
    if (!GeniHRN::IsValid($owner_certificate->urn())) {
	print STDERR "Invalid urn in owner certificate of credential\n";
	return undef;
    }
Leigh B. Stoller's avatar
Leigh B. Stoller committed
365
366

    my $self = {};
367
    $self->{'capabilities'}  = undef;
368
    $self->{'extensions'}    = $extensions;
369
    $self->{'uuid'}          = $this_uuid;
370
    $self->{'valid_until'}   = $expires;
371
372
373
374
    $self->{'target_uuid'}   = $target_certificate->uuid();
    $self->{'target_cert'}   = $target_certificate;
    $self->{'owner_uuid'}    = $owner_certificate->uuid();
    $self->{'owner_cert'}    = $owner_certificate;
Leigh B. Stoller's avatar
Leigh B. Stoller committed
375
    $self->{'string'}        = $string;
Leigh B. Stoller's avatar
Leigh B. Stoller committed
376
    $self->{'idx'}	     = undef;	# Only set when stored to DB.
Leigh B. Stoller's avatar
Leigh B. Stoller committed
377
378
    bless($self, $class);

379
380
381
    # Dig out the capabilities
    foreach my $cap (GeniXML::FindNodes('.//n:privileges/n:privilege',
					 $root)->get_nodelist()) {
382
383
	my $name = GeniXML::FindElement('n:name', $cap);
	my $delegate = GeniXML::FindElement('n:can_delegate', $cap);
384
385
386
387
388
389
	if (defined($name) && defined($delegate)) {
	    $self->AddCapability($name->textContent(),
				 $delegate->textContent());
	}
    }

Leigh B. Stoller's avatar
Leigh B. Stoller committed
390
391
392
    return $self;
}

393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
# 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 B. Stoller's avatar
Leigh B. Stoller committed
417
418
419
420
421
422
423
424
425
426
#
# Might have to delete this from the DB.
#
sub Delete($)
{
    my ($self) = @_;

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

Leigh B. Stoller's avatar
Leigh B. Stoller committed
427
    if (defined($self->idx())) {
428
429
	my $idx  = $self->idx();
	my $uuid = $self->uuid();
Leigh B. Stoller's avatar
Leigh B. Stoller committed
430
	
431
432
	DBQueryWarn("delete from geni_certificates where uuid='$uuid'")
	    or return -1;
Leigh B. Stoller's avatar
Leigh B. Stoller committed
433
434
435
	DBQueryWarn("delete from geni_credentials where idx='$idx'")
	    or return -1;
    }
Leigh B. Stoller's avatar
Leigh B. Stoller committed
436
437
438
439
440
441
    return 0;
}

#
# Sign the credential.
#
Leigh B. Stoller's avatar
Leigh B. Stoller committed
442
sub Sign($$)
Leigh B. Stoller's avatar
Leigh B. Stoller committed
443
{
444
    my ($self, $how) = @_;
Leigh B. Stoller's avatar
Leigh B. Stoller committed
445
446
447
448

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

449
    # If no capabilities, then allow all rights, with delegation.
Leigh B. Stoller's avatar
Leigh B. Stoller committed
450
    if (!defined($self->capabilities())) {
451
	$self->AddCapability("*", 1);
Leigh B. Stoller's avatar
Leigh B. Stoller committed
452
453
    }
    # This little wrapup is for xmlout.
454
455
456
457
458
459
460
461
462
    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 B. Stoller's avatar
Leigh B. Stoller committed
463

464
465
466
    my $extensions = $self->extensions();
    $cap_xml .= GeniXML::Serialize($extensions)
        if (defined($extensions) && $extensions->hasChildNodes());
Leigh B. Stoller's avatar
Leigh B. Stoller committed
467
468
    # Every one gets a new unique index, which is used in the xml:id below.
    my $idx = TBGetUniqueIndex('next_ticket', 1);
Leigh B. Stoller's avatar
Leigh B. Stoller committed
469

470
    #
471
    # Every ticket/credential its own uuid.
472
    #
473
    my $cred_uuid = GeniUtil::NewUUID();
474

Leigh B. Stoller's avatar
Leigh B. Stoller committed
475
476
477
    #
    # Need the certificates for target and owner of the credential.
    #
Leigh B. Stoller's avatar
Leigh B. Stoller committed
478
479
    if (!defined($self->target_cert())) {
	print STDERR "No target certificate attached to $self\n";
Leigh B. Stoller's avatar
Leigh B. Stoller committed
480
481
	return -1;
    }
Leigh B. Stoller's avatar
Leigh B. Stoller committed
482
    my $target_cert = $self->target_cert()->cert();
483
    my $target_urn = $self->target_urn();
484
485
486
    if (! defined($target_urn)) {
	$target_urn = $self->target_uuid();
    }
Leigh B. Stoller's avatar
Leigh B. Stoller committed
487

Leigh B. Stoller's avatar
Leigh B. Stoller committed
488
489
    if (!defined($self->owner_cert())) {
	print STDERR "No owner certificate attached to $self\n";
Leigh B. Stoller's avatar
Leigh B. Stoller committed
490
491
	return -1;
    }
Leigh B. Stoller's avatar
Leigh B. Stoller committed
492
    my $owner_cert = $self->owner_cert()->cert();
493
    my $owner_urn = $self->owner_urn();
494
495
496
    if (! defined($owner_urn)) {
	$owner_urn = $self->owner_uuid();
    }
Leigh B. Stoller's avatar
Leigh B. Stoller committed
497

498
499
500
501
502
503
504
505
506
507
508
    # 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)));
    }
509

Leigh B. Stoller's avatar
Leigh B. Stoller committed
510
511
512
513
514
515
    #
    # Create a template xml file to sign.
    #
    my $template =
	"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n".
	"<credential xml:id=\"ref1\">\n".
516
	" <type>privilege</type>\n".
Leigh B. Stoller's avatar
Leigh B. Stoller committed
517
	" <serial>$idx</serial>\n".
518
	" <owner_gid>$owner_cert</owner_gid>\n".
519
	" <owner_urn>$owner_urn</owner_urn>\n".
520
	" <target_gid>$target_cert</target_gid>\n".
521
	" <target_urn>$target_urn</target_urn>\n".
522
	" <uuid>$cred_uuid</uuid>\n".
523
	" <expires>$expires</expires>\n".
Leigh B. Stoller's avatar
Leigh B. Stoller committed
524
525
526
527
528
529
530
531
532
533
	"  $cap_xml\n".
        "</credential>\n";

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

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

534
535
536
537
    #
    # Who signs the credential? $how is either a flag (CM or SA) or its
    # a certificate object in the DB. 
    #
538
539
540
    my $certificate;
    
    if (ref($how)) {
541
	# This will auto delete too.
Leigh B. Stoller's avatar
Leigh B. Stoller committed
542
	my $certfile = $how->certfile() || $how->WriteToFile(1);
543
	if (!defined($certfile)) {
544
	    print STDERR "Could not write $how to temp file\n";
545
546
547
548
549
550
551
552
553
554
	    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";
    }
555
    elsif ($how == $LOCALMA_FLAG) {
556
557
558
559
560
561
562
	if (defined($main::GENI_CHPEMFILE)) {
	    # See xmlrpc/protogeni-ch.pl.in
	    $certificate = "-c $main::GENI_CHPEMFILE";
	}
	else {
	    $certificate = "-c $TB/etc/genich.pem";
	}
563
    }
564
565
566
567
568
    else {
	print STDERR "Invalid 'how' argument to Sign()\n";
	return -1;
    }

Leigh B. Stoller's avatar
Leigh B. Stoller committed
569
570
571
572
    #
    # Fire up the signer and capture the output. This is the signed credential
    # that is returned. 
    #
573
    if (! open(SIGNER, "$SIGNCRED $certificate $filename |")) {
Leigh B. Stoller's avatar
Leigh B. Stoller committed
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
	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 B. Stoller's avatar
Leigh B. Stoller committed
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
#
# 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);
    
606
    my $this_uuid  = $self->target_uuid();
Leigh B. Stoller's avatar
Leigh B. Stoller committed
607
    my $owner_uuid = $self->owner_uuid();
608
    my $uuid       = $self->uuid();
609
    my $expires    = $self->expires();
Leigh B. Stoller's avatar
Leigh B. Stoller committed
610
611
612
613
614
615

    # 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'");
616
    push(@insert_data, "uuid='$uuid'");
Leigh B. Stoller's avatar
Leigh B. Stoller committed
617
618
619
620
    
    my $safe_credential = DBQuoteSpecial($self->asString());
    push(@insert_data, "credential_string=$safe_credential");

621
622
    if (defined($expires)) {
	my $safe_expires = DBQuoteSpecial($expires);
623
	push(@insert_data, "valid_until=$safe_expires");
624
625
    }

Leigh B. Stoller's avatar
Leigh B. Stoller committed
626
627
628
629
630
631
632
633
634
635
    # 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;
}

636
637
638
639
640
641
642
643
644
645
646
647
648
sub HasPrivilege($$)
{
    my ( $self, $p ) = @_;

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

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

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

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