GeniUser.pm.in 17.9 KB
Newer Older
1 2
#!/usr/bin/perl -wT
#
3
# GENIPUBLIC-COPYRIGHT
4
# Copyright (c) 2008-2010 University of Utah and the Flux Group.
5 6 7 8 9 10 11 12 13 14 15 16
# All rights reserved.
#
package GeniUser;

use strict;
use Exporter;
use vars qw(@ISA @EXPORT);

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

use GeniDB;
Leigh B. Stoller's avatar
Leigh B. Stoller committed
17
use GeniRegistry;
Leigh B. Stoller's avatar
Leigh B. Stoller committed
18
use GeniAuthority;
19
use GeniCertificate;
20
use GeniHRN;
21
use emutil qw(TBGetUniqueIndex);
22 23 24 25
use English;
use overload ('""' => 'Stringify');
use vars qw();

26 27 28 29
# Do not load this for the Clearinghouse XML server.
BEGIN { 
    if (! defined($main::GENI_ISCLRHOUSE)) {
	require User;
30
	require emdb;
31 32 33
    }
}

34 35 36 37 38 39 40 41
# Configure variables
my $TB		   = "@prefix@";
my $TBOPS          = "@TBOPSEMAIL@";
my $TBAPPROVAL     = "@TBAPPROVALEMAIL@";
my $TBAUDIT   	   = "@TBAUDITEMAIL@";
my $BOSSNODE       = "@BOSSNODE@";
my $CONTROL	   = "@USERNODE@";
my $OURDOMAIN      = "@OURDOMAIN@";
42
my $PGENIDOMAIN    = "@PROTOGENI_DOMAIN@";
43 44 45

# Cache of instances to avoid regenerating them.
my %users      = ();
46
BEGIN { use GeniUtil; GeniUtil::AddCache(\%users); }
47 48 49 50 51 52 53 54 55 56 57 58 59
my $debug      = 0;

# Little helper and debug function.
sub mysystem($)
{
    my ($command) = @_;

    print STDERR "Running '$command'\n"
	if ($debug);
    return system($command);
}

#
60
# Lookup by URN, idx, or uuid.
61
#
62
sub Lookup($$;$)
63
{
64
    my ($class, $token, $includelocal) = @_;
65
    my $query_result;
Leigh B. Stoller's avatar
Leigh B. Stoller committed
66
    my $idx;
67

68 69 70
    $includelocal = 0
	if (!defined($includelocal));

71
    if( GeniHRN::IsValid( $token ) ) {
72
	$token = GeniHRN::Normalise( $token );
73 74 75 76
	my ($authority, $type, $id) = GeniHRN::Parse( $token );

	return undef if $type ne "user";

77 78 79 80 81 82
	if( GeniHRN::Authoritative( $token, "@OURDOMAIN@" ) ) {
	    # A local name, so look only for local users...
	    $query_result =
		DBQueryWarn("select idx from geni_users ".
			    "where hrn='${PGENIDOMAIN}.$id' " .
			    "and status='active'");
83 84

	    return undef
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
		if (!$query_result);

	    if (!$query_result->numrows) {
		return undef
		    if (!$includelocal);

		#
		# Check Emulab users table. 
		#
		my $user = User->Lookup($id);
		return undef
		    if (!defined($user));
		return GeniUser->CreateFromLocal($user);
	    }
	} else {
	    # A foreign name: check against names in certificates.
	    $query_result = DBQueryWarn(
		"SELECT geni_users.idx FROM geni_users, geni_certificates " .
		"WHERE geni_users.uuid = geni_certificates.uuid AND " .
		"geni_certificates.urn = '$token';" );
	    return undef unless $query_result and $query_result->numrows;
106 107 108 109
	}
	($idx) = $query_result->fetchrow_array();	
    }
    elsif ($token =~ /^\d+$/) {
Leigh B. Stoller's avatar
Leigh B. Stoller committed
110
	$idx = $token;
Leigh B. Stoller's avatar
Leigh B. Stoller committed
111 112 113
    }
    elsif ($token =~ /^\w+\-\w+\-\w+\-\w+\-\w+$/) {
	$query_result =
Leigh B. Stoller's avatar
Leigh B. Stoller committed
114
	    DBQueryWarn("select idx from geni_users ".
Leigh B. Stoller's avatar
Leigh B. Stoller committed
115
			"where uuid='$token' and status='active'");
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133

	return undef
	    if (!$query_result);

	if (!$query_result->numrows) {
	    return undef
		if (!$includelocal);

	    #
	    # Check Emulab users table. 
	    #
	    my $user = User->LookupByUUID($token);
	    return undef
		if (!defined($user));
	    return GeniUser->CreateFromLocal($user);
	}
	($idx) = $query_result->fetchrow_array();
    }
Leigh B. Stoller's avatar
Leigh B. Stoller committed
134
    elsif ($token =~ /^[-\w\.]*$/) {
135 136 137 138 139 140 141 142
	$query_result =
	    DBQueryWarn("select idx from geni_users ".
			"where hrn='$token' and status='active'");

	return undef
	    if (!$query_result);

	if (!$query_result->numrows) {
Leigh B. Stoller's avatar
Leigh B. Stoller committed
143
	    return undef
144
		if (!$includelocal);
Leigh B. Stoller's avatar
Leigh B. Stoller committed
145

146 147 148 149 150 151 152 153 154 155 156
	    #
	    # Check Emulab users table for last part of hrn.
	    #
	    ($token) = ($token =~ /\.(\w*)$/);

	    my $user = User->Lookup($token);
	    return undef
		if (!defined($user));
	    return GeniUser->CreateFromLocal($user);
	}
	($idx) = $query_result->fetchrow_array();
157 158 159 160 161
    }
    else {
	return undef;
    }
    
Leigh B. Stoller's avatar
Leigh B. Stoller committed
162 163 164 165 166 167
    # Look in cache first
    return $users{"$idx"}
        if (exists($users{"$idx"}));

    $query_result =
	DBQueryWarn("select * from geni_users where idx='$idx'");
168
    
169 170 171 172 173 174
    return undef
	if (!$query_result || !$query_result->numrows);

    my $self         = {};
    $self->{'USER'}  = $query_result->fetchrow_hashref();
    bless($self, $class);
Leigh B. Stoller's avatar
Leigh B. Stoller committed
175 176 177 178 179

    #
    # Grab the certificate, since we will probably want it.
    #
    my $uuid = $self->{'USER'}->{'uuid'};
180 181 182
    my $certificate = GeniCertificate->Lookup($uuid);
    if (!defined($certificate)) {
	print STDERR "Could not find certificate for user $idx ($uuid)\n";
Leigh B. Stoller's avatar
Leigh B. Stoller committed
183 184
	return undef;
    }
185
    $self->{'CERT'} = $certificate;
186 187
    
    # Add to cache. 
Leigh B. Stoller's avatar
Leigh B. Stoller committed
188
    $users{$self->{'USER'}->{'idx'}} = $self;
189 190 191 192 193
    
    return $self;
}
# accessors
sub field($$) { return ((! ref($_[0])) ? -1 : $_[0]->{'USER'}->{$_[1]}); }
Leigh B. Stoller's avatar
Leigh B. Stoller committed
194
sub idx($)		{ return field($_[0], "idx"); }
195
sub uid($)		{ return field($_[0], "uid"); }
Leigh B. Stoller's avatar
Leigh B. Stoller committed
196
sub hrn($)		{ return field($_[0], "hrn"); }
197
sub uuid($)		{ return field($_[0], "uuid"); }
198
sub expires($)		{ return field($_[0], "expires"); }
199 200 201 202 203
sub status($)		{ return field($_[0], "status"); }
sub created($)		{ return field($_[0], "created"); }
sub archived($)		{ return field($_[0], "archived"); }
sub name($)		{ return field($_[0], "name"); }
sub email($)		{ return field($_[0], "email"); }
204
sub cert($)		{ return $_[0]->{'CERT'}->cert(); }
205
sub sa_uuid($)		{ return field($_[0], "sa_uuid"); }
206
sub GetCertificate($)   { return $_[0]->{'CERT'}; }
207

Leigh B. Stoller's avatar
Leigh B. Stoller committed
208 209 210 211 212 213 214
#
# Stringify for output.
#
sub Stringify($)
{
    my ($self) = @_;
    
Leigh B. Stoller's avatar
Leigh B. Stoller committed
215 216
    my $hrn = $self->hrn();
    my $idx = $self->idx();
217

Leigh B. Stoller's avatar
Leigh B. Stoller committed
218
    return "[GeniUser: $hrn, IDX: $idx]";
219 220
}

221 222 223 224 225 226 227 228 229 230
#
# Flush from our little cache.
#
sub Flush($)
{
    my ($self) = @_;

    delete($users{$self->idx()});
}

Leigh B. Stoller's avatar
Leigh B. Stoller committed
231 232 233 234 235 236 237 238 239 240 241 242 243 244 245
# Return the URN.
#
# Return the URN. This is complicated by the fact that the DB does
# not store the urn, but is in the certificate. Further, it might
# be a slice from an SA not doing URNs yet, in which case set it to
# the uuid and hope for the best.
#
sub urn($)
{
    my ($self) = @_;
    my $urn = $self->GetCertificate()->urn();

    return $urn
	if (defined($urn) && $urn ne "");

246
    return $self->uuid();
Leigh B. Stoller's avatar
Leigh B. Stoller committed
247 248
}

Leigh B. Stoller's avatar
Leigh B. Stoller committed
249 250 251 252 253
#
# Class method to check for an existing user that has the same
# uid/email. Lets not allow this for now. Return the number of
# users that match or -1 if an error. 
#
254
sub CheckConflict($$)
Leigh B. Stoller's avatar
Leigh B. Stoller committed
255
{
256
    my ($class, $certificate) = @_;
Leigh B. Stoller's avatar
Leigh B. Stoller committed
257

258 259
    my $safe_hrn   = DBQuoteSpecial($certificate->hrn());
    my $safe_email = DBQuoteSpecial($certificate->email());
Leigh B. Stoller's avatar
Leigh B. Stoller committed
260 261

    my $query_result =
Leigh B. Stoller's avatar
Leigh B. Stoller committed
262
	DBQueryFatal("select idx from geni_users ".
263
		     "where hrn=$safe_hrn or email=$safe_email");
Leigh B. Stoller's avatar
Leigh B. Stoller committed
264 265 266 267 268 269
    return -1
	if (!defined($query_result));

    return $query_result->numrows;
}

270
#
271
# Class function to create new Geni user in the DB and return object. 
272
#
273
sub Create($$$$;$)
274
{
275
    my ($class, $certificate, $authority, $info, $keys) = @_;
276
    my $idx;
277 278
    my @insert_data = ();

Leigh B. Stoller's avatar
Leigh B. Stoller committed
279
    # Every user gets a new unique index.
280 281 282 283
    if (defined($main::GENI_ISCLRHOUSE) && $main::GENI_ISCLRHOUSE) {
	$idx = TBGetUniqueIndex('next_geniuser', 1);
    }
    else {
284
	$idx = User->NextIDX();
285
    }	
286

287 288 289 290 291 292
    if (!defined($authority)) {
	print STDERR "Need to specify an authority!\n";
	return undef;
    }
    my $sa_uuid = $authority->uuid();

293 294
    # Now tack on other stuff we need.
    push(@insert_data, "created=now()");
Leigh B. Stoller's avatar
Leigh B. Stoller committed
295
    push(@insert_data, "idx='$idx'");
Leigh B. Stoller's avatar
Leigh B. Stoller committed
296
    push(@insert_data, "status='active'");
297

298 299 300
    my $safe_hrn   = DBQuoteSpecial($certificate->hrn());
    my $safe_uuid  = DBQuoteSpecial($certificate->uuid());
    my $safe_email = DBQuoteSpecial($certificate->email());
Leigh B. Stoller's avatar
Leigh B. Stoller committed
301 302
    push(@insert_data, "hrn=$safe_hrn");
    push(@insert_data, "uuid=$safe_uuid");
303
    push(@insert_data, "email=$safe_email");
304
    push(@insert_data, "sa_uuid='$sa_uuid'");
305

306
    #
Leigh B. Stoller's avatar
Leigh B. Stoller committed
307
    # uid comes from last component of the hrn.
308 309
    #
    my ($uid) = ($certificate->hrn() =~ /^.*\.(\w*)$/);
Leigh B. Stoller's avatar
Leigh B. Stoller committed
310 311 312 313
    if (!defined($uid)) {
	print STDERR "HRN is not dotted: " . $certificate->hrn() . "\n";
	return undef;
    }
314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331

    #
    # This comes from either an info record or the cert.
    #
    my $safe_name;
    if (defined($info) && exists($info->{'name'})) {
	$safe_name = DBQuoteSpecial($info->{'name'});
    }
    else {
	$safe_name = DBQuoteSpecial($uid);
    }
    my $safe_uid = DBQuoteSpecial($uid);

    push(@insert_data, "uid=$safe_uid");
    push(@insert_data, "name=$safe_name");

    if ($certificate->Store() != 0) {
	print STDERR "Could not store certificate for new user.\n";
332 333 334
	return undef;
    }

Leigh B. Stoller's avatar
Leigh B. Stoller committed
335
    # Insert the sshkey if we got one.
336
    if (defined($keys) && ref($keys)) {
337
	foreach my $keyref (@{ $keys }) {
338 339 340
	    next
		if (!ref($keyref));
	    
341 342
	    my $key  = $keyref->{'key'};
	    my $type = $keyref->{'type'};
343 344 345 346 347

	    next
		if (! (defined($key) && defined($type) &&
		       $key ne "" && $type ne ""));
		
348 349 350 351 352
	    chomp($key);
	    chomp($type);
	    
	    my $safe_key  = DBQuoteSpecial($key);
	    my $safe_type = DBQuoteSpecial($type);
353 354 355
	    
	    DBQueryWarn("replace into geni_userkeys set ".
			"  uuid=$safe_uuid, created=now(), ".
356 357
			"  `key`=$safe_key, `type`=$safe_type")
		or return undef;
358
	}
Leigh B. Stoller's avatar
Leigh B. Stoller committed
359 360
    }

361
    # Insert into DB.
Leigh B. Stoller's avatar
Leigh B. Stoller committed
362 363
    if (! DBQueryWarn("insert into geni_users set " .
		      join(",", @insert_data))) {
364
	DBQueryWarn("delete from geni_userkeys where uuid=$safe_uuid");
Leigh B. Stoller's avatar
Leigh B. Stoller committed
365 366
	return undef;
    }
367

Leigh B. Stoller's avatar
Leigh B. Stoller committed
368
    return GeniUser->Lookup($idx);
369 370
}

371 372 373 374 375 376 377 378 379 380
#
# Modify a record; only partial.
#
sub Modify($$$$)
{
    my ($self, $name, $email, $keys) = @_;
    my @insert_data = ();

    my $idx  = $self->idx();
    my $uuid = $self->uuid();
Leigh B. Stoller's avatar
Leigh B. Stoller committed
381 382
    my $safe_name  = DBQuoteSpecial($name || $self->name());
    my $safe_email = DBQuoteSpecial($email || $self->email());
383

384 385 386 387 388 389
    if (defined($name) || defined($email)) {
	return -1
	    if (!DBQueryWarn("update geni_users set ".
			     " name=$safe_name, email=$safe_email ".
			     "where idx='$idx'"));
    }
390

391
    if (defined($keys) && ref($keys)) {
392 393 394 395
	return -1
	    if (!DBQueryWarn("delete from geni_userkeys where uuid='$uuid'"));
	
	foreach my $keyref (@{ $keys }) {
396 397 398
	    next
		if (!ref($keyref));

399 400
	    my $key  = $keyref->{'key'};
	    my $type = $keyref->{'type'};
401 402 403 404 405

	    next
		if (! (defined($key) && defined($type) &&
		       $key ne "" && $type ne ""));
		
406 407 408 409 410
	    chomp($key);
	    chomp($type);
	    
	    my $safe_key  = DBQuoteSpecial($key);
	    my $safe_type = DBQuoteSpecial($type);
411 412 413 414 415 416 417 418 419 420
	    
	    DBQueryWarn("replace into geni_userkeys set ".
			"  uuid='$uuid', created=now(), ".
			"  `key`=$safe_key, `type`=$safe_type")
		or return undef;
	}
    }
    return 0;
}

Leigh B. Stoller's avatar
Leigh B. Stoller committed
421 422 423 424 425 426 427 428 429 430 431
#
# We wrap up local users so that the interface to them is consistent, but
# do not want to duplicate any data, so use a different class wrapper.
#
sub CreateFromLocal($$)
{
    my ($class, $user) = @_;

    return GeniUser::LocalUser->Create($user);
}

432
#
433
# Delete the user.
434 435 436 437 438 439 440 441
#
sub Delete($)
{
    my ($self) = @_;

    return 0
	if (! ref($self));

442 443
    my $idx  = $self->idx();
    my $uuid = $self->uuid();
444

445 446
    DBQueryWarn("delete from geni_bindings where user_uuid='$uuid'")
	or return -1;
Leigh B. Stoller's avatar
Leigh B. Stoller committed
447
    DBQueryWarn("delete from geni_userkeys where uuid='$uuid'")
448
	or return -1;
449 450
    DBQueryWarn("delete from geni_certificates where uuid='$uuid'")
	or return -1;
Leigh B. Stoller's avatar
Leigh B. Stoller committed
451
    DBQueryWarn("delete from geni_users where idx='$idx'")
452 453 454 455 456
	or return -1;
    
    return 0;
}

Leigh B. Stoller's avatar
Leigh B. Stoller committed
457
#
458
# Get the sshkeys for a user.
Leigh B. Stoller's avatar
Leigh B. Stoller committed
459
#
460
sub GetSSHKeys($$)
Leigh B. Stoller's avatar
Leigh B. Stoller committed
461 462
{
    my ($self, $pref) = @_;
463
    my @results = ();
Leigh B. Stoller's avatar
Leigh B. Stoller committed
464 465 466 467

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

468 469
    my $uuid = $self->uuid();
    my $query_result =
470
	DBQueryWarn("select `key` from geni_userkeys ".
471 472 473 474 475 476 477 478 479 480 481 482
		    "where uuid='$uuid' and type='ssh'");
    return -1
	if (!$query_result);

    while (my ($sshkey) = $query_result->fetchrow_array()) {
	push(@results, $sshkey);
    }
    @$pref = @results;
    return 0;
}

#
483
# Get the keys for a user. See the SA. 
484
#
485
sub GetKeyBundle($$)
486 487 488 489 490 491
{
    my ($self, $pref) = @_;
    my @results = ();

    return -1
	if (! (ref($self) && ref($pref)));
Leigh B. Stoller's avatar
Leigh B. Stoller committed
492 493 494

    my $uuid = $self->uuid();
    my $query_result =
495
	DBQueryWarn("select `type`,`key` from geni_userkeys ".
496
		    "where uuid='$uuid'");
Leigh B. Stoller's avatar
Leigh B. Stoller committed
497 498 499
    return -1
	if (!$query_result);

500 501 502 503 504
    while (my ($type,$key) = $query_result->fetchrow_array()) {
	push(@results, {"type" => $type,
			"key"  => $key});
    }
    @$pref = @results;
Leigh B. Stoller's avatar
Leigh B. Stoller committed
505 506 507 508 509 510 511 512 513 514 515 516 517
    return 0;
}

#
# Create a nonlocal user.
#
sub CreateNonLocal($)
{
    my ($self) = @_;

    return undef
	if (! ref($self));

518 519
    my @sshkeys = ();
    $self->GetSSHKeys(\@sshkeys);
Leigh B. Stoller's avatar
Leigh B. Stoller committed
520 521 522 523 524 525

    return User::NonLocal->Create($self->idx(),
				  $self->uid(),
				  $self->uuid(),
				  $self->name(),
				  $self->email(),
526
				  \@sshkeys);
Leigh B. Stoller's avatar
Leigh B. Stoller committed
527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547
}

#
# Bind user to slice, which is another way of saying bind the nonlocal
# user to the experiment (for tmcd).
#
sub BindToSlice($$)
{
    my ($self, $slice) = @_;

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

    my $emulab_user = User::NonLocal->Lookup($self->uuid());
    if (!defined($emulab_user)) {
	$emulab_user = $self->CreateNonLocal();
	if (!defined($emulab_user)) {
	    print STDERR "Could not create nonlocal user for $self\n";
	    return -1;
	}
    }
548 549
    else {
	my @sshkeys = ();
550 551 552 553
	if ($self->GetSSHKeys(\@sshkeys) == 0) {
	    if ($emulab_user->ModifyKeys(\@sshkeys)) {
		print STDERR "Could not update keys for user $self\n";
		return -1;
554 555 556
	    }
	}
    }
Leigh B. Stoller's avatar
Leigh B. Stoller committed
557 558 559 560 561 562 563 564
    my $experiment = $slice->GetExperiment();
    if (!defined($experiment)) {
	print STDERR "Could not locate experiment object for $slice\n";
	return -1;
    }
    return $emulab_user->BindToExperiment($experiment);
}

Leigh B. Stoller's avatar
Leigh B. Stoller committed
565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583
sub UnBindFromSlice($$)
{
    my ($self, $slice) = @_;

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

    my $emulab_user = User::NonLocal->Lookup($self->uuid());
    return 0
	if (!defined($emulab_user));

    my $experiment = $slice->GetExperiment();
    if (!defined($experiment)) {
	print STDERR "Could not locate experiment object for $slice\n";
	return -1;
    }
    return $emulab_user->UnBindFromExperiment($experiment);
}

584 585 586 587 588 589 590 591 592 593
#
# Archive user. 
#
sub Archive($)
{
    my ($self) = @_;

    return 0
	if (! ref($self));

Leigh B. Stoller's avatar
Leigh B. Stoller committed
594
    my $idx = $self->idx();
595 596

    DBQueryWarn("update geni_users set status='archived' ".
Leigh B. Stoller's avatar
Leigh B. Stoller committed
597
		"where idx='$idx'")
598 599 600 601 602
	or return -1;
    
    return 0;
}

Leigh B. Stoller's avatar
Leigh B. Stoller committed
603 604 605 606 607 608 609 610 611 612
#
# Is this a local user. 
#
sub IsLocal($)
{
    my ($self) = @_;

    return ref($self) eq "GeniUser::LocalUser";
}

613
#
Leigh B. Stoller's avatar
Leigh B. Stoller committed
614
# Delete all users for an authority.
615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665
#
sub DeleteAll($$)
{
    my ($class, $authority) = @_;

    my $uuid = $authority->uuid();
    my $query_result =
	DBQueryWarn("select uuid from geni_users ".
		    "where sa_uuid='$uuid'");

    return -1
	if (! $query_result);
    return 0
	if (!$query_result->numrows);

    while (my ($uuid) = $query_result->fetchrow_array()) {
	my $user = GeniUser->Lookup($uuid);
	if (!defined($user)) {
	    print STDERR "Could not lookup user $uuid\n";
	    return -1;
	}
	#
	# Do not allow users with active slices to be deleted.
	#
	my $active_result =
	    DBQueryWarn("select uuid from geni_slices ".
			"where creator_uuid='$uuid'");
	return -1
	    if (!$active_result);
	if ($active_result->numrows()) {
	    print STDERR "$user is heading up active slices\n";
	}

	$active_result =
	    DBQueryWarn("select uuid from geni_slivers ".
			"where creator_uuid='$uuid'");
	return -1
	    if (!$active_result);
	if ($active_result->numrows()) {
	    print STDERR "$user is heading up active slivers\n";
	}
	
	if ($user->Delete() != 0) {
	    print STDERR "Could not delete $user\n";
	    return -1;
	}
    }

    return 0;
}

Leigh B. Stoller's avatar
Leigh B. Stoller committed
666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694
#
# List All users.
#
sub ListAll($$)
{
    my ($class, $pref) = @_;
    my @result = ();
    @$pref = ();

    my $query_result =
	DBQueryWarn("select uuid from geni_users");

    return -1
	if (! $query_result);
    return 0
	if (!$query_result->numrows);

    while (my ($uuid) = $query_result->fetchrow_array()) {
	my $user = GeniUser->Lookup($uuid);
	if (!defined($user)) {
	    print STDERR "Could not lookup user $uuid\n";
	    return -1;
	}
	push(@result, $user);
    }
    @$pref = @result;
    return 0;
}

Leigh B. Stoller's avatar
Leigh B. Stoller committed
695 696 697 698 699
############################################################################
#
# Wrapper for local users.
#
package GeniUser::LocalUser;
700 701 702
use vars qw(@ISA);
@ISA = "GeniUser";

Leigh B. Stoller's avatar
Leigh B. Stoller committed
703 704
use English;
use GeniDB;
705
use GeniUser;
Leigh B. Stoller's avatar
Leigh B. Stoller committed
706
use GeniHRN;
707
use GeniCertificate;
Leigh B. Stoller's avatar
Leigh B. Stoller committed
708 709 710 711 712 713 714 715 716 717 718 719
use overload ('""' => 'Stringify');

#
# Create a wrapper, with the same access names.
#
sub Create($$)
{
    my ($class, $user) = @_;

    my $self         = {};
    $self->{'USER'}  = $user;

720 721
    # And the certificate wrapper.
    my $certificate = GeniCertificate::LocalUser->Create($user);
Leigh B. Stoller's avatar
Leigh B. Stoller committed
722 723 724 725
    if (!defined($certificate)) {
	print STDERR "No certificate found for $user\n";
	return undef;
    }
726
    $self->{'CERT'} = $certificate;
727

Leigh B. Stoller's avatar
Leigh B. Stoller committed
728 729 730 731
    bless($self, $class);
    return $self;
}

732
sub emulab_user()       { return $_[0]->{'USER'}; }
733
sub idx($)		{ return $_[0]->{'USER'}->uid_idx(); }
Leigh B. Stoller's avatar
Leigh B. Stoller committed
734 735 736 737 738
sub uid($)		{ return $_[0]->{'USER'}->uid(); }
sub uuid                { return $_[0]->{'USER'}->uuid(); }
sub created($)		{ return $_[0]->{'USER'}->created(); }
sub name($)		{ return $_[0]->{'USER'}->name(); }
sub email($)		{ return $_[0]->{'USER'}->email(); }
739 740
sub SSLPassPhrase($$$)  { return $_[0]->{'USER'}->SSLPassPhrase($_[1],$_[2]); }
sub HomeDir($)          { return $_[0]->{'USER'}->HomeDir(); }
741
sub admin($)		{ return $_[0]->{'USER'}->admin(); }
Leigh B. Stoller's avatar
Leigh B. Stoller committed
742 743

# Need to construct this since not in User structure.
744
sub hrn($)		{ return "${PGENIDOMAIN}." . $_[0]->uid(); }
Leigh B. Stoller's avatar
Leigh B. Stoller committed
745

746 747 748
# And this is in another structure.
sub cert($)             { return $_[0]->{'CERT'}->cert(); }
sub GetCertificate($)   { return $_[0]->{'CERT'}; }
Leigh B. Stoller's avatar
Leigh B. Stoller committed
749

Leigh B. Stoller's avatar
Leigh B. Stoller committed
750 751 752 753 754 755 756 757
# Return the URN.
sub urn($)
{
    my ($self) = @_;

    return GeniHRN::Generate("@OURDOMAIN@", "user", $self->uid());
}

Leigh B. Stoller's avatar
Leigh B. Stoller committed
758 759 760 761 762 763 764
#
# Register this local user at the ClearingHouse.
#
sub Register($)
{
    my ($self) = @_;

Leigh B. Stoller's avatar
Leigh B. Stoller committed
765 766 767 768 769 770
    my $clearinghouse = GeniRegistry::ClearingHouse->Create();
    return -1
	if (!defined($clearinghouse));

    return $clearinghouse->RegisterUser($self->name(), $self->email(),
					$self->cert());
Leigh B. Stoller's avatar
Leigh B. Stoller committed
771
}
772 773

#
774 775 776
# Get the key bundle for a local user, which are just sshkeys. 
# This function is intended to be used only by the SA to get the
# key bundle from the emulab ssh keys for the local user. 
777
#
778
sub GetKeyBundle($$)
779 780 781 782 783 784 785 786 787
{
    my ($self, $pref) = @_;
    my @results = ();

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

    my $uuid = $self->uuid();
    my @sshkeys    = ();
788
    $self->emulab_user()->GetSSHKeys(\@sshkeys);
Leigh B. Stoller's avatar
Leigh B. Stoller committed
789
    
790 791 792 793 794 795 796 797
    foreach my $sshkey (@sshkeys) {
	push(@results, {"type" => 'ssh',
			"key"  => $sshkey});
    }
    @$pref = @results;
    return 0;
}

Leigh B. Stoller's avatar
Leigh B. Stoller committed
798 799 800 801 802 803
#
# Stringify for output.
#
sub Stringify($)
{
    my ($self) = @_;
Leigh B. Stoller's avatar
Leigh B. Stoller committed
804
    my $user = $self->{'USER'};
Leigh B. Stoller's avatar
Leigh B. Stoller committed
805 806 807 808
    
    return "$user";
}

809 810
# _Always_ make sure that this 1 is at the end of the file...
1;